From e38053487dc20b8fd710fc105f3bda10dbcd80c0 Mon Sep 17 00:00:00 2001 From: Lufaneng Date: Tue, 28 Jul 2026 10:11:44 +0800 Subject: [PATCH] init --- .gitignore | 28 + backend/.env.example | 46 + backend/README.md | 24 + backend/package-lock.json | 1039 ++ backend/package.json | 16 + backend/sql/init.sql | 220 + ...260630_add_wechat_phone_binding_fields.sql | 145 + .../20260630_clear_demo_seed_data.sql | 12 + ...20260630_clear_parent_permission_codes.sql | 5 + .../20260701_add_points_rule_permission.sql | 7 + .../20260701_appointment_unique_user.sql | 35 + .../20260701_redemption_voucher_workflow.sql | 57 + .../20260701_reward_description_and_stock.sql | 18 + .../20260701_update_rbac_permissions.sql | 37 + .../20260703_add_lead_referral_identity.sql | 21 + ...260709_add_point_transaction_reference.sql | 37 + .../20260721_normalize_permission_codes.sql | 47 + .../20260722_account_trial_booking_limit.sql | 51 + backend/src/app.js | 50 + backend/src/config/env.js | 77 + backend/src/constants/permissions.js | 160 + backend/src/controllers/adminController.js | 121 + backend/src/controllers/authController.js | 86 + .../src/controllers/bootstrapController.js | 33 + backend/src/controllers/courseController.js | 94 + backend/src/controllers/pointController.js | 184 + backend/src/controllers/referralController.js | 40 + backend/src/controllers/uploadController.js | 107 + backend/src/data/seed.js | 63 + backend/src/middleware/errorHandler.js | 14 + backend/src/middleware/permission.js | 21 + backend/src/middleware/session.js | 50 + backend/src/repositories/index.js | 7 + backend/src/repositories/memoryRepository.js | 549 + backend/src/repositories/mysqlRepository.js | 1033 ++ backend/src/routes/index.js | 112 + backend/src/server.js | 6 + backend/src/services/adminService.js | 685 + backend/src/services/authService.js | 482 + backend/src/services/courseService.js | 369 + backend/src/services/index.js | 24 + backend/src/services/pointService.js | 646 + backend/src/services/referralService.js | 254 + backend/src/services/smsService.js | 179 + backend/src/utils/ids.js | 5 + backend/src/utils/password.js | 14 + backend/src/utils/sessionToken.js | 38 + backend/uploads/.gitkeep | 0 docker-compose.yml | 85 + front/.env.development | 2 + front/index.html | 20 + front/package-lock.json | 13919 ++++++++++++++++ front/package.json | 69 + front/shims-uni.d.ts | 10 + front/src/App.vue | 38 + front/src/components/AdminTabbar.vue | 96 + front/src/config/index.js | 8 + front/src/main.js | 46 + front/src/manifest.json | 56 + front/src/pages.json | 208 + front/src/pages/account/index.vue | 594 + front/src/pages/admin-appointments/index.vue | 327 + front/src/pages/admin-course-edit/index.vue | 514 + front/src/pages/admin-courses/index.vue | 566 + front/src/pages/admin-leads/index.vue | 509 + .../src/pages/admin-point-accounts/index.vue | 435 + front/src/pages/admin-point-records/index.vue | 346 + front/src/pages/admin-points/index.vue | 474 + front/src/pages/admin-profile/index.vue | 431 + front/src/pages/admin/index.vue | 421 + front/src/pages/campaign/index.vue | 236 + front/src/pages/courses-list/index.vue | 277 + front/src/pages/courses/index.vue | 352 + front/src/pages/index/index.vue | 457 + front/src/pages/login/index.vue | 425 + front/src/pages/point-records/index.vue | 241 + front/src/pages/point-rewards/index.vue | 258 + front/src/pages/points/index.vue | 523 + front/src/pages/referral-records/index.vue | 228 + front/src/pages/referral/index.vue | 592 + front/src/services/accountSession.js | 38 + front/src/services/educationApi.js | 186 + front/src/services/http.js | 57 + front/src/shime-uni.d.ts | 6 + front/src/static/logo.png | Bin 0 -> 4023 bytes .../src/static/share/referral-share-cover.jpg | Bin 0 -> 127016 bytes front/src/static/tabbar/account-active.png | Bin 0 -> 361 bytes front/src/static/tabbar/account.png | Bin 0 -> 359 bytes front/src/static/tabbar/courses-active.png | Bin 0 -> 271 bytes front/src/static/tabbar/courses.png | Bin 0 -> 269 bytes front/src/static/tabbar/home-active.png | Bin 0 -> 312 bytes front/src/static/tabbar/home.png | Bin 0 -> 311 bytes front/src/static/tabbar/points-active.png | Bin 0 -> 446 bytes front/src/static/tabbar/points.png | Bin 0 -> 444 bytes front/src/static/tabbar/referral-active.png | Bin 0 -> 305 bytes front/src/static/tabbar/referral.png | Bin 0 -> 304 bytes front/src/styles/theme.scss | 121 + front/src/uni.scss | 83 + front/src/utils/format.js | 14 + front/vite.config.js | 8 + pc-admin/.env.development | 4 + pc-admin/README.md | 19 + pc-admin/index.html | 12 + pc-admin/package-lock.json | 2257 +++ pc-admin/package.json | 24 + pc-admin/src/App.vue | 3 + pc-admin/src/api/courses/trial.js | 47 + pc-admin/src/api/leads/index.js | 24 + pc-admin/src/api/login.js | 32 + pc-admin/src/api/points/manager.js | 89 + pc-admin/src/api/points/redemption.js | 41 + pc-admin/src/api/statistics/dashboard.js | 9 + pc-admin/src/api/system/account.js | 48 + pc-admin/src/api/system/role.js | 16 + pc-admin/src/api/upload.js | 11 + .../assets/images/login-learning-studio.webp | Bin 0 -> 94452 bytes pc-admin/src/assets/styles/index.scss | 114 + pc-admin/src/assets/styles/variables.scss | 9 + pc-admin/src/components/AppCard/index.vue | 29 + pc-admin/src/components/StatusTag/index.vue | 19 + pc-admin/src/directive/permission/index.js | 40 + .../src/layout/components/AppMain/index.vue | 30 + .../src/layout/components/Navbar/index.vue | 271 + .../src/layout/components/Sidebar/index.vue | 245 + pc-admin/src/layout/index.vue | 40 + pc-admin/src/main.js | 18 + pc-admin/src/permission.js | 68 + pc-admin/src/router/index.js | 155 + pc-admin/src/settings.js | 5 + pc-admin/src/store/index.js | 5 + pc-admin/src/store/modules/user.js | 48 + pc-admin/src/utils/auth.js | 27 + pc-admin/src/utils/permission.js | 5 + pc-admin/src/utils/request.js | 31 + .../src/views/courses/appointments/index.vue | 270 + pc-admin/src/views/courses/trial/index.vue | 365 + pc-admin/src/views/dashboard/index.vue | 525 + pc-admin/src/views/leads/index.vue | 242 + pc-admin/src/views/login.vue | 181 + pc-admin/src/views/points/accounts/index.vue | 366 + pc-admin/src/views/points/details/index.vue | 316 + pc-admin/src/views/points/manager/index.vue | 441 + .../src/views/points/redemptions/index.vue | 336 + .../src/views/points/reward-detail/index.vue | 202 + pc-admin/src/views/points/rewards/index.vue | 305 + pc-admin/src/views/points/vouchers/index.vue | 399 + .../src/views/statistics/channel/index.vue | 124 + pc-admin/src/views/system/account/index.vue | 745 + pc-admin/src/views/system/role/index.vue | 240 + pc-admin/vite.config.js | 26 + scripts/build-server-package.ps1 | 43 + scripts/build-server-package.sh | 42 + 152 files changed, 39587 insertions(+) create mode 100644 .gitignore create mode 100644 backend/.env.example create mode 100644 backend/README.md create mode 100644 backend/package-lock.json create mode 100644 backend/package.json create mode 100644 backend/sql/init.sql create mode 100644 backend/sql/migrations/20260630_add_wechat_phone_binding_fields.sql create mode 100644 backend/sql/migrations/20260630_clear_demo_seed_data.sql create mode 100644 backend/sql/migrations/20260630_clear_parent_permission_codes.sql create mode 100644 backend/sql/migrations/20260701_add_points_rule_permission.sql create mode 100644 backend/sql/migrations/20260701_appointment_unique_user.sql create mode 100644 backend/sql/migrations/20260701_redemption_voucher_workflow.sql create mode 100644 backend/sql/migrations/20260701_reward_description_and_stock.sql create mode 100644 backend/sql/migrations/20260701_update_rbac_permissions.sql create mode 100644 backend/sql/migrations/20260703_add_lead_referral_identity.sql create mode 100644 backend/sql/migrations/20260709_add_point_transaction_reference.sql create mode 100644 backend/sql/migrations/20260721_normalize_permission_codes.sql create mode 100644 backend/sql/migrations/20260722_account_trial_booking_limit.sql create mode 100644 backend/src/app.js create mode 100644 backend/src/config/env.js create mode 100644 backend/src/constants/permissions.js create mode 100644 backend/src/controllers/adminController.js create mode 100644 backend/src/controllers/authController.js create mode 100644 backend/src/controllers/bootstrapController.js create mode 100644 backend/src/controllers/courseController.js create mode 100644 backend/src/controllers/pointController.js create mode 100644 backend/src/controllers/referralController.js create mode 100644 backend/src/controllers/uploadController.js create mode 100644 backend/src/data/seed.js create mode 100644 backend/src/middleware/errorHandler.js create mode 100644 backend/src/middleware/permission.js create mode 100644 backend/src/middleware/session.js create mode 100644 backend/src/repositories/index.js create mode 100644 backend/src/repositories/memoryRepository.js create mode 100644 backend/src/repositories/mysqlRepository.js create mode 100644 backend/src/routes/index.js create mode 100644 backend/src/server.js create mode 100644 backend/src/services/adminService.js create mode 100644 backend/src/services/authService.js create mode 100644 backend/src/services/courseService.js create mode 100644 backend/src/services/index.js create mode 100644 backend/src/services/pointService.js create mode 100644 backend/src/services/referralService.js create mode 100644 backend/src/services/smsService.js create mode 100644 backend/src/utils/ids.js create mode 100644 backend/src/utils/password.js create mode 100644 backend/src/utils/sessionToken.js create mode 100644 backend/uploads/.gitkeep create mode 100644 docker-compose.yml create mode 100644 front/.env.development create mode 100644 front/index.html create mode 100644 front/package-lock.json create mode 100644 front/package.json create mode 100644 front/shims-uni.d.ts create mode 100644 front/src/App.vue create mode 100644 front/src/components/AdminTabbar.vue create mode 100644 front/src/config/index.js create mode 100644 front/src/main.js create mode 100644 front/src/manifest.json create mode 100644 front/src/pages.json create mode 100644 front/src/pages/account/index.vue create mode 100644 front/src/pages/admin-appointments/index.vue create mode 100644 front/src/pages/admin-course-edit/index.vue create mode 100644 front/src/pages/admin-courses/index.vue create mode 100644 front/src/pages/admin-leads/index.vue create mode 100644 front/src/pages/admin-point-accounts/index.vue create mode 100644 front/src/pages/admin-point-records/index.vue create mode 100644 front/src/pages/admin-points/index.vue create mode 100644 front/src/pages/admin-profile/index.vue create mode 100644 front/src/pages/admin/index.vue create mode 100644 front/src/pages/campaign/index.vue create mode 100644 front/src/pages/courses-list/index.vue create mode 100644 front/src/pages/courses/index.vue create mode 100644 front/src/pages/index/index.vue create mode 100644 front/src/pages/login/index.vue create mode 100644 front/src/pages/point-records/index.vue create mode 100644 front/src/pages/point-rewards/index.vue create mode 100644 front/src/pages/points/index.vue create mode 100644 front/src/pages/referral-records/index.vue create mode 100644 front/src/pages/referral/index.vue create mode 100644 front/src/services/accountSession.js create mode 100644 front/src/services/educationApi.js create mode 100644 front/src/services/http.js create mode 100644 front/src/shime-uni.d.ts create mode 100644 front/src/static/logo.png create mode 100644 front/src/static/share/referral-share-cover.jpg create mode 100644 front/src/static/tabbar/account-active.png create mode 100644 front/src/static/tabbar/account.png create mode 100644 front/src/static/tabbar/courses-active.png create mode 100644 front/src/static/tabbar/courses.png create mode 100644 front/src/static/tabbar/home-active.png create mode 100644 front/src/static/tabbar/home.png create mode 100644 front/src/static/tabbar/points-active.png create mode 100644 front/src/static/tabbar/points.png create mode 100644 front/src/static/tabbar/referral-active.png create mode 100644 front/src/static/tabbar/referral.png create mode 100644 front/src/styles/theme.scss create mode 100644 front/src/uni.scss create mode 100644 front/src/utils/format.js create mode 100644 front/vite.config.js create mode 100644 pc-admin/.env.development create mode 100644 pc-admin/README.md create mode 100644 pc-admin/index.html create mode 100644 pc-admin/package-lock.json create mode 100644 pc-admin/package.json create mode 100644 pc-admin/src/App.vue create mode 100644 pc-admin/src/api/courses/trial.js create mode 100644 pc-admin/src/api/leads/index.js create mode 100644 pc-admin/src/api/login.js create mode 100644 pc-admin/src/api/points/manager.js create mode 100644 pc-admin/src/api/points/redemption.js create mode 100644 pc-admin/src/api/statistics/dashboard.js create mode 100644 pc-admin/src/api/system/account.js create mode 100644 pc-admin/src/api/system/role.js create mode 100644 pc-admin/src/api/upload.js create mode 100644 pc-admin/src/assets/images/login-learning-studio.webp create mode 100644 pc-admin/src/assets/styles/index.scss create mode 100644 pc-admin/src/assets/styles/variables.scss create mode 100644 pc-admin/src/components/AppCard/index.vue create mode 100644 pc-admin/src/components/StatusTag/index.vue create mode 100644 pc-admin/src/directive/permission/index.js create mode 100644 pc-admin/src/layout/components/AppMain/index.vue create mode 100644 pc-admin/src/layout/components/Navbar/index.vue create mode 100644 pc-admin/src/layout/components/Sidebar/index.vue create mode 100644 pc-admin/src/layout/index.vue create mode 100644 pc-admin/src/main.js create mode 100644 pc-admin/src/permission.js create mode 100644 pc-admin/src/router/index.js create mode 100644 pc-admin/src/settings.js create mode 100644 pc-admin/src/store/index.js create mode 100644 pc-admin/src/store/modules/user.js create mode 100644 pc-admin/src/utils/auth.js create mode 100644 pc-admin/src/utils/permission.js create mode 100644 pc-admin/src/utils/request.js create mode 100644 pc-admin/src/views/courses/appointments/index.vue create mode 100644 pc-admin/src/views/courses/trial/index.vue create mode 100644 pc-admin/src/views/dashboard/index.vue create mode 100644 pc-admin/src/views/leads/index.vue create mode 100644 pc-admin/src/views/login.vue create mode 100644 pc-admin/src/views/points/accounts/index.vue create mode 100644 pc-admin/src/views/points/details/index.vue create mode 100644 pc-admin/src/views/points/manager/index.vue create mode 100644 pc-admin/src/views/points/redemptions/index.vue create mode 100644 pc-admin/src/views/points/reward-detail/index.vue create mode 100644 pc-admin/src/views/points/rewards/index.vue create mode 100644 pc-admin/src/views/points/vouchers/index.vue create mode 100644 pc-admin/src/views/statistics/channel/index.vue create mode 100644 pc-admin/src/views/system/account/index.vue create mode 100644 pc-admin/src/views/system/role/index.vue create mode 100644 pc-admin/vite.config.js create mode 100644 scripts/build-server-package.ps1 create mode 100755 scripts/build-server-package.sh diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..9fea1a2 --- /dev/null +++ b/.gitignore @@ -0,0 +1,28 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +.DS_Store +dist +release/ +.codex-tmp +*.local + +# Editor directories and files +.idea +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? + +.env +.env.prod +backend/uploads/* +!backend/uploads/.gitkeep diff --git a/backend/.env.example b/backend/.env.example new file mode 100644 index 0000000..5fe0e9f --- /dev/null +++ b/backend/.env.example @@ -0,0 +1,46 @@ +NODE_ENV=production +PORT=3100 +PUBLIC_BASE_URL=http://127.0.0.1:3100 +# Optional. Leave empty to use backend/public/pc-admin. +PC_ADMIN_DIST_DIR= +# Reserved H5 preview config. Keep disabled for the current PC-only release. +ENABLE_H5_PREVIEW=false +# Optional. When H5 preview is enabled later, leave empty to use backend/public/h5. +H5_DIST_DIR= + +# Signed login session. Replace with a long random value before production deployment. +AUTH_SESSION_SECRET=replace_with_at_least_32_random_characters +# Default: 168 hours (7 days). +AUTH_SESSION_TTL_HOURS=168 + +DB_CLIENT=mysql +MYSQL_HOST=127.0.0.1 +MYSQL_PORT=3306 +MYSQL_USER=lifanghe +MYSQL_PASSWORD=lifanghe123 +MYSQL_DATABASE=lifanghe_education +MYSQL_CONNECTION_LIMIT=10 + +# WeChat Mini Program config for login, phone binding, and mini program code generation. +WECHAT_APP_ID=wx_your_app_id +WECHAT_APP_SECRET=your_wechat_app_secret +# Use release for production, trial for experience version, develop for development version. +WECHAT_ENV_VERSION=release + +# SMS verification config. +# In production set SMS_ALLOW_TEST_CODE=false so the fixed test code cannot pass. +SMS_PROVIDER=aliyun +SMS_ALLOW_TEST_CODE=true +SMS_TEST_CODE=111111 +SMS_CODE_LENGTH=6 +SMS_CODE_TTL_SECONDS=300 +SMS_CODE_COOLDOWN_SECONDS=60 + +# Aliyun SMS OpenAPI config. The SMS template must contain a variable named ${code} +# unless ALIYUN_SMS_TEMPLATE_PARAM_KEY is changed. +ALIYUN_ACCESS_KEY_ID=your_aliyun_access_key_id +ALIYUN_ACCESS_KEY_SECRET=your_aliyun_access_key_secret +ALIYUN_SMS_ENDPOINT=dysmsapi.aliyuncs.com +ALIYUN_SMS_SIGN_NAME=your_sms_sign_name +ALIYUN_SMS_TEMPLATE_CODE=SMS_000000000 +ALIYUN_SMS_TEMPLATE_PARAM_KEY=code diff --git a/backend/README.md b/backend/README.md new file mode 100644 index 0000000..994662f --- /dev/null +++ b/backend/README.md @@ -0,0 +1,24 @@ +# 立方和教育推广机制后端 + +Node + Express 分层接口,用内存仓库模拟数据库,方便后续替换为 MySQL、PostgreSQL 或 MongoDB。 + +## Scripts + +```bash +npm install +npm run dev +``` + +默认服务地址: + +```text +http://localhost:3100/api +``` + +## Main Modules + +- `controllers/`: HTTP 入参和出参 +- `services/`: 推荐、积分、课程、管理台业务规则 +- `repositories/`: 数据访问层 +- `data/seed.js`: 初始模拟数据 +- `routes/`: API 路由聚合 diff --git a/backend/package-lock.json b/backend/package-lock.json new file mode 100644 index 0000000..2cc4080 --- /dev/null +++ b/backend/package-lock.json @@ -0,0 +1,1039 @@ +{ + "name": "lifanghe-education-backend", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "lifanghe-education-backend", + "version": "1.0.0", + "dependencies": { + "cors": "^2.8.5", + "express": "^4.19.2", + "morgan": "^1.10.0", + "mysql2": "^3.22.5" + } + }, + "node_modules/@types/node": { + "version": "26.0.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-26.0.1.tgz", + "integrity": "sha512-fc3KiUoBt6kie0N9bIW3E47vZsuaMf0PM2AaUpLCLT0s/LvX1nxAim6Fc049cNxODPpGm6qRAuUOB86SkRuPQw==", + "license": "MIT", + "peer": true, + "dependencies": { + "undici-types": "~8.3.0" + } + }, + "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/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/aws-ssl-profiles": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/aws-ssl-profiles/-/aws-ssl-profiles-1.1.2.tgz", + "integrity": "sha512-NZKeq9AfyQvEeNlN0zSYAaWrmBffJh3IELMZfRpJVWgrpEbtEpnjvzqBPf+mxoI287JohRDoa+/nsfqqiZmF6g==", + "license": "MIT", + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/basic-auth": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz", + "integrity": "sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==", + "license": "MIT", + "dependencies": { + "safe-buffer": "5.1.2" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/basic-auth/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "license": "MIT" + }, + "node_modules/body-parser": { + "version": "1.20.5", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.5.tgz", + "integrity": "sha512-3grm+/2tUOvu2cjJkvsIxrv/wVpfXQW4PsQHYm7yk4vfpu7Ekl6nEsYBoJUL6qDwZUx8wUhQ8tR2qz+ad9c9OA==", + "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.15.1", + "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/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/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/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.6", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.6.tgz", + "integrity": "sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw==", + "license": "MIT", + "dependencies": { + "object-assign": "^4", + "vary": "^1" + }, + "engines": { + "node": ">= 0.10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "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/denque": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/denque/-/denque-2.1.0.tgz", + "integrity": "sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==", + "license": "Apache-2.0", + "engines": { + "node": ">=0.10" + } + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "license": "MIT", + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/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/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/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/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.2", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.2.tgz", + "integrity": "sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==", + "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/express": { + "version": "4.22.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.22.2.tgz", + "integrity": "sha512-IuL+Elrou2ZvCFHs18/CIzy2Nzvo25nZ1/D2eIZlz7c+QUayAcYoiM2BthCjs+EBHVpjYjcuLDAiCWgeIX3X1Q==", + "license": "MIT", + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "~1.20.5", + "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.15.1", + "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/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/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/generate-function": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.3.1.tgz", + "integrity": "sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ==", + "license": "MIT", + "dependencies": { + "is-property": "^1.0.2" + } + }, + "node_modules/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/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/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/hasown": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.4.tgz", + "integrity": "sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "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/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/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "license": "ISC" + }, + "node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/is-property": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz", + "integrity": "sha512-Ks/IoX00TtClbGQr4TWXemAnktAQvYB7HzcCxDGqEZU6oCmb2INHuOoKxbtR+HFkmYWBKv/dOZtGRiAjDhj92g==", + "license": "MIT" + }, + "node_modules/long": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/long/-/long-5.3.2.tgz", + "integrity": "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==", + "license": "Apache-2.0" + }, + "node_modules/lru.min": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/lru.min/-/lru.min-1.1.4.tgz", + "integrity": "sha512-DqC6n3QQ77zdFpCMASA1a3Jlb64Hv2N2DciFGkO/4L9+q/IpIAuRlKOvCXabtRW6cQf8usbmM6BE/TOPysCdIA==", + "license": "MIT", + "engines": { + "bun": ">=1.0.0", + "deno": ">=1.30.0", + "node": ">=8.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wellwelwel" + } + }, + "node_modules/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/morgan": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.11.0.tgz", + "integrity": "sha512-zSkVu3t18r39pw4ixfBKvfZi3y2UOqr7d4WYwcj3m8nXpEQK4rPO6GLzs/CExoRgmX3y9EjmmcXqv6jq0SK46g==", + "license": "MIT", + "dependencies": { + "basic-auth": "~2.0.1", + "debug": "2.6.9", + "depd": "~2.0.0", + "on-finished": "~2.4.1", + "on-headers": "~1.1.0" + }, + "engines": { + "node": ">= 0.8.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "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/mysql2": { + "version": "3.22.5", + "resolved": "https://registry.npmjs.org/mysql2/-/mysql2-3.22.5.tgz", + "integrity": "sha512-95uZ2TrPWAZdwpB3vvvDbmEMcNG8yIeNCyu6GUcr/QnWEE/wXm7+mhOCsdQfWQDTV7qYT/PDUZ4U4UPP4AsXqQ==", + "license": "MIT", + "dependencies": { + "aws-ssl-profiles": "^1.1.2", + "denque": "^2.1.0", + "generate-function": "^2.3.1", + "iconv-lite": "^0.7.2", + "long": "^5.3.2", + "lru.min": "^1.1.4", + "named-placeholders": "^1.1.6", + "sql-escaper": "^1.3.3" + }, + "engines": { + "node": ">= 8.0" + }, + "peerDependencies": { + "@types/node": ">= 8" + } + }, + "node_modules/mysql2/node_modules/iconv-lite": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.2.tgz", + "integrity": "sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/named-placeholders": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/named-placeholders/-/named-placeholders-1.1.6.tgz", + "integrity": "sha512-Tz09sEL2EEuv5fFowm419c1+a/jSMiBjI9gHxVLrVdbUkkNUUfjsVYs9pVZu5oCon/kmRh9TfLEObFtkVxmY0w==", + "license": "MIT", + "dependencies": { + "lru.min": "^1.1.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "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/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/on-headers": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.1.0.tgz", + "integrity": "sha512-737ZY3yNnXy37FHkQxPzt4UZ2UWPWiCZWLvFZ4fu5cueciegX0zGPnrlY6bwRg4FdQOe9YU8MkmJwGhoMybl8A==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "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-to-regexp": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.13.tgz", + "integrity": "sha512-A/AGNMFN3c8bOlvV9RreMdrv7jsmF9XIfDeCd87+I8RNg6s78BhJxMu69NEMHBSJFxKidViTEdruRwEk/WIKqA==", + "license": "MIT" + }, + "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/qs": { + "version": "6.15.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.15.2.tgz", + "integrity": "sha512-Rzq0KEyX/w/tEybncDgdkZrJgVUsUMk3xjh3t5bv3S1HTAtg+uOYt72+ZfwiQwKdysThkTBdL/rTi6HDmX9Ddw==", + "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/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/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/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.1", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.1.tgz", + "integrity": "sha512-6x6dK6zJdpTzF4sQeNYxwtvBzf6Eg4GtlesS94HOvTudUeyK2WXAaIfmDgsyslYrRBeFIlsi54AYsFGUuhmvrQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.4", + "side-channel-list": "^1.0.1", + "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.1", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.1.tgz", + "integrity": "sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.4" + }, + "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/sql-escaper": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/sql-escaper/-/sql-escaper-1.3.3.tgz", + "integrity": "sha512-BsTCV265VpTp8tm1wyIm1xqQCS+Q9NHx2Sr+WcnUrgLrQ6yiDIvHYJV5gHxsj1lMBy2zm5twLaZao8Jd+S8JJw==", + "license": "MIT", + "engines": { + "bun": ">=1.0.0", + "deno": ">=2.0.0", + "node": ">=12.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/mysqljs/sql-escaper?sponsor=1" + } + }, + "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/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/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/undici-types": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-8.3.0.tgz", + "integrity": "sha512-j375ScV60dom+YkPFIfTLcOiPxkN/buHz5GobjLhixFuANaNs3C9l4GmrWqejgXWJ7BbJcFYpTEUkS1Ge8bpZQ==", + "license": "MIT", + "peer": true + }, + "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/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" + } + } + } +} diff --git a/backend/package.json b/backend/package.json new file mode 100644 index 0000000..fa42973 --- /dev/null +++ b/backend/package.json @@ -0,0 +1,16 @@ +{ + "name": "lifanghe-education-backend", + "version": "1.0.0", + "private": true, + "type": "commonjs", + "scripts": { + "dev": "node --watch src/server.js", + "start": "node src/server.js" + }, + "dependencies": { + "cors": "^2.8.5", + "express": "^4.19.2", + "morgan": "^1.10.0", + "mysql2": "^3.22.5" + } +} diff --git a/backend/sql/init.sql b/backend/sql/init.sql new file mode 100644 index 0000000..bbf8006 --- /dev/null +++ b/backend/sql/init.sql @@ -0,0 +1,220 @@ +CREATE DATABASE IF NOT EXISTS lifanghe_education DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; +USE lifanghe_education; + +CREATE TABLE IF NOT EXISTS roles ( + role VARCHAR(40) PRIMARY KEY, + name VARCHAR(80) NOT NULL, + permissions JSON NOT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +CREATE TABLE IF NOT EXISTS users ( + id VARCHAR(40) PRIMARY KEY, + username VARCHAR(80) NOT NULL UNIQUE, + password_hash CHAR(64) NULL, + role VARCHAR(40) NOT NULL, + role_name VARCHAR(80) NOT NULL, + name VARCHAR(80) NOT NULL, + phone VARCHAR(30) NULL UNIQUE, + wechat_openid VARCHAR(80) NULL UNIQUE, + wechat_unionid VARCHAR(80) NULL UNIQUE, + wechat_nickname VARCHAR(80) NULL, + wechat_avatar VARCHAR(500) NULL, + login_provider VARCHAR(30) NOT NULL DEFAULT 'password', + phone_bound TINYINT(1) NOT NULL DEFAULT 1, + phone_bound_at VARCHAR(32) NULL, + wechat_bound_at VARCHAR(32) NULL, + status VARCHAR(20) NOT NULL DEFAULT 'active', + last_login_at VARCHAR(32) NULL, + inviter_code VARCHAR(40) NULL UNIQUE, + child_id VARCHAR(40) NULL, + child_name VARCHAR(80) NULL, + child_grade VARCHAR(40) NULL, + child_focus VARCHAR(80) NULL, + trial_booking_limit INT NOT NULL DEFAULT 1, + created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + INDEX idx_users_role (role), + INDEX idx_users_phone (phone), + INDEX idx_users_login_provider (login_provider), + CONSTRAINT fk_users_role FOREIGN KEY (role) REFERENCES roles(role) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +CREATE TABLE IF NOT EXISTS point_accounts ( + user_id VARCHAR(40) PRIMARY KEY, + available INT NOT NULL DEFAULT 0, + pending INT NOT NULL DEFAULT 0, + frozen INT NOT NULL DEFAULT 0, + expiring INT NOT NULL DEFAULT 0, + CONSTRAINT fk_point_accounts_user FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +CREATE TABLE IF NOT EXISTS point_transactions ( + id VARCHAR(40) PRIMARY KEY, + user_id VARCHAR(40) NOT NULL, + title VARCHAR(200) NOT NULL, + amount INT NOT NULL, + status VARCHAR(30) NOT NULL, + reference_type VARCHAR(40) NULL, + reference_id VARCHAR(60) NULL, + created_at VARCHAR(32) NOT NULL, + INDEX idx_point_transactions_user (user_id), + INDEX idx_point_transactions_reference (reference_type, reference_id), + CONSTRAINT fk_point_transactions_user FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +CREATE TABLE IF NOT EXISTS point_expiry_rule ( + id INT PRIMARY KEY DEFAULT 1, + title VARCHAR(100) NOT NULL, + valid_days INT NOT NULL, + description VARCHAR(500) NOT NULL, + reminder VARCHAR(500) NOT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +CREATE TABLE IF NOT EXISTS point_expiry_schedules ( + id VARCHAR(40) PRIMARY KEY, + user_id VARCHAR(40) NOT NULL, + points INT NOT NULL, + expire_at VARCHAR(32) NOT NULL, + source VARCHAR(200) NOT NULL, + INDEX idx_point_expiry_user (user_id), + CONSTRAINT fk_point_expiry_user FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +CREATE TABLE IF NOT EXISTS referral_rules ( + event VARCHAR(40) PRIMARY KEY, + title VARCHAR(100) NOT NULL, + inviter INT NOT NULL, + invitee INT NOT NULL, + sort_order INT NOT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +CREATE TABLE IF NOT EXISTS referrals ( + id VARCHAR(40) PRIMARY KEY, + inviter_id VARCHAR(40) NOT NULL, + invitee_id VARCHAR(40) NULL, + name VARCHAR(80) NOT NULL, + phone VARCHAR(30) NOT NULL, + child_grade VARCHAR(40) NOT NULL, + status VARCHAR(40) NOT NULL, + reward INT NOT NULL DEFAULT 0, + channel VARCHAR(80) NOT NULL, + created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + INDEX idx_referrals_inviter (inviter_id), + CONSTRAINT fk_referrals_inviter FOREIGN KEY (inviter_id) REFERENCES users(id) ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +CREATE TABLE IF NOT EXISTS courses ( + id VARCHAR(40) PRIMARY KEY, + name VARCHAR(120) NOT NULL, + tags JSON NOT NULL, + next_time VARCHAR(32) NOT NULL, + points_back INT NOT NULL DEFAULT 0, + seats INT NOT NULL DEFAULT 0, + campus VARCHAR(80) NOT NULL, + teacher VARCHAR(80) NOT NULL, + trial_minutes INT NOT NULL DEFAULT 45, + status VARCHAR(30) NOT NULL DEFAULT 'active', + created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +CREATE TABLE IF NOT EXISTS appointments ( + id VARCHAR(40) PRIMARY KEY, + user_id VARCHAR(40) NOT NULL, + child_id VARCHAR(40) NULL, + course_id VARCHAR(40) NOT NULL, + status VARCHAR(30) NOT NULL, + created_at VARCHAR(40) NOT NULL, + INDEX idx_appointments_user (user_id), + INDEX idx_appointments_course (course_id), + CONSTRAINT fk_appointments_user FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE, + CONSTRAINT fk_appointments_course FOREIGN KEY (course_id) REFERENCES courses(id) ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +CREATE TABLE IF NOT EXISTS rewards ( + id VARCHAR(40) PRIMARY KEY, + name VARCHAR(120) NOT NULL, + cost INT NOT NULL, + type VARCHAR(60) NOT NULL, + stock INT NOT NULL DEFAULT 0, + description VARCHAR(500) NOT NULL DEFAULT '' +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +CREATE TABLE IF NOT EXISTS redemption_orders ( + id VARCHAR(40) PRIMARY KEY, + user_id VARCHAR(40) NOT NULL, + item_id VARCHAR(40) NOT NULL, + status VARCHAR(40) NOT NULL, + cost_points INT NOT NULL DEFAULT 0, + voucher_code VARCHAR(60) NULL UNIQUE, + voucher_status VARCHAR(40) NOT NULL DEFAULT 'not_issued', + created_at VARCHAR(40) NOT NULL, + reviewed_by VARCHAR(40) NULL, + reviewed_at VARCHAR(40) NULL, + rejected_reason VARCHAR(255) NULL, + expire_at VARCHAR(40) NULL, + used_at VARCHAR(40) NULL, + used_by VARCHAR(40) NULL, + verify_note VARCHAR(255) NULL, + INDEX idx_redemption_user (user_id), + INDEX idx_redemption_status (status), + INDEX idx_redemption_voucher (voucher_code), + CONSTRAINT fk_redemption_user FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE, + CONSTRAINT fk_redemption_reward FOREIGN KEY (item_id) REFERENCES rewards(id) ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +CREATE TABLE IF NOT EXISTS leads ( + id VARCHAR(40) PRIMARY KEY, + referral_id VARCHAR(40) NULL, + invitee_id VARCHAR(40) NULL, + parent VARCHAR(80) NOT NULL, + source VARCHAR(100) NOT NULL, + stage VARCHAR(40) NOT NULL, + advisor VARCHAR(80) NOT NULL, + risk VARCHAR(40) NOT NULL DEFAULT '正常', + channel VARCHAR(80) NOT NULL, + created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + INDEX idx_leads_referral (referral_id), + INDEX idx_leads_invitee (invitee_id) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +CREATE TABLE IF NOT EXISTS channel_stats ( + channel VARCHAR(80) PRIMARY KEY, + leads INT NOT NULL DEFAULT 0, + attended INT NOT NULL DEFAULT 0, + purchased INT NOT NULL DEFAULT 0 +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +INSERT INTO roles (role, name, permissions) VALUES +('parent', '家长', JSON_ARRAY()), +('super_admin', '超级管理员', JSON_ARRAY('*:*:*')), +('campus_admin', '校区管理员', JSON_ARRAY('dashboard:overview:view', 'system:user:view', 'system:role:view', 'leads:referral:view', 'leads:referral:advance', 'points:account:view', 'points:rule:edit', 'points:redemption:view', 'points:redemption:review', 'points:voucher:verify', 'courses:trial:view', 'courses:trial:add', 'courses:trial:edit', 'statistics:channel:view')), +('advisor', '课程顾问', JSON_ARRAY('dashboard:overview:view', 'leads:referral:view', 'leads:referral:advance', 'courses:trial:view', 'points:account:view', 'points:redemption:view')), +('teacher', '老师', JSON_ARRAY('dashboard:overview:view', 'leads:referral:view', 'courses:trial:view')), +('finance', '财务', JSON_ARRAY('dashboard:overview:view', 'points:account:view', 'points:account:adjust', 'points:rule:edit', 'points:reward:edit', 'points:redemption:view', 'points:redemption:review', 'points:voucher:verify', 'statistics:channel:view')) +ON DUPLICATE KEY UPDATE name = VALUES(name), permissions = VALUES(permissions); + +INSERT INTO users ( + id, username, password_hash, role, role_name, name, phone, + wechat_openid, wechat_unionid, wechat_nickname, wechat_avatar, + login_provider, phone_bound, phone_bound_at, wechat_bound_at, + status, last_login_at, inviter_code, child_id, child_name, child_grade, child_focus +) VALUES +('admin_001', 'admin', '240be518fabd2724ddb6f04eeb1da5967448d7e831c08c8fa822809f74c720a9', 'super_admin', '超级管理员', '系统管理员', '13800009999', NULL, NULL, NULL, NULL, 'password', 1, NULL, NULL, 'active', NULL, NULL, NULL, NULL, NULL, NULL) +ON DUPLICATE KEY UPDATE username = VALUES(username), password_hash = VALUES(password_hash), role = VALUES(role), role_name = VALUES(role_name), name = VALUES(name), phone = VALUES(phone), login_provider = VALUES(login_provider), phone_bound = VALUES(phone_bound), status = VALUES(status); + +INSERT INTO point_expiry_rule (id, title, valid_days, description, reminder) VALUES +(1, '积分有效期说明', 180, '积分自实际到账日起 180 天内有效,仅可兑换课程、测评和学习服务权益,不可提现或转赠。', '系统会在到期前 30 天进入“将过期”口径,运营可通过积分管理页提醒家长尽快兑换。') +ON DUPLICATE KEY UPDATE title = VALUES(title), valid_days = VALUES(valid_days), description = VALUES(description), reminder = VALUES(reminder); + +INSERT INTO referral_rules (event, title, inviter, invitee, sort_order) VALUES +('registered', '新家长注册', 20, 20, 1), +('booked', '预约试听', 50, 50, 2), +('attended', '确认到课', 150, 100, 3), +('purchased', '报名正价课', 800, 500, 4) +ON DUPLICATE KEY UPDATE title = VALUES(title), inviter = VALUES(inviter), invitee = VALUES(invitee), sort_order = VALUES(sort_order); + +INSERT INTO rewards (id, name, cost, type, stock, description) VALUES +('reward_001', '精品体验课 1 次', 800, '课程权益', 30, '适用于校区公开试听课,审核通过后生成课程券码,30 天内到店核销。'), +('reward_002', '学习规划咨询', 500, '服务权益', 50, '由课程顾问提供一次学习规划沟通,适合新生测评后使用。'), +('reward_003', '正价课抵扣券 100 元', 1000, '抵扣券', 20, '报名正价课程时抵扣 100 元,不可叠加现金活动使用。'), +('reward_004', '阶段测评报告', 300, '测评', 80, '兑换后安排一次阶段测评报告解读,帮助家长了解学习状态。') +ON DUPLICATE KEY UPDATE name = VALUES(name), cost = VALUES(cost), type = VALUES(type), stock = VALUES(stock), description = VALUES(description); diff --git a/backend/sql/migrations/20260630_add_wechat_phone_binding_fields.sql b/backend/sql/migrations/20260630_add_wechat_phone_binding_fields.sql new file mode 100644 index 0000000..d122254 --- /dev/null +++ b/backend/sql/migrations/20260630_add_wechat_phone_binding_fields.sql @@ -0,0 +1,145 @@ +USE lifanghe_education; + +ALTER TABLE users MODIFY password_hash CHAR(64) NULL; +ALTER TABLE users MODIFY phone VARCHAR(30) NULL; + +SET @schema_name = DATABASE(); + +SET @sql = ( + SELECT IF(COUNT(*) = 0, + 'ALTER TABLE users ADD COLUMN wechat_openid VARCHAR(80) NULL AFTER phone', + 'SELECT 1' + ) + FROM INFORMATION_SCHEMA.COLUMNS + WHERE TABLE_SCHEMA = @schema_name AND TABLE_NAME = 'users' AND COLUMN_NAME = 'wechat_openid' +); +PREPARE stmt FROM @sql; +EXECUTE stmt; +DEALLOCATE PREPARE stmt; + +SET @sql = ( + SELECT IF(COUNT(*) = 0, + 'ALTER TABLE users ADD COLUMN wechat_unionid VARCHAR(80) NULL AFTER wechat_openid', + 'SELECT 1' + ) + FROM INFORMATION_SCHEMA.COLUMNS + WHERE TABLE_SCHEMA = @schema_name AND TABLE_NAME = 'users' AND COLUMN_NAME = 'wechat_unionid' +); +PREPARE stmt FROM @sql; +EXECUTE stmt; +DEALLOCATE PREPARE stmt; + +SET @sql = ( + SELECT IF(COUNT(*) = 0, + 'ALTER TABLE users ADD COLUMN wechat_nickname VARCHAR(80) NULL AFTER wechat_unionid', + 'SELECT 1' + ) + FROM INFORMATION_SCHEMA.COLUMNS + WHERE TABLE_SCHEMA = @schema_name AND TABLE_NAME = 'users' AND COLUMN_NAME = 'wechat_nickname' +); +PREPARE stmt FROM @sql; +EXECUTE stmt; +DEALLOCATE PREPARE stmt; + +SET @sql = ( + SELECT IF(COUNT(*) = 0, + 'ALTER TABLE users ADD COLUMN wechat_avatar VARCHAR(500) NULL AFTER wechat_nickname', + 'SELECT 1' + ) + FROM INFORMATION_SCHEMA.COLUMNS + WHERE TABLE_SCHEMA = @schema_name AND TABLE_NAME = 'users' AND COLUMN_NAME = 'wechat_avatar' +); +PREPARE stmt FROM @sql; +EXECUTE stmt; +DEALLOCATE PREPARE stmt; + +SET @sql = ( + SELECT IF(COUNT(*) = 0, + 'ALTER TABLE users ADD COLUMN login_provider VARCHAR(30) NOT NULL DEFAULT ''password'' AFTER wechat_avatar', + 'SELECT 1' + ) + FROM INFORMATION_SCHEMA.COLUMNS + WHERE TABLE_SCHEMA = @schema_name AND TABLE_NAME = 'users' AND COLUMN_NAME = 'login_provider' +); +PREPARE stmt FROM @sql; +EXECUTE stmt; +DEALLOCATE PREPARE stmt; + +SET @sql = ( + SELECT IF(COUNT(*) = 0, + 'ALTER TABLE users ADD COLUMN phone_bound TINYINT(1) NOT NULL DEFAULT 1 AFTER login_provider', + 'SELECT 1' + ) + FROM INFORMATION_SCHEMA.COLUMNS + WHERE TABLE_SCHEMA = @schema_name AND TABLE_NAME = 'users' AND COLUMN_NAME = 'phone_bound' +); +PREPARE stmt FROM @sql; +EXECUTE stmt; +DEALLOCATE PREPARE stmt; + +SET @sql = ( + SELECT IF(COUNT(*) = 0, + 'ALTER TABLE users ADD COLUMN phone_bound_at VARCHAR(32) NULL AFTER phone_bound', + 'SELECT 1' + ) + FROM INFORMATION_SCHEMA.COLUMNS + WHERE TABLE_SCHEMA = @schema_name AND TABLE_NAME = 'users' AND COLUMN_NAME = 'phone_bound_at' +); +PREPARE stmt FROM @sql; +EXECUTE stmt; +DEALLOCATE PREPARE stmt; + +SET @sql = ( + SELECT IF(COUNT(*) = 0, + 'ALTER TABLE users ADD COLUMN wechat_bound_at VARCHAR(32) NULL AFTER phone_bound_at', + 'SELECT 1' + ) + FROM INFORMATION_SCHEMA.COLUMNS + WHERE TABLE_SCHEMA = @schema_name AND TABLE_NAME = 'users' AND COLUMN_NAME = 'wechat_bound_at' +); +PREPARE stmt FROM @sql; +EXECUTE stmt; +DEALLOCATE PREPARE stmt; + +SET @sql = ( + SELECT IF(COUNT(*) = 0, + 'ALTER TABLE users ADD UNIQUE KEY uk_users_wechat_openid (wechat_openid)', + 'SELECT 1' + ) + FROM INFORMATION_SCHEMA.STATISTICS + WHERE TABLE_SCHEMA = @schema_name AND TABLE_NAME = 'users' AND COLUMN_NAME = 'wechat_openid' AND NON_UNIQUE = 0 +); +PREPARE stmt FROM @sql; +EXECUTE stmt; +DEALLOCATE PREPARE stmt; + +SET @sql = ( + SELECT IF(COUNT(*) = 0, + 'ALTER TABLE users ADD UNIQUE KEY uk_users_wechat_unionid (wechat_unionid)', + 'SELECT 1' + ) + FROM INFORMATION_SCHEMA.STATISTICS + WHERE TABLE_SCHEMA = @schema_name AND TABLE_NAME = 'users' AND COLUMN_NAME = 'wechat_unionid' AND NON_UNIQUE = 0 +); +PREPARE stmt FROM @sql; +EXECUTE stmt; +DEALLOCATE PREPARE stmt; + +SET @sql = ( + SELECT IF(COUNT(*) = 0, + 'ALTER TABLE users ADD INDEX idx_users_login_provider (login_provider)', + 'SELECT 1' + ) + FROM INFORMATION_SCHEMA.STATISTICS + WHERE TABLE_SCHEMA = @schema_name AND TABLE_NAME = 'users' AND INDEX_NAME = 'idx_users_login_provider' +); +PREPARE stmt FROM @sql; +EXECUTE stmt; +DEALLOCATE PREPARE stmt; + +UPDATE users +SET + login_provider = COALESCE(login_provider, 'password'), + phone_bound = IF(phone IS NULL OR phone = '', 0, 1), + phone_bound_at = IF((phone IS NULL OR phone = ''), NULL, COALESCE(phone_bound_at, last_login_at)) +WHERE id IS NOT NULL; diff --git a/backend/sql/migrations/20260630_clear_demo_seed_data.sql b/backend/sql/migrations/20260630_clear_demo_seed_data.sql new file mode 100644 index 0000000..7729d20 --- /dev/null +++ b/backend/sql/migrations/20260630_clear_demo_seed_data.sql @@ -0,0 +1,12 @@ +USE lifanghe_education; + +DELETE FROM redemption_orders WHERE user_id IN ('parent_001', 'parent_002', 'parent_003'); +DELETE FROM appointments WHERE user_id IN ('parent_001', 'parent_002', 'parent_003'); +DELETE FROM referrals WHERE id IN ('rel_001', 'rel_002', 'rel_003'); +DELETE FROM point_expiry_schedules WHERE id IN ('exp_001', 'exp_002', 'exp_003'); +DELETE FROM point_transactions WHERE id IN ('pt_001', 'pt_002', 'pt_003', 'pt_004', 'pt_005'); +DELETE FROM point_accounts WHERE user_id IN ('parent_001', 'parent_002', 'parent_003'); +DELETE FROM leads WHERE id IN ('lead_001', 'lead_002', 'lead_003', 'lead_004', 'lead_005'); +DELETE FROM courses WHERE id IN ('course_001', 'course_002', 'course_003', 'course_004'); +DELETE FROM channel_stats WHERE channel IN ('朋友圈海报', '微信好友', 'H5链接', '顾问二维码'); +DELETE FROM users WHERE id IN ('parent_001', 'parent_002', 'parent_003', 'campus_001', 'advisor_001', 'teacher_001', 'finance_001'); diff --git a/backend/sql/migrations/20260630_clear_parent_permission_codes.sql b/backend/sql/migrations/20260630_clear_parent_permission_codes.sql new file mode 100644 index 0000000..cb522af --- /dev/null +++ b/backend/sql/migrations/20260630_clear_parent_permission_codes.sql @@ -0,0 +1,5 @@ +USE lifanghe_education; + +UPDATE roles +SET permissions = JSON_ARRAY() +WHERE role = 'parent'; diff --git a/backend/sql/migrations/20260701_add_points_rule_permission.sql b/backend/sql/migrations/20260701_add_points_rule_permission.sql new file mode 100644 index 0000000..5009832 --- /dev/null +++ b/backend/sql/migrations/20260701_add_points_rule_permission.sql @@ -0,0 +1,7 @@ +USE lifanghe_education; + +UPDATE roles +SET permissions = JSON_ARRAY_APPEND(permissions, '$', 'points:rule') +WHERE role IN ('campus_admin', 'finance') + AND JSON_CONTAINS(permissions, JSON_QUOTE('points:rule')) = 0 + AND JSON_CONTAINS(permissions, JSON_QUOTE('*:*:*')) = 0; diff --git a/backend/sql/migrations/20260701_appointment_unique_user.sql b/backend/sql/migrations/20260701_appointment_unique_user.sql new file mode 100644 index 0000000..67bac2e --- /dev/null +++ b/backend/sql/migrations/20260701_appointment_unique_user.sql @@ -0,0 +1,35 @@ +USE lifanghe_education; + +CREATE TABLE IF NOT EXISTS appointment_duplicates_backup LIKE appointments; + +INSERT INTO appointment_duplicates_backup +SELECT a.* +FROM appointments a +JOIN appointments b + ON a.user_id = b.user_id + AND (a.created_at < b.created_at OR (a.created_at = b.created_at AND a.id < b.id)) +LEFT JOIN appointment_duplicates_backup bak ON bak.id = a.id +WHERE bak.id IS NULL; + +DELETE a +FROM appointments a +JOIN appointments b + ON a.user_id = b.user_id + AND (a.created_at < b.created_at OR (a.created_at = b.created_at AND a.id < b.id)); + +SET @schema_name = DATABASE(); +SET @has_unique := ( + SELECT COUNT(1) + FROM INFORMATION_SCHEMA.STATISTICS + WHERE TABLE_SCHEMA = @schema_name + AND TABLE_NAME = 'appointments' + AND INDEX_NAME = 'uk_appointments_user' +); +SET @add_unique_sql := IF( + @has_unique = 0, + 'ALTER TABLE appointments ADD UNIQUE KEY uk_appointments_user (user_id)', + 'SELECT 1' +); +PREPARE add_unique_stmt FROM @add_unique_sql; +EXECUTE add_unique_stmt; +DEALLOCATE PREPARE add_unique_stmt; diff --git a/backend/sql/migrations/20260701_redemption_voucher_workflow.sql b/backend/sql/migrations/20260701_redemption_voucher_workflow.sql new file mode 100644 index 0000000..74df741 --- /dev/null +++ b/backend/sql/migrations/20260701_redemption_voucher_workflow.sql @@ -0,0 +1,57 @@ +ALTER TABLE redemption_orders + ADD COLUMN cost_points INT NOT NULL DEFAULT 0 AFTER status, + ADD COLUMN voucher_code VARCHAR(60) NULL UNIQUE AFTER cost_points, + ADD COLUMN voucher_status VARCHAR(40) NOT NULL DEFAULT 'not_issued' AFTER voucher_code, + ADD COLUMN reviewed_by VARCHAR(40) NULL AFTER created_at, + ADD COLUMN reviewed_at VARCHAR(40) NULL AFTER reviewed_by, + ADD COLUMN rejected_reason VARCHAR(255) NULL AFTER reviewed_at, + ADD COLUMN expire_at VARCHAR(40) NULL AFTER rejected_reason, + ADD COLUMN used_at VARCHAR(40) NULL AFTER expire_at, + ADD COLUMN used_by VARCHAR(40) NULL AFTER used_at, + ADD COLUMN verify_note VARCHAR(255) NULL AFTER used_by, + ADD INDEX idx_redemption_status (status), + ADD INDEX idx_redemption_voucher (voucher_code); + +UPDATE redemption_orders ro +LEFT JOIN rewards r ON r.id = ro.item_id +SET ro.cost_points = COALESCE(NULLIF(ro.cost_points, 0), r.cost, 0), + ro.voucher_status = CASE + WHEN ro.status = 'approved' THEN 'issued' + WHEN ro.status = 'rejected' THEN 'void' + ELSE ro.voucher_status + END; + +UPDATE roles +SET permissions = JSON_ARRAY( + 'dashboard:view', + 'system:user:view', + 'system:role:view', + 'leads:view', + 'leads:advance', + 'points:view', + 'points:redemption:view', + 'points:redemption:review', + 'points:voucher:verify', + 'courses:view', + 'courses:add', + 'courses:edit', + 'statistics:view' +) +WHERE role = 'campus_admin'; + +UPDATE roles +SET permissions = JSON_ARRAY('dashboard:view', 'leads:view', 'leads:advance', 'courses:view', 'points:view', 'points:redemption:view') +WHERE role = 'advisor'; + +UPDATE roles +SET permissions = JSON_ARRAY( + 'dashboard:view', + 'points:view', + 'points:adjust', + 'points:reward', + 'points:redemption:view', + 'points:redemption:review', + 'points:voucher:verify', + 'statistics:view' +) +WHERE role = 'finance'; diff --git a/backend/sql/migrations/20260701_reward_description_and_stock.sql b/backend/sql/migrations/20260701_reward_description_and_stock.sql new file mode 100644 index 0000000..8ca2d18 --- /dev/null +++ b/backend/sql/migrations/20260701_reward_description_and_stock.sql @@ -0,0 +1,18 @@ +ALTER TABLE rewards + ADD COLUMN description VARCHAR(500) NOT NULL DEFAULT '' AFTER stock; + +UPDATE rewards +SET stock = CASE id + WHEN 'reward_001' THEN 30 + WHEN 'reward_002' THEN 50 + WHEN 'reward_003' THEN 20 + WHEN 'reward_004' THEN 80 + ELSE stock +END, +description = CASE id + WHEN 'reward_001' THEN '适用于校区公开试听课,审核通过后生成课程券码,30 天内到店核销。' + WHEN 'reward_002' THEN '由课程顾问提供一次学习规划沟通,适合新生测评后使用。' + WHEN 'reward_003' THEN '报名正价课程时抵扣 100 元,不可叠加现金活动使用。' + WHEN 'reward_004' THEN '兑换后安排一次阶段测评报告解读,帮助家长了解学习状态。' + ELSE description +END; diff --git a/backend/sql/migrations/20260701_update_rbac_permissions.sql b/backend/sql/migrations/20260701_update_rbac_permissions.sql new file mode 100644 index 0000000..84e7915 --- /dev/null +++ b/backend/sql/migrations/20260701_update_rbac_permissions.sql @@ -0,0 +1,37 @@ +USE lifanghe_education; + +UPDATE roles +SET permissions = JSON_ARRAY() +WHERE role = 'parent'; + +UPDATE roles +SET permissions = JSON_ARRAY('*:*:*') +WHERE role = 'super_admin'; + +UPDATE roles +SET permissions = JSON_ARRAY( + 'dashboard:view', + 'system:user:view', + 'system:role:view', + 'leads:view', + 'leads:advance', + 'points:view', + 'points:rule', + 'courses:view', + 'courses:add', + 'courses:edit', + 'statistics:view' +) +WHERE role = 'campus_admin'; + +UPDATE roles +SET permissions = JSON_ARRAY('dashboard:view', 'leads:view', 'leads:advance', 'courses:view', 'points:view') +WHERE role = 'advisor'; + +UPDATE roles +SET permissions = JSON_ARRAY('dashboard:view', 'leads:view', 'courses:view') +WHERE role = 'teacher'; + +UPDATE roles +SET permissions = JSON_ARRAY('dashboard:view', 'points:view', 'points:adjust', 'points:rule', 'points:reward', 'statistics:view') +WHERE role = 'finance'; diff --git a/backend/sql/migrations/20260703_add_lead_referral_identity.sql b/backend/sql/migrations/20260703_add_lead_referral_identity.sql new file mode 100644 index 0000000..2e32a35 --- /dev/null +++ b/backend/sql/migrations/20260703_add_lead_referral_identity.sql @@ -0,0 +1,21 @@ +ALTER TABLE leads + ADD COLUMN referral_id VARCHAR(40) NULL AFTER id, + ADD COLUMN invitee_id VARCHAR(40) NULL AFTER referral_id, + ADD INDEX idx_leads_referral (referral_id), + ADD INDEX idx_leads_invitee (invitee_id); + +UPDATE leads l +JOIN referrals r +JOIN users inviter ON inviter.id = r.inviter_id +LEFT JOIN users invitee ON invitee.id = r.invitee_id +SET l.referral_id = r.id, + l.invitee_id = r.invitee_id, + l.parent = COALESCE(invitee.name, r.name) +WHERE l.referral_id IS NULL + AND ( + l.parent = r.name + OR l.parent = COALESCE(invitee.name, r.name) + OR l.parent = CONCAT('家长', RIGHT(r.phone, 4)) + ) + AND (l.source = inviter.name OR l.source = inviter.id OR l.source = inviter.phone) + AND (l.channel = r.channel OR l.channel = '' OR r.channel = ''); diff --git a/backend/sql/migrations/20260709_add_point_transaction_reference.sql b/backend/sql/migrations/20260709_add_point_transaction_reference.sql new file mode 100644 index 0000000..4e06894 --- /dev/null +++ b/backend/sql/migrations/20260709_add_point_transaction_reference.sql @@ -0,0 +1,37 @@ +SET @schema_name = DATABASE(); + +SET @sql = ( + SELECT IF(COUNT(*) = 0, + 'ALTER TABLE point_transactions ADD COLUMN reference_type VARCHAR(40) NULL AFTER status', + 'SELECT 1' + ) + FROM INFORMATION_SCHEMA.COLUMNS + WHERE TABLE_SCHEMA = @schema_name AND TABLE_NAME = 'point_transactions' AND COLUMN_NAME = 'reference_type' +); +PREPARE stmt FROM @sql; +EXECUTE stmt; +DEALLOCATE PREPARE stmt; + +SET @sql = ( + SELECT IF(COUNT(*) = 0, + 'ALTER TABLE point_transactions ADD COLUMN reference_id VARCHAR(60) NULL AFTER reference_type', + 'SELECT 1' + ) + FROM INFORMATION_SCHEMA.COLUMNS + WHERE TABLE_SCHEMA = @schema_name AND TABLE_NAME = 'point_transactions' AND COLUMN_NAME = 'reference_id' +); +PREPARE stmt FROM @sql; +EXECUTE stmt; +DEALLOCATE PREPARE stmt; + +SET @sql = ( + SELECT IF(COUNT(*) = 0, + 'ALTER TABLE point_transactions ADD INDEX idx_point_transactions_reference (reference_type, reference_id)', + 'SELECT 1' + ) + FROM INFORMATION_SCHEMA.STATISTICS + WHERE TABLE_SCHEMA = @schema_name AND TABLE_NAME = 'point_transactions' AND INDEX_NAME = 'idx_point_transactions_reference' +); +PREPARE stmt FROM @sql; +EXECUTE stmt; +DEALLOCATE PREPARE stmt; diff --git a/backend/sql/migrations/20260721_normalize_permission_codes.sql b/backend/sql/migrations/20260721_normalize_permission_codes.sql new file mode 100644 index 0000000..4d0a904 --- /dev/null +++ b/backend/sql/migrations/20260721_normalize_permission_codes.sql @@ -0,0 +1,47 @@ +UPDATE roles +SET permissions = JSON_REPLACE(permissions, JSON_UNQUOTE(JSON_SEARCH(permissions, 'one', 'dashboard:view')), 'dashboard:overview:view') +WHERE JSON_SEARCH(permissions, 'one', 'dashboard:view') IS NOT NULL; + +UPDATE roles +SET permissions = JSON_REPLACE(permissions, JSON_UNQUOTE(JSON_SEARCH(permissions, 'one', 'leads:view')), 'leads:referral:view') +WHERE JSON_SEARCH(permissions, 'one', 'leads:view') IS NOT NULL; + +UPDATE roles +SET permissions = JSON_REPLACE(permissions, JSON_UNQUOTE(JSON_SEARCH(permissions, 'one', 'leads:advance')), 'leads:referral:advance') +WHERE JSON_SEARCH(permissions, 'one', 'leads:advance') IS NOT NULL; + +UPDATE roles +SET permissions = JSON_REPLACE(permissions, JSON_UNQUOTE(JSON_SEARCH(permissions, 'one', 'points:view')), 'points:account:view') +WHERE JSON_SEARCH(permissions, 'one', 'points:view') IS NOT NULL; + +UPDATE roles +SET permissions = JSON_REPLACE(permissions, JSON_UNQUOTE(JSON_SEARCH(permissions, 'one', 'points:adjust')), 'points:account:adjust') +WHERE JSON_SEARCH(permissions, 'one', 'points:adjust') IS NOT NULL; + +UPDATE roles +SET permissions = JSON_REPLACE(permissions, JSON_UNQUOTE(JSON_SEARCH(permissions, 'one', 'points:rule')), 'points:rule:edit') +WHERE JSON_SEARCH(permissions, 'one', 'points:rule') IS NOT NULL; + +UPDATE roles +SET permissions = JSON_REPLACE(permissions, JSON_UNQUOTE(JSON_SEARCH(permissions, 'one', 'points:reward')), 'points:reward:edit') +WHERE JSON_SEARCH(permissions, 'one', 'points:reward') IS NOT NULL; + +UPDATE roles +SET permissions = JSON_REPLACE(permissions, JSON_UNQUOTE(JSON_SEARCH(permissions, 'one', 'courses:view')), 'courses:trial:view') +WHERE JSON_SEARCH(permissions, 'one', 'courses:view') IS NOT NULL; + +UPDATE roles +SET permissions = JSON_REPLACE(permissions, JSON_UNQUOTE(JSON_SEARCH(permissions, 'one', 'courses:add')), 'courses:trial:add') +WHERE JSON_SEARCH(permissions, 'one', 'courses:add') IS NOT NULL; + +UPDATE roles +SET permissions = JSON_REPLACE(permissions, JSON_UNQUOTE(JSON_SEARCH(permissions, 'one', 'courses:edit')), 'courses:trial:edit') +WHERE JSON_SEARCH(permissions, 'one', 'courses:edit') IS NOT NULL; + +UPDATE roles +SET permissions = JSON_REPLACE(permissions, JSON_UNQUOTE(JSON_SEARCH(permissions, 'one', 'courses:delete')), 'courses:trial:delete') +WHERE JSON_SEARCH(permissions, 'one', 'courses:delete') IS NOT NULL; + +UPDATE roles +SET permissions = JSON_REPLACE(permissions, JSON_UNQUOTE(JSON_SEARCH(permissions, 'one', 'statistics:view')), 'statistics:channel:view') +WHERE JSON_SEARCH(permissions, 'one', 'statistics:view') IS NOT NULL; diff --git a/backend/sql/migrations/20260722_account_trial_booking_limit.sql b/backend/sql/migrations/20260722_account_trial_booking_limit.sql new file mode 100644 index 0000000..b99238a --- /dev/null +++ b/backend/sql/migrations/20260722_account_trial_booking_limit.sql @@ -0,0 +1,51 @@ +USE lifanghe_education; + +SET @schema_name = DATABASE(); + +SET @has_trial_booking_limit := ( + SELECT COUNT(1) + FROM INFORMATION_SCHEMA.COLUMNS + WHERE TABLE_SCHEMA = @schema_name + AND TABLE_NAME = 'users' + AND COLUMN_NAME = 'trial_booking_limit' +); +SET @add_trial_booking_limit_sql := IF( + @has_trial_booking_limit = 0, + 'ALTER TABLE users ADD COLUMN trial_booking_limit INT NOT NULL DEFAULT 1 AFTER child_focus', + 'SELECT 1' +); +PREPARE add_trial_booking_limit_stmt FROM @add_trial_booking_limit_sql; +EXECUTE add_trial_booking_limit_stmt; +DEALLOCATE PREPARE add_trial_booking_limit_stmt; + +SET @has_unique_user_index := ( + SELECT COUNT(1) + FROM INFORMATION_SCHEMA.STATISTICS + WHERE TABLE_SCHEMA = @schema_name + AND TABLE_NAME = 'appointments' + AND INDEX_NAME = 'uk_appointments_user' +); +SET @drop_unique_user_index_sql := IF( + @has_unique_user_index > 0, + 'ALTER TABLE appointments DROP INDEX uk_appointments_user', + 'SELECT 1' +); +PREPARE drop_unique_user_index_stmt FROM @drop_unique_user_index_sql; +EXECUTE drop_unique_user_index_stmt; +DEALLOCATE PREPARE drop_unique_user_index_stmt; + +SET @has_appointment_user_index := ( + SELECT COUNT(1) + FROM INFORMATION_SCHEMA.STATISTICS + WHERE TABLE_SCHEMA = @schema_name + AND TABLE_NAME = 'appointments' + AND INDEX_NAME = 'idx_appointments_user' +); +SET @add_appointment_user_index_sql := IF( + @has_appointment_user_index = 0, + 'ALTER TABLE appointments ADD INDEX idx_appointments_user (user_id)', + 'SELECT 1' +); +PREPARE add_appointment_user_index_stmt FROM @add_appointment_user_index_sql; +EXECUTE add_appointment_user_index_stmt; +DEALLOCATE PREPARE add_appointment_user_index_stmt; diff --git a/backend/src/app.js b/backend/src/app.js new file mode 100644 index 0000000..476703a --- /dev/null +++ b/backend/src/app.js @@ -0,0 +1,50 @@ +const express = require('express') +const cors = require('cors') +const morgan = require('morgan') +const fs = require('fs') +const path = require('path') +const { env } = require('./config/env') +const { router } = require('./routes') +const { errorHandler } = require('./middleware/errorHandler') + +const app = express() + +app.disable('etag') +app.use(cors()) +app.use(express.json()) +app.use(morgan('dev')) +app.use('/uploads', express.static(path.resolve(__dirname, '../uploads'))) + +const pcAdminDistDir = env.pcAdminDistDir + ? path.resolve(env.pcAdminDistDir) + : path.resolve(__dirname, '../public/pc-admin') +const pcAdminIndex = path.join(pcAdminDistDir, 'index.html') +const hasPcAdmin = fs.existsSync(pcAdminIndex) +if (hasPcAdmin) { + app.use(express.static(pcAdminDistDir)) +} + +app.get('/health', (req, res) => { + res.json({ ok: true, service: 'lifanghe-education-api' }) +}) + +app.use('/api', (req, res, next) => { + res.set({ + 'Cache-Control': 'no-store, no-cache, must-revalidate, proxy-revalidate', + Pragma: 'no-cache', + Expires: '0', + 'Surrogate-Control': 'no-store', + }) + next() +}, router) + +if (hasPcAdmin) { + app.get('*', (req, res, next) => { + if (req.path.startsWith('/api') || req.path.startsWith('/uploads')) return next() + return res.sendFile(pcAdminIndex) + }) +} + +app.use(errorHandler) + +module.exports = { app } diff --git a/backend/src/config/env.js b/backend/src/config/env.js new file mode 100644 index 0000000..2029a38 --- /dev/null +++ b/backend/src/config/env.js @@ -0,0 +1,77 @@ +const fs = require('fs') +const path = require('path') + +function loadDotEnv(filePath) { + if (!fs.existsSync(filePath)) return + const lines = fs.readFileSync(filePath, 'utf8').split(/\r?\n/) + for (const line of lines) { + const trimmed = line.trim() + if (!trimmed || trimmed.startsWith('#')) continue + const match = trimmed.match(/^([A-Za-z_][A-Za-z0-9_]*)\s*=\s*(.*)$/) + if (!match) continue + const key = match[1] + let value = match[2].trim() + if ((value.startsWith('"') && value.endsWith('"')) || (value.startsWith("'") && value.endsWith("'"))) { + value = value.slice(1, -1) + } + if (process.env[key] === undefined || process.env[key] === '') { + process.env[key] = value + } + } +} + +loadDotEnv(path.resolve(__dirname, '../../.env')) + +function readBool(value, fallback = false) { + if (value === undefined || value === '') return fallback + return ['1', 'true', 'yes', 'on'].includes(String(value).trim().toLowerCase()) +} + +const nodeEnv = process.env.NODE_ENV || 'development' +const sessionSecret = process.env.AUTH_SESSION_SECRET || 'lifanghe-development-session-secret' +if (nodeEnv === 'production' && (!process.env.AUTH_SESSION_SECRET || sessionSecret.length < 32)) { + throw new Error('生产环境必须配置至少 32 位的 AUTH_SESSION_SECRET') +} + +const env = { + nodeEnv, + port: Number(process.env.PORT || 3100), + publicBaseUrl: process.env.PUBLIC_BASE_URL || '', + pcAdminDistDir: process.env.PC_ADMIN_DIST_DIR || '', + dbClient: process.env.DB_CLIENT || (process.env.MYSQL_HOST ? 'mysql' : 'memory'), + auth: { + sessionSecret, + sessionTtlHours: Number(process.env.AUTH_SESSION_TTL_HOURS || 168), + }, + mysql: { + host: process.env.MYSQL_HOST || '127.0.0.1', + port: Number(process.env.MYSQL_PORT || 3306), + user: process.env.MYSQL_USER || 'lifanghe', + password: process.env.MYSQL_PASSWORD || 'lifanghe123', + database: process.env.MYSQL_DATABASE || 'lifanghe_education', + connectionLimit: Number(process.env.MYSQL_CONNECTION_LIMIT || 10), + }, + wechat: { + appId: process.env.WECHAT_APP_ID || '', + appSecret: process.env.WECHAT_APP_SECRET || '', + envVersion: process.env.WECHAT_ENV_VERSION || 'release', + }, + sms: { + provider: process.env.SMS_PROVIDER || 'aliyun', + allowTestCode: readBool(process.env.SMS_ALLOW_TEST_CODE, true), + testCode: process.env.SMS_TEST_CODE || '111111', + codeLength: Number(process.env.SMS_CODE_LENGTH || 6), + codeTtlSeconds: Number(process.env.SMS_CODE_TTL_SECONDS || 300), + codeCooldownSeconds: Number(process.env.SMS_CODE_COOLDOWN_SECONDS || 60), + aliyun: { + endpoint: process.env.ALIYUN_SMS_ENDPOINT || 'dysmsapi.aliyuncs.com', + accessKeyId: process.env.ALIYUN_ACCESS_KEY_ID || '', + accessKeySecret: process.env.ALIYUN_ACCESS_KEY_SECRET || '', + signName: process.env.ALIYUN_SMS_SIGN_NAME || '', + templateCode: process.env.ALIYUN_SMS_TEMPLATE_CODE || '', + templateParamKey: process.env.ALIYUN_SMS_TEMPLATE_PARAM_KEY || 'code', + }, + }, +} + +module.exports = { env } diff --git a/backend/src/constants/permissions.js b/backend/src/constants/permissions.js new file mode 100644 index 0000000..f34bfc0 --- /dev/null +++ b/backend/src/constants/permissions.js @@ -0,0 +1,160 @@ +const PERMISSION_TREE = [ + { + id: 'dashboard', + label: '数据驾驶舱', + children: [ + { id: 'dashboard:overview:view', label: '查看驾驶舱', permission: 'dashboard:overview:view' }, + ], + }, + { + id: 'system', + label: '系统管理', + children: [ + { + id: 'system:user', + label: '用户管理', + children: [ + { id: 'system:user:view', label: '查看用户', permission: 'system:user:view' }, + { id: 'system:user:add', label: '新增用户', permission: 'system:user:add' }, + { id: 'system:user:edit', label: '编辑用户', permission: 'system:user:edit' }, + { id: 'system:user:delete', label: '删除用户', permission: 'system:user:delete' }, + { id: 'system:user:role', label: '分配角色', permission: 'system:user:role' }, + { id: 'system:user:status', label: '启停账号', permission: 'system:user:status' }, + ], + }, + { + id: 'system:role', + label: '角色权限', + children: [ + { id: 'system:role:view', label: '查看角色', permission: 'system:role:view' }, + { id: 'system:role:edit', label: '配置权限', permission: 'system:role:edit' }, + ], + }, + ], + }, + { + id: 'leads', + label: '线索管理', + children: [ + { id: 'leads:referral:view', label: '查看线索', permission: 'leads:referral:view' }, + { id: 'leads:referral:advance', label: '推进线索', permission: 'leads:referral:advance' }, + ], + }, + { + id: 'points', + label: '积分管理', + children: [ + { id: 'points:account:view', label: '查看积分', permission: 'points:account:view' }, + { id: 'points:account:adjust', label: '调整积分', permission: 'points:account:adjust' }, + { id: 'points:rule:edit', label: '维护积分规则', permission: 'points:rule:edit' }, + { id: 'points:reward:edit', label: '维护兑换项', permission: 'points:reward:edit' }, + { id: 'points:redemption:view', label: '查看兑换申请', permission: 'points:redemption:view' }, + { id: 'points:redemption:review', label: '审核兑换申请', permission: 'points:redemption:review' }, + { id: 'points:voucher:verify', label: '核销权益券码', permission: 'points:voucher:verify' }, + ], + }, + { + id: 'courses', + label: '课程管理', + children: [ + { id: 'courses:trial:view', label: '查看课程', permission: 'courses:trial:view' }, + { id: 'courses:trial:add', label: '新增课程', permission: 'courses:trial:add' }, + { id: 'courses:trial:edit', label: '编辑课程', permission: 'courses:trial:edit' }, + { id: 'courses:trial:delete', label: '删除课程', permission: 'courses:trial:delete' }, + ], + }, + { + id: 'statistics', + label: '数据统计', + children: [ + { id: 'statistics:channel:view', label: '查看统计', permission: 'statistics:channel:view' }, + ], + }, +] + +const ROLE_PERMISSIONS = { + parent: [], + super_admin: ['*:*:*'], + campus_admin: [ + 'dashboard:overview:view', + 'system:user:view', + 'system:role:view', + 'leads:referral:view', + 'leads:referral:advance', + 'points:account:view', + 'points:rule:edit', + 'points:redemption:view', + 'points:redemption:review', + 'points:voucher:verify', + 'courses:trial:view', + 'courses:trial:add', + 'courses:trial:edit', + 'statistics:channel:view', + ], + advisor: ['dashboard:overview:view', 'leads:referral:view', 'leads:referral:advance', 'courses:trial:view', 'points:account:view', 'points:redemption:view'], + teacher: ['dashboard:overview:view', 'leads:referral:view', 'courses:trial:view'], + finance: ['dashboard:overview:view', 'points:account:view', 'points:account:adjust', 'points:rule:edit', 'points:reward:edit', 'points:redemption:view', 'points:redemption:review', 'points:voucher:verify', 'statistics:channel:view'], +} + +function flattenPermissions(nodes = PERMISSION_TREE) { + return nodes.flatMap((node) => { + const current = node.permission ? [node.permission] : [] + return current.concat(flattenPermissions(node.children || [])) + }) +} + +const ALL_PERMISSIONS = flattenPermissions() + +const LEGACY_PERMISSION_MAP = { + 'dashboard:view': ['dashboard:overview:view'], + 'leads:view': ['leads:referral:view'], + 'leads:advance': ['leads:referral:advance'], + 'points:view': ['points:account:view'], + 'points:adjust': ['points:account:adjust'], + 'points:rule': ['points:rule:edit'], + 'points:reward': ['points:reward:edit'], + 'courses:view': ['courses:trial:view'], + 'courses:add': ['courses:trial:add'], + 'courses:edit': ['courses:trial:edit'], + 'courses:delete': ['courses:trial:delete'], + 'statistics:view': ['statistics:channel:view'], + 账号权限: ['system:user:view', 'system:user:add', 'system:user:edit', 'system:user:delete', 'system:user:role', 'system:user:status', 'system:role:view', 'system:role:edit'], + 活动配置: ['courses:trial:view', 'courses:trial:add', 'courses:trial:edit', 'courses:trial:delete'], + 积分规则: ['points:account:view', 'points:account:adjust', 'points:rule:edit', 'points:reward:edit', 'points:redemption:view', 'points:redemption:review', 'points:voucher:verify'], + 财务数据: ['points:account:view', 'statistics:channel:view'], + 线索分配: ['leads:referral:view', 'leads:referral:advance'], + 校区数据: ['dashboard:overview:view', 'statistics:channel:view', 'courses:trial:view'], + 兑换审核: ['points:account:view', 'points:redemption:view', 'points:redemption:review', 'points:voucher:verify'], + 线索跟进: ['leads:referral:view', 'leads:referral:advance'], + 预约管理: ['courses:trial:view'], + 到课确认: ['leads:referral:view', 'courses:trial:view'], + 课消记录: ['courses:trial:view', 'statistics:channel:view'], + 订单核对: ['statistics:channel:view'], + 积分冲正: ['points:account:view', 'points:account:adjust'], +} + +function normalizePermissions(permissions = []) { + const normalized = permissions.flatMap((item) => LEGACY_PERMISSION_MAP[item] || item) + return sanitizePermissions(normalized) +} + +function hasPermission(account, required = []) { + const permissions = account?.permissions || [] + if (!required.length) return true + if (permissions.includes('*:*:*')) return true + return required.some((item) => permissions.includes(item)) +} + +function sanitizePermissions(permissions = []) { + const allowed = new Set(['*:*:*', ...ALL_PERMISSIONS]) + return [...new Set(permissions.filter((item) => allowed.has(item)))] +} + +module.exports = { + ALL_PERMISSIONS, + PERMISSION_TREE, + ROLE_PERMISSIONS, + hasPermission, + normalizePermissions, + sanitizePermissions, +} diff --git a/backend/src/controllers/adminController.js b/backend/src/controllers/adminController.js new file mode 100644 index 0000000..866382f --- /dev/null +++ b/backend/src/controllers/adminController.js @@ -0,0 +1,121 @@ +const { adminService } = require('../services') + +async function getDashboard(req, res, next) { + try { + res.json({ ok: true, data: await adminService.getDashboard() }) + } catch (error) { + next(error) + } +} + +async function getLeads(req, res, next) { + try { + res.json({ ok: true, data: await adminService.listLeads(req.query) }) + } catch (error) { + next(error) + } +} + +async function updateLeadStage(req, res, next) { + try { + res.json({ ok: true, data: await adminService.updateLeadStage(req.params.id, req.body.stage) }) + } catch (error) { + next(error) + } +} + +async function confirmLeadPurchase(req, res, next) { + try { + res.json({ ok: true, data: await adminService.confirmLeadPurchase(req.params.id) }) + } catch (error) { + next(error) + } +} + +async function getPcOverview(req, res, next) { + try { + res.json({ ok: true, data: await adminService.getPcOverview(req.query) }) + } catch (error) { + next(error) + } +} + +async function getAccounts(req, res, next) { + try { + res.json({ ok: true, data: await adminService.getAccounts(req.query) }) + } catch (error) { + next(error) + } +} + +async function getRoles(req, res, next) { + try { + res.json({ ok: true, data: await adminService.getRoles() }) + } catch (error) { + next(error) + } +} + +async function updateRolePermissions(req, res, next) { + try { + res.json({ ok: true, data: await adminService.updateRolePermissions(req.params.role, req.body) }) + } catch (error) { + next(error) + } +} + +async function createAccount(req, res, next) { + try { + res.status(201).json({ ok: true, data: await adminService.createAccount(req.body) }) + } catch (error) { + next(error) + } +} + +async function updateAccount(req, res, next) { + try { + res.json({ ok: true, data: await adminService.updateAccount(req.params.id, req.body, req.operator) }) + } catch (error) { + next(error) + } +} + +async function deleteAccount(req, res, next) { + try { + res.json({ ok: true, data: await adminService.deleteAccount(req.params.id) }) + } catch (error) { + next(error) + } +} + +async function updateAccountRole(req, res, next) { + try { + res.json({ ok: true, data: await adminService.updateAccountRole(req.params.id, req.body.role) }) + } catch (error) { + next(error) + } +} + +async function updateAccountStatus(req, res, next) { + try { + res.json({ ok: true, data: await adminService.updateAccountStatus(req.params.id, req.body.status) }) + } catch (error) { + next(error) + } +} + +module.exports = { + getDashboard, + getLeads, + confirmLeadPurchase, + updateLeadStage, + getPcOverview, + getAccounts, + getRoles, + createAccount, + updateAccount, + deleteAccount, + updateAccountRole, + updateAccountStatus, + updateRolePermissions, +} diff --git a/backend/src/controllers/authController.js b/backend/src/controllers/authController.js new file mode 100644 index 0000000..07249b8 --- /dev/null +++ b/backend/src/controllers/authController.js @@ -0,0 +1,86 @@ +const { authService } = require('../services') + +async function login(req, res, next) { + try { + res.json({ ok: true, data: await authService.login(req.body) }) + } catch (error) { + next(error) + } +} + +async function phoneLogin(req, res, next) { + try { + res.json({ ok: true, data: await authService.loginByPhone(req.body) }) + } catch (error) { + next(error) + } +} + +async function sendSmsCode(req, res, next) { + try { + const data = await authService.sendSmsCode(req.body) + res.json({ ok: true, data, message: data.message || '验证码已发送' }) + } catch (error) { + next(error) + } +} + +async function wechatLogin(req, res, next) { + try { + res.json({ ok: true, data: await authService.loginByWechat(req.body) }) + } catch (error) { + next(error) + } +} + +async function bindWechatPhone(req, res, next) { + try { + res.json({ ok: true, data: await authService.bindWechatPhone(req.body) }) + } catch (error) { + next(error) + } +} + +async function updateProfile(req, res, next) { + try { + res.json({ ok: true, data: await authService.updateProfile(req.account.id, req.body) }) + } catch (error) { + next(error) + } +} + +async function updatePassword(req, res, next) { + try { + res.json({ ok: true, data: await authService.updatePassword(req.account.id, req.body) }) + } catch (error) { + next(error) + } +} + +async function updatePhone(req, res, next) { + try { + res.json({ ok: true, data: await authService.updatePhone(req.account.id, req.body) }) + } catch (error) { + next(error) + } +} + +async function current(req, res, next) { + try { + res.json({ ok: true, data: await authService.current(req.account.id) }) + } catch (error) { + next(error) + } +} + +module.exports = { + login, + phoneLogin, + sendSmsCode, + wechatLogin, + bindWechatPhone, + updateProfile, + updatePassword, + updatePhone, + current, +} diff --git a/backend/src/controllers/bootstrapController.js b/backend/src/controllers/bootstrapController.js new file mode 100644 index 0000000..11f7ac8 --- /dev/null +++ b/backend/src/controllers/bootstrapController.js @@ -0,0 +1,33 @@ +const { adminService, courseService, referralService, repository } = require('../services') +const { hasPermission } = require('../constants/permissions') + +async function getBootstrap(req, res, next) { + try { + const profile = await repository.findUserById(req.account.id) + if (!profile) { + const error = new Error('账号不存在') + error.status = 404 + throw error + } + const safeProfile = await repository.withPermissions(profile) + const account = await repository.getPointAccount(profile.id) + const referralCenter = await referralService.getCenter(profile.id) + + res.json({ + ok: true, + data: { + profile: { ...safeProfile, points: account }, + points: account, + stats: referralCenter.stats, + referralStats: referralCenter.stats, + rules: referralCenter.rules, + courses: await courseService.listCourses(), + admin: hasPermission(safeProfile, ['dashboard:overview:view']) ? await adminService.getDashboard() : null, + }, + }) + } catch (error) { + next(error) + } +} + +module.exports = { getBootstrap } diff --git a/backend/src/controllers/courseController.js b/backend/src/controllers/courseController.js new file mode 100644 index 0000000..2557344 --- /dev/null +++ b/backend/src/controllers/courseController.js @@ -0,0 +1,94 @@ +const { courseService } = require('../services') + +async function listCourses(req, res, next) { + try { + res.json({ ok: true, data: await courseService.listCourses(req.query) }) + } catch (error) { + next(error) + } +} + +async function listAdminCourses(req, res, next) { + try { + res.json({ ok: true, data: await courseService.listAdminCourses(req.query) }) + } catch (error) { + next(error) + } +} + +async function getAdminCourse(req, res, next) { + try { + res.json({ ok: true, data: await courseService.getAdminCourse(req.params.id) }) + } catch (error) { + next(error) + } +} + +async function listAppointments(req, res, next) { + try { + res.json({ ok: true, data: await courseService.listAppointments(req.query) }) + } catch (error) { + next(error) + } +} + +async function listUserAppointments(req, res, next) { + try { + res.json({ ok: true, data: await courseService.listUserAppointments(req.account.id) }) + } catch (error) { + next(error) + } +} + +async function attendAppointment(req, res, next) { + try { + res.json({ ok: true, data: await courseService.attendAppointment(req.params.id) }) + } catch (error) { + next(error) + } +} + +async function createCourse(req, res, next) { + try { + res.status(201).json({ ok: true, data: await courseService.createCourse(req.body) }) + } catch (error) { + next(error) + } +} + +async function updateCourse(req, res, next) { + try { + res.json({ ok: true, data: await courseService.updateCourse(req.params.id, req.body) }) + } catch (error) { + next(error) + } +} + +async function deleteCourse(req, res, next) { + try { + res.json({ ok: true, data: await courseService.deleteCourse(req.params.id) }) + } catch (error) { + next(error) + } +} + +async function bookCourse(req, res, next) { + try { + res.status(201).json({ ok: true, data: await courseService.book({ ...req.body, userId: req.account.id }) }) + } catch (error) { + next(error) + } +} + +module.exports = { + listCourses, + listAdminCourses, + listAppointments, + listUserAppointments, + attendAppointment, + bookCourse, + createCourse, + deleteCourse, + getAdminCourse, + updateCourse, +} diff --git a/backend/src/controllers/pointController.js b/backend/src/controllers/pointController.js new file mode 100644 index 0000000..0238d6c --- /dev/null +++ b/backend/src/controllers/pointController.js @@ -0,0 +1,184 @@ +const { pointService } = require('../services') + +async function getPointCenter(req, res, next) { + try { + res.json({ ok: true, data: await pointService.getCenter(req.account.id) }) + } catch (error) { + next(error) + } +} + +async function redeemReward(req, res, next) { + try { + res.status(201).json({ ok: true, data: await pointService.redeem(req.account.id, req.body.itemId) }) + } catch (error) { + next(error) + } +} + +async function listUserRewards(req, res, next) { + try { + res.json({ ok: true, data: await pointService.listUserRewards(req.account.id, req.query) }) + } catch (error) { + next(error) + } +} + +async function listUserTransactions(req, res, next) { + try { + res.json({ ok: true, data: await pointService.listUserTransactions(req.account.id, req.query) }) + } catch (error) { + next(error) + } +} + +async function listUserRedemptions(req, res, next) { + try { + res.json({ ok: true, data: await pointService.listUserRedemptions(req.account.id, req.query) }) + } catch (error) { + next(error) + } +} + +async function getAdminPointManager(req, res, next) { + try { + res.json({ ok: true, data: await pointService.getAdminManager() }) + } catch (error) { + next(error) + } +} + +async function listPointAccounts(req, res, next) { + try { + res.json({ ok: true, data: await pointService.listPointAccounts(req.query) }) + } catch (error) { + next(error) + } +} + +async function listPointTransactions(req, res, next) { + try { + res.json({ ok: true, data: await pointService.listPointTransactions(req.query) }) + } catch (error) { + next(error) + } +} + +async function adjustPoints(req, res, next) { + try { + res.status(201).json({ + ok: true, + data: await pointService.adjust(req.body.userId, req.body.amount, req.body.title, req.body.status), + }) + } catch (error) { + next(error) + } +} + +async function settlePendingPoints(req, res, next) { + try { + res.json({ + ok: true, + data: await pointService.settlePending(req.body.userId, req.body.amount, req.body.title), + }) + } catch (error) { + next(error) + } +} + +async function updateReward(req, res, next) { + try { + res.json({ ok: true, data: await pointService.updateReward(req.params.id, req.body) }) + } catch (error) { + next(error) + } +} + +async function updateReferralRule(req, res, next) { + try { + res.json({ ok: true, data: await pointService.updateReferralRule(req.params.event, req.body) }) + } catch (error) { + next(error) + } +} + +async function createReward(req, res, next) { + try { + res.status(201).json({ ok: true, data: await pointService.createReward(req.body) }) + } catch (error) { + next(error) + } +} + +async function listRewards(req, res, next) { + try { + res.json({ ok: true, data: await pointService.listRewards(req.query) }) + } catch (error) { + next(error) + } +} + +async function getRewardDetail(req, res, next) { + try { + res.json({ ok: true, data: await pointService.getRewardDetail(req.params.id) }) + } catch (error) { + next(error) + } +} + +async function listRedemptions(req, res, next) { + try { + res.json({ ok: true, data: await pointService.listRedemptions(req.query) }) + } catch (error) { + next(error) + } +} + +async function approveRedemption(req, res, next) { + try { + res.json({ ok: true, data: await pointService.approveRedemption(req.params.id, req.operator?.id || req.body.operatorId, req.body) }) + } catch (error) { + next(error) + } +} + +async function rejectRedemption(req, res, next) { + try { + res.json({ ok: true, data: await pointService.rejectRedemption(req.params.id, req.operator?.id || req.body.operatorId, req.body) }) + } catch (error) { + next(error) + } +} + +async function verifyVoucher(req, res, next) { + try { + res.json({ ok: true, data: await pointService.verifyVoucher({ + ...req.body, + operatorId: req.operator?.id || req.body.operatorId, + }) }) + } catch (error) { + next(error) + } +} + +module.exports = { + adjustPoints, + approveRedemption, + createReward, + getAdminPointManager, + getPointCenter, + getRewardDetail, + listPointAccounts, + listPointTransactions, + listRedemptions, + listRewards, + listUserRedemptions, + listUserRewards, + listUserTransactions, + redeemReward, + rejectRedemption, + settlePendingPoints, + updateReward, + updateReferralRule, + verifyVoucher, +} diff --git a/backend/src/controllers/referralController.js b/backend/src/controllers/referralController.js new file mode 100644 index 0000000..a478982 --- /dev/null +++ b/backend/src/controllers/referralController.js @@ -0,0 +1,40 @@ +const { referralService } = require('../services') + +async function getReferralCenter(req, res, next) { + try { + res.json({ ok: true, data: await referralService.getCenter(req.account.id, req.query) }) + } catch (error) { + next(error) + } +} + +async function createShareMaterial(req, res, next) { + try { + res.json({ ok: true, data: { share: await referralService.createShare(req.body.channel || '默认', req.account.id) } }) + } catch (error) { + next(error) + } +} + +async function createMiniProgramCode(req, res, next) { + try { + res.json({ ok: true, data: await referralService.createMiniProgramCode(req.account.id) }) + } catch (error) { + next(error) + } +} + +async function bindReferral(req, res, next) { + try { + res.status(201).json({ ok: true, data: await referralService.bindReferral(req.body) }) + } catch (error) { + next(error) + } +} + +module.exports = { + getReferralCenter, + createShareMaterial, + createMiniProgramCode, + bindReferral, +} diff --git a/backend/src/controllers/uploadController.js b/backend/src/controllers/uploadController.js new file mode 100644 index 0000000..166e5a3 --- /dev/null +++ b/backend/src/controllers/uploadController.js @@ -0,0 +1,107 @@ +const fs = require('fs') +const path = require('path') +const { createId } = require('../utils/ids') +const { env } = require('../config/env') + +const MAX_AVATAR_SIZE = 2 * 1024 * 1024 +const AVATAR_DIR = path.resolve(__dirname, '../../uploads/avatars') +const MIME_EXTENSIONS = { + 'image/jpeg': 'jpg', + 'image/png': 'png', + 'image/webp': 'webp', + 'image/gif': 'gif', +} + +function ensureAvatarDir() { + fs.mkdirSync(AVATAR_DIR, { recursive: true }) +} + +function collectRequest(req) { + return new Promise((resolve, reject) => { + const chunks = [] + let size = 0 + req.on('data', (chunk) => { + size += chunk.length + if (size > MAX_AVATAR_SIZE + 1024 * 1024) { + reject(Object.assign(new Error('头像文件不能超过 2MB'), { status: 413 })) + req.destroy() + return + } + chunks.push(chunk) + }) + req.on('end', () => resolve(Buffer.concat(chunks))) + req.on('error', reject) + }) +} + +function parseMultipart(buffer, contentType) { + const boundaryMatch = String(contentType || '').match(/boundary=(?:"([^"]+)"|([^;]+))/i) + if (!boundaryMatch) { + const error = new Error('上传格式不正确') + error.status = 400 + throw error + } + const boundary = Buffer.from(`--${boundaryMatch[1] || boundaryMatch[2]}`) + let cursor = buffer.indexOf(boundary) + while (cursor >= 0) { + const next = buffer.indexOf(boundary, cursor + boundary.length) + if (next < 0) break + const part = buffer.subarray(cursor + boundary.length + 2, next - 2) + const headerEnd = part.indexOf(Buffer.from('\r\n\r\n')) + if (headerEnd > 0) { + const header = part.subarray(0, headerEnd).toString('utf8') + const body = part.subarray(headerEnd + 4) + const fileNameMatch = header.match(/filename="([^"]+)"/i) + const contentTypeMatch = header.match(/Content-Type:\s*([^\r\n]+)/i) + if (fileNameMatch && contentTypeMatch) { + return { + filename: fileNameMatch[1], + mime: contentTypeMatch[1].trim().toLowerCase(), + data: body, + } + } + } + cursor = next + } + const error = new Error('没有找到上传文件') + error.status = 400 + throw error +} + +async function uploadAvatar(req, res, next) { + try { + const buffer = await collectRequest(req) + const file = parseMultipart(buffer, req.headers['content-type']) + const extension = MIME_EXTENSIONS[file.mime] + if (!extension) { + const error = new Error('仅支持 JPG、PNG、WEBP、GIF 图片') + error.status = 400 + throw error + } + if (!file.data.length || file.data.length > MAX_AVATAR_SIZE) { + const error = new Error('头像文件不能超过 2MB') + error.status = 413 + throw error + } + + ensureAvatarDir() + const filename = `${createId('avatar')}.${extension}` + const absolutePath = path.join(AVATAR_DIR, filename) + fs.writeFileSync(absolutePath, file.data) + + const pathUrl = `/uploads/avatars/${filename}` + const baseUrl = env.publicBaseUrl || `${req.protocol}://${req.get('host')}` + res.status(201).json({ + ok: true, + data: { + filename, + path: pathUrl, + url: `${baseUrl}${pathUrl}`, + }, + }) + } catch (error) { + next(error) + } +} + +module.exports = { uploadAvatar } diff --git a/backend/src/data/seed.js b/backend/src/data/seed.js new file mode 100644 index 0000000..791519a --- /dev/null +++ b/backend/src/data/seed.js @@ -0,0 +1,63 @@ +const { ROLE_PERMISSIONS } = require('../constants/permissions') + +const seed = { + roles: [ + { role: 'parent', name: '家长', permissions: ROLE_PERMISSIONS.parent }, + { role: 'super_admin', name: '超级管理员', permissions: ROLE_PERMISSIONS.super_admin }, + { role: 'campus_admin', name: '校区管理员', permissions: ROLE_PERMISSIONS.campus_admin }, + { role: 'advisor', name: '课程顾问', permissions: ROLE_PERMISSIONS.advisor }, + { role: 'teacher', name: '老师', permissions: ROLE_PERMISSIONS.teacher }, + { role: 'finance', name: '财务', permissions: ROLE_PERMISSIONS.finance }, + ], + users: [ + { + id: 'admin_001', + username: 'admin', + passwordHash: '240be518fabd2724ddb6f04eeb1da5967448d7e831c08c8fa822809f74c720a9', + role: 'super_admin', + roleName: '超级管理员', + name: '系统管理员', + phone: '13800009999', + status: 'active', + trialBookingLimit: 1, + lastLoginAt: '', + wechatOpenid: null, + wechatUnionid: null, + wechatNickname: null, + wechatAvatar: null, + loginProvider: 'password', + phoneBound: true, + phoneBoundAt: '', + wechatBoundAt: null, + }, + ], + pointAccounts: [], + pointTransactions: [], + pointExpiryRule: { + title: '积分有效期说明', + validDays: 180, + description: '积分自实际到账日起 180 天内有效,仅可兑换课程、测评和学习服务权益,不可提现或转赠。', + reminder: '系统会在到期前 30 天进入“将过期”口径,运营可通过积分管理页提醒家长尽快兑换。', + }, + pointExpirySchedules: [], + referralRules: [ + { event: 'registered', title: '新家长注册', inviter: 20, invitee: 20 }, + { event: 'booked', title: '预约试听', inviter: 50, invitee: 50 }, + { event: 'attended', title: '确认到课', inviter: 150, invitee: 100 }, + { event: 'purchased', title: '报名正价课', inviter: 800, invitee: 500 }, + ], + referrals: [], + courses: [], + rewards: [ + { id: 'reward_001', name: '精品体验课 1 次', cost: 800, type: '课程权益', stock: 30, description: '适用于校区公开试听课,审核通过后生成课程券码,30 天内到店核销。' }, + { id: 'reward_002', name: '学习规划咨询', cost: 500, type: '服务权益', stock: 50, description: '由课程顾问提供一次学习规划沟通,适合新生测评后使用。' }, + { id: 'reward_003', name: '正价课抵扣券 100 元', cost: 1000, type: '抵扣券', stock: 20, description: '报名正价课程时抵扣 100 元,不可叠加现金活动使用。' }, + { id: 'reward_004', name: '阶段测评报告', cost: 300, type: '测评', stock: 80, description: '兑换后安排一次阶段测评报告解读,帮助家长了解学习状态。' }, + ], + appointments: [], + redemptionOrders: [], + leads: [], + channelStats: [], +} + +module.exports = { seed } diff --git a/backend/src/middleware/errorHandler.js b/backend/src/middleware/errorHandler.js new file mode 100644 index 0000000..21a36bd --- /dev/null +++ b/backend/src/middleware/errorHandler.js @@ -0,0 +1,14 @@ +function errorHandler(error, req, res, next) { + if (res.headersSent) { + next(error) + return + } + + const status = error.status || 500 + res.status(status).json({ + ok: false, + message: error.message || '服务器异常', + }) +} + +module.exports = { errorHandler } diff --git a/backend/src/middleware/permission.js b/backend/src/middleware/permission.js new file mode 100644 index 0000000..e41f92a --- /dev/null +++ b/backend/src/middleware/permission.js @@ -0,0 +1,21 @@ +const { hasPermission } = require('../constants/permissions') +const { authenticateRequest } = require('./session') + +function requirePermission(...required) { + return async (req, res, next) => { + try { + const account = await authenticateRequest(req) + if (!hasPermission(account, required)) { + const error = new Error('没有操作权限') + error.status = 403 + throw error + } + req.operator = account + next() + } catch (error) { + next(error) + } + } +} + +module.exports = { requirePermission } diff --git a/backend/src/middleware/session.js b/backend/src/middleware/session.js new file mode 100644 index 0000000..7468996 --- /dev/null +++ b/backend/src/middleware/session.js @@ -0,0 +1,50 @@ +const { repository } = require('../repositories') +const { verifySessionToken } = require('../utils/sessionToken') + +function readSessionToken(req) { + const authorization = String(req.get('authorization') || '').trim() + if (authorization.toLowerCase().startsWith('bearer ')) return authorization.slice(7).trim() + return String(req.get('x-session-token') || '').trim() +} + +async function authenticateRequest(req) { + if (req.account) return req.account + const payload = verifySessionToken(readSessionToken(req)) + if (!payload) { + const error = new Error('登录状态无效或已过期,请重新登录') + error.status = 401 + throw error + } + const account = await repository.withPermissions(await repository.findUserById(payload.sub)) + if (!account || account.status !== 'active') { + const error = new Error('账号不存在或已停用') + error.status = 403 + throw error + } + req.account = account + return account +} + +async function requireSession(req, res, next) { + try { + await authenticateRequest(req) + next() + } catch (error) { + next(error) + } +} + +function requireSelf(source, key) { + return (req, res, next) => { + const targetId = String(req[source]?.[key] || '').trim() + if (targetId && targetId !== req.account?.id) { + const error = new Error('不能访问或修改其他用户的数据') + error.status = 403 + next(error) + return + } + next() + } +} + +module.exports = { authenticateRequest, requireSelf, requireSession } diff --git a/backend/src/repositories/index.js b/backend/src/repositories/index.js new file mode 100644 index 0000000..818919a --- /dev/null +++ b/backend/src/repositories/index.js @@ -0,0 +1,7 @@ +const { env } = require('../config/env') +const { repository: memoryRepository } = require('./memoryRepository') +const { MySqlRepository } = require('./mysqlRepository') + +const repository = env.dbClient === 'mysql' ? new MySqlRepository() : memoryRepository + +module.exports = { repository } diff --git a/backend/src/repositories/memoryRepository.js b/backend/src/repositories/memoryRepository.js new file mode 100644 index 0000000..38ee909 --- /dev/null +++ b/backend/src/repositories/memoryRepository.js @@ -0,0 +1,549 @@ +const { seed } = require('../data/seed') +const { hashPassword } = require('../utils/password') +const { normalizePermissions } = require('../constants/permissions') + +class MemoryRepository { + constructor(initialState) { + this.state = structuredClone(initialState) + } + + findUserById(id) { + return this.state.users.find((user) => user.id === id) + } + + findUserByInviteCode(inviterCode) { + return this.state.users.find((user) => user.inviterCode === inviterCode) + } + + findUserByPhone(phone) { + return this.state.users.find((user) => user.phone === phone) + } + + findUserByLoginAccount(account) { + const value = String(account || '').trim() + return this.state.users.find((user) => [user.username, user.phone, user.id, user.wechatOpenid, user.wechatUnionid].filter(Boolean).includes(value)) + } + + listAccounts() { + return this.state.users + .map((user) => this.withPermissions(user)) + } + + listParentUsers() { + return this.state.users + .filter((user) => user.role === 'parent') + .map((user) => this.withPermissions(user)) + } + + getRoleMatrix() { + return this.state.roles.filter((role) => role.role !== 'parent').map((role) => ({ + ...role, + permissions: normalizePermissions(role.permissions || []), + })) + } + + findRole(roleName) { + return this.state.roles.find((item) => item.role === roleName) + } + + updateRolePermissions(roleName, permissions) { + const role = this.findRole(roleName) + if (!role) return null + role.permissions = [...(permissions || [])] + return role + } + + withPermissions(user) { + const role = this.findRole(user.role) + const hasPassword = Boolean(user.passwordHash) + return { + ...user, + trialBookingLimit: Number.isInteger(Number(user.trialBookingLimit)) ? Number(user.trialBookingLimit) : 1, + passwordHash: undefined, + hasPassword, + roleName: role?.name || user.roleName || user.role, + permissions: user.role === 'parent' ? [] : normalizePermissions(role?.permissions || []), + } + } + + touchLogin(id) { + const user = this.findUserById(id) + if (!user) return null + user.lastLoginAt = new Date().toISOString().slice(0, 16).replace('T', ' ') + return this.withPermissions(user) + } + + addUser(user) { + if (!user.username) user.username = user.phone || user.id + if (!user.passwordHash && user.password) user.passwordHash = hashPassword(user.password) + if (user.passwordHash === undefined) user.passwordHash = null + user.phone = user.phone || null + user.wechatOpenid = user.wechatOpenid || null + user.wechatUnionid = user.wechatUnionid || null + user.wechatNickname = user.wechatNickname || null + user.wechatAvatar = user.wechatAvatar || null + user.loginProvider = user.loginProvider || (user.wechatOpenid ? 'wechat' : 'password') + user.phoneBound = user.phoneBound === undefined ? Boolean(user.phone) : Boolean(user.phoneBound) + user.phoneBoundAt = user.phoneBoundAt || (user.phone ? new Date().toISOString().slice(0, 16).replace('T', ' ') : null) + user.wechatBoundAt = user.wechatBoundAt || (user.wechatOpenid ? new Date().toISOString().slice(0, 16).replace('T', ' ') : null) + user.trialBookingLimit = Number.isInteger(Number(user.trialBookingLimit)) ? Number(user.trialBookingLimit) : 1 + user.createdAt = user.createdAt || new Date().toISOString().slice(0, 16).replace('T', ' ') + delete user.password + this.state.users.push(user) + return user + } + + updateUser(id, patch) { + const user = this.findUserById(id) + if (!user) return null + if (patch.passwordHash !== undefined) user.passwordHash = patch.passwordHash + if (patch.username !== undefined) user.username = patch.username + if (patch.role !== undefined) user.role = patch.role + if (patch.roleName !== undefined) user.roleName = patch.roleName + if (patch.name !== undefined) user.name = patch.name + if (patch.phone !== undefined) user.phone = patch.phone || null + if (patch.wechatOpenid !== undefined) user.wechatOpenid = patch.wechatOpenid || null + if (patch.wechatUnionid !== undefined) user.wechatUnionid = patch.wechatUnionid || null + if (patch.wechatNickname !== undefined) user.wechatNickname = patch.wechatNickname || null + if (patch.wechatAvatar !== undefined) user.wechatAvatar = patch.wechatAvatar || null + if (patch.loginProvider !== undefined) user.loginProvider = patch.loginProvider + if (patch.phoneBound !== undefined) user.phoneBound = Boolean(patch.phoneBound) + if (patch.phoneBoundAt !== undefined) user.phoneBoundAt = patch.phoneBoundAt + if (patch.wechatBoundAt !== undefined) user.wechatBoundAt = patch.wechatBoundAt + if (patch.status !== undefined) user.status = patch.status + if (patch.inviterCode !== undefined) user.inviterCode = patch.inviterCode + if (patch.trialBookingLimit !== undefined) user.trialBookingLimit = Number(patch.trialBookingLimit) + if (patch.child !== undefined) user.child = patch.child + return user + } + + deleteUser(id) { + const index = this.state.users.findIndex((user) => user.id === id) + if (index < 0) return null + const [user] = this.state.users.splice(index, 1) + this.state.pointAccounts = this.state.pointAccounts.filter((item) => item.userId !== id) + this.state.pointTransactions = this.state.pointTransactions.filter((item) => item.userId !== id) + this.state.referrals = this.state.referrals.filter((item) => item.inviterId !== id && item.inviteeId !== id) + this.state.appointments = this.state.appointments.filter((item) => item.userId !== id) + this.state.redemptionOrders = this.state.redemptionOrders.filter((item) => item.userId !== id) + return user + } + + updateAccountRole(id, roleName) { + const user = this.findUserById(id) + const role = this.findRole(roleName) + if (!user || !role) return null + user.role = role.role + user.roleName = role.name + return this.withPermissions(user) + } + + updateAccountStatus(id, status) { + const user = this.findUserById(id) + if (!user) return null + user.status = status + return this.withPermissions(user) + } + + getPointAccount(userId) { + let account = this.state.pointAccounts.find((item) => item.userId === userId) + if (!account) { + account = { userId, available: 0, pending: 0, frozen: 0, expiring: 0 } + this.state.pointAccounts.push(account) + } + return account + } + + updatePointAccount(userId, patch) { + const account = this.getPointAccount(userId) + Object.assign(account, patch) + return account + } + + addPointTransaction(transaction) { + this.state.pointTransactions.unshift(transaction) + return transaction + } + + listPointTransactions() { + return this.state.pointTransactions + } + + getPointTransactions(userId) { + return this.state.pointTransactions.filter((item) => item.userId === userId) + } + + getPointExpiryRule() { + return this.state.pointExpiryRule + } + + listPointExpirySchedules(userId) { + return this.state.pointExpirySchedules.filter((item) => !userId || item.userId === userId) + } + + getReferralRules() { + return this.state.referralRules + } + + updateReferralRule(event, patch) { + const rule = this.state.referralRules.find((item) => item.event === event) + if (!rule) return null + Object.assign(rule, patch) + return rule + } + + getReferralsByInviter(inviterId) { + return this.state.referrals.filter((item) => item.inviterId === inviterId) + } + + findReferralByInvitee(inviteeId) { + return this.state.referrals.find((item) => item.inviteeId === inviteeId) + } + + findReferralById(id) { + return this.state.referrals.find((item) => item.id === id) + } + + findReferralForLead(lead = {}) { + if (lead.referralId) { + const referral = this.findReferralById(lead.referralId) + if (referral) return referral + } + if (lead.inviteeId) { + const referral = this.findReferralByInvitee(lead.inviteeId) + if (referral) return referral + } + + const parent = String(lead.parent || '').trim() + if (!parent) return null + const source = String(lead.source || '').trim() + const channel = String(lead.channel || '').trim() + const candidates = this.state.referrals + .map((referral) => { + const inviter = this.findUserById(referral.inviterId) + const invitee = referral.inviteeId ? this.findUserById(referral.inviteeId) : null + const fallbackNames = [ + { value: invitee?.name, score: 40 }, + { value: referral.name, score: 30 }, + { value: invitee?.phone ? `家长${String(invitee.phone).slice(-4)}` : '', score: 20 }, + { value: referral.phone ? `家长${String(referral.phone).slice(-4)}` : '', score: 20 }, + ].filter((item) => item.value) + const parentHit = fallbackNames.find((item) => item.value === parent) + if (!parentHit) return null + const sourceValues = [inviter?.name, inviter?.id, inviter?.phone].filter(Boolean) + const sourceScore = !source || sourceValues.includes(source) ? 8 : 0 + const channelScore = !channel || !referral.channel || referral.channel === channel ? 4 : 0 + return { referral, score: parentHit.score + sourceScore + channelScore } + }) + .filter(Boolean) + .sort((a, b) => b.score - a.score) + + return candidates[0]?.referral || null + } + + addReferral(referral) { + this.state.referrals.unshift(referral) + return referral + } + + updateReferral(id, patch) { + const referral = this.state.referrals.find((item) => item.id === id) + if (!referral) return null + Object.assign(referral, patch) + return referral + } + + updateReferralInviteeInfo(inviteeId, patch = {}) { + const updated = [] + this.state.referrals.forEach((referral) => { + if (referral.inviteeId !== inviteeId) return + if (patch.name !== undefined) referral.name = patch.name + if (patch.phone !== undefined) referral.phone = patch.phone + if (patch.childGrade !== undefined) referral.childGrade = patch.childGrade + updated.push(referral) + }) + return updated + } + + getCourses() { + return this.state.courses + } + + findCourse(id) { + return this.state.courses.find((course) => course.id === id) + } + + addCourse(course) { + this.state.courses.unshift(course) + return course + } + + updateCourse(id, patch) { + const course = this.findCourse(id) + if (!course) return null + Object.assign(course, patch) + return course + } + + deleteCourse(id) { + const index = this.state.courses.findIndex((course) => course.id === id) + if (index < 0) return null + const [course] = this.state.courses.splice(index, 1) + return course + } + + addAppointment(appointment) { + this.state.appointments.unshift(appointment) + return appointment + } + + findAppointmentById(id) { + return this.decorateAppointment(this.state.appointments.find((appointment) => appointment.id === id)) + } + + updateAppointment(id, patch) { + const appointment = this.state.appointments.find((item) => item.id === id) + if (!appointment) return null + Object.assign(appointment, patch) + return this.decorateAppointment(appointment) + } + + decorateAppointment(appointment) { + if (!appointment) return null + const user = this.findUserById(appointment.userId) + const course = this.findCourse(appointment.courseId) + return { + ...appointment, + user: user + ? { + id: user.id, + name: user.name, + phone: user.phone, + } + : undefined, + course: course + ? { + id: course.id, + name: course.name, + campus: course.campus, + teacher: course.teacher, + nextTime: course.nextTime, + pointsBack: Number(course.pointsBack || 0), + } + : undefined, + } + } + + findAppointmentByUserId(userId) { + return this.decorateAppointment(this.state.appointments.find((appointment) => appointment.userId === userId)) + } + + listAppointments(filters = {}) { + const keyword = String(filters.keyword || '').trim() + return this.state.appointments + .map((appointment) => this.decorateAppointment(appointment)) + .filter((appointment) => { + const matchUser = !filters.userId || appointment.userId === filters.userId + const matchCourse = !filters.courseId || appointment.courseId === filters.courseId + const matchStatus = !filters.status || filters.status === 'all' || appointment.status === filters.status + const matchKeyword = !keyword || [appointment.user?.name, appointment.user?.phone, appointment.course?.name, appointment.course?.campus, appointment.course?.teacher].some((value) => String(value || '').includes(keyword)) + return matchUser && matchCourse && matchStatus && matchKeyword + }) + } + + getRewards() { + return this.state.rewards + } + + listRewards(filters = {}) { + const keyword = String(filters.keyword || '').trim() + return this.state.rewards.filter((reward) => { + const matchKeyword = !keyword || [reward.name, reward.type, reward.description].some((value) => String(value || '').includes(keyword)) + const matchType = !filters.type || filters.type === 'all' || reward.type === filters.type + const matchStock = !filters.stockStatus + || filters.stockStatus === 'all' + || (filters.stockStatus === 'in_stock' && Number(reward.stock || 0) > 0) + || (filters.stockStatus === 'sold_out' && Number(reward.stock || 0) <= 0) + return matchKeyword && matchType && matchStock + }) + } + + findReward(id) { + return this.state.rewards.find((reward) => reward.id === id) + } + + addReward(reward) { + this.state.rewards.unshift(reward) + return reward + } + + updateReward(id, patch) { + const reward = this.findReward(id) + if (!reward) return null + Object.assign(reward, patch) + return reward + } + + decorateRedemption(order) { + if (!order) return null + const user = this.findUserById(order.userId) + const reward = this.findReward(order.itemId) + return { + ...order, + costPoints: Number(order.costPoints || reward?.cost || 0), + voucherCode: order.voucherCode || '', + voucherStatus: order.voucherStatus || 'not_issued', + reviewedBy: order.reviewedBy || '', + reviewedAt: order.reviewedAt || '', + rejectedReason: order.rejectedReason || '', + expireAt: order.expireAt || '', + usedAt: order.usedAt || '', + usedBy: order.usedBy || '', + verifyNote: order.verifyNote || '', + user: user + ? { + id: user.id, + name: user.name, + phone: user.phone, + } + : undefined, + reward: reward + ? { + id: reward.id, + name: reward.name, + type: reward.type, + cost: Number(reward.cost || 0), + } + : undefined, + } + } + + addRedemption(order) { + const next = { + ...order, + costPoints: Number(order.costPoints || 0), + voucherCode: order.voucherCode || '', + voucherStatus: order.voucherStatus || 'not_issued', + reviewedBy: order.reviewedBy || '', + reviewedAt: order.reviewedAt || '', + rejectedReason: order.rejectedReason || '', + expireAt: order.expireAt || '', + usedAt: order.usedAt || '', + usedBy: order.usedBy || '', + verifyNote: order.verifyNote || '', + } + this.state.redemptionOrders.unshift(next) + return this.decorateRedemption(next) + } + + findRedemptionById(id) { + return this.decorateRedemption(this.state.redemptionOrders.find((order) => order.id === id)) + } + + findRedemptionByVoucherCode(voucherCode) { + return this.decorateRedemption(this.state.redemptionOrders.find((order) => order.voucherCode === voucherCode)) + } + + listRedemptions(filters = {}) { + const keyword = String(filters.keyword || '').trim() + return this.state.redemptionOrders + .map((order) => this.decorateRedemption(order)) + .filter((order) => { + if (!order) return false + const matchUser = !filters.userId || order.userId === filters.userId + const matchItem = !filters.itemId || order.itemId === filters.itemId + const matchStatus = !filters.status || filters.status === 'all' || order.status === filters.status + const matchVoucherStatus = !filters.voucherStatus || filters.voucherStatus === 'all' || order.voucherStatus === filters.voucherStatus + const matchType = !filters.type || filters.type === 'all' || order.reward?.type === filters.type + const matchKeyword = !keyword || [order.id, order.voucherCode, order.user?.name, order.user?.phone, order.reward?.name].some((value) => String(value || '').includes(keyword)) + return matchUser && matchItem && matchStatus && matchVoucherStatus && matchType && matchKeyword + }) + } + + updateRedemption(id, patch) { + const order = this.state.redemptionOrders.find((item) => item.id === id) + if (!order) return null + Object.assign(order, patch) + return this.decorateRedemption(order) + } + + getLeads() { + return this.state.leads + } + + getChannelStats() { + return this.state.channelStats + } + + addLead(lead) { + const next = { + referralId: '', + inviteeId: '', + createdAt: new Date().toISOString().slice(0, 16).replace('T', ' '), + ...lead, + } + this.state.leads.unshift(next) + return next + } + + updateLeadStage(id, stage) { + const lead = this.state.leads.find((item) => item.id === id) + if (!lead) return null + lead.stage = stage + return lead + } + + updateLeadsByParent(parent, patch = {}) { + const updated = [] + this.state.leads.forEach((lead) => { + if (lead.parent !== parent) return + Object.assign(lead, patch) + updated.push(lead) + }) + return updated + } + + findLeadForReferral(referral, previous = {}) { + if (!referral) return null + const inviter = this.findUserById(referral.inviterId) + const sources = [inviter?.name, inviter?.id, inviter?.phone].filter(Boolean) + const fallbackNames = [ + referral.name, + previous.name, + referral.phone ? `家长${String(referral.phone).slice(-4)}` : '', + previous.phone ? `家长${String(previous.phone).slice(-4)}` : '', + ].filter(Boolean) + + const exactLead = this.state.leads.find((lead) => referral.id && lead.referralId === referral.id) + || this.state.leads.find((lead) => referral.inviteeId && lead.inviteeId === referral.inviteeId) + if (exactLead) return exactLead + + const candidates = this.state.leads + .map((lead) => { + if (!fallbackNames.includes(lead.parent)) return null + const sourceScore = !lead.source || sources.includes(lead.source) ? 8 : 0 + const channelScore = !referral.channel || !lead.channel || lead.channel === referral.channel ? 4 : 0 + return { lead, score: sourceScore + channelScore } + }) + .filter(Boolean) + .sort((a, b) => b.score - a.score) + return candidates[0]?.lead || null + } + + updateLeadInfoByReferral(referral, patch = {}, previous = {}) { + const lead = this.findLeadForReferral(referral, previous) + if (!lead) return [] + Object.assign(lead, patch) + if (referral.id && !lead.referralId) lead.referralId = referral.id + if (referral.inviteeId && !lead.inviteeId) lead.inviteeId = referral.inviteeId + return [lead] + } + + updateLeadStageByReferral(referral, stage) { + return this.updateLeadInfoByReferral(referral, { stage }) + } +} + +const repository = new MemoryRepository(seed) + +module.exports = { repository } diff --git a/backend/src/repositories/mysqlRepository.js b/backend/src/repositories/mysqlRepository.js new file mode 100644 index 0000000..73ca9c9 --- /dev/null +++ b/backend/src/repositories/mysqlRepository.js @@ -0,0 +1,1033 @@ +const mysql = require('mysql2/promise') +const { env } = require('../config/env') +const { normalizePermissions } = require('../constants/permissions') + +function parseJson(value, fallback = []) { + if (Array.isArray(value)) return value + if (!value) return fallback + try { + return JSON.parse(value) + } catch (error) { + return fallback + } +} + +function toDate(value) { + if (!value) return '' + if (value instanceof Date) return value.toISOString().slice(0, 10) + return String(value).slice(0, 10) +} + +function toDateTime(value) { + if (!value) return '' + if (value instanceof Date) return value.toISOString().slice(0, 16).replace('T', ' ') + return String(value).slice(0, 16).replace('T', ' ') +} + +class MySqlRepository { + constructor() { + this.pool = mysql.createPool({ + host: env.mysql.host, + port: env.mysql.port, + user: env.mysql.user, + password: env.mysql.password, + database: env.mysql.database, + waitForConnections: true, + connectionLimit: env.mysql.connectionLimit, + namedPlaceholders: true, + }) + } + + async query(sql, params = {}) { + const [rows] = await this.pool.execute(sql, params) + return rows + } + + rowToUser(row) { + if (!row) return null + return { + id: row.id, + username: row.username, + passwordHash: row.password_hash, + role: row.role, + roleName: row.role_name, + name: row.name, + phone: row.phone, + wechatOpenid: row.wechat_openid, + wechatUnionid: row.wechat_unionid, + wechatNickname: row.wechat_nickname, + wechatAvatar: row.wechat_avatar, + loginProvider: row.login_provider || 'password', + phoneBound: Boolean(row.phone_bound), + phoneBoundAt: toDateTime(row.phone_bound_at), + wechatBoundAt: toDateTime(row.wechat_bound_at), + status: row.status, + lastLoginAt: toDateTime(row.last_login_at), + createdAt: toDateTime(row.created_at), + inviterCode: row.inviter_code, + trialBookingLimit: Number(row.trial_booking_limit ?? 1), + child: row.child_id + ? { + id: row.child_id, + name: row.child_name, + grade: row.child_grade, + focus: row.child_focus, + } + : undefined, + } + } + + rowToRole(row) { + if (!row) return null + return { + role: row.role, + name: row.name, + permissions: normalizePermissions(parseJson(row.permissions)), + } + } + + rowToCourse(row) { + return { + id: row.id, + name: row.name, + tags: parseJson(row.tags), + nextTime: toDateTime(row.next_time), + pointsBack: Number(row.points_back || 0), + seats: Number(row.seats || 0), + campus: row.campus, + teacher: row.teacher, + trialMinutes: Number(row.trial_minutes || 0), + status: row.status, + } + } + + rowToAppointment(row) { + return { + id: row.id, + userId: row.user_id, + childId: row.child_id, + courseId: row.course_id, + status: row.status, + createdAt: toDateTime(row.created_at), + user: row.user_name + ? { + id: row.user_id, + name: row.user_name, + phone: row.user_phone, + } + : undefined, + course: row.course_name + ? { + id: row.course_id, + name: row.course_name, + campus: row.course_campus, + teacher: row.course_teacher, + nextTime: toDateTime(row.course_next_time), + pointsBack: Number(row.course_points_back || 0), + } + : undefined, + } + } + + rowToReward(row) { + return { + id: row.id, + name: row.name, + cost: Number(row.cost || 0), + type: row.type, + stock: Number(row.stock || 0), + description: row.description || '', + } + } + + rowToPointAccount(row) { + return { + userId: row.user_id, + available: Number(row.available || 0), + pending: Number(row.pending || 0), + frozen: Number(row.frozen || 0), + expiring: Number(row.expiring || 0), + } + } + + rowToPointTransaction(row) { + return { + id: row.id, + userId: row.user_id, + title: row.title, + amount: Number(row.amount || 0), + status: row.status, + referenceType: row.reference_type || '', + referenceId: row.reference_id || '', + createdAt: toDate(row.created_at), + } + } + + rowToReferral(row) { + return { + id: row.id, + inviterId: row.inviter_id, + inviteeId: row.invitee_id, + name: row.name, + phone: row.phone, + childGrade: row.child_grade, + status: row.status, + reward: Number(row.reward || 0), + channel: row.channel, + } + } + + rowToRedemption(row) { + return { + id: row.id, + userId: row.user_id, + itemId: row.item_id, + status: row.status, + costPoints: Number(row.cost_points || row.reward_cost || 0), + voucherCode: row.voucher_code || '', + voucherStatus: row.voucher_status || 'not_issued', + createdAt: toDateTime(row.created_at), + reviewedBy: row.reviewed_by || '', + reviewedAt: toDateTime(row.reviewed_at), + rejectedReason: row.rejected_reason || '', + expireAt: toDateTime(row.expire_at), + usedAt: toDateTime(row.used_at), + usedBy: row.used_by || '', + verifyNote: row.verify_note || '', + user: row.user_name + ? { + id: row.user_id, + name: row.user_name, + phone: row.user_phone, + } + : undefined, + reward: row.reward_name + ? { + id: row.item_id, + name: row.reward_name, + type: row.reward_type, + cost: Number(row.reward_cost || row.cost_points || 0), + } + : undefined, + } + } + + rowToLead(row) { + return { + id: row.id, + referralId: row.referral_id || '', + inviteeId: row.invitee_id || '', + parent: row.parent, + source: row.source, + stage: row.stage, + advisor: row.advisor, + risk: row.risk, + channel: row.channel, + createdAt: toDateTime(row.created_at), + } + } + + async findUserById(id) { + const rows = await this.query('SELECT * FROM users WHERE id = :id LIMIT 1', { id }) + return this.rowToUser(rows[0]) + } + + async findUserByLoginAccount(account) { + const value = String(account || '').trim() + const rows = await this.query('SELECT * FROM users WHERE username = :value OR phone = :value OR id = :value OR wechat_openid = :value OR wechat_unionid = :value LIMIT 1', { value }) + return this.rowToUser(rows[0]) + } + + async findUserByInviteCode(inviterCode) { + const rows = await this.query('SELECT * FROM users WHERE inviter_code = :inviterCode LIMIT 1', { inviterCode }) + return this.rowToUser(rows[0]) + } + + async findUserByPhone(phone) { + const rows = await this.query('SELECT * FROM users WHERE phone = :phone LIMIT 1', { phone }) + return this.rowToUser(rows[0]) + } + + async findRole(roleName) { + const rows = await this.query('SELECT * FROM roles WHERE role = :roleName LIMIT 1', { roleName }) + return this.rowToRole(rows[0]) + } + + async withPermissions(user) { + if (!user) return null + const role = await this.findRole(user.role) + const { passwordHash, ...safeUser } = user + return { + ...safeUser, + hasPassword: Boolean(user.passwordHash), + roleName: role?.name || user.roleName || user.role, + permissions: user.role === 'parent' ? [] : normalizePermissions(role?.permissions || []), + } + } + + async touchLogin(id) { + await this.query('UPDATE users SET last_login_at = NOW() WHERE id = :id', { id }) + return this.withPermissions(await this.findUserById(id)) + } + + async listAccounts() { + const rows = await this.query("SELECT * FROM users ORDER BY FIELD(role, 'super_admin', 'campus_admin', 'advisor', 'teacher', 'finance', 'parent'), id") + return Promise.all(rows.map((row) => this.withPermissions(this.rowToUser(row)))) + } + + async listParentUsers() { + const rows = await this.query("SELECT * FROM users WHERE role = 'parent' ORDER BY id") + return Promise.all(rows.map((row) => this.withPermissions(this.rowToUser(row)))) + } + + async getRoleMatrix() { + const rows = await this.query("SELECT * FROM roles WHERE role <> 'parent' ORDER BY FIELD(role, 'super_admin', 'campus_admin', 'advisor', 'teacher', 'finance')") + return rows.map((row) => this.rowToRole(row)) + } + + async updateRolePermissions(role, permissions) { + await this.query('UPDATE roles SET permissions = :permissions WHERE role = :role', { + role, + permissions: JSON.stringify(permissions || []), + }) + return this.findRole(role) + } + + async addUser(user) { + await this.query( + `INSERT INTO users ( + id, username, password_hash, role, role_name, name, phone, + wechat_openid, wechat_unionid, wechat_nickname, wechat_avatar, + login_provider, phone_bound, phone_bound_at, wechat_bound_at, + status, inviter_code, trial_booking_limit, child_id, child_name, child_grade, child_focus + ) + VALUES ( + :id, :username, :passwordHash, :role, :roleName, :name, :phone, + :wechatOpenid, :wechatUnionid, :wechatNickname, :wechatAvatar, + :loginProvider, :phoneBound, :phoneBoundAt, :wechatBoundAt, + :status, :inviterCode, :trialBookingLimit, :childId, :childName, :childGrade, :childFocus + )`, + { + id: user.id, + username: user.username || user.phone || user.id, + passwordHash: user.passwordHash || null, + role: user.role || 'parent', + roleName: user.roleName || '家长', + name: user.name, + phone: user.phone || null, + wechatOpenid: user.wechatOpenid || null, + wechatUnionid: user.wechatUnionid || null, + wechatNickname: user.wechatNickname || null, + wechatAvatar: user.wechatAvatar || null, + loginProvider: user.loginProvider || (user.wechatOpenid ? 'wechat' : 'password'), + phoneBound: user.phoneBound === undefined ? Boolean(user.phone) : Boolean(user.phoneBound), + phoneBoundAt: user.phoneBoundAt || (user.phone ? new Date().toISOString().slice(0, 16).replace('T', ' ') : null), + wechatBoundAt: user.wechatBoundAt || (user.wechatOpenid ? new Date().toISOString().slice(0, 16).replace('T', ' ') : null), + status: user.status || 'active', + inviterCode: user.inviterCode, + trialBookingLimit: Number.isInteger(Number(user.trialBookingLimit)) ? Number(user.trialBookingLimit) : 1, + childId: user.child?.id || null, + childName: user.child?.name || null, + childGrade: user.child?.grade || null, + childFocus: user.child?.focus || null, + }, + ) + return this.findUserById(user.id) + } + + async updateUser(id, patch) { + const current = await this.findUserById(id) + if (!current) return null + const next = { + ...current, + ...patch, + child: patch.child !== undefined ? patch.child : current.child, + } + await this.query( + `UPDATE users + SET username = :username, + password_hash = :passwordHash, + role = :role, + role_name = :roleName, + name = :name, + phone = :phone, + wechat_openid = :wechatOpenid, + wechat_unionid = :wechatUnionid, + wechat_nickname = :wechatNickname, + wechat_avatar = :wechatAvatar, + login_provider = :loginProvider, + phone_bound = :phoneBound, + phone_bound_at = :phoneBoundAt, + wechat_bound_at = :wechatBoundAt, + status = :status, + inviter_code = :inviterCode, + trial_booking_limit = :trialBookingLimit, + child_id = :childId, + child_name = :childName, + child_grade = :childGrade, + child_focus = :childFocus + WHERE id = :id`, + { + id, + username: next.username || next.phone || id, + passwordHash: next.passwordHash || null, + role: next.role || 'parent', + roleName: next.roleName || next.role || '家长', + name: next.name, + phone: next.phone || null, + wechatOpenid: next.wechatOpenid || null, + wechatUnionid: next.wechatUnionid || null, + wechatNickname: next.wechatNickname || null, + wechatAvatar: next.wechatAvatar || null, + loginProvider: next.loginProvider || 'password', + phoneBound: Boolean(next.phoneBound), + phoneBoundAt: next.phoneBoundAt || null, + wechatBoundAt: next.wechatBoundAt || null, + status: next.status || 'active', + inviterCode: next.inviterCode || null, + trialBookingLimit: Number.isInteger(Number(next.trialBookingLimit)) ? Number(next.trialBookingLimit) : 1, + childId: next.child?.id || null, + childName: next.child?.name || null, + childGrade: next.child?.grade || null, + childFocus: next.child?.focus || null, + }, + ) + return this.findUserById(id) + } + + async deleteUser(id) { + const user = await this.findUserById(id) + if (!user) return null + await this.query('DELETE FROM referrals WHERE inviter_id = :id OR invitee_id = :id', { id }) + await this.query('DELETE FROM point_expiry_schedules WHERE user_id = :id', { id }) + await this.query('DELETE FROM users WHERE id = :id', { id }) + return user + } + + async updateAccountRole(id, roleName) { + const role = await this.findRole(roleName) + const user = await this.findUserById(id) + if (!role || !user) return null + await this.query('UPDATE users SET role = :roleName, role_name = :roleDisplay WHERE id = :id', { id, roleName, roleDisplay: role.name }) + return this.withPermissions(await this.findUserById(id)) + } + + async updateAccountStatus(id, status) { + const user = await this.findUserById(id) + if (!user) return null + await this.query('UPDATE users SET status = :status WHERE id = :id', { id, status }) + return this.withPermissions(await this.findUserById(id)) + } + + async getPointAccount(userId) { + let rows = await this.query('SELECT * FROM point_accounts WHERE user_id = :userId LIMIT 1', { userId }) + if (!rows[0]) { + await this.query('INSERT INTO point_accounts (user_id, available, pending, frozen, expiring) VALUES (:userId, 0, 0, 0, 0)', { userId }) + rows = await this.query('SELECT * FROM point_accounts WHERE user_id = :userId LIMIT 1', { userId }) + } + return this.rowToPointAccount(rows[0]) + } + + async updatePointAccount(userId, patch) { + await this.getPointAccount(userId) + await this.query( + 'UPDATE point_accounts SET available = :available, pending = :pending, frozen = :frozen, expiring = :expiring WHERE user_id = :userId', + { + userId, + available: Number(patch.available || 0), + pending: Number(patch.pending || 0), + frozen: Number(patch.frozen || 0), + expiring: Number(patch.expiring || 0), + }, + ) + return this.getPointAccount(userId) + } + + async addPointTransaction(transaction) { + await this.query( + `INSERT INTO point_transactions (id, user_id, title, amount, status, reference_type, reference_id, created_at) + VALUES (:id, :userId, :title, :amount, :status, :referenceType, :referenceId, :createdAt)`, + { + ...transaction, + referenceType: transaction.referenceType || null, + referenceId: transaction.referenceId || null, + }, + ) + return transaction + } + + async listPointTransactions() { + const rows = await this.query('SELECT * FROM point_transactions ORDER BY created_at DESC, id DESC') + return rows.map((row) => this.rowToPointTransaction(row)) + } + + async getPointTransactions(userId) { + const rows = await this.query('SELECT * FROM point_transactions WHERE user_id = :userId ORDER BY created_at DESC, id DESC', { userId }) + return rows.map((row) => this.rowToPointTransaction(row)) + } + + async getPointExpiryRule() { + const rows = await this.query('SELECT * FROM point_expiry_rule ORDER BY id LIMIT 1') + const row = rows[0] + return { + title: row?.title || '积分有效期说明', + validDays: Number(row?.valid_days || 180), + description: row?.description || '', + reminder: row?.reminder || '', + } + } + + async listPointExpirySchedules(userId) { + const rows = await this.query( + `SELECT * FROM point_expiry_schedules + WHERE (:userId IS NULL OR user_id = :userId) + ORDER BY expire_at ASC`, + { userId: userId || null }, + ) + return rows.map((row) => ({ + id: row.id, + userId: row.user_id, + points: Number(row.points || 0), + expireAt: toDateTime(row.expire_at), + source: row.source, + })) + } + + async getReferralRules() { + const rows = await this.query('SELECT * FROM referral_rules ORDER BY sort_order ASC') + return rows.map((row) => ({ + event: row.event, + title: row.title, + inviter: Number(row.inviter || 0), + invitee: Number(row.invitee || 0), + sortOrder: Number(row.sort_order || 0), + })) + } + + async updateReferralRule(event, patch) { + const rows = await this.query('SELECT * FROM referral_rules WHERE event = :event LIMIT 1', { event }) + if (!rows[0]) return null + const current = { + event: rows[0].event, + title: rows[0].title, + inviter: Number(rows[0].inviter || 0), + invitee: Number(rows[0].invitee || 0), + sortOrder: Number(rows[0].sort_order || 0), + } + const next = { ...current, ...patch } + await this.query( + 'UPDATE referral_rules SET title = :title, inviter = :inviter, invitee = :invitee WHERE event = :event', + { event, title: next.title, inviter: next.inviter, invitee: next.invitee }, + ) + return (await this.getReferralRules()).find((rule) => rule.event === event) + } + + async getReferralsByInviter(inviterId) { + const rows = await this.query('SELECT * FROM referrals WHERE inviter_id = :inviterId ORDER BY created_at DESC, id DESC', { inviterId }) + return rows.map((row) => this.rowToReferral(row)) + } + + async findReferralByInvitee(inviteeId) { + const rows = await this.query('SELECT * FROM referrals WHERE invitee_id = :inviteeId ORDER BY created_at DESC, id DESC LIMIT 1', { inviteeId }) + return rows[0] ? this.rowToReferral(rows[0]) : null + } + + async findReferralById(id) { + const rows = await this.query('SELECT * FROM referrals WHERE id = :id LIMIT 1', { id }) + return rows[0] ? this.rowToReferral(rows[0]) : null + } + + async findReferralForLead(lead = {}) { + if (lead.referralId) { + const referral = await this.findReferralById(lead.referralId) + if (referral) return referral + } + if (lead.inviteeId) { + const referral = await this.findReferralByInvitee(lead.inviteeId) + if (referral) return referral + } + + const parent = String(lead.parent || '').trim() + if (!parent) return null + const rows = await this.query( + `SELECT r.*, + CASE + WHEN invitee.name = :parent THEN 40 + WHEN r.name = :parent THEN 30 + WHEN CONCAT('家长', RIGHT(COALESCE(invitee.phone, ''), 4)) = :parent THEN 20 + WHEN CONCAT('家长', RIGHT(COALESCE(r.phone, ''), 4)) = :parent THEN 20 + ELSE 0 + END AS parent_score, + CASE + WHEN :source = '' THEN 8 + WHEN inviter.name = :source OR inviter.id = :source OR inviter.phone = :source THEN 8 + ELSE 0 + END AS source_score, + CASE + WHEN :channel = '' OR r.channel = :channel THEN 4 + ELSE 0 + END AS channel_score + FROM referrals r + LEFT JOIN users invitee ON invitee.id = r.invitee_id + LEFT JOIN users inviter ON inviter.id = r.inviter_id + WHERE invitee.name = :parent + OR r.name = :parent + OR CONCAT('家长', RIGHT(COALESCE(invitee.phone, ''), 4)) = :parent + OR CONCAT('家长', RIGHT(COALESCE(r.phone, ''), 4)) = :parent + ORDER BY parent_score DESC, source_score DESC, channel_score DESC, r.created_at DESC, r.id DESC + LIMIT 1`, + { + parent, + source: String(lead.source || '').trim(), + channel: String(lead.channel || '').trim(), + }, + ) + return rows[0] ? this.rowToReferral(rows[0]) : null + } + + async addReferral(referral) { + await this.query( + `INSERT INTO referrals (id, inviter_id, invitee_id, name, phone, child_grade, status, reward, channel) + VALUES (:id, :inviterId, :inviteeId, :name, :phone, :childGrade, :status, :reward, :channel)`, + referral, + ) + return referral + } + + async updateReferral(id, patch) { + const rows = await this.query('SELECT * FROM referrals WHERE id = :id LIMIT 1', { id }) + if (!rows[0]) return null + const current = this.rowToReferral(rows[0]) + const next = { ...current, ...patch } + await this.query( + 'UPDATE referrals SET status = :status, reward = :reward WHERE id = :id', + { id, status: next.status, reward: next.reward }, + ) + const nextRows = await this.query('SELECT * FROM referrals WHERE id = :id LIMIT 1', { id }) + return nextRows[0] ? this.rowToReferral(nextRows[0]) : null + } + + async updateReferralInviteeInfo(inviteeId, patch = {}) { + const assignments = [] + const params = { inviteeId } + if (patch.name !== undefined) { + assignments.push('name = :name') + params.name = patch.name + } + if (patch.phone !== undefined) { + assignments.push('phone = :phone') + params.phone = patch.phone + } + if (patch.childGrade !== undefined) { + assignments.push('child_grade = :childGrade') + params.childGrade = patch.childGrade + } + if (!assignments.length) return [] + await this.query(`UPDATE referrals SET ${assignments.join(', ')} WHERE invitee_id = :inviteeId`, params) + const rows = await this.query('SELECT * FROM referrals WHERE invitee_id = :inviteeId ORDER BY created_at DESC, id DESC', { inviteeId }) + return rows.map((row) => this.rowToReferral(row)) + } + + async getCourses() { + const rows = await this.query('SELECT * FROM courses ORDER BY created_at DESC, id') + return rows.map((row) => this.rowToCourse(row)) + } + + async findCourse(id) { + const rows = await this.query('SELECT * FROM courses WHERE id = :id LIMIT 1', { id }) + return rows[0] ? this.rowToCourse(rows[0]) : null + } + + async addCourse(course) { + await this.query( + `INSERT INTO courses (id, name, tags, next_time, points_back, seats, campus, teacher, trial_minutes, status) + VALUES (:id, :name, :tags, :nextTime, :pointsBack, :seats, :campus, :teacher, :trialMinutes, :status)`, + { ...course, tags: JSON.stringify(course.tags || []) }, + ) + return this.findCourse(course.id) + } + + async updateCourse(id, patch) { + const course = await this.findCourse(id) + if (!course) return null + const next = { ...course, ...patch } + await this.query( + `UPDATE courses + SET name = :name, tags = :tags, next_time = :nextTime, points_back = :pointsBack, seats = :seats, + campus = :campus, teacher = :teacher, trial_minutes = :trialMinutes, status = :status + WHERE id = :id`, + { ...next, id, tags: JSON.stringify(next.tags || []) }, + ) + return this.findCourse(id) + } + + async deleteCourse(id) { + const course = await this.findCourse(id) + if (!course) return null + await this.query('DELETE FROM courses WHERE id = :id', { id }) + return course + } + + async addAppointment(appointment) { + await this.query( + 'INSERT INTO appointments (id, user_id, child_id, course_id, status, created_at) VALUES (:id, :userId, :childId, :courseId, :status, :createdAt)', + appointment, + ) + return appointment + } + + async findAppointmentById(id) { + const rows = await this.query(`${this.appointmentSelectSql()} WHERE a.id = :id LIMIT 1`, { id }) + return rows[0] ? this.rowToAppointment(rows[0]) : null + } + + async updateAppointment(id, patch) { + const appointment = await this.findAppointmentById(id) + if (!appointment) return null + const next = { ...appointment, ...patch } + await this.query('UPDATE appointments SET status = :status WHERE id = :id', { id, status: next.status }) + return this.findAppointmentById(id) + } + + appointmentSelectSql() { + return `SELECT a.*, u.name AS user_name, u.phone AS user_phone, + c.name AS course_name, c.campus AS course_campus, c.teacher AS course_teacher, + c.next_time AS course_next_time, c.points_back AS course_points_back + FROM appointments a + LEFT JOIN users u ON u.id = a.user_id + LEFT JOIN courses c ON c.id = a.course_id` + } + + async findAppointmentByUserId(userId) { + const rows = await this.query(`${this.appointmentSelectSql()} WHERE a.user_id = :userId ORDER BY a.created_at DESC LIMIT 1`, { userId }) + return rows[0] ? this.rowToAppointment(rows[0]) : null + } + + async listAppointments(filters = {}) { + const conditions = [] + const params = {} + if (filters.userId) { + conditions.push('a.user_id = :userId') + params.userId = filters.userId + } + if (filters.courseId) { + conditions.push('a.course_id = :courseId') + params.courseId = filters.courseId + } + if (filters.status && filters.status !== 'all') { + conditions.push('a.status = :status') + params.status = filters.status + } + if (filters.keyword) { + conditions.push('(u.name LIKE :keyword OR u.phone LIKE :keyword OR c.name LIKE :keyword OR c.campus LIKE :keyword OR c.teacher LIKE :keyword)') + params.keyword = `%${filters.keyword}%` + } + const where = conditions.length ? ` WHERE ${conditions.join(' AND ')}` : '' + const rows = await this.query(`${this.appointmentSelectSql()}${where} ORDER BY a.created_at DESC, a.id DESC`, params) + return rows.map((row) => this.rowToAppointment(row)) + } + + async getRewards() { + const rows = await this.query('SELECT * FROM rewards ORDER BY id') + return rows.map((row) => this.rowToReward(row)) + } + + async listRewards(filters = {}) { + const conditions = [] + const params = {} + if (filters.keyword) { + conditions.push('(name LIKE :keyword OR type LIKE :keyword OR description LIKE :keyword)') + params.keyword = `%${filters.keyword}%` + } + if (filters.type && filters.type !== 'all') { + conditions.push('type = :type') + params.type = filters.type + } + if (filters.stockStatus === 'in_stock') conditions.push('stock > 0') + if (filters.stockStatus === 'sold_out') conditions.push('stock <= 0') + const where = conditions.length ? ` WHERE ${conditions.join(' AND ')}` : '' + const rows = await this.query(`SELECT * FROM rewards${where} ORDER BY id`, params) + return rows.map((row) => this.rowToReward(row)) + } + + async findReward(id) { + const rows = await this.query('SELECT * FROM rewards WHERE id = :id LIMIT 1', { id }) + return rows[0] ? this.rowToReward(rows[0]) : null + } + + async addReward(reward) { + await this.query( + 'INSERT INTO rewards (id, name, cost, type, stock, description) VALUES (:id, :name, :cost, :type, :stock, :description)', + reward, + ) + return this.findReward(reward.id) + } + + async updateReward(id, patch) { + const reward = await this.findReward(id) + if (!reward) return null + const next = { ...reward, ...patch } + await this.query('UPDATE rewards SET name = :name, type = :type, cost = :cost, stock = :stock, description = :description WHERE id = :id', { ...next, id }) + return this.findReward(id) + } + + async addRedemption(order) { + await this.query( + `INSERT INTO redemption_orders ( + id, user_id, item_id, status, cost_points, voucher_code, voucher_status, + created_at, reviewed_by, reviewed_at, rejected_reason, expire_at, used_at, used_by, verify_note + ) + VALUES ( + :id, :userId, :itemId, :status, :costPoints, :voucherCode, :voucherStatus, + :createdAt, :reviewedBy, :reviewedAt, :rejectedReason, :expireAt, :usedAt, :usedBy, :verifyNote + )`, + { + ...order, + costPoints: order.costPoints || 0, + voucherCode: order.voucherCode || null, + voucherStatus: order.voucherStatus || 'not_issued', + reviewedBy: order.reviewedBy || null, + reviewedAt: order.reviewedAt || null, + rejectedReason: order.rejectedReason || null, + expireAt: order.expireAt || null, + usedAt: order.usedAt || null, + usedBy: order.usedBy || null, + verifyNote: order.verifyNote || null, + }, + ) + return this.findRedemptionById(order.id) + } + + redemptionSelectSql() { + return `SELECT ro.*, u.name AS user_name, u.phone AS user_phone, r.name AS reward_name, r.type AS reward_type, r.cost AS reward_cost + FROM redemption_orders ro + LEFT JOIN users u ON u.id = ro.user_id + LEFT JOIN rewards r ON r.id = ro.item_id` + } + + async findRedemptionById(id) { + const rows = await this.query(`${this.redemptionSelectSql()} WHERE ro.id = :id LIMIT 1`, { id }) + return rows[0] ? this.rowToRedemption(rows[0]) : null + } + + async findRedemptionByVoucherCode(voucherCode) { + const rows = await this.query(`${this.redemptionSelectSql()} WHERE ro.voucher_code = :voucherCode LIMIT 1`, { voucherCode }) + return rows[0] ? this.rowToRedemption(rows[0]) : null + } + + async listRedemptions(filters = {}) { + const conditions = [] + const params = {} + if (filters.userId) { + conditions.push('ro.user_id = :userId') + params.userId = filters.userId + } + if (filters.itemId) { + conditions.push('ro.item_id = :itemId') + params.itemId = filters.itemId + } + if (filters.status && filters.status !== 'all') { + conditions.push('ro.status = :status') + params.status = filters.status + } + if (filters.voucherStatus && filters.voucherStatus !== 'all') { + conditions.push('ro.voucher_status = :voucherStatus') + params.voucherStatus = filters.voucherStatus + } + if (filters.type && filters.type !== 'all') { + conditions.push('r.type = :type') + params.type = filters.type + } + if (filters.keyword) { + conditions.push('(u.name LIKE :keyword OR u.phone LIKE :keyword OR r.name LIKE :keyword OR ro.voucher_code LIKE :keyword OR ro.id LIKE :keyword)') + params.keyword = `%${filters.keyword}%` + } + const where = conditions.length ? ` WHERE ${conditions.join(' AND ')}` : '' + const rows = await this.query(`${this.redemptionSelectSql()}${where} ORDER BY ro.created_at DESC, ro.id DESC`, params) + return rows.map((row) => this.rowToRedemption(row)) + } + + async updateRedemption(id, patch) { + const columnMap = { + status: 'status', + costPoints: 'cost_points', + voucherCode: 'voucher_code', + voucherStatus: 'voucher_status', + reviewedBy: 'reviewed_by', + reviewedAt: 'reviewed_at', + rejectedReason: 'rejected_reason', + expireAt: 'expire_at', + usedAt: 'used_at', + usedBy: 'used_by', + verifyNote: 'verify_note', + } + const assignments = [] + const params = { id } + Object.entries(columnMap).forEach(([key, column]) => { + if (patch[key] !== undefined) { + assignments.push(`${column} = :${key}`) + params[key] = patch[key] || null + } + }) + if (!assignments.length) return this.findRedemptionById(id) + await this.query(`UPDATE redemption_orders SET ${assignments.join(', ')} WHERE id = :id`, params) + return this.findRedemptionById(id) + } + + async getLeads() { + const rows = await this.query('SELECT * FROM leads ORDER BY created_at DESC, id DESC') + return rows.map((row) => this.rowToLead(row)) + } + + async getChannelStats() { + const rows = await this.query('SELECT * FROM channel_stats ORDER BY leads DESC') + return rows.map((row) => ({ + channel: row.channel, + leads: Number(row.leads || 0), + attended: Number(row.attended || 0), + purchased: Number(row.purchased || 0), + })) + } + + async addLead(lead) { + await this.query( + `INSERT INTO leads (id, referral_id, invitee_id, parent, source, stage, advisor, risk, channel) + VALUES (:id, :referralId, :inviteeId, :parent, :source, :stage, :advisor, :risk, :channel)`, + { + id: lead.id, + referralId: lead.referralId || null, + inviteeId: lead.inviteeId || null, + parent: lead.parent, + source: lead.source, + stage: lead.stage, + advisor: lead.advisor, + risk: lead.risk || '正常', + channel: lead.channel || '小程序邀请码', + }, + ) + return lead + } + + async updateLeadStage(id, stage) { + const rows = await this.query('SELECT * FROM leads WHERE id = :id LIMIT 1', { id }) + if (!rows[0]) return null + await this.query('UPDATE leads SET stage = :stage WHERE id = :id', { id, stage }) + return { ...this.rowToLead(rows[0]), stage } + } + + async updateLeadsByParent(parent, patch = {}) { + const assignments = [] + const params = { parent } + if (patch.parent !== undefined) { + assignments.push('parent = :nextParent') + params.nextParent = patch.parent + } + if (patch.stage !== undefined) { + assignments.push('stage = :stage') + params.stage = patch.stage + } + if (patch.channel !== undefined) { + assignments.push('channel = :channel') + params.channel = patch.channel + } + if (!assignments.length) return [] + await this.query(`UPDATE leads SET ${assignments.join(', ')} WHERE parent = :parent`, params) + return this.getLeads() + } + + async findLeadForReferral(referral, previous = {}) { + if (!referral) return null + const exactRows = await this.query( + `SELECT * FROM leads + WHERE (:referralId <> '' AND referral_id = :referralId) + OR (:inviteeId <> '' AND invitee_id = :inviteeId) + ORDER BY created_at DESC, id DESC + LIMIT 1`, + { + referralId: referral.id || '', + inviteeId: referral.inviteeId || '', + }, + ) + if (exactRows[0]) return this.rowToLead(exactRows[0]) + + const inviter = referral.inviterId ? await this.findUserById(referral.inviterId) : null + const sources = [inviter?.name, inviter?.id, inviter?.phone].filter(Boolean) + const fallbackNames = [ + referral.name, + previous.name, + referral.phone ? `家长${String(referral.phone).slice(-4)}` : '', + previous.phone ? `家长${String(previous.phone).slice(-4)}` : '', + ].filter(Boolean) + if (!fallbackNames.length) return null + + const params = { + channel: referral.channel || '', + } + const parentConditions = fallbackNames.map((name, index) => { + const key = `parent${index}` + params[key] = name + return `parent = :${key}` + }) + const sourceConditions = sources.map((source, index) => { + const key = `source${index}` + params[key] = source + return `source = :${key}` + }) + const rows = await this.query( + `SELECT *, + CASE + WHEN ${sourceConditions.length ? sourceConditions.join(' OR ') : '1 = 1'} THEN 8 + ELSE 0 + END AS source_score, + CASE + WHEN :channel = '' OR channel = :channel OR channel = '' THEN 4 + ELSE 0 + END AS channel_score + FROM leads + WHERE (${parentConditions.join(' OR ')}) + ORDER BY source_score DESC, channel_score DESC, created_at DESC, id DESC + LIMIT 1`, + params, + ) + return rows[0] ? this.rowToLead(rows[0]) : null + } + + async updateLeadInfoByReferral(referral, patch = {}, previous = {}) { + const lead = await this.findLeadForReferral(referral, previous) + if (!lead) return [] + + const nextPatch = { ...patch } + if (referral.id && !lead.referralId) nextPatch.referralId = referral.id + if (referral.inviteeId && !lead.inviteeId) nextPatch.inviteeId = referral.inviteeId + + const columnMap = { + referralId: 'referral_id', + inviteeId: 'invitee_id', + parent: 'parent', + source: 'source', + stage: 'stage', + advisor: 'advisor', + risk: 'risk', + channel: 'channel', + } + const assignments = [] + const params = { id: lead.id } + Object.entries(columnMap).forEach(([key, column]) => { + if (nextPatch[key] !== undefined) { + assignments.push(`${column} = :${key}`) + params[key] = nextPatch[key] || null + } + }) + if (!assignments.length) return [lead] + + await this.query(`UPDATE leads SET ${assignments.join(', ')} WHERE id = :id`, params) + const rows = await this.query('SELECT * FROM leads WHERE id = :id LIMIT 1', { id: lead.id }) + return rows[0] ? [this.rowToLead(rows[0])] : [] + } + + async updateLeadStageByReferral(referral, stage) { + return this.updateLeadInfoByReferral(referral, { stage }) + } +} + +module.exports = { MySqlRepository } diff --git a/backend/src/routes/index.js b/backend/src/routes/index.js new file mode 100644 index 0000000..6892f59 --- /dev/null +++ b/backend/src/routes/index.js @@ -0,0 +1,112 @@ +const express = require('express') +const { + getAccounts, + createAccount, + deleteAccount, + getDashboard, + getLeads, + confirmLeadPurchase, + getPcOverview, + getRoles, + updateAccount, + updateAccountRole, + updateAccountStatus, + updateLeadStage, + updateRolePermissions, +} = require('../controllers/adminController') +const { bindWechatPhone, current, login, phoneLogin, sendSmsCode, updatePassword, updatePhone, updateProfile, wechatLogin } = require('../controllers/authController') +const { getBootstrap } = require('../controllers/bootstrapController') +const { attendAppointment, bookCourse, createCourse, deleteCourse, getAdminCourse, listAdminCourses, listAppointments, listCourses, listUserAppointments, updateCourse } = require('../controllers/courseController') +const { + adjustPoints, + approveRedemption, + createReward, + getRewardDetail, + getAdminPointManager, + getPointCenter, + listPointAccounts, + listPointTransactions, + listRedemptions, + listRewards, + listUserRedemptions, + listUserRewards, + listUserTransactions, + redeemReward, + rejectRedemption, + settlePendingPoints, + updateReward, + updateReferralRule, + verifyVoucher, +} = require('../controllers/pointController') +const { bindReferral, createMiniProgramCode, createShareMaterial, getReferralCenter } = require('../controllers/referralController') +const { uploadAvatar } = require('../controllers/uploadController') +const { requirePermission } = require('../middleware/permission') +const { requireSelf, requireSession } = require('../middleware/session') + +const router = express.Router() + +router.get('/bootstrap', requireSession, requireSelf('query', 'accountId'), getBootstrap) + +router.get('/auth/current', requireSession, current) +router.post('/auth/login', login) +router.post('/auth/sms-code', sendSmsCode) +router.post('/auth/phone-login', phoneLogin) +router.post('/auth/wechat-login', wechatLogin) +router.post('/auth/wechat-bind-phone', bindWechatPhone) +router.patch('/auth/profile/:id', requireSession, requireSelf('params', 'id'), updateProfile) +router.patch('/auth/password/:id', requireSession, requireSelf('params', 'id'), updatePassword) +router.patch('/auth/phone/:id', requireSession, requireSelf('params', 'id'), updatePhone) + +router.post('/uploads/avatar', requireSession, uploadAvatar) + +router.get('/referrals', requireSession, requireSelf('query', 'inviterId'), getReferralCenter) +router.post('/referrals/share', requireSession, requireSelf('body', 'inviterId'), createShareMaterial) +router.post('/referrals/mini-code', requireSession, requireSelf('body', 'inviterId'), createMiniProgramCode) +router.post('/referrals/bind', bindReferral) + +router.get('/points/:userId/rewards', requireSession, requireSelf('params', 'userId'), listUserRewards) +router.get('/points/:userId/transactions', requireSession, requireSelf('params', 'userId'), listUserTransactions) +router.get('/points/:userId/redemptions', requireSession, requireSelf('params', 'userId'), listUserRedemptions) +router.get('/points/:userId', requireSession, requireSelf('params', 'userId'), getPointCenter) +router.post('/redemptions', requireSession, requireSelf('body', 'userId'), redeemReward) + +router.get('/courses', listCourses) +router.get('/appointments', requireSession, requireSelf('query', 'userId'), listUserAppointments) +router.post('/appointments', requireSession, requireSelf('body', 'userId'), bookCourse) + +router.get('/admin/dashboard', requirePermission('dashboard:overview:view'), getDashboard) +router.get('/admin/leads', requirePermission('leads:referral:view'), getLeads) +router.post('/admin/leads/:id/purchase', requirePermission('leads:referral:advance'), confirmLeadPurchase) +router.get('/admin/courses', requirePermission('courses:trial:view'), listAdminCourses) +router.get('/admin/courses/:id', requirePermission('courses:trial:view'), getAdminCourse) +router.get('/admin/appointments', requirePermission('courses:trial:view'), listAppointments) +router.patch('/admin/appointments/:id/attend', requirePermission('courses:trial:edit'), attendAppointment) +router.post('/admin/courses', requirePermission('courses:trial:add'), createCourse) +router.patch('/admin/courses/:id', requirePermission('courses:trial:edit'), updateCourse) +router.delete('/admin/courses/:id', requirePermission('courses:trial:delete'), deleteCourse) +router.get('/admin/pc-overview', requirePermission('dashboard:overview:view', 'statistics:channel:view'), getPcOverview) +router.get('/admin/accounts', requirePermission('system:user:view'), getAccounts) +router.post('/admin/accounts', requirePermission('system:user:add'), createAccount) +router.patch('/admin/accounts/:id', requirePermission('system:user:edit'), updateAccount) +router.delete('/admin/accounts/:id', requirePermission('system:user:delete'), deleteAccount) +router.get('/admin/roles', requirePermission('system:role:view', 'system:user:view'), getRoles) +router.patch('/admin/roles/:role/permissions', requirePermission('system:role:edit'), updateRolePermissions) +router.get('/admin/points', requirePermission('points:account:view'), getAdminPointManager) +router.get('/admin/point-accounts', requirePermission('points:account:view'), listPointAccounts) +router.get('/admin/point-transactions', requirePermission('points:account:view'), listPointTransactions) +router.post('/admin/points/adjust', requirePermission('points:account:adjust'), adjustPoints) +router.post('/admin/points/settle-pending', requirePermission('points:account:adjust'), settlePendingPoints) +router.patch('/admin/referral-rules/:event', requirePermission('points:rule:edit', 'points:account:adjust'), updateReferralRule) +router.get('/admin/redemptions', requirePermission('points:redemption:view', 'points:voucher:verify'), listRedemptions) +router.patch('/admin/redemptions/:id/approve', requirePermission('points:redemption:review'), approveRedemption) +router.patch('/admin/redemptions/:id/reject', requirePermission('points:redemption:review'), rejectRedemption) +router.post('/admin/vouchers/verify', requirePermission('points:voucher:verify'), verifyVoucher) +router.patch('/admin/leads/:id/stage', requirePermission('leads:referral:advance'), updateLeadStage) +router.patch('/admin/accounts/:id/role', requirePermission('system:user:role'), updateAccountRole) +router.patch('/admin/accounts/:id/status', requirePermission('system:user:status'), updateAccountStatus) +router.get('/admin/rewards', requirePermission('points:reward:edit', 'points:redemption:view'), listRewards) +router.post('/admin/rewards', requirePermission('points:reward:edit'), createReward) +router.get('/admin/rewards/:id', requirePermission('points:reward:edit', 'points:redemption:view'), getRewardDetail) +router.patch('/admin/rewards/:id', requirePermission('points:reward:edit'), updateReward) + +module.exports = { router } diff --git a/backend/src/server.js b/backend/src/server.js new file mode 100644 index 0000000..72facea --- /dev/null +++ b/backend/src/server.js @@ -0,0 +1,6 @@ +const { app } = require('./app') +const { env } = require('./config/env') + +app.listen(env.port, () => { + console.log(`LiFangHe Education API running at http://localhost:${env.port}/api`) +}) diff --git a/backend/src/services/adminService.js b/backend/src/services/adminService.js new file mode 100644 index 0000000..13a1e0d --- /dev/null +++ b/backend/src/services/adminService.js @@ -0,0 +1,685 @@ +const { createId } = require('../utils/ids') +const { hashPassword } = require('../utils/password') +const { PERMISSION_TREE, hasPermission, sanitizePermissions } = require('../constants/permissions') + +const VALID_ROLES = ['parent', 'super_admin', 'campus_admin', 'advisor', 'teacher', 'finance'] +const VALID_STATUSES = ['active', 'disabled'] +const LEAD_STAGE_FLOW = ['待跟进', '已注册', '已预约', '已到课', '已报名'] +const REFERRAL_STAGE_FLOW = ['待注册', '已注册', '已预约', '已到课', '已报名'] +const REFERRAL_STAGE_EVENTS = { + 已注册: 'registered', + 已预约: 'booked', + 已到课: 'attended', + 已报名: 'purchased', +} +const DAY_MS = 24 * 60 * 60 * 1000 + +function formatDateKey(date) { + const year = date.getFullYear() + const month = String(date.getMonth() + 1).padStart(2, '0') + const day = String(date.getDate()).padStart(2, '0') + return `${year}-${month}-${day}` +} + +function parseDateKey(value) { + const match = String(value || '').match(/^(\d{4})-(\d{2})-(\d{2})$/) + if (!match) return null + const date = new Date(Number(match[1]), Number(match[2]) - 1, Number(match[3])) + return formatDateKey(date) === match[0] ? date : null +} + +function shiftDate(date, days) { + const next = new Date(date) + next.setDate(next.getDate() + days) + return next +} + +function snapshotAccount(account) { + if (!account) return null + return { + ...account, + child: account.child ? { ...account.child } : account.child, + } +} + +function paginate(list = [], filters = {}) { + const pageNum = Math.max(1, Number(filters.pageNum || filters.page || 1)) + const pageSize = Math.min(100, Math.max(1, Number(filters.pageSize || filters.limit || 10))) + const start = (pageNum - 1) * pageSize + return { + list: list.slice(start, start + pageSize), + total: list.length, + pageNum, + pageSize, + } +} + +function parseTrialBookingLimit(value, fallback = 1) { + const limit = Number(value ?? fallback) + if (!Number.isInteger(limit) || limit < 0 || limit > 99) { + const error = new Error('可预约试听次数必须是 0 到 99 之间的整数') + error.status = 400 + throw error + } + return limit +} + +class AdminService { + constructor(repository, pointService) { + this.repository = repository + this.pointService = pointService + } + + async getDashboard() { + const leads = await this.getDecoratedLeads() + const transactions = await this.repository.listPointTransactions() + const overview = this.getLeadOverview(leads, transactions) + + return { + overview, + funnel: [ + { label: '触达', value: leads.length }, + { label: '注册', value: leads.filter((lead) => lead.stage !== '待跟进').length }, + { label: '预约', value: leads.filter((lead) => ['已预约', '已到课', '已报名'].includes(lead.stage)).length }, + { label: '到课', value: overview.attended }, + { label: '报名', value: overview.purchased }, + ], + leads, + } + } + + getLeadOverview(leads, transactions) { + return { + leads: leads.length, + attended: leads.filter((lead) => ['已到课', '已报名'].includes(lead.stage)).length, + purchased: leads.filter((lead) => lead.stage === '已报名').length, + pointsCost: transactions + .filter((tx) => tx.status !== 'pending') + .reduce((sum, tx) => sum + Math.max(0, tx.amount), 0), + revenue: 0, + } + } + + async listLeads(filters = {}) { + const keyword = String(filters.keyword || '').trim() + const stage = String(filters.stage || '').trim() + const advisor = String(filters.advisor || '').trim() + const leads = await this.getDecoratedLeads() + const list = leads.filter((lead) => { + const matchKeyword = !keyword || [lead.parent, lead.phone, lead.childGrade, lead.source, lead.channel].some((value) => String(value || '').includes(keyword)) + const matchStage = !stage || stage === '全部' || lead.stage === stage + const matchAdvisor = !advisor || advisor === '全部' || lead.advisor === advisor + return matchKeyword && matchStage && matchAdvisor + }) + + return { + list, + total: list.length, + } + } + + async getPcOverview(filters = {}) { + const accounts = await this.repository.listAccounts() + const leads = await this.getDecoratedLeads() + const transactions = await this.repository.listPointTransactions() + const purchased = leads.filter((lead) => lead.stage === '已报名').length + const totalLeads = leads.length + return { + overview: { + accounts: accounts.length, + activeAccounts: accounts.filter((account) => account.status === 'active').length, + leads: totalLeads, + conversion: totalLeads ? Math.round((purchased / totalLeads) * 100) : 0, + pointsCost: transactions + .filter((tx) => tx.status !== 'pending') + .reduce((sum, tx) => sum + Math.max(0, tx.amount), 0), + revenue: 0, + }, + accounts, + roleMatrix: await this.repository.getRoleMatrix(), + channelStats: this.buildChannelStats(leads), + referralRules: await this.repository.getReferralRules(), + trend: this.buildDailyTrend(accounts, leads, filters), + } + } + + buildDailyTrend(accounts = [], leads = [], filters = {}) { + const today = new Date() + today.setHours(0, 0, 0, 0) + let endDate = parseDateKey(filters.endDate) || today + if (endDate > today) endDate = today + let startDate = parseDateKey(filters.startDate) || shiftDate(endDate, -29) + if (startDate > endDate) startDate = shiftDate(endDate, -29) + if ((endDate - startDate) / DAY_MS > 365) startDate = shiftDate(endDate, -365) + + const dates = [] + const usersByDate = new Map() + const leadsByDate = new Map() + for (let cursor = new Date(startDate); cursor <= endDate; cursor = shiftDate(cursor, 1)) { + const key = formatDateKey(cursor) + dates.push(key) + usersByDate.set(key, 0) + leadsByDate.set(key, 0) + } + + accounts + .filter((account) => account.role === 'parent') + .forEach((account) => this.incrementDailyCount(usersByDate, account.createdAt)) + leads.forEach((lead) => this.incrementDailyCount(leadsByDate, lead.createdAt)) + + return { + startDate: formatDateKey(startDate), + endDate: formatDateKey(endDate), + dates, + users: dates.map((date) => usersByDate.get(date) || 0), + leads: dates.map((date) => leadsByDate.get(date) || 0), + } + } + + incrementDailyCount(counter, createdAt) { + const date = String(createdAt || '').slice(0, 10) + if (counter.has(date)) counter.set(date, counter.get(date) + 1) + } + + buildChannelStats(leads = []) { + const rows = new Map() + leads.forEach((lead) => { + const channel = String(lead.channel || '未标记渠道').trim() || '未标记渠道' + const current = rows.get(channel) || { channel, leads: 0, attended: 0, purchased: 0 } + current.leads += 1 + if (['已到课', '已报名'].includes(lead.stage)) current.attended += 1 + if (lead.stage === '已报名') current.purchased += 1 + rows.set(channel, current) + }) + return [...rows.values()].sort((left, right) => right.leads - left.leads || left.channel.localeCompare(right.channel, 'zh-CN')) + } + + async getAccounts(filters = {}) { + const keyword = String(filters.keyword || '').trim() + const role = String(filters.role || '').trim() + const status = String(filters.status || '').trim() + const wechatBound = String(filters.wechatBound || '').trim() + const accounts = await this.repository.listAccounts() + const filtered = accounts.filter((account) => { + const matchKeyword = !keyword || [ + account.name, + account.phone, + account.username, + account.id, + account.roleName, + account.role, + account.wechatNickname, + account.wechatOpenid, + account.wechatUnionid, + ].some((value) => String(value || '').toLowerCase().includes(keyword.toLowerCase())) + const matchRole = !role || role === 'all' || account.role === role + const matchStatus = !status || status === 'all' || account.status === status + const isWechatBound = Boolean(account.wechatOpenid || account.wechatUnionid) + const matchWechat = !wechatBound + || wechatBound === 'all' + || (wechatBound === 'bound' && isWechatBound) + || (wechatBound === 'unbound' && !isWechatBound) + return matchKeyword && matchRole && matchStatus && matchWechat + }) + if (String(filters.paged || '') !== '1') return this.decorateInvitationRelations(filtered) + const page = paginate(filtered, filters) + return { + ...page, + list: await this.decorateInvitationRelations(page.list), + overview: { + total: filtered.length, + active: filtered.filter((item) => item.status === 'active').length, + parents: filtered.filter((item) => item.role === 'parent').length, + admins: filtered.filter((item) => item.role !== 'parent').length, + wechatBound: filtered.filter((item) => item.wechatOpenid || item.wechatUnionid).length, + }, + } + } + + async decorateInvitationRelations(accounts = []) { + const appointments = await this.repository.listAppointments() + const appointmentUsage = appointments.reduce((result, item) => { + if (item.status !== 'cancelled') result.set(item.userId, (result.get(item.userId) || 0) + 1) + return result + }, new Map()) + + return Promise.all(accounts.map(async (account) => { + const trialBookingLimit = Number.isInteger(Number(account.trialBookingLimit)) ? Number(account.trialBookingLimit) : 1 + const trialBookingUsed = appointmentUsage.get(account.id) || 0 + const bookingQuota = { + trialBookingLimit, + trialBookingUsed, + trialBookingRemaining: Math.max(0, trialBookingLimit - trialBookingUsed), + } + if (account.role !== 'parent') { + return { + ...account, + ...bookingQuota, + invitedBy: null, + invitedUsers: [], + invitedCount: 0, + } + } + + const referral = await this.repository.findReferralByInvitee?.(account.id) + const inviter = referral?.inviterId ? await this.repository.findUserById(referral.inviterId) : null + const invitedRecords = await this.repository.getReferralsByInviter(account.id) + const invitedUsers = await Promise.all(invitedRecords.map(async (item) => { + const invitee = item.inviteeId ? await this.repository.findUserById(item.inviteeId) : null + return { + id: invitee?.id || item.inviteeId || '', + name: invitee?.name || item.name, + phone: invitee?.phone || item.phone, + status: item.status, + childGrade: item.childGrade, + channel: item.channel, + } + })) + + return { + ...account, + ...bookingQuota, + invitedBy: inviter + ? { + id: inviter.id, + name: inviter.name, + phone: inviter.phone, + } + : null, + invitedUsers, + invitedCount: invitedUsers.length, + } + })) + } + + async getRoles() { + return { + roles: await this.repository.getRoleMatrix(), + permissionTree: PERMISSION_TREE, + } + } + + async updateRolePermissions(role, payload = {}) { + if (role === 'parent') { + const error = new Error('家长角色不参与后台权限配置') + error.status = 400 + throw error + } + const roleInfo = await this.repository.findRole(role) + if (!roleInfo) { + const error = new Error('角色不存在') + error.status = 404 + throw error + } + const permissions = sanitizePermissions(payload.permissions || []) + if (role === 'super_admin' && !permissions.includes('*:*:*')) { + permissions.unshift('*:*:*') + } + return this.repository.updateRolePermissions(role, permissions) + } + + async createAccount(payload = {}) { + const role = String(payload.role || 'parent').trim() + const phone = String(payload.phone || '').trim() + const username = String(payload.username || phone || '').trim() + const name = String(payload.name || '').trim() + const password = String(payload.password || '').trim() + const status = String(payload.status || 'active').trim() + const trialBookingLimit = parseTrialBookingLimit(payload.trialBookingLimit) + + if (!VALID_ROLES.includes(role)) { + const error = new Error('角色无效') + error.status = 400 + throw error + } + if (!VALID_STATUSES.includes(status)) { + const error = new Error('账号状态无效') + error.status = 400 + throw error + } + if (!name || !phone || !/^1\d{10}$/.test(phone)) { + const error = new Error('姓名和正确手机号必填') + error.status = 400 + throw error + } + if (!username) { + const error = new Error('登录账号不能为空') + error.status = 400 + throw error + } + const existed = await this.repository.findUserByLoginAccount(username) + const phoneExisted = await this.repository.findUserByPhone(phone) + if (existed || phoneExisted) { + const error = new Error('账号或手机号已存在') + error.status = 409 + throw error + } + + const roleInfo = await this.repository.findRole(role) + const user = await this.repository.addUser({ + id: createId(role === 'parent' ? 'parent' : 'user'), + username, + passwordHash: password ? hashPassword(password) : null, + role, + roleName: roleInfo?.name || role, + name, + phone, + status, + trialBookingLimit, + inviterCode: role === 'parent' ? `LFH-${Math.random().toString(36).slice(2, 7).toUpperCase()}` : null, + phoneBound: true, + phoneBoundAt: new Date().toISOString().slice(0, 16).replace('T', ' '), + child: payload.childName + ? { + id: createId('child'), + name: String(payload.childName).trim(), + grade: String(payload.childGrade || '待确认').trim(), + focus: String(payload.childFocus || '待测评').trim(), + } + : undefined, + }) + + if (role === 'parent') await this.repository.getPointAccount(user.id) + return this.repository.withPermissions(user) + } + + async updateAccount(id, payload = {}, operator = null) { + const account = await this.repository.findUserById(id) + if (!account) { + const error = new Error('账号不存在') + error.status = 404 + throw error + } + + const role = payload.role !== undefined ? String(payload.role || '').trim() : account.role + const status = payload.status !== undefined ? String(payload.status || '').trim() : account.status + const phone = payload.phone !== undefined ? String(payload.phone || '').trim() : account.phone + const username = payload.username !== undefined ? String(payload.username || '').trim() : account.username + const name = payload.name !== undefined ? String(payload.name || '').trim() : account.name + const password = String(payload.password || '').trim() + const trialBookingLimit = parseTrialBookingLimit(payload.trialBookingLimit, account.trialBookingLimit ?? 1) + + if (operator && role !== account.role && !hasPermission(operator, ['system:user:role'])) { + const error = new Error('没有分配角色权限') + error.status = 403 + throw error + } + if (operator && status !== account.status && !hasPermission(operator, ['system:user:status'])) { + const error = new Error('没有启停账号权限') + error.status = 403 + throw error + } + + if (!VALID_ROLES.includes(role)) { + const error = new Error('角色无效') + error.status = 400 + throw error + } + if (!VALID_STATUSES.includes(status)) { + const error = new Error('账号状态无效') + error.status = 400 + throw error + } + if (!name || !phone || !/^1\d{10}$/.test(phone)) { + const error = new Error('姓名和正确手机号必填') + error.status = 400 + throw error + } + if (!username) { + const error = new Error('登录账号不能为空') + error.status = 400 + throw error + } + + const accounts = await this.repository.listAccounts() + const duplicated = accounts.find((item) => item.id !== id && (item.username === username || item.phone === phone)) + if (duplicated) { + const error = new Error('账号或手机号已存在') + error.status = 409 + throw error + } + + const previous = snapshotAccount(account) + const roleInfo = await this.repository.findRole(role) + const childName = String(payload.childName !== undefined ? payload.childName : account.child?.name || '').trim() + const childGrade = String(payload.childGrade !== undefined ? payload.childGrade : account.child?.grade || '').trim() + const childFocus = String(payload.childFocus !== undefined ? payload.childFocus : account.child?.focus || '').trim() + const patch = { + username, + role, + roleName: roleInfo?.name || role, + name, + phone, + status, + trialBookingLimit, + phoneBound: true, + phoneBoundAt: account.phoneBoundAt || new Date().toISOString().slice(0, 16).replace('T', ' '), + inviterCode: role === 'parent' ? account.inviterCode || `LFH-${Math.random().toString(36).slice(2, 7).toUpperCase()}` : account.inviterCode, + child: role === 'parent' + ? { + id: account.child?.id || createId('child'), + name: childName || '未填写', + grade: childGrade || '待确认', + focus: childFocus || '待测评', + } + : null, + } + if (password) patch.passwordHash = hashPassword(password) + + const updated = await this.repository.updateUser(id, patch) + if (role === 'parent') await this.repository.getPointAccount(id) + await this.syncParentDisplayInfo(previous, updated) + return this.repository.withPermissions(updated) + } + + async deleteAccount(id) { + const account = await this.repository.findUserById(id) + if (!account) { + const error = new Error('账号不存在') + error.status = 404 + throw error + } + if (account.role === 'super_admin') { + const superAdmins = (await this.repository.listAccounts()).filter((item) => item.role === 'super_admin' && item.status !== 'disabled') + if (superAdmins.length <= 1) { + const error = new Error('至少保留一个启用的超级管理员') + error.status = 400 + throw error + } + } + const [transactions, appointments, redemptions, invitedRecords, invitedBy] = await Promise.all([ + this.repository.getPointTransactions(id), + this.repository.listAppointments({ userId: id }), + this.repository.listRedemptions({ userId: id }), + this.repository.getReferralsByInviter(id), + this.repository.findReferralByInvitee?.(id), + ]) + if (transactions.length || appointments.length || redemptions.length || invitedRecords.length || invitedBy) { + const error = new Error('该用户已有推荐、积分、预约或兑换记录,请停用账号以保留业务历史') + error.status = 409 + throw error + } + await this.repository.deleteUser(id) + return this.repository.withPermissions(account) + } + + async updateAccountRole(id, role) { + const account = await this.repository.updateAccountRole(id, role) + if (!account) { + const error = new Error('账号或角色不存在') + error.status = 404 + throw error + } + return account + } + + async updateAccountStatus(id, status) { + if (!VALID_STATUSES.includes(status)) { + const error = new Error('账号状态无效') + error.status = 400 + throw error + } + const account = await this.repository.updateAccountStatus(id, status) + if (!account) { + const error = new Error('账号不存在') + error.status = 404 + throw error + } + return account + } + + async updateLeadStage(id, stage) { + if (!LEAD_STAGE_FLOW.includes(stage)) { + const error = new Error('线索阶段无效') + error.status = 400 + throw error + } + const lead = await this.repository.updateLeadStage(id, stage) + if (!lead) { + const error = new Error('线索不存在') + error.status = 404 + throw error + } + await this.syncReferralWithLeadStage(lead, stage) + return lead + } + + async confirmLeadPurchase(id) { + return this.updateLeadStage(id, '已报名') + } + + async getDecoratedLeads() { + const leads = await this.repository.getLeads() + return Promise.all(leads.map((lead) => this.decorateLead(lead))) + } + + async decorateLead(lead) { + const referral = await this.findReferralByLead(lead) + if (!referral) return lead + const invitee = referral.inviteeId ? await this.repository.findUserById(referral.inviteeId) : null + const hasIdentityLink = Boolean( + (lead.referralId && lead.referralId === referral.id) + || (lead.inviteeId && referral.inviteeId && lead.inviteeId === referral.inviteeId), + ) + return { + ...lead, + referralId: referral.id || lead.referralId, + inviteeId: referral.inviteeId || lead.inviteeId, + parent: invitee?.name || referral.name || lead.parent, + phone: invitee?.phone || referral.phone || '', + childGrade: invitee?.child?.grade || referral.childGrade || '', + stage: hasIdentityLink ? this.maxLeadStage(lead.stage, referral.status) : lead.stage, + } + } + + maxLeadStage(leadStage, referralStage) { + const leadRank = LEAD_STAGE_FLOW.indexOf(leadStage) + const referralRank = LEAD_STAGE_FLOW.indexOf(referralStage) + if (referralRank < 0) return leadStage + if (leadRank < 0) return referralStage + return LEAD_STAGE_FLOW[Math.max(leadRank, referralRank)] + } + + async syncParentDisplayInfo(previous, current) { + if (!current || current.role !== 'parent') return + const referrals = await this.repository.updateReferralInviteeInfo?.(current.id, { + name: current.name, + phone: current.phone, + childGrade: current.child?.grade || '待确认', + }) + if (Array.isArray(referrals) && referrals.length && this.repository.updateLeadInfoByReferral) { + await Promise.all(referrals.map((referral) => this.repository.updateLeadInfoByReferral(referral, { + parent: current.name, + }, previous || {}))) + return + } + if (previous?.name && previous.name !== current.name) { + await this.repository.updateLeadsByParent?.(previous.name, { parent: current.name }) + } + } + + async syncReferralWithLeadStage(lead, targetStage) { + if (!this.pointService || !REFERRAL_STAGE_EVENTS[targetStage]) return null + const referral = await this.findReferralByLead(lead) + if (!referral) return null + + const currentRank = Math.max(0, REFERRAL_STAGE_FLOW.indexOf(referral.status)) + const targetRank = REFERRAL_STAGE_FLOW.indexOf(targetStage) + if (targetRank <= currentRank) return referral + + let nextReferral = referral + for (let rank = currentRank + 1; rank <= targetRank; rank += 1) { + const nextStatus = REFERRAL_STAGE_FLOW[rank] + const event = REFERRAL_STAGE_EVENTS[nextStatus] + if (!event) continue + nextReferral = await this.applyReferralStageReward(nextReferral, nextStatus, event) + } + return nextReferral + } + + async findReferralByLead(lead) { + const matchedReferral = await this.repository.findReferralForLead?.(lead) + if (matchedReferral) return matchedReferral + + if (lead?.referralId && this.repository.findReferralById) { + const referral = await this.repository.findReferralById(lead.referralId) + if (referral) return referral + } + if (lead?.inviteeId && this.repository.findReferralByInvitee) { + const referral = await this.repository.findReferralByInvitee(lead.inviteeId) + if (referral) return referral + } + if (!lead?.parent || !lead?.source) return null + const accounts = await this.repository.listAccounts() + const inviter = accounts.find((account) => account.role === 'parent' && [account.id, account.name, account.phone].filter(Boolean).includes(lead.source)) + if (!inviter) return null + + const records = await this.repository.getReferralsByInviter(inviter.id) + const matches = [] + for (const record of records) { + const invitee = record.inviteeId ? await this.repository.findUserById(record.inviteeId) : null + const fallbackNames = [ + invitee?.name, + record.name, + invitee?.phone ? `家长${String(invitee.phone).slice(-4)}` : '', + record.phone ? `家长${String(record.phone).slice(-4)}` : '', + ].filter(Boolean) + if (fallbackNames.includes(lead.parent)) matches.push(record) + } + if (!matches.length) return null + return matches.find((record) => !lead.channel || record.channel === lead.channel) || matches[0] + } + + async applyReferralStageReward(referral, nextStatus, event) { + const rule = await this.pointService.getReferralRule(event) || { inviter: 0, invitee: 0 } + const inviterPoints = Number(rule.inviter || 0) + const inviteePoints = Number(rule.invitee || 0) + const inviteeId = referral.inviteeId + + if (event === 'attended') { + await this.settleReferralPending(referral.inviterId, `${referral.name}确认到课`) + if (inviteeId) await this.settleReferralPending(inviteeId, '推荐确认到课') + } + + if (inviterPoints > 0) { + await this.pointService.grant(referral.inviterId, `${referral.name}${rule.title || nextStatus}`, inviterPoints, event === 'booked' ? 'pending' : 'available') + } + if (inviteeId && inviteePoints > 0) { + await this.pointService.grant(inviteeId, `推荐${rule.title || nextStatus}奖励`, inviteePoints, event === 'booked' ? 'pending' : 'available') + } + + return this.repository.updateReferral(referral.id, { + status: nextStatus, + reward: Number(referral.reward || 0) + inviterPoints, + }) + } + + async settleReferralPending(userId, title) { + const account = await this.repository.getPointAccount(userId) + if (Number(account.pending || 0) > 0) { + await this.pointService.settlePending(userId, account.pending, title) + } + } +} + +module.exports = { AdminService } diff --git a/backend/src/services/authService.js b/backend/src/services/authService.js new file mode 100644 index 0000000..56d5d1d --- /dev/null +++ b/backend/src/services/authService.js @@ -0,0 +1,482 @@ +const { hashPassword, verifyPassword } = require('../utils/password') +const { createId } = require('../utils/ids') +const { env } = require('../config/env') +const { createSessionToken } = require('../utils/sessionToken') + +function snapshotAccount(account) { + if (!account) return null + return { + ...account, + child: account.child ? { ...account.child } : account.child, + } +} + +class AuthService { + constructor(repository, pointService, smsService) { + this.repository = repository + this.pointService = pointService + this.smsService = smsService + } + + withSession(account) { + if (!account) return account + return { + ...account, + sessionToken: createSessionToken(account.id), + } + } + + async login(credentials = {}) { + const loginAccount = String(credentials.account || credentials.username || credentials.phone || credentials.accountId || '').trim() + const password = String(credentials.password || '') + if (!loginAccount || !password) { + const error = new Error('账号和密码不能为空') + error.status = 400 + throw error + } + const rawAccount = await this.repository.findUserByLoginAccount(loginAccount) + if (!rawAccount) { + const error = new Error('账号或密码错误') + error.status = 401 + throw error + } + if (!verifyPassword(password, rawAccount.passwordHash)) { + const error = new Error('账号或密码错误') + error.status = 401 + throw error + } + const account = await this.repository.touchLogin(rawAccount.id) + if (!account) { + const error = new Error('账号不存在') + error.status = 404 + throw error + } + if (account.status === 'disabled') { + const error = new Error('账号已停用') + error.status = 403 + throw error + } + return this.withSession(account) + } + + async loginByPhone(payload = {}) { + const phone = String(payload.phone || '').trim() + const code = String(payload.code || '').trim() + const inviterCode = String(payload.inviterCode || payload.inviteCode || '').trim().toUpperCase() + if (!/^1\d{10}$/.test(phone)) { + const error = new Error('手机号格式不正确') + error.status = 400 + throw error + } + this.verifySmsCode(phone, code, 'login') + + let account = await this.repository.findUserByPhone(phone) + const isNewAccount = !account + if (isNewAccount && inviterCode) await this.assertInviteCode(inviterCode) + if (!account) { + account = await this.repository.addUser({ + id: createId('parent'), + username: phone, + role: 'parent', + roleName: '家长', + name: `家长${phone.slice(-4)}`, + phone, + status: 'active', + inviterCode: `LFH-${Math.random().toString(36).slice(2, 7).toUpperCase()}`, + phoneBound: true, + phoneBoundAt: new Date().toISOString().slice(0, 16).replace('T', ' '), + }) + await this.repository.getPointAccount(account.id) + if (inviterCode) await this.applyReferralCode(account, inviterCode, '小程序邀请码') + } + + const safeAccount = await this.repository.touchLogin(account.id) + if (!safeAccount) { + const error = new Error('账号不存在') + error.status = 404 + throw error + } + if (safeAccount.status === 'disabled') { + const error = new Error('账号已停用') + error.status = 403 + throw error + } + if (!safeAccount.phoneBound) { + const error = new Error('请先绑定手机号') + error.status = 403 + throw error + } + return this.withSession(safeAccount) + } + + async loginByWechat(payload = {}) { + const code = String(payload.code || '').trim() + if (!code) { + const error = new Error('缺少微信登录 code') + error.status = 400 + throw error + } + + const wechat = await this.exchangeWechatCode(code) + const account = await this.findWechatAccount(wechat) + if (!account) { + return { needPhoneBinding: true } + } + if (account.status === 'disabled') { + const error = new Error('账号已停用') + error.status = 403 + throw error + } + if (!account.phoneBound || !account.phone) { + return { needPhoneBinding: true, account: await this.repository.withPermissions(account) } + } + return { needPhoneBinding: false, account: this.withSession(await this.repository.touchLogin(account.id)) } + } + + async bindWechatPhone(payload = {}) { + const phone = String(payload.phone || '').trim() + const code = String(payload.code || '').trim() + const name = String(payload.name || '').trim() + const inviterCode = String(payload.inviterCode || payload.inviteCode || '').trim().toUpperCase() + if (!/^1\d{10}$/.test(phone)) { + const error = new Error('手机号格式不正确') + error.status = 400 + throw error + } + this.verifySmsCode(phone, code, 'bind_wechat') + + const wechatCode = String(payload.wechatCode || payload.wxCode || '').trim() + if (!wechatCode) { + const error = new Error('缺少微信登录 code') + error.status = 400 + throw error + } + const wechat = await this.exchangeWechatCode(wechatCode) + const wechatAccount = await this.findWechatAccount(wechat) + const phoneAccount = await this.repository.findUserByPhone(phone) + if (wechatAccount?.phone && wechatAccount.phone !== phone) { + const error = new Error('该微信已绑定其他手机号,请在当前账号的账号安全中换绑手机号') + error.status = 409 + throw error + } + if (phoneAccount && this.isAccountBoundToOtherWechat(phoneAccount, wechat)) { + const error = new Error('该手机号已绑定其他微信,请使用原微信登录或联系管理员处理') + error.status = 409 + throw error + } + if (wechatAccount && phoneAccount && wechatAccount.id !== phoneAccount.id) { + const error = new Error('该微信和手机号已分别绑定不同账号,请联系管理员处理') + error.status = 409 + throw error + } + + let account = phoneAccount || wechatAccount + const isNewAccount = !account + if (isNewAccount && inviterCode) await this.assertInviteCode(inviterCode) + if (account) { + const previous = snapshotAccount(account) + account = await this.repository.updateUser(account.id, { + name: name || account.name, + phone, + wechatOpenid: wechat.openid, + wechatUnionid: wechat.unionid || account.wechatUnionid, + loginProvider: 'wechat_phone', + phoneBound: true, + phoneBoundAt: new Date().toISOString().slice(0, 16).replace('T', ' '), + wechatBoundAt: account.wechatBoundAt || new Date().toISOString().slice(0, 16).replace('T', ' '), + }) + await this.syncParentDisplayInfo(previous, account) + } else { + account = await this.repository.addUser({ + id: createId('parent'), + username: phone, + role: 'parent', + roleName: '家长', + name: name || `家长${phone.slice(-4)}`, + phone, + wechatOpenid: wechat.openid, + wechatUnionid: wechat.unionid || null, + loginProvider: 'wechat_phone', + status: 'active', + inviterCode: `LFH-${Math.random().toString(36).slice(2, 7).toUpperCase()}`, + phoneBound: true, + phoneBoundAt: new Date().toISOString().slice(0, 16).replace('T', ' '), + wechatBoundAt: new Date().toISOString().slice(0, 16).replace('T', ' '), + }) + await this.repository.getPointAccount(account.id) + if (inviterCode) await this.applyReferralCode(account, inviterCode, '微信绑定邀请码') + } + + return this.withSession(await this.repository.touchLogin(account.id)) + } + + async updateProfile(accountId, payload = {}) { + if (!accountId) { + const error = new Error('缺少账号 ID') + error.status = 400 + throw error + } + const account = await this.repository.findUserById(accountId) + if (!account) { + const error = new Error('账号不存在') + error.status = 404 + throw error + } + + const patch = {} + if (payload.name !== undefined) patch.name = String(payload.name || '').trim() + if (payload.wechatNickname !== undefined) patch.wechatNickname = String(payload.wechatNickname || '').trim() + if (payload.wechatAvatar !== undefined) patch.wechatAvatar = String(payload.wechatAvatar || '').trim() + const childName = String(payload.childName || account.child?.name || '').trim() + const childGrade = String(payload.childGrade || account.child?.grade || '').trim() + const childFocus = String(payload.childFocus || account.child?.focus || '').trim() + if (childName || childGrade || childFocus) { + patch.child = { + id: account.child?.id || createId('child'), + name: childName || '未填写', + grade: childGrade || '待确认', + focus: childFocus || '待测评', + } + } + if (patch.name !== undefined && !patch.name) { + const error = new Error('姓名不能为空') + error.status = 400 + throw error + } + + const previous = snapshotAccount(account) + const updated = await this.repository.updateUser(accountId, patch) + await this.syncParentDisplayInfo(previous, updated) + return this.repository.withPermissions(updated) + } + + async updatePassword(accountId, payload = {}) { + const account = await this.repository.findUserById(accountId) + if (!account) { + const error = new Error('账号不存在') + error.status = 404 + throw error + } + + const oldPassword = String(payload.oldPassword || '').trim() + const password = String(payload.password || payload.newPassword || '').trim() + const confirmPassword = String(payload.confirmPassword || '').trim() + if (password.length < 6) { + const error = new Error('密码至少需要 6 位') + error.status = 400 + throw error + } + if (confirmPassword && confirmPassword !== password) { + const error = new Error('两次输入的密码不一致') + error.status = 400 + throw error + } + if (account.passwordHash && !verifyPassword(oldPassword, account.passwordHash)) { + const error = new Error('原密码不正确') + error.status = 401 + throw error + } + + const updated = await this.repository.updateUser(accountId, { + passwordHash: hashPassword(password), + loginProvider: account.wechatOpenid ? 'wechat_phone_password' : 'password', + }) + return this.repository.withPermissions(updated) + } + + async updatePhone(accountId, payload = {}) { + const account = await this.repository.findUserById(accountId) + if (!account) { + const error = new Error('账号不存在') + error.status = 404 + throw error + } + + const phone = String(payload.phone || '').trim() + const code = String(payload.code || '').trim() + if (!/^1\d{10}$/.test(phone)) { + const error = new Error('手机号格式不正确') + error.status = 400 + throw error + } + this.verifySmsCode(phone, code, 'update_phone') + + const existed = await this.repository.findUserByPhone(phone) + if (existed && existed.id !== accountId) { + const error = new Error('该手机号已被其他账号绑定') + error.status = 409 + throw error + } + + const patch = { + phone, + phoneBound: true, + phoneBoundAt: new Date().toISOString().slice(0, 16).replace('T', ' '), + } + if (!account.username || account.username === account.phone) { + patch.username = phone + } + + const previous = snapshotAccount(account) + const updated = await this.repository.updateUser(accountId, patch) + await this.syncParentDisplayInfo(previous, updated) + return this.repository.withPermissions(updated) + } + + async current(accountId) { + if (!accountId) { + const error = new Error('缺少账号 ID') + error.status = 400 + throw error + } + const account = await this.repository.findUserById(accountId) + if (!account) { + const error = new Error('账号不存在') + error.status = 404 + throw error + } + const safeAccount = await this.repository.withPermissions(account) + const appointments = await this.repository.listAppointments({ userId: account.id }) + const trialBookingUsed = appointments.filter((item) => item.status !== 'cancelled').length + const trialBookingLimit = Number.isInteger(Number(safeAccount.trialBookingLimit)) ? Number(safeAccount.trialBookingLimit) : 1 + return { + ...safeAccount, + trialBookingLimit, + trialBookingUsed, + trialBookingRemaining: Math.max(0, trialBookingLimit - trialBookingUsed), + } + } + + async findWechatAccount(wechat) { + const byOpenid = wechat.openid ? await this.repository.findUserByLoginAccount(wechat.openid) : null + if (byOpenid) return byOpenid + return wechat.unionid ? await this.repository.findUserByLoginAccount(wechat.unionid) : null + } + + isAccountBoundToOtherWechat(account, wechat) { + if (!account) return false + const openid = String(wechat?.openid || '').trim() + const unionid = String(wechat?.unionid || '').trim() + const accountOpenid = String(account.wechatOpenid || '').trim() + const accountUnionid = String(account.wechatUnionid || '').trim() + if (accountOpenid && accountOpenid !== openid) return true + if (accountUnionid && unionid && accountUnionid !== unionid) return true + return false + } + + async assertInviteCode(inviterCode) { + const inviter = await this.repository.findUserByInviteCode(inviterCode) + if (!inviter) { + const error = new Error('邀请码无效') + error.status = 400 + throw error + } + return inviter + } + + async sendSmsCode(payload = {}) { + if (!this.smsService) { + const error = new Error('短信服务未启用') + error.status = 501 + throw error + } + return this.smsService.sendVerificationCode(payload) + } + + verifySmsCode(phone, code, purpose) { + if (!this.smsService) { + const error = new Error('短信服务未启用') + error.status = 501 + throw error + } + return this.smsService.verifyCode(phone, code, purpose) + } + + async syncParentDisplayInfo(previous, current) { + if (!current || current.role !== 'parent') return + const referrals = await this.repository.updateReferralInviteeInfo?.(current.id, { + name: current.name, + phone: current.phone, + childGrade: current.child?.grade || '待确认', + }) + if (Array.isArray(referrals) && referrals.length && this.repository.updateLeadInfoByReferral) { + await Promise.all(referrals.map((referral) => this.repository.updateLeadInfoByReferral(referral, { + parent: current.name, + }, previous || {}))) + return + } + if (previous?.name && previous.name !== current.name) { + await this.repository.updateLeadsByParent?.(previous.name, { parent: current.name }) + } + } + + async applyReferralCode(invitee, inviterCode, channel) { + if (!inviterCode || !invitee || invitee.role !== 'parent') return null + const inviter = await this.assertInviteCode(inviterCode) + if (inviter.id === invitee.id) return null + const records = await this.repository.getReferralsByInviter(inviter.id) + const existed = records.some((item) => item.inviteeId === invitee.id || item.phone === invitee.phone) + if (existed) return null + + const rule = await this.pointService.getReferralRule('registered') || { inviter: 20, invitee: 20 } + const referral = await this.repository.addReferral({ + id: createId('rel'), + inviterId: inviter.id, + inviteeId: invitee.id, + name: invitee.name, + phone: invitee.phone, + childGrade: invitee.child?.grade || '待确认', + status: '已注册', + reward: rule.inviter, + channel, + }) + + await this.repository.addLead({ + id: createId('lead'), + referralId: referral.id, + inviteeId: invitee.id, + parent: invitee.name, + source: inviter.name, + stage: '已注册', + advisor: '未分配', + risk: '正常', + channel, + }) + + if (rule.inviter > 0) await this.pointService.grant(inviter.id, `${invitee.name}完成邀请码注册`, rule.inviter) + if (rule.invitee > 0) await this.pointService.grant(invitee.id, '填写邀请码注册奖励', rule.invitee) + return referral + } + + async exchangeWechatCode(code) { + if (!env.wechat.appId || !env.wechat.appSecret) { + const error = new Error('微信登录尚未配置 AppID 和 AppSecret') + error.status = 501 + throw error + } + const params = new URLSearchParams({ + appid: env.wechat.appId, + secret: env.wechat.appSecret, + js_code: code, + grant_type: 'authorization_code', + }) + const response = await fetch(`https://api.weixin.qq.com/sns/jscode2session?${params.toString()}`) + const data = await response.json() + if (!response.ok || data.errcode) { + const error = new Error(data.errmsg || '微信登录校验失败') + error.status = 400 + throw error + } + if (!data.openid) { + const error = new Error('微信登录未返回 openid') + error.status = 400 + throw error + } + return { + openid: data.openid, + unionid: data.unionid || null, + } + } +} + +module.exports = { AuthService } diff --git a/backend/src/services/courseService.js b/backend/src/services/courseService.js new file mode 100644 index 0000000..af53858 --- /dev/null +++ b/backend/src/services/courseService.js @@ -0,0 +1,369 @@ +const { createId } = require('../utils/ids') + +function readPagination(filters = {}) { + const pageNum = Math.max(1, Number(filters.pageNum || filters.page || 1)) + const pageSize = Math.min(100, Math.max(1, Number(filters.pageSize || filters.limit || 10))) + return { pageNum, pageSize } +} + +function paginate(list = [], filters = {}) { + const { pageNum, pageSize } = readPagination(filters) + const start = (pageNum - 1) * pageSize + return { + list: list.slice(start, start + pageSize), + total: list.length, + pageNum, + pageSize, + } +} + +function isValidDateTime(value) { + const match = String(value || '').match(/^(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2})$/) + if (!match) return false + const date = new Date(Number(match[1]), Number(match[2]) - 1, Number(match[3]), Number(match[4]), Number(match[5])) + return date.getFullYear() === Number(match[1]) + && date.getMonth() === Number(match[2]) - 1 + && date.getDate() === Number(match[3]) + && date.getHours() === Number(match[4]) + && date.getMinutes() === Number(match[5]) +} + +class CourseService { + constructor(repository, pointService) { + this.repository = repository + this.pointService = pointService + } + + normalizeCoursePayload(payload = {}) { + const patch = {} + if (payload.name !== undefined) patch.name = String(payload.name).trim() + if (payload.nextTime !== undefined) { + patch.nextTime = String(payload.nextTime).trim() + if (patch.nextTime && !isValidDateTime(patch.nextTime)) { + const error = new Error('试听时间格式无效,请重新选择日期和时间') + error.status = 400 + throw error + } + } + if (payload.campus !== undefined) patch.campus = String(payload.campus).trim() + if (payload.teacher !== undefined) patch.teacher = String(payload.teacher).trim() + if (payload.status !== undefined) patch.status = ['active', 'paused'].includes(payload.status) ? payload.status : 'active' + if (payload.seats !== undefined) patch.seats = Number(payload.seats) + if (payload.pointsBack !== undefined) patch.pointsBack = Number(payload.pointsBack) + if (payload.trialMinutes !== undefined) patch.trialMinutes = Number(payload.trialMinutes) + if (payload.tags !== undefined) patch.tags = Array.isArray(payload.tags) ? payload.tags : String(payload.tags).split(',').map((item) => item.trim()).filter(Boolean) + + for (const key of ['seats', 'pointsBack', 'trialMinutes']) { + if (patch[key] !== undefined && (!Number.isFinite(patch[key]) || patch[key] < 0)) { + const error = new Error('课程数值字段无效') + error.status = 400 + throw error + } + } + return patch + } + + async listCourses(filters = {}) { + const keyword = String(filters.keyword || '').trim() + const campus = String(filters.campus || '').trim() + const courses = await this.repository.getCourses() + const active = courses.filter((course) => course.status !== 'paused') + const filtered = active.filter((course) => { + const matchKeyword = !keyword || [course.name, course.teacher, course.campus, ...(course.tags || [])].some((value) => String(value || '').includes(keyword)) + const matchCampus = !campus || campus === 'all' || campus === '全部' || course.campus === campus + return matchKeyword && matchCampus + }) + if (String(filters.paged || '') !== '1') return filtered + return { + ...paginate(filtered, filters), + campusOptions: [...new Set(active.map((item) => item.campus).filter(Boolean))], + } + } + + async listAdminCourses(filters = {}) { + const keyword = String(filters.keyword || '').trim() + const status = String(filters.status || '').trim() + const campus = String(filters.campus || '').trim() + const courses = await this.repository.getCourses() + const filtered = courses.filter((course) => { + const matchKeyword = !keyword || [course.name, course.teacher, course.campus, ...(course.tags || [])].some((value) => String(value || '').includes(keyword)) + const matchStatus = !status || status === '全部' || course.status === status + const matchCampus = !campus || campus === '全部' || course.campus === campus + return matchKeyword && matchStatus && matchCampus + }) + if (String(filters.paged || '') !== '1') return filtered + const active = filtered.filter((item) => item.status === 'active') + const overview = { + total: filtered.length, + active: active.length, + seats: active.reduce((sum, item) => sum + Number(item.seats || 0), 0), + campuses: new Set(filtered.map((item) => item.campus).filter(Boolean)).size, + avgPoints: active.length ? Math.round(active.reduce((sum, item) => sum + Number(item.pointsBack || 0), 0) / active.length) : 0, + } + return { + ...paginate(filtered, filters), + overview, + campusOptions: [...new Set(courses.map((item) => item.campus).filter(Boolean))], + } + } + + async getAdminCourse(id) { + const course = await this.repository.findCourse(id) + if (!course) { + const error = new Error('课程不存在') + error.status = 404 + throw error + } + return course + } + + async listAppointments(filters = {}) { + const appointments = await this.repository.listAppointments(filters) + const overview = appointments.reduce( + (result, item) => { + result.total += 1 + result[item.status] = (result[item.status] || 0) + 1 + return result + }, + { total: 0, booked: 0, attended: 0, cancelled: 0 }, + ) + return { + ...paginate(appointments, filters), + overview, + } + } + + async listUserAppointments(userId) { + const value = String(userId || '').trim() + if (!value) { + const error = new Error('缺少预约账号') + error.status = 400 + throw error + } + return this.repository.listAppointments({ userId: value }) + } + + async attendAppointment(id) { + const appointment = await this.repository.findAppointmentById(id) + if (!appointment) { + const error = new Error('预约记录不存在') + error.status = 404 + throw error + } + if (appointment.status === 'attended') return appointment + if (appointment.status !== 'booked') { + const error = new Error('当前预约状态不能确认到课') + error.status = 400 + throw error + } + + const referral = await this.repository.findReferralByInvitee?.(appointment.userId) + const bookingRule = referral + ? await this.pointService.getReferralRule('booked') || { inviter: 50, invitee: 50 } + : { inviter: 0, invitee: 0 } + const inviteeSettlement = await this.pointService.settlePendingReference( + appointment.userId, + 'appointment', + appointment.id, + `确认${appointment.course?.name || '试听课'}到课`, + ) + if (!inviteeSettlement) { + await this.settleLegacyAppointmentPoints( + appointment.userId, + Number(appointment.course?.pointsBack || 0) + Number(bookingRule.invitee || 0), + `确认${appointment.course?.name || '试听课'}到课`, + ) + } + + if (referral && !['已到课', '已报名'].includes(referral.status)) { + const inviterSettlement = await this.pointService.settlePendingReference( + referral.inviterId, + 'appointment', + appointment.id, + `${referral.name}确认到课`, + ) + if (!inviterSettlement) { + await this.settleLegacyAppointmentPoints( + referral.inviterId, + Number(bookingRule.inviter || 0), + `${referral.name}确认到课`, + ) + } + const rule = await this.pointService.getReferralRule('attended') || { inviter: 150, invitee: 100 } + const updatedReferral = await this.repository.updateReferral(referral.id, { + status: '已到课', + reward: Number(referral.reward || 0) + Number(rule.inviter || 0), + }) + await this.repository.updateLeadStageByReferral?.(updatedReferral || referral, '已到课') + if (rule.inviter > 0) await this.pointService.grant(referral.inviterId, `${referral.name}确认到课`, rule.inviter) + if (rule.invitee > 0) await this.pointService.grant(appointment.userId, '推荐到课奖励', rule.invitee) + } + + return this.repository.updateAppointment(id, { status: 'attended' }) + } + + async settleLegacyAppointmentPoints(userId, expectedAmount, title) { + if (expectedAmount <= 0) return null + const account = await this.repository.getPointAccount(userId) + const amount = Math.min(Number(account.pending || 0), expectedAmount) + if (amount <= 0) return null + return this.pointService.settlePending(userId, amount, title) + } + + async createCourse(payload) { + const course = { + id: createId('course'), + name: '新试听课程', + tags: ['试听'], + nextTime: '', + pointsBack: 0, + seats: 0, + campus: '', + teacher: '', + trialMinutes: 45, + status: 'paused', + ...this.normalizeCoursePayload(payload), + } + if (!course.name) { + const error = new Error('课程名称不能为空') + error.status = 400 + throw error + } + return this.repository.addCourse(course) + } + + async updateCourse(id, payload) { + const patch = this.normalizeCoursePayload(payload) + if (patch.name !== undefined && !patch.name) { + const error = new Error('课程名称不能为空') + error.status = 400 + throw error + } + const course = await this.repository.updateCourse(id, patch) + if (!course) { + const error = new Error('课程不存在') + error.status = 404 + throw error + } + return course + } + + async deleteCourse(id) { + const appointments = await this.repository.listAppointments({ courseId: id }) + if (appointments.length) { + const error = new Error('该课程已有预约记录,不能删除;请暂停课程以保留历史记录') + error.status = 409 + throw error + } + if (patch.nextTime !== undefined && !patch.nextTime) { + const error = new Error('请选择试听日期和时间') + error.status = 400 + throw error + } + if (!course.nextTime) { + const error = new Error('请选择试听日期和时间') + error.status = 400 + throw error + } + const course = await this.repository.deleteCourse(id) + if (!course) { + const error = new Error('课程不存在') + error.status = 404 + throw error + } + return course + } + + async book(payload) { + const userId = String(payload.userId || '').trim() + if (!userId) { + const error = new Error('缺少预约账号') + error.status = 400 + throw error + } + const user = await this.repository.findUserById(userId) + if (!user || user.role !== 'parent') { + const error = new Error('家长账号不存在') + error.status = 404 + throw error + } + if (user.status !== 'active') { + const error = new Error('账号已停用,不能预约课程') + error.status = 403 + throw error + } + if (!user.phoneBound || !user.phone) { + const error = new Error('请先绑定手机号再预约课程') + error.status = 400 + throw error + } + if (payload.childId && user.child?.id && payload.childId !== user.child.id) { + const error = new Error('预约学生信息与当前账号不一致') + error.status = 400 + throw error + } + const appointments = await this.repository.listAppointments({ userId }) + const activeAppointments = appointments.filter((item) => item.status !== 'cancelled') + if (activeAppointments.some((item) => item.courseId === payload.courseId)) { + const error = new Error('该试听课程已经预约,请勿重复预约') + error.status = 400 + throw error + } + const trialBookingLimit = Number.isInteger(Number(user.trialBookingLimit)) ? Number(user.trialBookingLimit) : 1 + if (activeAppointments.length >= trialBookingLimit) { + const error = new Error(trialBookingLimit > 0 + ? `当前账号最多可预约 ${trialBookingLimit} 次试听课程` + : '当前账号暂不可预约试听课程') + error.status = 400 + throw error + } + const course = await this.repository.findCourse(payload.courseId) + if (!course) { + const error = new Error('课程不存在') + error.status = 404 + throw error + } + if (course.status !== 'active') { + const error = new Error('该课程已暂停预约') + error.status = 400 + throw error + } + if (course.seats <= 0) { + const error = new Error('该课程已约满') + error.status = 400 + throw error + } + + const appointment = await this.repository.addAppointment({ + id: createId('appt'), + userId, + childId: payload.childId, + courseId: payload.courseId, + status: 'booked', + createdAt: new Date().toISOString(), + }) + + await this.repository.updateCourse(course.id, { seats: course.seats - 1 }) + const referral = await this.repository.findReferralByInvitee?.(userId) + if (referral && !['已预约', '已到课', '已报名'].includes(referral.status)) { + const rule = await this.pointService.getReferralRule('booked') || { inviter: 50, invitee: 50 } + const updatedReferral = await this.repository.updateReferral(referral.id, { + status: '已预约', + reward: Number(referral.reward || 0) + Number(rule.inviter || 0), + }) + await this.repository.updateLeadStageByReferral?.(updatedReferral || referral, '已预约') + const reference = { referenceType: 'appointment', referenceId: appointment.id } + if (rule.inviter > 0) await this.pointService.grant(referral.inviterId, `${referral.name}预约试听`, rule.inviter, 'pending', reference) + if (rule.invitee > 0) await this.pointService.grant(userId, '推荐预约试听奖励', rule.invitee, 'pending', reference) + } + if (course.pointsBack > 0) { + await this.pointService.grant(userId, `预约${course.name}`, course.pointsBack, 'pending', { + referenceType: 'appointment', + referenceId: appointment.id, + }) + } + return appointment + } +} + +module.exports = { CourseService } diff --git a/backend/src/services/index.js b/backend/src/services/index.js new file mode 100644 index 0000000..f75cfad --- /dev/null +++ b/backend/src/services/index.js @@ -0,0 +1,24 @@ +const { repository } = require('../repositories') +const { PointService } = require('./pointService') +const { ReferralService } = require('./referralService') +const { CourseService } = require('./courseService') +const { AdminService } = require('./adminService') +const { AuthService } = require('./authService') +const { SmsService } = require('./smsService') + +const pointService = new PointService(repository) +const smsService = new SmsService() +const referralService = new ReferralService(repository, pointService, smsService) +const courseService = new CourseService(repository, pointService) +const adminService = new AdminService(repository, pointService) +const authService = new AuthService(repository, pointService, smsService) + +module.exports = { + repository, + smsService, + pointService, + referralService, + courseService, + adminService, + authService, +} diff --git a/backend/src/services/pointService.js b/backend/src/services/pointService.js new file mode 100644 index 0000000..6f44c87 --- /dev/null +++ b/backend/src/services/pointService.js @@ -0,0 +1,646 @@ +const { createId } = require('../utils/ids') + +const REDEMPTION_STATUS_LABELS = { + pending_review: '待审核', + approved: '已发券', + rejected: '已驳回', + used: '已核销', + expired: '已过期', +} + +const VOUCHER_STATUS_LABELS = { + not_issued: '未发券', + issued: '待核销', + used: '已核销', + void: '已作废', + expired: '已过期', +} + +function toDateTime(value = new Date()) { + return new Date(value).toISOString().slice(0, 16).replace('T', ' ') +} + +function addDays(days) { + const date = new Date() + date.setDate(date.getDate() + days) + return toDateTime(date) +} + +function readPagination(filters = {}) { + const pageNum = Math.max(1, Number(filters.pageNum || filters.page || 1)) + const pageSize = Math.min(100, Math.max(1, Number(filters.pageSize || filters.limit || 10))) + return { pageNum, pageSize } +} + +function paginate(list = [], filters = {}) { + const { pageNum, pageSize } = readPagination(filters) + const start = (pageNum - 1) * pageSize + return { + list: list.slice(start, start + pageSize), + total: list.length, + pageNum, + pageSize, + } +} + +class PointService { + constructor(repository) { + this.repository = repository + } + + async getCenter(userId) { + const redemptions = await this.repository.listRedemptions({ userId }) + return { + account: await this.repository.getPointAccount(userId), + transactions: await this.repository.getPointTransactions(userId), + rewards: await this.repository.getRewards(), + redemptions: redemptions.map((item) => this.decorateRedemption(item)), + expiryRule: await this.repository.getPointExpiryRule(), + expirySchedules: await this.repository.listPointExpirySchedules(userId), + } + } + + async listUserRewards(userId, filters = {}) { + const keyword = String(filters.keyword || '').trim() + const rewards = await this.repository.listRewards(filters) + const filtered = rewards.filter((reward) => { + const matchKeyword = !keyword || [reward.name, reward.type, reward.description].some((value) => String(value || '').includes(keyword)) + return matchKeyword + }) + return paginate(filtered, filters) + } + + async listUserTransactions(userId, filters = {}) { + const keyword = String(filters.keyword || '').trim() + const transactions = await this.repository.getPointTransactions(userId) + const filtered = transactions.filter((item) => { + const matchKeyword = !keyword || [item.title, item.createdAt, item.status].some((value) => String(value || '').includes(keyword)) + const matchStatus = !filters.status || filters.status === 'all' || item.status === filters.status + return matchKeyword && matchStatus + }) + return paginate(filtered, filters) + } + + async listUserRedemptions(userId, filters = {}) { + const keyword = String(filters.keyword || '').trim() + const redemptions = (await this.repository.listRedemptions({ userId })).map((item) => this.decorateRedemption(item)) + const filtered = redemptions.filter((item) => { + const matchKeyword = !keyword || [item.id, item.reward?.name, item.voucherCode, item.statusLabel, item.rejectedReason].some((value) => String(value || '').includes(keyword)) + const matchStatus = !filters.status || filters.status === 'all' || item.status === filters.status + return matchKeyword && matchStatus + }) + return paginate(filtered, filters) + } + + async getAdminManager() { + const parentUsers = await this.repository.listParentUsers() + const accounts = await Promise.all(parentUsers.map(async (user) => ({ + user, + points: await this.repository.getPointAccount(user.id), + }))) + const rawTransactions = await this.repository.listPointTransactions() + const transactions = await Promise.all(rawTransactions.map(async (transaction) => ({ + ...transaction, + userName: (await this.repository.findUserById(transaction.userId))?.name || transaction.userId, + }))) + const rawExpirySchedules = await this.repository.listPointExpirySchedules() + const expirySchedules = await Promise.all(rawExpirySchedules.map(async (item) => ({ + ...item, + userName: (await this.repository.findUserById(item.userId))?.name || item.userId, + }))) + const redemptions = await this.repository.listRedemptions() + const overview = accounts.reduce( + (result, item) => { + result.available += item.points.available + result.pending += item.points.pending + result.frozen += item.points.frozen + result.expiring += item.points.expiring + return result + }, + { available: 0, pending: 0, frozen: 0, expiring: 0 }, + ) + + return { + overview: { + ...overview, + parents: accounts.length, + rewards: (await this.repository.getRewards()).length, + transactions: transactions.length, + pendingRedemptions: redemptions.filter((item) => item.status === 'pending_review').length, + issuedVouchers: redemptions.filter((item) => item.voucherStatus === 'issued').length, + nextExpireAt: expirySchedules[0]?.expireAt || '', + }, + accounts, + transactions, + expiryRule: await this.repository.getPointExpiryRule(), + expirySchedules, + rewards: await this.repository.getRewards(), + redemptions: redemptions.slice(0, 8).map((item) => this.decorateRedemption(item)), + rules: await this.repository.getReferralRules(), + } + } + + async listPointAccounts(filters = {}) { + const keyword = String(filters.keyword || '').trim() + const parentUsers = await this.repository.listParentUsers() + const rows = await Promise.all(parentUsers.map(async (user) => ({ + user, + points: await this.repository.getPointAccount(user.id), + }))) + const filtered = rows.filter((item) => { + const matchKeyword = !keyword || [item.user.name, item.user.phone, item.user.id, item.user.child?.name].some((value) => String(value || '').includes(keyword)) + const matchStatus = !filters.pointStatus + || filters.pointStatus === 'all' + || (filters.pointStatus === 'available' && item.points.available > 0) + || (filters.pointStatus === 'pending' && item.points.pending > 0) + || (filters.pointStatus === 'expiring' && item.points.expiring > 0) + || (filters.pointStatus === 'frozen' && item.points.frozen > 0) + return matchKeyword && matchStatus + }) + const overview = filtered.reduce( + (result, item) => { + result.available += item.points.available + result.pending += item.points.pending + result.frozen += item.points.frozen + result.expiring += item.points.expiring + return result + }, + { available: 0, pending: 0, frozen: 0, expiring: 0 }, + ) + return { + ...paginate(filtered, filters), + overview: { + ...overview, + parents: filtered.length, + }, + } + } + + async listPointTransactions(filters = {}) { + const keyword = String(filters.keyword || '').trim() + const startDate = String(filters.startDate || '').trim() + const endDate = String(filters.endDate || '').trim() + const rawTransactions = await this.repository.listPointTransactions() + const rows = await Promise.all(rawTransactions.map(async (transaction) => ({ + ...transaction, + userName: (await this.repository.findUserById(transaction.userId))?.name || transaction.userId, + }))) + const filtered = rows.filter((item) => { + const matchUser = !filters.userId || item.userId === filters.userId + const matchStatus = !filters.status || filters.status === 'all' || item.status === filters.status + const matchDate = (!startDate || item.createdAt >= startDate) && (!endDate || item.createdAt <= endDate) + const matchKeyword = !keyword || [item.userName, item.title, item.userId].some((value) => String(value || '').includes(keyword)) + return matchUser && matchStatus && matchDate && matchKeyword + }) + const overview = filtered.reduce( + (result, item) => { + if (item.status === 'pending') result.pending += item.amount + if (item.status !== 'pending' && item.amount > 0) result.income += item.amount + if (item.status !== 'pending' && item.amount < 0) result.expense += Math.abs(item.amount) + return result + }, + { income: 0, expense: 0, pending: 0 }, + ) + return { + ...paginate(filtered, filters), + overview, + expiryRule: await this.repository.getPointExpiryRule(), + expirySchedules: await this.listPointExpirySchedules(filters), + } + } + + async listPointExpirySchedules(filters = {}) { + const keyword = String(filters.expiryKeyword || filters.keyword || '').trim() + const rawExpirySchedules = await this.repository.listPointExpirySchedules(filters.userId) + const rows = await Promise.all(rawExpirySchedules.map(async (item) => ({ + ...item, + userName: (await this.repository.findUserById(item.userId))?.name || item.userId, + }))) + return rows.filter((item) => { + const matchKeyword = !keyword || [item.userName, item.source, item.userId].some((value) => String(value || '').includes(keyword)) + const matchDate = (!filters.expireStart || item.expireAt >= filters.expireStart) && (!filters.expireEnd || item.expireAt <= filters.expireEnd) + return matchKeyword && matchDate + }) + } + + async getReferralRule(event) { + const rules = await this.repository.getReferralRules() + return rules.find((rule) => rule.event === event) || null + } + + normalizeReferralRulePayload(payload = {}) { + const patch = {} + if (payload.title !== undefined) patch.title = String(payload.title).trim() + if (payload.inviter !== undefined) patch.inviter = Number(payload.inviter) + if (payload.invitee !== undefined) patch.invitee = Number(payload.invitee) + if (!patch.title) { + const error = new Error('规则名称不能为空') + error.status = 400 + throw error + } + for (const key of ['inviter', 'invitee']) { + if (!Number.isFinite(patch[key]) || patch[key] < 0) { + const error = new Error('奖励积分必须是不小于 0 的数字') + error.status = 400 + throw error + } + patch[key] = Math.round(patch[key]) + } + return patch + } + + async updateReferralRule(event, payload = {}) { + const rule = await this.repository.updateReferralRule(event, this.normalizeReferralRulePayload(payload)) + if (!rule) { + const error = new Error('推荐奖励规则不存在') + error.status = 404 + throw error + } + return rule + } + + async listRewards(filters = {}) { + const rewards = await this.repository.listRewards(filters) + const overview = rewards.reduce( + (result, item) => { + result.total += 1 + if (item.stock > 0) result.inStock += 1 + if (item.stock <= 0) result.soldOut += 1 + return result + }, + { total: 0, inStock: 0, soldOut: 0 }, + ) + return { + ...paginate(rewards, filters), + overview, + } + } + + async getRewardDetail(id) { + const reward = await this.repository.findReward(id) + if (!reward) { + const error = new Error('兑换权益不存在') + error.status = 404 + throw error + } + const redemptions = (await this.repository.listRedemptions({ itemId: id })).slice(0, 10).map((item) => this.decorateRedemption(item)) + return { reward, redemptions } + } + + normalizeRewardPayload(payload = {}) { + const reward = {} + if (payload.name !== undefined) reward.name = String(payload.name).trim() + if (payload.type !== undefined) reward.type = String(payload.type).trim() + if (payload.cost !== undefined) reward.cost = Number(payload.cost) + if (payload.stock !== undefined) reward.stock = Number(payload.stock) + if (payload.description !== undefined) reward.description = String(payload.description || '').trim() + if (!reward.name) { + const error = new Error('兑换权益名称不能为空') + error.status = 400 + throw error + } + if (!reward.type) reward.type = '课程权益' + if (!Number.isFinite(reward.cost) || reward.cost < 0) { + const error = new Error('兑换积分无效') + error.status = 400 + throw error + } + if (!Number.isFinite(reward.stock) || reward.stock < 0) { + const error = new Error('库存数量无效') + error.status = 400 + throw error + } + return reward + } + + async createReward(payload = {}) { + return this.repository.addReward({ + id: createId('reward'), + description: '', + ...this.normalizeRewardPayload(payload), + }) + } + + async grant(userId, title, amount, status = 'available', reference = {}) { + const account = await this.repository.getPointAccount(userId) + const target = status === 'pending' ? 'pending' : 'available' + account[target] += Number(amount) + await this.repository.updatePointAccount(userId, account) + return this.repository.addPointTransaction({ + id: createId('pt'), + userId, + title, + amount, + status, + referenceType: reference.referenceType || '', + referenceId: reference.referenceId || '', + createdAt: new Date().toISOString().slice(0, 10), + }) + } + + async adjust(userId, amount, title, status = 'available') { + const numericAmount = Number(amount) + if (!Number.isFinite(numericAmount) || numericAmount === 0) { + const error = new Error('积分调整数量无效') + error.status = 400 + throw error + } + const user = await this.repository.findUserById(userId) + if (!user || user.role !== 'parent') { + const error = new Error('家长账号不存在') + error.status = 404 + throw error + } + const target = status === 'pending' ? 'pending' : 'available' + const account = await this.repository.getPointAccount(userId) + if (account[target] + numericAmount < 0) { + const error = new Error('调整后积分不能小于 0') + error.status = 400 + throw error + } + account[target] += numericAmount + await this.repository.updatePointAccount(userId, account) + return this.repository.addPointTransaction({ + id: createId('pt'), + userId, + title: title || '后台手动调整', + amount: numericAmount, + status: target, + createdAt: new Date().toISOString().slice(0, 10), + }) + } + + async settlePending(userId, amount, title = '手动确认到账', reference = {}) { + const numericAmount = Number(amount) + if (!Number.isFinite(numericAmount) || numericAmount <= 0) { + const error = new Error('到账积分数量无效') + error.status = 400 + throw error + } + const user = await this.repository.findUserById(userId) + if (!user || user.role !== 'parent') { + const error = new Error('家长账号不存在') + error.status = 404 + throw error + } + const account = await this.repository.getPointAccount(userId) + if (account.pending < numericAmount) { + const error = new Error('待到账积分不足') + error.status = 400 + throw error + } + account.pending -= numericAmount + account.available += numericAmount + await this.repository.updatePointAccount(userId, account) + + const pendingTransaction = await this.repository.addPointTransaction({ + id: createId('pt'), + userId, + title: `${title || '手动确认到账'}(待到账转出)`, + amount: -numericAmount, + status: 'pending', + referenceType: reference.referenceType || '', + referenceId: reference.referenceId || '', + createdAt: new Date().toISOString().slice(0, 10), + }) + const transaction = await this.repository.addPointTransaction({ + id: createId('pt'), + userId, + title: `${title || '手动确认到账'}(已到账)`, + amount: numericAmount, + status: 'available', + referenceType: reference.referenceType || '', + referenceId: reference.referenceId || '', + createdAt: new Date().toISOString().slice(0, 10), + }) + return { + account, + pendingTransaction, + transaction, + } + } + + async settlePendingReference(userId, referenceType, referenceId, title) { + if (!referenceType || !referenceId) return null + const transactions = await this.repository.getPointTransactions(userId) + const amount = transactions + .filter((item) => item.status === 'pending' && item.referenceType === referenceType && item.referenceId === referenceId) + .reduce((sum, item) => sum + Number(item.amount || 0), 0) + if (amount <= 0) return null + return this.settlePending(userId, amount, title, { referenceType, referenceId }) + } + + async updateReward(id, payload) { + const patch = {} + if (payload.name !== undefined) patch.name = String(payload.name).trim() + if (payload.type !== undefined) patch.type = String(payload.type).trim() + if (payload.cost !== undefined) patch.cost = Number(payload.cost) + if (payload.stock !== undefined) patch.stock = Number(payload.stock) + if (payload.description !== undefined) patch.description = String(payload.description || '').trim() + if (patch.cost !== undefined && (!Number.isFinite(patch.cost) || patch.cost < 0)) { + const error = new Error('兑换积分无效') + error.status = 400 + throw error + } + if (patch.stock !== undefined && (!Number.isFinite(patch.stock) || patch.stock < 0)) { + const error = new Error('库存数量无效') + error.status = 400 + throw error + } + const reward = await this.repository.updateReward(id, patch) + if (!reward) { + const error = new Error('兑换权益不存在') + error.status = 404 + throw error + } + return reward + } + + async redeem(userId, itemId) { + const user = await this.repository.findUserById(userId) + if (!user || user.role !== 'parent') { + const error = new Error('家长账号不存在') + error.status = 404 + throw error + } + const reward = await this.repository.findReward(itemId) + if (!reward) { + const error = new Error('兑换权益不存在') + error.status = 404 + throw error + } + + const account = await this.repository.getPointAccount(userId) + if (account.available < reward.cost) { + const error = new Error('可用积分不足') + error.status = 400 + throw error + } + if (Number(reward.stock || 0) <= 0) { + const error = new Error('兑换权益库存不足') + error.status = 400 + throw error + } + + account.available -= reward.cost + await this.repository.updatePointAccount(userId, account) + await this.repository.updateReward(reward.id, { stock: reward.stock - 1 }) + await this.repository.addPointTransaction({ + id: createId('pt'), + userId, + title: `兑换${reward.name}`, + amount: -reward.cost, + status: 'available', + createdAt: new Date().toISOString().slice(0, 10), + }) + + return this.repository.addRedemption({ + id: createId('redeem'), + userId, + itemId, + costPoints: reward.cost, + status: 'pending_review', + voucherStatus: 'not_issued', + createdAt: toDateTime(), + }) + } + + async listRedemptions(filters = {}) { + const list = await this.repository.listRedemptions(filters) + const overviewFilters = { + ...filters, + status: 'all', + voucherStatus: 'all', + } + const overviewList = await this.repository.listRedemptions(overviewFilters) + const overview = overviewList.reduce( + (result, item) => { + result.total += 1 + result[item.status] = (result[item.status] || 0) + 1 + if (item.voucherStatus === 'issued') result.issuedVouchers += 1 + return result + }, + { total: 0, pending_review: 0, approved: 0, rejected: 0, used: 0, expired: 0, issuedVouchers: 0 }, + ) + return { + ...paginate(list.map((item) => this.decorateRedemption(item)), filters), + overview, + statusLabels: REDEMPTION_STATUS_LABELS, + voucherStatusLabels: VOUCHER_STATUS_LABELS, + } + } + + decorateRedemption(order) { + return { + ...order, + statusLabel: REDEMPTION_STATUS_LABELS[order.status] || order.status, + voucherStatusLabel: VOUCHER_STATUS_LABELS[order.voucherStatus] || order.voucherStatus, + } + } + + createVoucherCode() { + const time = Date.now().toString(36).toUpperCase() + const random = Math.random().toString(36).slice(2, 6).toUpperCase() + return `LFH-${time}-${random}` + } + + async approveRedemption(id, operatorId, payload = {}) { + const order = await this.repository.findRedemptionById(id) + if (!order) { + const error = new Error('兑换申请不存在') + error.status = 404 + throw error + } + if (order.status !== 'pending_review') { + const error = new Error('只有待审核申请可以通过') + error.status = 400 + throw error + } + + let voucherCode = this.createVoucherCode() + for (let i = 0; i < 5; i += 1) { + const exists = await this.repository.findRedemptionByVoucherCode(voucherCode) + if (!exists) break + voucherCode = this.createVoucherCode() + } + + const expireAt = payload.expireAt ? String(payload.expireAt) : addDays(Number(payload.validDays || 30)) + return this.decorateRedemption(await this.repository.updateRedemption(id, { + status: 'approved', + voucherCode, + voucherStatus: 'issued', + reviewedBy: operatorId || '', + reviewedAt: toDateTime(), + expireAt, + })) + } + + async rejectRedemption(id, operatorId, payload = {}) { + const order = await this.repository.findRedemptionById(id) + if (!order) { + const error = new Error('兑换申请不存在') + error.status = 404 + throw error + } + if (!['pending_review', 'approved'].includes(order.status) || order.voucherStatus === 'used') { + const error = new Error('当前状态不能驳回') + error.status = 400 + throw error + } + + const account = await this.repository.getPointAccount(order.userId) + const refund = Number(order.costPoints || order.reward?.cost || 0) + if (refund > 0) { + account.available += refund + await this.repository.updatePointAccount(order.userId, account) + await this.repository.addPointTransaction({ + id: createId('pt'), + userId: order.userId, + title: `兑换驳回退还${order.reward?.name || '学习权益'}`, + amount: refund, + status: 'available', + createdAt: new Date().toISOString().slice(0, 10), + }) + } + + return this.decorateRedemption(await this.repository.updateRedemption(id, { + status: 'rejected', + voucherStatus: 'void', + reviewedBy: operatorId || '', + reviewedAt: toDateTime(), + rejectedReason: String(payload.reason || '审核未通过').trim(), + })) + } + + async verifyVoucher(payload = {}) { + const id = String(payload.id || '').trim() + const code = String(payload.code || '').trim().toUpperCase() + const order = id ? await this.repository.findRedemptionById(id) : await this.repository.findRedemptionByVoucherCode(code) + if (!order) { + const error = new Error('券码不存在') + error.status = 404 + throw error + } + if (order.status !== 'approved' || order.voucherStatus !== 'issued') { + const error = new Error('当前券码不能核销') + error.status = 400 + throw error + } + if (order.expireAt && new Date(order.expireAt.replace(' ', 'T')).getTime() < Date.now()) { + await this.repository.updateRedemption(order.id, { status: 'expired', voucherStatus: 'expired' }) + const error = new Error('券码已过期') + error.status = 400 + throw error + } + + return this.decorateRedemption(await this.repository.updateRedemption(order.id, { + status: 'used', + voucherStatus: 'used', + usedAt: toDateTime(), + usedBy: String(payload.operatorId || '').trim(), + verifyNote: String(payload.note || '现场核销').trim(), + })) + } +} + +module.exports = { PointService } diff --git a/backend/src/services/referralService.js b/backend/src/services/referralService.js new file mode 100644 index 0000000..ac695bc --- /dev/null +++ b/backend/src/services/referralService.js @@ -0,0 +1,254 @@ +const { createId } = require('../utils/ids') +const { env } = require('../config/env') +const { createSessionToken } = require('../utils/sessionToken') + +let wechatTokenCache = { + token: '', + expiresAt: 0, +} + +function readPagination(filters = {}) { + const pageNum = Math.max(1, Number(filters.pageNum || filters.page || 1)) + const pageSize = Math.min(100, Math.max(1, Number(filters.pageSize || filters.limit || 10))) + return { pageNum, pageSize } +} + +function paginate(list = [], filters = {}) { + const { pageNum, pageSize } = readPagination(filters) + const start = (pageNum - 1) * pageSize + return { + list: list.slice(start, start + pageSize), + total: list.length, + pageNum, + pageSize, + } +} + +class ReferralService { + constructor(repository, pointService, smsService) { + this.repository = repository + this.pointService = pointService + this.smsService = smsService + } + + async getCenter(inviterId, filters = {}) { + if (!inviterId) { + const error = new Error('缺少推荐人') + error.status = 400 + throw error + } + const records = await this.repository.getReferralsByInviter(inviterId) + const keyword = String(filters.keyword || '').trim() + const status = String(filters.status || '').trim() + const filteredRecords = records.filter((item) => { + const matchKeyword = !keyword || [item.name, item.phone, item.childGrade, item.channel, item.status].some((value) => String(value || '').includes(keyword)) + const matchStatus = !status || status === 'all' || item.status === status + return matchKeyword && matchStatus + }) + return { + stats: this.getStats(records), + rules: (await this.repository.getReferralRules()).map(({ title, inviter, invitee }) => ({ title, inviter, invitee })), + records: String(filters.paged || '') === '1' ? paginate(filteredRecords, filters) : filteredRecords, + share: await this.createShare('默认', inviterId), + } + } + + async createShare(channel, inviterId) { + if (!inviterId) { + const error = new Error('缺少推荐人') + error.status = 400 + throw error + } + const inviter = await this.repository.findUserById(inviterId) + if (!inviter) { + const error = new Error('推荐人不存在') + error.status = 404 + throw error + } + return { + title: `${inviter.name}邀请你领取立方和教育试听积分`, + channel, + path: `/pages/login/index?inviteCode=${inviter.inviterCode}`, + posterText: '扫码领取试听积分', + } + } + + async createMiniProgramCode(inviterId) { + if (!inviterId) { + const error = new Error('缺少推荐人') + error.status = 400 + throw error + } + const inviter = await this.repository.findUserById(inviterId) + if (!inviter) { + const error = new Error('推荐人不存在') + error.status = 404 + throw error + } + if (!env.wechat.appId || !env.wechat.appSecret) { + const error = new Error('微信小程序码尚未配置 AppID 和 AppSecret') + error.status = 501 + throw error + } + + const accessToken = await this.getWechatAccessToken() + const response = await fetch(`https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token=${accessToken}`, { + method: 'POST', + headers: { 'content-type': 'application/json' }, + body: JSON.stringify({ + scene: `invite=${inviter.inviterCode}`, + page: 'pages/login/index', + check_path: false, + env_version: env.wechat.envVersion || 'release', + width: 430, + }), + }) + + const contentType = response.headers.get('content-type') || '' + if (contentType.includes('application/json')) { + const data = await response.json() + const error = new Error(data.errmsg || '微信小程序码生成失败') + error.status = 400 + throw error + } + if (!response.ok) { + const error = new Error('微信小程序码生成失败') + error.status = 400 + throw error + } + + const buffer = Buffer.from(await response.arrayBuffer()) + return { + inviterCode: inviter.inviterCode, + path: `/pages/login/index?inviteCode=${inviter.inviterCode}`, + image: `data:image/png;base64,${buffer.toString('base64')}`, + } + } + + async getWechatAccessToken() { + if (wechatTokenCache.token && Date.now() < wechatTokenCache.expiresAt) return wechatTokenCache.token + const params = new URLSearchParams({ + grant_type: 'client_credential', + appid: env.wechat.appId, + secret: env.wechat.appSecret, + }) + const response = await fetch(`https://api.weixin.qq.com/cgi-bin/token?${params.toString()}`) + const data = await response.json() + if (!response.ok || data.errcode || !data.access_token) { + const error = new Error(data.errmsg || '微信 access_token 获取失败') + error.status = 400 + throw error + } + wechatTokenCache = { + token: data.access_token, + expiresAt: Date.now() + Math.max(60, Number(data.expires_in || 7200) - 300) * 1000, + } + return wechatTokenCache.token + } + + async bindReferral(payload) { + const inviterCode = String(payload.inviterCode || '').trim().toUpperCase() + const parentName = String(payload.parentName || '').trim() + const phone = String(payload.phone || '').trim() + const code = String(payload.code || '').trim() + const childName = String(payload.childName || '').trim() + const grade = String(payload.grade || '').trim() + if (!parentName || !/^1\d{10}$/.test(phone)) { + const error = new Error('家长姓名和正确手机号必填') + error.status = 400 + throw error + } + if (!this.smsService) { + const error = new Error('短信服务未启用') + error.status = 501 + throw error + } + this.smsService.verifyCode(phone, code, 'referral_register') + + const inviter = await this.repository.findUserByInviteCode(inviterCode) + if (!inviter) { + const error = new Error('推荐码无效') + error.status = 400 + throw error + } + + const existed = await this.repository.findUserByLoginAccount(phone) + if (existed) { + const error = new Error('该手机号已注册,不能重复领取新客奖励') + error.status = 409 + throw error + } + + const invitee = await this.repository.addUser({ + id: createId('parent'), + username: phone, + passwordHash: null, + role: 'parent', + roleName: '家长', + name: parentName, + phone, + status: 'active', + inviterCode: `LFH-${Math.random().toString(36).slice(2, 7).toUpperCase()}`, + child: { id: createId('child'), name: childName || '未填写', grade: grade || '待确认', focus: '待测评' }, + }) + + const rule = await this.pointService.getReferralRule('registered') || { inviter: 20, invitee: 20 } + const referral = await this.repository.addReferral({ + id: createId('rel'), + inviterId: inviter.id, + inviteeId: invitee.id, + name: parentName, + phone, + childGrade: grade || '待确认', + status: '已注册', + reward: rule.inviter, + channel: 'H5/小程序', + }) + + await this.repository.addLead({ + id: createId('lead'), + referralId: referral.id, + inviteeId: invitee.id, + parent: parentName, + source: inviter.name, + stage: '已注册', + advisor: '未分配', + risk: '正常', + channel: referral.channel, + }) + + if (rule.inviter > 0) await this.pointService.grant(inviter.id, `${parentName}完成注册`, rule.inviter) + if (rule.invitee > 0) await this.pointService.grant(invitee.id, '新家长注册奖励', rule.invitee) + + const safeInvitee = await this.repository.withPermissions(invitee) + return { + referral, + invitee: { + ...safeInvitee, + sessionToken: createSessionToken(safeInvitee.id), + }, + } + } + + getStats(records) { + const stageRank = { + 待注册: 0, + 已注册: 1, + 已预约: 2, + 已到课: 3, + 已报名: 4, + } + const reached = (status) => records.filter((item) => (stageRank[item.status] || 0) >= stageRank[status]).length + const purchased = reached('已报名') + return { + invited: records.length, + registered: reached('已注册'), + booked: reached('已预约'), + attended: reached('已到课'), + purchased, + conversion: records.length ? Math.round((purchased / records.length) * 100) : 0, + } + } +} + +module.exports = { ReferralService } diff --git a/backend/src/services/smsService.js b/backend/src/services/smsService.js new file mode 100644 index 0000000..18c086e --- /dev/null +++ b/backend/src/services/smsService.js @@ -0,0 +1,179 @@ +const crypto = require('crypto') +const { env } = require('../config/env') + +const VALID_PURPOSES = ['login', 'bind_wechat', 'update_phone', 'referral_register'] + +function nowSeconds() { + return Math.floor(Date.now() / 1000) +} + +function toAliyunTimestamp(date = new Date()) { + return date.toISOString().replace(/\.\d{3}Z$/, 'Z') +} + +function percentEncode(value) { + return encodeURIComponent(String(value)) + .replace(/\+/g, '%20') + .replace(/\*/g, '%2A') + .replace(/%7E/g, '~') +} + +function hasRealConfig(value) { + const text = String(value || '').trim() + return Boolean(text && !text.startsWith('your_') && text !== 'SMS_000000000') +} + +class SmsService { + constructor(options = env.sms) { + this.options = options + this.codes = new Map() + } + + normalizePhone(phone) { + return String(phone || '').trim() + } + + assertPhone(phone) { + if (!/^1\d{10}$/.test(phone)) { + const error = new Error('手机号格式不正确') + error.status = 400 + throw error + } + } + + normalizePurpose(purpose) { + const value = String(purpose || 'login').trim() + if (!VALID_PURPOSES.includes(value)) { + const error = new Error('验证码用途无效') + error.status = 400 + throw error + } + return value + } + + cacheKey(phone, purpose) { + return `${purpose}:${phone}` + } + + createCode() { + const length = Math.max(4, Math.min(8, Number(this.options.codeLength || 6))) + const min = 10 ** (length - 1) + const max = (10 ** length) - 1 + return String(crypto.randomInt(min, max + 1)) + } + + async sendVerificationCode(payload = {}) { + const phone = this.normalizePhone(payload.phone) + const purpose = this.normalizePurpose(payload.purpose) + this.assertPhone(phone) + + const key = this.cacheKey(phone, purpose) + const existed = this.codes.get(key) + const current = nowSeconds() + const cooldown = Math.max(0, Number(this.options.codeCooldownSeconds || 60)) + if (existed && existed.sentAt + cooldown > current) { + const error = new Error(`验证码发送过于频繁,请 ${existed.sentAt + cooldown - current} 秒后再试`) + error.status = 429 + throw error + } + + const code = this.createCode() + if (this.shouldUseAliyun()) { + await this.sendAliyunSms(phone, code) + this.codes.set(key, { + code, + sentAt: current, + expiresAt: current + Math.max(60, Number(this.options.codeTtlSeconds || 300)), + }) + return { + phone, + purpose, + expiresIn: Number(this.options.codeTtlSeconds || 300), + cooldown, + message: '验证码已发送', + } + } + + if (this.options.allowTestCode) { + return { + phone, + purpose, + expiresIn: Number(this.options.codeTtlSeconds || 300), + cooldown, + message: '短信未配置,测试验证码可用', + } + } + + const error = new Error('短信服务未配置') + error.status = 501 + throw error + } + + verifyCode(phoneValue, codeValue, purposeValue = 'login') { + const phone = this.normalizePhone(phoneValue) + const code = String(codeValue || '').trim() + const purpose = this.normalizePurpose(purposeValue) + this.assertPhone(phone) + + if (this.options.allowTestCode && code === String(this.options.testCode || '111111')) return true + + const key = this.cacheKey(phone, purpose) + const record = this.codes.get(key) + if (!record || record.expiresAt < nowSeconds() || record.code !== code) { + const error = new Error('验证码错误') + error.status = 401 + throw error + } + this.codes.delete(key) + return true + } + + shouldUseAliyun() { + const aliyun = this.options.aliyun || {} + return String(this.options.provider || 'aliyun') === 'aliyun' + && hasRealConfig(aliyun.accessKeyId) + && hasRealConfig(aliyun.accessKeySecret) + && hasRealConfig(aliyun.signName) + && hasRealConfig(aliyun.templateCode) + } + + async sendAliyunSms(phone, code) { + const aliyun = this.options.aliyun || {} + const params = { + AccessKeyId: aliyun.accessKeyId, + Action: 'SendSms', + Format: 'JSON', + PhoneNumbers: phone, + RegionId: 'cn-hangzhou', + SignName: aliyun.signName, + SignatureMethod: 'HMAC-SHA1', + SignatureNonce: crypto.randomUUID(), + SignatureVersion: '1.0', + TemplateCode: aliyun.templateCode, + TemplateParam: JSON.stringify({ [aliyun.templateParamKey || 'code']: code }), + Timestamp: toAliyunTimestamp(), + Version: '2017-05-25', + } + const canonicalQuery = Object.keys(params) + .sort() + .map((key) => `${percentEncode(key)}=${percentEncode(params[key])}`) + .join('&') + const stringToSign = `GET&%2F&${percentEncode(canonicalQuery)}` + const signature = crypto + .createHmac('sha1', `${aliyun.accessKeySecret}&`) + .update(stringToSign) + .digest('base64') + const url = `https://${aliyun.endpoint || 'dysmsapi.aliyuncs.com'}/?Signature=${percentEncode(signature)}&${canonicalQuery}` + const response = await fetch(url, { method: 'GET' }) + const data = await response.json().catch(() => ({})) + if (!response.ok || data.Code !== 'OK') { + const error = new Error(data.Message || '短信发送失败') + error.status = 502 + error.providerCode = data.Code + throw error + } + return data + } +} + +module.exports = { SmsService } diff --git a/backend/src/utils/ids.js b/backend/src/utils/ids.js new file mode 100644 index 0000000..12310e2 --- /dev/null +++ b/backend/src/utils/ids.js @@ -0,0 +1,5 @@ +function createId(prefix) { + return `${prefix}_${Date.now().toString(36)}${Math.random().toString(36).slice(2, 7)}` +} + +module.exports = { createId } diff --git a/backend/src/utils/password.js b/backend/src/utils/password.js new file mode 100644 index 0000000..9fc2610 --- /dev/null +++ b/backend/src/utils/password.js @@ -0,0 +1,14 @@ +const crypto = require('crypto') + +function hashPassword(password) { + return crypto.createHash('sha256').update(String(password || '')).digest('hex') +} + +function verifyPassword(password, passwordHash) { + return Boolean(passwordHash) && hashPassword(password) === passwordHash +} + +module.exports = { + hashPassword, + verifyPassword, +} diff --git a/backend/src/utils/sessionToken.js b/backend/src/utils/sessionToken.js new file mode 100644 index 0000000..c6a0ab7 --- /dev/null +++ b/backend/src/utils/sessionToken.js @@ -0,0 +1,38 @@ +const crypto = require('crypto') +const { env } = require('../config/env') + +function sign(value) { + return crypto + .createHmac('sha256', env.auth.sessionSecret) + .update(value) + .digest('base64url') +} + +function createSessionToken(accountId) { + const issuedAt = Math.floor(Date.now() / 1000) + const payload = Buffer.from(JSON.stringify({ + sub: accountId, + iat: issuedAt, + exp: issuedAt + Math.max(1, Number(env.auth.sessionTtlHours || 168)) * 60 * 60, + })).toString('base64url') + return `${payload}.${sign(payload)}` +} + +function verifySessionToken(token) { + const [payload, signature, extra] = String(token || '').trim().split('.') + if (!payload || !signature || extra) return null + const expected = sign(payload) + const actualBuffer = Buffer.from(signature) + const expectedBuffer = Buffer.from(expected) + if (actualBuffer.length !== expectedBuffer.length || !crypto.timingSafeEqual(actualBuffer, expectedBuffer)) return null + + try { + const data = JSON.parse(Buffer.from(payload, 'base64url').toString('utf8')) + if (!data.sub || !data.exp || Number(data.exp) <= Math.floor(Date.now() / 1000)) return null + return data + } catch (error) { + return null + } +} + +module.exports = { createSessionToken, verifySessionToken } diff --git a/backend/uploads/.gitkeep b/backend/uploads/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..50bcafe --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,85 @@ +services: + mysql: + image: mysql:8.4 + container_name: lifanghe-mysql + command: --character-set-server=utf8mb4 --collation-server=utf8mb4_0900_ai_ci + environment: + MYSQL_ROOT_PASSWORD: root123456 + MYSQL_DATABASE: lifanghe_education + MYSQL_USER: lifanghe + MYSQL_PASSWORD: lifanghe123 + TZ: Asia/Shanghai + ports: + - "3306:3306" + volumes: + - mysql_data:/var/lib/mysql + - ./backend/sql/init.sql:/docker-entrypoint-initdb.d/01-init.sql:ro + healthcheck: + test: ["CMD", "mysqladmin", "ping", "-h", "127.0.0.1", "-ulifanghe", "-plifanghe123"] + interval: 10s + timeout: 5s + retries: 10 + + backend: + image: node:20-alpine + container_name: lifanghe-backend + working_dir: /app + depends_on: + mysql: + condition: service_healthy + environment: + NODE_ENV: development + PORT: 3100 + DB_CLIENT: mysql + MYSQL_HOST: mysql + MYSQL_PORT: 3306 + MYSQL_USER: lifanghe + MYSQL_PASSWORD: lifanghe123 + MYSQL_DATABASE: lifanghe_education + WECHAT_APP_ID: ${WECHAT_APP_ID:-} + WECHAT_APP_SECRET: ${WECHAT_APP_SECRET:-} + TZ: Asia/Shanghai + ports: + - "3100:3100" + volumes: + - ./backend:/app + - backend_node_modules:/app/node_modules + command: sh -c "npm install && npm start" + + front-h5: + image: node:20-alpine + container_name: lifanghe-front-h5 + working_dir: /app + depends_on: + - backend + environment: + VITE_API_BASE_URL: http://127.0.0.1:3100/api + TZ: Asia/Shanghai + ports: + - "5177:5177" + volumes: + - ./front:/app + - front_node_modules:/app/node_modules + command: sh -c "npm install && npm run dev:h5 -- --host 0.0.0.0 --port 5177" + + pc-admin: + image: node:20-alpine + container_name: lifanghe-pc-admin + working_dir: /app + depends_on: + - backend + environment: + VITE_APP_BASE_API: http://127.0.0.1:3100/api + TZ: Asia/Shanghai + ports: + - "5174:5174" + volumes: + - ./pc-admin:/app + - pc_admin_node_modules:/app/node_modules + command: sh -c "npm install && npx vite --host 0.0.0.0 --port 5174" + +volumes: + mysql_data: + backend_node_modules: + front_node_modules: + pc_admin_node_modules: diff --git a/front/.env.development b/front/.env.development new file mode 100644 index 0000000..aac097e --- /dev/null +++ b/front/.env.development @@ -0,0 +1,2 @@ +VITE_API_BASE_URL=http://localhost:3100/api +# VITE_API_BASE_URL=https://lfhedu.ruixininfo.com/api diff --git a/front/index.html b/front/index.html new file mode 100644 index 0000000..fb81ddc --- /dev/null +++ b/front/index.html @@ -0,0 +1,20 @@ + + + + + + + + + + +
+ + + diff --git a/front/package-lock.json b/front/package-lock.json new file mode 100644 index 0000000..2b4dca6 --- /dev/null +++ b/front/package-lock.json @@ -0,0 +1,13919 @@ +{ + "name": "uni-preset-vue", + "version": "0.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "uni-preset-vue", + "version": "0.0.0", + "dependencies": { + "@dcloudio/uni-app": "3.0.0-5000720260410001", + "@dcloudio/uni-app-harmony": "3.0.0-5000720260410001", + "@dcloudio/uni-app-plus": "3.0.0-5000720260410001", + "@dcloudio/uni-components": "3.0.0-5000720260410001", + "@dcloudio/uni-h5": "3.0.0-5000720260410001", + "@dcloudio/uni-mp-alipay": "3.0.0-5000720260410001", + "@dcloudio/uni-mp-baidu": "3.0.0-5000720260410001", + "@dcloudio/uni-mp-harmony": "3.0.0-5000720260410001", + "@dcloudio/uni-mp-jd": "3.0.0-5000720260410001", + "@dcloudio/uni-mp-kuaishou": "3.0.0-5000720260410001", + "@dcloudio/uni-mp-lark": "3.0.0-5000720260410001", + "@dcloudio/uni-mp-qq": "3.0.0-5000720260410001", + "@dcloudio/uni-mp-toutiao": "3.0.0-5000720260410001", + "@dcloudio/uni-mp-weixin": "3.0.0-5000720260410001", + "@dcloudio/uni-mp-xhs": "3.0.0-5000720260410001", + "@dcloudio/uni-quickapp-webview": "3.0.0-5000720260410001", + "uview-plus": "^3.4.41", + "vue": "^3.4.21", + "vue-i18n": "^9.1.9" + }, + "devDependencies": { + "@dcloudio/types": "^3.4.8", + "@dcloudio/uni-automator": "3.0.0-5000720260410001", + "@dcloudio/uni-cli-shared": "3.0.0-5000720260410001", + "@dcloudio/uni-stacktracey": "3.0.0-5000720260410001", + "@dcloudio/vite-plugin-uni": "3.0.0-5000720260410001", + "@vue/runtime-core": "^3.4.21", + "sass": "^1.89.2", + "vite": "5.2.8" + } + }, + "node_modules/@ampproject/remapping": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", + "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", + "license": "Apache-2.0", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.7.tgz", + "integrity": "sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==", + "license": "MIT", + "dependencies": { + "@babel/highlight": "^7.24.7", + "picocolors": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.7.tgz", + "integrity": "sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.25.2", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.25.2.tgz", + "integrity": "sha512-BBt3opiCOxUr9euZ5/ro/Xv8/V7yJ5bjYMqG/C1YAo8MIKAnumZalCN+msbci3Pigy4lIQfPUpfMM27HMGaYEA==", + "license": "MIT", + "dependencies": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.24.7", + "@babel/generator": "^7.25.0", + "@babel/helper-compilation-targets": "^7.25.2", + "@babel/helper-module-transforms": "^7.25.2", + "@babel/helpers": "^7.25.0", + "@babel/parser": "^7.25.0", + "@babel/template": "^7.25.0", + "@babel/traverse": "^7.25.2", + "@babel/types": "^7.25.2", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/generator": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.7.tgz", + "integrity": "sha512-DkXD5OJQaAQIdZ1bt3UZdEnHAn9Imd3IVBdX03UFe+ony9Ojw5pzr9YVKGDY1jt+Gcn/FnGkNf8r+Vj5NOJWtQ==", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.29.7", + "@babel/types": "^7.29.7", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/generator/node_modules/@babel/parser": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.7.tgz", + "integrity": "sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.7" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/generator/node_modules/@babel/types": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.7.tgz", + "integrity": "sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==", + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-annotate-as-pure": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.29.7.tgz", + "integrity": "sha512-OoK6239jHPuSQOoS0kfTVKn0b/rVTk0seKq4Gd2UMLtmOVLjDC0ki3e+c90Trqv2gMfvJFqkiljrr568+qddiw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-annotate-as-pure/node_modules/@babel/types": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.7.tgz", + "integrity": "sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.29.7.tgz", + "integrity": "sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g==", + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.29.7", + "@babel/helper-validator-option": "^7.29.7", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-create-class-features-plugin": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.29.7.tgz", + "integrity": "sha512-IY3ZD9Tmooqr3TUhc3DUWxiuo8xx1DWLhd5M7hQ+ZWJamqM2BbalrBJb2MisSLoYorOj75U03qULCxQTY9r3hg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.29.7", + "@babel/helper-member-expression-to-functions": "^7.29.7", + "@babel/helper-optimise-call-expression": "^7.29.7", + "@babel/helper-replace-supers": "^7.29.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.29.7", + "@babel/traverse": "^7.29.7", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-create-regexp-features-plugin": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.29.7.tgz", + "integrity": "sha512-907Uymvqgg1dwUA+7IGwFAOSYzQOuzPXKNJ1yxzwPffzkYFg2q2eHi1fIOs6sXkG9NbIUMunnUlkYsfRFNvomg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.29.7", + "regexpu-core": "^6.3.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-define-polyfill-provider": { + "version": "0.6.8", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.8.tgz", + "integrity": "sha512-47UwBLPpQi1NoWzLuHNjRoHlYXMwIJoBf7MFou6viC/sIHWYygpvr0B6IAyh5sBdA2nr2LPIRww8lfaUVQINBA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-compilation-targets": "^7.28.6", + "@babel/helper-plugin-utils": "^7.28.6", + "debug": "^4.4.3", + "lodash.debounce": "^4.0.8", + "resolve": "^1.22.11" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/@babel/helper-define-polyfill-provider/node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@babel/helper-define-polyfill-provider/node_modules/resolve": { + "version": "1.22.12", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.12.tgz", + "integrity": "sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "is-core-module": "^2.16.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/@babel/helper-globals": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.29.7.tgz", + "integrity": "sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-member-expression-to-functions": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.29.7.tgz", + "integrity": "sha512-j+7JYmk1JYDtACIGj0QJqqWZjoUpMoEikQGADMaHgCMCSDqd2+P32rfcibUNrGOMWrlzK1WJBdxrB3JJQZwWtg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-member-expression-to-functions/node_modules/@babel/types": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.7.tgz", + "integrity": "sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.29.7.tgz", + "integrity": "sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g==", + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports/node_modules/@babel/types": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.7.tgz", + "integrity": "sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==", + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.29.7.tgz", + "integrity": "sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg==", + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7", + "@babel/traverse": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-optimise-call-expression": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.29.7.tgz", + "integrity": "sha512-+kmGVjcT9RGYzoDwdwEqEvGgKe3BYq+O1iGzjFubaNgZHwYHP6lsF2Yghf4kEuv9BV7tYDZ913aBW9am6YKong==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-optimise-call-expression/node_modules/@babel/types": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.7.tgz", + "integrity": "sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.29.7.tgz", + "integrity": "sha512-G7sHYigPY17oO5SYWnfD/0MTBwVR781S/JI643e/JhUYgVgWE/61SoW3NH9KWUKyKq5LVh3npif99Wkt6j86Jw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-remap-async-to-generator": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.29.7.tgz", + "integrity": "sha512-16AMiW26DbXWBbr3B8wNozKM0ydMLB892vaOaJW/fPJdnT8vJk5sdkQcU/isqUxyCE0cEoa8wZOcbgDuC4b6Og==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.29.7", + "@babel/helper-wrap-function": "^7.29.7", + "@babel/traverse": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-replace-supers": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.29.7.tgz", + "integrity": "sha512-atfGXWSeCiF4DnKZIfmJfQRkSw9b9gNNXR1kqKjbhG4pGYCOnkp8OcTB8E3NXjBu8NpheSnOeNKz8KT7UNFTmQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-member-expression-to-functions": "^7.29.7", + "@babel/helper-optimise-call-expression": "^7.29.7", + "@babel/traverse": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.29.7.tgz", + "integrity": "sha512-brcMGQaVzIeUb+6/bs1Av0f8YuNNjKY2JyvfRCsFuFsdKccEQ5Ges2y74D74NZ1Rz8lKJ9ksJkfqwQFJ/iNEyQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-skip-transparent-expression-wrappers/node_modules/@babel/types": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.7.tgz", + "integrity": "sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz", + "integrity": "sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz", + "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.29.7.tgz", + "integrity": "sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-wrap-function": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.29.7.tgz", + "integrity": "sha512-iES0Skag9ERIF68aXadpO6dbXa03mNWK3sEqJaMnLNs/eC3l0lkImdfoy6Y09/SfkpawdAB4RjQ7PVA7TcVGdw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.29.7", + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-wrap-function/node_modules/@babel/types": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.7.tgz", + "integrity": "sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.7.tgz", + "integrity": "sha512-1k2lAGRMfHTcwuNYcCNUmaUffmQv8KWMfh2iJUUeRlwlwH4FdNG7mfPI10NPfLHJFThE4Tyr4mv7kTNZOiPuBg==", + "license": "MIT", + "dependencies": { + "@babel/template": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers/node_modules/@babel/types": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.7.tgz", + "integrity": "sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==", + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.25.9.tgz", + "integrity": "sha512-llL88JShoCsth8fF8R4SJnIn+WLvR6ccFxu1H3FlMhDontdcmZWf2HgIZ7AIqV3Xcck1idlohrN4EUBQz6klbw==", + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.25.9", + "chalk": "^2.4.2", + "js-tokens": "^4.0.0", + "picocolors": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.25.6", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.25.6.tgz", + "integrity": "sha512-trGdfBdbD0l1ZPmcJ83eNxB9rbEax4ALFTF7fN386TMYbeCQbyme5cOEXQhbGXKebwGaB/J52w1mrklMcbgy6Q==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.25.6" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-firefox-class-in-computed-class-key": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.29.7.tgz", + "integrity": "sha512-j8SrR0zLZrRsC09DlszEx8FpMiwukKffYXMK0d5LmOglO7vGG6sz/BR/20yHqWH+Lnn31JTt2PE3hIWNgM2J6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/traverse": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-safari-class-field-initializer-scope": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-class-field-initializer-scope/-/plugin-bugfix-safari-class-field-initializer-scope-7.29.7.tgz", + "integrity": "sha512-r8j8escF+U2FUHo0KOhPUdMzUO+jp9fInva6+ACVAF3Y97Ev+5iNZwiqTghmzNeWwDkOPlYuTcfb1vDaoZKmAQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.29.7.tgz", + "integrity": "sha512-GE1TFSiuFeGsCxmYXZl8HwoPrVlwe4rHPFE8weieGKZqnDORK+Ar3vgWMgW+AOxQ6/2TgLSKx9p6W7O4rC6qgQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-safari-rest-destructuring-rhs-array": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-rest-destructuring-rhs-array/-/plugin-bugfix-safari-rest-destructuring-rhs-array-7.29.7.tgz", + "integrity": "sha512-oBNVCvnO5tND+xSopWvV8WNGfpTfgP4Zr/YXXSj8zfmcPktp5Ku/aZlsIowgSD4fjmgHn6sGmB9APVsU5zOdhA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.29.7.tgz", + "integrity": "sha512-QQt9qKHZ2sg/kivaLr7lnQr8HVrQDdBNSfCsTjiDxRuX/K5ORyKq+Bu8Xr0cDE3Dfkv0cw28Ve0EKyKMvulkOw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.29.7", + "@babel/plugin-transform-optional-chaining": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.13.0" + } + }, + "node_modules/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.29.7.tgz", + "integrity": "sha512-pn6QacGLgvCcwc+syUhKE/qSjV2D1IHDB84RNxWYSt1mW3K/SCtjinZ2p0cETJxAWBjPy3K/1lHwG5BjjPxNlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/traverse": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-proposal-private-property-in-object": { + "version": "7.21.0-placeholder-for-preset-env.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz", + "integrity": "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-bigint": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", + "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-properties": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", + "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.12.13" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-static-block": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", + "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-assertions": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.29.7.tgz", + "integrity": "sha512-/An1OCBN93thpBAGyfsK2pcf0jvju1SAtKkL2Ny++B5Sy6sqgzXDQH1cZxWbF96Wuk+bn41MDA9bLd4VVAw6rw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-attributes": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.29.7.tgz", + "integrity": "sha512-zGYcYfq/WmZ4V+kBIXQon9dSSc8ircGZqw9ZaNhhGj9nZkeBu1jHLBDQqYYi5WA9uawvA2sIMbry2nCFhf5Djg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-meta": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", + "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-jsx": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.29.7.tgz", + "integrity": "sha512-TSu8+mHCoEaaCDEZ0I3+6mvTBYR4PCxQwf2z9/r5Tbztv6NaLR3B9thGTTxX2WGuGHJqRiAbKPeGTJ5XWXVg6A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-private-property-in-object": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", + "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-top-level-await": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", + "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-typescript": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.29.7.tgz", + "integrity": "sha512-ngr+82Sh0xMz25TPCZi+nC2iTzjfCdWS2ONXTp/PtSCHCgaCNBpdMqgvJ2ccdLlClVZ7sisIgB914j/JFe+RZA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-unicode-sets-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz", + "integrity": "sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-arrow-functions": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.29.7.tgz", + "integrity": "sha512-N7zArUXWzAMzm+/N0uPBeVB3Fam5lMxtUwMmDK5f/IBBS7a7p1qeUoxd/6CckXoxUdgsntq1Dh8xNW06maZbDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-async-generator-functions": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.29.7.tgz", + "integrity": "sha512-d98gXZkgswvkyohMBABkhm3GeXhYj8psWfwQ2C7gtfrKGTykQa/iOIi+JJhwMjPlZ6Vm2XN+DCf3Es1EoG4ZLA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-remap-async-to-generator": "^7.29.7", + "@babel/traverse": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-async-to-generator": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.29.7.tgz", + "integrity": "sha512-pcUb2SS+RMo9TWVBwKGI5ShtoG7R+zBsFmCKDa6fe8c+hPr3XJlZgoE5j6i8W7gDjhyvy+85vmYexanvXh3d1w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-remap-async-to-generator": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoped-functions": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.29.7.tgz", + "integrity": "sha512-cUSmjh72N+rN4PrkFlN1dJwNCwjVp5d38/CQrEsFggkD10UiFlBFgdH3tv5dNsLuHY+3S8db2xCHjhZcv5WgvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoping": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.29.7.tgz", + "integrity": "sha512-ONyr4+AZhKh8yKWInVxU9AXA9EbsyeLcL6V0dJy6M2/62vuvpGm29zzuymbTpdc451GEpDIdAyPLP3r+P61yKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-class-properties": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.29.7.tgz", + "integrity": "sha512-GtcpjFvanPfzNQi3eTitsCqtRRmmqzpy/A+yhTR1HaZo1Ly3EA8ZXxlPyHdR8/IuRMYc3E4wdGBewB2QKQjAaA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-class-static-block": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.29.7.tgz", + "integrity": "sha512-kibJgmEdX2iMwsHY2tSZNDgj8PwIlCQz7FK9KuGKO8zsuoUwSEhoNnNVp/emKWrbY4HeO6kkXfdMqRKKKXBm2A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.12.0" + } + }, + "node_modules/@babel/plugin-transform-classes": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.29.7.tgz", + "integrity": "sha512-qV0OGGBVacduzQHE649JyCneOFI/maT+YKsO+K4Yi3xv2wTPNjM/W2o2gdzMwEAZz7fXNTHAe0NcSg30bIN69g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.29.7", + "@babel/helper-compilation-targets": "^7.29.7", + "@babel/helper-globals": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-replace-supers": "^7.29.7", + "@babel/traverse": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-computed-properties": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.29.7.tgz", + "integrity": "sha512-RK7/IyU5phpuCdBAuig5VkzG/EnbDaui5SQGdU9BFrHdV+mV4cUjLMQ9lJDjLNtWHsqtiefpGZUXQP2BiTYMsA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/template": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-destructuring": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.29.7.tgz", + "integrity": "sha512-iPX8aD6H9zV5s7ZsqTdNocPN/MGQ5sSMnElKrktxjJRMnB2jN/1p2+R7GkfD6CAYoVFqy5A4XnSIUeGgJzIWpg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/traverse": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-dotall-regex": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.29.7.tgz", + "integrity": "sha512-3qc18hsD2RdZiyJNDNc7HQpv6xbncwh8FYtxNFFzclSyh/trPD9KkVR9BDECUjDLvb7yJVF15GfYUuC+LMkkiQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-duplicate-keys": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.29.7.tgz", + "integrity": "sha512-6IvRRriEMqnBwD6chtxdLpMYCHWEzN+oL5cyQtjykya19UgzbmKhxmhZgKC/LHxS2nYr9Q/qYPZ5Lr6jOL9+yQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-duplicate-named-capturing-groups-regex": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-named-capturing-groups-regex/-/plugin-transform-duplicate-named-capturing-groups-regex-7.29.7.tgz", + "integrity": "sha512-2wiIyo2BjtgU7HufSeDnL9L2O7zr8jmhFKuSr65VpRkUiRKRNpb0mdlk56+XPPKoIrfHqzbMuglDvZun0RISsA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-dynamic-import": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.29.7.tgz", + "integrity": "sha512-giOlEm/EFjfjr+te9NsdjkUo2v4f8rS/SXPumRVHAtbNcyNlvtREkU1dZzaIDclNpnaVhlCqRdFKhJBjBikzLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-explicit-resource-management": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-explicit-resource-management/-/plugin-transform-explicit-resource-management-7.29.7.tgz", + "integrity": "sha512-Rstj7coNz8sE+7Ju7ihpHLI564lsK5pUpNNlvptCIC/16E/S5hbl6n3kESPKdNRmqEWlpn5xpS5Q2dvXBsySLw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/plugin-transform-destructuring": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-exponentiation-operator": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.29.7.tgz", + "integrity": "sha512-zFpMOTLZBdW5LfObqcSbL6kefg4R4eLdmvS0wbN9M6D5Mym/sKm9toOoWyVOa+xDjvCnuWcHls2YonXwHvH3CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-export-namespace-from": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.29.7.tgz", + "integrity": "sha512-24B2nOy2TeJSMheqwPD4DDQOV/elLSIlKxjZt4i05H5AgdPdWR3n18HnNrcJ+j76WJd9gbwb9jPjNYUy6RautA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-for-of": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.29.7.tgz", + "integrity": "sha512-zeSIHh0+E1Um1WJRXCFlHQYu2ieJNdivLLjlBEp+dIBu3S51n+SZZmIXjxnItw6pz56Cn+KvK68BIBVsxq2JiQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-function-name": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.29.7.tgz", + "integrity": "sha512-otRWaHXE6fbAGkePvaj/kvs3HsqXfPhlnzwSOlnFgbqCPMd975dW+4wZ00WFBt+/YlBGcJwNrARQTOJOb4ZrIg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-compilation-targets": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/traverse": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-json-strings": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.29.7.tgz", + "integrity": "sha512-RRnE2+eon1rJAq8MnoF1b5kTpY1vU88twHcvcKMrsqP/jxIRqDVs9iJB5fqPuqyeFAW0wJo4MlUIPpQCq/aRsg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-literals": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.29.7.tgz", + "integrity": "sha512-DZ/oLP21ZuWx1vKqnoNv6/tvEK48AQOBRai40CX9dTjGluvT/YZCyY3rryDtyUqCEoyNroy5KKPwX2iQCiRvyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-logical-assignment-operators": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.29.7.tgz", + "integrity": "sha512-A0H91hh6W8MFRkp5TqJmMr39jzGD1A1E1Ysiv2O06Sfbhkapm+XyIzxWCEh5kqwOZ1/8QZ0dY3SeQ7XBqfJd5Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-member-expression-literals": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.29.7.tgz", + "integrity": "sha512-hl1kwFZCCiDyfH25Xmco9jTrkPgnS9pmOzSG7W5I4SaGbLeqKv417hcU2RKmaxoPEgsoJh7ZPOrnPGq99bHoUg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-amd": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.29.7.tgz", + "integrity": "sha512-fxtQoH3m5ywUSIfaH0FGCzWu4McsYon5bD3K4XnskC7f+OyQMj7rsOMi4NvvmJ83WwBAg4UCe+ov4VZlqEvyew==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-transforms": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-commonjs": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.29.7.tgz", + "integrity": "sha512-j0vCldybPC5b5dwCQOJ21uKtHzt7hxLygJTg9eF1ScfaikEDNfzn94XoW5Fi+seBR0nCyL23xaBFFkq7dTM8XQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-transforms": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-systemjs": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.29.7.tgz", + "integrity": "sha512-TM2ZcQLoG2/y4HODiStCo10DibYhWhGWAwVv+EQKmG/7GFl0N+AAmUiXOMKM+aiJ9XBJ9AHVZBvTzMnJ2sM3cQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-transforms": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7", + "@babel/traverse": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-umd": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.29.7.tgz", + "integrity": "sha512-B4UkaTK3QpgCwJnrxKfMPKdo92CN7OKXAlpAAnM3UPu0Q0lCCk57ylA9AJbRy2v8dDKOPAAWcoR6CMyeoHwRCA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-transforms": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.29.7.tgz", + "integrity": "sha512-vuFoLwr4qnv2xbZ16SQd6uPcH5FNrLHhk/Jzo++0XJFcaDsr4gjJVg6j398oMHiC+83k/GiBzviwF5KBJkPUtQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-new-target": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.29.7.tgz", + "integrity": "sha512-fEo41GmsOUhOBlw8ioo6zvjX5Xc2Lqkzlyfqbpsk3eB6TReV18uhxZ0esfEokVbY2+PVJAQHNKxER6lGrzNd3A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-nullish-coalescing-operator": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.29.7.tgz", + "integrity": "sha512-idmp1dFaekP9GbcMvG24Kvw2BfhFZjHnNJCkV4WuIY4PskJzwI3f1N5OdgYke38T7rftO6ERulFRn2cFeZwRkg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-numeric-separator": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.29.7.tgz", + "integrity": "sha512-zR7fv/z14OjgHl4AgRtkDBvBMhIzCxqV/qN/2BCRC7LjFwvuzjYe7gDWxC4Wl/SNsLM6SE1IWvRPYMgSJaUvNw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-object-rest-spread": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.29.7.tgz", + "integrity": "sha512-Ld98jn4c0smUywL57m7SgsHq3OpThOa6LqZJif3G6jYOovPleoFhVrBJ1WegRApSFB2wu4+RelAj9AC9G08Z4A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-compilation-targets": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/plugin-transform-destructuring": "^7.29.7", + "@babel/plugin-transform-parameters": "^7.29.7", + "@babel/traverse": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-object-super": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.29.7.tgz", + "integrity": "sha512-Ea/diGcw0twB5IlZPO5sgET6fJsLJqPABqTuFWIR+iMPGPZJkATEIWx0wa+aEQ5UY1CBQyP/gkAiLEqn1vBiQA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-replace-supers": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-optional-catch-binding": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.29.7.tgz", + "integrity": "sha512-sLsyndxK2VwX6yNUOakMb7Sh553ZTe/vVM1XJ+9Z5aW1ytsc8xOIwmyk05NNjN60vkc5/KqoTH6hB4V41LJhng==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-optional-chaining": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.29.7.tgz", + "integrity": "sha512-6GM1dhvK3gNODkXcEcMCOLEDCLSoZ/sBbro2Ax8HURyasQ4NshagQixkRFdh5niI6E4gmA/jYI/4aT7rRos3ZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-parameters": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.29.7.tgz", + "integrity": "sha512-ZDOBqV/qLYJI0YElr8DcENEyARsFQeESqWXH6gZlghYXuPPjvweuDhP4VyEi4BlUBlLRFZVjxoZDMjxhLW766g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-private-methods": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.29.7.tgz", + "integrity": "sha512-/6Rz4DK1ETDEM/bWHsPHcaEe7ZaT1EqSXjtSP/L0DijOYuaUhiRiOKcwpZ8P7zR4xXEHc2ITdiCgBm9Tpyv9ug==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-private-property-in-object": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.29.7.tgz", + "integrity": "sha512-+BNo06dnrzdNNqCm1X6YUaVv0DKk8Q+JYcoZfOkLhYWNCXzlwTSRq8zGWayT1csjcpNXV9CQTBRRbmTLZac5cA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.29.7", + "@babel/helper-create-class-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-property-literals": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.29.7.tgz", + "integrity": "sha512-bOMRLQuI0A5ZqHq3OWJ89/rXpJ/NJrbVhXiP4zwPGMs6kpcVsuTUNjwoE30K0Qm3mf48a/TnRYYD6vPNqcg6jA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-regenerator": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.29.7.tgz", + "integrity": "sha512-rNNFV0DBAJp988xW2DOntfDoYn1eR8GGF5AT5vYc+rjyfaQkM242c9tZUHHPe7KYaiJizXPWhQTzzdbXySyhBw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-regexp-modifiers": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regexp-modifiers/-/plugin-transform-regexp-modifiers-7.29.7.tgz", + "integrity": "sha512-mB5Fs0VWrJ42ZCmc8114v60qetdaUVNkj9PmSZRmanCZM3S9hm0CFRLjRmYIsuXav14l2jvZ+4T8iiCGnhj3nQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-reserved-words": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.29.7.tgz", + "integrity": "sha512-5+YhdpVgmfSmwZyLMftfaiffLRMHjzIRHFHHLdibcSyJm2pasMrKHrO3Ptrt2DRshjvpgjEJJ1zVW14WPq/6QA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-shorthand-properties": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.29.7.tgz", + "integrity": "sha512-I+WYbGBAiCn7nA6xBrlgPH+MB7HWb4u8pv5S0Pv7OtwNvIFvCCb24YlttKEeUFVurfBCEaOTnuhlqsb7f0Z5Dg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-spread": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.29.7.tgz", + "integrity": "sha512-/u5K1QWada7tbYNqTjMh96718g9NTwh9tfPJMsSmVsQwGT447FskV+KcfeXkXq2GWki4EM/MuTdmBec+hOuVTQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-sticky-regex": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.29.7.tgz", + "integrity": "sha512-BCHzNYJGe9l7EpwwDBN/ztlL2NYFFq8hp9ddjtUEM9f2O7S7kKV/lL6Fwo7IF7NSkYhPK2vO+86nIGltA90MsA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-template-literals": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.29.7.tgz", + "integrity": "sha512-NCSEJ4sLFU2gqAub45HYh4fus2yQ36rr6ei6vpU7NdoJqCpxvEG8E6eJpscGyXP3VHD2Ny+fSXr04k1hoUrFqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-typeof-symbol": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.29.7.tgz", + "integrity": "sha512-223mNGoTkBiTEWFoK+Q6Go3tueMRclO8vxxxxquNCYuNI4jWOofFKJRRDu6SDrB8Sgo1UEGW9T4GAQ8ZyRso1A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-typescript": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.29.7.tgz", + "integrity": "sha512-jK52h8LaLc7JarhQV2ofeFMts4H7vnOXnqZNA6fYglBTZewRBE51KWt3BUltW1P+KoPsYkHoJeXePuz4zo2LMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.29.7", + "@babel/helper-create-class-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.29.7", + "@babel/plugin-syntax-typescript": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-escapes": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.29.7.tgz", + "integrity": "sha512-jCfXxSjf94lf4E0hKE0AByxF6F3/pVFqRdUUNkDJhsY0m1ZKjnN6ZYyMeHNpzflxb/0q5b7t3p+BE+SLF1WOtA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-property-regex": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.29.7.tgz", + "integrity": "sha512-OgZ+zoAJgZLUCunsTRQ5LAjOywDv5zzZ2/hQ5aMw1pGXyY2rtE8/chXYUmu3AlVHKpm10KEdG9aMwbI/K76ZGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-regex": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.29.7.tgz", + "integrity": "sha512-7D/x/23/d/3VqZ0QA+LGbZMlGwZjztBygSWWWsfTPoQ1oQ6Q1P6Mr3d0kk42XabyUVw+fha3LqdRsFqeKqvCyA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-sets-regex": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.29.7.tgz", + "integrity": "sha512-BLOhLht9DOJwIxlmp91wHvkXv1lguuHS3/FwUO8HL1H0u8s4hR1gASVFyilu9iGtcTRYqjTZmlsFFeQletntEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/preset-env": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.29.7.tgz", + "integrity": "sha512-GYzX36n1nsciIb0uyH0GHwxwtNwPQIcpxSeiVLDtG/B7jB5xXgchnmL1f/jCX5o+pwnaDBtO60ONSJhEBJfxYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.29.7", + "@babel/helper-compilation-targets": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-validator-option": "^7.29.7", + "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.29.7", + "@babel/plugin-bugfix-safari-class-field-initializer-scope": "^7.29.7", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.29.7", + "@babel/plugin-bugfix-safari-rest-destructuring-rhs-array": "^7.29.7", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.29.7", + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.29.7", + "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", + "@babel/plugin-syntax-import-assertions": "^7.29.7", + "@babel/plugin-syntax-import-attributes": "^7.29.7", + "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", + "@babel/plugin-transform-arrow-functions": "^7.29.7", + "@babel/plugin-transform-async-generator-functions": "^7.29.7", + "@babel/plugin-transform-async-to-generator": "^7.29.7", + "@babel/plugin-transform-block-scoped-functions": "^7.29.7", + "@babel/plugin-transform-block-scoping": "^7.29.7", + "@babel/plugin-transform-class-properties": "^7.29.7", + "@babel/plugin-transform-class-static-block": "^7.29.7", + "@babel/plugin-transform-classes": "^7.29.7", + "@babel/plugin-transform-computed-properties": "^7.29.7", + "@babel/plugin-transform-destructuring": "^7.29.7", + "@babel/plugin-transform-dotall-regex": "^7.29.7", + "@babel/plugin-transform-duplicate-keys": "^7.29.7", + "@babel/plugin-transform-duplicate-named-capturing-groups-regex": "^7.29.7", + "@babel/plugin-transform-dynamic-import": "^7.29.7", + "@babel/plugin-transform-explicit-resource-management": "^7.29.7", + "@babel/plugin-transform-exponentiation-operator": "^7.29.7", + "@babel/plugin-transform-export-namespace-from": "^7.29.7", + "@babel/plugin-transform-for-of": "^7.29.7", + "@babel/plugin-transform-function-name": "^7.29.7", + "@babel/plugin-transform-json-strings": "^7.29.7", + "@babel/plugin-transform-literals": "^7.29.7", + "@babel/plugin-transform-logical-assignment-operators": "^7.29.7", + "@babel/plugin-transform-member-expression-literals": "^7.29.7", + "@babel/plugin-transform-modules-amd": "^7.29.7", + "@babel/plugin-transform-modules-commonjs": "^7.29.7", + "@babel/plugin-transform-modules-systemjs": "^7.29.7", + "@babel/plugin-transform-modules-umd": "^7.29.7", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.29.7", + "@babel/plugin-transform-new-target": "^7.29.7", + "@babel/plugin-transform-nullish-coalescing-operator": "^7.29.7", + "@babel/plugin-transform-numeric-separator": "^7.29.7", + "@babel/plugin-transform-object-rest-spread": "^7.29.7", + "@babel/plugin-transform-object-super": "^7.29.7", + "@babel/plugin-transform-optional-catch-binding": "^7.29.7", + "@babel/plugin-transform-optional-chaining": "^7.29.7", + "@babel/plugin-transform-parameters": "^7.29.7", + "@babel/plugin-transform-private-methods": "^7.29.7", + "@babel/plugin-transform-private-property-in-object": "^7.29.7", + "@babel/plugin-transform-property-literals": "^7.29.7", + "@babel/plugin-transform-regenerator": "^7.29.7", + "@babel/plugin-transform-regexp-modifiers": "^7.29.7", + "@babel/plugin-transform-reserved-words": "^7.29.7", + "@babel/plugin-transform-shorthand-properties": "^7.29.7", + "@babel/plugin-transform-spread": "^7.29.7", + "@babel/plugin-transform-sticky-regex": "^7.29.7", + "@babel/plugin-transform-template-literals": "^7.29.7", + "@babel/plugin-transform-typeof-symbol": "^7.29.7", + "@babel/plugin-transform-unicode-escapes": "^7.29.7", + "@babel/plugin-transform-unicode-property-regex": "^7.29.7", + "@babel/plugin-transform-unicode-regex": "^7.29.7", + "@babel/plugin-transform-unicode-sets-regex": "^7.29.7", + "@babel/preset-modules": "0.1.6-no-external-plugins", + "babel-plugin-polyfill-corejs2": "^0.4.15", + "babel-plugin-polyfill-corejs3": "^0.14.0", + "babel-plugin-polyfill-regenerator": "^0.6.6", + "core-js-compat": "^3.48.0", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-modules": { + "version": "0.1.6-no-external-plugins", + "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.6-no-external-plugins.tgz", + "integrity": "sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/types": "^7.4.4", + "esutils": "^2.0.2" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/@babel/runtime": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.29.7.tgz", + "integrity": "sha512-Nq8OhGWiZIZGV6hLHoyAKLLcJihP/xFeBMGJoUrxTX2psI8dCifzLhZISFb+VWS3wFMRDmCGw5R+dOySCqPLhw==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/runtime-corejs3": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.29.7.tgz", + "integrity": "sha512-ppj9ouYku+RX0ljtgZd+KMO5mkM2bCqg8H2PYAFWnLsHEIKIdRojqbJ2i3eVHrisuxy7nOFCmngTDdWtUCdXUQ==", + "license": "MIT", + "dependencies": { + "core-js-pure": "^3.48.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/template": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.29.7.tgz", + "integrity": "sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/template/node_modules/@babel/code-frame": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.7.tgz", + "integrity": "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==", + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.29.7", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/template/node_modules/@babel/parser": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.7.tgz", + "integrity": "sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.7" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/template/node_modules/@babel/types": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.7.tgz", + "integrity": "sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==", + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/template/node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "license": "ISC" + }, + "node_modules/@babel/traverse": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.7.tgz", + "integrity": "sha512-EhlfNQtZ+NK22w5BM61ciuiq1m58ed33Wr1Xan//ZRTy6hgjnwyCffRYwzsGXdASJSUJ1guZILsErh1eQcl+zw==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.7", + "@babel/generator": "^7.29.7", + "@babel/helper-globals": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/template": "^7.29.7", + "@babel/types": "^7.29.7", + "debug": "^4.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse/node_modules/@babel/code-frame": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.7.tgz", + "integrity": "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==", + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.29.7", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse/node_modules/@babel/parser": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.7.tgz", + "integrity": "sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.7" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/traverse/node_modules/@babel/types": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.7.tgz", + "integrity": "sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==", + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse/node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "license": "ISC" + }, + "node_modules/@babel/types": { + "version": "7.25.6", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.25.6.tgz", + "integrity": "sha512-/l42B1qxpG6RdfYf343Uw1vmDjeNhneUXtzhojE7pDgfpEypmRhI6j1kr17XCVv4Cgl9HdAiQY2x0GwKm7rWCw==", + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.24.8", + "@babel/helper-validator-identifier": "^7.24.7", + "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@bcoe/v8-coverage": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", + "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/@dcloudio/types": { + "version": "3.4.28", + "resolved": "https://registry.npmjs.org/@dcloudio/types/-/types-3.4.28.tgz", + "integrity": "sha512-uVIRp1VLBkrL0LaGLgIS/sT3bl1zzVTKZQbfqJEQcSAvBffRdirbSh5OvOHfA1WV5lmCAGfjhKsUQouNEVUQHg==", + "license": "Apache-2.0" + }, + "node_modules/@dcloudio/uni-app": { + "version": "3.0.0-5000720260410001", + "resolved": "https://registry.npmjs.org/@dcloudio/uni-app/-/uni-app-3.0.0-5000720260410001.tgz", + "integrity": "sha512-1JWt4rSnYDjj6bSThDKcW8OhP68qQlsY1Zd/GBIUsiRTVSrkvA3xVwmeV5odXirpZeH5xthus4eIRdv/Qmmheg==", + "license": "Apache-2.0", + "dependencies": { + "@dcloudio/uni-cloud": "3.0.0-5000720260410001", + "@dcloudio/uni-components": "3.0.0-5000720260410001", + "@dcloudio/uni-console": "3.0.0-5000720260410001", + "@dcloudio/uni-i18n": "3.0.0-5000720260410001", + "@dcloudio/uni-push": "3.0.0-5000720260410001", + "@dcloudio/uni-shared": "3.0.0-5000720260410001", + "@dcloudio/uni-stat": "3.0.0-5000720260410001", + "@vue/shared": "3.4.21" + }, + "peerDependencies": { + "@dcloudio/types": "3.4.28" + } + }, + "node_modules/@dcloudio/uni-app-harmony": { + "version": "3.0.0-5000720260410001", + "resolved": "https://registry.npmjs.org/@dcloudio/uni-app-harmony/-/uni-app-harmony-3.0.0-5000720260410001.tgz", + "integrity": "sha512-pzhLF9Xiqc4kx4SbR4+9JS0QFIuoglWw5w8gC4WtTK8qyOvpQqYOWQNPAqw72IvVo/nj85b/MzWWr7eDfm39NQ==", + "license": "Apache-2.0", + "dependencies": { + "@dcloudio/uni-app-uts": "3.0.0-5000720260410001", + "@dcloudio/uni-app-vite": "3.0.0-5000720260410001", + "debug": "4.3.7", + "fs-extra": "10.1.0", + "licia": "1.41.1", + "postcss-selector-parser": "6.1.2" + } + }, + "node_modules/@dcloudio/uni-app-plus": { + "version": "3.0.0-5000720260410001", + "resolved": "https://registry.npmjs.org/@dcloudio/uni-app-plus/-/uni-app-plus-3.0.0-5000720260410001.tgz", + "integrity": "sha512-8i8I0d2JwrbP9ShRNmmuiw2sC3aaUciTx1Uqqzx6OwKZm4zwAiUzp4dbWadyKxjdnuwzfNF4v664hAgLOoiUdg==", + "license": "Apache-2.0", + "dependencies": { + "@dcloudio/uni-app-uts": "3.0.0-5000720260410001", + "@dcloudio/uni-app-vite": "3.0.0-5000720260410001", + "@dcloudio/uni-app-vue": "3.0.0-5000720260410001", + "debug": "4.3.7", + "fs-extra": "10.1.0", + "licia": "1.41.1", + "postcss-selector-parser": "6.1.2" + } + }, + "node_modules/@dcloudio/uni-app-uts": { + "version": "3.0.0-5000720260410001", + "resolved": "https://registry.npmjs.org/@dcloudio/uni-app-uts/-/uni-app-uts-3.0.0-5000720260410001.tgz", + "integrity": "sha512-SRtr9V7oSSWT3gmD72co36XLcUQrKWxA5YN9LWs6zfDaaOLHHNDnzDaf/Ozn57p+ixpfusawvJd06bS3r65Bag==", + "license": "Apache-2.0", + "dependencies": { + "@babel/parser": "7.25.6", + "@babel/types": "7.25.6", + "@dcloudio/uni-cli-shared": "3.0.0-5000720260410001", + "@dcloudio/uni-console": "3.0.0-5000720260410001", + "@dcloudio/uni-i18n": "3.0.0-5000720260410001", + "@dcloudio/uni-nvue-styler": "3.0.0-5000720260410001", + "@dcloudio/uni-shared": "3.0.0-5000720260410001", + "@jridgewell/gen-mapping": "^0.3.3", + "@jridgewell/trace-mapping": "^0.3.19", + "@rollup/pluginutils": "5.1.0", + "@vue/compiler-core": "3.4.21", + "@vue/compiler-dom": "3.4.21", + "@vue/compiler-sfc": "3.4.21", + "@vue/consolidate": "1.0.0", + "@vue/shared": "3.4.21", + "debug": "4.3.7", + "es-module-lexer": "1.5.4", + "estree-walker": "2.0.2", + "fast-glob": "3.3.3", + "fs-extra": "10.1.0", + "magic-string": "0.30.11", + "picocolors": "1.1.0", + "source-map-js": "1.2.1", + "unimport": "4.1.1" + } + }, + "node_modules/@dcloudio/uni-app-vite": { + "version": "3.0.0-5000720260410001", + "resolved": "https://registry.npmjs.org/@dcloudio/uni-app-vite/-/uni-app-vite-3.0.0-5000720260410001.tgz", + "integrity": "sha512-qJJBIzBzhe9ogG3CTIANru5cBxGwHt4Qv+izrBD3bff03Zxq91z5LULcY+HrlFgRIDl7p7oCFpMyMQdEaIeDGw==", + "license": "Apache-2.0", + "dependencies": { + "@dcloudio/uni-cli-shared": "3.0.0-5000720260410001", + "@dcloudio/uni-i18n": "3.0.0-5000720260410001", + "@dcloudio/uni-nvue-styler": "3.0.0-5000720260410001", + "@dcloudio/uni-shared": "3.0.0-5000720260410001", + "@rollup/pluginutils": "5.1.0", + "@vitejs/plugin-vue": "5.2.4", + "@vue/compiler-dom": "3.4.21", + "@vue/compiler-sfc": "3.4.21", + "debug": "4.3.7", + "fs-extra": "10.1.0", + "picocolors": "1.1.0" + } + }, + "node_modules/@dcloudio/uni-app-vue": { + "version": "3.0.0-5000720260410001", + "resolved": "https://registry.npmjs.org/@dcloudio/uni-app-vue/-/uni-app-vue-3.0.0-5000720260410001.tgz", + "integrity": "sha512-o/svSkAGrwnPOnM/WQfpLyiCt8sgogzubow9ze+h7f50kcTSTgJl1130Kk56D+YCLZBKMwXYXHWXyEZj+haYCA==", + "license": "Apache-2.0" + }, + "node_modules/@dcloudio/uni-automator": { + "version": "3.0.0-5000720260410001", + "resolved": "https://registry.npmjs.org/@dcloudio/uni-automator/-/uni-automator-3.0.0-5000720260410001.tgz", + "integrity": "sha512-H1HOVwEdpALzPsADObkfTXAW8Uo5V2XFAsXNOPhoYYQmzs8cjHJU2UljgpMO1itvZO1O6oIMsGEH5E4kQdrkmg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@dcloudio/uni-cli-shared": "3.0.0-5000720260410001", + "address": "^1.1.2", + "cross-env": "^7.0.3", + "debug": "4.3.7", + "default-gateway": "^6.0.3", + "fs-extra": "10.1.0", + "jsonc-parser": "3.3.1", + "licia": "1.41.1", + "merge": "2.1.1", + "qrcode-reader": "1.0.4", + "qrcode-terminal": "0.12.0", + "ws": "8.18.0" + }, + "peerDependencies": { + "jest": "27.0.4", + "jest-environment-node": "27.5.1" + } + }, + "node_modules/@dcloudio/uni-cli-shared": { + "version": "3.0.0-5000720260410001", + "resolved": "https://registry.npmjs.org/@dcloudio/uni-cli-shared/-/uni-cli-shared-3.0.0-5000720260410001.tgz", + "integrity": "sha512-UW0eEjO+GgmHixnSfBJxpI1fTW+0VgyjPTFUL+L7zNtIpI8eLEQHrGEbAC8IIOi4hAkVN3riDk80Dg2i3KSGqA==", + "license": "Apache-2.0", + "dependencies": { + "@ampproject/remapping": "^2.1.2", + "@babel/code-frame": "7.24.7", + "@babel/core": "7.25.2", + "@babel/parser": "7.25.6", + "@babel/types": "7.25.6", + "@dcloudio/uni-i18n": "3.0.0-5000720260410001", + "@dcloudio/uni-nvue-styler": "3.0.0-5000720260410001", + "@dcloudio/uni-shared": "3.0.0-5000720260410001", + "@intlify/core-base": "9.1.9", + "@intlify/shared": "9.1.9", + "@intlify/vue-devtools": "9.1.9", + "@rollup/pluginutils": "5.1.0", + "@vue/compiler-core": "3.4.21", + "@vue/compiler-dom": "3.4.21", + "@vue/compiler-sfc": "3.4.21", + "@vue/compiler-ssr": "3.4.21", + "@vue/server-renderer": "3.4.21", + "@vue/shared": "3.4.21", + "adm-zip": "0.5.16", + "autoprefixer": "10.4.20", + "base64url": "^3.0.1", + "chokidar": "3.6.0", + "compare-versions": "^3.6.0", + "debug": "4.3.7", + "entities": "^7.0.0", + "es-module-lexer": "1.5.4", + "esbuild": "0.20.2", + "estree-walker": "2.0.2", + "fast-glob": "3.3.3", + "fs-extra": "10.1.0", + "hash-sum": "2.0.0", + "isbinaryfile": "5.0.2", + "jsonc-parser": "3.3.1", + "lines-and-columns": "^2.0.4", + "magic-string": "0.30.11", + "merge": "2.1.1", + "mime": "3.0.0", + "module-alias": "2.2.3", + "os-locale-s-fix": "^1.0.8-fix-1", + "picocolors": "1.1.0", + "postcss-import": "^14.0.2", + "postcss-load-config": "^3.1.1", + "postcss-modules": "^4.3.0", + "postcss-selector-parser": "6.1.2", + "resolve": "1.22.8", + "source-map-js": "1.2.1", + "tapable": "^2.2.0", + "tinycolor2": "1.6.0", + "unimport": "4.1.1", + "unplugin-auto-import": "19.1.0", + "xregexp": "5.1.2" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + } + }, + "node_modules/@dcloudio/uni-cli-shared/node_modules/picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/@dcloudio/uni-cli-shared/node_modules/unplugin-auto-import": { + "version": "19.1.0", + "resolved": "https://registry.npmjs.org/unplugin-auto-import/-/unplugin-auto-import-19.1.0.tgz", + "integrity": "sha512-B+TGBEBHqY9aR+7YfShfLujETOHstzpV+yaqgy5PkfV0QG7Py+TYMX7vJ9W4SrysHR+UzR+gzcx/nuZjmPeclA==", + "license": "MIT", + "dependencies": { + "local-pkg": "^1.0.0", + "magic-string": "^0.30.17", + "picomatch": "^4.0.2", + "unimport": "^4.1.1", + "unplugin": "^2.2.0", + "unplugin-utils": "^0.2.4" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "@nuxt/kit": "^3.2.2", + "@vueuse/core": "*" + }, + "peerDependenciesMeta": { + "@nuxt/kit": { + "optional": true + }, + "@vueuse/core": { + "optional": true + } + } + }, + "node_modules/@dcloudio/uni-cli-shared/node_modules/unplugin-auto-import/node_modules/magic-string": { + "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, + "node_modules/@dcloudio/uni-cloud": { + "version": "3.0.0-5000720260410001", + "resolved": "https://registry.npmjs.org/@dcloudio/uni-cloud/-/uni-cloud-3.0.0-5000720260410001.tgz", + "integrity": "sha512-VGM8jhB3ol80mjvpSf+9gZApkYc2QDEk12ODTQKdQZbmjR33K7eqt8mpefErNYumnRmdQ4iL4oPArJ+O4GZpog==", + "license": "Apache-2.0", + "dependencies": { + "@dcloudio/uni-cli-shared": "3.0.0-5000720260410001", + "@dcloudio/uni-i18n": "3.0.0-5000720260410001", + "@dcloudio/uni-shared": "3.0.0-5000720260410001", + "@vue/shared": "3.4.21", + "fast-glob": "3.3.3" + } + }, + "node_modules/@dcloudio/uni-components": { + "version": "3.0.0-5000720260410001", + "resolved": "https://registry.npmjs.org/@dcloudio/uni-components/-/uni-components-3.0.0-5000720260410001.tgz", + "integrity": "sha512-ZwGKA1/mucO6SufgfN6JL1MFmeXFaEAoZUbXck8mvk/vwVduZHJeocWousF6bJtGMm23FM5ItG31KjcnwQpPjQ==", + "license": "Apache-2.0", + "dependencies": { + "@dcloudio/uni-cloud": "3.0.0-5000720260410001", + "@dcloudio/uni-h5": "3.0.0-5000720260410001", + "@dcloudio/uni-i18n": "3.0.0-5000720260410001" + } + }, + "node_modules/@dcloudio/uni-console": { + "version": "3.0.0-5000720260410001", + "resolved": "https://registry.npmjs.org/@dcloudio/uni-console/-/uni-console-3.0.0-5000720260410001.tgz", + "integrity": "sha512-ropH7p+fk4tjnFEex2FRqNPzK2g8Fs9OixJmDoR7th+7VZJ13LICR1DMd9cbwtERDECSbs5AJSQ/GU6/UP4P0Q==", + "license": "Apache-2.0", + "dependencies": { + "@dcloudio/uni-cli-shared": "3.0.0-5000720260410001", + "fs-extra": "10.1.0" + } + }, + "node_modules/@dcloudio/uni-h5": { + "version": "3.0.0-5000720260410001", + "resolved": "https://registry.npmjs.org/@dcloudio/uni-h5/-/uni-h5-3.0.0-5000720260410001.tgz", + "integrity": "sha512-N2Cp08qRfICs5yjNQ3Jnz3E4iM0EsDsCbyISOfHDcXeBeDNHAV57ZFMwI0yB4OpGOFp+th8dW2V50t/LlIcqfw==", + "license": "Apache-2.0", + "dependencies": { + "@dcloudio/uni-h5-vite": "3.0.0-5000720260410001", + "@dcloudio/uni-h5-vue": "3.0.0-5000720260410001", + "@dcloudio/uni-i18n": "3.0.0-5000720260410001", + "@dcloudio/uni-shared": "3.0.0-5000720260410001", + "@vue/server-renderer": "3.4.21", + "@vue/shared": "3.4.21", + "debug": "4.3.7", + "localstorage-polyfill": "^1.0.1", + "postcss-selector-parser": "6.1.2", + "safe-area-insets": "1.4.1", + "vue-router": "4.4.4", + "xmlhttprequest": "^1.8.0" + } + }, + "node_modules/@dcloudio/uni-h5-vite": { + "version": "3.0.0-5000720260410001", + "resolved": "https://registry.npmjs.org/@dcloudio/uni-h5-vite/-/uni-h5-vite-3.0.0-5000720260410001.tgz", + "integrity": "sha512-wqbr6VMH89RPbtWGL1EkCNyz9krtbd1XeobfwWkHjlJZnrgw0kf5KJQcS1Pi5v+mSoUi2L+jloOzCUyGKVZ4VQ==", + "license": "Apache-2.0", + "dependencies": { + "@dcloudio/uni-cli-shared": "3.0.0-5000720260410001", + "@dcloudio/uni-shared": "3.0.0-5000720260410001", + "@rollup/pluginutils": "5.1.0", + "@vue/compiler-dom": "3.4.21", + "@vue/compiler-sfc": "3.4.21", + "@vue/server-renderer": "3.4.21", + "@vue/shared": "3.4.21", + "debug": "4.3.7", + "fs-extra": "10.1.0", + "mime": "3.0.0", + "module-alias": "2.2.3" + } + }, + "node_modules/@dcloudio/uni-h5-vue": { + "version": "3.0.0-5000720260410001", + "resolved": "https://registry.npmjs.org/@dcloudio/uni-h5-vue/-/uni-h5-vue-3.0.0-5000720260410001.tgz", + "integrity": "sha512-69fkZ1rMFE+RBGbQeBBOI/fa0jKBbJLZN3HSu/bZqGGeqjGZQz22FdH5luYXyQuNxxT+rXTIFQlV5Z+NM2hr/w==", + "license": "Apache-2.0", + "dependencies": { + "@dcloudio/uni-shared": "3.0.0-5000720260410001", + "@vue/server-renderer": "3.4.21" + } + }, + "node_modules/@dcloudio/uni-i18n": { + "version": "3.0.0-5000720260410001", + "resolved": "https://registry.npmjs.org/@dcloudio/uni-i18n/-/uni-i18n-3.0.0-5000720260410001.tgz", + "integrity": "sha512-6X/2eRqbAmQR1bUJpzCjr2xKXDY2+3rQWsvQ5RjwKQVFsz641GlVlUdxI6YwIZumGDRiCIz8T9eGfyIC6pGt9Q==", + "license": "Apache-2.0" + }, + "node_modules/@dcloudio/uni-mp-alipay": { + "version": "3.0.0-5000720260410001", + "resolved": "https://registry.npmjs.org/@dcloudio/uni-mp-alipay/-/uni-mp-alipay-3.0.0-5000720260410001.tgz", + "integrity": "sha512-09T0my/A3Vm6Qocuq7g6b/nvUECJF1cnEkfKuyrF9SAVwVOSAdsYdltoUpo3vkz0ktladKdRBwWXk26sQUz27A==", + "license": "Apache-2.0", + "dependencies": { + "@dcloudio/uni-cli-shared": "3.0.0-5000720260410001", + "@dcloudio/uni-mp-compiler": "3.0.0-5000720260410001", + "@dcloudio/uni-mp-vite": "3.0.0-5000720260410001", + "@dcloudio/uni-mp-vue": "3.0.0-5000720260410001", + "@dcloudio/uni-shared": "3.0.0-5000720260410001", + "@vue/compiler-core": "3.4.21", + "@vue/shared": "3.4.21" + } + }, + "node_modules/@dcloudio/uni-mp-baidu": { + "version": "3.0.0-5000720260410001", + "resolved": "https://registry.npmjs.org/@dcloudio/uni-mp-baidu/-/uni-mp-baidu-3.0.0-5000720260410001.tgz", + "integrity": "sha512-pD8p7t6scgNcyI2uzgkyktxL8yCxQPTs88byW5s/zPbnT4NMJHCf/49UNA6qJQdpcVtvtiPEsj1tmFbAyGaszw==", + "license": "Apache-2.0", + "dependencies": { + "@dcloudio/uni-app": "3.0.0-5000720260410001", + "@dcloudio/uni-cli-shared": "3.0.0-5000720260410001", + "@dcloudio/uni-mp-compiler": "3.0.0-5000720260410001", + "@dcloudio/uni-mp-vite": "3.0.0-5000720260410001", + "@dcloudio/uni-mp-vue": "3.0.0-5000720260410001", + "@dcloudio/uni-mp-weixin": "3.0.0-5000720260410001", + "@dcloudio/uni-shared": "3.0.0-5000720260410001", + "@vue/compiler-core": "3.4.21", + "@vue/shared": "3.4.21", + "jimp": "0.10.3", + "licia": "1.41.1", + "qrcode-reader": "1.0.4", + "qrcode-terminal": "0.12.0", + "ws": "8.18.0" + } + }, + "node_modules/@dcloudio/uni-mp-compiler": { + "version": "3.0.0-5000720260410001", + "resolved": "https://registry.npmjs.org/@dcloudio/uni-mp-compiler/-/uni-mp-compiler-3.0.0-5000720260410001.tgz", + "integrity": "sha512-2+61GVODCLj8EOV3dhKQq8db8Ru8AHHv04Xm1bW188m3PbD6lh5hgGUc5HeKuQFdVxUzS4U0UtUtwGavPRc9ww==", + "license": "Apache-2.0", + "dependencies": { + "@babel/generator": "7.25.6", + "@babel/parser": "7.25.6", + "@babel/types": "7.25.6", + "@dcloudio/uni-cli-shared": "3.0.0-5000720260410001", + "@dcloudio/uni-shared": "3.0.0-5000720260410001", + "@vue/compiler-core": "3.4.21", + "@vue/compiler-dom": "3.4.21", + "@vue/shared": "3.4.21", + "estree-walker": "2.0.2" + } + }, + "node_modules/@dcloudio/uni-mp-compiler/node_modules/@babel/generator": { + "version": "7.25.6", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.25.6.tgz", + "integrity": "sha512-VPC82gr1seXOpkjAAKoLhP50vx4vGNlF4msF64dSFq1P8RfB+QAuJWGHPXXPc8QyfVWwwB/TNNU4+ayZmHNbZw==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.25.6", + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25", + "jsesc": "^2.5.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@dcloudio/uni-mp-compiler/node_modules/jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@dcloudio/uni-mp-harmony": { + "version": "3.0.0-5000720260410001", + "resolved": "https://registry.npmjs.org/@dcloudio/uni-mp-harmony/-/uni-mp-harmony-3.0.0-5000720260410001.tgz", + "integrity": "sha512-nQV5UTrgRMdf5AtOAIwNDkRUBXvLQLIrilUTCMB2E1ILgrmwf5jO/1+ghUQRiBRL5UeXF+o7GRpSN572bcBtcg==", + "license": "Apache-2.0", + "dependencies": { + "@dcloudio/uni-cli-shared": "3.0.0-5000720260410001", + "@dcloudio/uni-mp-toutiao": "3.0.0-5000720260410001", + "@dcloudio/uni-mp-vite": "3.0.0-5000720260410001", + "@dcloudio/uni-mp-vue": "3.0.0-5000720260410001", + "@dcloudio/uni-quickapp-webview": "3.0.0-5000720260410001", + "@dcloudio/uni-shared": "3.0.0-5000720260410001", + "@vue/shared": "3.4.21" + } + }, + "node_modules/@dcloudio/uni-mp-jd": { + "version": "3.0.0-5000720260410001", + "resolved": "https://registry.npmjs.org/@dcloudio/uni-mp-jd/-/uni-mp-jd-3.0.0-5000720260410001.tgz", + "integrity": "sha512-RNawlyPrJVTH4VHCXhJcokSZ5XS4niBCvgEI4h96qTT1SfyMXveJwATGlc3n80mVeqKjJy5FnGdUjPSsMO5L4Q==", + "license": "Apache-2.0", + "dependencies": { + "@dcloudio/uni-cli-shared": "3.0.0-5000720260410001", + "@dcloudio/uni-mp-compiler": "3.0.0-5000720260410001", + "@dcloudio/uni-mp-vite": "3.0.0-5000720260410001", + "@dcloudio/uni-mp-vue": "3.0.0-5000720260410001", + "@dcloudio/uni-shared": "3.0.0-5000720260410001", + "@vue/shared": "3.4.21" + } + }, + "node_modules/@dcloudio/uni-mp-kuaishou": { + "version": "3.0.0-5000720260410001", + "resolved": "https://registry.npmjs.org/@dcloudio/uni-mp-kuaishou/-/uni-mp-kuaishou-3.0.0-5000720260410001.tgz", + "integrity": "sha512-4lybG8gYPbrU2Gdjg5Q3IJxB9Ac8AH5k6CJVM9t0mvRzc8TBFrFGn30qnpzvGOgXDgWaRVjkHouiLB36SPFBLw==", + "license": "Apache-2.0", + "dependencies": { + "@dcloudio/uni-cli-shared": "3.0.0-5000720260410001", + "@dcloudio/uni-mp-compiler": "3.0.0-5000720260410001", + "@dcloudio/uni-mp-vite": "3.0.0-5000720260410001", + "@dcloudio/uni-mp-vue": "3.0.0-5000720260410001", + "@dcloudio/uni-mp-weixin": "3.0.0-5000720260410001", + "@dcloudio/uni-shared": "3.0.0-5000720260410001", + "@vue/compiler-core": "3.4.21", + "@vue/shared": "3.4.21" + } + }, + "node_modules/@dcloudio/uni-mp-lark": { + "version": "3.0.0-5000720260410001", + "resolved": "https://registry.npmjs.org/@dcloudio/uni-mp-lark/-/uni-mp-lark-3.0.0-5000720260410001.tgz", + "integrity": "sha512-8POfMKrFgRcOrWJLGmklXvNPhDjm5ZKHjcRyg00d5QFyh2mQRq27X6zNlSU9F/ecJoVLxgFxkRyjK8cJYRPfxA==", + "license": "Apache-2.0", + "dependencies": { + "@dcloudio/uni-cli-shared": "3.0.0-5000720260410001", + "@dcloudio/uni-mp-compiler": "3.0.0-5000720260410001", + "@dcloudio/uni-mp-toutiao": "3.0.0-5000720260410001", + "@dcloudio/uni-mp-vite": "3.0.0-5000720260410001", + "@dcloudio/uni-mp-vue": "3.0.0-5000720260410001", + "@dcloudio/uni-shared": "3.0.0-5000720260410001", + "@vue/compiler-core": "3.4.21", + "@vue/shared": "3.4.21" + } + }, + "node_modules/@dcloudio/uni-mp-qq": { + "version": "3.0.0-5000720260410001", + "resolved": "https://registry.npmjs.org/@dcloudio/uni-mp-qq/-/uni-mp-qq-3.0.0-5000720260410001.tgz", + "integrity": "sha512-vt6XcFGEwY5S9n6UvndKZb3YT6jTpQcctzVzSZI12cu8/nxCVGbrnZosyxNKf2g8sRLlFkN2VahJaFXzWBYn9A==", + "license": "Apache-2.0", + "dependencies": { + "@dcloudio/uni-cli-shared": "3.0.0-5000720260410001", + "@dcloudio/uni-mp-compiler": "3.0.0-5000720260410001", + "@dcloudio/uni-mp-vite": "3.0.0-5000720260410001", + "@dcloudio/uni-mp-vue": "3.0.0-5000720260410001", + "@dcloudio/uni-shared": "3.0.0-5000720260410001", + "@vue/shared": "3.4.21", + "fs-extra": "10.1.0" + } + }, + "node_modules/@dcloudio/uni-mp-toutiao": { + "version": "3.0.0-5000720260410001", + "resolved": "https://registry.npmjs.org/@dcloudio/uni-mp-toutiao/-/uni-mp-toutiao-3.0.0-5000720260410001.tgz", + "integrity": "sha512-obnJZ+lASqWFybC72DewGiN44TYJpcVEcQJL0CQYtv77+N5mLa7eiTd0H4vsl8IRF84qVNsz+QuBQgAn/w42QA==", + "license": "Apache-2.0", + "dependencies": { + "@dcloudio/uni-cli-shared": "3.0.0-5000720260410001", + "@dcloudio/uni-mp-compiler": "3.0.0-5000720260410001", + "@dcloudio/uni-mp-vite": "3.0.0-5000720260410001", + "@dcloudio/uni-mp-vue": "3.0.0-5000720260410001", + "@dcloudio/uni-shared": "3.0.0-5000720260410001", + "@vue/compiler-core": "3.4.21", + "@vue/shared": "3.4.21" + } + }, + "node_modules/@dcloudio/uni-mp-vite": { + "version": "3.0.0-5000720260410001", + "resolved": "https://registry.npmjs.org/@dcloudio/uni-mp-vite/-/uni-mp-vite-3.0.0-5000720260410001.tgz", + "integrity": "sha512-SH0WF3RNiANzhankhqLJT0dPDnbty6mTjj8JUibrDcj3MwplO/jgmiRxECMFKJGmE//xfRlaZgDCAUX5tHj76w==", + "license": "Apache-2.0", + "dependencies": { + "@dcloudio/uni-cli-shared": "3.0.0-5000720260410001", + "@dcloudio/uni-i18n": "3.0.0-5000720260410001", + "@dcloudio/uni-mp-compiler": "3.0.0-5000720260410001", + "@dcloudio/uni-mp-vue": "3.0.0-5000720260410001", + "@dcloudio/uni-shared": "3.0.0-5000720260410001", + "@vue/compiler-dom": "3.4.21", + "@vue/compiler-sfc": "3.4.21", + "@vue/shared": "3.4.21", + "debug": "4.3.7" + } + }, + "node_modules/@dcloudio/uni-mp-vue": { + "version": "3.0.0-5000720260410001", + "resolved": "https://registry.npmjs.org/@dcloudio/uni-mp-vue/-/uni-mp-vue-3.0.0-5000720260410001.tgz", + "integrity": "sha512-IzPJ94VJdeo0OOdZ+Knz7RKXvxyw5t2gFo3ti072Xfh/nXIv4KgfcgkrofKHz1iYBwRZE/MYW92ZYwJt/2Q+1g==", + "license": "Apache-2.0", + "dependencies": { + "@dcloudio/uni-shared": "3.0.0-5000720260410001", + "@vue/shared": "3.4.21" + } + }, + "node_modules/@dcloudio/uni-mp-weixin": { + "version": "3.0.0-5000720260410001", + "resolved": "https://registry.npmjs.org/@dcloudio/uni-mp-weixin/-/uni-mp-weixin-3.0.0-5000720260410001.tgz", + "integrity": "sha512-mS9yLbBbPn2OWtMnKZgjuQuiJW/f1GW51qTqblWz/T6viHeYoReAge2UfOGCHEAgO/HVLK5vlm8eZLP3jnQOBA==", + "license": "Apache-2.0", + "dependencies": { + "@dcloudio/uni-cli-shared": "3.0.0-5000720260410001", + "@dcloudio/uni-mp-compiler": "3.0.0-5000720260410001", + "@dcloudio/uni-mp-vite": "3.0.0-5000720260410001", + "@dcloudio/uni-mp-vue": "3.0.0-5000720260410001", + "@dcloudio/uni-shared": "3.0.0-5000720260410001", + "@vue/shared": "3.4.21", + "jimp": "0.10.3", + "licia": "1.41.1", + "qrcode-reader": "1.0.4", + "qrcode-terminal": "0.12.0", + "ws": "8.18.0" + } + }, + "node_modules/@dcloudio/uni-mp-xhs": { + "version": "3.0.0-5000720260410001", + "resolved": "https://registry.npmjs.org/@dcloudio/uni-mp-xhs/-/uni-mp-xhs-3.0.0-5000720260410001.tgz", + "integrity": "sha512-ambnwwAJJ9xeT13wvHTuf+FCWBH/VqaHTPpziJowFDTnqNkXGqFLRrMAd/EPj3gIxUjW7zvspsudTlUvqjAv1g==", + "license": "Apache-2.0", + "dependencies": { + "@dcloudio/uni-cli-shared": "3.0.0-5000720260410001", + "@dcloudio/uni-mp-compiler": "3.0.0-5000720260410001", + "@dcloudio/uni-mp-vite": "3.0.0-5000720260410001", + "@dcloudio/uni-mp-vue": "3.0.0-5000720260410001", + "@dcloudio/uni-shared": "3.0.0-5000720260410001", + "@vue/shared": "3.4.21" + } + }, + "node_modules/@dcloudio/uni-nvue-styler": { + "version": "3.0.0-5000720260410001", + "resolved": "https://registry.npmjs.org/@dcloudio/uni-nvue-styler/-/uni-nvue-styler-3.0.0-5000720260410001.tgz", + "integrity": "sha512-7eFvhU67IDBxfyLP5zUyRTQPzJFoJ0WeV7QNpgvJf4FznynAGLfZ0Rh8Zgan8vxWa+PSSbpooVQbjCYJXhq5lg==", + "license": "Apache-2.0", + "dependencies": { + "@vue/shared": "3.4.21", + "parse-css-font": "^4.0.0", + "postcss": "8.4.45", + "tinycolor2": "1.6.0" + } + }, + "node_modules/@dcloudio/uni-nvue-styler/node_modules/postcss": { + "version": "8.4.45", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.45.tgz", + "integrity": "sha512-7KTLTdzdZZYscUc65XmjFiB73vBhBfbPztCYdUNvlaso9PrzjzcmjqBPR0lNGkcVlcO4BjiO5rK/qNz+XAen1Q==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.7", + "picocolors": "^1.0.1", + "source-map-js": "^1.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/@dcloudio/uni-push": { + "version": "3.0.0-5000720260410001", + "resolved": "https://registry.npmjs.org/@dcloudio/uni-push/-/uni-push-3.0.0-5000720260410001.tgz", + "integrity": "sha512-oCmufDQ20AFxwBs7Aoz9BDWx1KMSW76bKU6AQ8YqM1MPxCDLif5d830Gwivc4rQFGlc3x7hYGh30r8/kl8FLbw==", + "license": "Apache-2.0", + "dependencies": { + "@dcloudio/uni-cli-shared": "3.0.0-5000720260410001" + } + }, + "node_modules/@dcloudio/uni-quickapp-webview": { + "version": "3.0.0-5000720260410001", + "resolved": "https://registry.npmjs.org/@dcloudio/uni-quickapp-webview/-/uni-quickapp-webview-3.0.0-5000720260410001.tgz", + "integrity": "sha512-X1mIwQgqv/KMYfcbw6BnXA9+h7pg1CDyj9F0v6fhgAcHmKZOczYh+VgVPiQ5RTBNj/KkGO/ea+enP79TFdCqtA==", + "license": "Apache-2.0", + "dependencies": { + "@dcloudio/uni-cli-shared": "3.0.0-5000720260410001", + "@dcloudio/uni-mp-vite": "3.0.0-5000720260410001", + "@dcloudio/uni-mp-vue": "3.0.0-5000720260410001", + "@dcloudio/uni-shared": "3.0.0-5000720260410001", + "@vue/shared": "3.4.21" + } + }, + "node_modules/@dcloudio/uni-shared": { + "version": "3.0.0-5000720260410001", + "resolved": "https://registry.npmjs.org/@dcloudio/uni-shared/-/uni-shared-3.0.0-5000720260410001.tgz", + "integrity": "sha512-B51i5GohH5D6v4OgXQToESihIpmssBNSQAbiKdV10uQ/6u5TtyQkTtUKwdhjm+SY5xQSluV9sBpnB+LvYyWakg==", + "license": "Apache-2.0", + "dependencies": { + "@vue/shared": "3.4.21" + } + }, + "node_modules/@dcloudio/uni-stacktracey": { + "version": "3.0.0-5000720260410001", + "resolved": "https://registry.npmjs.org/@dcloudio/uni-stacktracey/-/uni-stacktracey-3.0.0-5000720260410001.tgz", + "integrity": "sha512-/PDrXioKUsxXUSIwcnjnJhbr7URyDfGH2skImF7KrDn3dYG+dN0WJQqPsWVwr5zr0p3kpr+uO42ce2fsT6yv5Q==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/@dcloudio/uni-stat": { + "version": "3.0.0-5000720260410001", + "resolved": "https://registry.npmjs.org/@dcloudio/uni-stat/-/uni-stat-3.0.0-5000720260410001.tgz", + "integrity": "sha512-6jDWTufAjGsdOPcfnSsB2ylaBosFj5+UqZch56NgDrHejasdJ5Pb+peqOP7zn/mlRCiYk0dWTi6ZhcUFJ8ZKDA==", + "license": "Apache-2.0", + "dependencies": { + "@dcloudio/uni-cli-shared": "3.0.0-5000720260410001", + "@dcloudio/uni-shared": "3.0.0-5000720260410001", + "debug": "4.3.7" + } + }, + "node_modules/@dcloudio/vite-plugin-uni": { + "version": "3.0.0-5000720260410001", + "resolved": "https://registry.npmjs.org/@dcloudio/vite-plugin-uni/-/vite-plugin-uni-3.0.0-5000720260410001.tgz", + "integrity": "sha512-wVNF7QRImQkAOwtRLrZ80z5KnF+F7P+cBV/BH16aA/Upj1xyFcihRF4QENt9PyhO0syg5n+Dl4Xhm7Oz+6mjPA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@babel/core": "7.25.2", + "@babel/plugin-syntax-import-meta": "^7.10.4", + "@babel/plugin-transform-typescript": "^7.23.3", + "@dcloudio/uni-cli-shared": "3.0.0-5000720260410001", + "@dcloudio/uni-nvue-styler": "3.0.0-5000720260410001", + "@dcloudio/uni-shared": "3.0.0-5000720260410001", + "@rollup/pluginutils": "5.1.0", + "@vitejs/plugin-legacy": "5.3.2", + "@vitejs/plugin-vue": "5.2.4", + "@vitejs/plugin-vue-jsx": "3.1.0", + "@vue/compiler-core": "3.4.21", + "@vue/compiler-dom": "3.4.21", + "@vue/compiler-sfc": "3.4.21", + "@vue/shared": "3.4.21", + "cac": "6.7.9", + "debug": "4.3.7", + "estree-walker": "2.0.2", + "express": "4.20.0", + "fast-glob": "3.3.3", + "fs-extra": "10.1.0", + "hash-sum": "2.0.0", + "jsonc-parser": "3.3.1", + "magic-string": "0.30.11", + "picocolors": "1.1.0", + "terser": "^5.4.0", + "unplugin-auto-import": "19.1.0" + }, + "bin": { + "uni": "bin/uni.js" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "peerDependencies": { + "vite": "5.2.8" + } + }, + "node_modules/@dcloudio/vite-plugin-uni/node_modules/picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/@dcloudio/vite-plugin-uni/node_modules/unplugin-auto-import": { + "version": "19.1.0", + "resolved": "https://registry.npmjs.org/unplugin-auto-import/-/unplugin-auto-import-19.1.0.tgz", + "integrity": "sha512-B+TGBEBHqY9aR+7YfShfLujETOHstzpV+yaqgy5PkfV0QG7Py+TYMX7vJ9W4SrysHR+UzR+gzcx/nuZjmPeclA==", + "dev": true, + "license": "MIT", + "dependencies": { + "local-pkg": "^1.0.0", + "magic-string": "^0.30.17", + "picomatch": "^4.0.2", + "unimport": "^4.1.1", + "unplugin": "^2.2.0", + "unplugin-utils": "^0.2.4" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "@nuxt/kit": "^3.2.2", + "@vueuse/core": "*" + }, + "peerDependenciesMeta": { + "@nuxt/kit": { + "optional": true + }, + "@vueuse/core": { + "optional": true + } + } + }, + "node_modules/@dcloudio/vite-plugin-uni/node_modules/unplugin-auto-import/node_modules/magic-string": { + "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.20.2.tgz", + "integrity": "sha512-D+EBOJHXdNZcLJRBkhENNG8Wji2kgc9AZ9KiPr1JuZjsNtyHzrsfLRrY0tk2H2aoFu6RANO1y1iPPUCDYWkb5g==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.20.2.tgz", + "integrity": "sha512-t98Ra6pw2VaDhqNWO2Oph2LXbz/EJcnLmKLGBJwEwXX/JAN83Fym1rU8l0JUWK6HkIbWONCSSatf4sf2NBRx/w==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.20.2.tgz", + "integrity": "sha512-mRzjLacRtl/tWU0SvD8lUEwb61yP9cqQo6noDZP/O8VkwafSYwZ4yWy24kan8jE/IMERpYncRt2dw438LP3Xmg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.20.2.tgz", + "integrity": "sha512-btzExgV+/lMGDDa194CcUQm53ncxzeBrWJcncOBxuC6ndBkKxnHdFJn86mCIgTELsooUmwUm9FkhSp5HYu00Rg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.20.2.tgz", + "integrity": "sha512-4J6IRT+10J3aJH3l1yzEg9y3wkTDgDk7TSDFX+wKFiWjqWp/iCfLIYzGyasx9l0SAFPT1HwSCR+0w/h1ES/MjA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.20.2.tgz", + "integrity": "sha512-tBcXp9KNphnNH0dfhv8KYkZhjc+H3XBkF5DKtswJblV7KlT9EI2+jeA8DgBjp908WEuYll6pF+UStUCfEpdysA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.20.2.tgz", + "integrity": "sha512-d3qI41G4SuLiCGCFGUrKsSeTXyWG6yem1KcGZVS+3FYlYhtNoNgYrWcvkOoaqMhwXSMrZRl69ArHsGJ9mYdbbw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.20.2.tgz", + "integrity": "sha512-d+DipyvHRuqEeM5zDivKV1KuXn9WeRX6vqSqIDgwIfPQtwMP4jaDsQsDncjTDDsExT4lR/91OLjRo8bmC1e+Cw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.20.2.tgz", + "integrity": "sha512-VhLPeR8HTMPccbuWWcEUD1Az68TqaTYyj6nfE4QByZIQEQVWBB8vup8PpR7y1QHL3CpcF6xd5WVBU/+SBEvGTg==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.20.2.tgz", + "integrity": "sha512-9pb6rBjGvTFNira2FLIWqDk/uaf42sSyLE8j1rnUpuzsODBq7FvpwHYZxQ/It/8b+QOS1RYfqgGFNLRI+qlq2A==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.20.2.tgz", + "integrity": "sha512-o10utieEkNPFDZFQm9CoP7Tvb33UutoJqg3qKf1PWVeeJhJw0Q347PxMvBgVVFgouYLGIhFYG0UGdBumROyiig==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.20.2.tgz", + "integrity": "sha512-PR7sp6R/UC4CFVomVINKJ80pMFlfDfMQMYynX7t1tNTeivQ6XdX5r2XovMmha/VjR1YN/HgHWsVcTRIMkymrgQ==", + "cpu": [ + "loong64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.20.2.tgz", + "integrity": "sha512-4BlTqeutE/KnOiTG5Y6Sb/Hw6hsBOZapOVF6njAESHInhlQAghVVZL1ZpIctBOoTFbQyGW+LsVYZ8lSSB3wkjA==", + "cpu": [ + "mips64el" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.20.2.tgz", + "integrity": "sha512-rD3KsaDprDcfajSKdn25ooz5J5/fWBylaaXkuotBDGnMnDP1Uv5DLAN/45qfnf3JDYyJv/ytGHQaziHUdyzaAg==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.20.2.tgz", + "integrity": "sha512-snwmBKacKmwTMmhLlz/3aH1Q9T8v45bKYGE3j26TsaOVtjIag4wLfWSiZykXzXuE1kbCE+zJRmwp+ZbIHinnVg==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.20.2.tgz", + "integrity": "sha512-wcWISOobRWNm3cezm5HOZcYz1sKoHLd8VL1dl309DiixxVFoFe/o8HnwuIwn6sXre88Nwj+VwZUvJf4AFxkyrQ==", + "cpu": [ + "s390x" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.20.2.tgz", + "integrity": "sha512-1MdwI6OOTsfQfek8sLwgyjOXAu+wKhLEoaOLTjbijk6E2WONYpH9ZU2mNtR+lZ2B4uwr+usqGuVfFT9tMtGvGw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.20.2.tgz", + "integrity": "sha512-K8/DhBxcVQkzYc43yJXDSyjlFeHQJBiowJ0uVL6Tor3jGQfSGHNNJcWxNbOI8v5k82prYqzPuwkzHt3J1T1iZQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.20.2.tgz", + "integrity": "sha512-eMpKlV0SThJmmJgiVyN9jTPJ2VBPquf6Kt/nAoo6DgHAoN57K15ZghiHaMvqjCye/uU4X5u3YSMgVBI1h3vKrQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.20.2.tgz", + "integrity": "sha512-2UyFtRC6cXLyejf/YEld4Hajo7UHILetzE1vsRcGL3earZEW77JxrFjH4Ez2qaTiEfMgAXxfAZCm1fvM/G/o8w==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.20.2.tgz", + "integrity": "sha512-GRibxoawM9ZCnDxnP3usoUDO9vUkpAxIIZ6GQI+IlVmr5kP3zUq+l17xELTHMWTWzjxa2guPNyrpq1GWmPvcGQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.20.2.tgz", + "integrity": "sha512-HfLOfn9YWmkSKRQqovpnITazdtquEW8/SoHW7pWpuEeguaZI4QnCRW6b+oZTztdBnZOS2hqJ6im/D5cPzBTTlQ==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.20.2.tgz", + "integrity": "sha512-N49X4lJX27+l9jbLKSqZ6bKNjzQvHaT8IIFUy+YIqmXQdjYCToGWwOItDrfby14c78aDd5NHQl29xingXfCdLQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@intlify/core-base": { + "version": "9.1.9", + "resolved": "https://registry.npmjs.org/@intlify/core-base/-/core-base-9.1.9.tgz", + "integrity": "sha512-x5T0p/Ja0S8hs5xs+ImKyYckVkL4CzcEXykVYYV6rcbXxJTe2o58IquSqX9bdncVKbRZP7GlBU1EcRaQEEJ+vw==", + "license": "MIT", + "dependencies": { + "@intlify/devtools-if": "9.1.9", + "@intlify/message-compiler": "9.1.9", + "@intlify/message-resolver": "9.1.9", + "@intlify/runtime": "9.1.9", + "@intlify/shared": "9.1.9", + "@intlify/vue-devtools": "9.1.9" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/@intlify/devtools-if": { + "version": "9.1.9", + "resolved": "https://registry.npmjs.org/@intlify/devtools-if/-/devtools-if-9.1.9.tgz", + "integrity": "sha512-oKSMKjttG3Ut/1UGEZjSdghuP3fwA15zpDPcjkf/1FjlOIm6uIBGMNS5jXzsZy593u+P/YcnrZD6cD3IVFz9vQ==", + "license": "MIT", + "dependencies": { + "@intlify/shared": "9.1.9" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/@intlify/message-compiler": { + "version": "9.1.9", + "resolved": "https://registry.npmjs.org/@intlify/message-compiler/-/message-compiler-9.1.9.tgz", + "integrity": "sha512-6YgCMF46Xd0IH2hMRLCssZI3gFG4aywidoWQ3QP4RGYQXQYYfFC54DxhSgfIPpVoPLQ+4AD29eoYmhiHZ+qLFQ==", + "license": "MIT", + "dependencies": { + "@intlify/message-resolver": "9.1.9", + "@intlify/shared": "9.1.9", + "source-map": "0.6.1" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/@intlify/message-resolver": { + "version": "9.1.9", + "resolved": "https://registry.npmjs.org/@intlify/message-resolver/-/message-resolver-9.1.9.tgz", + "integrity": "sha512-Lx/DBpigeK0sz2BBbzv5mu9/dAlt98HxwbG7xLawC3O2xMF9MNWU5FtOziwYG6TDIjNq0O/3ZbOJAxwITIWXEA==", + "license": "MIT", + "engines": { + "node": ">= 10" + } + }, + "node_modules/@intlify/runtime": { + "version": "9.1.9", + "resolved": "https://registry.npmjs.org/@intlify/runtime/-/runtime-9.1.9.tgz", + "integrity": "sha512-XgPw8+UlHCiie3fI41HPVa/VDJb3/aSH7bLhY1hJvlvNV713PFtb4p4Jo+rlE0gAoMsMCGcsiT982fImolSltg==", + "license": "MIT", + "dependencies": { + "@intlify/message-compiler": "9.1.9", + "@intlify/message-resolver": "9.1.9", + "@intlify/shared": "9.1.9" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/@intlify/shared": { + "version": "9.1.9", + "resolved": "https://registry.npmjs.org/@intlify/shared/-/shared-9.1.9.tgz", + "integrity": "sha512-xKGM1d0EAxdDFCWedcYXOm6V5Pfw/TMudd6/qCdEb4tv0hk9EKeg7lwQF1azE0dP2phvx0yXxrt7UQK+IZjNdw==", + "license": "MIT", + "engines": { + "node": ">= 10" + } + }, + "node_modules/@intlify/vue-devtools": { + "version": "9.1.9", + "resolved": "https://registry.npmjs.org/@intlify/vue-devtools/-/vue-devtools-9.1.9.tgz", + "integrity": "sha512-YPehH9uL4vZcGXky4Ev5qQIITnHKIvsD2GKGXgqf+05osMUI6WSEQHaN9USRa318Rs8RyyPCiDfmA0hRu3k7og==", + "license": "MIT", + "dependencies": { + "@intlify/message-resolver": "9.1.9", + "@intlify/runtime": "9.1.9", + "@intlify/shared": "9.1.9" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/@istanbuljs/load-nyc-config": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", + "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", + "dev": true, + "license": "ISC", + "peer": true, + "dependencies": { + "camelcase": "^5.3.1", + "find-up": "^4.1.0", + "get-package-type": "^0.1.0", + "js-yaml": "^3.13.1", + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/schema": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.6.tgz", + "integrity": "sha512-+Sg6GCR/wy1oSmQDFq4LQDAhm3ETKnorxN+y5nbLULOR3P0c14f2Wurzj3/xqPXtasLFfHd5iRFQ7AJt4KH2cw==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/console": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-27.5.1.tgz", + "integrity": "sha512-kZ/tNpS3NXn0mlXXXPNuDZnb4c0oZ20r4K5eemM2k30ZC3G0T02nXUvyhf5YdbXWHPEJLc9qGLxEZ216MdL+Zg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@jest/types": "^27.5.1", + "@types/node": "*", + "chalk": "^4.0.0", + "jest-message-util": "^27.5.1", + "jest-util": "^27.5.1", + "slash": "^3.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jest/console/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@jest/console/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@jest/console/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/@jest/console/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/@jest/console/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/console/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/core": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-27.5.1.tgz", + "integrity": "sha512-AK6/UTrvQD0Cd24NSqmIA6rKsu0tKIxfiCducZvqxYdmMisOYAsdItspT+fQDQYARPf8XgjAFZi0ogW2agH5nQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@jest/console": "^27.5.1", + "@jest/reporters": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/transform": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "emittery": "^0.8.1", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "jest-changed-files": "^27.5.1", + "jest-config": "^27.5.1", + "jest-haste-map": "^27.5.1", + "jest-message-util": "^27.5.1", + "jest-regex-util": "^27.5.1", + "jest-resolve": "^27.5.1", + "jest-resolve-dependencies": "^27.5.1", + "jest-runner": "^27.5.1", + "jest-runtime": "^27.5.1", + "jest-snapshot": "^27.5.1", + "jest-util": "^27.5.1", + "jest-validate": "^27.5.1", + "jest-watcher": "^27.5.1", + "micromatch": "^4.0.4", + "rimraf": "^3.0.0", + "slash": "^3.0.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/@jest/core/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@jest/core/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@jest/core/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/@jest/core/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/@jest/core/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/core/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/environment": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-27.5.1.tgz", + "integrity": "sha512-/WQjhPJe3/ghaol/4Bq480JKXV/Rfw8nQdN7f41fM8VDHLcxKXou6QyXAh3EFr9/bVG3x74z1NWDkP87EiY8gA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@jest/fake-timers": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "jest-mock": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jest/fake-timers": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-27.5.1.tgz", + "integrity": "sha512-/aPowoolwa07k7/oM3aASneNeBGCmGQsc3ugN4u6s4C/+s5M64MFo/+djTdiwcbQlRfFElGuDXWzaWj6QgKObQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@jest/types": "^27.5.1", + "@sinonjs/fake-timers": "^8.0.1", + "@types/node": "*", + "jest-message-util": "^27.5.1", + "jest-mock": "^27.5.1", + "jest-util": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jest/globals": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-27.5.1.tgz", + "integrity": "sha512-ZEJNB41OBQQgGzgyInAv0UUfDDj3upmHydjieSxFvTRuZElrx7tXg/uVQ5hYVEwiXs3+aMsAeEc9X7xiSKCm4Q==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@jest/environment": "^27.5.1", + "@jest/types": "^27.5.1", + "expect": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jest/reporters": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-27.5.1.tgz", + "integrity": "sha512-cPXh9hWIlVJMQkVk84aIvXuBB4uQQmFqZiacloFuGiP3ah1sbCxCosidXFDfqG8+6fO1oR2dTJTlsOy4VFmUfw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@bcoe/v8-coverage": "^0.2.3", + "@jest/console": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/transform": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "chalk": "^4.0.0", + "collect-v8-coverage": "^1.0.0", + "exit": "^0.1.2", + "glob": "^7.1.2", + "graceful-fs": "^4.2.9", + "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-instrument": "^5.1.0", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^4.0.0", + "istanbul-reports": "^3.1.3", + "jest-haste-map": "^27.5.1", + "jest-resolve": "^27.5.1", + "jest-util": "^27.5.1", + "jest-worker": "^27.5.1", + "slash": "^3.0.0", + "source-map": "^0.6.0", + "string-length": "^4.0.1", + "terminal-link": "^2.0.0", + "v8-to-istanbul": "^8.1.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/@jest/reporters/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@jest/reporters/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@jest/reporters/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/@jest/reporters/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/@jest/reporters/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/reporters/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/source-map": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-27.5.1.tgz", + "integrity": "sha512-y9NIHUYF3PJRlHk98NdC/N1gl88BL08aQQgu4k4ZopQkCw9t9cV8mtl3TV8b/YCB8XaVTFrmUTAJvjsntDireg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "callsites": "^3.0.0", + "graceful-fs": "^4.2.9", + "source-map": "^0.6.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jest/test-result": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-27.5.1.tgz", + "integrity": "sha512-EW35l2RYFUcUQxFJz5Cv5MTOxlJIQs4I7gxzi2zVU7PJhOwfYq1MdC5nhSmYjX1gmMmLPvB3sIaC+BkcHRBfag==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@jest/console": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/istanbul-lib-coverage": "^2.0.0", + "collect-v8-coverage": "^1.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jest/test-sequencer": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-27.5.1.tgz", + "integrity": "sha512-LCheJF7WB2+9JuCS7VB/EmGIdQuhtqjRNI9A43idHv3E4KltCTsPsLxvdaubFHSYwY/fNjMWjl6vNRhDiN7vpQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@jest/test-result": "^27.5.1", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^27.5.1", + "jest-runtime": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jest/transform": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-27.5.1.tgz", + "integrity": "sha512-ipON6WtYgl/1329g5AIJVbUuEh0wZVbdpGwC99Jw4LwuoBNS95MVphU6zOeD9pDkon+LLbFL7lOQRapbB8SCHw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/core": "^7.1.0", + "@jest/types": "^27.5.1", + "babel-plugin-istanbul": "^6.1.1", + "chalk": "^4.0.0", + "convert-source-map": "^1.4.0", + "fast-json-stable-stringify": "^2.0.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^27.5.1", + "jest-regex-util": "^27.5.1", + "jest-util": "^27.5.1", + "micromatch": "^4.0.4", + "pirates": "^4.0.4", + "slash": "^3.0.0", + "source-map": "^0.6.1", + "write-file-atomic": "^3.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jest/transform/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@jest/transform/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@jest/transform/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/@jest/transform/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/@jest/transform/node_modules/convert-source-map": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/@jest/transform/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/transform/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/types": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", + "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jest/types/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@jest/types/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@jest/types/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/@jest/types/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/@jest/types/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/types/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jimp/bmp": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/@jimp/bmp/-/bmp-0.10.3.tgz", + "integrity": "sha512-keMOc5woiDmONXsB/6aXLR4Z5Q+v8lFq3EY2rcj2FmstbDMhRuGbmcBxlEgOqfRjwvtf/wOtJ3Of37oAWtVfLg==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.7.2", + "@jimp/utils": "^0.10.3", + "bmp-js": "^0.1.0", + "core-js": "^3.4.1" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" + } + }, + "node_modules/@jimp/core": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/@jimp/core/-/core-0.10.3.tgz", + "integrity": "sha512-Gd5IpL3U2bFIO57Fh/OA3HCpWm4uW/pU01E75rI03BXfTdz3T+J7TwvyG1XaqsQ7/DSlS99GXtLQPlfFIe28UA==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.7.2", + "@jimp/utils": "^0.10.3", + "any-base": "^1.1.0", + "buffer": "^5.2.0", + "core-js": "^3.4.1", + "exif-parser": "^0.1.12", + "file-type": "^9.0.0", + "load-bmfont": "^1.3.1", + "mkdirp": "^0.5.1", + "phin": "^2.9.1", + "pixelmatch": "^4.0.2", + "tinycolor2": "^1.4.1" + } + }, + "node_modules/@jimp/custom": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/@jimp/custom/-/custom-0.10.3.tgz", + "integrity": "sha512-nZmSI+jwTi5IRyNLbKSXQovoeqsw+D0Jn0SxW08wYQvdkiWA8bTlDQFgQ7HVwCAKBm8oKkDB/ZEo9qvHJ+1gAQ==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.7.2", + "@jimp/core": "^0.10.3", + "core-js": "^3.4.1" + } + }, + "node_modules/@jimp/gif": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/@jimp/gif/-/gif-0.10.3.tgz", + "integrity": "sha512-vjlRodSfz1CrUvvrnUuD/DsLK1GHB/yDZXHthVdZu23zYJIW7/WrIiD1IgQ5wOMV7NocfrvPn2iqUfBP81/WWA==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.7.2", + "@jimp/utils": "^0.10.3", + "core-js": "^3.4.1", + "omggif": "^1.0.9" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" + } + }, + "node_modules/@jimp/jpeg": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/@jimp/jpeg/-/jpeg-0.10.3.tgz", + "integrity": "sha512-AAANwgUZOt6f6P7LZxY9lyJ9xclqutYJlsxt3JbriXUGJgrrFAIkcKcqv1nObgmQASSAQKYaMV9KdHjMlWFKlQ==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.7.2", + "@jimp/utils": "^0.10.3", + "core-js": "^3.4.1", + "jpeg-js": "^0.3.4" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" + } + }, + "node_modules/@jimp/plugin-blit": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/@jimp/plugin-blit/-/plugin-blit-0.10.3.tgz", + "integrity": "sha512-5zlKlCfx4JWw9qUVC7GI4DzXyxDWyFvgZLaoGFoT00mlXlN75SarlDwc9iZ/2e2kp4bJWxz3cGgG4G/WXrbg3Q==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.7.2", + "@jimp/utils": "^0.10.3", + "core-js": "^3.4.1" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" + } + }, + "node_modules/@jimp/plugin-blur": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/@jimp/plugin-blur/-/plugin-blur-0.10.3.tgz", + "integrity": "sha512-cTOK3rjh1Yjh23jSfA6EHCHjsPJDEGLC8K2y9gM7dnTUK1y9NNmkFS23uHpyjgsWFIoH9oRh2SpEs3INjCpZhQ==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.7.2", + "@jimp/utils": "^0.10.3", + "core-js": "^3.4.1" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" + } + }, + "node_modules/@jimp/plugin-circle": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/@jimp/plugin-circle/-/plugin-circle-0.10.3.tgz", + "integrity": "sha512-51GAPIVelqAcfuUpaM5JWJ0iWl4vEjNXB7p4P7SX5udugK5bxXUjO6KA2qgWmdpHuCKtoNgkzWU9fNSuYp7tCA==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.7.2", + "@jimp/utils": "^0.10.3", + "core-js": "^3.4.1" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" + } + }, + "node_modules/@jimp/plugin-color": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/@jimp/plugin-color/-/plugin-color-0.10.3.tgz", + "integrity": "sha512-RgeHUElmlTH7vpI4WyQrz6u59spiKfVQbsG/XUzfWGamFSixa24ZDwX/yV/Ts+eNaz7pZeIuv533qmKPvw2ujg==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.7.2", + "@jimp/utils": "^0.10.3", + "core-js": "^3.4.1", + "tinycolor2": "^1.4.1" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" + } + }, + "node_modules/@jimp/plugin-contain": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/@jimp/plugin-contain/-/plugin-contain-0.10.3.tgz", + "integrity": "sha512-bYJKW9dqzcB0Ihc6u7jSyKa3juStzbLs2LFr6fu8TzA2WkMS/R8h+ddkiO36+F9ILTWHP0CIA3HFe5OdOGcigw==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.7.2", + "@jimp/utils": "^0.10.3", + "core-js": "^3.4.1" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5", + "@jimp/plugin-blit": ">=0.3.5", + "@jimp/plugin-resize": ">=0.3.5", + "@jimp/plugin-scale": ">=0.3.5" + } + }, + "node_modules/@jimp/plugin-cover": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/@jimp/plugin-cover/-/plugin-cover-0.10.3.tgz", + "integrity": "sha512-pOxu0cM0BRPzdV468n4dMocJXoMbTnARDY/EpC3ZW15SpMuc/dr1KhWQHgoQX5kVW1Wt8zgqREAJJCQ5KuPKDA==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.7.2", + "@jimp/utils": "^0.10.3", + "core-js": "^3.4.1" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5", + "@jimp/plugin-crop": ">=0.3.5", + "@jimp/plugin-resize": ">=0.3.5", + "@jimp/plugin-scale": ">=0.3.5" + } + }, + "node_modules/@jimp/plugin-crop": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/@jimp/plugin-crop/-/plugin-crop-0.10.3.tgz", + "integrity": "sha512-nB7HgOjjl9PgdHr076xZ3Sr6qHYzeBYBs9qvs3tfEEUeYMNnvzgCCGtUl6eMakazZFCMk3mhKmcB9zQuHFOvkg==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.7.2", + "@jimp/utils": "^0.10.3", + "core-js": "^3.4.1" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" + } + }, + "node_modules/@jimp/plugin-displace": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/@jimp/plugin-displace/-/plugin-displace-0.10.3.tgz", + "integrity": "sha512-8t3fVKCH5IVqI4lewe4lFFjpxxr69SQCz5/tlpDLQZsrNScNJivHdQ09zljTrVTCSgeCqQJIKgH2Q7Sk/pAZ0w==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.7.2", + "@jimp/utils": "^0.10.3", + "core-js": "^3.4.1" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" + } + }, + "node_modules/@jimp/plugin-dither": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/@jimp/plugin-dither/-/plugin-dither-0.10.3.tgz", + "integrity": "sha512-JCX/oNSnEg1kGQ8ffZ66bEgQOLCY3Rn+lrd6v1jjLy/mn9YVZTMsxLtGCXpiCDC2wG/KTmi4862ysmP9do9dAQ==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.7.2", + "@jimp/utils": "^0.10.3", + "core-js": "^3.4.1" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" + } + }, + "node_modules/@jimp/plugin-fisheye": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/@jimp/plugin-fisheye/-/plugin-fisheye-0.10.3.tgz", + "integrity": "sha512-RRZb1wqe+xdocGcFtj2xHU7sF7xmEZmIa6BmrfSchjyA2b32TGPWKnP3qyj7p6LWEsXn+19hRYbjfyzyebPElQ==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.7.2", + "@jimp/utils": "^0.10.3", + "core-js": "^3.4.1" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" + } + }, + "node_modules/@jimp/plugin-flip": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/@jimp/plugin-flip/-/plugin-flip-0.10.3.tgz", + "integrity": "sha512-0epbi8XEzp0wmSjoW9IB0iMu0yNF17aZOxLdURCN3Zr+8nWPs5VNIMqSVa1Y62GSyiMDpVpKF/ITiXre+EqrPg==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.7.2", + "@jimp/utils": "^0.10.3", + "core-js": "^3.4.1" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5", + "@jimp/plugin-rotate": ">=0.3.5" + } + }, + "node_modules/@jimp/plugin-gaussian": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/@jimp/plugin-gaussian/-/plugin-gaussian-0.10.3.tgz", + "integrity": "sha512-25eHlFbHUDnMMGpgRBBeQ2AMI4wsqCg46sue0KklI+c2BaZ+dGXmJA5uT8RTOrt64/K9Wz5E+2n7eBnny4dfpQ==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.7.2", + "@jimp/utils": "^0.10.3", + "core-js": "^3.4.1" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" + } + }, + "node_modules/@jimp/plugin-invert": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/@jimp/plugin-invert/-/plugin-invert-0.10.3.tgz", + "integrity": "sha512-effYSApWY/FbtlzqsKXlTLkgloKUiHBKjkQnqh5RL4oQxh/33j6aX+HFdDyQKtsXb8CMd4xd7wyiD2YYabTa0g==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.7.2", + "@jimp/utils": "^0.10.3", + "core-js": "^3.4.1" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" + } + }, + "node_modules/@jimp/plugin-mask": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/@jimp/plugin-mask/-/plugin-mask-0.10.3.tgz", + "integrity": "sha512-twrg8q8TIhM9Z6Jcu9/5f+OCAPaECb0eKrrbbIajJqJ3bCUlj5zbfgIhiQIzjPJ6KjpnFPSqHQfHkU1Vvk/nVw==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.7.2", + "@jimp/utils": "^0.10.3", + "core-js": "^3.4.1" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" + } + }, + "node_modules/@jimp/plugin-normalize": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/@jimp/plugin-normalize/-/plugin-normalize-0.10.3.tgz", + "integrity": "sha512-xkb5eZI/mMlbwKkDN79+1/t/+DBo8bBXZUMsT4gkFgMRKNRZ6NQPxlv1d3QpRzlocsl6UMxrHnhgnXdLAcgrXw==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.7.2", + "@jimp/utils": "^0.10.3", + "core-js": "^3.4.1" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" + } + }, + "node_modules/@jimp/plugin-print": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/@jimp/plugin-print/-/plugin-print-0.10.3.tgz", + "integrity": "sha512-wjRiI6yjXsAgMe6kVjizP+RgleUCLkH256dskjoNvJzmzbEfO7xQw9g6M02VET+emnbY0CO83IkrGm2q43VRyg==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.7.2", + "@jimp/utils": "^0.10.3", + "core-js": "^3.4.1", + "load-bmfont": "^1.4.0" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5", + "@jimp/plugin-blit": ">=0.3.5" + } + }, + "node_modules/@jimp/plugin-resize": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/@jimp/plugin-resize/-/plugin-resize-0.10.3.tgz", + "integrity": "sha512-rf8YmEB1d7Sg+g4LpqF0Mp+dfXfb6JFJkwlAIWPUOR7lGsPWALavEwTW91c0etEdnp0+JB9AFpy6zqq7Lwkq6w==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.7.2", + "@jimp/utils": "^0.10.3", + "core-js": "^3.4.1" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" + } + }, + "node_modules/@jimp/plugin-rotate": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/@jimp/plugin-rotate/-/plugin-rotate-0.10.3.tgz", + "integrity": "sha512-YXLlRjm18fkW9MOHUaVAxWjvgZM851ofOipytz5FyKp4KZWDLk+dZK1JNmVmK7MyVmAzZ5jsgSLhIgj+GgN0Eg==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.7.2", + "@jimp/utils": "^0.10.3", + "core-js": "^3.4.1" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5", + "@jimp/plugin-blit": ">=0.3.5", + "@jimp/plugin-crop": ">=0.3.5", + "@jimp/plugin-resize": ">=0.3.5" + } + }, + "node_modules/@jimp/plugin-scale": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/@jimp/plugin-scale/-/plugin-scale-0.10.3.tgz", + "integrity": "sha512-5DXD7x7WVcX1gUgnlFXQa8F+Q3ThRYwJm+aesgrYvDOY+xzRoRSdQvhmdd4JEEue3lyX44DvBSgCIHPtGcEPaw==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.7.2", + "@jimp/utils": "^0.10.3", + "core-js": "^3.4.1" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5", + "@jimp/plugin-resize": ">=0.3.5" + } + }, + "node_modules/@jimp/plugin-shadow": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/@jimp/plugin-shadow/-/plugin-shadow-0.10.3.tgz", + "integrity": "sha512-/nkFXpt2zVcdP4ETdkAUL0fSzyrC5ZFxdcphbYBodqD7fXNqChS/Un1eD4xCXWEpW8cnG9dixZgQgStjywH0Mg==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.7.2", + "@jimp/utils": "^0.10.3", + "core-js": "^3.4.1" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5", + "@jimp/plugin-blur": ">=0.3.5", + "@jimp/plugin-resize": ">=0.3.5" + } + }, + "node_modules/@jimp/plugin-threshold": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/@jimp/plugin-threshold/-/plugin-threshold-0.10.3.tgz", + "integrity": "sha512-Dzh0Yq2wXP2SOnxcbbiyA4LJ2luwrdf1MghNIt9H+NX7B+IWw/N8qA2GuSm9n4BPGSLluuhdAWJqHcTiREriVA==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.7.2", + "@jimp/utils": "^0.10.3", + "core-js": "^3.4.1" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5", + "@jimp/plugin-color": ">=0.8.0", + "@jimp/plugin-resize": ">=0.8.0" + } + }, + "node_modules/@jimp/plugins": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/@jimp/plugins/-/plugins-0.10.3.tgz", + "integrity": "sha512-jTT3/7hOScf0EIKiAXmxwayHhryhc1wWuIe3FrchjDjr9wgIGNN2a7XwCgPl3fML17DXK1x8EzDneCdh261bkw==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.7.2", + "@jimp/plugin-blit": "^0.10.3", + "@jimp/plugin-blur": "^0.10.3", + "@jimp/plugin-circle": "^0.10.3", + "@jimp/plugin-color": "^0.10.3", + "@jimp/plugin-contain": "^0.10.3", + "@jimp/plugin-cover": "^0.10.3", + "@jimp/plugin-crop": "^0.10.3", + "@jimp/plugin-displace": "^0.10.3", + "@jimp/plugin-dither": "^0.10.3", + "@jimp/plugin-fisheye": "^0.10.3", + "@jimp/plugin-flip": "^0.10.3", + "@jimp/plugin-gaussian": "^0.10.3", + "@jimp/plugin-invert": "^0.10.3", + "@jimp/plugin-mask": "^0.10.3", + "@jimp/plugin-normalize": "^0.10.3", + "@jimp/plugin-print": "^0.10.3", + "@jimp/plugin-resize": "^0.10.3", + "@jimp/plugin-rotate": "^0.10.3", + "@jimp/plugin-scale": "^0.10.3", + "@jimp/plugin-shadow": "^0.10.3", + "@jimp/plugin-threshold": "^0.10.3", + "core-js": "^3.4.1", + "timm": "^1.6.1" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" + } + }, + "node_modules/@jimp/png": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/@jimp/png/-/png-0.10.3.tgz", + "integrity": "sha512-YKqk/dkl+nGZxSYIDQrqhmaP8tC3IK8H7dFPnnzFVvbhDnyYunqBZZO3SaZUKTichClRw8k/CjBhbc+hifSGWg==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.7.2", + "@jimp/utils": "^0.10.3", + "core-js": "^3.4.1", + "pngjs": "^3.3.3" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" + } + }, + "node_modules/@jimp/tiff": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/@jimp/tiff/-/tiff-0.10.3.tgz", + "integrity": "sha512-7EsJzZ5Y/EtinkBGuwX3Bi4S+zgbKouxjt9c82VJTRJOQgLWsE/RHqcyRCOQBhHAZ9QexYmDz34medfLKdoX0g==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.7.2", + "core-js": "^3.4.1", + "utif": "^2.0.1" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" + } + }, + "node_modules/@jimp/types": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/@jimp/types/-/types-0.10.3.tgz", + "integrity": "sha512-XGmBakiHZqseSWr/puGN+CHzx0IKBSpsKlmEmsNV96HKDiP6eu8NSnwdGCEq2mmIHe0JNcg1hqg59hpwtQ7Tiw==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.7.2", + "@jimp/bmp": "^0.10.3", + "@jimp/gif": "^0.10.3", + "@jimp/jpeg": "^0.10.3", + "@jimp/png": "^0.10.3", + "@jimp/tiff": "^0.10.3", + "core-js": "^3.4.1", + "timm": "^1.6.1" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" + } + }, + "node_modules/@jimp/utils": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/@jimp/utils/-/utils-0.10.3.tgz", + "integrity": "sha512-VcSlQhkil4ReYmg1KkN+WqHyYfZ2XfZxDsKAHSfST1GEz/RQHxKZbX+KhFKtKflnL0F4e6DlNQj3vznMNXCR2w==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.7.2", + "core-js": "^3.4.1", + "regenerator-runtime": "^0.13.3" + } + }, + "node_modules/@jimp/utils/node_modules/regenerator-runtime": { + "version": "0.13.11", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", + "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==", + "license": "MIT" + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/source-map": { + "version": "0.3.11", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.11.tgz", + "integrity": "sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@parcel/watcher": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.5.6.tgz", + "integrity": "sha512-tmmZ3lQxAe/k/+rNnXQRawJ4NjxO2hqiOLTHvWchtGZULp4RyFeh6aU4XdOYBFe2KE1oShQTv4AblOs2iOrNnQ==", + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "dependencies": { + "detect-libc": "^2.0.3", + "is-glob": "^4.0.3", + "node-addon-api": "^7.0.0", + "picomatch": "^4.0.3" + }, + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "@parcel/watcher-android-arm64": "2.5.6", + "@parcel/watcher-darwin-arm64": "2.5.6", + "@parcel/watcher-darwin-x64": "2.5.6", + "@parcel/watcher-freebsd-x64": "2.5.6", + "@parcel/watcher-linux-arm-glibc": "2.5.6", + "@parcel/watcher-linux-arm-musl": "2.5.6", + "@parcel/watcher-linux-arm64-glibc": "2.5.6", + "@parcel/watcher-linux-arm64-musl": "2.5.6", + "@parcel/watcher-linux-x64-glibc": "2.5.6", + "@parcel/watcher-linux-x64-musl": "2.5.6", + "@parcel/watcher-win32-arm64": "2.5.6", + "@parcel/watcher-win32-ia32": "2.5.6", + "@parcel/watcher-win32-x64": "2.5.6" + } + }, + "node_modules/@parcel/watcher-android-arm64": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.5.6.tgz", + "integrity": "sha512-YQxSS34tPF/6ZG7r/Ih9xy+kP/WwediEUsqmtf0cuCV5TPPKw/PQHRhueUo6JdeFJaqV3pyjm0GdYjZotbRt/A==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-darwin-arm64": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.5.6.tgz", + "integrity": "sha512-Z2ZdrnwyXvvvdtRHLmM4knydIdU9adO3D4n/0cVipF3rRiwP+3/sfzpAwA/qKFL6i1ModaabkU7IbpeMBgiVEA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-darwin-x64": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.5.6.tgz", + "integrity": "sha512-HgvOf3W9dhithcwOWX9uDZyn1lW9R+7tPZ4sug+NGrGIo4Rk1hAXLEbcH1TQSqxts0NYXXlOWqVpvS1SFS4fRg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-freebsd-x64": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.5.6.tgz", + "integrity": "sha512-vJVi8yd/qzJxEKHkeemh7w3YAn6RJCtYlE4HPMoVnCpIXEzSrxErBW5SJBgKLbXU3WdIpkjBTeUNtyBVn8TRng==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm-glibc": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.5.6.tgz", + "integrity": "sha512-9JiYfB6h6BgV50CCfasfLf/uvOcJskMSwcdH1PHH9rvS1IrNy8zad6IUVPVUfmXr+u+Km9IxcfMLzgdOudz9EQ==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm-musl": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.5.6.tgz", + "integrity": "sha512-Ve3gUCG57nuUUSyjBq/MAM0CzArtuIOxsBdQ+ftz6ho8n7s1i9E1Nmk/xmP323r2YL0SONs1EuwqBp2u1k5fxg==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm64-glibc": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.5.6.tgz", + "integrity": "sha512-f2g/DT3NhGPdBmMWYoxixqYr3v/UXcmLOYy16Bx0TM20Tchduwr4EaCbmxh1321TABqPGDpS8D/ggOTaljijOA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm64-musl": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.5.6.tgz", + "integrity": "sha512-qb6naMDGlbCwdhLj6hgoVKJl2odL34z2sqkC7Z6kzir8b5W65WYDpLB6R06KabvZdgoHI/zxke4b3zR0wAbDTA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-x64-glibc": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.5.6.tgz", + "integrity": "sha512-kbT5wvNQlx7NaGjzPFu8nVIW1rWqV780O7ZtkjuWaPUgpv2NMFpjYERVi0UYj1msZNyCzGlaCWEtzc+exjMGbQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-x64-musl": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.5.6.tgz", + "integrity": "sha512-1JRFeC+h7RdXwldHzTsmdtYR/Ku8SylLgTU/reMuqdVD7CtLwf0VR1FqeprZ0eHQkO0vqsbvFLXUmYm/uNKJBg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-win32-arm64": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.5.6.tgz", + "integrity": "sha512-3ukyebjc6eGlw9yRt678DxVF7rjXatWiHvTXqphZLvo7aC5NdEgFufVwjFfY51ijYEWpXbqF5jtrK275z52D4Q==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-win32-ia32": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.5.6.tgz", + "integrity": "sha512-k35yLp1ZMwwee3Ez/pxBi5cf4AoBKYXj00CZ80jUz5h8prpiaQsiRPKQMxoLstNuqe2vR4RNPEAEcjEFzhEz/g==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-win32-x64": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.5.6.tgz", + "integrity": "sha512-hbQlYcCq5dlAX9Qx+kFb0FHue6vbjlf0FrNzSKdYK2APUf7tGfGxQCk2ihEREmbR6ZMc0MVAD5RIX/41gpUzTw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher/node_modules/picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/@rollup/pluginutils": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.1.0.tgz", + "integrity": "sha512-XTIWOPPcpvyKI6L1NHo0lFlCyznUEyPmPY1mc3KpPVDYulHSTvyeLNVW00QTLIAFNhR3kYnJTQHeGqU4M3n09g==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "estree-walker": "^2.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.62.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.62.0.tgz", + "integrity": "sha512-IPIQ55ythEHkfEd9jMEi32OQ7SxURsGA43JI22lj01OLZNt2NUbJX8YUHxkVWyQ6daHPNn0truF5nSj3DQp6YQ==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.62.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.62.0.tgz", + "integrity": "sha512-M6s9cr10MibETyo8JsOkq+Lo1+lU6hcvb1MApnUql5qte/5hMEgzlN8/ReIKNfRV8rrqX50W1BX9zoUhC192RA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.62.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.62.0.tgz", + "integrity": "sha512-BqCoMoIbn0keKys+dEAdBa70EtOwV1bEsQCUgU9FdiZmmMge/Zk7LlkYGqbrdHR+Frnt0E1FOanly+rlwvvQzw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.62.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.62.0.tgz", + "integrity": "sha512-SIMzST3VFNXDAbeIWDWiFCNM5qncUBDWaEV7NfE7oZbDt2mgfW4MvbKdbYiGOLoM32gbTv608UMd0XktEYSD7w==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.62.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.62.0.tgz", + "integrity": "sha512-ezjfSQMP7ArdUsbBwbQIfwAlhE84I2iVnzQNCFSveqV42q+BmKlzVpf7mxv5EchLcoWU4y6/heFzVg1F+hodUQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.62.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.62.0.tgz", + "integrity": "sha512-9+qTWGW9AZRhnUgwtTwzNwcPlL87ngkeN0LA+q1bADvmY9aNvWaF2TFW8BZgnQPYxpDI7+rMVLivcd4V737TAQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.62.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.62.0.tgz", + "integrity": "sha512-T1dMEQhXA/jkJ/jyMIw9IovK8bSUq7A8kLIlvZTb/6YIVsp2zLavr4F3oyllHWo7eIVJRyE5n3tUjQJEbE1IuQ==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.62.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.62.0.tgz", + "integrity": "sha512-2as0LgT7qQpyceQq6VUJYnumUMUrgGQCWIiDIN9DE0/tglsk6o66uCB4f3djRawAltvfCNLyZZrsqbPA6inCsA==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.62.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.62.0.tgz", + "integrity": "sha512-bVURMg+6eNN9C/yc0aVjooZcwTTtYF4YW3xta5pP0//r3o1V8gXEHXWCndj47w/HhwsFroZrFhR+6uQP5T0n0g==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.62.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.62.0.tgz", + "integrity": "sha512-Ful8pM/2yYI83PViWdFdpZhdI8HJ5qsXANe5atypbHDf+KIBBDsZsbyy8hbXnULVvW9NsTh5DHwbcBftyLTfiw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.62.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.62.0.tgz", + "integrity": "sha512-9Gp/DgrkzfUBmNPVTyPTvay+4xEP7M/clXpj3efXBcm6uTIVIgDg4rqUpqKXvLEuFRVuEpSAOkhgNeecvaZ4Cg==", + "cpu": [ + "loong64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-musl": { + "version": "4.62.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.62.0.tgz", + "integrity": "sha512-m9tsJz54LUXkSYM8+8PG81B9IKK5r+2T0clMq4QrS16xFosufU7firBDAZEsDheDs7wTlP7h3++S7lMsU955HA==", + "cpu": [ + "loong64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.62.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.62.0.tgz", + "integrity": "sha512-3UvJ5PNVU16aJf6M3tFI24pWzAl2/ynfbyRN3ICyQajK1lSkrnVYNnLz3v04J32qKa0FczJc22zeToc0lr2A3w==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-musl": { + "version": "4.62.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.62.0.tgz", + "integrity": "sha512-vRWUAbYLGHBZS6Q8Msb2sfnf1fvJf+47t8l/TwOerM2qArzy+IeNMTHrYLHXh95h8MoatPHI5hhSZNs+mGXKPg==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.62.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.62.0.tgz", + "integrity": "sha512-c00T5SYENHAt86cfW47URaP3Us5vLC/4QO7GYud1G5VNRffCwwCuBspwqYrriuJB+5m0WFzClCn9wed0FBjKvg==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.62.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.62.0.tgz", + "integrity": "sha512-krrCDilhXOwFkSkO3Wm9I/f9H0L92XHHwy2fwxjukxIbh0dem8gZqOW5Y8BsHrpJv5qwlRBV+Wl4ZFyRWhUpwg==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.62.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.62.0.tgz", + "integrity": "sha512-7pfYFSTc4/rUC/FtAI0Qp6QthDBCIi6/AuP1xYqFk5vanI6KnL5dWKP60OM/05LOsbwTmIcvr6eXC4CJuJ75IA==", + "cpu": [ + "s390x" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.62.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.62.0.tgz", + "integrity": "sha512-7SDIalKeIpG0Ifogbbdn58HmSotYMlf23K3dCJEmiVd9Fg36Vmni82iPQec27N3wY4Bvbxftkxz6vSx9OcouTg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.62.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.62.0.tgz", + "integrity": "sha512-eRZevouTH2i1HeAVLqJuLnt256krQkGY0TN6WsTmsIhuzbh457HuWDMakKwmi0Cjadux983CoSr8Lim2QhUIFw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-openbsd-x64": { + "version": "4.62.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.62.0.tgz", + "integrity": "sha512-3oVS7FLGa4U1qcvao9ylGxrjXZyUQqR8UwxEcnUEyPX53O/C/mKDZegNXTdHCP+h3e6ta/f1EN38Yif1mmZHYg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ] + }, + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.62.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.62.0.tgz", + "integrity": "sha512-yTB9TgfWj5wHe5QgktAgXTLLot1gvEjl1NiPPAUiCs4oPrIWFl5V4nC3GrkNdj9LaAU4s94nVrGbGOCqUpyWsg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.62.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.62.0.tgz", + "integrity": "sha512-5LOhoaesY3doG1c+ac/2JtgREpKoJr5bUHH8tKY0V8di7+uSV6BwLs2PlR0/yzefGOkR+wE7ZolZphHCsyG5Rw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.62.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.62.0.tgz", + "integrity": "sha512-yYkWHhmbhRTWTnWos5HC4GcPQfjlzzCNbM9e/+GXrLuaBXYA3qSDR9f0Vgufd5S8yX81U8jPKp7ZnAjZFMtRnw==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.62.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.62.0.tgz", + "integrity": "sha512-SoTb6lPg25xZlA2ibwQ++ahCCnH+FP0qmEuafMJ4gznZKOlXioKEAeJLgCrqjM98ACziXM9V1amFjICVL4IFoA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.62.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.62.0.tgz", + "integrity": "sha512-5L+T1fMX4RIEBoZzT0+sQ0PhTS36NULFmMXtl1TZo44TMAROIMHbZufSOjVWt/Y622BtxgxtaNOokbTDvfsrZA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@sinonjs/commons": { + "version": "1.8.6", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.6.tgz", + "integrity": "sha512-Ky+XkAkqPZSm3NLBeUng77EBQl3cmeJhITaGHdYH8kjVB+aun3S4XBRti2zt17mtt0mIUDiNxYeoJm6drVvBJQ==", + "dev": true, + "license": "BSD-3-Clause", + "peer": true, + "dependencies": { + "type-detect": "4.0.8" + } + }, + "node_modules/@sinonjs/fake-timers": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-8.1.0.tgz", + "integrity": "sha512-OAPJUAtgeINhh/TAlUID4QTs53Njm7xzddaVlEs/SXwgtiD1tW22zAB/W1wdqfrpmikgaWQ9Fw6Ws+hsiRm5Vg==", + "dev": true, + "license": "BSD-3-Clause", + "peer": true, + "dependencies": { + "@sinonjs/commons": "^1.7.0" + } + }, + "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==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/@types/babel__core": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", + "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.27.0", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz", + "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", + "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz", + "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/types": "^7.28.2" + } + }, + "node_modules/@types/babel__traverse/node_modules/@babel/types": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.7.tgz", + "integrity": "sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/helper-string-parser": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@types/estree": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz", + "integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==", + "license": "MIT" + }, + "node_modules/@types/graceful-fs": { + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.9.tgz", + "integrity": "sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/istanbul-lib-coverage": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", + "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/@types/istanbul-lib-report": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz", + "integrity": "sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@types/istanbul-lib-coverage": "*" + } + }, + "node_modules/@types/istanbul-reports": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz", + "integrity": "sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@types/istanbul-lib-report": "*" + } + }, + "node_modules/@types/node": { + "version": "25.9.3", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.9.3.tgz", + "integrity": "sha512-603BddQMv3pUcr4U2dhujk83N2tTDVr/34wII2B6bJy6g+8WD6yUb11jszNs0gdi4PesVWl7ABt8nYMVpnLUcg==", + "devOptional": true, + "license": "MIT", + "peer": true, + "dependencies": { + "undici-types": ">=7.24.0 <7.24.7" + } + }, + "node_modules/@types/prettier": { + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.7.3.tgz", + "integrity": "sha512-+68kP9yzs4LMp7VNh8gdzMSPZFL44MLGqiHWvttYJe+6qnuVr4Ek9wSBQoveqY/r+LwjCcU29kNVkidwim+kYA==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/@types/stack-utils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz", + "integrity": "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/@types/yargs": { + "version": "16.0.11", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.11.tgz", + "integrity": "sha512-sbtvk8wDN+JvEdabmZExoW/HNr1cB7D/j4LT08rMiuikfA7m/JNJg7ATQcgzs34zHnoScDkY0ZRSl29Fkmk36g==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@types/yargs-parser": { + "version": "21.0.3", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz", + "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/@vitejs/plugin-legacy": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-legacy/-/plugin-legacy-5.3.2.tgz", + "integrity": "sha512-8moCOrIMaZ/Rjln0Q6GsH6s8fAt1JOI3k8nmfX4tXUxE5KAExVctSyOBk+A25GClsdSWqIk2yaUthH3KJ2X4tg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.23.9", + "@babel/preset-env": "^7.23.9", + "browserslist": "^4.23.0", + "browserslist-to-esbuild": "^2.1.1", + "core-js": "^3.36.0", + "magic-string": "^0.30.7", + "regenerator-runtime": "^0.14.1", + "systemjs": "^6.14.3" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "peerDependencies": { + "terser": "^5.4.0", + "vite": "^5.0.0" + } + }, + "node_modules/@vitejs/plugin-vue": { + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-5.2.4.tgz", + "integrity": "sha512-7Yx/SXSOcQq5HiiV3orevHUFn+pmMB4cgbEkDYgnkUWb0WfeQ/wa2yFv6D5ICiCQOVpjA7vYDXrC7AGO8yjDHA==", + "license": "MIT", + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "peerDependencies": { + "vite": "^5.0.0 || ^6.0.0", + "vue": "^3.2.25" + } + }, + "node_modules/@vitejs/plugin-vue-jsx": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue-jsx/-/plugin-vue-jsx-3.1.0.tgz", + "integrity": "sha512-w9M6F3LSEU5kszVb9An2/MmXNxocAnUb3WhRr8bHlimhDrXNt6n6D2nJQR3UXpGlZHh/EsgouOHCsM8V3Ln+WA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.23.3", + "@babel/plugin-transform-typescript": "^7.23.3", + "@vue/babel-plugin-jsx": "^1.1.5" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "peerDependencies": { + "vite": "^4.0.0 || ^5.0.0", + "vue": "^3.0.0" + } + }, + "node_modules/@vue/babel-helper-vue-transform-on": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@vue/babel-helper-vue-transform-on/-/babel-helper-vue-transform-on-1.5.0.tgz", + "integrity": "sha512-0dAYkerNhhHutHZ34JtTl2czVQHUNWv6xEbkdF5W+Yrv5pCWsqjeORdOgbtW2I9gWlt+wBmVn+ttqN9ZxR5tzA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@vue/babel-plugin-jsx": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@vue/babel-plugin-jsx/-/babel-plugin-jsx-1.5.0.tgz", + "integrity": "sha512-mneBhw1oOqCd2247O0Yw/mRwC9jIGACAJUlawkmMBiNmL4dGA2eMzuNZVNqOUfYTa6vqmND4CtOPzmEEEqLKFw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/plugin-syntax-jsx": "^7.27.1", + "@babel/template": "^7.27.2", + "@babel/traverse": "^7.28.0", + "@babel/types": "^7.28.2", + "@vue/babel-helper-vue-transform-on": "1.5.0", + "@vue/babel-plugin-resolve-type": "1.5.0", + "@vue/shared": "^3.5.18" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + }, + "peerDependenciesMeta": { + "@babel/core": { + "optional": true + } + } + }, + "node_modules/@vue/babel-plugin-jsx/node_modules/@babel/types": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.7.tgz", + "integrity": "sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@vue/babel-plugin-jsx/node_modules/@vue/shared": { + "version": "3.5.38", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.38.tgz", + "integrity": "sha512-FTW0AFZNaK5/mOqvGBwVfUlNLU38TiQn4+DQgIFUnrBBJQ1crMJ82yeGQLV5jyKFsO8yRukpbuP7x+nRbH6aug==", + "dev": true, + "license": "MIT" + }, + "node_modules/@vue/babel-plugin-resolve-type": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@vue/babel-plugin-resolve-type/-/babel-plugin-resolve-type-1.5.0.tgz", + "integrity": "sha512-Wm/60o+53JwJODm4Knz47dxJnLDJ9FnKnGZJbUUf8nQRAtt6P+undLUAVU3Ha33LxOJe6IPoifRQ6F/0RrU31w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@babel/helper-module-imports": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/parser": "^7.28.0", + "@vue/compiler-sfc": "^3.5.18" + }, + "funding": { + "url": "https://github.com/sponsors/sxzz" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@vue/babel-plugin-resolve-type/node_modules/@babel/code-frame": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.7.tgz", + "integrity": "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.29.7", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@vue/babel-plugin-resolve-type/node_modules/@babel/parser": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.7.tgz", + "integrity": "sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.7" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@vue/babel-plugin-resolve-type/node_modules/@babel/types": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.7.tgz", + "integrity": "sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@vue/babel-plugin-resolve-type/node_modules/@vue/compiler-core": { + "version": "3.5.38", + "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.38.tgz", + "integrity": "sha512-s99aGxWYig9ErHbct27KXEGhrBYlRI6c4MwAgXErOAbX9xiW37/uMa+XUDO69zLz83dng8UUZ70CTOJrLrYrEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.29.7", + "@vue/shared": "3.5.38", + "entities": "^7.0.1", + "estree-walker": "^2.0.2", + "source-map-js": "^1.2.1" + } + }, + "node_modules/@vue/babel-plugin-resolve-type/node_modules/@vue/compiler-dom": { + "version": "3.5.38", + "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.38.tgz", + "integrity": "sha512-JTqp25l8aFfJYF7/KmsXZjAxJz7T+SjmTJLoXVjHtc2BrSgSiW2n9Aem/cWq1OPe68A8JL06B3eVdhlP0H4TVw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vue/compiler-core": "3.5.38", + "@vue/shared": "3.5.38" + } + }, + "node_modules/@vue/babel-plugin-resolve-type/node_modules/@vue/compiler-sfc": { + "version": "3.5.38", + "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.38.tgz", + "integrity": "sha512-DuA2GiZawSEW442iw/9+Fkol8hTgb4Ke5KkhmSry65QA7YuyMbIdy8p0XZRMvNwJdgRz307W8g1CSzdvS4nuNg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.29.7", + "@vue/compiler-core": "3.5.38", + "@vue/compiler-dom": "3.5.38", + "@vue/compiler-ssr": "3.5.38", + "@vue/shared": "3.5.38", + "estree-walker": "^2.0.2", + "magic-string": "^0.30.21", + "postcss": "^8.5.15", + "source-map-js": "^1.2.1" + } + }, + "node_modules/@vue/babel-plugin-resolve-type/node_modules/@vue/compiler-ssr": { + "version": "3.5.38", + "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.38.tgz", + "integrity": "sha512-7s+W5Gc42FGxZMcuwl8H5B29T8BJPMdBT7KHFE+BbAuZ/iTEdTtv7z2XiMjiaUUw4w3ZcCEdHs36RuYJ2VA7bA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vue/compiler-dom": "3.5.38", + "@vue/shared": "3.5.38" + } + }, + "node_modules/@vue/babel-plugin-resolve-type/node_modules/@vue/shared": { + "version": "3.5.38", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.38.tgz", + "integrity": "sha512-FTW0AFZNaK5/mOqvGBwVfUlNLU38TiQn4+DQgIFUnrBBJQ1crMJ82yeGQLV5jyKFsO8yRukpbuP7x+nRbH6aug==", + "dev": true, + "license": "MIT" + }, + "node_modules/@vue/babel-plugin-resolve-type/node_modules/magic-string": { + "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, + "node_modules/@vue/babel-plugin-resolve-type/node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/@vue/compiler-core": { + "version": "3.4.21", + "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.4.21.tgz", + "integrity": "sha512-MjXawxZf2SbZszLPYxaFCjxfibYrzr3eYbKxwpLR9EQN+oaziSu3qKVbwBERj1IFIB8OLUewxB5m/BFzi613og==", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.23.9", + "@vue/shared": "3.4.21", + "entities": "^4.5.0", + "estree-walker": "^2.0.2", + "source-map-js": "^1.0.2" + } + }, + "node_modules/@vue/compiler-core/node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/@vue/compiler-dom": { + "version": "3.4.21", + "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.4.21.tgz", + "integrity": "sha512-IZC6FKowtT1sl0CR5DpXSiEB5ayw75oT2bma1BEhV7RRR1+cfwLrxc2Z8Zq/RGFzJ8w5r9QtCOvTjQgdn0IKmA==", + "license": "MIT", + "dependencies": { + "@vue/compiler-core": "3.4.21", + "@vue/shared": "3.4.21" + } + }, + "node_modules/@vue/compiler-sfc": { + "version": "3.4.21", + "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.4.21.tgz", + "integrity": "sha512-me7epoTxYlY+2CUM7hy9PCDdpMPfIwrOvAXud2Upk10g4YLv9UBW7kL798TvMeDhPthkZ0CONNrK2GoeI1ODiQ==", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.23.9", + "@vue/compiler-core": "3.4.21", + "@vue/compiler-dom": "3.4.21", + "@vue/compiler-ssr": "3.4.21", + "@vue/shared": "3.4.21", + "estree-walker": "^2.0.2", + "magic-string": "^0.30.7", + "postcss": "^8.4.35", + "source-map-js": "^1.0.2" + } + }, + "node_modules/@vue/compiler-ssr": { + "version": "3.4.21", + "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.4.21.tgz", + "integrity": "sha512-M5+9nI2lPpAsgXOGQobnIueVqc9sisBFexh5yMIMRAPYLa7+5wEJs8iqOZc1WAa9WQbx9GR2twgznU8LTIiZ4Q==", + "license": "MIT", + "dependencies": { + "@vue/compiler-dom": "3.4.21", + "@vue/shared": "3.4.21" + } + }, + "node_modules/@vue/consolidate": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@vue/consolidate/-/consolidate-1.0.0.tgz", + "integrity": "sha512-oTyUE+QHIzLw2PpV14GD/c7EohDyP64xCniWTcqcEmTd699eFqTIwOmtDYjcO1j3QgdXoJEoWv1/cCdLrRoOfg==", + "license": "MIT", + "engines": { + "node": ">= 0.12.0" + } + }, + "node_modules/@vue/devtools-api": { + "version": "6.6.4", + "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-6.6.4.tgz", + "integrity": "sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g==", + "license": "MIT" + }, + "node_modules/@vue/reactivity": { + "version": "3.5.38", + "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.38.tgz", + "integrity": "sha512-pG6LV/NDNRbKizcUjFFLAfjaL8mcv4DmR9avNcUw2gDHBzZneuS2TWCmp633ynzxz9YYKNeEPK2I8Wraqy2HUQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vue/shared": "3.5.38" + } + }, + "node_modules/@vue/reactivity/node_modules/@vue/shared": { + "version": "3.5.38", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.38.tgz", + "integrity": "sha512-FTW0AFZNaK5/mOqvGBwVfUlNLU38TiQn4+DQgIFUnrBBJQ1crMJ82yeGQLV5jyKFsO8yRukpbuP7x+nRbH6aug==", + "dev": true, + "license": "MIT" + }, + "node_modules/@vue/runtime-core": { + "version": "3.5.38", + "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.38.tgz", + "integrity": "sha512-iyW8WVfF1CpCXxncZY5Ei6rSd6oZr5DgEom//fUjRBRl56AXPD+s9ATvukRt77ZFTuYlnVA1bxY+dJB94tWVYw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vue/reactivity": "3.5.38", + "@vue/shared": "3.5.38" + } + }, + "node_modules/@vue/runtime-core/node_modules/@vue/shared": { + "version": "3.5.38", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.38.tgz", + "integrity": "sha512-FTW0AFZNaK5/mOqvGBwVfUlNLU38TiQn4+DQgIFUnrBBJQ1crMJ82yeGQLV5jyKFsO8yRukpbuP7x+nRbH6aug==", + "dev": true, + "license": "MIT" + }, + "node_modules/@vue/runtime-dom": { + "version": "3.4.21", + "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.4.21.tgz", + "integrity": "sha512-gvf+C9cFpevsQxbkRBS1NpU8CqxKw0ebqMvLwcGQrNpx6gqRDodqKqA+A2VZZpQ9RpK2f9yfg8VbW/EpdFUOJw==", + "license": "MIT", + "dependencies": { + "@vue/runtime-core": "3.4.21", + "@vue/shared": "3.4.21", + "csstype": "^3.1.3" + } + }, + "node_modules/@vue/runtime-dom/node_modules/@vue/reactivity": { + "version": "3.4.21", + "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.4.21.tgz", + "integrity": "sha512-UhenImdc0L0/4ahGCyEzc/pZNwVgcglGy9HVzJ1Bq2Mm9qXOpP8RyNTjookw/gOCUlXSEtuZ2fUg5nrHcoqJcw==", + "license": "MIT", + "dependencies": { + "@vue/shared": "3.4.21" + } + }, + "node_modules/@vue/runtime-dom/node_modules/@vue/runtime-core": { + "version": "3.4.21", + "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.4.21.tgz", + "integrity": "sha512-pQthsuYzE1XcGZznTKn73G0s14eCJcjaLvp3/DKeYWoFacD9glJoqlNBxt3W2c5S40t6CCcpPf+jG01N3ULyrA==", + "license": "MIT", + "dependencies": { + "@vue/reactivity": "3.4.21", + "@vue/shared": "3.4.21" + } + }, + "node_modules/@vue/server-renderer": { + "version": "3.4.21", + "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.4.21.tgz", + "integrity": "sha512-aV1gXyKSN6Rz+6kZ6kr5+Ll14YzmIbeuWe7ryJl5muJ4uwSwY/aStXTixx76TwkZFJLm1aAlA/HSWEJ4EyiMkg==", + "license": "MIT", + "dependencies": { + "@vue/compiler-ssr": "3.4.21", + "@vue/shared": "3.4.21" + }, + "peerDependencies": { + "vue": "3.4.21" + } + }, + "node_modules/@vue/shared": { + "version": "3.4.21", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.4.21.tgz", + "integrity": "sha512-PuJe7vDIi6VYSinuEbUIQgMIRZGgM8e4R+G+/dQTk0X1NEdvgvvgv7m+rfmDH1gZzyA1OjjoWskvHlfRNfQf3g==", + "license": "MIT" + }, + "node_modules/abab": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz", + "integrity": "sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==", + "deprecated": "Use your platform's native atob() and btoa() methods instead", + "dev": true, + "license": "BSD-3-Clause", + "peer": 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==", + "dev": true, + "license": "MIT", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/acorn": { + "version": "8.17.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.17.0.tgz", + "integrity": "sha512-xRQbDb9BnwDafYNn6Vwl839DYVjqXYb1XVGtWAZ1kcDc6iwAL4hg3B1dZlRiuENFeO2H53gFG3in621AdERVAg==", + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-globals": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-6.0.0.tgz", + "integrity": "sha512-ZQl7LOWaF5ePqqcX4hLuv/bLXYQNfNWw2c0/yX/TsPRKamzHcTGQnlCjHT3TsmkOUVEPS3crCxiPfdzE/Trlhg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "acorn": "^7.1.1", + "acorn-walk": "^7.1.1" + } + }, + "node_modules/acorn-globals/node_modules/acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "dev": true, + "license": "MIT", + "peer": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-walk": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz", + "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/address": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/address/-/address-1.2.2.tgz", + "integrity": "sha512-4B/qKCfeE/ODUaAUpSwfzazo5x29WD4r3vXiWsB7I2mSDAihwEqKO+g8GELZUQSSAo5e1XTYh3ZVfLyxBc12nA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/adm-zip": { + "version": "0.5.16", + "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.5.16.tgz", + "integrity": "sha512-TGw5yVi4saajsSEgz25grObGHEUaDrniwvA2qwSC060KfqGPdglhvPMA2lPIoxs3PQIItj2iag35fONcQqgUaQ==", + "license": "MIT", + "engines": { + "node": ">=12.0" + } + }, + "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==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "type-fest": "^0.21.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "license": "MIT", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/any-base": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/any-base/-/any-base-1.1.0.tgz", + "integrity": "sha512-uMgjozySS8adZZYePpaWs8cxB9/kdzmpX6SgJZ+wbz1K5eYk5QMYDVJaZKhxyIHUdnnJkfR7SVgStgH7LkGUyg==", + "license": "MIT" + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "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==", + "dev": true, + "license": "MIT" + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/autoprefixer": { + "version": "10.4.20", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.20.tgz", + "integrity": "sha512-XY25y5xSv/wEoqzDyXXME4AFfkZI0P23z6Fs3YgymDnKJkCGOnkL0iTxCa85UTqaSgfcqyf3UA6+c7wUvx/16g==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/autoprefixer" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "browserslist": "^4.23.3", + "caniuse-lite": "^1.0.30001646", + "fraction.js": "^4.3.7", + "normalize-range": "^0.1.2", + "picocolors": "^1.0.1", + "postcss-value-parser": "^4.2.0" + }, + "bin": { + "autoprefixer": "bin/autoprefixer" + }, + "engines": { + "node": "^10 || ^12 || >=14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/babel-jest": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-27.5.1.tgz", + "integrity": "sha512-cdQ5dXjGRd0IBRATiQ4mZGlGlRE8kJpjPOixdNRdT+m3UcNqmYWN6rK6nvtXYfY3D76cb8s/O1Ss8ea24PIwcg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@jest/transform": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/babel__core": "^7.1.14", + "babel-plugin-istanbul": "^6.1.1", + "babel-preset-jest": "^27.5.1", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "slash": "^3.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.8.0" + } + }, + "node_modules/babel-jest/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/babel-jest/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/babel-jest/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/babel-jest/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/babel-jest/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/babel-jest/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/babel-plugin-istanbul": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", + "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", + "dev": true, + "license": "BSD-3-Clause", + "peer": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-instrument": "^5.0.4", + "test-exclude": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/babel-plugin-jest-hoist": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-27.5.1.tgz", + "integrity": "sha512-50wCwD5EMNW4aRpOwtqzyZHIewTYNxLA4nhB+09d8BIssfNfzBRhkBIHiaPv1Si226TQSvp8gxAJm2iY2qs2hQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/template": "^7.3.3", + "@babel/types": "^7.3.3", + "@types/babel__core": "^7.0.0", + "@types/babel__traverse": "^7.0.6" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/babel-plugin-polyfill-corejs2": { + "version": "0.4.17", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.17.tgz", + "integrity": "sha512-aTyf30K/rqAsNwN76zYrdtx8obu0E4KoUME29B1xj+B3WxgvWkp943vYQ+z8Mv3lw9xHXMHpvSPOBxzAkIa94w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.28.6", + "@babel/helper-define-polyfill-provider": "^0.6.8", + "semver": "^6.3.1" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-polyfill-corejs3": { + "version": "0.14.2", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.14.2.tgz", + "integrity": "sha512-coWpDLJ410R781Npmn/SIBZEsAetR4xVi0SxLMXPaMO4lSf1MwnkGYMtkFxew0Dn8B3/CpbpYxN0JCgg8mn67g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.6.8", + "core-js-compat": "^3.48.0" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-polyfill-regenerator": { + "version": "0.6.8", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.8.tgz", + "integrity": "sha512-M762rNHfSF1EV3SLtnCJXFoQbbIIz0OyRwnCmV0KPC7qosSfCO0QLTSuJX3ayAebubhE6oYBAYPrBA5ljowaZg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.6.8" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-preset-current-node-syntax": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.2.0.tgz", + "integrity": "sha512-E/VlAEzRrsLEb2+dv8yp3bo4scof3l9nR4lrld+Iy5NyVqgVYUJnDAmunkhPMisRI32Qc4iRiz425d8vM++2fg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-bigint": "^7.8.3", + "@babel/plugin-syntax-class-properties": "^7.12.13", + "@babel/plugin-syntax-class-static-block": "^7.14.5", + "@babel/plugin-syntax-import-attributes": "^7.24.7", + "@babel/plugin-syntax-import-meta": "^7.10.4", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.10.4", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5", + "@babel/plugin-syntax-top-level-await": "^7.14.5" + }, + "peerDependencies": { + "@babel/core": "^7.0.0 || ^8.0.0-0" + } + }, + "node_modules/babel-preset-jest": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-27.5.1.tgz", + "integrity": "sha512-Nptf2FzlPCWYuJg41HBqXVT8ym6bXOevuCTbhxlUpjwtysGaIWFvDEjp4y+G7fl13FgOdjs7P/DmErqH7da0Ag==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "babel-plugin-jest-hoist": "^27.5.1", + "babel-preset-current-node-syntax": "^1.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT", + "peer": 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/base64url": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/base64url/-/base64url-3.0.1.tgz", + "integrity": "sha512-ir1UPr3dkwexU7FdV8qBBbNDRUhMmIekYMFZfi+C/sLNnRESKPl23nB9b2pltqfOQNnGzsDdId90AEtG5tCx4A==", + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/baseline-browser-mapping": { + "version": "2.10.37", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.37.tgz", + "integrity": "sha512-girxaJ7WZssDOFhzCGZTDKoTa1gk6A1TbflaYTpykLJ4UU9Fz9kx1aREM8JCuoVHbL8X8T/mJg7w2oYSq72Oig==", + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.cjs" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/bmp-js": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/bmp-js/-/bmp-js-0.1.0.tgz", + "integrity": "sha512-vHdS19CnY3hwiNdkaqk93DvjVLfbEcI8mys4UjuWrlX1haDmroo8o4xCzh4wD6DGV6HxRCyauwhHRqMTfERtjw==", + "license": "MIT" + }, + "node_modules/body-parser": { + "version": "1.20.3", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", + "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==", + "dev": true, + "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.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.13.0", + "raw-body": "2.5.2", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/body-parser/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/body-parser/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true, + "license": "MIT" + }, + "node_modules/body-parser/node_modules/qs": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", + "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "side-channel": "^1.0.6" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.15.tgz", + "integrity": "sha512-EwOCDEex4quD37XhqM3omwtMoJjr//isUZz1JopUNWms+4Z2ViyM/k1YIRePpoVNnQhENnxtFjLaxNHrT7xIUg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browser-process-hrtime": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz", + "integrity": "sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==", + "dev": true, + "license": "BSD-2-Clause", + "peer": true + }, + "node_modules/browserslist": { + "version": "4.28.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.2.tgz", + "integrity": "sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "baseline-browser-mapping": "^2.10.12", + "caniuse-lite": "^1.0.30001782", + "electron-to-chromium": "^1.5.328", + "node-releases": "^2.0.36", + "update-browserslist-db": "^1.2.3" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/browserslist-to-esbuild": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/browserslist-to-esbuild/-/browserslist-to-esbuild-2.1.1.tgz", + "integrity": "sha512-KN+mty6C3e9AN8Z5dI1xeN15ExcRNeISoC3g7V0Kax/MMF9MSoYA2G7lkTTcVUFntiEjkpI0HNgqJC1NjdyNUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "meow": "^13.0.0" + }, + "bin": { + "browserslist-to-esbuild": "cli/index.js" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "browserslist": "*" + } + }, + "node_modules/bser": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", + "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", + "dev": true, + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "node-int64": "^0.4.0" + } + }, + "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": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal/-/buffer-equal-0.0.1.tgz", + "integrity": "sha512-RgSV6InVQ9ODPdLWJ5UAqBqJBOg370Nz6ZQtRzpt6nUjc8v0St97uJ4PYC6NztqIScrAXafKM3mZPMygSe1ggA==", + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/cac": { + "version": "6.7.9", + "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.9.tgz", + "integrity": "sha512-XN5qEpfNQCJ8jRaZgitSkkukjMRCGio+X3Ks5KUbGGlPbV+pSem1l9VuzooCBXOiMFshUZgyYqg6rgN8rjkb/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "dev": true, + "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==", + "dev": true, + "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/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001799", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001799.tgz", + "integrity": "sha512-hG1bReV+OUU+MOqK4t/ZWI0tZOyz3rqS9XuhOUz1cIcbwBKjOyJEJuw9ER5JuNyqxNk8u/JUVbGibBOL1yrjFw==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/centra": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/centra/-/centra-2.7.0.tgz", + "integrity": "sha512-PbFMgMSrmgx6uxCdm57RUos9Tc3fclMvhLSATYN39XsDV29B89zZ3KA89jmY0vwSGazyU+uerqwa6t+KaodPcg==", + "license": "MIT", + "dependencies": { + "follow-redirects": "^1.15.6" + } + }, + "node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/char-regex": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", + "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "license": "MIT", + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/ci-info": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", + "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "license": "MIT", + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/cjs-module-lexer": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.4.3.tgz", + "integrity": "sha512-9z8TZaGM1pfswYeXrUpzPrkx8UnWYdhJclsiYMm6x/w5+nN+8Tf/LnAgfLGQCm59qAOxU8WwHEq2vNwF6i4j+Q==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "license": "ISC", + "peer": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "iojs": ">= 1.0.0", + "node": ">= 0.12.0" + } + }, + "node_modules/collect-v8-coverage": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.3.tgz", + "integrity": "sha512-1L5aqIkwPfiodaMgQunkF1zRhNqifHBmtbbbxcr6yVxxBnliw4TDOW6NxpO8DJLgJ16OT+Y4ztZqP6p/FtXnAw==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "license": "MIT", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "license": "MIT" + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/compare-versions": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-3.6.0.tgz", + "integrity": "sha512-W6Af2Iw1z4CB7q4uU4hv646dW9GQuBM+YpC0UvUCWSD8w90SJjp+ujJuXaEMtAXBtSqGfMPuFOVn4/+FlaqfBA==", + "license": "MIT" + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/confbox": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.1.8.tgz", + "integrity": "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==", + "license": "MIT" + }, + "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==", + "dev": true, + "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==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "license": "MIT" + }, + "node_modules/cookie": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", + "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/core-js": { + "version": "3.49.0", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.49.0.tgz", + "integrity": "sha512-es1U2+YTtzpwkxVLwAFdSpaIMyQaq0PBgm3YD1W3Qpsn1NAmO3KSgZfu+oGSWVu6NvLHoHCV/aYcsE5wiB7ALg==", + "hasInstallScript": true, + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/core-js-compat": { + "version": "3.49.0", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.49.0.tgz", + "integrity": "sha512-VQXt1jr9cBz03b331DFDCCP90b3fanciLkgiOoy8SBHy06gNf+vQ1A3WFLqG7I8TipYIKeYK9wxd0tUrvHcOZA==", + "dev": true, + "license": "MIT", + "dependencies": { + "browserslist": "^4.28.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/core-js-pure": { + "version": "3.49.0", + "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.49.0.tgz", + "integrity": "sha512-XM4RFka59xATyJv/cS3O3Kml72hQXUeGRuuTmMYFxwzc9/7C8OYTaIR/Ji+Yt8DXzsFLNhat15cE/JP15HrCgw==", + "hasInstallScript": true, + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/cross-env": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz", + "integrity": "sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "cross-spawn": "^7.0.1" + }, + "bin": { + "cross-env": "src/bin/cross-env.js", + "cross-env-shell": "src/bin/cross-env-shell.js" + }, + "engines": { + "node": ">=10.14", + "npm": ">=6", + "yarn": ">=1" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/css-font-size-keywords": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/css-font-size-keywords/-/css-font-size-keywords-1.0.0.tgz", + "integrity": "sha512-Q+svMDbMlelgCfH/RVDKtTDaf5021O486ZThQPIpahnIjUkMUslC+WuOQSWTgGSrNCH08Y7tYNEmmy0hkfMI8Q==", + "license": "MIT" + }, + "node_modules/css-font-stretch-keywords": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/css-font-stretch-keywords/-/css-font-stretch-keywords-1.0.1.tgz", + "integrity": "sha512-KmugPO2BNqoyp9zmBIUGwt58UQSfyk1X5DbOlkb2pckDXFSAfjsD5wenb88fNrD6fvS+vu90a/tsPpb9vb0SLg==", + "license": "MIT" + }, + "node_modules/css-font-style-keywords": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/css-font-style-keywords/-/css-font-style-keywords-1.0.1.tgz", + "integrity": "sha512-0Fn0aTpcDktnR1RzaBYorIxQily85M2KXRpzmxQPgh8pxUN9Fcn00I8u9I3grNr1QXVgCl9T5Imx0ZwKU973Vg==", + "license": "MIT" + }, + "node_modules/css-font-weight-keywords": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/css-font-weight-keywords/-/css-font-weight-keywords-1.0.0.tgz", + "integrity": "sha512-5So8/NH+oDD+EzsnF4iaG4ZFHQ3vaViePkL1ZbZ5iC/KrsCY+WHq/lvOgrtmuOQ9pBBZ1ADGpaf+A4lj1Z9eYA==", + "license": "MIT" + }, + "node_modules/css-list-helpers": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/css-list-helpers/-/css-list-helpers-2.0.0.tgz", + "integrity": "sha512-9Bj8tZ0jWbAM3u/U6m/boAzAwLPwtjzFvwivr2piSvyVa3K3rChJzQy4RIHkNkKiZCHrEMWDJWtTR8UyVhdDnQ==", + "license": "MIT" + }, + "node_modules/css-system-font-keywords": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/css-system-font-keywords/-/css-system-font-keywords-1.0.0.tgz", + "integrity": "sha512-1umTtVd/fXS25ftfjB71eASCrYhilmEsvDEI6wG/QplnmlfmVM5HkZ/ZX46DT5K3eblFPgLUHt5BRCb0YXkSFA==", + "license": "MIT" + }, + "node_modules/cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "license": "MIT", + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/cssom": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.4.4.tgz", + "integrity": "sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/cssstyle": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-2.3.0.tgz", + "integrity": "sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "cssom": "~0.3.6" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cssstyle/node_modules/cssom": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", + "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/csstype": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", + "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", + "license": "MIT" + }, + "node_modules/data-urls": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-2.0.0.tgz", + "integrity": "sha512-X5eWTSXO/BJmpdIKCRuKUgSCgAN0OwliVK3yPKbwIWU1Tdw5BRajxlzMidvh+gwko9AfQ9zIj52pzF91Q3YAvQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "abab": "^2.0.3", + "whatwg-mimetype": "^2.3.0", + "whatwg-url": "^8.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/debug": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decimal.js": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.6.0.tgz", + "integrity": "sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/dedent": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", + "integrity": "sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/default-gateway": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-6.0.3.tgz", + "integrity": "sha512-fwSOJsbbNzZ/CUFpqFBqYfYNLj1NbMPm8MMCIzHjC83iSJRBEGmDUxU+WP661BaBQImeC2yHwXtz+P/O9o+XEg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "execa": "^5.0.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=0.4.0" + } + }, + "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==", + "dev": true, + "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==", + "dev": true, + "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", + "optional": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/detect-newline": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", + "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/diff-sequences": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-27.5.1.tgz", + "integrity": "sha512-k1gCAXAsNgLwEL+Y8Wvl+M6oEFj5bgazfZULpS5CneoPPXRaCCW7dm+q21Ky2VEE5X+VeRDBVg1Pcvvsr4TtNQ==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/dom-walk": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/dom-walk/-/dom-walk-0.1.2.tgz", + "integrity": "sha512-6QvTW9mrGeIegrFXdtQi9pk7O/nSK6lSdXW2eqUspN5LWD7UTji2Fqw5V2YLjBpHEoU9Xl/eUWNpDeZvoyOv2w==" + }, + "node_modules/domexception": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/domexception/-/domexception-2.0.1.tgz", + "integrity": "sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg==", + "deprecated": "Use your platform's native DOMException instead", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "webidl-conversions": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/domexception/node_modules/webidl-conversions": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-5.0.0.tgz", + "integrity": "sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA==", + "dev": true, + "license": "BSD-2-Clause", + "peer": true, + "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==", + "dev": true, + "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/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==", + "dev": true, + "license": "MIT" + }, + "node_modules/electron-to-chromium": { + "version": "1.5.372", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.372.tgz", + "integrity": "sha512-M3yhbAlilnwqC8D21t28UCDGHyitShTmmLRU/H+b74P6Ski16Nb9HONYEaVpMj/pwC7BEo5B95FpjODLCWbtfA==", + "license": "ISC" + }, + "node_modules/emittery": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.8.1.tgz", + "integrity": "sha512-uDfvUjVrfGJJhymx/kz6prltenw1u7WrCg1oa94zYY8xxVpLLUu045LAT0dhDZdXG58/EpPL/5kA180fQ/qudg==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/emittery?sponsor=1" + } + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/entities": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-7.0.1.tgz", + "integrity": "sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/error-ex": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.4.tgz", + "integrity": "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "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==", + "dev": true, + "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==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-module-lexer": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.5.4.tgz", + "integrity": "sha512-MVNK56NiMrOwitFB7cqDwq0CQutbw+0BvLshJSse0MUNU+y1FC3bUS/AQg7oUng+/wKrrki7JfmwtVHkVfPLlw==", + "license": "MIT" + }, + "node_modules/es-object-atoms": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.2.tgz", + "integrity": "sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/esbuild": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.20.2.tgz", + "integrity": "sha512-WdOOppmUNU+IbZ0PaDiTst80zjnrOkyJNHoKupIcVyU8Lvla3Ugx94VzkQ32Ijqd7UhHJy75gNWDMUekcrSJ6g==", + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.20.2", + "@esbuild/android-arm": "0.20.2", + "@esbuild/android-arm64": "0.20.2", + "@esbuild/android-x64": "0.20.2", + "@esbuild/darwin-arm64": "0.20.2", + "@esbuild/darwin-x64": "0.20.2", + "@esbuild/freebsd-arm64": "0.20.2", + "@esbuild/freebsd-x64": "0.20.2", + "@esbuild/linux-arm": "0.20.2", + "@esbuild/linux-arm64": "0.20.2", + "@esbuild/linux-ia32": "0.20.2", + "@esbuild/linux-loong64": "0.20.2", + "@esbuild/linux-mips64el": "0.20.2", + "@esbuild/linux-ppc64": "0.20.2", + "@esbuild/linux-riscv64": "0.20.2", + "@esbuild/linux-s390x": "0.20.2", + "@esbuild/linux-x64": "0.20.2", + "@esbuild/netbsd-x64": "0.20.2", + "@esbuild/openbsd-x64": "0.20.2", + "@esbuild/sunos-x64": "0.20.2", + "@esbuild/win32-arm64": "0.20.2", + "@esbuild/win32-ia32": "0.20.2", + "@esbuild/win32-x64": "0.20.2" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "dev": true, + "license": "MIT" + }, + "node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "license": "MIT", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/escodegen": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.1.0.tgz", + "integrity": "sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==", + "dev": true, + "license": "BSD-2-Clause", + "peer": true, + "dependencies": { + "esprima": "^4.0.1", + "estraverse": "^5.2.0", + "esutils": "^2.0.2" + }, + "bin": { + "escodegen": "bin/escodegen.js", + "esgenerate": "bin/esgenerate.js" + }, + "engines": { + "node": ">=6.0" + }, + "optionalDependencies": { + "source-map": "~0.6.1" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, + "license": "BSD-2-Clause", + "peer": true, + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "license": "BSD-2-Clause", + "peer": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "license": "MIT" + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "license": "MIT", + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/exif-parser": { + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/exif-parser/-/exif-parser-0.1.12.tgz", + "integrity": "sha512-c2bQfLNbMzLPmzQuOr8fy0csy84WmwnER81W88DzTp9CYNPJ6yzOj2EZAh9pywYpqHnshVLHQJ8WzldAyfY+Iw==" + }, + "node_modules/exit": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", + "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==", + "dev": true, + "peer": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/expect": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/expect/-/expect-27.5.1.tgz", + "integrity": "sha512-E1q5hSUG2AmYQwQJ041nvgpkODHQvB+RKlB4IYdru6uJsyFTRyZAP463M+1lINorwbqAmUggi6+WwkD8lCS/Dw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@jest/types": "^27.5.1", + "jest-get-type": "^27.5.1", + "jest-matcher-utils": "^27.5.1", + "jest-message-util": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/express": { + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/express/-/express-4.20.0.tgz", + "integrity": "sha512-pLdae7I6QqShF5PnNTCVn4hI91Dx0Grkn2+IAsMTgMIKuQVte2dN9PeGSSAME2FR8anOhVA62QDIUaWVfEXVLw==", + "dev": true, + "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.6.0", + "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.2.0", + "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.10", + "proxy-addr": "~2.0.7", + "qs": "6.11.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.19.0", + "serve-static": "1.16.0", + "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" + } + }, + "node_modules/express/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/express/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true, + "license": "MIT" + }, + "node_modules/exsolve": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/exsolve/-/exsolve-1.0.8.tgz", + "integrity": "sha512-LmDxfWXwcTArk8fUEnOfSZpHOJ6zOMUJKOtFLFqJLoKJetuQG874Uc7/Kki7zFLzYybmZhp1M7+98pfMqeX8yA==", + "license": "MIT" + }, + "node_modules/fast-glob": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.8" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/fastq": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz", + "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==", + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fb-watchman": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", + "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", + "dev": true, + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "bser": "2.1.1" + } + }, + "node_modules/file-type": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/file-type/-/file-type-9.0.0.tgz", + "integrity": "sha512-Qe/5NJrgIOlwijpq3B7BEpzPFcgzggOTagZmkXQY4LA6bsXKTUstK7Wp12lEJ/mLKTpvIZxmIuRcLYWT6ov9lw==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/finalhandler": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", + "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/finalhandler/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/finalhandler/node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/finalhandler/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true, + "license": "MIT" + }, + "node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/follow-redirects": { + "version": "1.16.0", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.16.0.tgz", + "integrity": "sha512-y5rN/uOsadFT/JfYwhxRS5R7Qce+g3zG97+JrtFZlC9klX/W5hD7iiLzScI4nZqUS7DNUdhPgw4xI8W2LuXlUw==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "license": "MIT", + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/form-data": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.5.tgz", + "integrity": "sha512-j23EibVLnp4zNXGW7LjryXYa2X6U/M96yoOX+ybZxwkYajdxRNEqYY3zhh7y0i6kfISKS2jr+EJq1YTUDEv5+w==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.4", + "mime-types": "^2.1.35" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fraction.js": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz", + "integrity": "sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==", + "license": "MIT", + "engines": { + "node": "*" + }, + "funding": { + "type": "patreon", + "url": "https://github.com/sponsors/rawify" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true, + "license": "ISC", + "peer": true + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "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/generic-names": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/generic-names/-/generic-names-4.0.0.tgz", + "integrity": "sha512-ySFolZQfw9FoDb3ed9d80Cm9f0+r7qj+HJkWjeD9RBfpxEVTlVhol+gvaQB/78WbwYfbnNh8nWHHBSlg072y6A==", + "license": "MIT", + "dependencies": { + "loader-utils": "^3.2.0" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "license": "ISC", + "peer": true, + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-package-type": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", + "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "dev": true, + "license": "ISC", + "peer": 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/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/global": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/global/-/global-4.4.0.tgz", + "integrity": "sha512-wv/LAoHdRE3BeTGz53FAamhGlPLhlssK45usmGFThIi4XqnBmjKQ16u+RNbP7WvigRZDxUsM0J3gcQ5yicaL0w==", + "license": "MIT", + "dependencies": { + "min-document": "^2.19.0", + "process": "^0.11.10" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "dev": true, + "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" + }, + "node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "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==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hash-sum": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/hash-sum/-/hash-sum-2.0.0.tgz", + "integrity": "sha512-WdZTbAByD+pHfl/g9QSsBIIwy8IT+EsPiKDs0KNX+zSHhdDLFKdZu0BQHljvO+0QI/BasbMSUa8wYNCZTvhslg==", + "license": "MIT" + }, + "node_modules/hasown": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.4.tgz", + "integrity": "sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/html-encoding-sniffer": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz", + "integrity": "sha512-D5JbOMBIR/TVZkubHT+OyT2705QvogUW4IBn6nHd756OwieSF9aDYFj4dv6HHEVGYbHaLETa3WggZYWWMyy3ZQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "whatwg-encoding": "^1.0.5" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/http-proxy-agent": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", + "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@tootallnate/once": "1", + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "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==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=10.17.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==", + "dev": true, + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/icss-replace-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/icss-replace-symbols/-/icss-replace-symbols-1.1.0.tgz", + "integrity": "sha512-chIaY3Vh2mh2Q3RGXttaDIzeiPvaVXJ+C4DAh/w3c37SKZ/U6PGMmuicR2EQQp9bKG8zLMCl7I+PtIoOOPp8Gg==", + "license": "ISC" + }, + "node_modules/icss-utils": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz", + "integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==", + "license": "ISC", + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.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/immutable": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-5.1.6.tgz", + "integrity": "sha512-q1swsS8K7L8usSHuOqF2TAoCCkonYz0SG38wLAggaa4Wml70zixIvt2ql4coQ2C2B3hTjltJry4r6bULwgAXLQ==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/import-local": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.2.0.tgz", + "integrity": "sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + }, + "bin": { + "import-local-fixture": "fixtures/cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "dev": true, + "license": "ISC", + "peer": 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==", + "dev": true, + "license": "ISC" + }, + "node_modules/invert-kv": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-3.0.1.tgz", + "integrity": "sha512-CYdFeFexxhv/Bcny+Q0BfOV+ltRlJcd4BBZBYFX/O0u4npJrgZtIcjokegtiSMAvlMTJ+Koq0GBCc//3bueQxw==", + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sindresorhus/invert-kv?sponsor=1" + } + }, + "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==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "license": "MIT", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-core-module": { + "version": "2.16.2", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.2.tgz", + "integrity": "sha512-evOr8xfXKxE6qSR0hSXL2r3sd7ALj8+7jQEUvPYcm5sgZFdJ+AYzT6yNmJenvIYQBgIGwfwz08sL8zoL7yq2BA==", + "license": "MIT", + "dependencies": { + "hasown": "^2.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-function": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-function/-/is-function-1.0.2.tgz", + "integrity": "sha512-lw7DUp0aWXYg+CBCN+JKkcE0Q2RayZnSvnZBlwgxHBQhqt5pZNVy4Ri7H9GmmXkdu7LUthszM+Tor1u/2iBcpQ==", + "license": "MIT" + }, + "node_modules/is-generator-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", + "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-potential-custom-element-name": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", + "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/isbinaryfile": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-5.0.2.tgz", + "integrity": "sha512-GvcjojwonMjWbTkfMpnVHVqXW/wKMYDfEpY94/8zy8HFMOqb/VL6oeONq9v87q4ttVlaTLnGXnJD4B5B1OTGIg==", + "license": "MIT", + "engines": { + "node": ">= 18.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/gjtorikian/" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/istanbul-lib-coverage": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", + "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", + "dev": true, + "license": "BSD-3-Clause", + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-instrument": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz", + "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==", + "dev": true, + "license": "BSD-3-Clause", + "peer": true, + "dependencies": { + "@babel/core": "^7.12.3", + "@babel/parser": "^7.14.7", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-report": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", + "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", + "dev": true, + "license": "BSD-3-Clause", + "peer": true, + "dependencies": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^4.0.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-report/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-report/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-source-maps": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", + "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", + "dev": true, + "license": "BSD-3-Clause", + "peer": true, + "dependencies": { + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-reports": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.2.0.tgz", + "integrity": "sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==", + "dev": true, + "license": "BSD-3-Clause", + "peer": true, + "dependencies": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest": { + "version": "27.0.4", + "resolved": "https://registry.npmjs.org/jest/-/jest-27.0.4.tgz", + "integrity": "sha512-Px1iKFooXgGSkk1H8dJxxBIrM3tsc5SIuI4kfKYK2J+4rvCvPGr/cXktxh0e9zIPQ5g09kOMNfHQEmusBUf/ZA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@jest/core": "^27.0.4", + "import-local": "^3.0.2", + "jest-cli": "^27.0.4" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/jest-changed-files": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-27.5.1.tgz", + "integrity": "sha512-buBLMiByfWGCoMsLLzGUUSpAmIAGnbR2KJoMN10ziLhOLvP4e0SlypHnAel8iqQXTrcbmfEY9sSqae5sgUsTvw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@jest/types": "^27.5.1", + "execa": "^5.0.0", + "throat": "^6.0.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-circus": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-27.5.1.tgz", + "integrity": "sha512-D95R7x5UtlMA5iBYsOHFFbMD/GVA4R/Kdq15f7xYWUfWHBto9NYRsOvnSauTgdF+ogCpJ4tyKOXhUifxS65gdw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@jest/environment": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "chalk": "^4.0.0", + "co": "^4.6.0", + "dedent": "^0.7.0", + "expect": "^27.5.1", + "is-generator-fn": "^2.0.0", + "jest-each": "^27.5.1", + "jest-matcher-utils": "^27.5.1", + "jest-message-util": "^27.5.1", + "jest-runtime": "^27.5.1", + "jest-snapshot": "^27.5.1", + "jest-util": "^27.5.1", + "pretty-format": "^27.5.1", + "slash": "^3.0.0", + "stack-utils": "^2.0.3", + "throat": "^6.0.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-circus/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-circus/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-circus/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-circus/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/jest-circus/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-circus/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-cli": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-27.5.1.tgz", + "integrity": "sha512-Hc6HOOwYq4/74/c62dEE3r5elx8wjYqxY0r0G/nFrLDPMFRu6RA/u8qINOIkvhxG7mMQ5EJsOGfRpI8L6eFUVw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@jest/core": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/types": "^27.5.1", + "chalk": "^4.0.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "import-local": "^3.0.2", + "jest-config": "^27.5.1", + "jest-util": "^27.5.1", + "jest-validate": "^27.5.1", + "prompts": "^2.0.1", + "yargs": "^16.2.0" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/jest-cli/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-cli/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-cli/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-cli/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/jest-cli/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-cli/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-config": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-27.5.1.tgz", + "integrity": "sha512-5sAsjm6tGdsVbW9ahcChPAFCk4IlkQUknH5AvKjuLTSlcO/wCZKyFdn7Rg0EkC+OGgWODEy2hDpWB1PgzH0JNA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/core": "^7.8.0", + "@jest/test-sequencer": "^27.5.1", + "@jest/types": "^27.5.1", + "babel-jest": "^27.5.1", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "deepmerge": "^4.2.2", + "glob": "^7.1.1", + "graceful-fs": "^4.2.9", + "jest-circus": "^27.5.1", + "jest-environment-jsdom": "^27.5.1", + "jest-environment-node": "^27.5.1", + "jest-get-type": "^27.5.1", + "jest-jasmine2": "^27.5.1", + "jest-regex-util": "^27.5.1", + "jest-resolve": "^27.5.1", + "jest-runner": "^27.5.1", + "jest-util": "^27.5.1", + "jest-validate": "^27.5.1", + "micromatch": "^4.0.4", + "parse-json": "^5.2.0", + "pretty-format": "^27.5.1", + "slash": "^3.0.0", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + }, + "peerDependencies": { + "ts-node": ">=9.0.0" + }, + "peerDependenciesMeta": { + "ts-node": { + "optional": true + } + } + }, + "node_modules/jest-config/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-config/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-config/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-config/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/jest-config/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-config/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-diff": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-27.5.1.tgz", + "integrity": "sha512-m0NvkX55LDt9T4mctTEgnZk3fmEg3NRYutvMPWM/0iPnkFj2wIeF45O1718cMSOFO1vINkqmxqD8vE37uTEbqw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "chalk": "^4.0.0", + "diff-sequences": "^27.5.1", + "jest-get-type": "^27.5.1", + "pretty-format": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-diff/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-diff/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-diff/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-diff/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/jest-diff/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-diff/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-docblock": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-27.5.1.tgz", + "integrity": "sha512-rl7hlABeTsRYxKiUfpHrQrG4e2obOiTQWfMEH3PxPjOtdsfLQO4ReWSZaQ7DETm4xu07rl4q/h4zcKXyU0/OzQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "detect-newline": "^3.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-each": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-27.5.1.tgz", + "integrity": "sha512-1Ff6p+FbhT/bXQnEouYy00bkNSY7OUpfIcmdl8vZ31A1UUaurOLPA8a8BbJOF2RDUElwJhmeaV7LnagI+5UwNQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@jest/types": "^27.5.1", + "chalk": "^4.0.0", + "jest-get-type": "^27.5.1", + "jest-util": "^27.5.1", + "pretty-format": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-each/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-each/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-each/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-each/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/jest-each/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-each/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-environment-jsdom": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-27.5.1.tgz", + "integrity": "sha512-TFBvkTC1Hnnnrka/fUb56atfDtJ9VMZ94JkjTbggl1PEpwrYtUBKMezB3inLmWqQsXYLcMwNoDQwoBTAvFfsfw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@jest/environment": "^27.5.1", + "@jest/fake-timers": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "jest-mock": "^27.5.1", + "jest-util": "^27.5.1", + "jsdom": "^16.6.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-environment-node": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-27.5.1.tgz", + "integrity": "sha512-Jt4ZUnxdOsTGwSRAfKEnE6BcwsSPNOijjwifq5sDFSA2kesnXTvNqKHYgM0hDq3549Uf/KzdXNYn4wMZJPlFLw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@jest/environment": "^27.5.1", + "@jest/fake-timers": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "jest-mock": "^27.5.1", + "jest-util": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-get-type": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.5.1.tgz", + "integrity": "sha512-2KY95ksYSaK7DMBWQn6dQz3kqAf3BB64y2udeG+hv4KfSOb9qwcYQstTJc1KCbsix+wLZWZYN8t7nwX3GOBLRw==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-haste-map": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-27.5.1.tgz", + "integrity": "sha512-7GgkZ4Fw4NFbMSDSpZwXeBiIbx+t/46nJ2QitkOjvwPYyZmqttu2TDSimMHP1EkPOi4xUZAN1doE5Vd25H4Jng==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@jest/types": "^27.5.1", + "@types/graceful-fs": "^4.1.2", + "@types/node": "*", + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", + "graceful-fs": "^4.2.9", + "jest-regex-util": "^27.5.1", + "jest-serializer": "^27.5.1", + "jest-util": "^27.5.1", + "jest-worker": "^27.5.1", + "micromatch": "^4.0.4", + "walker": "^1.0.7" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + }, + "optionalDependencies": { + "fsevents": "^2.3.2" + } + }, + "node_modules/jest-jasmine2": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-27.5.1.tgz", + "integrity": "sha512-jtq7VVyG8SqAorDpApwiJJImd0V2wv1xzdheGHRGyuT7gZm6gG47QEskOlzsN1PG/6WNaCo5pmwMHDf3AkG2pQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@jest/environment": "^27.5.1", + "@jest/source-map": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "chalk": "^4.0.0", + "co": "^4.6.0", + "expect": "^27.5.1", + "is-generator-fn": "^2.0.0", + "jest-each": "^27.5.1", + "jest-matcher-utils": "^27.5.1", + "jest-message-util": "^27.5.1", + "jest-runtime": "^27.5.1", + "jest-snapshot": "^27.5.1", + "jest-util": "^27.5.1", + "pretty-format": "^27.5.1", + "throat": "^6.0.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-jasmine2/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-jasmine2/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-jasmine2/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-jasmine2/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/jest-jasmine2/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-jasmine2/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-leak-detector": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-27.5.1.tgz", + "integrity": "sha512-POXfWAMvfU6WMUXftV4HolnJfnPOGEu10fscNCA76KBpRRhcMN2c8d3iT2pxQS3HLbA+5X4sOUPzYO2NUyIlHQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "jest-get-type": "^27.5.1", + "pretty-format": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-matcher-utils": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-27.5.1.tgz", + "integrity": "sha512-z2uTx/T6LBaCoNWNFWwChLBKYxTMcGBRjAt+2SbP929/Fflb9aa5LGma654Rz8z9HLxsrUaYzxE9T/EFIL/PAw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "chalk": "^4.0.0", + "jest-diff": "^27.5.1", + "jest-get-type": "^27.5.1", + "pretty-format": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-matcher-utils/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-matcher-utils/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-matcher-utils/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-matcher-utils/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/jest-matcher-utils/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-matcher-utils/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-message-util": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-27.5.1.tgz", + "integrity": "sha512-rMyFe1+jnyAAf+NHwTclDz0eAaLkVDdKVHHBFWsBWHnnh5YeJMNWWsv7AbFYXfK3oTqvL7VTWkhNLu1jX24D+g==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^27.5.1", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^27.5.1", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-message-util/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-message-util/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-message-util/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-message-util/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/jest-message-util/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-message-util/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-mock": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-27.5.1.tgz", + "integrity": "sha512-K4jKbY1d4ENhbrG2zuPWaQBvDly+iZ2yAW+T1fATN78hc0sInwn7wZB8XtlNnvHug5RMwV897Xm4LqmPM4e2Og==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@jest/types": "^27.5.1", + "@types/node": "*" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-pnp-resolver": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz", + "integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=6" + }, + "peerDependencies": { + "jest-resolve": "*" + }, + "peerDependenciesMeta": { + "jest-resolve": { + "optional": true + } + } + }, + "node_modules/jest-regex-util": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-27.5.1.tgz", + "integrity": "sha512-4bfKq2zie+x16okqDXjXn9ql2B0dScQu+vcwe4TvFVhkVyuWLqpZrZtXxLLWoXYgn0E87I6r6GRYHF7wFZBUvg==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-resolve": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-27.5.1.tgz", + "integrity": "sha512-FFDy8/9E6CV83IMbDpcjOhumAQPDyETnU2KZ1O98DwTnz8AOBsW/Xv3GySr1mOZdItLR+zDZ7I/UdTFbgSOVCw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@jest/types": "^27.5.1", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^27.5.1", + "jest-pnp-resolver": "^1.2.2", + "jest-util": "^27.5.1", + "jest-validate": "^27.5.1", + "resolve": "^1.20.0", + "resolve.exports": "^1.1.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-resolve-dependencies": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-27.5.1.tgz", + "integrity": "sha512-QQOOdY4PE39iawDn5rzbIePNigfe5B9Z91GDD1ae/xNDlu9kaat8QQ5EKnNmVWPV54hUdxCVwwj6YMgR2O7IOg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@jest/types": "^27.5.1", + "jest-regex-util": "^27.5.1", + "jest-snapshot": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-resolve/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-resolve/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-resolve/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-resolve/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/jest-resolve/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-resolve/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-runner": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-27.5.1.tgz", + "integrity": "sha512-g4NPsM4mFCOwFKXO4p/H/kWGdJp9V8kURY2lX8Me2drgXqG7rrZAx5kv+5H7wtt/cdFIjhqYx1HrlqWHaOvDaQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@jest/console": "^27.5.1", + "@jest/environment": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/transform": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "chalk": "^4.0.0", + "emittery": "^0.8.1", + "graceful-fs": "^4.2.9", + "jest-docblock": "^27.5.1", + "jest-environment-jsdom": "^27.5.1", + "jest-environment-node": "^27.5.1", + "jest-haste-map": "^27.5.1", + "jest-leak-detector": "^27.5.1", + "jest-message-util": "^27.5.1", + "jest-resolve": "^27.5.1", + "jest-runtime": "^27.5.1", + "jest-util": "^27.5.1", + "jest-worker": "^27.5.1", + "source-map-support": "^0.5.6", + "throat": "^6.0.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-runner/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-runner/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-runner/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-runner/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/jest-runner/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-runner/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-runtime": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-27.5.1.tgz", + "integrity": "sha512-o7gxw3Gf+H2IGt8fv0RiyE1+r83FJBRruoA+FXrlHw6xEyBsU8ugA6IPfTdVyA0w8HClpbK+DGJxH59UrNMx8A==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@jest/environment": "^27.5.1", + "@jest/fake-timers": "^27.5.1", + "@jest/globals": "^27.5.1", + "@jest/source-map": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/transform": "^27.5.1", + "@jest/types": "^27.5.1", + "chalk": "^4.0.0", + "cjs-module-lexer": "^1.0.0", + "collect-v8-coverage": "^1.0.0", + "execa": "^5.0.0", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^27.5.1", + "jest-message-util": "^27.5.1", + "jest-mock": "^27.5.1", + "jest-regex-util": "^27.5.1", + "jest-resolve": "^27.5.1", + "jest-snapshot": "^27.5.1", + "jest-util": "^27.5.1", + "slash": "^3.0.0", + "strip-bom": "^4.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-runtime/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-runtime/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-runtime/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-runtime/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/jest-runtime/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-runtime/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-serializer": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-serializer/-/jest-serializer-27.5.1.tgz", + "integrity": "sha512-jZCyo6iIxO1aqUxpuBlwTDMkzOAJS4a3eYz3YzgxxVQFwLeSA7Jfq5cbqCY+JLvTDrWirgusI/0KwxKMgrdf7w==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@types/node": "*", + "graceful-fs": "^4.2.9" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-snapshot": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-27.5.1.tgz", + "integrity": "sha512-yYykXI5a0I31xX67mgeLw1DZ0bJB+gpq5IpSuCAoyDi0+BhgU/RIrL+RTzDmkNTchvDFWKP8lp+w/42Z3us5sA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/core": "^7.7.2", + "@babel/generator": "^7.7.2", + "@babel/plugin-syntax-typescript": "^7.7.2", + "@babel/traverse": "^7.7.2", + "@babel/types": "^7.0.0", + "@jest/transform": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/babel__traverse": "^7.0.4", + "@types/prettier": "^2.1.5", + "babel-preset-current-node-syntax": "^1.0.0", + "chalk": "^4.0.0", + "expect": "^27.5.1", + "graceful-fs": "^4.2.9", + "jest-diff": "^27.5.1", + "jest-get-type": "^27.5.1", + "jest-haste-map": "^27.5.1", + "jest-matcher-utils": "^27.5.1", + "jest-message-util": "^27.5.1", + "jest-util": "^27.5.1", + "natural-compare": "^1.4.0", + "pretty-format": "^27.5.1", + "semver": "^7.3.2" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-snapshot/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-snapshot/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-snapshot/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-snapshot/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/jest-snapshot/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-snapshot/node_modules/semver": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.4.tgz", + "integrity": "sha512-rUCObTnP32Q08R2uuIrt7r9PlEonuTmtuXYcW6s5kjdlj3xbnwe+21yXptAUYcMAABLkYYTtnmzb3w3EDZfueA==", + "dev": true, + "license": "ISC", + "peer": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/jest-snapshot/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-util": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.5.1.tgz", + "integrity": "sha512-Kv2o/8jNvX1MQ0KGtw480E/w4fBCDOnH6+6DmeKi6LZUIlKA5kwY0YNdlzaWTiVgxqAqik11QyxDOKk543aKXw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@jest/types": "^27.5.1", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-util/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-util/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-util/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-util/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/jest-util/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-util/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-validate": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-27.5.1.tgz", + "integrity": "sha512-thkNli0LYTmOI1tDB3FI1S1RTp/Bqyd9pTarJwL87OIBFuqEb5Apv5EaApEudYg4g86e3CT6kM0RowkhtEnCBQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@jest/types": "^27.5.1", + "camelcase": "^6.2.0", + "chalk": "^4.0.0", + "jest-get-type": "^27.5.1", + "leven": "^3.1.0", + "pretty-format": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-validate/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-validate/node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/jest-validate/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-validate/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-validate/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/jest-validate/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-validate/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-watcher": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-27.5.1.tgz", + "integrity": "sha512-z676SuD6Z8o8qbmEGhoEUFOM1+jfEiL3DXHK/xgEiG2EyNYfFG60jluWcupY6dATjfEsKQuibReS1djInQnoVw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@jest/test-result": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "jest-util": "^27.5.1", + "string-length": "^4.0.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-watcher/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-watcher/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-watcher/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-watcher/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/jest-watcher/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-watcher/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-worker": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", + "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/jest-worker/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-worker/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/jimp": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/jimp/-/jimp-0.10.3.tgz", + "integrity": "sha512-meVWmDMtyUG5uYjFkmzu0zBgnCvvxwWNi27c4cg55vWNVC9ES4Lcwb+ogx+uBBQE3Q+dLKjXaLl0JVW+nUNwbQ==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.7.2", + "@jimp/custom": "^0.10.3", + "@jimp/plugins": "^0.10.3", + "@jimp/types": "^0.10.3", + "core-js": "^3.4.1", + "regenerator-runtime": "^0.13.3" + } + }, + "node_modules/jimp/node_modules/regenerator-runtime": { + "version": "0.13.11", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", + "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==", + "license": "MIT" + }, + "node_modules/jpeg-js": { + "version": "0.3.7", + "resolved": "https://registry.npmjs.org/jpeg-js/-/jpeg-js-0.3.7.tgz", + "integrity": "sha512-9IXdWudL61npZjvLuVe/ktHiA41iE8qFyLB+4VDTblEsWBzeg8WQTlktdUK4CdncUqtUgUg0bbOmTE2bKBKaBQ==", + "license": "BSD-3-Clause" + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "3.14.2", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.2.tgz", + "integrity": "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsdom": { + "version": "16.7.0", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-16.7.0.tgz", + "integrity": "sha512-u9Smc2G1USStM+s/x1ru5Sxrl6mPYCbByG1U/hUmqaVsm4tbNyS7CicOSRyuGQYZhTu0h84qkZZQ/I+dzizSVw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "abab": "^2.0.5", + "acorn": "^8.2.4", + "acorn-globals": "^6.0.0", + "cssom": "^0.4.4", + "cssstyle": "^2.3.0", + "data-urls": "^2.0.0", + "decimal.js": "^10.2.1", + "domexception": "^2.0.1", + "escodegen": "^2.0.0", + "form-data": "^3.0.0", + "html-encoding-sniffer": "^2.0.1", + "http-proxy-agent": "^4.0.1", + "https-proxy-agent": "^5.0.0", + "is-potential-custom-element-name": "^1.0.1", + "nwsapi": "^2.2.0", + "parse5": "6.0.1", + "saxes": "^5.0.1", + "symbol-tree": "^3.2.4", + "tough-cookie": "^4.0.0", + "w3c-hr-time": "^1.0.2", + "w3c-xmlserializer": "^2.0.0", + "webidl-conversions": "^6.1.0", + "whatwg-encoding": "^1.0.5", + "whatwg-mimetype": "^2.3.0", + "whatwg-url": "^8.5.0", + "ws": "^7.4.6", + "xml-name-validator": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "canvas": "^2.5.0" + }, + "peerDependenciesMeta": { + "canvas": { + "optional": true + } + } + }, + "node_modules/jsdom/node_modules/ws": { + "version": "7.5.11", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.11.tgz", + "integrity": "sha512-zS54Oen9bITtp7kp2XM3AydrCIq1D+HwJOuH+c+e4LfpL/lotP5osijd+UoMnxwAam1GN8R4KtLAyIrIcBNpiA==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jsonc-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.3.1.tgz", + "integrity": "sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ==", + "license": "MIT" + }, + "node_modules/jsonfile": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.1.tgz", + "integrity": "sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q==", + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/lcid": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/lcid/-/lcid-3.1.1.tgz", + "integrity": "sha512-M6T051+5QCGLBQb8id3hdvIW8+zeFV2FyBGFS9IEK5H9Wt4MueD4bW1eWikpHgZp+5xR3l5c8pZUkQsIA0BFZg==", + "license": "MIT", + "dependencies": { + "invert-kv": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/licia": { + "version": "1.41.1", + "resolved": "https://registry.npmjs.org/licia/-/licia-1.41.1.tgz", + "integrity": "sha512-XqObV8u1KEMdYWaNK0leRrTwhzKnLQEkhbnuUu7qGNH3zJoN7l9sfvF6PfHstSCuUOmpEP+0SBjRrk0I9uZs8g==", + "license": "MIT" + }, + "node_modules/lilconfig": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz", + "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==", + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/lines-and-columns": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-2.0.4.tgz", + "integrity": "sha512-wM1+Z03eypVAVUCE7QdSqpVIvelbOakn1M0bPDoA4SGWPx3sNDVUiMo3L6To6WWGClB7VyXnhQ4Sn7gxiJbE6A==", + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + } + }, + "node_modules/load-bmfont": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/load-bmfont/-/load-bmfont-1.4.2.tgz", + "integrity": "sha512-qElWkmjW9Oq1F9EI5Gt7aD9zcdHb9spJCW1L/dmPf7KzCCEJxq8nhHz5eCgI9aMf7vrG/wyaCqdsI+Iy9ZTlog==", + "license": "MIT", + "dependencies": { + "buffer-equal": "0.0.1", + "mime": "^1.3.4", + "parse-bmfont-ascii": "^1.0.3", + "parse-bmfont-binary": "^1.0.5", + "parse-bmfont-xml": "^1.1.4", + "phin": "^3.7.1", + "xhr": "^2.0.1", + "xtend": "^4.0.0" + } + }, + "node_modules/load-bmfont/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/load-bmfont/node_modules/phin": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/phin/-/phin-3.7.1.tgz", + "integrity": "sha512-GEazpTWwTZaEQ9RhL7Nyz0WwqilbqgLahDM3D0hxWwmVDI52nXEybHqiN6/elwpkJBhcuj+WbBu+QfT0uhPGfQ==", + "deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.", + "license": "MIT", + "dependencies": { + "centra": "^2.7.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/loader-utils": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-3.3.1.tgz", + "integrity": "sha512-FMJTLMXfCLMLfJxcX9PFqX5qD88Z5MRGaZCVzfuqeZSPsyiBzs+pahDQjbIWz2QIzPZz0NX9Zy4FX3lmK6YHIg==", + "license": "MIT", + "engines": { + "node": ">= 12.13.0" + } + }, + "node_modules/local-pkg": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/local-pkg/-/local-pkg-1.2.1.tgz", + "integrity": "sha512-++gUqRDEvcnN6Zhqrr+y/CkVEHhlrR96vZn3nZZPYzMcBUyBtTKzB9NadClFIsIVSsu+3i9tfk/erqy9kAmt7Q==", + "license": "MIT", + "dependencies": { + "mlly": "^1.7.4", + "pkg-types": "^2.3.0", + "quansync": "^0.2.11" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/local-pkg/node_modules/confbox": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.2.4.tgz", + "integrity": "sha512-ysOGlgTFbN2/Y6Cg3Iye8YKulHw+R2fNXHrgSmXISQdMnomY6eNDprVdW9R5xBguEqI954+S6709UyiO7B+6OQ==", + "license": "MIT" + }, + "node_modules/local-pkg/node_modules/pkg-types": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-2.3.1.tgz", + "integrity": "sha512-y+ichcgc2LrADuhLNAx8DFjVfgz91pRxfZdI3UDhxHvcVEZsenLO+7XaU5vOp0u/7V/wZ+plyuQxtrDlZJ+yeg==", + "license": "MIT", + "dependencies": { + "confbox": "^0.2.4", + "exsolve": "^1.0.8", + "pathe": "^2.0.3" + } + }, + "node_modules/localstorage-polyfill": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/localstorage-polyfill/-/localstorage-polyfill-1.0.1.tgz", + "integrity": "sha512-m4iHVZxFH5734oQcPKU08025gIz2+4bjWR9lulP8ZYxEJR0BpA0w32oJmkzh8y3UI9ci7xCBehQDc3oA1X+VHw==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/lodash": { + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.18.1.tgz", + "integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/lodash.camelcase": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", + "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==", + "license": "MIT" + }, + "node_modules/lodash.debounce": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", + "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", + "dev": true, + "license": "MIT" + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/magic-string": { + "version": "0.30.11", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.11.tgz", + "integrity": "sha512-+Wri9p0QHMy+545hKww7YAu5NyzF8iomPL/RQazugQ9+Ez4Ic3mERMd8ZTX5rfK944j+560ZJi8iAwgak1Ac7A==", + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0" + } + }, + "node_modules/make-dir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", + "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/make-dir/node_modules/semver": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.4.tgz", + "integrity": "sha512-rUCObTnP32Q08R2uuIrt7r9PlEonuTmtuXYcW6s5kjdlj3xbnwe+21yXptAUYcMAABLkYYTtnmzb3w3EDZfueA==", + "dev": true, + "license": "ISC", + "peer": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/makeerror": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", + "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", + "dev": true, + "license": "BSD-3-Clause", + "peer": true, + "dependencies": { + "tmpl": "1.0.5" + } + }, + "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==", + "dev": true, + "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==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/meow": { + "version": "13.2.0", + "resolved": "https://registry.npmjs.org/meow/-/meow-13.2.0.tgz", + "integrity": "sha512-pxQJQzB6djGPXh08dacEloMFopsOqGVRKFPYvPOt9XDZ1HasbgDZA74CJGreSU4G3Ak7EFJGoiH2auq+yXISgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/merge": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/merge/-/merge-2.1.1.tgz", + "integrity": "sha512-jz+Cfrg9GWOZbQAnDQ4hlVnQky+341Yk5ru8bZSe6sIDTCIg8n9i/u7hSQGSVOF3C7lH6mGtqjkiT9G4wFLL0w==", + "license": "MIT" + }, + "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==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true, + "license": "MIT" + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-3.0.0.tgz", + "integrity": "sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==", + "license": "MIT", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "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==", + "dev": true, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/min-document": { + "version": "2.19.2", + "resolved": "https://registry.npmjs.org/min-document/-/min-document-2.19.2.tgz", + "integrity": "sha512-8S5I8db/uZN8r9HSLFVWPdJCvYOejMcEC82VIzNUc6Zkklf/d1gg2psfE79/vyhWOj4+J8MtwmoOz3TmvaGu5A==", + "license": "MIT", + "dependencies": { + "dom-walk": "^0.1.0" + } + }, + "node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "dev": true, + "license": "ISC", + "peer": 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/mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "license": "MIT", + "dependencies": { + "minimist": "^1.2.6" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/mlly": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.8.2.tgz", + "integrity": "sha512-d+ObxMQFmbt10sretNDytwt85VrbkhhUA/JBGm1MPaWJ65Cl4wOgLaB1NYvJSZ0Ef03MMEU/0xpPMXUIQ29UfA==", + "license": "MIT", + "dependencies": { + "acorn": "^8.16.0", + "pathe": "^2.0.3", + "pkg-types": "^1.3.1", + "ufo": "^1.6.3" + } + }, + "node_modules/module-alias": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/module-alias/-/module-alias-2.2.3.tgz", + "integrity": "sha512-23g5BFj4zdQL/b6tor7Ji+QY4pEfNH784BMslY9Qb0UnJWRAt+lQGLYmRaM0KDBwIG23ffEBELhZDP2rhi9f/Q==", + "license": "MIT" + }, + "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/nanoid": { + "version": "3.3.12", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.12.tgz", + "integrity": "sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true, + "license": "MIT", + "peer": true + }, + "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==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "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", + "optional": true + }, + "node_modules/node-int64": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", + "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/node-releases": { + "version": "2.0.47", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.47.tgz", + "integrity": "sha512-Uzmd6LXpouKo8EUK68IjH4+E01w/hXyV3R3g/geCJo+rXLNfh1xucB+LOzYEOQPSiUK3h/xZf0cQGcSsmyL2Og==", + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/normalize-range": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", + "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/nwsapi": { + "version": "2.2.24", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.24.tgz", + "integrity": "sha512-7YRhZ3jS45LwmSCT4b2sVFHt/WuovaktDU07QrtOBY2PXskss5a9jfmR9jptyumwXST+rFjrmppMY1KT/yn35A==", + "dev": true, + "license": "MIT", + "peer": true + }, + "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==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/omggif": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/omggif/-/omggif-1.0.10.tgz", + "integrity": "sha512-LMJTtvgc/nugXj0Vcrrs68Mn2D1r0zf630VNtqtpI1FEO7e+O9FP4gqs9AcnBaSEeoHIPm28u6qgPR0oyEpGSw==", + "license": "MIT" + }, + "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==", + "dev": true, + "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==", + "dev": true, + "license": "ISC", + "peer": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/os-locale-s-fix": { + "version": "1.0.8-fix-1", + "resolved": "https://registry.npmjs.org/os-locale-s-fix/-/os-locale-s-fix-1.0.8-fix-1.tgz", + "integrity": "sha512-Sv0OvhPiMutICiwORAUefv02DCPb62IelBmo8ZsSrRHyI3FStqIWZvjqDkvtjU+lcujo7UNir+dCwKSqlEQ/5w==", + "license": "MIT", + "dependencies": { + "lcid": "^3.0.0" + }, + "engines": { + "node": ">=10", + "yarn": "^1.22.4" + } + }, + "node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/pako": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", + "license": "(MIT AND Zlib)" + }, + "node_modules/parse-bmfont-ascii": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/parse-bmfont-ascii/-/parse-bmfont-ascii-1.0.6.tgz", + "integrity": "sha512-U4RrVsUFCleIOBsIGYOMKjn9PavsGOXxbvYGtMOEfnId0SVNsgehXh1DxUdVPLoxd5mvcEtvmKs2Mmf0Mpa1ZA==", + "license": "MIT" + }, + "node_modules/parse-bmfont-binary": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/parse-bmfont-binary/-/parse-bmfont-binary-1.0.6.tgz", + "integrity": "sha512-GxmsRea0wdGdYthjuUeWTMWPqm2+FAd4GI8vCvhgJsFnoGhTrLhXDDupwTo7rXVAgaLIGoVHDZS9p/5XbSqeWA==", + "license": "MIT" + }, + "node_modules/parse-bmfont-xml": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/parse-bmfont-xml/-/parse-bmfont-xml-1.1.6.tgz", + "integrity": "sha512-0cEliVMZEhrFDwMh4SxIyVJpqYoOWDJ9P895tFuS+XuNzI5UBmBk5U5O4KuJdTnZpSBI4LFA2+ZiJaiwfSwlMA==", + "license": "MIT", + "dependencies": { + "xml-parse-from-string": "^1.0.0", + "xml2js": "^0.5.0" + } + }, + "node_modules/parse-css-font": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-css-font/-/parse-css-font-4.0.0.tgz", + "integrity": "sha512-lnY7dTUfjRXsSo5G5C639L8RaBBaVSgL+5hacIFKsNHzeCJQ5SFSZv1DZmc7+wZv/22PFGOq2YbaEHLdaCS/mQ==", + "license": "MIT", + "dependencies": { + "css-font-size-keywords": "^1.0.0", + "css-font-stretch-keywords": "^1.0.1", + "css-font-style-keywords": "^1.0.1", + "css-font-weight-keywords": "^1.0.0", + "css-list-helpers": "^2.0.0", + "css-system-font-keywords": "^1.0.0", + "unquote": "^1.1.1" + } + }, + "node_modules/parse-headers": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/parse-headers/-/parse-headers-2.0.6.tgz", + "integrity": "sha512-Tz11t3uKztEW5FEVZnj1ox8GKblWn+PvHY9TmJV5Mll2uHEwRdR/5Li1OlXoECjLYkApdhWy44ocONwXLiKO5A==", + "license": "MIT" + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parse-json/node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/parse5": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", + "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "license": "MIT" + }, + "node_modules/path-to-regexp": { + "version": "0.1.10", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.10.tgz", + "integrity": "sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w==", + "dev": true, + "license": "MIT" + }, + "node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "license": "MIT" + }, + "node_modules/phin": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/phin/-/phin-2.9.3.tgz", + "integrity": "sha512-CzFr90qM24ju5f88quFC/6qohjC144rehe5n6DH900lgXmUe86+xCKc10ev56gRKC4/BkHUoG4uSiQgBiIXwDA==", + "deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.", + "license": "MIT" + }, + "node_modules/picocolors": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.0.tgz", + "integrity": "sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw==", + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pirates": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.7.tgz", + "integrity": "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/pixelmatch": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/pixelmatch/-/pixelmatch-4.0.2.tgz", + "integrity": "sha512-J8B6xqiO37sU/gkcMglv6h5Jbd9xNER7aHzpfRdNmV4IbQBzBpe4l9XmbG+xPF/znacgu2jfEw+wHffaq/YkXA==", + "license": "ISC", + "dependencies": { + "pngjs": "^3.0.0" + }, + "bin": { + "pixelmatch": "bin/pixelmatch" + } + }, + "node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-types": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.3.1.tgz", + "integrity": "sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==", + "license": "MIT", + "dependencies": { + "confbox": "^0.1.8", + "mlly": "^1.7.4", + "pathe": "^2.0.1" + } + }, + "node_modules/pngjs": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-3.4.0.tgz", + "integrity": "sha512-NCrCHhWmnQklfH4MtJMRjZ2a8c80qXeMlQMv2uVp9ISJMTt562SbGd6n2oq0PaPgKm7Z6pL9E2UlLIhC+SHL3w==", + "license": "MIT", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/postcss": { + "version": "8.5.15", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.15.tgz", + "integrity": "sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.12", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postcss-import": { + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-14.1.0.tgz", + "integrity": "sha512-flwI+Vgm4SElObFVPpTIT7SU7R3qk2L7PyduMcokiaVKuWv9d/U+Gm/QAd8NDLuykTWTkcrjOeD2Pp1rMeBTGw==", + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.0.0", + "read-cache": "^1.0.0", + "resolve": "^1.1.7" + }, + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "postcss": "^8.0.0" + } + }, + "node_modules/postcss-load-config": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-3.1.4.tgz", + "integrity": "sha512-6DiM4E7v4coTE4uzA8U//WhtPwyhiim3eyjEMFCnUpzbrkK9wJHgKDT2mR+HbtSrd/NubVaYTOpSpjUl8NQeRg==", + "license": "MIT", + "dependencies": { + "lilconfig": "^2.0.5", + "yaml": "^1.10.2" + }, + "engines": { + "node": ">= 10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + "peerDependencies": { + "postcss": ">=8.0.9", + "ts-node": ">=9.0.0" + }, + "peerDependenciesMeta": { + "postcss": { + "optional": true + }, + "ts-node": { + "optional": true + } + } + }, + "node_modules/postcss-modules": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/postcss-modules/-/postcss-modules-4.3.1.tgz", + "integrity": "sha512-ItUhSUxBBdNamkT3KzIZwYNNRFKmkJrofvC2nWab3CPKhYBQ1f27XXh1PAPE27Psx58jeelPsxWB/+og+KEH0Q==", + "license": "MIT", + "dependencies": { + "generic-names": "^4.0.0", + "icss-replace-symbols": "^1.1.0", + "lodash.camelcase": "^4.3.0", + "postcss-modules-extract-imports": "^3.0.0", + "postcss-modules-local-by-default": "^4.0.0", + "postcss-modules-scope": "^3.0.0", + "postcss-modules-values": "^4.0.0", + "string-hash": "^1.1.1" + }, + "peerDependencies": { + "postcss": "^8.0.0" + } + }, + "node_modules/postcss-modules-extract-imports": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.1.0.tgz", + "integrity": "sha512-k3kNe0aNFQDAZGbin48pL2VNidTF0w4/eASDsxlyspobzU3wZQLOGj7L9gfRe0Jo9/4uud09DsjFNH7winGv8Q==", + "license": "ISC", + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-local-by-default": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.2.0.tgz", + "integrity": "sha512-5kcJm/zk+GJDSfw+V/42fJ5fhjL5YbFDl8nVdXkJPLLW+Vf9mTD5Xe0wqIaDnLuL2U6cDNpTr+UQ+v2HWIBhzw==", + "license": "MIT", + "dependencies": { + "icss-utils": "^5.0.0", + "postcss-selector-parser": "^7.0.0", + "postcss-value-parser": "^4.1.0" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-local-by-default/node_modules/postcss-selector-parser": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.4.tgz", + "integrity": "sha512-HeP7D2wyhkR+XaK6v4W8oRF62Dsz4flyuczALJp61GckGm42u1saSSJ/0auvcBqxs3jMRFEcPK34At/0JBKdOg==", + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-modules-scope": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.2.1.tgz", + "integrity": "sha512-m9jZstCVaqGjTAuny8MdgE88scJnCiQSlSrOWcTQgM2t32UBe+MUmFSO5t7VMSfAf/FJKImAxBav8ooCHJXCJA==", + "license": "ISC", + "dependencies": { + "postcss-selector-parser": "^7.0.0" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-scope/node_modules/postcss-selector-parser": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.4.tgz", + "integrity": "sha512-HeP7D2wyhkR+XaK6v4W8oRF62Dsz4flyuczALJp61GckGm42u1saSSJ/0auvcBqxs3jMRFEcPK34At/0JBKdOg==", + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-modules-values": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz", + "integrity": "sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==", + "license": "ISC", + "dependencies": { + "icss-utils": "^5.0.0" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-selector-parser": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", + "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", + "license": "MIT" + }, + "node_modules/postcss/node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "license": "ISC" + }, + "node_modules/pretty-format": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", + "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^17.0.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", + "license": "MIT", + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/prompts": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", + "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" + }, + "engines": { + "node": ">= 6" + } + }, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/psl": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.15.0.tgz", + "integrity": "sha512-JZd3gMVBAVQkSs6HdNZo9Sdo0LNcQeMNP3CozBJb3JYC/QUYZTnKxP+f8oWRX4rHP5EurWxqAHTSwUCjlNKa1w==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "punycode": "^2.3.1" + }, + "funding": { + "url": "https://github.com/sponsors/lupomontero" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/qrcode-reader": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/qrcode-reader/-/qrcode-reader-1.0.4.tgz", + "integrity": "sha512-rRjALGNh9zVqvweg1j5OKIQKNsw3bLC+7qwlnead5K/9cb1cEIAGkwikt/09U0K+2IDWGD9CC6SP7tHAjUeqvQ==", + "license": "Apache-2.0" + }, + "node_modules/qrcode-terminal": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/qrcode-terminal/-/qrcode-terminal-0.12.0.tgz", + "integrity": "sha512-EXtzRZmC+YGmGlDFbXKxQiMZNwCLEO6BANKXG4iCtSIM0yqc/pappSx3RIKr4r0uh5JsBckOXeKrB3Iz7mdQpQ==", + "bin": { + "qrcode-terminal": "bin/qrcode-terminal.js" + } + }, + "node_modules/qs": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/quansync": { + "version": "0.2.11", + "resolved": "https://registry.npmjs.org/quansync/-/quansync-0.2.11.tgz", + "integrity": "sha512-AifT7QEbW9Nri4tAwR5M/uzpBuqfZf+zwaEM/QkzEjj7NBuFD2rBuy0K3dE+8wltbezDV7JMA0WfnCPYRSYbXA==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/antfu" + }, + { + "type": "individual", + "url": "https://github.com/sponsors/sxzz" + } + ], + "license": "MIT" + }, + "node_modules/querystringify": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", + "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "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/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==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", + "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", + "dev": true, + "license": "MIT", + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/react-is": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/read-cache": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", + "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==", + "license": "MIT", + "dependencies": { + "pify": "^2.3.0" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "license": "MIT", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/regenerate": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", + "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==", + "dev": true, + "license": "MIT" + }, + "node_modules/regenerate-unicode-properties": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.2.2.tgz", + "integrity": "sha512-m03P+zhBeQd1RGnYxrGyDAPpWX/epKirLrp8e3qevZdVkKtnCrjjWczIbYc8+xd6vcTStVlqfycTx1KR4LOr0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "regenerate": "^1.4.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regenerator-runtime": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", + "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==", + "dev": true, + "license": "MIT" + }, + "node_modules/regexpu-core": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-6.4.0.tgz", + "integrity": "sha512-0ghuzq67LI9bLXpOX/ISfve/Mq33a4aFRzoQYhnnok1JOFpmE/A2TBGkNVenOGEeSBCjIiWcc6MVOG5HEQv0sA==", + "dev": true, + "license": "MIT", + "dependencies": { + "regenerate": "^1.4.2", + "regenerate-unicode-properties": "^10.2.2", + "regjsgen": "^0.8.0", + "regjsparser": "^0.13.0", + "unicode-match-property-ecmascript": "^2.0.0", + "unicode-match-property-value-ecmascript": "^2.2.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regjsgen": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.8.0.tgz", + "integrity": "sha512-RvwtGe3d7LvWiDQXeQw8p5asZUmfU1G/l6WbUXeHta7Y2PEIvBTwH6E2EfmYUK8pxcxEdEmaomqyp0vZZ7C+3Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/regjsparser": { + "version": "0.13.2", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.13.2.tgz", + "integrity": "sha512-NgRBy2Nx/bE+9F27nVHnqcN5HjyLmecqsqx2PJHu3/IEtADD4WuxuXIVExD5PoSDFVrl78dOonfcOe5O+5nbzQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "jsesc": "~3.1.0" + }, + "bin": { + "regjsparser": "bin/parser" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/resolve": { + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", + "license": "MIT", + "dependencies": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve.exports": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-1.1.1.tgz", + "integrity": "sha512-/NtpHNDN7jWhAaQ9BvBUYZ6YTXsRBgfqWFWP7BZBaoMJO/I3G5OFzvTuWNlZC3aPjins1F+TNrLKsGbH4rfsRQ==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/reusify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "dev": true, + "license": "ISC", + "peer": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rollup": { + "version": "4.62.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.62.0.tgz", + "integrity": "sha512-nc72Wgq62I7rtDV4izT5/aaS0zxy3kttkinf9586ApknY3jZO9NYsmtc24fUckA0X7Q2v+ML4a15pdUlV5V/jA==", + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.9" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.62.0", + "@rollup/rollup-android-arm64": "4.62.0", + "@rollup/rollup-darwin-arm64": "4.62.0", + "@rollup/rollup-darwin-x64": "4.62.0", + "@rollup/rollup-freebsd-arm64": "4.62.0", + "@rollup/rollup-freebsd-x64": "4.62.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.62.0", + "@rollup/rollup-linux-arm-musleabihf": "4.62.0", + "@rollup/rollup-linux-arm64-gnu": "4.62.0", + "@rollup/rollup-linux-arm64-musl": "4.62.0", + "@rollup/rollup-linux-loong64-gnu": "4.62.0", + "@rollup/rollup-linux-loong64-musl": "4.62.0", + "@rollup/rollup-linux-ppc64-gnu": "4.62.0", + "@rollup/rollup-linux-ppc64-musl": "4.62.0", + "@rollup/rollup-linux-riscv64-gnu": "4.62.0", + "@rollup/rollup-linux-riscv64-musl": "4.62.0", + "@rollup/rollup-linux-s390x-gnu": "4.62.0", + "@rollup/rollup-linux-x64-gnu": "4.62.0", + "@rollup/rollup-linux-x64-musl": "4.62.0", + "@rollup/rollup-openbsd-x64": "4.62.0", + "@rollup/rollup-openharmony-arm64": "4.62.0", + "@rollup/rollup-win32-arm64-msvc": "4.62.0", + "@rollup/rollup-win32-ia32-msvc": "4.62.0", + "@rollup/rollup-win32-x64-gnu": "4.62.0", + "@rollup/rollup-win32-x64-msvc": "4.62.0", + "fsevents": "~2.3.2" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/safe-area-insets": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/safe-area-insets/-/safe-area-insets-1.4.1.tgz", + "integrity": "sha512-r/nRWTjFGhhm3w1Z6Kd/jY11srN+lHt2mNl1E/emQGW8ic7n3Avu4noibklfSM+Y34peNphHD/BSZecav0sXYQ==", + "license": "ISC" + }, + "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==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true, + "license": "MIT" + }, + "node_modules/sass": { + "version": "1.101.0", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.101.0.tgz", + "integrity": "sha512-OL3GoQyoUdDt843DpVmDO6y2k1sc5IhUDSpu8XucEI+35neq5QivZ1iuegnpraEVTJXlQGK1gl27zKcTLEPbQw==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "chokidar": "^5.0.0", + "immutable": "^5.1.5", + "source-map-js": ">=0.6.2 <2.0.0" + }, + "bin": { + "sass": "sass.js" + }, + "engines": { + "node": ">=20.19.0" + }, + "optionalDependencies": { + "@parcel/watcher": "^2.4.1" + } + }, + "node_modules/sass/node_modules/chokidar": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-5.0.0.tgz", + "integrity": "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "readdirp": "^5.0.0" + }, + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/sass/node_modules/readdirp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-5.0.0.tgz", + "integrity": "sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/sax": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.6.0.tgz", + "integrity": "sha512-6R3J5M4AcbtLUdZmRv2SygeVaM7IhrLXu9BmnOGmmACak8fiUtOsYNWUS4uK7upbmHIBbLBeFeI//477BKLBzA==", + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=11.0.0" + } + }, + "node_modules/saxes": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/saxes/-/saxes-5.0.1.tgz", + "integrity": "sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw==", + "dev": true, + "license": "ISC", + "peer": true, + "dependencies": { + "xmlchars": "^2.2.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/scule": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/scule/-/scule-1.3.0.tgz", + "integrity": "sha512-6FtHJEvt+pVMIB9IBY+IcCJ6Z5f1iQnytgyfKMhDKgmzYG+TeH/wx1y3l27rshSbLiSanrR9ffZDrEsmjlQF2g==", + "license": "MIT" + }, + "node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/send": { + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", + "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/send/node_modules/debug/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true, + "license": "MIT" + }, + "node_modules/send/node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/send/node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "dev": true, + "license": "MIT", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/serve-static": { + "version": "1.16.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.0.tgz", + "integrity": "sha512-pDLK8zwl2eKaYrs8mrPZBJua4hMplRWJ1tIFksVC3FtBEBnl8dxgeHtsaMS8DhS9i4fLObaon6ABoc4/hQGdPA==", + "dev": true, + "license": "MIT", + "dependencies": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.18.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/serve-static/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/serve-static/node_modules/debug/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true, + "license": "MIT" + }, + "node_modules/serve-static/node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/serve-static/node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "dev": true, + "license": "MIT", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/serve-static/node_modules/send": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", + "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "dev": true, + "license": "ISC" + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/side-channel": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.1.tgz", + "integrity": "sha512-6x6dK6zJdpTzF4sQeNYxwtvBzf6Eg4GtlesS94HOvTudUeyK2WXAaIfmDgsyslYrRBeFIlsi54AYsFGUuhmvrQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.4", + "side-channel-list": "^1.0.1", + "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.1", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.1.tgz", + "integrity": "sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.4" + }, + "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==", + "dev": true, + "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==", + "dev": true, + "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==", + "dev": true, + "license": "ISC" + }, + "node_modules/sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "dev": true, + "license": "BSD-3-Clause", + "peer": true + }, + "node_modules/stack-utils": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", + "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "escape-string-regexp": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/stack-utils/node_modules/escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/string-hash": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/string-hash/-/string-hash-1.1.3.tgz", + "integrity": "sha512-kJUvRUFK49aub+a7T1nNE66EJbZBMnBgoC1UbCZ5n6bsZKBRga4KgBRTMn/pFkeCZSYtNeSyMxPDM0AXWELk2A==", + "license": "CC0-1.0" + }, + "node_modules/string-length": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", + "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "char-regex": "^1.0.2", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "peer": 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==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-bom": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", + "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/strip-literal": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/strip-literal/-/strip-literal-3.1.0.tgz", + "integrity": "sha512-8r3mkIM/2+PpjHoOtiAW8Rg3jJLHaV7xPwG+YRGrv6FP0wwk/toTpATxWYOW0BKdWwl82VT2tFYi5DlROa0Mxg==", + "license": "MIT", + "dependencies": { + "js-tokens": "^9.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/strip-literal/node_modules/js-tokens": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-9.0.1.tgz", + "integrity": "sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==", + "license": "MIT" + }, + "node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "license": "MIT", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/supports-hyperlinks": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.3.0.tgz", + "integrity": "sha512-RpsAZlpWcDwOPQA22aCH4J0t7L8JmAvsCxfOSEwm7cQs3LshN36QaTkwd70DnBOXDWGssw2eUoc8CaRWT0XunA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "has-flag": "^4.0.0", + "supports-color": "^7.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-hyperlinks/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-hyperlinks/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/symbol-tree": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", + "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/systemjs": { + "version": "6.15.1", + "resolved": "https://registry.npmjs.org/systemjs/-/systemjs-6.15.1.tgz", + "integrity": "sha512-Nk8c4lXvMB98MtbmjX7JwJRgJOL8fluecYCfCeYBznwmpOs8Bf15hLM6z4z71EDAhQVrQrI+wt1aLWSXZq+hXA==", + "dev": true, + "license": "MIT" + }, + "node_modules/tapable": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.3.tgz", + "integrity": "sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==", + "license": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/terminal-link": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/terminal-link/-/terminal-link-2.1.1.tgz", + "integrity": "sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "ansi-escapes": "^4.2.1", + "supports-hyperlinks": "^2.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/terser": { + "version": "5.48.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.48.0.tgz", + "integrity": "sha512-J/9An6vs9Us6wKRriSFXBWdRZapREHqFzdNUKk0pmu804EMR6dr6winwo7e5JDxN4xahxQsuysyYFwlwj4XN/Q==", + "devOptional": true, + "license": "BSD-2-Clause", + "dependencies": { + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.15.0", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "bin": { + "terser": "bin/terser" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/test-exclude": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", + "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", + "dev": true, + "license": "ISC", + "peer": true, + "dependencies": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/throat": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/throat/-/throat-6.0.2.tgz", + "integrity": "sha512-WKexMoJj3vEuK0yFEapj8y64V0A6xcuPuK9Gt1d0R+dzCSJc0lHqQytAbSB4cDAK0dWh4T0E2ETkoLE2WZ41OQ==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/timm": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/timm/-/timm-1.7.1.tgz", + "integrity": "sha512-IjZc9KIotudix8bMaBW6QvMuq64BrJWFs1+4V0lXwWGQZwH+LnX87doAYhem4caOEusRP9/g6jVDQmZ8XOk1nw==", + "license": "MIT" + }, + "node_modules/tinycolor2": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/tinycolor2/-/tinycolor2-1.6.0.tgz", + "integrity": "sha512-XPaBkWQJdsf3pLKJV9p4qN/S+fm2Oj8AIPo1BTUhg5oxkvm9+SVEGFdhyOz7tTdUTfvxMiAs4sp6/eZO2Ew+pw==", + "license": "MIT" + }, + "node_modules/tmpl": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", + "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", + "dev": true, + "license": "BSD-3-Clause", + "peer": true + }, + "node_modules/to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "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==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/tough-cookie": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.4.tgz", + "integrity": "sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag==", + "dev": true, + "license": "BSD-3-Clause", + "peer": true, + "dependencies": { + "psl": "^1.1.33", + "punycode": "^2.1.1", + "universalify": "^0.2.0", + "url-parse": "^1.5.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/tough-cookie/node_modules/universalify": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz", + "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/tr46": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-2.1.0.tgz", + "integrity": "sha512-15Ih7phfcdP5YxqiB+iDtLoaTz4Nd35+IiAv0kQ5FNKHzXgdWqPoTIqEDDJmXceQt4JZk6lVPT8lnDlPpGDppw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "punycode": "^2.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "peer": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/typedarray-to-buffer": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", + "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "is-typedarray": "^1.0.0" + } + }, + "node_modules/ufo": { + "version": "1.6.4", + "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.6.4.tgz", + "integrity": "sha512-JFNbkD1Svwe0KvGi8GOeLcP4kAWQ609twvCdcHxq1oSL8svv39ZuSvajcD8B+5D0eL4+s1Is2D/O6KN3qcTeRA==", + "license": "MIT" + }, + "node_modules/undici-types": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.24.6.tgz", + "integrity": "sha512-WRNW+sJgj5OBN4/0JpHFqtqzhpbnV0GuB+OozA9gCL7a993SmU+1JBZCzLNxYsbMfIeDL+lTsphD5jN5N+n0zg==", + "devOptional": true, + "license": "MIT", + "peer": true + }, + "node_modules/unicode-canonical-property-names-ecmascript": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.1.tgz", + "integrity": "sha512-dA8WbNeb2a6oQzAQ55YlT5vQAWGV9WXOsi3SskE3bcCdM0P4SDd+24zS/OCacdRq5BkdsRj9q3Pg6YyQoxIGqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", + "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "unicode-canonical-property-names-ecmascript": "^2.0.0", + "unicode-property-aliases-ecmascript": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-value-ecmascript": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.2.1.tgz", + "integrity": "sha512-JQ84qTuMg4nVkx8ga4A16a1epI9H6uTXAknqxkGF/aFfRLw1xC/Bp24HNLaZhHSkWd3+84t8iXnp1J0kYcZHhg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-property-aliases-ecmascript": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.2.0.tgz", + "integrity": "sha512-hpbDzxUY9BFwX+UeBnxv3Sh1q7HFxj48DTmXchNgRa46lO8uj3/1iEn3MiNUYTg1g9ctIqXCCERn8gYZhHC5lQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/unimport": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/unimport/-/unimport-4.1.1.tgz", + "integrity": "sha512-j9+fijH6aDd05yv1fXlyt7HSxtOWtGtrZeYTVBsSUg57Iuf+Ps2itIZjeyu7bEQ4k0WOgYhHrdW8m/pJgOpl5g==", + "license": "MIT", + "dependencies": { + "acorn": "^8.14.0", + "escape-string-regexp": "^5.0.0", + "estree-walker": "^3.0.3", + "fast-glob": "^3.3.3", + "local-pkg": "^1.0.0", + "magic-string": "^0.30.17", + "mlly": "^1.7.4", + "pathe": "^2.0.2", + "picomatch": "^4.0.2", + "pkg-types": "^1.3.1", + "scule": "^1.3.0", + "strip-literal": "^3.0.0", + "unplugin": "^2.1.2", + "unplugin-utils": "^0.2.3" + }, + "engines": { + "node": ">=18.12.0" + } + }, + "node_modules/unimport/node_modules/escape-string-regexp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", + "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/unimport/node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0" + } + }, + "node_modules/unimport/node_modules/magic-string": { + "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, + "node_modules/unimport/node_modules/picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/unplugin": { + "version": "2.3.11", + "resolved": "https://registry.npmjs.org/unplugin/-/unplugin-2.3.11.tgz", + "integrity": "sha512-5uKD0nqiYVzlmCRs01Fhs2BdkEgBS3SAVP6ndrBsuK42iC2+JHyxM05Rm9G8+5mkmRtzMZGY8Ct5+mliZxU/Ww==", + "license": "MIT", + "dependencies": { + "@jridgewell/remapping": "^2.3.5", + "acorn": "^8.15.0", + "picomatch": "^4.0.3", + "webpack-virtual-modules": "^0.6.2" + }, + "engines": { + "node": ">=18.12.0" + } + }, + "node_modules/unplugin-utils": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/unplugin-utils/-/unplugin-utils-0.2.5.tgz", + "integrity": "sha512-gwXJnPRewT4rT7sBi/IvxKTjsms7jX7QIDLOClApuZwR49SXbrB1z2NLUZ+vDHyqCj/n58OzRRqaW+B8OZi8vg==", + "license": "MIT", + "dependencies": { + "pathe": "^2.0.3", + "picomatch": "^4.0.3" + }, + "engines": { + "node": ">=18.12.0" + }, + "funding": { + "url": "https://github.com/sponsors/sxzz" + } + }, + "node_modules/unplugin-utils/node_modules/picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/unplugin/node_modules/picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/unquote": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/unquote/-/unquote-1.1.1.tgz", + "integrity": "sha512-vRCqFv6UhXpWxZPyGDh/F3ZpNv8/qo7w6iufLpQg9aKnQ71qM4B5KiI7Mia9COcjEhrO9LueHpMYjYzsWH3OIg==", + "license": "MIT" + }, + "node_modules/update-browserslist-db": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", + "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/update-browserslist-db/node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "license": "ISC" + }, + "node_modules/url-parse": { + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", + "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "querystringify": "^2.1.1", + "requires-port": "^1.0.0" + } + }, + "node_modules/utif": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/utif/-/utif-2.0.1.tgz", + "integrity": "sha512-Z/S1fNKCicQTf375lIP9G8Sa1H/phcysstNrrSdZKj1f9g58J4NMgb5IgiEZN9/nLMPDwF0W7hdOe9Qq2IYoLg==", + "license": "MIT", + "dependencies": { + "pako": "^1.0.5" + } + }, + "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==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/uview-plus": { + "version": "3.8.55", + "resolved": "https://registry.npmjs.org/uview-plus/-/uview-plus-3.8.55.tgz", + "integrity": "sha512-OcjitgqLWZzMZuq93YSfpvOzyFvOuhGC6Lh4cljX28bNmDImoe14IhOpW8tcLcjLilbEOZJBYxbvpZpGAdiQxQ==", + "engines": { + "HBuilderX": "^3.1.0", + "uni-app": "^4.66", + "uni-app-x": "" + } + }, + "node_modules/v8-to-istanbul": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-8.1.1.tgz", + "integrity": "sha512-FGtKtv3xIpR6BYhvgH8MI/y78oT7d8Au3ww4QIxymrCtZEh5b8gCw2siywE+puhEmuWKDtmfrvF5UlB298ut3w==", + "dev": true, + "license": "ISC", + "peer": true, + "dependencies": { + "@types/istanbul-lib-coverage": "^2.0.1", + "convert-source-map": "^1.6.0", + "source-map": "^0.7.3" + }, + "engines": { + "node": ">=10.12.0" + } + }, + "node_modules/v8-to-istanbul/node_modules/convert-source-map": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/v8-to-istanbul/node_modules/source-map": { + "version": "0.7.6", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.6.tgz", + "integrity": "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==", + "dev": true, + "license": "BSD-3-Clause", + "peer": true, + "engines": { + "node": ">= 12" + } + }, + "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==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/vite": { + "version": "5.2.8", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.2.8.tgz", + "integrity": "sha512-OyZR+c1CE8yeHw5V5t59aXsUPPVTHMDjEZz8MgguLL/Q7NblxhZUlTu9xSPqlsUO/y+X7dlU05jdhvyycD55DA==", + "license": "MIT", + "dependencies": { + "esbuild": "^0.20.1", + "postcss": "^8.4.38", + "rollup": "^4.13.0" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^18.0.0 || >=20.0.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.4.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + } + } + }, + "node_modules/vue": { + "version": "3.4.21", + "resolved": "https://registry.npmjs.org/vue/-/vue-3.4.21.tgz", + "integrity": "sha512-5hjyV/jLEIKD/jYl4cavMcnzKwjMKohureP8ejn3hhEjwhWIhWeuzL2kJAjzl/WyVsgPY56Sy4Z40C3lVshxXA==", + "license": "MIT", + "dependencies": { + "@vue/compiler-dom": "3.4.21", + "@vue/compiler-sfc": "3.4.21", + "@vue/runtime-dom": "3.4.21", + "@vue/server-renderer": "3.4.21", + "@vue/shared": "3.4.21" + }, + "peerDependencies": { + "typescript": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/vue-i18n": { + "version": "9.14.5", + "resolved": "https://registry.npmjs.org/vue-i18n/-/vue-i18n-9.14.5.tgz", + "integrity": "sha512-0jQ9Em3ymWngyiIkj0+c/k7WgaPO+TNzjKSNq9BvBQaKJECqn9cd9fL4tkDhB5G1QBskGl9YxxbDAhgbFtpe2g==", + "deprecated": "v9 and v10 no longer supported. please migrate to v11. about maintenance status, see https://vue-i18n.intlify.dev/guide/maintenance.html", + "license": "MIT", + "dependencies": { + "@intlify/core-base": "9.14.5", + "@intlify/shared": "9.14.5", + "@vue/devtools-api": "^6.5.0" + }, + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://github.com/sponsors/kazupon" + }, + "peerDependencies": { + "vue": "^3.0.0" + } + }, + "node_modules/vue-i18n/node_modules/@intlify/core-base": { + "version": "9.14.5", + "resolved": "https://registry.npmjs.org/@intlify/core-base/-/core-base-9.14.5.tgz", + "integrity": "sha512-5ah5FqZG4pOoHjkvs8mjtv+gPKYU0zCISaYNjBNNqYiaITxW8ZtVih3GS/oTOqN8d9/mDLyrjD46GBApNxmlsA==", + "license": "MIT", + "dependencies": { + "@intlify/message-compiler": "9.14.5", + "@intlify/shared": "9.14.5" + }, + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://github.com/sponsors/kazupon" + } + }, + "node_modules/vue-i18n/node_modules/@intlify/message-compiler": { + "version": "9.14.5", + "resolved": "https://registry.npmjs.org/@intlify/message-compiler/-/message-compiler-9.14.5.tgz", + "integrity": "sha512-IHzgEu61/YIpQV5Pc3aRWScDcnFKWvQA9kigcINcCBXN8mbW+vk9SK+lDxA6STzKQsVJxUPg9ACC52pKKo3SVQ==", + "license": "MIT", + "dependencies": { + "@intlify/shared": "9.14.5", + "source-map-js": "^1.0.2" + }, + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://github.com/sponsors/kazupon" + } + }, + "node_modules/vue-i18n/node_modules/@intlify/shared": { + "version": "9.14.5", + "resolved": "https://registry.npmjs.org/@intlify/shared/-/shared-9.14.5.tgz", + "integrity": "sha512-9gB+E53BYuAEMhbCAxVgG38EZrk59sxBtv3jSizNL2hEWlgjBjAw1AwpLHtNaeda12pe6W20OGEa0TwuMSRbyQ==", + "license": "MIT", + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://github.com/sponsors/kazupon" + } + }, + "node_modules/vue-router": { + "version": "4.4.4", + "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-4.4.4.tgz", + "integrity": "sha512-3MlnDqwRwZwCQVbtVfpsU+nrNymNjnXSsQtXName5925NVC1+326VVfYH9vSrA0N13teGEo8z5x7gbRnGjCDiQ==", + "license": "MIT", + "dependencies": { + "@vue/devtools-api": "^6.6.4" + }, + "funding": { + "url": "https://github.com/sponsors/posva" + }, + "peerDependencies": { + "vue": "^3.2.0" + } + }, + "node_modules/w3c-hr-time": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz", + "integrity": "sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ==", + "deprecated": "Use your platform's native performance.now() and performance.timeOrigin.", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "browser-process-hrtime": "^1.0.0" + } + }, + "node_modules/w3c-xmlserializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-2.0.0.tgz", + "integrity": "sha512-4tzD0mF8iSiMiNs30BiLO3EpfGLZUT2MSX/G+o7ZywDzliWQ3OPtTZ0PTC3B3ca1UAf4cJMHB+2Bf56EriJuRA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "xml-name-validator": "^3.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/walker": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", + "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", + "dev": true, + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "makeerror": "1.0.12" + } + }, + "node_modules/webidl-conversions": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-6.1.0.tgz", + "integrity": "sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w==", + "dev": true, + "license": "BSD-2-Clause", + "peer": true, + "engines": { + "node": ">=10.4" + } + }, + "node_modules/webpack-virtual-modules": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/webpack-virtual-modules/-/webpack-virtual-modules-0.6.2.tgz", + "integrity": "sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==", + "license": "MIT" + }, + "node_modules/whatwg-encoding": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz", + "integrity": "sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw==", + "deprecated": "Use @exodus/bytes instead for a more spec-conformant and faster implementation", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "iconv-lite": "0.4.24" + } + }, + "node_modules/whatwg-mimetype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz", + "integrity": "sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/whatwg-url": { + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-8.7.0.tgz", + "integrity": "sha512-gAojqb/m9Q8a5IV96E3fHJM70AzCkgt4uXYX2O7EmuyOnLrViCQlsEBmF9UQIu3/aeAIp2U17rtbpZWNntQqdg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "lodash": "^4.7.0", + "tr46": "^2.1.0", + "webidl-conversions": "^6.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/wrap-ansi/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT", + "peer": true + }, + "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==", + "dev": true, + "license": "ISC", + "peer": true + }, + "node_modules/write-file-atomic": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", + "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", + "dev": true, + "license": "ISC", + "peer": true, + "dependencies": { + "imurmurhash": "^0.1.4", + "is-typedarray": "^1.0.0", + "signal-exit": "^3.0.2", + "typedarray-to-buffer": "^3.1.5" + } + }, + "node_modules/ws": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", + "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/xhr": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/xhr/-/xhr-2.6.0.tgz", + "integrity": "sha512-/eCGLb5rxjx5e3mF1A7s+pLlR6CGyqWN91fv1JgER5mVWg1MZmlhBvy9kjcsOdRk8RrIujotWyJamfyrp+WIcA==", + "license": "MIT", + "dependencies": { + "global": "~4.4.0", + "is-function": "^1.0.1", + "parse-headers": "^2.0.0", + "xtend": "^4.0.0" + } + }, + "node_modules/xml-name-validator": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz", + "integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==", + "dev": true, + "license": "Apache-2.0", + "peer": true + }, + "node_modules/xml-parse-from-string": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/xml-parse-from-string/-/xml-parse-from-string-1.0.1.tgz", + "integrity": "sha512-ErcKwJTF54uRzzNMXq2X5sMIy88zJvfN2DmdoQvy7PAFJ+tPRU6ydWuOKNMyfmOjdyBQTFREi60s0Y0SyI0G0g==", + "license": "MIT" + }, + "node_modules/xml2js": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.5.0.tgz", + "integrity": "sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA==", + "license": "MIT", + "dependencies": { + "sax": ">=0.6.0", + "xmlbuilder": "~11.0.0" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/xmlbuilder": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", + "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", + "license": "MIT", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/xmlchars": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", + "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/xmlhttprequest": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/xmlhttprequest/-/xmlhttprequest-1.8.0.tgz", + "integrity": "sha512-58Im/U0mlVBLM38NdZjHyhuMtCqa61469k2YP/AaPbvCoV9aQGUpbJBj1QRm2ytRiVQBD/fsw7L2bJGDVQswBA==", + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/xregexp": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/xregexp/-/xregexp-5.1.2.tgz", + "integrity": "sha512-6hGgEMCGhqCTFEJbqmWrNIPqfpdirdGWkqshu7fFZddmTSfgv5Sn9D2SaKloR79s5VUiUlpwzg3CM3G6D3VIlw==", + "license": "MIT", + "dependencies": { + "@babel/runtime-corejs3": "^7.26.9" + } + }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "license": "MIT", + "engines": { + "node": ">=0.4" + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "license": "ISC", + "peer": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "license": "ISC" + }, + "node_modules/yaml": { + "version": "1.10.3", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.3.tgz", + "integrity": "sha512-vIYeF1u3CjlhAFekPPAk2h/Kv4T3mAkMox5OymRiJQB0spDP10LHvt+K7G9Ny6NuuMAb25/6n1qyUjAcGNf/AA==", + "license": "ISC", + "engines": { + "node": ">= 6" + } + }, + "node_modules/yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs-parser": { + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "dev": true, + "license": "ISC", + "peer": true, + "engines": { + "node": ">=10" + } + } + } +} diff --git a/front/package.json b/front/package.json new file mode 100644 index 0000000..4107680 --- /dev/null +++ b/front/package.json @@ -0,0 +1,69 @@ +{ + "name": "uni-preset-vue", + "version": "0.0.0", + "scripts": { + "dev:custom": "uni -p", + "dev:h5": "uni", + "dev:h5:ssr": "uni --ssr", + "dev:mp-alipay": "uni -p mp-alipay", + "dev:mp-baidu": "uni -p mp-baidu", + "dev:mp-jd": "uni -p mp-jd", + "dev:mp-kuaishou": "uni -p mp-kuaishou", + "dev:mp-lark": "uni -p mp-lark", + "dev:mp-qq": "uni -p mp-qq", + "dev:mp-toutiao": "uni -p mp-toutiao", + "dev:mp-harmony": "uni -p mp-harmony", + "dev:mp-weixin": "uni -p mp-weixin", + "dev:mp-xhs": "uni -p mp-xhs", + "dev:quickapp-webview": "uni -p quickapp-webview", + "dev:quickapp-webview-huawei": "uni -p quickapp-webview-huawei", + "dev:quickapp-webview-union": "uni -p quickapp-webview-union", + "build:custom": "uni build -p", + "build:h5": "uni build", + "build:h5:ssr": "uni build --ssr", + "build:mp-alipay": "uni build -p mp-alipay", + "build:mp-baidu": "uni build -p mp-baidu", + "build:mp-jd": "uni build -p mp-jd", + "build:mp-kuaishou": "uni build -p mp-kuaishou", + "build:mp-lark": "uni build -p mp-lark", + "build:mp-qq": "uni build -p mp-qq", + "build:mp-toutiao": "uni build -p mp-toutiao", + "build:mp-harmony": "uni build -p mp-harmony", + "build:mp-weixin": "uni build -p mp-weixin", + "build:mp-xhs": "uni build -p mp-xhs", + "build:quickapp-webview": "uni build -p quickapp-webview", + "build:quickapp-webview-huawei": "uni build -p quickapp-webview-huawei", + "build:quickapp-webview-union": "uni build -p quickapp-webview-union" + }, + "dependencies": { + "@dcloudio/uni-app": "3.0.0-5000720260410001", + "@dcloudio/uni-app-harmony": "3.0.0-5000720260410001", + "@dcloudio/uni-app-plus": "3.0.0-5000720260410001", + "@dcloudio/uni-components": "3.0.0-5000720260410001", + "@dcloudio/uni-h5": "3.0.0-5000720260410001", + "@dcloudio/uni-mp-alipay": "3.0.0-5000720260410001", + "@dcloudio/uni-mp-baidu": "3.0.0-5000720260410001", + "@dcloudio/uni-mp-harmony": "3.0.0-5000720260410001", + "@dcloudio/uni-mp-jd": "3.0.0-5000720260410001", + "@dcloudio/uni-mp-kuaishou": "3.0.0-5000720260410001", + "@dcloudio/uni-mp-lark": "3.0.0-5000720260410001", + "@dcloudio/uni-mp-qq": "3.0.0-5000720260410001", + "@dcloudio/uni-mp-toutiao": "3.0.0-5000720260410001", + "@dcloudio/uni-mp-weixin": "3.0.0-5000720260410001", + "@dcloudio/uni-mp-xhs": "3.0.0-5000720260410001", + "@dcloudio/uni-quickapp-webview": "3.0.0-5000720260410001", + "uview-plus": "^3.4.41", + "vue": "^3.4.21", + "vue-i18n": "^9.1.9" + }, + "devDependencies": { + "@dcloudio/types": "^3.4.8", + "@dcloudio/uni-automator": "3.0.0-5000720260410001", + "@dcloudio/uni-cli-shared": "3.0.0-5000720260410001", + "@dcloudio/uni-stacktracey": "3.0.0-5000720260410001", + "@dcloudio/vite-plugin-uni": "3.0.0-5000720260410001", + "@vue/runtime-core": "^3.4.21", + "sass": "^1.89.2", + "vite": "5.2.8" + } +} diff --git a/front/shims-uni.d.ts b/front/shims-uni.d.ts new file mode 100644 index 0000000..ed4adcf --- /dev/null +++ b/front/shims-uni.d.ts @@ -0,0 +1,10 @@ +/// +import 'vue' + +declare module '@vue/runtime-core' { + type Hooks = App.AppInstance & Page.PageInstance; + + interface ComponentCustomOptions extends Hooks { + + } +} diff --git a/front/src/App.vue b/front/src/App.vue new file mode 100644 index 0000000..2c347b8 --- /dev/null +++ b/front/src/App.vue @@ -0,0 +1,38 @@ + + + diff --git a/front/src/components/AdminTabbar.vue b/front/src/components/AdminTabbar.vue new file mode 100644 index 0000000..1813ab6 --- /dev/null +++ b/front/src/components/AdminTabbar.vue @@ -0,0 +1,96 @@ + + + + + diff --git a/front/src/config/index.js b/front/src/config/index.js new file mode 100644 index 0000000..000dde7 --- /dev/null +++ b/front/src/config/index.js @@ -0,0 +1,8 @@ +export const API_BASE_URL = import.meta.env.VITE_API_BASE_URL || 'https://lfhedu.ruixininfo.com/api' + +export const POINT_STATUS = { + available: '可用', + pending: '待发放', + frozen: '冻结', + revoked: '已撤销' +} diff --git a/front/src/main.js b/front/src/main.js new file mode 100644 index 0000000..5e50dd1 --- /dev/null +++ b/front/src/main.js @@ -0,0 +1,46 @@ +import { + createSSRApp +} from "vue"; +import App from "./App.vue"; +import uviewPlus from "uview-plus"; +import "uview-plus/index.scss"; +import "./styles/theme.scss"; +import UButton from "uview-plus/components/u-button/u-button.vue"; +import UDatetimePicker from "uview-plus/components/u-datetime-picker/u-datetime-picker.vue"; +import UGap from "uview-plus/components/u-gap/u-gap.vue"; +import UIcon from "uview-plus/components/u-icon/u-icon.vue"; +import UInput from "uview-plus/components/u-input/u-input.vue"; +import ULoadingIcon from "uview-plus/components/u-loading-icon/u-loading-icon.vue"; +import UOverlay from "uview-plus/components/u-overlay/u-overlay.vue"; +import UPicker from "uview-plus/components/u-picker/u-picker.vue"; +import UPopup from "uview-plus/components/u-popup/u-popup.vue"; +import USafeBottom from "uview-plus/components/u-safe-bottom/u-safe-bottom.vue"; +import UStatusBar from "uview-plus/components/u-status-bar/u-status-bar.vue"; +import UTag from "uview-plus/components/u-tag/u-tag.vue"; +import UToast from "uview-plus/components/u-toast/u-toast.vue"; +import UToolbar from "uview-plus/components/u-toolbar/u-toolbar.vue"; +import UTransition from "uview-plus/components/u-transition/u-transition.vue"; + +export function createApp() { + const app = createSSRApp(App); + app.use(uviewPlus); + app.component("u-button", UButton); + app.component("up-datetime-picker", UDatetimePicker); + app.component("u-gap", UGap); + app.component("u-icon", UIcon); + app.component("up-icon", UIcon); + app.component("up-input", UInput); + app.component("u-loading-icon", ULoadingIcon); + app.component("u-overlay", UOverlay); + app.component("u-picker", UPicker); + app.component("u-popup", UPopup); + app.component("u-safe-bottom", USafeBottom); + app.component("u-status-bar", UStatusBar); + app.component("u-tag", UTag); + app.component("u-toast", UToast); + app.component("u-toolbar", UToolbar); + app.component("u-transition", UTransition); + return { + app, + }; +} diff --git a/front/src/manifest.json b/front/src/manifest.json new file mode 100644 index 0000000..7378c69 --- /dev/null +++ b/front/src/manifest.json @@ -0,0 +1,56 @@ +{ + "name": "", + "appid": "", + "description": "", + "versionName": "1.0.0", + "versionCode": "100", + "transformPx": false, + /* 5+App特有相关 */ + "app-plus": { + "usingComponents": true, + "nvueStyleCompiler": "uni-app", + "compilerVersion": 3, + "splashscreen": { + "alwaysShowBeforeRender": true, + "waiting": true, + "autoclose": true, + "delay": 0 + }, + /* 模块配置 */ + "modules": {}, + /* 应用发布信息 */ + "distribute": { + /* android打包配置 */ + "android": { + "permissions": ["", "", "", "", "", "", "", "", "", "", "", "", "", "", ""] + }, + /* ios打包配置 */ + "ios": {}, + /* SDK配置 */ + "sdkConfigs": {} + } + }, + /* 快应用特有相关 */ + "quickapp": {}, + /* 小程序特有相关 */ + "mp-weixin": { + "appid": "wx48e101cff8e91db9", + "setting": { + "urlCheck": false + }, + "usingComponents": true + }, + "mp-alipay": { + "usingComponents": true + }, + "mp-baidu": { + "usingComponents": true + }, + "mp-toutiao": { + "usingComponents": true + }, + "uniStatistics": { + "enable": false + }, + "vueVersion": "3" +} diff --git a/front/src/pages.json b/front/src/pages.json new file mode 100644 index 0000000..9f2acc6 --- /dev/null +++ b/front/src/pages.json @@ -0,0 +1,208 @@ +{ + "easycom": { + "^u-(.*)": "uview-plus/components/u-$1/u-$1.vue" + }, + "pages": [ + { + "path": "pages/index/index", + "style": { + "navigationBarTitleText": "立方和教育", + "navigationStyle": "custom", + "enablePullDownRefresh": true + } + }, + { + "path": "pages/referral/index", + "style": { + "navigationBarTitleText": "推荐有礼", + "navigationStyle": "custom", + "enablePullDownRefresh": true + } + }, + { + "path": "pages/points/index", + "style": { + "navigationBarTitleText": "积分中心", + "navigationStyle": "custom", + "enablePullDownRefresh": true + } + }, + { + "path": "pages/courses/index", + "style": { + "navigationBarTitleText": "课程预约", + "navigationStyle": "custom", + "enablePullDownRefresh": true + } + }, + { + "path": "pages/account/index", + "style": { + "navigationBarTitleText": "我的账号", + "navigationStyle": "custom", + "enablePullDownRefresh": true + } + }, + { + "path": "pages/admin/index", + "style": { + "navigationBarTitleText": "增长管理台", + "navigationStyle": "custom", + "enablePullDownRefresh": true + } + }, + { + "path": "pages/admin-leads/index", + "style": { + "navigationBarTitleText": "线索管理", + "navigationStyle": "custom", + "enablePullDownRefresh": true + } + }, + { + "path": "pages/admin-points/index", + "style": { + "navigationBarTitleText": "积分管理", + "navigationStyle": "custom", + "enablePullDownRefresh": true + } + }, + { + "path": "pages/admin-point-records/index", + "style": { + "navigationBarTitleText": "积分流水", + "navigationStyle": "custom", + "enablePullDownRefresh": true + } + }, + { + "path": "pages/admin-point-accounts/index", + "style": { + "navigationBarTitleText": "积分账户", + "navigationStyle": "custom", + "enablePullDownRefresh": true + } + }, + { + "path": "pages/admin-courses/index", + "style": { + "navigationBarTitleText": "试听管理", + "navigationStyle": "custom", + "enablePullDownRefresh": true + } + }, + { + "path": "pages/admin-course-edit/index", + "style": { + "navigationBarTitleText": "维护试听课", + "navigationStyle": "custom" + } + }, + { + "path": "pages/admin-appointments/index", + "style": { + "navigationBarTitleText": "预约到课", + "navigationStyle": "custom", + "enablePullDownRefresh": true + } + }, + { + "path": "pages/admin-profile/index", + "style": { + "navigationBarTitleText": "管理账号", + "navigationStyle": "custom", + "enablePullDownRefresh": true + } + }, + { + "path": "pages/login/index", + "style": { + "navigationBarTitleText": "账号登录", + "navigationStyle": "custom" + } + }, + { + "path": "pages/campaign/index", + "style": { + "navigationBarTitleText": "成长邀请", + "navigationStyle": "custom" + } + }, + { + "path": "pages/courses-list/index", + "style": { + "navigationBarTitleText": "可约课程", + "navigationStyle": "custom", + "enablePullDownRefresh": true + } + }, + { + "path": "pages/referral-records/index", + "style": { + "navigationBarTitleText": "推荐记录", + "navigationStyle": "custom", + "enablePullDownRefresh": true + } + }, + { + "path": "pages/point-rewards/index", + "style": { + "navigationBarTitleText": "兑换权益", + "navigationStyle": "custom", + "enablePullDownRefresh": true + } + }, + { + "path": "pages/point-records/index", + "style": { + "navigationBarTitleText": "积分记录", + "navigationStyle": "custom", + "enablePullDownRefresh": true + } + } + ], + "tabBar": { + "color": "#6f7c78", + "selectedColor": "#0b4f46", + "backgroundColor": "#fbfcf7", + "borderStyle": "white", + "list": [ + { + "pagePath": "pages/index/index", + "text": "首页", + "iconPath": "static/tabbar/home.png", + "selectedIconPath": "static/tabbar/home-active.png" + }, + { + "pagePath": "pages/referral/index", + "text": "推荐", + "iconPath": "static/tabbar/referral.png", + "selectedIconPath": "static/tabbar/referral-active.png" + }, + { + "pagePath": "pages/points/index", + "text": "积分", + "iconPath": "static/tabbar/points.png", + "selectedIconPath": "static/tabbar/points-active.png" + }, + { + "pagePath": "pages/courses/index", + "text": "课程", + "iconPath": "static/tabbar/courses.png", + "selectedIconPath": "static/tabbar/courses-active.png" + }, + { + "pagePath": "pages/account/index", + "text": "我的", + "iconPath": "static/tabbar/account.png", + "selectedIconPath": "static/tabbar/account-active.png" + } + ] + }, + "globalStyle": { + "navigationBarTextStyle": "white", + "navigationBarTitleText": "立方和教育", + "navigationBarBackgroundColor": "#0b2f2a", + "backgroundColor": "#f3f6ed" + } +} diff --git a/front/src/pages/account/index.vue b/front/src/pages/account/index.vue new file mode 100644 index 0000000..c08a581 --- /dev/null +++ b/front/src/pages/account/index.vue @@ -0,0 +1,594 @@ + + + + + diff --git a/front/src/pages/admin-appointments/index.vue b/front/src/pages/admin-appointments/index.vue new file mode 100644 index 0000000..ee44218 --- /dev/null +++ b/front/src/pages/admin-appointments/index.vue @@ -0,0 +1,327 @@ + + + + + diff --git a/front/src/pages/admin-course-edit/index.vue b/front/src/pages/admin-course-edit/index.vue new file mode 100644 index 0000000..bc7824a --- /dev/null +++ b/front/src/pages/admin-course-edit/index.vue @@ -0,0 +1,514 @@ + + + + + diff --git a/front/src/pages/admin-courses/index.vue b/front/src/pages/admin-courses/index.vue new file mode 100644 index 0000000..ddb841d --- /dev/null +++ b/front/src/pages/admin-courses/index.vue @@ -0,0 +1,566 @@ + + + + + diff --git a/front/src/pages/admin-leads/index.vue b/front/src/pages/admin-leads/index.vue new file mode 100644 index 0000000..59901a5 --- /dev/null +++ b/front/src/pages/admin-leads/index.vue @@ -0,0 +1,509 @@ + + + + + diff --git a/front/src/pages/admin-point-accounts/index.vue b/front/src/pages/admin-point-accounts/index.vue new file mode 100644 index 0000000..f39aed6 --- /dev/null +++ b/front/src/pages/admin-point-accounts/index.vue @@ -0,0 +1,435 @@ + + + + + diff --git a/front/src/pages/admin-point-records/index.vue b/front/src/pages/admin-point-records/index.vue new file mode 100644 index 0000000..19c3548 --- /dev/null +++ b/front/src/pages/admin-point-records/index.vue @@ -0,0 +1,346 @@ + + + + + diff --git a/front/src/pages/admin-points/index.vue b/front/src/pages/admin-points/index.vue new file mode 100644 index 0000000..6f59ac9 --- /dev/null +++ b/front/src/pages/admin-points/index.vue @@ -0,0 +1,474 @@ + + + + + diff --git a/front/src/pages/admin-profile/index.vue b/front/src/pages/admin-profile/index.vue new file mode 100644 index 0000000..593a29c --- /dev/null +++ b/front/src/pages/admin-profile/index.vue @@ -0,0 +1,431 @@ + + + + + diff --git a/front/src/pages/admin/index.vue b/front/src/pages/admin/index.vue new file mode 100644 index 0000000..55092ea --- /dev/null +++ b/front/src/pages/admin/index.vue @@ -0,0 +1,421 @@ + + + + + diff --git a/front/src/pages/campaign/index.vue b/front/src/pages/campaign/index.vue new file mode 100644 index 0000000..0e1b63b --- /dev/null +++ b/front/src/pages/campaign/index.vue @@ -0,0 +1,236 @@ + + + + + diff --git a/front/src/pages/courses-list/index.vue b/front/src/pages/courses-list/index.vue new file mode 100644 index 0000000..583c70b --- /dev/null +++ b/front/src/pages/courses-list/index.vue @@ -0,0 +1,277 @@ + + + + + diff --git a/front/src/pages/courses/index.vue b/front/src/pages/courses/index.vue new file mode 100644 index 0000000..e6abfee --- /dev/null +++ b/front/src/pages/courses/index.vue @@ -0,0 +1,352 @@ + + + + + diff --git a/front/src/pages/index/index.vue b/front/src/pages/index/index.vue new file mode 100644 index 0000000..490f540 --- /dev/null +++ b/front/src/pages/index/index.vue @@ -0,0 +1,457 @@ + + + + + diff --git a/front/src/pages/login/index.vue b/front/src/pages/login/index.vue new file mode 100644 index 0000000..7b39922 --- /dev/null +++ b/front/src/pages/login/index.vue @@ -0,0 +1,425 @@ + + + + + diff --git a/front/src/pages/point-records/index.vue b/front/src/pages/point-records/index.vue new file mode 100644 index 0000000..53cb2f3 --- /dev/null +++ b/front/src/pages/point-records/index.vue @@ -0,0 +1,241 @@ + + + + + diff --git a/front/src/pages/point-rewards/index.vue b/front/src/pages/point-rewards/index.vue new file mode 100644 index 0000000..de98eff --- /dev/null +++ b/front/src/pages/point-rewards/index.vue @@ -0,0 +1,258 @@ + + + + + diff --git a/front/src/pages/points/index.vue b/front/src/pages/points/index.vue new file mode 100644 index 0000000..b52da74 --- /dev/null +++ b/front/src/pages/points/index.vue @@ -0,0 +1,523 @@ + + + + + diff --git a/front/src/pages/referral-records/index.vue b/front/src/pages/referral-records/index.vue new file mode 100644 index 0000000..1d2733e --- /dev/null +++ b/front/src/pages/referral-records/index.vue @@ -0,0 +1,228 @@ + + + + + diff --git a/front/src/pages/referral/index.vue b/front/src/pages/referral/index.vue new file mode 100644 index 0000000..14a5104 --- /dev/null +++ b/front/src/pages/referral/index.vue @@ -0,0 +1,592 @@ + + + + + diff --git a/front/src/services/accountSession.js b/front/src/services/accountSession.js new file mode 100644 index 0000000..1013628 --- /dev/null +++ b/front/src/services/accountSession.js @@ -0,0 +1,38 @@ +import { getCurrentAccount } from './educationApi' + +const STORAGE_KEY = 'lfh_current_account' + +export function getStoredAccount() { + try { + return uni.getStorageSync(STORAGE_KEY) || null + } catch (error) { + return null + } +} + +export function setStoredAccount(account) { + const current = getStoredAccount() + const next = { + ...account, + sessionToken: account?.sessionToken || current?.sessionToken || '', + } + uni.setStorageSync(STORAGE_KEY, next) + return next +} + +export function clearStoredAccount() { + uni.removeStorageSync(STORAGE_KEY) +} + +export async function refreshStoredAccount() { + const current = getStoredAccount() + if (!current?.sessionToken) return current + const response = await getCurrentAccount() + if (response?.ok === false) return current + return setStoredAccount(response?.data || response) +} + +export function isAdminAccount(account = getStoredAccount()) { + if (!account) return false + return ['super_admin', 'campus_admin', 'advisor', 'teacher', 'finance'].includes(account.role) +} diff --git a/front/src/services/educationApi.js b/front/src/services/educationApi.js new file mode 100644 index 0000000..fb1b669 --- /dev/null +++ b/front/src/services/educationApi.js @@ -0,0 +1,186 @@ +import { http } from './http' +import { API_BASE_URL } from '../config' + +function toQuery(params = {}) { + const query = Object.entries(params) + .filter(([, value]) => value !== undefined && value !== null && value !== '') + .map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(value)}`) + .join('&') + return query ? `?${query}` : '' +} + +export function getBootstrap(accountId) { + return http.get(`/bootstrap?accountId=${encodeURIComponent(accountId)}`) +} + +export function loginWithPhone(phone, code, inviterCode = '') { + return http.post('/auth/phone-login', { phone, code, inviterCode }) +} + +export function sendSmsCode(phone, purpose = 'login') { + return http.post('/auth/sms-code', { phone, purpose }) +} + +export function loginWithPassword(account, password) { + return http.post('/auth/login', { account, password }) +} + +export function loginWithWechat(code) { + return http.post('/auth/wechat-login', { code }) +} + +export function bindWechatPhone(payload) { + return http.post('/auth/wechat-bind-phone', payload) +} + +export function getCurrentAccount() { + return http.get('/auth/current') +} + +export function updateProfile(accountId, payload) { + return http.patch(`/auth/profile/${encodeURIComponent(accountId)}`, payload) +} + +export function updatePassword(accountId, payload) { + return http.patch(`/auth/password/${encodeURIComponent(accountId)}`, payload) +} + +export function updateBoundPhone(accountId, payload) { + return http.patch(`/auth/phone/${encodeURIComponent(accountId)}`, payload) +} + +export function uploadAvatar(filePath) { + return new Promise((resolve) => { + const sessionToken = uni.getStorageSync('lfh_current_account')?.sessionToken || '' + uni.uploadFile({ + url: `${API_BASE_URL}/uploads/avatar`, + filePath, + name: 'file', + header: sessionToken ? { Authorization: `Bearer ${sessionToken}` } : {}, + success: (res) => { + try { + resolve(JSON.parse(res.data)) + } catch (error) { + resolve({ ok: false, message: '头像上传响应格式错误' }) + } + }, + fail: () => resolve({ ok: false, message: '头像上传失败' }), + }) + }) +} + +export function getReferralCenter(inviterId) { + return http.get(`/referrals${inviterId ? `?inviterId=${encodeURIComponent(inviterId)}` : ''}`) +} + +export function getReferralRecords(inviterId, filters = {}) { + return http.get(`/referrals${toQuery({ ...filters, inviterId, paged: 1 })}`) +} + +export function createShareMaterial(channel, inviterId) { + return http.post('/referrals/share', { channel, inviterId }) +} + +export function createMiniProgramCode(inviterId) { + return http.post('/referrals/mini-code', { inviterId }) +} + +export function bindReferral(payload) { + return http.post('/referrals/bind', payload) +} + +export function getPointCenter(userId) { + return http.get(`/points/${userId}`) +} + +export function getPointRewards(userId, filters = {}) { + return http.get(`/points/${userId}/rewards${toQuery(filters)}`) +} + +export function getPointTransactions(userId, filters = {}) { + return http.get(`/points/${userId}/transactions${toQuery(filters)}`) +} + +export function getPointRedemptions(userId, filters = {}) { + return http.get(`/points/${userId}/redemptions${toQuery(filters)}`) +} + +export function redeemReward(payload) { + return http.post('/redemptions', payload) +} + +export function getCourses() { + return http.get('/courses') +} + +export function getCoursesPage(filters = {}) { + return http.get(`/courses${toQuery({ ...filters, paged: 1 })}`) +} + +export function getMyAppointments(userId) { + return http.get(`/appointments?userId=${encodeURIComponent(userId)}`) +} + +export function getAdminCourses(filters = {}) { + return http.get(`/admin/courses${toQuery(filters)}`) +} + +export function getAdminCourse(id) { + return http.get(`/admin/courses/${encodeURIComponent(id)}`) +} + +export function getAdminAppointments(filters = {}) { + return http.get(`/admin/appointments${toQuery(filters)}`) +} + +export function attendAdminAppointment(id) { + return http.patch(`/admin/appointments/${encodeURIComponent(id)}/attend`, {}) +} + +export function createAdminCourse(payload) { + return http.post('/admin/courses', payload) +} + +export function updateAdminCourse(id, payload) { + return http.patch(`/admin/courses/${id}`, payload) +} + +export function deleteAdminCourse(id) { + return http.delete(`/admin/courses/${id}`) +} + +export function bookCourse(payload) { + return http.post('/appointments', payload) +} + +export function getAdminDashboard() { + return http.get('/admin/dashboard') +} + +export function getAdminLeads(filters = {}) { + return http.get(`/admin/leads${toQuery(filters)}`) +} + +export function updateLeadStage(id, stage) { + return http.patch(`/admin/leads/${id}/stage`, { stage }) +} + +export function confirmLeadPurchase(id) { + return http.post(`/admin/leads/${id}/purchase`, {}) +} + +export function getAdminPointManager(filters = {}) { + return http.get(`/admin/points${toQuery(filters)}`) +} + +export function getAdminPointAccounts(filters = {}) { + return http.get(`/admin/point-accounts${toQuery(filters)}`) +} + +export function getAdminPointTransactions(filters = {}) { + return http.get(`/admin/point-transactions${toQuery(filters)}`) +} + +export function adjustPoints(payload) { + return http.post('/admin/points/adjust', payload) +} diff --git a/front/src/services/http.js b/front/src/services/http.js new file mode 100644 index 0000000..6a02bb2 --- /dev/null +++ b/front/src/services/http.js @@ -0,0 +1,57 @@ +import { API_BASE_URL } from '../config' + +let requestSequence = 0 + +function getSessionToken() { + try { + return uni.getStorageSync('lfh_current_account')?.sessionToken || '' + } catch (error) { + return '' + } +} + +function request(path, options = {}) { + return new Promise((resolve) => { + const sessionToken = getSessionToken() + const requestPath = options.method === 'GET' || !options.method + ? `${path}${path.includes('?') ? '&' : '?'}_t=${Date.now()}_${requestSequence += 1}` + : path + uni.request({ + url: `${API_BASE_URL}${requestPath}`, + method: options.method || 'GET', + data: options.data || {}, + enableCache: false, + header: { + 'content-type': 'application/json', + 'cache-control': 'no-cache', + ...(sessionToken ? { Authorization: `Bearer ${sessionToken}` } : {}), + ...(options.header || {}), + }, + success: (res) => { + if (res.statusCode >= 200 && res.statusCode < 300) { + resolve(res.data) + return + } + resolve({ ok: false, message: res.data?.message || '请求失败' }) + }, + fail: () => { + resolve({ ok: false, message: '网络异常,请确认后端服务已启动' }) + }, + }) + }) +} + +export const http = { + get(path) { + return request(path, { method: 'GET' }) + }, + post(path, data) { + return request(path, { method: 'POST', data }) + }, + patch(path, data) { + return request(path, { method: 'PATCH', data }) + }, + delete(path) { + return request(path, { method: 'DELETE' }) + }, +} diff --git a/front/src/shime-uni.d.ts b/front/src/shime-uni.d.ts new file mode 100644 index 0000000..b3d3cc9 --- /dev/null +++ b/front/src/shime-uni.d.ts @@ -0,0 +1,6 @@ +export {}; + +declare module "vue" { + type Hooks = App.AppInstance & Page.PageInstance; + interface ComponentCustomOptions extends Hooks {} +} \ No newline at end of file diff --git a/front/src/static/logo.png b/front/src/static/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..b5771e209bb677e2ebd5ff766ad5ee11790f305a GIT binary patch literal 4023 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 SYs}WS&%*SCNx89m_#Dp^b&jdPe4}tn3`z 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

5G!0_A=iur{qm13sO+-~b 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 literal 0 HcmV?d00001 diff --git a/front/src/static/tabbar/account.png b/front/src/static/tabbar/account.png new file mode 100644 index 0000000000000000000000000000000000000000..d1a4ece32351d0fcfca72bf10bc2620412222183 GIT binary patch literal 359 zcmeAS@N?(olHy`uVBq!ia0vp^2_VeD1|%QND7Ro>VAS(;aSW-r_4bw{Uz3A?OJLrc zYpvzi_i_s^@+tlPn^W6$`K#LkYI)K?9bn*KvHkepm95;T|9!h~t?AN94xRZeM~?~% zhS+g3KAkKOV8_X#F~6nZlc$B|gHz{~AEX4buuO4bVzgyhQqRuFBJkkXd%FZC4uuAW z?~K>~XLH}G?q%4$kVU|Of%B9(<0*B;Eq?-qgu3OG7dic0t17VI&rG4Z&_klnw@&`> z{(<{_Yd@!`2Z2mMhx;Z@klD1ifr~NPdxg-Nr43mNZ+R*#@KDJ9mi@|{b*i&K!dv5V z+h|*UpvjCtC*1cuvAkxZ&@SJ@)!T%acKHDX1p?e0N;#`cF6*2UngHn&gR}qu literal 0 HcmV?d00001 diff --git a/front/src/static/tabbar/courses-active.png b/front/src/static/tabbar/courses-active.png new file mode 100644 index 0000000000000000000000000000000000000000..4a4cc6a1975ecdff0d7c13ef1fce11626a5b2ce6 GIT binary patch literal 271 zcmeAS@N?(olHy`uVBq!ia0vp^2_VeD1|%QND7OGo*F0SuLn>~)y>pPa*+9T0@czqg z?Z4s7z6!m^f6tq;`|*61{0R}rVWft<0ft;0}X&UR@{)Ba46o z1CUst(C{_yOIy(VCm$Iv*=w$2T*t`7q0qp<#PL8Rh0lO}MhokPI7XHYapH-`1C9qY z&j8ARq%Bx2S!Xi)9J;36zyQSEAI{HyDj{XJTl&Z$<|zzJXMSiqG291QP{3ux&XFKg y=6sA-5@x3ZOTUh=14IA1EkBcFw!eh9Q{X#e+Pmi9S=thIAOTNTKbLh*2~7Z)9ausD literal 0 HcmV?d00001 diff --git a/front/src/static/tabbar/courses.png b/front/src/static/tabbar/courses.png new file mode 100644 index 0000000000000000000000000000000000000000..bc242c06f6cce59d1aba1df1cf717170b8bc6963 GIT binary patch literal 269 zcmeAS@N?(olHy`uVBq!ia0vp^2_VeD1|%QND7OGoS3F%DLn>~)z2nH&Y#_km_0+6s^oymNLQ7w^iO*jMNn(MAN46hhoQBZ?Q z`#JhKK4X}?;VYLy!&j~cN`F45S+=#Ef5*1*1A}SbP0l+XkKA}?Dm literal 0 HcmV?d00001 diff --git a/front/src/static/tabbar/home-active.png b/front/src/static/tabbar/home-active.png new file mode 100644 index 0000000000000000000000000000000000000000..49d6fed34a4f28b17db045761500a50690556104 GIT binary patch literal 312 zcmeAS@N?(olHy`uVBq!ia0vp^2_VeD1|%QND7OGo|2~)y=}Sw@&0c8 z=x_U_a&t924pi1ZyL05)0c+j`Yg9casX&p{>(V{;VHy&D-z3jH^ih$ehhH(FhU4hr zW)3NNrvpC(n2xmz7}&Kmz@^ON9ye=9{Exq%`KR02QA0-F>4Jd(6I-Kz!I6xXDW?xl zoW63ZdHCb}TULGhd7Ykrd@QKeBj0V1`NxBWf#DgGkBofNM@9yQ4ey)R3zi=V_csxJ z@VzF=eoAo+(EUK*@S!v8Pbn*e11Brk4(P{2c@1&zyCmg-9DzM+_A(!XdnIW7K8ue2 U_P^R!KZ8_yy85}Sb4q9e0FAzGivR!s literal 0 HcmV?d00001 diff --git a/front/src/static/tabbar/home.png b/front/src/static/tabbar/home.png new file mode 100644 index 0000000000000000000000000000000000000000..5c94caad9e9f7844e6e827e6399e33ee824d77c5 GIT binary patch literal 311 zcmeAS@N?(olHy`uVBq!ia0vp^2_VeD1|%QND7OGo|2$nBLn>~)y}gmIDL}yG;`ig* z#QyBwW+tNY;M{Fn^Npqk%NeI^Rq>nzL+N|_z8~jeT|B>bO|XSsOT$M+mLC3v6%_)G zkDWOr$Y)%Ih1en?+dM6ZBT6{9v z`srELAK&QXAGbTcu&J{-)bcS|P_0+KlY!wtOhe~mX9GK+L%-F2Fn!eb<5lM}ra$xi zU$+fP3ZDRq;0^?{>(k R$?gVe^mO%eS?83{1ON)Ea@7C; literal 0 HcmV?d00001 diff --git a/front/src/static/tabbar/points-active.png b/front/src/static/tabbar/points-active.png new file mode 100644 index 0000000000000000000000000000000000000000..c59c544aac04d73a1b3fc51df410145597680119 GIT binary patch literal 446 zcmeAS@N?(olHy`uVBq!ia0vp^2_VeD1|%QND7Ro>U~KhtaSW-r_4bZ;-eCg)mcX~g z`uWBGFRQp4nR^}Tdocf3tT*TG z!}k>zmj3XMwO={+@genx-F$0z)J4s{-Ll`yL7LOrDxmgl1mo^^3q%+Th008A9{wt1 znwM4L)%)Cnvs`*kSWdRK!q%W)CG+q6ojk9}n%8&T@9n}9Y$7+W%4ZRn@cq}$MX|@Z zJ*3%tL?;*ssWmjb+2y&YL0P4Oi9?~Gp_xTR$5=*FA#?BY#u<$_?uBnvVN^bK@#@zF zW|t>Tp5Gu=d?=IYnD43Ods%zqW(C>uNo+JYeQHPZ>c!XE#O^zWxr>({`PaZ&KW{2i zPVgpo9rvc#NsLTyg!v{WEU)QcNq1%OEQmT~z!`4d;@@=m_axVt%K~&qjQ|4jUO!i~ z>v#caw=SBNk>^8Fz4X)Y{PEJILzj;*QuKu;9IR|APG)O87ATChVV&ncwe%JYZ}5Q!V$(*BBWg;Lb?Sq mq_|j+6aWAK00000Af10cjPmXHn4XdV0000~)y>XiNkb?lLP~)y>XiNkb?lLWBQq? z%sZV~I20@QMXL%n#6LdzV;4{v2y}d@u)QDVA@}F{aWB`y+!r%y1f_cPn;4FXJ2uQb zf4{tMzmmf-*L$|Vx)?5sOI!Z>!7)*Mw&kC~$Mw5kyt&A#Ay=EzptqPap@xwq!(i4& z>6+lbKeLK#D&Agr6BGA)(b@ion;61G9T@~&1RPrq2>fT;oOR*zc8?}D!3+0 + + + + + 立方和教育管理端 + + +

+ + + diff --git a/pc-admin/package-lock.json b/pc-admin/package-lock.json new file mode 100644 index 0000000..2e4baea --- /dev/null +++ b/pc-admin/package-lock.json @@ -0,0 +1,2257 @@ +{ + "name": "lifanghe-pc-admin", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "lifanghe-pc-admin", + "version": "1.0.0", + "dependencies": { + "@element-plus/icons-vue": "^2.3.1", + "axios": "^1.7.9", + "echarts": "^5.6.0", + "element-plus": "^2.8.8", + "pinia": "^2.2.6", + "vue": "^3.4.21", + "vue-router": "^4.4.5" + }, + "devDependencies": { + "@vitejs/plugin-vue": "^5.1.4", + "sass": "^1.89.2", + "vite": "^5.2.8" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz", + "integrity": "sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz", + "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.7.tgz", + "integrity": "sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.7" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/types": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.7.tgz", + "integrity": "sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==", + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@ctrl/tinycolor": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@ctrl/tinycolor/-/tinycolor-4.2.0.tgz", + "integrity": "sha512-kzyuwOAQnXJNLS9PSyrk0CWk35nWJW/zl/6KvnTBMFK65gm7U1/Z5BqjxeapjZCIhQcM/DsrEmcbRwDyXyXK4A==", + "license": "MIT", + "engines": { + "node": ">=14" + } + }, + "node_modules/@element-plus/icons-vue": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/@element-plus/icons-vue/-/icons-vue-2.3.2.tgz", + "integrity": "sha512-OzIuTaIfC8QXEPmJvB4Y4kw34rSXdCJzxcD1kFStBvr8bK6X1zQAYDo0CNMjojnfTqRQCJ0I7prlErcoRiET2A==", + "license": "MIT", + "peerDependencies": { + "vue": "^3.2.0" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", + "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz", + "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz", + "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz", + "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", + "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz", + "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz", + "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz", + "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz", + "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz", + "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz", + "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz", + "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz", + "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz", + "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz", + "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz", + "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", + "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", + "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", + "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", + "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz", + "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz", + "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", + "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@floating-ui/core": { + "version": "1.7.5", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.7.5.tgz", + "integrity": "sha512-1Ih4WTWyw0+lKyFMcBHGbb5U5FtuHJuujoyyr5zTaWS5EYMeT6Jb2AuDeftsCsEuchO+mM2ij5+q9crhydzLhQ==", + "license": "MIT", + "dependencies": { + "@floating-ui/utils": "^0.2.11" + } + }, + "node_modules/@floating-ui/dom": { + "version": "1.7.6", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.7.6.tgz", + "integrity": "sha512-9gZSAI5XM36880PPMm//9dfiEngYoC6Am2izES1FF406YFsjvyBMmeJ2g4SAju3xWwtuynNRFL2s9hgxpLI5SQ==", + "license": "MIT", + "dependencies": { + "@floating-ui/core": "^1.7.5", + "@floating-ui/utils": "^0.2.11" + } + }, + "node_modules/@floating-ui/utils": { + "version": "0.2.11", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.11.tgz", + "integrity": "sha512-RiB/yIh78pcIxl6lLMG0CgBXAZ2Y0eVHqMPYugu+9U0AeT6YBeiJpf7lbdJNIugFP5SIjwNRgo4DhR1Qxi26Gg==", + "license": "MIT" + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "license": "MIT" + }, + "node_modules/@parcel/watcher": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.5.6.tgz", + "integrity": "sha512-tmmZ3lQxAe/k/+rNnXQRawJ4NjxO2hqiOLTHvWchtGZULp4RyFeh6aU4XdOYBFe2KE1oShQTv4AblOs2iOrNnQ==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "dependencies": { + "detect-libc": "^2.0.3", + "is-glob": "^4.0.3", + "node-addon-api": "^7.0.0", + "picomatch": "^4.0.3" + }, + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "@parcel/watcher-android-arm64": "2.5.6", + "@parcel/watcher-darwin-arm64": "2.5.6", + "@parcel/watcher-darwin-x64": "2.5.6", + "@parcel/watcher-freebsd-x64": "2.5.6", + "@parcel/watcher-linux-arm-glibc": "2.5.6", + "@parcel/watcher-linux-arm-musl": "2.5.6", + "@parcel/watcher-linux-arm64-glibc": "2.5.6", + "@parcel/watcher-linux-arm64-musl": "2.5.6", + "@parcel/watcher-linux-x64-glibc": "2.5.6", + "@parcel/watcher-linux-x64-musl": "2.5.6", + "@parcel/watcher-win32-arm64": "2.5.6", + "@parcel/watcher-win32-ia32": "2.5.6", + "@parcel/watcher-win32-x64": "2.5.6" + } + }, + "node_modules/@parcel/watcher-android-arm64": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.5.6.tgz", + "integrity": "sha512-YQxSS34tPF/6ZG7r/Ih9xy+kP/WwediEUsqmtf0cuCV5TPPKw/PQHRhueUo6JdeFJaqV3pyjm0GdYjZotbRt/A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-darwin-arm64": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.5.6.tgz", + "integrity": "sha512-Z2ZdrnwyXvvvdtRHLmM4knydIdU9adO3D4n/0cVipF3rRiwP+3/sfzpAwA/qKFL6i1ModaabkU7IbpeMBgiVEA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-darwin-x64": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.5.6.tgz", + "integrity": "sha512-HgvOf3W9dhithcwOWX9uDZyn1lW9R+7tPZ4sug+NGrGIo4Rk1hAXLEbcH1TQSqxts0NYXXlOWqVpvS1SFS4fRg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-freebsd-x64": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.5.6.tgz", + "integrity": "sha512-vJVi8yd/qzJxEKHkeemh7w3YAn6RJCtYlE4HPMoVnCpIXEzSrxErBW5SJBgKLbXU3WdIpkjBTeUNtyBVn8TRng==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm-glibc": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.5.6.tgz", + "integrity": "sha512-9JiYfB6h6BgV50CCfasfLf/uvOcJskMSwcdH1PHH9rvS1IrNy8zad6IUVPVUfmXr+u+Km9IxcfMLzgdOudz9EQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm-musl": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.5.6.tgz", + "integrity": "sha512-Ve3gUCG57nuUUSyjBq/MAM0CzArtuIOxsBdQ+ftz6ho8n7s1i9E1Nmk/xmP323r2YL0SONs1EuwqBp2u1k5fxg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm64-glibc": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.5.6.tgz", + "integrity": "sha512-f2g/DT3NhGPdBmMWYoxixqYr3v/UXcmLOYy16Bx0TM20Tchduwr4EaCbmxh1321TABqPGDpS8D/ggOTaljijOA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm64-musl": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.5.6.tgz", + "integrity": "sha512-qb6naMDGlbCwdhLj6hgoVKJl2odL34z2sqkC7Z6kzir8b5W65WYDpLB6R06KabvZdgoHI/zxke4b3zR0wAbDTA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-x64-glibc": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.5.6.tgz", + "integrity": "sha512-kbT5wvNQlx7NaGjzPFu8nVIW1rWqV780O7ZtkjuWaPUgpv2NMFpjYERVi0UYj1msZNyCzGlaCWEtzc+exjMGbQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-x64-musl": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.5.6.tgz", + "integrity": "sha512-1JRFeC+h7RdXwldHzTsmdtYR/Ku8SylLgTU/reMuqdVD7CtLwf0VR1FqeprZ0eHQkO0vqsbvFLXUmYm/uNKJBg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-win32-arm64": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.5.6.tgz", + "integrity": "sha512-3ukyebjc6eGlw9yRt678DxVF7rjXatWiHvTXqphZLvo7aC5NdEgFufVwjFfY51ijYEWpXbqF5jtrK275z52D4Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-win32-ia32": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.5.6.tgz", + "integrity": "sha512-k35yLp1ZMwwee3Ez/pxBi5cf4AoBKYXj00CZ80jUz5h8prpiaQsiRPKQMxoLstNuqe2vR4RNPEAEcjEFzhEz/g==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-win32-x64": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.5.6.tgz", + "integrity": "sha512-hbQlYcCq5dlAX9Qx+kFb0FHue6vbjlf0FrNzSKdYK2APUf7tGfGxQCk2ihEREmbR6ZMc0MVAD5RIX/41gpUzTw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@popperjs/core": { + "name": "@sxzz/popperjs-es", + "version": "2.11.8", + "resolved": "https://registry.npmjs.org/@sxzz/popperjs-es/-/popperjs-es-2.11.8.tgz", + "integrity": "sha512-wOwESXvvED3S8xBmcPWHs2dUuzrE4XiZeFu7e1hROIJkm02a49N120pmOXxY33sBb6hArItm5W5tcg1cBtV+HQ==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/popperjs" + } + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.62.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.62.0.tgz", + "integrity": "sha512-IPIQ55ythEHkfEd9jMEi32OQ7SxURsGA43JI22lj01OLZNt2NUbJX8YUHxkVWyQ6daHPNn0truF5nSj3DQp6YQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.62.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.62.0.tgz", + "integrity": "sha512-M6s9cr10MibETyo8JsOkq+Lo1+lU6hcvb1MApnUql5qte/5hMEgzlN8/ReIKNfRV8rrqX50W1BX9zoUhC192RA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.62.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.62.0.tgz", + "integrity": "sha512-BqCoMoIbn0keKys+dEAdBa70EtOwV1bEsQCUgU9FdiZmmMge/Zk7LlkYGqbrdHR+Frnt0E1FOanly+rlwvvQzw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.62.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.62.0.tgz", + "integrity": "sha512-SIMzST3VFNXDAbeIWDWiFCNM5qncUBDWaEV7NfE7oZbDt2mgfW4MvbKdbYiGOLoM32gbTv608UMd0XktEYSD7w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.62.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.62.0.tgz", + "integrity": "sha512-ezjfSQMP7ArdUsbBwbQIfwAlhE84I2iVnzQNCFSveqV42q+BmKlzVpf7mxv5EchLcoWU4y6/heFzVg1F+hodUQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.62.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.62.0.tgz", + "integrity": "sha512-9+qTWGW9AZRhnUgwtTwzNwcPlL87ngkeN0LA+q1bADvmY9aNvWaF2TFW8BZgnQPYxpDI7+rMVLivcd4V737TAQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.62.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.62.0.tgz", + "integrity": "sha512-T1dMEQhXA/jkJ/jyMIw9IovK8bSUq7A8kLIlvZTb/6YIVsp2zLavr4F3oyllHWo7eIVJRyE5n3tUjQJEbE1IuQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.62.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.62.0.tgz", + "integrity": "sha512-2as0LgT7qQpyceQq6VUJYnumUMUrgGQCWIiDIN9DE0/tglsk6o66uCB4f3djRawAltvfCNLyZZrsqbPA6inCsA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.62.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.62.0.tgz", + "integrity": "sha512-bVURMg+6eNN9C/yc0aVjooZcwTTtYF4YW3xta5pP0//r3o1V8gXEHXWCndj47w/HhwsFroZrFhR+6uQP5T0n0g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.62.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.62.0.tgz", + "integrity": "sha512-Ful8pM/2yYI83PViWdFdpZhdI8HJ5qsXANe5atypbHDf+KIBBDsZsbyy8hbXnULVvW9NsTh5DHwbcBftyLTfiw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.62.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.62.0.tgz", + "integrity": "sha512-9Gp/DgrkzfUBmNPVTyPTvay+4xEP7M/clXpj3efXBcm6uTIVIgDg4rqUpqKXvLEuFRVuEpSAOkhgNeecvaZ4Cg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-musl": { + "version": "4.62.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.62.0.tgz", + "integrity": "sha512-m9tsJz54LUXkSYM8+8PG81B9IKK5r+2T0clMq4QrS16xFosufU7firBDAZEsDheDs7wTlP7h3++S7lMsU955HA==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.62.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.62.0.tgz", + "integrity": "sha512-3UvJ5PNVU16aJf6M3tFI24pWzAl2/ynfbyRN3ICyQajK1lSkrnVYNnLz3v04J32qKa0FczJc22zeToc0lr2A3w==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-musl": { + "version": "4.62.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.62.0.tgz", + "integrity": "sha512-vRWUAbYLGHBZS6Q8Msb2sfnf1fvJf+47t8l/TwOerM2qArzy+IeNMTHrYLHXh95h8MoatPHI5hhSZNs+mGXKPg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.62.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.62.0.tgz", + "integrity": "sha512-c00T5SYENHAt86cfW47URaP3Us5vLC/4QO7GYud1G5VNRffCwwCuBspwqYrriuJB+5m0WFzClCn9wed0FBjKvg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.62.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.62.0.tgz", + "integrity": "sha512-krrCDilhXOwFkSkO3Wm9I/f9H0L92XHHwy2fwxjukxIbh0dem8gZqOW5Y8BsHrpJv5qwlRBV+Wl4ZFyRWhUpwg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.62.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.62.0.tgz", + "integrity": "sha512-7pfYFSTc4/rUC/FtAI0Qp6QthDBCIi6/AuP1xYqFk5vanI6KnL5dWKP60OM/05LOsbwTmIcvr6eXC4CJuJ75IA==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.62.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.62.0.tgz", + "integrity": "sha512-7SDIalKeIpG0Ifogbbdn58HmSotYMlf23K3dCJEmiVd9Fg36Vmni82iPQec27N3wY4Bvbxftkxz6vSx9OcouTg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.62.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.62.0.tgz", + "integrity": "sha512-eRZevouTH2i1HeAVLqJuLnt256krQkGY0TN6WsTmsIhuzbh457HuWDMakKwmi0Cjadux983CoSr8Lim2QhUIFw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-openbsd-x64": { + "version": "4.62.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.62.0.tgz", + "integrity": "sha512-3oVS7FLGa4U1qcvao9ylGxrjXZyUQqR8UwxEcnUEyPX53O/C/mKDZegNXTdHCP+h3e6ta/f1EN38Yif1mmZHYg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ] + }, + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.62.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.62.0.tgz", + "integrity": "sha512-yTB9TgfWj5wHe5QgktAgXTLLot1gvEjl1NiPPAUiCs4oPrIWFl5V4nC3GrkNdj9LaAU4s94nVrGbGOCqUpyWsg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.62.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.62.0.tgz", + "integrity": "sha512-5LOhoaesY3doG1c+ac/2JtgREpKoJr5bUHH8tKY0V8di7+uSV6BwLs2PlR0/yzefGOkR+wE7ZolZphHCsyG5Rw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.62.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.62.0.tgz", + "integrity": "sha512-yYkWHhmbhRTWTnWos5HC4GcPQfjlzzCNbM9e/+GXrLuaBXYA3qSDR9f0Vgufd5S8yX81U8jPKp7ZnAjZFMtRnw==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.62.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.62.0.tgz", + "integrity": "sha512-SoTb6lPg25xZlA2ibwQ++ahCCnH+FP0qmEuafMJ4gznZKOlXioKEAeJLgCrqjM98ACziXM9V1amFjICVL4IFoA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.62.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.62.0.tgz", + "integrity": "sha512-5L+T1fMX4RIEBoZzT0+sQ0PhTS36NULFmMXtl1TZo44TMAROIMHbZufSOjVWt/Y622BtxgxtaNOokbTDvfsrZA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@types/estree": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz", + "integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/lodash": { + "version": "4.17.24", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.24.tgz", + "integrity": "sha512-gIW7lQLZbue7lRSWEFql49QJJWThrTFFeIMJdp3eH4tKoxm1OvEPg02rm4wCCSHS0cL3/Fizimb35b7k8atwsQ==", + "license": "MIT" + }, + "node_modules/@types/lodash-es": { + "version": "4.17.12", + "resolved": "https://registry.npmjs.org/@types/lodash-es/-/lodash-es-4.17.12.tgz", + "integrity": "sha512-0NgftHUcV4v34VhXm8QBSftKVXtbkBG3ViCjs6+eJ5a6y6Mi/jiFGPc1sC7QK+9BFhWrURE3EOggmWaSxL9OzQ==", + "license": "MIT", + "dependencies": { + "@types/lodash": "*" + } + }, + "node_modules/@types/web-bluetooth": { + "version": "0.0.21", + "resolved": "https://registry.npmjs.org/@types/web-bluetooth/-/web-bluetooth-0.0.21.tgz", + "integrity": "sha512-oIQLCGWtcFZy2JW77j9k8nHzAOpqMHLQejDA48XXMWH6tjCQHz5RCFz1bzsmROyL6PUm+LLnUiI4BCn221inxA==", + "license": "MIT" + }, + "node_modules/@vitejs/plugin-vue": { + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-5.2.4.tgz", + "integrity": "sha512-7Yx/SXSOcQq5HiiV3orevHUFn+pmMB4cgbEkDYgnkUWb0WfeQ/wa2yFv6D5ICiCQOVpjA7vYDXrC7AGO8yjDHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "peerDependencies": { + "vite": "^5.0.0 || ^6.0.0", + "vue": "^3.2.25" + } + }, + "node_modules/@vue/compiler-core": { + "version": "3.5.38", + "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.38.tgz", + "integrity": "sha512-s99aGxWYig9ErHbct27KXEGhrBYlRI6c4MwAgXErOAbX9xiW37/uMa+XUDO69zLz83dng8UUZ70CTOJrLrYrEQ==", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.29.7", + "@vue/shared": "3.5.38", + "entities": "^7.0.1", + "estree-walker": "^2.0.2", + "source-map-js": "^1.2.1" + } + }, + "node_modules/@vue/compiler-dom": { + "version": "3.5.38", + "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.38.tgz", + "integrity": "sha512-JTqp25l8aFfJYF7/KmsXZjAxJz7T+SjmTJLoXVjHtc2BrSgSiW2n9Aem/cWq1OPe68A8JL06B3eVdhlP0H4TVw==", + "license": "MIT", + "dependencies": { + "@vue/compiler-core": "3.5.38", + "@vue/shared": "3.5.38" + } + }, + "node_modules/@vue/compiler-sfc": { + "version": "3.5.38", + "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.38.tgz", + "integrity": "sha512-DuA2GiZawSEW442iw/9+Fkol8hTgb4Ke5KkhmSry65QA7YuyMbIdy8p0XZRMvNwJdgRz307W8g1CSzdvS4nuNg==", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.29.7", + "@vue/compiler-core": "3.5.38", + "@vue/compiler-dom": "3.5.38", + "@vue/compiler-ssr": "3.5.38", + "@vue/shared": "3.5.38", + "estree-walker": "^2.0.2", + "magic-string": "^0.30.21", + "postcss": "^8.5.15", + "source-map-js": "^1.2.1" + } + }, + "node_modules/@vue/compiler-ssr": { + "version": "3.5.38", + "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.38.tgz", + "integrity": "sha512-7s+W5Gc42FGxZMcuwl8H5B29T8BJPMdBT7KHFE+BbAuZ/iTEdTtv7z2XiMjiaUUw4w3ZcCEdHs36RuYJ2VA7bA==", + "license": "MIT", + "dependencies": { + "@vue/compiler-dom": "3.5.38", + "@vue/shared": "3.5.38" + } + }, + "node_modules/@vue/devtools-api": { + "version": "6.6.4", + "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-6.6.4.tgz", + "integrity": "sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g==", + "license": "MIT" + }, + "node_modules/@vue/reactivity": { + "version": "3.5.38", + "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.38.tgz", + "integrity": "sha512-pG6LV/NDNRbKizcUjFFLAfjaL8mcv4DmR9avNcUw2gDHBzZneuS2TWCmp633ynzxz9YYKNeEPK2I8Wraqy2HUQ==", + "license": "MIT", + "dependencies": { + "@vue/shared": "3.5.38" + } + }, + "node_modules/@vue/runtime-core": { + "version": "3.5.38", + "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.38.tgz", + "integrity": "sha512-iyW8WVfF1CpCXxncZY5Ei6rSd6oZr5DgEom//fUjRBRl56AXPD+s9ATvukRt77ZFTuYlnVA1bxY+dJB94tWVYw==", + "license": "MIT", + "dependencies": { + "@vue/reactivity": "3.5.38", + "@vue/shared": "3.5.38" + } + }, + "node_modules/@vue/runtime-dom": { + "version": "3.5.38", + "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.38.tgz", + "integrity": "sha512-apX2wt9sdfDshS+a2xueFZLVpt0GkRJZSoPmrW/SA4yzXTznhfcMVW59gr7h4YQeY0vJhdJkk2rsIDwgfFgC5A==", + "license": "MIT", + "dependencies": { + "@vue/reactivity": "3.5.38", + "@vue/runtime-core": "3.5.38", + "@vue/shared": "3.5.38", + "csstype": "^3.2.3" + } + }, + "node_modules/@vue/server-renderer": { + "version": "3.5.38", + "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.38.tgz", + "integrity": "sha512-vue8vbf2QlV4quHqzwmJy6dWfmRhP1J8l4wtZg60CL6VoKqcPY2oe7may3+1d9qfpedjK5PRLFqd5k3Isj9mUw==", + "license": "MIT", + "dependencies": { + "@vue/compiler-ssr": "3.5.38", + "@vue/shared": "3.5.38" + }, + "peerDependencies": { + "vue": "3.5.38" + } + }, + "node_modules/@vue/shared": { + "version": "3.5.38", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.38.tgz", + "integrity": "sha512-FTW0AFZNaK5/mOqvGBwVfUlNLU38TiQn4+DQgIFUnrBBJQ1crMJ82yeGQLV5jyKFsO8yRukpbuP7x+nRbH6aug==", + "license": "MIT" + }, + "node_modules/@vueuse/core": { + "version": "14.3.0", + "resolved": "https://registry.npmjs.org/@vueuse/core/-/core-14.3.0.tgz", + "integrity": "sha512-aHfz47g0ZhMtTVHmIzMVpJy8ePhhOy68GY5bv110+5DVtZ+W7BsOx+m61UNQqfrWyPztIHIanWa3E2tib3NFIw==", + "license": "MIT", + "dependencies": { + "@types/web-bluetooth": "^0.0.21", + "@vueuse/metadata": "14.3.0", + "@vueuse/shared": "14.3.0" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "vue": "^3.5.0" + } + }, + "node_modules/@vueuse/metadata": { + "version": "14.3.0", + "resolved": "https://registry.npmjs.org/@vueuse/metadata/-/metadata-14.3.0.tgz", + "integrity": "sha512-BwxmbAzwAVF50+MW57GXOUEV61nFBGnlBvrTqj49PqWJu3uw7hdu72ztXeZ33RdZtDY6kO+bfCAE1PCn88Tktw==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/@vueuse/shared": { + "version": "14.3.0", + "resolved": "https://registry.npmjs.org/@vueuse/shared/-/shared-14.3.0.tgz", + "integrity": "sha512-bZpge9eSXwa4ToSiqJ7j6KRwhAsneMFoSz3LMWKQDkqimm3D/tbFlrklrs/IOqC8tEcYmXQZJ6N0UrjhBirVCg==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "vue": "^3.5.0" + } + }, + "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", + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/async-validator": { + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/async-validator/-/async-validator-4.2.5.tgz", + "integrity": "sha512-7HhHjtERjqlNbZtqNqy2rckN/SpOOlmDliet+lP7k+eKZEjPk3DgyeU9lIXLdeLz0uBbbVp+9Qdow9wJWgwwfg==", + "license": "MIT" + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "license": "MIT" + }, + "node_modules/axios": { + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.18.0.tgz", + "integrity": "sha512-E32NzpYKp++W7XRe52rHiXV2ehxmh3wbdgO7MHeFM+vqxLBYHzt0ElkiImtOBxtOmyp0yoC8C6uESVV84Y2/hw==", + "license": "MIT", + "dependencies": { + "follow-redirects": "^1.16.0", + "form-data": "^4.0.5", + "https-proxy-agent": "^5.0.1", + "proxy-from-env": "^2.1.0" + } + }, + "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/chokidar": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-5.0.0.tgz", + "integrity": "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==", + "dev": true, + "license": "MIT", + "dependencies": { + "readdirp": "^5.0.0" + }, + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "license": "MIT", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/csstype": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", + "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", + "license": "MIT" + }, + "node_modules/dayjs": { + "version": "1.11.21", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.21.tgz", + "integrity": "sha512-98IT+HOahAisibz/yjKbzuOBwYcjJ7BCLPzARyHiyEBmRz4fatF+KPJszEHXsGYjUG234aH/cOjW1wwTbKUZlA==", + "license": "MIT" + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "dev": true, + "license": "Apache-2.0", + "optional": true, + "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/echarts": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/echarts/-/echarts-5.6.0.tgz", + "integrity": "sha512-oTbVTsXfKuEhxftHqL5xprgLoc0k7uScAwtryCgWF6hPYFLRwOUHiFmHGCBKP5NPFNkDVopOieyUqYGH8Fa3kA==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "2.3.0", + "zrender": "5.6.1" + } + }, + "node_modules/element-plus": { + "version": "2.14.2", + "resolved": "https://registry.npmjs.org/element-plus/-/element-plus-2.14.2.tgz", + "integrity": "sha512-eNH9uP3wQoNqieEIHXiNvIVv+zO5sZDU0CAZq5b0zqSN06DD0/V9xIq1R/qm3rw5k3nBTM1JvpxhCfRbaFLzDQ==", + "license": "MIT", + "dependencies": { + "@ctrl/tinycolor": "^4.2.0", + "@element-plus/icons-vue": "^2.3.2", + "@floating-ui/dom": "^1.7.6", + "@popperjs/core": "npm:@sxzz/popperjs-es@^2.11.8", + "@types/lodash": "^4.17.24", + "@types/lodash-es": "^4.17.12", + "@vueuse/core": "14.3.0", + "async-validator": "^4.2.5", + "dayjs": "^1.11.20", + "lodash": "^4.18.1", + "lodash-es": "^4.18.1", + "lodash-unified": "^1.0.3", + "memoize-one": "^6.0.0", + "normalize-wheel-es": "^1.2.0", + "vue-component-type-helpers": "^3.3.3" + }, + "peerDependencies": { + "vue": "^3.3.7" + } + }, + "node_modules/entities": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-7.0.1.tgz", + "integrity": "sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "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.2", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.2.tgz", + "integrity": "sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/esbuild": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", + "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.21.5", + "@esbuild/android-arm": "0.21.5", + "@esbuild/android-arm64": "0.21.5", + "@esbuild/android-x64": "0.21.5", + "@esbuild/darwin-arm64": "0.21.5", + "@esbuild/darwin-x64": "0.21.5", + "@esbuild/freebsd-arm64": "0.21.5", + "@esbuild/freebsd-x64": "0.21.5", + "@esbuild/linux-arm": "0.21.5", + "@esbuild/linux-arm64": "0.21.5", + "@esbuild/linux-ia32": "0.21.5", + "@esbuild/linux-loong64": "0.21.5", + "@esbuild/linux-mips64el": "0.21.5", + "@esbuild/linux-ppc64": "0.21.5", + "@esbuild/linux-riscv64": "0.21.5", + "@esbuild/linux-s390x": "0.21.5", + "@esbuild/linux-x64": "0.21.5", + "@esbuild/netbsd-x64": "0.21.5", + "@esbuild/openbsd-x64": "0.21.5", + "@esbuild/sunos-x64": "0.21.5", + "@esbuild/win32-arm64": "0.21.5", + "@esbuild/win32-ia32": "0.21.5", + "@esbuild/win32-x64": "0.21.5" + } + }, + "node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "license": "MIT" + }, + "node_modules/follow-redirects": { + "version": "1.16.0", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.16.0.tgz", + "integrity": "sha512-y5rN/uOsadFT/JfYwhxRS5R7Qce+g3zG97+JrtFZlC9klX/W5hD7iiLzScI4nZqUS7DNUdhPgw4xI8W2LuXlUw==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "license": "MIT", + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/form-data": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.6.tgz", + "integrity": "sha512-vKatAh4SlVfgbv+YtmhiRjhEMJsYpsG1Y2rMQtR+SVSbytsSD1YGzDIcrAJmdFec88u/+VoGmxnl+80gL1tRCQ==", + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.4", + "mime-types": "^2.1.35" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "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/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/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/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.4.tgz", + "integrity": "sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "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", + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/immutable": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-5.1.6.tgz", + "integrity": "sha512-q1swsS8K7L8usSHuOqF2TAoCCkonYz0SG38wLAggaa4Wml70zixIvt2ql4coQ2C2B3hTjltJry4r6bULwgAXLQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/lodash": { + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.18.1.tgz", + "integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==", + "license": "MIT" + }, + "node_modules/lodash-es": { + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.18.1.tgz", + "integrity": "sha512-J8xewKD/Gk22OZbhpOVSwcs60zhd95ESDwezOFuA3/099925PdHJ7OFHNTGtajL3AlZkykD32HykiMo+BIBI8A==", + "license": "MIT" + }, + "node_modules/lodash-unified": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/lodash-unified/-/lodash-unified-1.0.3.tgz", + "integrity": "sha512-WK9qSozxXOD7ZJQlpSqOT+om2ZfcT4yO+03FuzAHD0wF6S0l0090LRPDx3vhTTLZ8cFKpBn+IOcVXK6qOcIlfQ==", + "license": "MIT", + "peerDependencies": { + "@types/lodash-es": "*", + "lodash": "*", + "lodash-es": "*" + } + }, + "node_modules/magic-string": { + "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, + "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/memoize-one": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-6.0.0.tgz", + "integrity": "sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==", + "license": "MIT" + }, + "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/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/nanoid": { + "version": "3.3.12", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.12.tgz", + "integrity": "sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "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==", + "dev": true, + "license": "MIT", + "optional": true + }, + "node_modules/normalize-wheel-es": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/normalize-wheel-es/-/normalize-wheel-es-1.2.0.tgz", + "integrity": "sha512-Wj7+EJQ8mSuXr2iWfnujrimU35R2W4FAErEyTmJoJ7ucwTn2hOUSsRehMb5RSYkxXGTM7Y9QpvPmp++w5ftoJw==", + "license": "BSD-3-Clause" + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pinia": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/pinia/-/pinia-2.3.1.tgz", + "integrity": "sha512-khUlZSwt9xXCaTbbxFYBKDc/bWAGWJjOgvxETwkTN7KRm66EeT1ZdZj6i2ceh9sP2Pzqsbc704r2yngBrxBVug==", + "license": "MIT", + "dependencies": { + "@vue/devtools-api": "^6.6.3", + "vue-demi": "^0.14.10" + }, + "funding": { + "url": "https://github.com/sponsors/posva" + }, + "peerDependencies": { + "typescript": ">=4.4.4", + "vue": "^2.7.0 || ^3.5.11" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/postcss": { + "version": "8.5.15", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.15.tgz", + "integrity": "sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.12", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/proxy-from-env": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-2.1.0.tgz", + "integrity": "sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA==", + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/readdirp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-5.0.0.tgz", + "integrity": "sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/rollup": { + "version": "4.62.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.62.0.tgz", + "integrity": "sha512-nc72Wgq62I7rtDV4izT5/aaS0zxy3kttkinf9586ApknY3jZO9NYsmtc24fUckA0X7Q2v+ML4a15pdUlV5V/jA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.9" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.62.0", + "@rollup/rollup-android-arm64": "4.62.0", + "@rollup/rollup-darwin-arm64": "4.62.0", + "@rollup/rollup-darwin-x64": "4.62.0", + "@rollup/rollup-freebsd-arm64": "4.62.0", + "@rollup/rollup-freebsd-x64": "4.62.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.62.0", + "@rollup/rollup-linux-arm-musleabihf": "4.62.0", + "@rollup/rollup-linux-arm64-gnu": "4.62.0", + "@rollup/rollup-linux-arm64-musl": "4.62.0", + "@rollup/rollup-linux-loong64-gnu": "4.62.0", + "@rollup/rollup-linux-loong64-musl": "4.62.0", + "@rollup/rollup-linux-ppc64-gnu": "4.62.0", + "@rollup/rollup-linux-ppc64-musl": "4.62.0", + "@rollup/rollup-linux-riscv64-gnu": "4.62.0", + "@rollup/rollup-linux-riscv64-musl": "4.62.0", + "@rollup/rollup-linux-s390x-gnu": "4.62.0", + "@rollup/rollup-linux-x64-gnu": "4.62.0", + "@rollup/rollup-linux-x64-musl": "4.62.0", + "@rollup/rollup-openbsd-x64": "4.62.0", + "@rollup/rollup-openharmony-arm64": "4.62.0", + "@rollup/rollup-win32-arm64-msvc": "4.62.0", + "@rollup/rollup-win32-ia32-msvc": "4.62.0", + "@rollup/rollup-win32-x64-gnu": "4.62.0", + "@rollup/rollup-win32-x64-msvc": "4.62.0", + "fsevents": "~2.3.2" + } + }, + "node_modules/sass": { + "version": "1.101.0", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.101.0.tgz", + "integrity": "sha512-OL3GoQyoUdDt843DpVmDO6y2k1sc5IhUDSpu8XucEI+35neq5QivZ1iuegnpraEVTJXlQGK1gl27zKcTLEPbQw==", + "dev": true, + "license": "MIT", + "dependencies": { + "chokidar": "^5.0.0", + "immutable": "^5.1.5", + "source-map-js": ">=0.6.2 <2.0.0" + }, + "bin": { + "sass": "sass.js" + }, + "engines": { + "node": ">=20.19.0" + }, + "optionalDependencies": { + "@parcel/watcher": "^2.4.1" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/tslib": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.0.tgz", + "integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==", + "license": "0BSD" + }, + "node_modules/vite": { + "version": "5.4.21", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.21.tgz", + "integrity": "sha512-o5a9xKjbtuhY6Bi5S3+HvbRERmouabWbyUcpXXUA1u+GNUKoROi9byOJ8M0nHbHYHkYICiMlqxkg1KkYmm25Sw==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.21.3", + "postcss": "^8.4.43", + "rollup": "^4.20.0" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^18.0.0 || >=20.0.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "sass-embedded": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.4.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + } + } + }, + "node_modules/vue": { + "version": "3.5.38", + "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.38.tgz", + "integrity": "sha512-vAMKHfImQlYSy0C+PBue4s3ERZ2xGKfgZg5GXAsLInq1dyh2H78ILVP5sK0KPFPVW4kv+OGCIvBEondcjpZp7A==", + "license": "MIT", + "dependencies": { + "@vue/compiler-dom": "3.5.38", + "@vue/compiler-sfc": "3.5.38", + "@vue/runtime-dom": "3.5.38", + "@vue/server-renderer": "3.5.38", + "@vue/shared": "3.5.38" + }, + "peerDependencies": { + "typescript": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/vue-component-type-helpers": { + "version": "3.3.5", + "resolved": "https://registry.npmjs.org/vue-component-type-helpers/-/vue-component-type-helpers-3.3.5.tgz", + "integrity": "sha512-Fe1jyPJoUGpJOYKOri44jduR7My4yYINOMJISuMAbmrs+L5LbIDUc8NTWZYY3EJLK0yPLuCmcd5zoCsE4k2/KA==", + "license": "MIT" + }, + "node_modules/vue-demi": { + "version": "0.14.10", + "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.10.tgz", + "integrity": "sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==", + "hasInstallScript": true, + "license": "MIT", + "bin": { + "vue-demi-fix": "bin/vue-demi-fix.js", + "vue-demi-switch": "bin/vue-demi-switch.js" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "@vue/composition-api": "^1.0.0-rc.1", + "vue": "^3.0.0-0 || ^2.6.0" + }, + "peerDependenciesMeta": { + "@vue/composition-api": { + "optional": true + } + } + }, + "node_modules/vue-router": { + "version": "4.6.4", + "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-4.6.4.tgz", + "integrity": "sha512-Hz9q5sa33Yhduglwz6g9skT8OBPii+4bFn88w6J+J4MfEo4KRRpmiNG/hHHkdbRFlLBOqxN8y8gf2Fb0MTUgVg==", + "license": "MIT", + "dependencies": { + "@vue/devtools-api": "^6.6.4" + }, + "funding": { + "url": "https://github.com/sponsors/posva" + }, + "peerDependencies": { + "vue": "^3.5.0" + } + }, + "node_modules/zrender": { + "version": "5.6.1", + "resolved": "https://registry.npmjs.org/zrender/-/zrender-5.6.1.tgz", + "integrity": "sha512-OFXkDJKcrlx5su2XbzJvj/34Q3m6PvyCZkVPHGYpcCJ52ek4U/ymZyfuV1nKE23AyBJ51E/6Yr0mhZ7xGTO4ag==", + "license": "BSD-3-Clause", + "dependencies": { + "tslib": "2.3.0" + } + } + } +} diff --git a/pc-admin/package.json b/pc-admin/package.json new file mode 100644 index 0000000..98ee8af --- /dev/null +++ b/pc-admin/package.json @@ -0,0 +1,24 @@ +{ + "name": "lifanghe-pc-admin", + "version": "1.0.0", + "private": true, + "scripts": { + "dev": "vite --host 127.0.0.1 --port 5174", + "build": "vite build", + "preview": "vite preview --host 127.0.0.1 --port 4174" + }, + "dependencies": { + "@element-plus/icons-vue": "^2.3.1", + "axios": "^1.7.9", + "echarts": "^5.6.0", + "element-plus": "^2.8.8", + "pinia": "^2.2.6", + "vue": "^3.4.21", + "vue-router": "^4.4.5" + }, + "devDependencies": { + "@vitejs/plugin-vue": "^5.1.4", + "sass": "^1.89.2", + "vite": "^5.2.8" + } +} diff --git a/pc-admin/src/App.vue b/pc-admin/src/App.vue new file mode 100644 index 0000000..98240ae --- /dev/null +++ b/pc-admin/src/App.vue @@ -0,0 +1,3 @@ + diff --git a/pc-admin/src/api/courses/trial.js b/pc-admin/src/api/courses/trial.js new file mode 100644 index 0000000..7ab2b53 --- /dev/null +++ b/pc-admin/src/api/courses/trial.js @@ -0,0 +1,47 @@ +import request from '@/utils/request' + +export function getTrialCourses(params = {}) { + return request({ + url: '/admin/courses', + method: 'get', + params, + }) +} + +export function getAppointments(params = {}) { + return request({ + url: '/admin/appointments', + method: 'get', + params, + }) +} + +export function attendAppointment(id) { + return request({ + url: `/admin/appointments/${id}/attend`, + method: 'patch', + }) +} + +export function createTrialCourse(data) { + return request({ + url: '/admin/courses', + method: 'post', + data, + }) +} + +export function updateTrialCourse(id, data) { + return request({ + url: `/admin/courses/${id}`, + method: 'patch', + data, + }) +} + +export function deleteTrialCourse(id) { + return request({ + url: `/admin/courses/${id}`, + method: 'delete', + }) +} diff --git a/pc-admin/src/api/leads/index.js b/pc-admin/src/api/leads/index.js new file mode 100644 index 0000000..fbe170f --- /dev/null +++ b/pc-admin/src/api/leads/index.js @@ -0,0 +1,24 @@ +import request from '@/utils/request' + +export function getLeads(params = {}) { + return request({ + url: '/admin/leads', + method: 'get', + params, + }) +} + +export function updateLeadStage(id, stage) { + return request({ + url: `/admin/leads/${id}/stage`, + method: 'patch', + data: { stage }, + }) +} + +export function confirmLeadPurchase(id) { + return request({ + url: `/admin/leads/${id}/purchase`, + method: 'post', + }) +} diff --git a/pc-admin/src/api/login.js b/pc-admin/src/api/login.js new file mode 100644 index 0000000..e35d134 --- /dev/null +++ b/pc-admin/src/api/login.js @@ -0,0 +1,32 @@ +import request from '@/utils/request' + +export function login(data) { + return request({ + url: '/auth/login', + method: 'post', + data, + }) +} + +export function getInfo() { + return request({ + url: '/auth/current', + method: 'get', + }) +} + +export function updatePassword(accountId, data) { + return request({ + url: `/auth/password/${accountId}`, + method: 'patch', + data, + }) +} + +export function updateProfile(accountId, data) { + return request({ + url: `/auth/profile/${accountId}`, + method: 'patch', + data, + }) +} diff --git a/pc-admin/src/api/points/manager.js b/pc-admin/src/api/points/manager.js new file mode 100644 index 0000000..5d5f8f7 --- /dev/null +++ b/pc-admin/src/api/points/manager.js @@ -0,0 +1,89 @@ +import request from '@/utils/request' + +function toQuery(filters = {}) { + const query = new URLSearchParams() + Object.entries(filters).forEach(([key, value]) => { + if (Array.isArray(value)) { + if (value.length) query.append(key, value.join(',')) + return + } + if (value !== undefined && value !== null && value !== '') query.append(key, value) + }) + const value = query.toString() + return value ? `?${value}` : '' +} + +export function getPointManager() { + return request({ + url: '/admin/points', + method: 'get', + }) +} + +export function listPointAccounts(filters = {}) { + return request({ + url: `/admin/point-accounts${toQuery(filters)}`, + method: 'get', + }) +} + +export function listPointTransactions(filters = {}) { + return request({ + url: `/admin/point-transactions${toQuery(filters)}`, + method: 'get', + }) +} + +export function adjustPoints(data) { + return request({ + url: '/admin/points/adjust', + method: 'post', + data, + }) +} + +export function settlePendingPoints(data) { + return request({ + url: '/admin/points/settle-pending', + method: 'post', + data, + }) +} + +export function updateReferralRule(event, data) { + return request({ + url: `/admin/referral-rules/${event}`, + method: 'patch', + data, + }) +} + +export function listRewards(filters = {}) { + return request({ + url: `/admin/rewards${toQuery(filters)}`, + method: 'get', + }) +} + +export function getRewardDetail(id) { + return request({ + url: `/admin/rewards/${id}`, + method: 'get', + }) +} + +export function createReward(data) { + return request({ + url: '/admin/rewards', + method: 'post', + data, + }) +} + +export function updateReward(id, data) { + return request({ + url: `/admin/rewards/${id}`, + method: 'patch', + data, + }) +} diff --git a/pc-admin/src/api/points/redemption.js b/pc-admin/src/api/points/redemption.js new file mode 100644 index 0000000..09cd59c --- /dev/null +++ b/pc-admin/src/api/points/redemption.js @@ -0,0 +1,41 @@ +import request from '@/utils/request' + +function toQuery(filters = {}) { + const query = new URLSearchParams() + Object.entries(filters).forEach(([key, value]) => { + if (value !== undefined && value !== null && value !== '') query.append(key, value) + }) + const value = query.toString() + return value ? `?${value}` : '' +} + +export function listRedemptions(filters = {}) { + return request({ + url: `/admin/redemptions${toQuery(filters)}`, + method: 'get', + }) +} + +export function approveRedemption(id, data = {}) { + return request({ + url: `/admin/redemptions/${id}/approve`, + method: 'patch', + data, + }) +} + +export function rejectRedemption(id, data = {}) { + return request({ + url: `/admin/redemptions/${id}/reject`, + method: 'patch', + data, + }) +} + +export function verifyVoucher(data = {}) { + return request({ + url: '/admin/vouchers/verify', + method: 'post', + data, + }) +} diff --git a/pc-admin/src/api/statistics/dashboard.js b/pc-admin/src/api/statistics/dashboard.js new file mode 100644 index 0000000..88dee37 --- /dev/null +++ b/pc-admin/src/api/statistics/dashboard.js @@ -0,0 +1,9 @@ +import request from '@/utils/request' + +export function getPcOverview(params) { + return request({ + url: '/admin/pc-overview', + method: 'get', + params, + }) +} diff --git a/pc-admin/src/api/system/account.js b/pc-admin/src/api/system/account.js new file mode 100644 index 0000000..1af6aa2 --- /dev/null +++ b/pc-admin/src/api/system/account.js @@ -0,0 +1,48 @@ +import request from '@/utils/request' + +export function listAccounts(params = {}) { + return request({ + url: '/admin/accounts', + method: 'get', + params, + }) +} + +export function createAccount(data) { + return request({ + url: '/admin/accounts', + method: 'post', + data, + }) +} + +export function updateAccount(id, data) { + return request({ + url: `/admin/accounts/${id}`, + method: 'patch', + data, + }) +} + +export function deleteAccount(id) { + return request({ + url: `/admin/accounts/${id}`, + method: 'delete', + }) +} + +export function changeAccountRole(id, role) { + return request({ + url: `/admin/accounts/${id}/role`, + method: 'patch', + data: { role }, + }) +} + +export function changeAccountStatus(id, status) { + return request({ + url: `/admin/accounts/${id}/status`, + method: 'patch', + data: { status }, + }) +} diff --git a/pc-admin/src/api/system/role.js b/pc-admin/src/api/system/role.js new file mode 100644 index 0000000..5695fad --- /dev/null +++ b/pc-admin/src/api/system/role.js @@ -0,0 +1,16 @@ +import request from '@/utils/request' + +export function listRoles() { + return request({ + url: '/admin/roles', + method: 'get', + }) +} + +export function updateRolePermissions(role, permissions) { + return request({ + url: `/admin/roles/${role}/permissions`, + method: 'patch', + data: { permissions }, + }) +} diff --git a/pc-admin/src/api/upload.js b/pc-admin/src/api/upload.js new file mode 100644 index 0000000..439a3f1 --- /dev/null +++ b/pc-admin/src/api/upload.js @@ -0,0 +1,11 @@ +import request from '@/utils/request' + +export function uploadAvatar(file) { + const formData = new FormData() + formData.append('file', file) + return request({ + url: '/uploads/avatar', + method: 'post', + data: formData, + }) +} diff --git a/pc-admin/src/assets/images/login-learning-studio.webp b/pc-admin/src/assets/images/login-learning-studio.webp new file mode 100644 index 0000000000000000000000000000000000000000..6ed526e6e8d1732d0baf1a6565cd47778292306b GIT binary patch literal 94452 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%0A-h(?g_Yfy_0Hizg;21@8N5>81w&k^4`EwC3 zHETHt*0rA^6*mRRNkH#$>gl{;_NU1& zE%5_6@Z@rJ8i7<^HBT(Q;dMfIC8uq3vc4=vomEW`5GGF5Ry1QJG0-F^NZ2r4_YM_b zAZIpSpxrTV56w(3*bX1sdQ5K2U|K_B@>0(c9{n^FR#hwG98)JU*cA7#yE9>HwRlL( z;f;huR>*CoGs5D(#~J^S^76Pl%b}Y%)3v_PO=yYC*{l(O(z2=QL*a_Cbv1_=v*yXi|99`f+HU2vD3vErE2|V#sI#ID@uhEQ2RYm^=_oKp&6JPIuPi);a~EQqZ37j}5^kXmn4Q z!l9@0Kg=aD@1)L?2l!jrs$Q2?Bmy6Z`yxRF^u~{@rzI;M^Dnb8)I8F0;C=w(h|S>8 zo8Tr-v=AoIxCqW*X65xinWvW?UoI}ZWerTjTVhiv9Fn%2_H)fU5D_@GaR38|Mv zzy#wwzA#P~{cMK^Y?YA!6D~1C1joUn_^|n1(Ty9?@4PxLp|C1RYox=HRklgw;tA`e zr8lK@b{T#D>2INxlff{w5=h zDvwD_D0d~V!~o^7m34yEqS(J11@93QFLRg23Q41B^<1dLpoq*YcAL+x>h5Pu%M8uL zEVn+?n`S>;Ojj&q#bx3y-Hya(XK+Oj63E6j%^S>0{68JW&3P!& zCF8s%Z&}2CTwxy&=$BFSD%lr8^t|nI)LCJzU0P*m-vg=Wv_?2S1t}l=hcmKX{`~P2 z(2dC~a>9rJAy}tQPCd;QWo^MG55l@4bp6iNEl16vx~$gV%nk71YL11xnGWR^g=l;> ztHm8p*sY~gtp}K2;+oJ!gx^$lgfQ5kUi<)MXgV2EDeI;@eg3LiKdU5;J{zHW^G1Ei zDDs^q7IfV4WYn1aG0}~ZKN{-cfCj4&_y}oa-P)muf#)`KpBlMYkTFy75#i=u5Lih?ct3xYt}OA-KB zUysJadDXD+BKJ}Ik=-=4Go?p zzNE(Y&2$vKXQJI2>1+h zUPwME8mDK+kt1kzt{k7Ug42*%jL@0=$X5C5klYKvR`;rzfSrl=Chezbf*XpBzBVC8Xa#by$9VU`XT`{}JF9ZsRd|1s4Vt z_c-pSH}KX`SyH#OZ3hndM^RGm1fxcdmx7B2y;ut=7CSZ^kbT=wfVHQffe(nIYtsKA zqDO2Ca0{x%lPY-G=Iuo8_jh{Q`-1Oo5s^=&forP$v=OPzrH;rInJceec$qaNJ|}+d zkrKp(HcidBYt}`z$`&KG~c!_g!YN=fmEQwbXcf8|B;%2abH8*n$H z{h$i}2h*rBK4h&U{0(>ppLrK++pAT&_Cdp50qH@s2dj&I!NB`k)JY%j#Qkfrc)8OpDY-OT^gMq{%C!;;^9LI>D=q1GnRmHnJ6SkN z!ku(Y&tuPbt<*O4cqqt-;{ZD@Ia@pNAW?l|tJDmH!Zhp|4`q%Uw$`8hyr#+C?oc><&;Psz zNhD_HS-h~bfgI9JSRZk5?Yg23(LYF?#*A(8Rn)=#x)&HNOd$7kL^Gbk%rN;(%iup= z?W6)m&v;+6H}CSkGbm*3<>}v@g$47#(U=Lto&ovNjHATsmV1C{!ln?`zi3(M) zg$EUzO&k5age#lU8=fj;-^0FNjG;@Qr8Cil)@v?1izg{B<`(&(^*`weHfj9#JYq+> z1E7>t&&TW*v}pc3^zvl|UZXx;7lOAmIJGsf#lMSBG-Wn%+w6tzZ*exSc$D;xG7D21Q9o|-d+>EDlk%ks{<2f@9R+zjGb#hPOXDK`Uy zj*7*94Y?$#JrPNIJ=PjDUG++@VU+zZMkQc)wh)2QDSRD!^+`%GOx6a_Sdj}u zKTz_|&fjd$l|L#!!wza9<7TKYu_~G7R4%Bjf_Yp&MFBI zm8={4_rku)KsY;;ww+QO%Gs%*2Q%_W0mxgHrTCEC0Uz3*Ql+3896}s ze^*+7x-Dqmu*CN~DOD+zgv&;%jR7YFZr#$uMmBXC5J$J**OG?Ila!J_)K6tYTCupq!Z{%DmU9(iUW+sOim2d-CD78DHHUw7D^GLPdN5zcSUa z|L;Q6d#(Z^J&8v5<*kZFiEP+hAdi>9@R^iikhiC$lg_4>07#ORHbzGX!%%DReTj%w`amHG#c1QX=VF4*Odv! z4M~6L4DsWnA-o$(@m!2-T*wzzA0EvXY=XnKU*fYv;kUs<2dq6TztGp>#@xnqC2?W9 zHPw}I9(WeBbo*RvhXHVX4_VN@aQudFvc=x;$6H^Jz#8M2`1pX zf=VctsS2B#REC{JYf`6r@^W&k&(q2ehG{wnw3Tje5@#`r8g9jY#Rx zhOEgBU?eJp6VQPRELGz0KX^o9z0u6oVnNTqk;L}N;>Ozt?GBxd<4Uo8C-k*lWk4VH zr$9uBIezIY>dQo@$ApZ_`4liJyc8(-vj`p;O0 zy}nf5)h8x4*W4)znI4zp-RjUm^4iV76BkYb!kbqPvMYD>pUV_Sj4tFl!E_RiO+(>5h_!dFfsh>WNeI`-PBK) z(lM-q^ zbb;a_PF%fWid72&&aDDA%t z`jYbjDHfd5^X6FtE*Zih4-k*9mN)5(KiE|Fr_jn=#IpB`2w6#(%92x|7Y?K*x0vLI z38;AWH>+9pbGwj7^i8JUQ9f%^lg>#0k30FT&3Ly0tgZPlTiS-7gM-16%Betfrxq3} z%MGBPV4N+dHzJW3af4yBz^*?Q8l_MLQT_Gn`CcSBlNAAaU*UD_)eNgHZ7ic+e=&{f zRPegmo@Q2jxLQeqU9KF6Cg*x@z-6zIntjH^UF!g0br%eP?t?K6vJL(ZVnAJUh z(b7>TLvsRZG|Y-@-bb${WBIU&nKUE|MLP_PoSW$xiJ(0Uy?j$!5S3JinH=S~{)QQ@ zHQ2_W(RHYb|17SvkM4?NW!y~j2i;u~+`IM5M(cyV1U}rlYCh4$SOK>Te`Fxe>=>|)! z?4L*cMTy7i2UftF^1Lm%YSX8tiZQB?E-T%o9EI=G6u3deIR1Xo%}n-X5(`Jq+Fhit zivM#MW$HZcwb114Y>aCR9dhHD%uK1VW#?hM4-2_79+?*{?Kn=}!otRqgJ#fGGr~nh z?@eAU%O7tW&w=6u!;P5{f(CG%Fn|2KIg#&yz8G!QjPVZWfHz>Ce0 zd&hqcAp#)`Ey(t-E=tbwIL;5R^aGD?PfEA6!@7Ew?eib9a!c!?9GY|rt z9(L1uf??B9*-{W@&SKM?5kK#e0fXu;L|Zir4_j3%ESi>KRKAuXY6Oh3i! zO$jKT%S$**t+I2vttSz)w>0RZL&X{Wn6mr)o-E8ubv;3wrug5bW=R1o{K9_54Ba>n zt{wdq?--}XDf2n^oJf|Sw+_~=DA9?AK>3lSb{5>_hQDU#*3~i0*y88`9{btXyg@ls zYY;8VzF)%3sH9B-zAvqU6a&c3Nb$aF6vE7SwG7z}g> z-i{Q(;h4!;7J25(4$hLUCGj-_h?%Zq%F@T|+&C!iTmL$^KRcHWof)J2q7_eQ46%wt z{bt#QzELg+`zPJQHbI3vDuCruE0WA^ld-Sam(~mWQCX) z(I3TwsLWls7x#gc8<-~iZx{d)k)>JZx!1x6tJ>s9Lup63x8D{Uwx$uXPMiPr)bP9n z2!m*G6cq&pcaHmF&Nkuj@YKFN&0#N%OCb~p)}^{sX95ACS(&Fzyo5aiWz_;#uM}>~ zxEs5PR#Otk$^`$A-#4g>?rBZJFfrHE>fhQ6*Lo0}m*qV{9vUR^Gyvu@m8`*Fz2?t3 zue&+~p3hZ_)EA>+qprTyQYnbf=xfX8@AH@vk|Z&dUa@yL^0v)MYSW|cx`GU3ejPW$ zDKnuXZ^g?jXGHO5{fe~P{?k|6r1yYmUL+KiK04vf4EyUF z?)u^73)1SKU{z3^=`d>OQU5dHaFrOW*&1FXS?MkaJbPqa!Z3Vj8q71gKkM+cp>9Hb zkr`3?gq}@<6pv+pJXD8L3GYYW9U78tpJmMGJ~aBB1~I%`DYoys5$BnUUFge`%Q_Ld z%*qDP@Y84>!%3m9u!}b4s7rc$e|c%<2IX3`Vki%cwyZ78a%`)F9$Fl8Fy7STJ^;1n z&vRc$j7lTc86k7(J!VGmy*jkLkTR7p#OW96j^>aFd@jyo-zov8p+9ZNaQM>xgiFD7 zcBI8xI9#qR32y$CC|3%g>Itv*CtXwa-LL8Kt{O-Cq<(4ev}_?&;-QIb7LnkRX1`AU zG6qjk;L@2oy#!GzLBL@a4co45|VOwho| zetXi557;y4CRpb9y)R&5^c2aE^pVDQ*ATDI-W%wqD(w2ryO(L)P#~)y-uWu65ZH^ zUZr>M09YL$A*6-8{GY0ns{*bXqew>qeLGTY z+*q#zDL8{#<82tRA|p}_*Gg2D-W)m_9C5icVg(uFJ~?Lf8zY#r?4s)PFqa0f?58rT z+KA4dlOdbDhulP?>Hgw#LDq^El|i<{+E|+TX3*t-^!~)TnlH7;yd|n9qe9F`LWkXz zf5LEkJbr6HCx-N>;`iCe;P^`y5JzC~I>s<(Li)6m#^~n*rt}Mn>Mg~9bQQS{dH+UM zQ>-w5I)AeAS#V2TOp?Chp&B0PW$+{#Ay-a)#O7Mj<7bZJ)6U_~LctE_E!Ar-{0II@ z@KU~@!Dm?pz#a;zy-#<^*9rUQ6(b~=dP@Dsv?e0OE1WaNgs?`dN@WMK5o!^dqh{-G z<8-&<2DijG?DxmuPr@bsf z!=m-3f?PbMt`ngl<6i`1aC&_-tHVwp1e2z{kKFEkQh>XZQzv7ADE>F^nPb}N602~3 z&76F{lQP_`^OJ#VYA<=U`oNVOYgMpY<+hr08)8`tL{dCMGrRhN#Lq?{eb;_IKBcgx9HdQto zdcQxu&#CN?Z_?(LpNXN*&50&{;U3Y?o1VftceX}b*MTjhxO7FmSH-QOExws^FkT-# zT}nkKOyCcY%dpdQssqn2e5NCra`>B&xWGJ&YFy1gzJX28O}`Km`=o6A3jy-N8)rB) ztF1ptMJU>PFP-lGE)Lu;pQSl=`9pcm@dt5+;+43T-O?WvUfu5XIrgw+6o|R&Lu@%l z-O3v#UX*#ek1NfD7F$sm#CZY#!IeUE??3=%-EkI>=&)8>t1RS5@S&GowpCSu4`+(R zoq{oo>D$OGN;^^x-Ycp^D;Z2F7z|1?3jQPY02<}o|H8EaiILwF+H3VoM3PmIX}01i zRCcM7s8pl2s_I6ED3n05Qful46&jy^D&_$8Mcej~qb}fIOjC?=%<^(V6Mx@=sC9Z) z)sm{9-7i^1!%8<)ZuX@b4`l3Z@J)x-x;&S`@tj)lT1OaN(9SkE92rgu_z>y+)_h`M z^8(5CVUuU-m~pz@5FBF^6Mo#;?V2VT(|;)N$pE5Yffg(gb#!#7nT!$hzi>nPw7J59 zNTv!dV@dK7+jUADehyu{Q&2+9?!;etZ4}(dh`xy}0Pq#29k1CYZwEmm6cUa&b-mYG zjOxmlFkA^vWj9Ecw}d)$*Q~CUPbNwMm0AH<3k;g(vr5wU$yoUF=jeYKb5!DrdxoYG z%Cd*l0pz~y0JofqxgUiVS*DCo$-P9rwk&G~O%zr6`zYtcU4#Nj4N;K0cBgEWuWrec z#AsXR=J`}`Fni3y<_r-QxL+ZZU%SV*Y(D4fvn5D5=j0COS8R1Z4NW4EN64N-6_>KH zz8-73u~2f2CR-sowkBs9A)CW;H^!j2&p}L%(RUQRkeVTd>b}G~${UMSVKTR*r;FuA zFJ8#MOo?_Be7&K^1g7zr35p`7o&Bt&ajO?>2VuduRJ@)nWf|{@CFds?8epU}t7WNU z4qY5-sAO;|&oVmpOXVJB4DxI>g;~StPWjKJ+)89jhilen_Ze0irQ`|>Emb3TW_v-> zmtfHo1~o0fmx9{b|9zw(RPAeb$sO${X8{QT&bV%B=qn3qo&&t){UU)=N7Slkv2IWG zCDkoLg9#4%MDmL{Q~%9@@ZW&3%`Q=`%j9eM7rIVo-}`_sCI#@U3!^>pz`dLBUD~uy zw=fMI-5yPuc$IsFJ0R$=nG?4f0*No$Idbb+Va_2nwP;*kR=!RjFOKNOSIr1g{Qlf3 zf!*52@HGC%MBaa!zs$?ofszS)!t8i8_$2!J!C*^RJtmj|#q- zPQA4-kniki*@5H4#kL6RtW(^4!N>dO(EMv2me;aMz)<(LaN*je7`0s10 z5x_SeVRXd_sJZiwtqvUBBjO^fm``&pBvCivFAJpnB??aA#cx)>R~9SFi+qVYf1RCl zfSGF!O>R<}u?a%X1N{pz$%+B{4eWy(HD6FY!0KWhg2q0?Ea=aFC=ba?ZY@k!Q^Igp z?IG1I$6`#i#C;}sbc|4WAqi7?Shzq!yaNr}-B%+c(Ay>C5Il-45T%SEee7lxhNWki z%oi#9U-$LJJAJDBFoCjSuE7mu)Pk1j3ayyMwD7ZujER@9*74;~=TD6WnGMd)&XYnkwx3w9O z?QUK&3GkOcJv&^yEs)BH{%n{3K|uNrjmP+myL$JA*4K;AHJbYSLK+& zf4+MJ-V`kBv_RGL!rJ*3cZy^+0ZfcCfwNS;!W`9TJT_aM@dv)itpZ9ZEE|zdo%jxIFY5ymi-! z=samA-yRZf_uzA`AnBBv08%}^JmP*Frr*SkONj`GkuF+$6tR-}^2cpnyh{?0( zb5hRK-VKa2oInvGXYWVpgNH%voc8hef1yijDIvY+?JzIJ69KtcU#9Rad576%-j(I^IkH7*4=dO&gArp!1S@S zHSqn~*98Nfd#QFVqKk|_SptGWZCrL#IwCAJ>XPq2C!)Kdtb(ivqUawk4-jP<`{+ne z0H`at;35;D5!AV6z!C%`gLtIkL8)3>B2J$UCJgVdY@U|kTJ3-RQ*ZA}(Wk)tm&%S( z<70R)rTV&BaSyu`bRv9U;-?Byae3+YhDR`bTJnYCedO)TGWc%Gp zZy#4~FmaitDZ@oegeOv|#ZCt8<@a47xLq1E@bTtj&;2{Oy{mY0LPpz()Q`QHggxiU z009P7z-TsIk0^s^(^*2;J#0oL3(M}l_S>sfY`;`zMqQ{vwJsOHyyx9hTnGh4>zZf{((&O!^u zO@D#dJIfUG`^Z}j=lyY_-DVEm^Cl$eNTHPY81>y)2WjGztxF@DR@|?w0Q(ksQ-9S= zI0Jb=4Tz{6ed3Y?P{AgesHwaG^h@O}l%IlZ+cL>c=q>>iD}pM7>l~zo9pTk<`CZU> zU@BTJWu5S#A-qe()d8#s3lEk>2jpzsAE8VMx zD=igJS886jNg{<)N!Ov;@gmQsVaq10ssI2 DezthU literal 0 HcmV?d00001 diff --git a/pc-admin/src/assets/styles/index.scss b/pc-admin/src/assets/styles/index.scss new file mode 100644 index 0000000..0ea0d6f --- /dev/null +++ b/pc-admin/src/assets/styles/index.scss @@ -0,0 +1,114 @@ +@use './variables.scss' as *; + +* { + box-sizing: border-box; +} + +html, +body, +#app { + width: 100%; + min-width: 1180px; + height: 100%; + margin: 0; +} + +body { + color: $ink; + background: $field; + font-family: Inter, "PingFang SC", "Microsoft YaHei", Arial, sans-serif; + letter-spacing: 0; +} + +a { + color: inherit; + text-decoration: none; +} + +.page-shell { + padding: 22px 26px 34px; +} + +.page-head { + display: flex; + align-items: flex-end; + justify-content: space-between; + gap: 24px; + margin-bottom: 18px; +} + +.page-kicker { + color: $coral; + font-size: 12px; + font-weight: 800; + letter-spacing: 0; +} + +.page-title { + margin-top: 5px; + color: $ink; + font-size: 28px; + font-weight: 900; + line-height: 1.2; +} + +.page-subtitle { + margin-top: 8px; + color: $muted; + font-size: 14px; +} + +.growth-grid { + display: grid; + gap: 16px; +} + +.growth-card { + border: 1px solid rgba(11, 47, 42, 0.08); + border-radius: 8px; + background: rgba(255, 255, 255, 0.82); + box-shadow: 0 12px 30px rgba(11, 47, 42, 0.08); +} + +.metric-value { + color: $ink; + font-size: 30px; + font-weight: 900; +} + +.metric-label { + color: $muted; + font-size: 13px; + font-weight: 700; +} + +.ink-panel { + color: #fff; + background: linear-gradient(135deg, #0b2f2a, #123f37); +} + +.el-button { + font-weight: 800; +} + +.el-button.permission-disabled, +.el-button.permission-disabled:hover, +.el-button.permission-disabled:focus { + cursor: not-allowed; + opacity: 0.52; + filter: grayscale(1); +} + +.el-table { + --el-table-header-bg-color: #f2f6ee; + --el-table-header-text-color: #17312d; + --el-table-row-hover-bg-color: #f6faf2; +} + +.el-menu { + border-right: 0; +} + +.el-progress-bar__outer { + background-color: #e0eadf; +} diff --git a/pc-admin/src/assets/styles/variables.scss b/pc-admin/src/assets/styles/variables.scss new file mode 100644 index 0000000..9fe9545 --- /dev/null +++ b/pc-admin/src/assets/styles/variables.scss @@ -0,0 +1,9 @@ +$ink: #0b2f2a; +$ink-soft: #143f38; +$field: #f4f7ef; +$paper: #fbfcf7; +$mint: #17bebb; +$amber: #f5c451; +$coral: #ff7a59; +$line: #dbe7dc; +$muted: #72817b; diff --git a/pc-admin/src/components/AppCard/index.vue b/pc-admin/src/components/AppCard/index.vue new file mode 100644 index 0000000..886cb18 --- /dev/null +++ b/pc-admin/src/components/AppCard/index.vue @@ -0,0 +1,29 @@ + + + + + diff --git a/pc-admin/src/components/StatusTag/index.vue b/pc-admin/src/components/StatusTag/index.vue new file mode 100644 index 0000000..1839a70 --- /dev/null +++ b/pc-admin/src/components/StatusTag/index.vue @@ -0,0 +1,19 @@ + + + diff --git a/pc-admin/src/directive/permission/index.js b/pc-admin/src/directive/permission/index.js new file mode 100644 index 0000000..2b88c74 --- /dev/null +++ b/pc-admin/src/directive/permission/index.js @@ -0,0 +1,40 @@ +import { useUserStore } from '@/store/modules/user' +import { hasPermission as checkPermission } from '@/utils/permission' + +function hasPermission(value = []) { + const userStore = useUserStore() + return checkPermission(userStore.permissions, value) +} + +const clickBlockers = new WeakMap() + +function disableForPermission(el, binding) { + if (hasPermission(binding.value)) return + if ('disabled' in el) el.disabled = true + el.setAttribute('disabled', '') + el.setAttribute('aria-disabled', 'true') + el.setAttribute('title', '没有操作权限') + el.classList.add('is-disabled', 'permission-disabled') + if (!clickBlockers.has(el)) { + const blocker = (event) => { + event.preventDefault() + event.stopImmediatePropagation() + } + clickBlockers.set(el, blocker) + el.addEventListener('click', blocker, true) + } +} + +export default { + mounted(el, binding) { + disableForPermission(el, binding) + }, + updated(el, binding) { + disableForPermission(el, binding) + }, + unmounted(el) { + const blocker = clickBlockers.get(el) + if (blocker) el.removeEventListener('click', blocker, true) + clickBlockers.delete(el) + }, +} diff --git a/pc-admin/src/layout/components/AppMain/index.vue b/pc-admin/src/layout/components/AppMain/index.vue new file mode 100644 index 0000000..84163ef --- /dev/null +++ b/pc-admin/src/layout/components/AppMain/index.vue @@ -0,0 +1,30 @@ + + + diff --git a/pc-admin/src/layout/components/Navbar/index.vue b/pc-admin/src/layout/components/Navbar/index.vue new file mode 100644 index 0000000..04d533f --- /dev/null +++ b/pc-admin/src/layout/components/Navbar/index.vue @@ -0,0 +1,271 @@ + + + + + diff --git a/pc-admin/src/layout/components/Sidebar/index.vue b/pc-admin/src/layout/components/Sidebar/index.vue new file mode 100644 index 0000000..d48542d --- /dev/null +++ b/pc-admin/src/layout/components/Sidebar/index.vue @@ -0,0 +1,245 @@ + + + + + diff --git a/pc-admin/src/layout/index.vue b/pc-admin/src/layout/index.vue new file mode 100644 index 0000000..308aa41 --- /dev/null +++ b/pc-admin/src/layout/index.vue @@ -0,0 +1,40 @@ + + + + + diff --git a/pc-admin/src/main.js b/pc-admin/src/main.js new file mode 100644 index 0000000..bd609c5 --- /dev/null +++ b/pc-admin/src/main.js @@ -0,0 +1,18 @@ +import { createApp } from 'vue' +import ElementPlus from 'element-plus' +import zhCn from 'element-plus/es/locale/lang/zh-cn' +import 'element-plus/dist/index.css' +import App from './App.vue' +import router from './router' +import store from './store' +import permission from './directive/permission' +import './permission' +import './assets/styles/index.scss' + +const app = createApp(App) + +app.directive('hasPermi', permission) +app.use(store) +app.use(router) +app.use(ElementPlus, { locale: zhCn }) +app.mount('#app') diff --git a/pc-admin/src/permission.js b/pc-admin/src/permission.js new file mode 100644 index 0000000..d8398a2 --- /dev/null +++ b/pc-admin/src/permission.js @@ -0,0 +1,68 @@ +import router, { constantRoutes } from './router' +import { useUserStore } from './store/modules/user' +import { getToken } from './utils/auth' +import { hasPermission } from './utils/permission' + +const whiteList = ['/login'] + +function resolvePath(parent, child) { + if (child.startsWith('/')) return child + if (parent === '/') return `/${child}` + return `${parent}/${child}` +} + +function firstAllowedPath(permissions) { + for (const route of constantRoutes) { + if (route.hidden) continue + const children = route.children || [] + if (!children.length && hasPermission(permissions, route.meta?.permissions || [])) return route.path + for (const child of children) { + if (!child.hidden && hasPermission(permissions, child.meta?.permissions || [])) { + return resolvePath(route.path, child.path) + } + } + } + return '' +} + +router.beforeEach(async (to, from, next) => { + document.title = to.meta?.title ? `${to.meta.title} - 立方和教育管理端` : '立方和教育管理端' + + const token = getToken() + if (token) { + if (to.path === '/login') { + next({ path: '/index' }) + return + } + const userStore = useUserStore() + try { + const account = await userStore.loadCurrent() + if (!account) { + userStore.logout() + next(`/login?redirect=${to.fullPath}`) + return + } + } catch (error) { + userStore.logout() + next(`/login?redirect=${to.fullPath}`) + return + } + if (!hasPermission(userStore.permissions, to.meta?.permissions || [])) { + const path = firstAllowedPath(userStore.permissions) + if (path && path !== to.path) next({ path }) + else { + userStore.logout() + next('/login') + } + return + } + next() + return + } + + if (whiteList.includes(to.path)) { + next() + return + } + next(`/login?redirect=${to.fullPath}`) +}) diff --git a/pc-admin/src/router/index.js b/pc-admin/src/router/index.js new file mode 100644 index 0000000..54ef12c --- /dev/null +++ b/pc-admin/src/router/index.js @@ -0,0 +1,155 @@ +import { createRouter, createWebHashHistory } from 'vue-router' +import Layout from '@/layout/index.vue' + +export const constantRoutes = [ + { + path: '/login', + component: () => import('@/views/login.vue'), + hidden: true, + }, + { + path: '/', + component: Layout, + redirect: '/index', + children: [ + { + path: 'index', + name: 'Dashboard', + component: () => import('@/views/dashboard/index.vue'), + meta: { title: '数据驾驶舱', icon: 'DataLine', affix: true, permissions: ['dashboard:overview:view'] }, + }, + ], + }, + { + path: '/system', + component: Layout, + redirect: '/system/account', + meta: { title: '系统管理', icon: 'Setting' }, + children: [ + { + path: 'account', + name: 'Account', + component: () => import('@/views/system/account/index.vue'), + meta: { title: '用户管理', icon: 'UserFilled', permissions: ['system:user:view'] }, + }, + { + path: 'role', + name: 'Role', + component: () => import('@/views/system/role/index.vue'), + meta: { title: '角色权限', icon: 'Key', permissions: ['system:role:view'] }, + }, + ], + }, + { + path: '/leads', + component: Layout, + redirect: '/leads/index', + meta: { title: '线索管理', icon: 'Share' }, + children: [ + { + path: 'index', + name: 'Leads', + component: () => import('@/views/leads/index.vue'), + meta: { title: '推荐线索', icon: 'Share', permissions: ['leads:referral:view'] }, + }, + ], + }, + { + path: '/points', + component: Layout, + redirect: '/points/manager', + meta: { title: '积分管理', icon: 'Coin' }, + children: [ + { + path: 'manager', + name: 'PointManager', + component: () => import('@/views/points/manager/index.vue'), + meta: { title: '积分概览', icon: 'Coin', permissions: ['points:account:view'] }, + }, + { + path: 'accounts', + name: 'PointAccounts', + component: () => import('@/views/points/accounts/index.vue'), + meta: { title: '家长积分账户', icon: 'Coin', permissions: ['points:account:view'] }, + }, + { + path: 'rewards', + name: 'PointRewards', + component: () => import('@/views/points/rewards/index.vue'), + meta: { title: '兑换权益', icon: 'Coin', permissions: ['points:reward:edit'] }, + }, + { + path: 'rewards/:id', + name: 'PointRewardDetail', + component: () => import('@/views/points/reward-detail/index.vue'), + hidden: true, + meta: { title: '兑换权益详情', permissions: ['points:reward:edit', 'points:redemption:view'] }, + }, + { + path: 'redemptions', + name: 'PointRedemptions', + component: () => import('@/views/points/redemptions/index.vue'), + meta: { title: '兑换审核', icon: 'Coin', permissions: ['points:redemption:view'] }, + }, + { + path: 'vouchers', + name: 'PointVouchers', + component: () => import('@/views/points/vouchers/index.vue'), + meta: { title: '券码核销', icon: 'Coin', permissions: ['points:voucher:verify'] }, + }, + { + path: 'details', + name: 'PointDetails', + component: () => import('@/views/points/details/index.vue'), + meta: { title: '积分明细', icon: 'Coin', permissions: ['points:account:view'] }, + }, + ], + }, + { + path: '/courses', + component: Layout, + redirect: '/courses/trial', + meta: { title: '课程管理', icon: 'Calendar' }, + children: [ + { + path: 'trial', + name: 'TrialCourses', + component: () => import('@/views/courses/trial/index.vue'), + meta: { title: '试听课程', icon: 'Calendar', permissions: ['courses:trial:view'] }, + }, + { + path: 'appointments', + name: 'CourseAppointments', + component: () => import('@/views/courses/appointments/index.vue'), + meta: { title: '预约记录', icon: 'Tickets', permissions: ['courses:trial:view'] }, + }, + ], + }, + { + path: '/statistics', + component: Layout, + redirect: '/statistics/channel', + meta: { title: '数据统计', icon: 'TrendCharts' }, + children: [ + { + path: 'channel', + name: 'ChannelStatistics', + component: () => import('@/views/statistics/channel/index.vue'), + meta: { title: '渠道转化', icon: 'Share', permissions: ['statistics:channel:view'] }, + }, + ], + }, + { + path: '/:pathMatch(.*)*', + redirect: '/index', + hidden: true, + }, +] + +const router = createRouter({ + history: createWebHashHistory(), + routes: constantRoutes, + scrollBehavior: () => ({ top: 0 }), +}) + +export default router diff --git a/pc-admin/src/settings.js b/pc-admin/src/settings.js new file mode 100644 index 0000000..ee0d393 --- /dev/null +++ b/pc-admin/src/settings.js @@ -0,0 +1,5 @@ +export default { + title: '立方和教育管理端', + sideTheme: 'theme-growth', + showTagsView: true, +} diff --git a/pc-admin/src/store/index.js b/pc-admin/src/store/index.js new file mode 100644 index 0000000..94e2432 --- /dev/null +++ b/pc-admin/src/store/index.js @@ -0,0 +1,5 @@ +import { createPinia } from 'pinia' + +const store = createPinia() + +export default store diff --git a/pc-admin/src/store/modules/user.js b/pc-admin/src/store/modules/user.js new file mode 100644 index 0000000..d2ad5d6 --- /dev/null +++ b/pc-admin/src/store/modules/user.js @@ -0,0 +1,48 @@ +import { defineStore } from 'pinia' +import { login, getInfo } from '@/api/login' +import { getAccount, getToken, removeAccount, removeToken, setAccount, setToken } from '@/utils/auth' + +export const useUserStore = defineStore('user', { + state: () => ({ + token: getToken(), + account: getAccount(), + permissions: getAccount()?.permissions || [], + loaded: false, + }), + actions: { + async loginByPassword(account, password) { + const accountInfo = await login({ account, password }) + this.token = accountInfo.sessionToken + this.account = accountInfo + this.permissions = accountInfo.permissions || [] + this.loaded = true + setToken(accountInfo.sessionToken) + setAccount(accountInfo) + return accountInfo + }, + async loadCurrent(force = false) { + if (!this.token) return null + if (this.loaded && !force) return this.account + const account = await getInfo() + this.account = account + this.permissions = account.permissions || [] + this.loaded = true + setAccount(account) + return account + }, + setAccountInfo(account) { + this.account = account + this.permissions = account?.permissions || [] + this.loaded = true + setAccount(account) + }, + logout() { + this.token = '' + this.account = null + this.permissions = [] + this.loaded = false + removeToken() + removeAccount() + }, + }, +}) diff --git a/pc-admin/src/utils/auth.js b/pc-admin/src/utils/auth.js new file mode 100644 index 0000000..f2d0718 --- /dev/null +++ b/pc-admin/src/utils/auth.js @@ -0,0 +1,27 @@ +const TokenKey = 'Lfhe-Admin-Token' +const AccountKey = 'Lfhe-Admin-Account' + +export function getToken() { + return localStorage.getItem(TokenKey) +} + +export function setToken(token) { + localStorage.setItem(TokenKey, token) +} + +export function removeToken() { + localStorage.removeItem(TokenKey) +} + +export function getAccount() { + const raw = localStorage.getItem(AccountKey) + return raw ? JSON.parse(raw) : null +} + +export function setAccount(account) { + localStorage.setItem(AccountKey, JSON.stringify(account)) +} + +export function removeAccount() { + localStorage.removeItem(AccountKey) +} diff --git a/pc-admin/src/utils/permission.js b/pc-admin/src/utils/permission.js new file mode 100644 index 0000000..1b6a839 --- /dev/null +++ b/pc-admin/src/utils/permission.js @@ -0,0 +1,5 @@ +export function hasPermission(permissions = [], required = []) { + if (!required || !required.length) return true + if (permissions.includes('*:*:*')) return true + return required.some((permission) => permissions.includes(permission)) +} diff --git a/pc-admin/src/utils/request.js b/pc-admin/src/utils/request.js new file mode 100644 index 0000000..65e8648 --- /dev/null +++ b/pc-admin/src/utils/request.js @@ -0,0 +1,31 @@ +import axios from 'axios' +import { ElMessage } from 'element-plus' +import { getToken } from './auth' + +const service = axios.create({ + baseURL: import.meta.env.VITE_APP_BASE_API || '/api', + timeout: 10000, +}) + +service.interceptors.request.use((config) => { + const token = getToken() + if (token) config.headers.Authorization = `Bearer ${token}` + return config +}) + +service.interceptors.response.use( + (response) => { + const body = response.data + if (body?.ok === false) { + ElMessage.error(body.message || '请求失败') + return Promise.reject(new Error(body.message || '请求失败')) + } + return body?.data ?? body + }, + (error) => { + ElMessage.error(error.response?.data?.message || error.message || '网络异常') + return Promise.reject(error) + }, +) + +export default service diff --git a/pc-admin/src/views/courses/appointments/index.vue b/pc-admin/src/views/courses/appointments/index.vue new file mode 100644 index 0000000..d4b55b9 --- /dev/null +++ b/pc-admin/src/views/courses/appointments/index.vue @@ -0,0 +1,270 @@ + + + + + diff --git a/pc-admin/src/views/courses/trial/index.vue b/pc-admin/src/views/courses/trial/index.vue new file mode 100644 index 0000000..a37b33b --- /dev/null +++ b/pc-admin/src/views/courses/trial/index.vue @@ -0,0 +1,365 @@ + + + + + diff --git a/pc-admin/src/views/dashboard/index.vue b/pc-admin/src/views/dashboard/index.vue new file mode 100644 index 0000000..7d449fb --- /dev/null +++ b/pc-admin/src/views/dashboard/index.vue @@ -0,0 +1,525 @@ + + + + + diff --git a/pc-admin/src/views/leads/index.vue b/pc-admin/src/views/leads/index.vue new file mode 100644 index 0000000..83c3d38 --- /dev/null +++ b/pc-admin/src/views/leads/index.vue @@ -0,0 +1,242 @@ + + + + + diff --git a/pc-admin/src/views/login.vue b/pc-admin/src/views/login.vue new file mode 100644 index 0000000..c0b1add --- /dev/null +++ b/pc-admin/src/views/login.vue @@ -0,0 +1,181 @@ + + + + + diff --git a/pc-admin/src/views/points/accounts/index.vue b/pc-admin/src/views/points/accounts/index.vue new file mode 100644 index 0000000..66cc46e --- /dev/null +++ b/pc-admin/src/views/points/accounts/index.vue @@ -0,0 +1,366 @@ + + + + + diff --git a/pc-admin/src/views/points/details/index.vue b/pc-admin/src/views/points/details/index.vue new file mode 100644 index 0000000..8e7c64a --- /dev/null +++ b/pc-admin/src/views/points/details/index.vue @@ -0,0 +1,316 @@ + + + + + diff --git a/pc-admin/src/views/points/manager/index.vue b/pc-admin/src/views/points/manager/index.vue new file mode 100644 index 0000000..2156c37 --- /dev/null +++ b/pc-admin/src/views/points/manager/index.vue @@ -0,0 +1,441 @@ + + + + + diff --git a/pc-admin/src/views/points/redemptions/index.vue b/pc-admin/src/views/points/redemptions/index.vue new file mode 100644 index 0000000..93d52d3 --- /dev/null +++ b/pc-admin/src/views/points/redemptions/index.vue @@ -0,0 +1,336 @@ + + + + + diff --git a/pc-admin/src/views/points/reward-detail/index.vue b/pc-admin/src/views/points/reward-detail/index.vue new file mode 100644 index 0000000..4e5b762 --- /dev/null +++ b/pc-admin/src/views/points/reward-detail/index.vue @@ -0,0 +1,202 @@ + + + + + diff --git a/pc-admin/src/views/points/rewards/index.vue b/pc-admin/src/views/points/rewards/index.vue new file mode 100644 index 0000000..9517719 --- /dev/null +++ b/pc-admin/src/views/points/rewards/index.vue @@ -0,0 +1,305 @@ + + + + + diff --git a/pc-admin/src/views/points/vouchers/index.vue b/pc-admin/src/views/points/vouchers/index.vue new file mode 100644 index 0000000..2ca98fe --- /dev/null +++ b/pc-admin/src/views/points/vouchers/index.vue @@ -0,0 +1,399 @@ + + + + + diff --git a/pc-admin/src/views/statistics/channel/index.vue b/pc-admin/src/views/statistics/channel/index.vue new file mode 100644 index 0000000..19ea915 --- /dev/null +++ b/pc-admin/src/views/statistics/channel/index.vue @@ -0,0 +1,124 @@ + + + + + diff --git a/pc-admin/src/views/system/account/index.vue b/pc-admin/src/views/system/account/index.vue new file mode 100644 index 0000000..c03f2bd --- /dev/null +++ b/pc-admin/src/views/system/account/index.vue @@ -0,0 +1,745 @@ + + + + + diff --git a/pc-admin/src/views/system/role/index.vue b/pc-admin/src/views/system/role/index.vue new file mode 100644 index 0000000..d010a95 --- /dev/null +++ b/pc-admin/src/views/system/role/index.vue @@ -0,0 +1,240 @@ + + + + + diff --git a/pc-admin/vite.config.js b/pc-admin/vite.config.js new file mode 100644 index 0000000..5ec9c18 --- /dev/null +++ b/pc-admin/vite.config.js @@ -0,0 +1,26 @@ +import { fileURLToPath, URL } from 'node:url' +import { defineConfig, loadEnv } from 'vite' +import vue from '@vitejs/plugin-vue' + +export default defineConfig(({ mode }) => { + const env = loadEnv(mode, process.cwd()) + return { + plugins: [vue()], + resolve: { + alias: { + '@': fileURLToPath(new URL('./src', import.meta.url)), + }, + }, + server: { + host: '127.0.0.1', + port: Number(env.VITE_APP_PORT || 5174), + open: false, + proxy: { + '/api': { + target: env.VITE_APP_PROXY_API || 'http://127.0.0.1:3100', + changeOrigin: true, + }, + }, + }, + } +}) diff --git a/scripts/build-server-package.ps1 b/scripts/build-server-package.ps1 new file mode 100644 index 0000000..c00509a --- /dev/null +++ b/scripts/build-server-package.ps1 @@ -0,0 +1,43 @@ +param( + [string]$NodePath = "C:\Users\ruixininfo\AppData\Local\nodejs\npm.cmd" +) + +$ErrorActionPreference = "Stop" + +$root = Resolve-Path (Join-Path $PSScriptRoot "..") +$backend = Join-Path $root "backend" +$pcAdmin = Join-Path $root "pc-admin" +$release = Join-Path $root "release" +$serverPackage = Join-Path $release "server" +$pcStatic = Join-Path $serverPackage "public\pc-admin" + +$serverPackageFull = [System.IO.Path]::GetFullPath($serverPackage) +$releaseFull = [System.IO.Path]::GetFullPath($release) +if (-not $serverPackageFull.StartsWith($releaseFull, [System.StringComparison]::OrdinalIgnoreCase)) { + throw "Refusing to clean package path outside release directory: $serverPackageFull" +} + +if (Test-Path $serverPackage) { + Remove-Item -LiteralPath $serverPackage -Recurse -Force +} +New-Item -ItemType Directory -Force -Path $pcStatic | Out-Null + +Push-Location $pcAdmin +try { + & $NodePath run build +} finally { + Pop-Location +} + +Copy-Item -Path (Join-Path $backend "src") -Destination (Join-Path $serverPackage "src") -Recurse +Copy-Item -Path (Join-Path $backend "sql") -Destination (Join-Path $serverPackage "sql") -Recurse +Copy-Item -Path (Join-Path $backend "package.json") -Destination $serverPackage +Copy-Item -Path (Join-Path $backend "package-lock.json") -Destination $serverPackage +Copy-Item -Path (Join-Path $backend ".env.example") -Destination $serverPackage +Copy-Item -Path (Join-Path $pcAdmin "dist\*") -Destination $pcStatic -Recurse + +$uploads = Join-Path $serverPackage "uploads" +New-Item -ItemType Directory -Force -Path $uploads | Out-Null + +Write-Host "Server package ready:" $serverPackage +Write-Host "Upload this directory, then run npm ci --omit=dev and npm start on the server." diff --git a/scripts/build-server-package.sh b/scripts/build-server-package.sh new file mode 100755 index 0000000..fc3e81f --- /dev/null +++ b/scripts/build-server-package.sh @@ -0,0 +1,42 @@ +#!/usr/bin/env bash +set -euo pipefail + +ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd -P)" +BACKEND_DIR="$ROOT_DIR/backend" +PC_ADMIN_DIR="$ROOT_DIR/pc-admin" +RELEASE_DIR="$ROOT_DIR/release" +SERVER_PACKAGE="$RELEASE_DIR/server" +PC_STATIC="$SERVER_PACKAGE/public/pc-admin" +NPM_BIN="${NPM_BIN:-npm}" + +mkdir -p "$RELEASE_DIR" +RELEASE_FULL="$(cd "$RELEASE_DIR" && pwd -P)" +SERVER_PACKAGE_FULL="$RELEASE_FULL/server" + +case "$SERVER_PACKAGE_FULL" in + "$RELEASE_FULL"/*) ;; + *) + echo "Refusing to clean package path outside release directory: $SERVER_PACKAGE_FULL" >&2 + exit 1 + ;; +esac + +rm -rf "$SERVER_PACKAGE_FULL" +mkdir -p "$PC_STATIC" + +( + cd "$PC_ADMIN_DIR" + "$NPM_BIN" run build +) + +cp -R "$BACKEND_DIR/src" "$SERVER_PACKAGE/src" +cp -R "$BACKEND_DIR/sql" "$SERVER_PACKAGE/sql" +cp "$BACKEND_DIR/package.json" "$SERVER_PACKAGE/" +cp "$BACKEND_DIR/package-lock.json" "$SERVER_PACKAGE/" +cp "$BACKEND_DIR/.env.example" "$SERVER_PACKAGE/" +cp -R "$PC_ADMIN_DIR/dist/." "$PC_STATIC/" + +mkdir -p "$SERVER_PACKAGE/uploads" + +echo "Server package ready: $SERVER_PACKAGE" +echo "Upload this directory, then run npm ci --omit=dev and npm start on the server."