diff --git a/.editorconfig b/.editorconfig index 4d4cd05e..dced3c85 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1,40 +1,15 @@ -# editorconfig.org - root = true -[**] -indent_size = 4 -indent_style = space +[*] charset = utf-8 +indent_style = space +indent_size = 4 end_of_line = lf -trim_trailing_whitespace = true - -[**.html] -indent_size = 2 - -[**.jade] -indent_size = 2 - -[**.json] -indent_size = 2 - -[**.scss] -indent_size = 2 -insert_final_newline = true - -[**.css] -indent_size = 2 -insert_final_newline = true - -[**.md] -trim_trailing_whitespace = false - -[**.js] -indent_size = 2 insert_final_newline = true +trim_trailing_whitespace = true -[**.yml] +[{*.json,*.yml}] indent_size = 2 [Makefile] -indent_style = tab \ No newline at end of file +indent_style = tab diff --git a/.env.example b/.env.example new file mode 100644 index 00000000..05e0ef59 --- /dev/null +++ b/.env.example @@ -0,0 +1,110 @@ +############################################### +# CodePush Server Configuration (.env) +############################################### + +# ------------------------------- +# General / Logs +# ------------------------------- +# 클론시 유일한 환경변수 값 (*) +COMPOSE_PROJECT_NAME=code-push-server +LOG_LEVEL=debug +LOG_FORMAT=text + +# ------------------------------- +# Database (MySQL) (*) +# - 유저/앱/패키지 메타데이터 저장 +# ------------------------------- +RDS_USERNAME=codepush +RDS_PASSWORD=codepush +RDS_DATABASE=codepush +RDS_HOST=127.0.0.1 +RDS_PORT=3306 + +# ------------------------------- +# Storage Settings (*) +# storageType: local | s3 | qiniu | oss | tencentcloud +# ------------------------------- +STORAGE_TYPE=local + +# Local storage (default) (*) +# 저장 파일이 위치할 경로 (미설정 시 OS tmpdir 사용) +STORAGE_DIR=./storage + +# 파일 다운로드 URL - 반드시 본인 서버 URL로 수정 +LOCAL_DOWNLOAD_URL=http://127.0.0.1:3000/download + +# 공통 Download URL 우선순위: +# LOCAL_DOWNLOAD_URL > DOWNLOAD_URL +DOWNLOAD_URL=http://127.0.0.1:3000/download + +# ------------------------------- +# JWT Token (*) +# ------------------------------- +TOKEN_SECRET=REPLACE_WITH_RANDOM_LONG_SECRET + +# ------------------------------- +# Common Behavior +# ------------------------------- +# 프로덕션 배포 및 계정생성 후 false 로 수정 +ALLOW_REGISTRATION=true +TRY_LOGIN_TIMES=4 +DIFF_NUMS=3 +# DATA_DIR=./data +# 클라우드 배포시 보통 data 디렉토리에 쓰기 권한이 없음 +DATA_DIR= +# update_check 결과를 Redis에 캐시(프로덕션 true 사용) (*) +UPDATE_CHECK_CACHE=false +# rollout 대상 여부를 clientUniqueId별로 캐시(프로덕션 true 사용) (*) +ROLLOUT_CLIENT_UNIQUE_ID_CACHE=false + +# ------------------------------- +# Redis (optional: only needed for login attempt limit or caching) (*) +# ------------------------------- +REDIS_HOST=127.0.0.1 +REDIS_PORT=6379 +REDIS_PASSWORD= +REDIS_DB=0 + +# ------------------------------- +# Email SMTP (optional: only used for registration + verification) +# ------------------------------- +SMTP_HOST= +SMTP_PORT=465 +SMTP_USERNAME= +SMTP_PASSWORD= + +# ------------------------------- +# Cloud Storage (Optional) +# Qiniu / S3 / OSS / Tencent Cloud +# ------------------------------- +QINIU_ACCESS_KEY= +QINIU_SECRET_KEY= +QINIU_BUCKET_NAME= +QINIU_DOWNLOAD_URL= + +# AWS IAM - admin_codepush with the customS3BucketAccessForCodePush policy (*) +AWS_ACCESS_KEY_ID= +AWS_SECRET_ACCESS_KEY= +AWS_SESSION_TOKEN= +AWS_BUCKET_NAME= +AWS_REGION= +AWS_DOWNLOAD_URL= +# 버킷내 경로 프리픽스 (optional) +AWS_S3_KEY_PREFIX=codepush/ + +OSS_ACCESS_KEY_ID= +OSS_SECRET_ACCESS_KEY= +OSS_ENDPOINT= +OSS_BUCKET_NAME= +OSS_PREFIX= +OSS_DOWNLOAD_URL= + +COS_ACCESS_KEY_ID= +COS_SECRET_ACCESS_KEY= +COS_BUCKET_NAME= +COS_REGION= +COS_DOWNLOAD_URL= + +# The value should be a comma-separated list of IP addresses, e.g., "127.0.0.1,10.0.0.1". +WEB_UI_WHITELIST= +WEB_UI_ALLOW= diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 00000000..a6c7c285 --- /dev/null +++ b/.eslintignore @@ -0,0 +1 @@ +*.js diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 00000000..7fad6c4a --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,3 @@ +module.exports = { + extends: ['@shm-open/eslint-config-bundle'], +}; diff --git a/.github/workflows/nodejs.yml b/.github/workflows/nodejs.yml new file mode 100644 index 00000000..99870e31 --- /dev/null +++ b/.github/workflows/nodejs.yml @@ -0,0 +1,41 @@ +# This workflow will do a clean install of node dependencies, build the source code and run tests across different versions of node +# For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions + +name: Node.js CI + +on: + push: + branches: [master] + pull_request: + branches: [master] + +jobs: + build: + runs-on: ubuntu-latest + + strategy: + matrix: + node-version: [14.x] + + services: + redis: + image: redis + ports: + - 6379:6379 + mysql: + image: mysql + env: + MYSQL_ROOT_PASSWORD: password + ports: + - 3306:3306 + + steps: + - uses: actions/checkout@v3 + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v3 + with: + node-version: ${{ matrix.node-version }} + - run: npm ci + - run: npm run build --if-present + - run: npm test + - run: npm run lint --if-present diff --git a/.gitignore b/.gitignore index c8f8d743..6a095ea3 100644 --- a/.gitignore +++ b/.gitignore @@ -7,15 +7,18 @@ pids *.pid *.seed *.DS_Store +bin/ +.nyc_output/ -.grunt +# deps +node_modules/ -# Dependency directory -# https://docs.npmjs.com/misc/faq#should-i-check-my-node-modules-folder-into-git -node_modules - -coverage # vs code .history -.idea \ No newline at end of file +.idea + +# environment variables +!.env.example +.env +.env.* diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 00000000..5bef5195 --- /dev/null +++ b/.prettierignore @@ -0,0 +1,4 @@ + +CHANGELOG.md +coverage +public diff --git a/.prettierrc.cjs b/.prettierrc.cjs new file mode 100644 index 00000000..fb8347a7 --- /dev/null +++ b/.prettierrc.cjs @@ -0,0 +1 @@ +module.exports = require('@shm-open/eslint-config-bundle/prettier'); diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 3a0d6580..00000000 --- a/.travis.yml +++ /dev/null @@ -1,31 +0,0 @@ -language: node_js -env: - - CXX=g++-4.8 -addons: - apt: - sources: - - ubuntu-toolchain-r-test - packages: - - g++-4.8 - -services: - - redis-server - - mysql - -node_js: - - "8.10.0" - - "7.5" - - "7" - - "6.9.5" - - "6.1" - - "6" - -cache: - directories: - - node_modules -before_install: - # Update Node.js modules - - "test ! -d node_modules || npm prune" - - "test ! -d node_modules || npm rebuild" -script: "npm run-script coverage" -after_script: "npm install coveralls@2.10.0 && cat ./coverage/lcov.info | coveralls" diff --git a/CHANGELOG.md b/CHANGELOG.md index c6903211..719484d7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,292 @@ +# Changelog + +All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. + +### [2.1.6](https://github.com/shm-open/code-push-server/compare/v2.1.5...v2.1.6) (2022-07-17) + + +### Bug Fixes + +* **deps:** update dependency aws-sdk to v2.1176.0 ([eb3c14a](https://github.com/shm-open/code-push-server/commit/eb3c14abcc8b673f485088f1b8684504a34b60ac)) +* **deps:** update dependency cos-nodejs-sdk-v5 to v2.11.12 ([fa00c74](https://github.com/shm-open/code-push-server/commit/fa00c74cf951278ec547c00d0ed713b40a2710d3)) +* **deps:** update dependency express to v4.18.1 ([2adad28](https://github.com/shm-open/code-push-server/commit/2adad280d937fd9176cdc4a5f20547f9ecd88288)) +* **deps:** update dependency helmet to v5.1.0 ([aefde36](https://github.com/shm-open/code-push-server/commit/aefde366d6eb98ea401214709051ebab5b6f9ecc)) +* **deps:** update dependency i18n to v0.15.0 ([7cc216c](https://github.com/shm-open/code-push-server/commit/7cc216ce5eb88ab4ff299671547f5c39c1ea146a)) +* **deps:** update dependency nodemailer to v6.7.7 ([85ad522](https://github.com/shm-open/code-push-server/commit/85ad522d5b4cb31f57cf2b9bca35d9d64d35e45d)) +* **deps:** update dependency qiniu to v7.7.0 ([732a4ed](https://github.com/shm-open/code-push-server/commit/732a4ed6e82d2047b6df91ff004fc482aaffab6b)) +* **deps:** update dependency redis to v4.2.0 ([5a744c6](https://github.com/shm-open/code-push-server/commit/5a744c6ea111e74a834307131bf0a8a5dbecb137)) +* **deps:** update dependency sequelize to v6.21.3 ([7462594](https://github.com/shm-open/code-push-server/commit/746259467957a79b77d1ea1da69f9af5915b56b1)) +* **deps:** update dependency yargs to v17.5.1 ([fd9f58e](https://github.com/shm-open/code-push-server/commit/fd9f58e580e516cb188b4bea8da3eeb837bacae6)) + +### [2.1.5](https://github.com/shm-open/code-push-server/compare/v2.1.4...v2.1.5) (2022-04-26) + +### [2.1.4](https://github.com/shm-open/code-push-server/compare/v2.1.3...v2.1.4) (2022-04-26) + + +### Bug Fixes + +* **deps:** update dependency aws-sdk to v2.1121.0 ([f59e9ae](https://github.com/shm-open/code-push-server/commit/f59e9ae1d2605b2f5938fc6e8dde6c8e3a20711f)) +* **deps:** update dependency cos-nodejs-sdk-v5 to v2.11.7 ([d74aa2a](https://github.com/shm-open/code-push-server/commit/d74aa2a43670971e8eac227412931ddc9f39a91a)) +* **deps:** update dependency express to v4.18.0 ([9b2fee3](https://github.com/shm-open/code-push-server/commit/9b2fee3cf87a79ad7d26bf7e342d70efb21af273)) +* **deps:** update dependency fs-extra to v10.1.0 ([2699a4a](https://github.com/shm-open/code-push-server/commit/2699a4a6f2cf77d917a8cce5a0eac348149efa1a)) +* **deps:** update dependency moment to v2.29.3 ([b9af976](https://github.com/shm-open/code-push-server/commit/b9af976fcd701aa3d1645c8b82f50932c4fb414c)) +* **deps:** update dependency qiniu to v7.5.0 ([f9068c2](https://github.com/shm-open/code-push-server/commit/f9068c2dcc4e83aec9820b05b21262fe859f88d6)) +* **deps:** update dependency sequelize to v6.19.0 ([d447d42](https://github.com/shm-open/code-push-server/commit/d447d4258ec22ac367041a58599a2d803cf4d090)) +* **deps:** update dependency yargs to v17.4.1 ([5431b62](https://github.com/shm-open/code-push-server/commit/5431b624a2b7b0d72a1dd79365c690c536b2b708)) + +### [2.1.3](https://github.com/shm-open/code-push-server/compare/v2.1.2...v2.1.3) (2022-04-07) + + +### Bug Fixes + +* **deps:** update dependency aws-sdk to v2.1109.0 ([1d3cab0](https://github.com/shm-open/code-push-server/commit/1d3cab0c310ca39398e65d334970add1e9119529)) +* **deps:** update dependency body-parser to v1.20.0 ([ae55396](https://github.com/shm-open/code-push-server/commit/ae553969a3154617a60db8890da7a3467c5cbcd4)) +* **deps:** update dependency moment to v2.29.2 ([a4c875d](https://github.com/shm-open/code-push-server/commit/a4c875d7c0b69f88a82c1cb1ee43e2b354ad97b1)) +* **deps:** update dependency redis to v4.0.6 ([442743f](https://github.com/shm-open/code-push-server/commit/442743f20d642d3a0adc3be0f6abbc707544077f)) +* **deps:** update dependency sequelize to v6.18.0 ([34ef968](https://github.com/shm-open/code-push-server/commit/34ef96860518e9d31769bbed6c43b1501b6bb11b)) +* use latest matching deployment ([fb70185](https://github.com/shm-open/code-push-server/commit/fb701856c688a1a62a6f52b3b3de58b1179b954f)), closes [#162](https://github.com/shm-open/code-push-server/issues/162) + +### [2.1.2](https://github.com/shm-open/code-push-server/compare/v2.1.1...v2.1.2) (2022-03-25) + + +### Bug Fixes + +* change password success prompts localized message ([21c987a](https://github.com/shm-open/code-push-server/commit/21c987ad1e9e72a888965f42cb808294c4701477)) +* **deps:** update dependency aws-sdk to v2.1100.0 ([56f32d2](https://github.com/shm-open/code-push-server/commit/56f32d24d8f381abc33b69f3354b24401d7945dc)) +* refactor views, improve/simplify the auth workflows ([f1e3e2a](https://github.com/shm-open/code-push-server/commit/f1e3e2ac2b6fbca003d56d8217793b7d346e04b6)) +* zip file creation of diff release ([4bb074b](https://github.com/shm-open/code-push-server/commit/4bb074b3ad5f334ac7457e287035ae073fd59f2e)) + +### [2.1.1](https://github.com/shm-open/code-push-server/compare/v2.1.0...v2.1.1) (2022-03-23) + + +### Bug Fixes + +* zh locale support ([6a55bc5](https://github.com/shm-open/code-push-server/commit/6a55bc57f0b28d9b0000a886dc302e6772719ea0)) + +## [2.1.0](https://github.com/shm-open/code-push-server/compare/v2.0.3...v2.1.0) (2022-03-23) + + +### Features + +* **app:** add i18n support ([57a6e98](https://github.com/shm-open/code-push-server/commit/57a6e98df10bfcfc14badd3b4a399815e3c4349a)) + + +### Bug Fixes + +* **deps:** update dependency aws-sdk to v2.1098.0 ([381f51a](https://github.com/shm-open/code-push-server/commit/381f51a6bc6b5a85945bf2caac1b48e4b875c189)) +* **deps:** update dependency nodemailer to v6.7.3 ([154af3c](https://github.com/shm-open/code-push-server/commit/154af3c526ce000c3678627502c66c54f6bd6883)) +* **deps:** update dependency yargs to v17.4.0 ([763c924](https://github.com/shm-open/code-push-server/commit/763c924ee0a77db170ef307f0726f36da7e5ac0b)) + +### [2.0.3](https://github.com/shm-open/code-push-server/compare/v2.0.2...v2.0.3) (2022-03-09) + + +### Bug Fixes + +* **deps:** update dependency aws-sdk to v2.1089.0 ([2a40892](https://github.com/shm-open/code-push-server/commit/2a40892edcd945158b9ebb1c5b8f73942fabe4bf)) +* **deps:** update dependency fs-extra to v10.0.1 ([6e20737](https://github.com/shm-open/code-push-server/commit/6e207378305bdc3e9f0258a91a2074cbff0c608a)) +* **deps:** update dependency redis to v4.0.4 ([23e984a](https://github.com/shm-open/code-push-server/commit/23e984a7662a7cc365d3402cba1ee809d4602298)) +* **deps:** update dependency sequelize to v6.17.0 ([dd255d9](https://github.com/shm-open/code-push-server/commit/dd255d976f1e2cd3e3d965580b900cb7f99f738a)) + +### [2.0.2](https://github.com/shm-open/code-push-server/compare/v2.0.1...v2.0.2) (2022-02-21) + + +### Bug Fixes + +* log stringified account info ([85a09fa](https://github.com/shm-open/code-push-server/commit/85a09fad62bd21808461debba7140e1732851622)) + +### [2.0.1](https://github.com/shm-open/code-push-server/compare/v2.0.0...v2.0.1) (2022-02-21) + + +### Bug Fixes + +* **deps:** update dependency aws-sdk to v2.1077.0 ([fd22283](https://github.com/shm-open/code-push-server/commit/fd22283882e2462423bc25efa27c6b707957b41e)) +* **deps:** update dependency body-parser to v1.19.2 ([19d8acd](https://github.com/shm-open/code-push-server/commit/19d8acd994538cb683dc319e0f0aa164c75a882f)) +* **deps:** update dependency express to v4.17.3 ([915fd25](https://github.com/shm-open/code-push-server/commit/915fd25fedff2246d93c051bc7a56db52cbd61b7)) +* **deps:** update dependency kv-logger to v0.5.3 ([e7d2e0f](https://github.com/shm-open/code-push-server/commit/e7d2e0f28e1989227582505397139e0db617424d)) +* **deps:** update dependency sequelize to v6.16.2 ([ceb3e3e](https://github.com/shm-open/code-push-server/commit/ceb3e3ebac22983805d5dfa992c27c03f3da2f1f)) +* **deps:** update kv-logger to 0.5.1 ([6289835](https://github.com/shm-open/code-push-server/commit/6289835990e1ae964378fc28d2037d1ce752107a)) +* **deps:** update kv-logger to 0.5.2 and fix build issue ([cae80fe](https://github.com/shm-open/code-push-server/commit/cae80fe5ba00c920b79df3422fb8c86424a6dc07)) +* put x-request-id to res header ([e9c13a5](https://github.com/shm-open/code-push-server/commit/e9c13a5ea6cb48e8338cb3314312fce51587b631)) + +## [2.0.0](https://github.com/shm-open/code-push-server/compare/v1.2.0...v2.0.0) (2022-02-10) + + +### ⚠ BREAKING CHANGES + +* drop is_use_diff_text support +* drop codePushWeb redirect support +* drop upyun support +* drop CONFIG_FILE support, please use env variable config items + +### Features + +* drop upyun support ([57bbdc5](https://github.com/shm-open/code-push-server/commit/57bbdc58d7c9174f4d00ad9ec1525f5f828e00b4)) + + +### Bug Fixes + +* **deps:** update dependency aws-sdk to v2.1072.0 ([82f41e0](https://github.com/shm-open/code-push-server/commit/82f41e0e347802a851534af3d9558fe1a3919936)) +* **deps:** update dependency sequelize to v6.16.0 ([e3bb1e4](https://github.com/shm-open/code-push-server/commit/e3bb1e4f223f9a43430318fe20fc1af759c30721)) +* **deps:** update dependency sequelize to v6.16.1 ([568a5b0](https://github.com/shm-open/code-push-server/commit/568a5b02b280eb9211948a4d6a7380efac33d199)) +* update deps redis to v4, reuse the same redis client without quit ([98c2ca6](https://github.com/shm-open/code-push-server/commit/98c2ca60a3285353c9ce3cdab5f8eee1b9deffba)) + + +* drop codePushWeb redirect support ([255ea15](https://github.com/shm-open/code-push-server/commit/255ea1530aba7a57c66e0e304fa6c7b23485f219)) +* turn package-manager to ts ([e067aed](https://github.com/shm-open/code-push-server/commit/e067aed251a5376bc437502c9ceee86f9408988e)) +* turn top level app/www to ts ([76d8898](https://github.com/shm-open/code-push-server/commit/76d8898e563bbf52361b87b615bf7c13f40409e0)) + +## [1.2.0](https://github.com/shm-open/code-push-server/compare/v1.1.1...v1.2.0) (2022-02-08) + + +### Features + +* add typescript support ([6b1a5d7](https://github.com/shm-open/code-push-server/commit/6b1a5d7d8d836ab804f32c3931f4c57bde5f5dde)) + + +### Bug Fixes + +* add more info logs for account/app management ([4e45c7e](https://github.com/shm-open/code-push-server/commit/4e45c7e651c503383e6bb659397d27b3a3c76809)) +* **deps:** update dependency aws-sdk to v2.1062.0 ([9a62e4a](https://github.com/shm-open/code-push-server/commit/9a62e4a93855b233befedd6fbcd8aec47fd9d61d)) +* **deps:** update dependency body-parser to v1.19.1 ([1173672](https://github.com/shm-open/code-push-server/commit/117367240a63028eebd992161a354d1404827fd6)) +* **deps:** update dependency cos-nodejs-sdk-v5 to v2.11.6 ([4e570d6](https://github.com/shm-open/code-push-server/commit/4e570d646b3bae386280aa02cab6b7f58d504d1a)) +* **deps:** update dependency express to v4.17.2 ([59a9cd3](https://github.com/shm-open/code-push-server/commit/59a9cd3e4a871c38e024986fb46ba98d457dd617)) +* **deps:** update dependency helmet to v5 ([ffff5da](https://github.com/shm-open/code-push-server/commit/ffff5dab25bb001e5772bfe7c189e337fe108aaa)) +* **deps:** update dependency helmet to v5.0.2 ([b601ee7](https://github.com/shm-open/code-push-server/commit/b601ee763f9ed49417ac97f51c50bcded62ce2ca)) +* **deps:** update dependency node-fetch to v2.6.7 ([2bcaa19](https://github.com/shm-open/code-push-server/commit/2bcaa1992f2a2d6e00595728ee4b07edbfb1b727)) +* **deps:** update dependency nodemailer to v6.7.2 ([58a2af0](https://github.com/shm-open/code-push-server/commit/58a2af07a8d23fd2930b4745c28456f50bae16eb)) +* **deps:** update dependency sequelize to v6.12.4 ([5ec26ae](https://github.com/shm-open/code-push-server/commit/5ec26aed33f2eac595ee9e4de26f0eb5dfc28440)) +* **deps:** update dependency sequelize to v6.14.0 ([1786ca2](https://github.com/shm-open/code-push-server/commit/1786ca20b637bc5562aa99b30b4404bbbb89a651)) +* **deps:** update dependency yargs to v17.3.1 ([a099f8c](https://github.com/shm-open/code-push-server/commit/a099f8c162a84341b543eeba3683f7afaf067a00)) +* replace log4js with simple kv-logger ([7e1829e](https://github.com/shm-open/code-push-server/commit/7e1829edac2886e1370590696b7815fb922b7b47)) +* simplify redis config ([deefe90](https://github.com/shm-open/code-push-server/commit/deefe90fd373fd3a7ce0a9d35321b7f32eed724e)) + +### [1.1.1](https://github.com/shm-open/code-push-server/compare/v1.1.0...v1.1.1) (2021-11-23) + + +### Bug Fixes + +* make all config items accessible with environment variables ([187c198](https://github.com/shm-open/code-push-server/commit/187c198bc84acaf835c84f434438a8eb40720ad1)) +* use unified log level config and config it by LOG_LEVEL ([6699127](https://github.com/shm-open/code-push-server/commit/66991276444efcabd2d8b08244f7e459df9ef4e3)) + +## [1.1.0](https://github.com/shm-open/code-push-server/compare/v1.0.6...v1.1.0) (2021-11-23) + + +### Features + +* check config flag `common.allowRegistration` to allow registration ([53ffab6](https://github.com/shm-open/code-push-server/commit/53ffab6a2b18abd9468a87370c2300bf27fc27ec)) + + +### Bug Fixes + +* **deps:** update dependency aliyun-sdk to v1.12.4 ([5c7b64f](https://github.com/shm-open/code-push-server/commit/5c7b64fe3022af76f1ccad34efaeac027b3e37c8)) +* **deps:** update dependency aws-sdk to v2.1034.0 ([a57da57](https://github.com/shm-open/code-push-server/commit/a57da57e05070306df5b17ddae3c6ab9f92ebe74)) +* **deps:** update dependency aws-sdk to v2.975.0 ([ce7eb3f](https://github.com/shm-open/code-push-server/commit/ce7eb3f86e4f31b8172fc93500d4c6f209a26d37)) +* **deps:** update dependency aws-sdk to v2.976.0 ([e598d4b](https://github.com/shm-open/code-push-server/commit/e598d4b07676615f02514ede88f071d2534bd091)) +* **deps:** update dependency aws-sdk to v2.978.0 ([1ff838c](https://github.com/shm-open/code-push-server/commit/1ff838c85bfc96744943621dcee54abbdb20c76e)) +* **deps:** update dependency aws-sdk to v2.979.0 ([f046a22](https://github.com/shm-open/code-push-server/commit/f046a22864429000a3d43537a683c7dbb911a3f2)) +* **deps:** update dependency cookie-parser to v1.4.6 ([82858f7](https://github.com/shm-open/code-push-server/commit/82858f78d70abecd52c68300cfad3b64a091ee7e)) +* **deps:** update dependency cos-nodejs-sdk-v5 to v2.11.2 ([1ca57d5](https://github.com/shm-open/code-push-server/commit/1ca57d5000436ca84a48caefff994864ed5a422d)) +* **deps:** update dependency formidable to v1.2.6 ([8b6efad](https://github.com/shm-open/code-push-server/commit/8b6efad55800db13a4f79f6d4950516adae94ee2)) +* **deps:** update dependency mysql2 to v2.3.3 ([eafe186](https://github.com/shm-open/code-push-server/commit/eafe1864808502aafab6404624a75a640a96fc51)) +* **deps:** update dependency node-fetch to v2.6.6 ([885a88a](https://github.com/shm-open/code-push-server/commit/885a88a23fa35a43cbb24f0b3058fb80a932361d)) +* **deps:** update dependency nodemailer to v6.7.1 ([521061a](https://github.com/shm-open/code-push-server/commit/521061abfe34bceae6da244f03855f842ad3e67f)) +* **deps:** update dependency sequelize to v6.11.0 ([5d1d791](https://github.com/shm-open/code-push-server/commit/5d1d791b17da2fa7eb6be52576ac03d91bef3d28)) +* **deps:** update dependency validator to v13.7.0 ([2d8c47e](https://github.com/shm-open/code-push-server/commit/2d8c47e26b12f9f351a9fc9045754635d7ded4e3)) +* **deps:** update dependency yargs to v17.2.1 ([76052d6](https://github.com/shm-open/code-push-server/commit/76052d68fcdaa27ccc631b305639c00760ae400d)) +* **deps:** update formidable to v2 ([9949913](https://github.com/shm-open/code-push-server/commit/9949913c4014e29c294bddc283a9cb706c324f62)) +* handle registration and confirmation ([b8b0276](https://github.com/shm-open/code-push-server/commit/b8b0276f4a54199ce66fb646b327d323a434c7cc)) + +### [1.0.6](https://github.com/shm-open/code-push-server/compare/v1.0.5...v1.0.6) (2021-08-23) + + +### Bug Fixes + +* skip find diff package if check update without a client side packageHash ([d00a8cc](https://github.com/shm-open/code-push-server/commit/d00a8cc6479ebe2c5395ef9214ffc1af6497fd3c)) + +### [1.0.5](https://github.com/shm-open/code-push-server/compare/v1.0.4...v1.0.5) (2021-08-23) + + +### Bug Fixes + +* omit undefined query condition for no package_hash update check ([6dbe8df](https://github.com/shm-open/code-push-server/commit/6dbe8dfa192331adcf642d0804ed68362c3e2370)) + +### [1.0.4](https://github.com/shm-open/code-push-server/compare/v1.0.3...v1.0.4) (2021-08-23) + + +### Bug Fixes + +* **deps:** update dependency sequelize to v5.22.4 ([6146bf4](https://github.com/shm-open/code-push-server/commit/6146bf47add06bb7e8967409c9e3049dc431c168)) +* **deps:** update sequelize to v5 ([bbf8cad](https://github.com/shm-open/code-push-server/commit/bbf8cadd130da6888bd04d2beef5b15c6a620c63)) +* **deps:** update sequelize to v6 ([bf7a152](https://github.com/shm-open/code-push-server/commit/bf7a152da4b3c86029c557b966a3106af9c9f8f9)) + +### [1.0.3](https://github.com/shm-open/code-push-server/compare/v1.0.2...v1.0.3) (2021-08-23) + + +### Bug Fixes + +* **deps:** update dependency aws-sdk to v2.973.0 ([0880204](https://github.com/shm-open/code-push-server/commit/0880204282c2db605800788bba3ff9ba458a6874)) +* **deps:** update dependency sequelize to v4.44.4 ([e66bbf1](https://github.com/shm-open/code-push-server/commit/e66bbf1148396fc31f35cea5272587e2dcf4830f)) +* support REDIS_PASSWORD, REDIS_DB env var in default config ([e7fe615](https://github.com/shm-open/code-push-server/commit/e7fe6159a2cf8b180b0eb2993fe9fef239ab85a5)) + +### [1.0.2](https://github.com/shm-open/code-push-server/compare/v1.0.1...v1.0.2) (2021-08-19) + + +### Bug Fixes + +* cleanup some use of bluebird in favor of native Promise ([2a3f946](https://github.com/shm-open/code-push-server/commit/2a3f946a5a6edcbc6de05b33e46f41a497615ee6)) +* **deps:** update dependency aliyun-sdk to v1.12.3 ([1f2cb60](https://github.com/shm-open/code-push-server/commit/1f2cb60be694e87ef847b23dc4dab56980deef02)) +* **deps:** update dependency aws-sdk to v2.971.0 ([fa2a40a](https://github.com/shm-open/code-push-server/commit/fa2a40ab33c6ec6e34ec33c4f0b5f1be0fc8b9eb)) +* **deps:** update dependency bluebird to v3.7.2 ([fd221ec](https://github.com/shm-open/code-push-server/commit/fd221eced8b4c3ece6288024b0368471b6bde92f)) +* **deps:** update dependency body-parser to v1.19.0 ([92a5131](https://github.com/shm-open/code-push-server/commit/92a5131d2d1f5803b753588a60c943c29c8dfa33)) +* **deps:** update dependency cookie-parser to v1.4.5 ([f4fa15c](https://github.com/shm-open/code-push-server/commit/f4fa15c9500f946173a4aadeb716d6c4888f4c12)) +* **deps:** update dependency diff-match-patch to v1.0.5 ([e45052d](https://github.com/shm-open/code-push-server/commit/e45052d29a8c8d1f6758c59a26b2410630d6579c)) +* **deps:** update dependency extract-zip to v1.7.0 ([f690f32](https://github.com/shm-open/code-push-server/commit/f690f322de2ef4c068a1c2f444957651a90ec3aa)) +* **deps:** update dependency formidable to v1.2.2 ([eb90aad](https://github.com/shm-open/code-push-server/commit/eb90aada2de67759177926438b6262eb23ec9475)) +* **deps:** update dependency fs-extra to v10 ([8636b27](https://github.com/shm-open/code-push-server/commit/8636b27d8d1a683440409aa5c2e93d4c6aaa85dd)) +* **deps:** update dependency fs-extra to v7.0.1 ([10dbb59](https://github.com/shm-open/code-push-server/commit/10dbb5948bd802d5ec31571b65b94b60913fab65)) +* **deps:** update dependency helmet to v3.23.3 ([1371a70](https://github.com/shm-open/code-push-server/commit/1371a7086c469911bc97562891abd92a2d140f99)) +* **deps:** update dependency jschardet to v3 ([3e947d7](https://github.com/shm-open/code-push-server/commit/3e947d7602001d9874aa6d2c31da8ef05d9fdeb0)) +* **deps:** update dependency jsonwebtoken to v8.5.1 ([81b2635](https://github.com/shm-open/code-push-server/commit/81b2635520cc9cc286f1cdb9c7c01d9ddca7aeca)) +* **deps:** update dependency lodash to v4.17.21 ([90643a1](https://github.com/shm-open/code-push-server/commit/90643a1ace65db86678f4f86f44eb59ea937f535)) +* **deps:** update dependency log4js to v3.0.6 ([bc337a5](https://github.com/shm-open/code-push-server/commit/bc337a57a659b56448a1f0200d6d027336d7007b)) +* **deps:** update dependency moment to v2.29.1 ([e41d4f1](https://github.com/shm-open/code-push-server/commit/e41d4f1ce6107a26f909bc994651c6ed8a0dccda)) +* **deps:** update dependency nodemailer to v4.7.0 ([dd354db](https://github.com/shm-open/code-push-server/commit/dd354dbdc21810868bb94837a6deeca45345ae19)) +* **deps:** update dependency nodemailer to v6 ([73219d2](https://github.com/shm-open/code-push-server/commit/73219d2077dbe4879e42f64234ebaf6ad6fbb676)) +* **deps:** update dependency pug to v2.0.4 ([936a220](https://github.com/shm-open/code-push-server/commit/936a22068fe33e755077ae606f768ef2ab64fbb7)) +* **deps:** update dependency qiniu to v7.4.0 ([71d2645](https://github.com/shm-open/code-push-server/commit/71d2645ed83efe4222a58ff180cc1b37bf530d3d)) +* **deps:** update dependency request to v2.88.2 ([73d23aa](https://github.com/shm-open/code-push-server/commit/73d23aa0fce1f079cfb2e626274dc4041f4944ad)) +* **deps:** update dependency serve-favicon to v2.5.0 ([cbe23fb](https://github.com/shm-open/code-push-server/commit/cbe23fb7e3faee4b4ceba2db119e89458c3fa94c)) +* **deps:** update extract-zip to v2.0.1 ([6271be7](https://github.com/shm-open/code-push-server/commit/6271be7899540a169ecfde6bebdf3469f5d88f61)) +* **deps:** update helmet to v4.6.0 ([7b0592a](https://github.com/shm-open/code-push-server/commit/7b0592a9506624d9e9425b1df45354fe82b62051)) +* **deps:** update log4js to v6 ([572084e](https://github.com/shm-open/code-push-server/commit/572084e0ce5dc959df908b012c995cb1ec52f56e)) +* **deps:** update mocha and dev to their latest version ([9ece7fb](https://github.com/shm-open/code-push-server/commit/9ece7fb129376088b5844a76b69171843b0f1834)) +* **deps:** update pug to v3.0.2 ([cd1a47c](https://github.com/shm-open/code-push-server/commit/cd1a47c7b42e957a98a9c8fe8b4c6a20793b9092)) +* **deps:** update rand-token to v1.0.1 ([f229170](https://github.com/shm-open/code-push-server/commit/f2291700e702dc1cec39ebd6bea0564406e55db0)) +* **deps:** update redis to v3.1.2 ([c8c82c3](https://github.com/shm-open/code-push-server/commit/c8c82c390ef489983c0f0b2f3d4860244d5054f8)) +* **deps:** update slash to v3 ([41520ca](https://github.com/shm-open/code-push-server/commit/41520ca54dc1e7cfd0e791e5e0c74111c9fc10b5)) +* **deps:** update supertest to v6 ([9b19534](https://github.com/shm-open/code-push-server/commit/9b195344d52b8eed5689e8a220f86af507c07f13)) +* **deps:** update upyun to v3.4.4 ([e4b6e5e](https://github.com/shm-open/code-push-server/commit/e4b6e5eec9b5ebe12fc5f2afa878ad0ed8eeda71)) +* **deps:** update validator to v13 ([8c4cd00](https://github.com/shm-open/code-push-server/commit/8c4cd001979229a1041b9c134193ef02ce99b613)) +* **deps:** update yargs to v17 ([25fff4d](https://github.com/shm-open/code-push-server/commit/25fff4d74e08f22d32e077450cbd58199cf76d8a)) +* **deps:** update yazl to v2.5.1 ([ea20620](https://github.com/shm-open/code-push-server/commit/ea20620e43040510c1aac5d8508de6ac6cb66b88)) +* log more info for NotFound error ([3f890d1](https://github.com/shm-open/code-push-server/commit/3f890d1e0d4f44e319b54c0d317bb30d216aa8f0)) +* remove /README.md and remove markdown-it dep ([6100c52](https://github.com/shm-open/code-push-server/commit/6100c522778fe4ab6b05671e32c4b0aeae29ae1e)) +* remove debug from deps ([4283d9c](https://github.com/shm-open/code-push-server/commit/4283d9c8f6ac8110808cf8c6b40803d4e10ac4be)) +* remove unused i18n package ([56f4905](https://github.com/shm-open/code-push-server/commit/56f4905a4134dc4631add808f1863936fc63e79d)) +* remove unused morgan dep ([7c0dfb4](https://github.com/shm-open/code-push-server/commit/7c0dfb4cbf5885964e28e7e3dc2bd5307fe59e3d)) +* replace deprecated use of Buffer() ([dd2a141](https://github.com/shm-open/code-push-server/commit/dd2a141f9009be5e2d0bee89768295956585e07d)) + +### [1.0.1](https://github.com/shm-open/code-push-server/compare/v1.0.0...v1.0.1) (2021-08-19) + + +### Bug Fixes + +* **deps:** pin dependencies ([1822c0f](https://github.com/shm-open/code-push-server/commit/1822c0f99adee270a15f343275316a5de725a0f3)) +* **deps:** update dependency cos-nodejs-sdk-v5 to v2.10.0 ([9a65b0f](https://github.com/shm-open/code-push-server/commit/9a65b0faf51761178c16c46772ab80a92ee8c068)) +* **deps:** update dependency express to v4.17.1 ([1f4c7c1](https://github.com/shm-open/code-push-server/commit/1f4c7c11cf31f85b84c6209851fb96981d81129c)) +* **deps:** update mysql2 and setup github action ci ([6ab24d3](https://github.com/shm-open/code-push-server/commit/6ab24d336ce37e4a1522e21cf027096c3467a7a1)) +* return appVersion as target_binary_range to compatible with code-push 3.0.1 changes ([40b41fb](https://github.com/shm-open/code-push-server/commit/40b41fbc20ad35393d097336570a72d1eef16906)) + # Changelog for code-push-server ## 0.5.x diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 00000000..8a4a1eb4 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,15 @@ +FROM node:lts-alpine + +ARG VERSION latest + +RUN npm install -g @shm-open/code-push-server@${VERSION} pm2@latest --no-optional + +RUN mkdir /data/ + +WORKDIR /data/ + +COPY ./process.json /data/process.json + + # CMD ["pm2-runtime", "/data/process.json"] + # workaround for issue https://github.com/Unitech/pm2/issues/4950 + CMD ["sh", "-c", "pm2 ps && pm2-runtime /data/process.json"] diff --git a/LICENSE b/LICENSE index d92b04e8..8510ee18 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,8 @@ (The MIT License) -Copyright (c) 2016-present tablee +Copyright (c) 2020-present shihuimiao + +Copyright (c) 2016-2019 tablee Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the @@ -19,4 +21,4 @@ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/Makefile b/Makefile index 7e59757b..8ccfe406 100644 --- a/Makefile +++ b/Makefile @@ -1,27 +1,23 @@ -ROOT=$(shell pwd) +ROOT := $(shell pwd) +VERSION := $(shell node -p "require('./package.json').version") -test: test-integration - -# test-unit: -# @echo "\nRunning unit tests..." -# @NODE_ENV=test CONFIG_FILE=${ROOT}/config/config.test.js mocha test/unit --recursive - -test-integration: +.PHONY: test +test: @echo "\nRunning integration tests..." - @NODE_ENV=test CONFIG_FILE=${ROOT}/config/config.test.js mocha test/api/init - @NODE_ENV=test PORT=3000 HOST=127.0.0.1 CONFIG_FILE=${ROOT}/config/config.test.js node bin/www & - @NODE_ENV=test CONFIG_FILE=${ROOT}/config/config.test.js mocha \ - test/api/users test/api/auth test/api/account test/api/accessKeys test/api/apps test/api/index --recursive --timeout 15000 + @mocha tests/api/init --exit + @mocha tests/api/users tests/api/auth tests/api/account tests/api/accessKeys tests/api/apps tests/api/index --exit --recursive --timeout 30000 +.PHONY: coverage coverage: - @echo "\n\nRunning coverage report..." - rm -rf coverage - # @NODE_ENV=test CONFIG_FILE=${ROOT}/config/config.test.js ./node_modules/istanbul/lib/cli.js cover --report lcovonly --dir coverage/core ./node_modules/.bin/_mocha \ - # test/unit -- -R spec --recursive --timeout 15000 - @NODE_ENV=test CONFIG_FILE=${ROOT}/config/config.test.js mocha test/api/init - @NODE_ENV=test PORT=3000 HOST=127.0.0.1 CONFIG_FILE=${ROOT}/config/config.test.js node bin/www & - @NODE_ENV=test CONFIG_FILE=${ROOT}/config/config.test.js ./node_modules/istanbul/lib/cli.js cover --report lcovonly --dir coverage/api ./node_modules/.bin/_mocha \ - test/api/users test/api/auth test/api/account test/api/accessKeys test/api/apps test/api/index -- -R spec --recursive --timeout 15000 - @NODE_ENV=test CONFIG_FILE=${ROOT}/config/config.test.js ./node_modules/istanbul/lib/cli.js report + @echo "\nCheck test coverage..." + @mocha tests/api/init --exit + @nyc mocha tests/api/users tests/api/auth tests/api/account tests/api/accessKeys tests/api/apps tests/api/index --exit --recursive --timeout 30000 -.PHONY: coverage \ No newline at end of file +.PHONY: release-docker +release-docker: + @echo "\nBuilding docker image..." + docker pull node:lts-alpine + docker build --build-arg VERSION=${VERSION} -t shmopen/code-push-server:latest --no-cache . + docker tag shmopen/code-push-server:latest shmopen/code-push-server:${VERSION} + docker push shmopen/code-push-server:${VERSION} + docker push shmopen/code-push-server:latest diff --git a/Procfile b/Procfile new file mode 100644 index 00000000..063b78f4 --- /dev/null +++ b/Procfile @@ -0,0 +1 @@ +web: npm start diff --git a/README.cn.md b/README.cn.md new file mode 100644 index 00000000..f5410094 --- /dev/null +++ b/README.cn.md @@ -0,0 +1,78 @@ +# CodePush 服务端 + +微软官方的 CodePush 在国内的网络访问较慢, 所以我们使用这个服务端来架设自己的 CodePush 服务 + +## 关于本项目 + +因为原 [code-push-server](https://github.com/lisong/code-push-server) 项目的作者没有积极维护了, 我们创建了这个项目用来: + +- 保持依赖更新 +- 修复任何与最新的客户端的兼容问题 +- 我们只使用官方的 react-native-code-push 客户端, 所以定制的功能, 比如 [is_use_diff_text](https://github.com/lisong/code-push-server#advance-feature) 会被放弃. +- 我们只在生产环境使用了 react-native-code-push, 对于其他的 CodePush 客户端, 大部分功能应该没有差别, 如果遇到任何问题的话, 都欢迎提交 issue 或者 PR. + +## 支持的存储方式 + +- local: 在本地硬盘存储包文件 +- qiniu: 在[七牛云](http://www.qiniu.com/)存储包文件 +- s3: 在[aws](https://aws.amazon.com/)存储包文件 +- oss: 在[阿里云](https://www.aliyun.com/product/oss)存储包文件 +- tencentcloud: 在[腾迅云](https://cloud.tencent.com/product/cos)存储包文件 + +## 正确使用 code-push 热更新 + +- 苹果 App 允许使用热更新[Apple's developer agreement](https://developer.apple.com/programs/ios/information/iOS_Program_Information_4_3_15.pdf), 为了不影响用户体验,规定必须使用静默更新。 Google Play 不能使用静默更新,必须弹框告知用户 App 有更新。中国的 android 市场必须采用静默更新(如果弹框提示,App 会被“请上传最新版本的二进制应用包”原因驳回)。 +- react-native 不同平台 bundle 包不一样,在使用 code-push-server 的时候必须创建不同的应用来区分(eg. CodePushDemo-ios 和 CodePushDemo-android) +- react-native-code-push 只更新资源文件,不会更新 java 和 Objective C,所以 npm 升级依赖包版本的时候,如果依赖包使用的本地化实现, 这时候必须更改应用版本号(ios 修改 Info.plist 中的 CFBundleShortVersionString, android 修改 build.gradle 中的 versionName), 然后重新编译 app 发布到应用商店。 +- 推荐使用 code-push release-react 命令发布应用,该命令合并了打包和发布命令(eg. code-push release-react CodePushDemo-ios ios -d Production) +- 每次向 App Store 提交新的版本时,也应该基于该提交版本同时向 code-push-server 发布一个初始版本。(因为后面每次向 code-push-server 发布版本时,code-puse-server 都会和初始版本比较,生成补丁版本) + +### CodePush 命令行 + +[code-push-cli](https://github.com/shm-open/code-push-cli) 是用来管理 App 以及发布 CodePush 版本的, 请查看命令行项目的说明了解更多 + +### 客户端 + +- [React Native](https://github.com/Microsoft/react-native-code-push) +- [Cordova](https://github.com/microsoft/cordova-plugin-code-push) +- [Capacitor](https://github.com/mapiacompany/capacitor-codepush) + +## 如何安装 code-push-server + +- [Docker](./docs/install-server-by-docker.cn.md) (推荐) +- [直接安装](./docs/install-server.md) + +## 默认帐号和密码 + +- 帐号: `admin` +- 密码: `123456` + +## 登录并获取访问令牌 + +```sh +code-push login https:// +``` + +- 运行以上命令后将打开浏览器 → 登录账号 → 生成访问令牌 +- 令牌生成后,请将其输入回 CLI 终端以完成登录 +- WEB_UI_WHITELIST_IPS:允许访问 Web UI 的 IP 白名单(逗号分隔) + 例如:127.0.0.1,10.0.0.1 +- 访问令牌的有效期为 30 天。 +- WEB_UI_ALLOW:仅当该值设置为 true 时,才允许访问 Web UI + +## 常见问题 + +- [修改密码](https://github.com/lisong/code-push-server/issues/43) +- [code-push-server 使用+一些需要注意的地方](https://github.com/lisong/code-push-server/issues/135) +- 支持的 targetBinaryVersion + - `*` + - `1.2.3` + - `1.2`/`1.2.*` + - `1.2.3 - 1.2.7` + - `>=1.2.3 <1.2.7` + - `~1.2.3` + - `^1.2.3` + +``` + +``` diff --git a/README.ko.md b/README.ko.md new file mode 100644 index 00000000..9d2e3bc5 --- /dev/null +++ b/README.ko.md @@ -0,0 +1,115 @@ +# CodePush Server ![Node.js CI](https://github.com/shm-open/code-push-server/workflows/Node.js%20CI/badge.svg) + +[[영어 버전 English]](./README.md) [[중국어 버전 中文版]](./README.cn.md) + +CodePush Server는 CodePush 프로그램 서버입니다. +Microsoft 공식 CodePush 서비스는 아시아 지역에서 속도가 느린 경우가 많기 때문에, 우리는 자체 서버를 구축하여 사용합니다. + +- (해당 Repo의 오너가 중국인이므로 중국어 위주의 안내를 단순 한국어로 번역 했음을 미리 안내합니다.) + +## Requirement + +- Node.js v24.6.0 by package.json > engines +- npm install -g install @shm-open/code-push-cli +- data, storage 이름으로 디렉토리 생성후 서버 구동 + +## Key Changes + +- `AppErrorI18n` 클래스를 추가하여 에러 메시지를 포함한 다양한 텍스트에 대한 다국어(i18n) 지원을 제공함. +- 요청(Request) 컨텍스트에 `i18n` 유틸리티와 `lang` 필드를 추가하여 라우터 및 서비스 계층에서 일관된 번역 기능을 활용할 수 있도록 개선함. +- JSON 파일을 import하는 경우 TypeScript가 `src` 외부 디렉터리를 소스 경로로 포함하게 되어 `bin/locales` 및 `bin/src` 디렉터리가 생성되는 문제가 발생함. +- 기존 `bin` 디렉터리의 구조를 변경하지 않기 위해, i18n 관련 리소스(`locales` 디렉터리)를 `src/locales`로 이동하여 빌드 결과물을 안정적으로 유지함. +- App Tester의 semver 포맷 처리를 개선하기 위해 `parseVersion` 유틸 함수를 수정하고, `cleanVersion` 과정을 선행하도록 구조를 보완함. + - e.g., `'2.10.2-stg-01'` → `'2.10.2'` + +## 이 포크(Fork)에 대하여 + +원본 프로젝트인 [code-push-server](https://github.com/lisong/code-push-server)가 현재 활발히 유지·보수되고 있지 않기 때문에, 우리는 다음 목적을 위해 이 포크를 만들었습니다: + +- 의존성을 최신 상태로 유지 +- 최신 공식 CodePush 클라이언트와의 호환성 문제 해결 +- 공식 `react-native-code-push` 클라이언트만 사용하기 때문에, + [is_use_diff_text](https://github.com/lisong/code-push-server#advance-feature) 같은 커스텀 기능은 지원하지 않습니다. +- 프로덕션에서는 `react-native-code-push`만 사용합니다. + 다른 CodePush 클라이언트도 대부분 동일하게 동작할 것이지만, 문제가 있다면 Issue 또는 PR 환영합니다. + +## 지원되는 저장소(Storage) 모드 + +- local: 로컬 머신(서버 디스크)에 번들 파일 저장 +- qiniu: [qiniu](http://www.qiniu.com/)에 저장 +- s3: [AWS S3](https://aws.amazon.com/)에 저장 +- oss: [Alibaba Cloud OSS](https://www.aliyun.com/product/oss)에 저장 +- tencentcloud: [Tencent Cloud COS](https://cloud.tencent.com/product/cos)에 저장 + +## CodePush 핫 업데이트 올바르게 사용하기 + +- Apple App은 핫 업데이트 사용을 허용하지만, + [Apple 개발자 약관](https://developer.apple.com/programs/ios/information/iOS_Program_Information_4_3_15.pdf)에 따라 사용자 경험을 해치지 않도록 **반드시 Silent Update(무알림 업데이트)** 로만 사용해야 합니다. + + Google Play는 silent update를 허용하지 않으며, **업데이트 안내 팝업을 반드시 표시해야 합니다.** + + 중국 Android 마켓은 **Silent Update만 허용**합니다. + 팝업을 띄우면 “최신 버전의 바이너리 앱을 제출하세요”라는 이유로 반려될 수 있습니다. + +- React Native는 플랫폼별로 bundle 파일이 다르기 때문에, + CodePush Server 사용 시 **iOS/Android 앱을 각각 따로 생성**해야 합니다. + 예: `CodePushDemo-ios`, `CodePushDemo-android` + +- `react-native-code-push`는 리소스 파일만 업데이트하고, + **Java / Objective-C 네이티브 코드는 업데이트하지 않습니다.** + + 따라서 npm 패키지 버전을 올렸는데 해당 패키지가 네이티브 코드를 변경했다면, + 반드시 **앱 버전(ios: Info.plist의 CFBundleShortVersionString / android: build.gradle의 versionName)** 을 증가시키고 + **새로운 앱을 스토어에 제출해야 합니다.** + +- `code-push release-react` 명령을 사용하여 배포할 것을 추천합니다. + (예: `code-push release-react CodePushDemo-ios ios -d Production`) + 이 명령은 번들 생성과 배포를 한 번에 수행합니다. + +- App Store에 새 버전을 제출할 때는 반드시 **해당 버전에 대한 초기 CodePush 릴리즈도 함께 업로드**해야 합니다. + 이후 모든 CodePush 릴리즈는 이 초기 버전을 기준으로 diff 패치를 생성하기 때문입니다. + +### CodePush CLI + +- 앱 관리 및 CodePush 릴리즈 배포는 다음 [code-push-cli](https://github.com/shm-open/code-push-cli)를 사용하세요. + +### 클라이언트 + +- [React Native](https://github.com/Microsoft/react-native-code-push) +- [Cordova](https://github.com/microsoft/cordova-plugin-code-push) +- [Capacitor](https://github.com/mapiacompany/capacitor-codepush) + +## CodePush Server 설치 방법 + +- [docker](./docs/install-server-by-docker.md) (추천) +- [수동 설치](./docs/install-server.md) + +## 기본 계정 정보 + +- 계정: `admin` +- 비밀번호: `123456` + +## 로그인 및 엑세스 토큰 발급하기 + +```sh +code-push login https:// +``` + +- 위 커맨드를 통해 웹브라우저 오픈하기 +- 토큰 발급 후 CLI 터미널에 입력 +- 토큰 유효기간은 약 30일 +- WEB_UI_WHITELIST_IPS: e.g., 127.0.0.1,10.0.0.1 +- WEB_UI_ALLOW: true인 경우에만 웹브라우저 UI 노출 허용 + +## FAQ + +- [비밀번호 변경](https://github.com/lisong/code-push-server/issues/43) +- [code-push-server 일반적인 문제 해결 (중국어)](https://github.com/lisong/code-push-server/issues/135) +- 지원되는 targetBinaryVersion 형식 + - `*` + - `1.2.3` + - `1.2` / `1.2.*` + - `1.2.3 - 1.2.7` + - `>=1.2.3 <1.2.7` + - `~1.2.3` + - `^1.2.3` diff --git a/README.md b/README.md index 1611e8db..193e98e0 100644 --- a/README.md +++ b/README.md @@ -1,99 +1,76 @@ -# CodePush Server [source](https://github.com/lisong/code-push-server) +# CodePush Server ![Node.js CI](https://github.com/shm-open/code-push-server/workflows/Node.js%20CI/badge.svg) -[![NPM](https://nodei.co/npm/code-push-server.svg?downloads=true&downloadRank=true&stars=true)](https://nodei.co/npm/code-push-server/) +[[Korean version 한국어]](./README.ko.md) [[Chinese version 中文版]](./README.cn.md) -[![NPM Version](https://img.shields.io/npm/v/code-push-server.svg)](https://npmjs.org/package/code-push-server) -[![Node.js Version](https://img.shields.io/node/v/code-push-server.svg)](https://nodejs.org/en/download/) -[![Linux Status](https://img.shields.io/travis/lisong/code-push-server/master.svg?label=linux)](https://travis-ci.org/lisong/code-push-server) -[![Windows Status](https://img.shields.io/appveyor/ci/lisong/code-push-server/master.svg?label=windows)](https://ci.appveyor.com/project/lisong/code-push-server) -[![Coverage Status](https://img.shields.io/coveralls/lisong/code-push-server/master.svg)](https://coveralls.io/github/lisong/code-push-server) -[![Dependency Status](https://img.shields.io/david/lisong/code-push-server.svg)](https://david-dm.org/lisong/code-push-server) -[![Known Vulnerabilities](https://snyk.io/test/npm/code-push-server/badge.svg)](https://snyk.io/test/npm/code-push-server) -[![Licenses](https://img.shields.io/npm/l/code-push-server.svg)](https://spdx.org/licenses/MIT) +CodePush Server is a CodePush program server. The official Microsoft CodePush service is slow in China, therefore we use this to host our own server. -CodePush Server is a CodePush progam server! microsoft CodePush cloud is slow in China, we can use this to build our's. I use [qiniu](http://www.qiniu.com/) to store the files, because it's simple and quick! Or you can use [local/s3/oss/tencentcloud] storage, just modify config.js file, it's simple configure. +## About this fork +Since the original [code-push-server](https://github.com/lisong/code-push-server) project is not actively maintained, we created this fork to: -## Support Storage mode +- keep dependencies up-to-date +- fix any compatibility issue with latest official code-push clients +- we only stick to official react-native-code-push client, therefore the customized feature like [is_use_diff_text](https://github.com/lisong/code-push-server#advance-feature) won't be supported. +- we only use react-native-code-push client in production, most of the feature should be no difference for the rest CodePush clients, but if you found any, issues and PRs are always welcome. -- local *storage bundle file in local machine* -- qiniu *storage bundle file in [qiniu](http://www.qiniu.com/)* -- s3 *storage bundle file in [aws](https://aws.amazon.com/)* -- oss *storage bundle file in [aliyun](https://www.aliyun.com/product/oss)* -- tencentcloud *storage bundle file in [tencentcloud](https://cloud.tencent.com/product/cos)* +## Support Storage mode -## 正确使用code-push热更新 +- local: store bundle files in local machine +- qiniu: store bundle files in [qiniu](http://www.qiniu.com/) +- s3: store bundle files in [aws](https://aws.amazon.com/) +- oss: store bundle files in [aliyun](https://www.aliyun.com/product/oss) +- tencentcloud: store bundle files in [tencentcloud](https://cloud.tencent.com/product/cos) -- 苹果App允许使用热更新[Apple's developer agreement](https://developer.apple.com/programs/ios/information/iOS_Program_Information_4_3_15.pdf), 为了不影响用户体验,规定必须使用静默更新。 Google Play不能使用静默更新,必须弹框告知用户App有更新。中国的android市场必须采用静默更新(如果弹框提示,App会被“请上传最新版本的二进制应用包”原因驳回)。 -- react-native 不同平台bundle包不一样,在使用code-push-server的时候必须创建不同的应用来区分(eg. CodePushDemo-ios 和 CodePushDemo-android) -- react-native-code-push只更新资源文件,不会更新java和Objective C,所以npm升级依赖包版本的时候,如果依赖包使用的本地化实现, 这时候必须更改应用版本号(ios修改Info.plist中的CFBundleShortVersionString, android修改build.gradle中的versionName), 然后重新编译app发布到应用商店。 -- 推荐使用code-push release-react 命令发布应用,该命令合并了打包和发布命令(eg. code-push release-react CodePushDemo-ios ios -d Production) -- 每次向App Store提交新的版本时,也应该基于该提交版本同时向code-push-server发布一个初始版本。(因为后面每次向code-push-server发布版本时,code-puse-server都会和初始版本比较,生成补丁版本) +## Correct use of code-push hot update +- Apple App allows the use of hot updates [Apple's developer agreement](https://developer.apple.com/programs/ios/information/iOS_Program_Information_4_3_15.pdf), in order not to affect the user experience, it is stipulated that silent updates must be used. Google Play cannot use silent updates, and a pop-up box must inform users that there is an update to the app. China's android market must use silent updates (if the pop-up box prompts, the app will be rejected by the reason of "please upload the latest version of the binary application package"). +- The bundles of react-native are different for different platforms. When using code-push-server, you must create different applications to distinguish them (eg. CodePushDemo-ios and CodePushDemo-android) +- react-native-code-push only updates resource files, not java and Objective C, so when npm upgrades the version of the dependent package, if the localized implementation used by the dependent package, the application version number must be changed at this time (ios modify Info CFBundleShortVersionString in .plist, android modify versionName in build.gradle), then recompile the app and publish it to the app store. +- It is recommended to use the code-push release-react command to release the application, which combines the packaging and release commands (eg. code-push release-react CodePushDemo-ios ios -d Production) +- Every time a new version is submitted to the App Store, an initial version should also be released to code-push-server based on the submitted version. (Because every time a version is released to code-push-server, code-puse-server will compare it with the initial version to generate a patch version) -### shell login +### CodePush Cli -```shell -$ code-push login http://api.code-push.com #登录 -``` - -### [web](http://www.code-push.com) - -访问:http://www.code-push.com - -### client eg. - -[ReactNative CodePushDemo](https://github.com/lisong/code-push-demo-app) - -[Cordova CodePushDemo](https://github.com/lisong/code-push-cordova-demo-app) - -## HOW TO INSTALL code-push-server - -- [docker](https://github.com/lisong/code-push-server/blob/master/docker/README.md) (recommend) -- [manual operation](https://github.com/lisong/code-push-server/blob/master/docs/README.md) - -## DEFAULT ACCOUNT AND PASSWORD - -- account: `admin` -- password: `123456` +check out the [code-push-cli](https://github.com/shm-open/code-push-cli) which works with server for manage apps and publish releases -## HOW TO USE +### Clients -- [normal](https://github.com/lisong/code-push-server/blob/master/docs/react-native-code-push.md) -- [react-native-code-push](https://github.com/Microsoft/react-native-code-push) -- [code-push](https://github.com/Microsoft/code-push) +- [React Native](https://github.com/Microsoft/react-native-code-push) +- [Cordova](https://github.com/microsoft/cordova-plugin-code-push) +- [Capacitor](https://github.com/mapiacompany/capacitor-codepush) +## How To Install code-push-server -## ISSUES +- [docker](./docs/install-server-by-docker.md) (recommended) +- [manual operation](./docs/install-server.md) -[code-push-server normal solution](https://github.com/lisong/code-push-server/issues/135) +## Default Account and Password -[An unknown error occurred](https://github.com/lisong/code-push-server/issues?utf8=%E2%9C%93&q=unknown) +- account: `admin` +- password: `123456` -[modify password](https://github.com/lisong/code-push-server/issues/43) - - -# UPDATE TIME LINE - -- targetBinaryVersion support - - `*` - - `1.2.3` - - `1.2`/`1.2.*` - - `1.2.3 - 1.2.7` - - `>=1.2.3 <1.2.7` - - `~1.2.3` - - `^1.2.3` - - -## Advance Feature - -> use google diff-match-patch calculate text file diff patch - -- support iOS and Android -- use `"react-native-code-push": "git+https://git@github.com/lisong/react-native-code-push.git"` instead `"react-native-code-push": "x.x.x"` in `package.json` -- change `apps`.`is_use_diff_text` to `1` in mysql codepush database - -## License -MIT License [read](https://github.com/lisong/code-push-server/blob/master/LICENSE) +## Login and Access Token Issuance +```sh +code-push login https:// +``` +- Run the command above to open the web browser → authenticate → issue an access token +- After the token is issued, enter it back into the CLI terminal when prompted +- The access token is valid for 30 days. +- WEB_UI_WHITELIST_IPS: Comma-separated list of allowed IP addresses + e.g. 127.0.0.1,10.0.0.1 +- WEB_UI_ALLOW: Web UI access is enabled only when this value is set to true + +## FAQ + +- [modify password](https://github.com/lisong/code-push-server/issues/43) +- [code-push-server normal solution (CN)](https://github.com/lisong/code-push-server/issues/135) +- targetBinaryVersion support + - `*` + - `1.2.3` + - `1.2`/`1.2.*` + - `1.2.3 - 1.2.7` + - `>=1.2.3 <1.2.7` + - `~1.2.3` + - `^1.2.3` diff --git a/app.js b/app.js deleted file mode 100644 index ee93e3cc..00000000 --- a/app.js +++ /dev/null @@ -1,122 +0,0 @@ -var express = require('express'); -var path = require('path'); -var favicon = require('serve-favicon'); -var cookieParser = require('cookie-parser'); -var bodyParser = require('body-parser'); -var helmet = require('helmet'); -var config = require('./core/config'); -var _ = require('lodash'); -var fs = require('fs'); - -var routes = require('./routes/index'); -var indexV1 = require('./routes/indexV1'); -var auth = require('./routes/auth'); -var accessKeys = require('./routes/accessKeys'); -var account = require('./routes/account'); -var users = require('./routes/users'); -var apps = require('./routes/apps'); -var AppError = require('./core/app-error'); -var log4js = require('log4js'); -var log = log4js.getLogger("cps:app"); -var app = express(); -app.use(helmet()); -app.disable('x-powered-by'); -// view engine setup -app.set('views', path.join(__dirname, 'views')); -app.set('view engine', 'pug'); - -app.use(log4js.connectLogger(log4js.getLogger("http"), {level: log4js.levels.INFO, nolog:'\\.gif|\\.jpg|\\.js|\\.css$' })); - -app.use(bodyParser.json()); -app.use(bodyParser.urlencoded({ extended: false })); -app.use(cookieParser()); -app.use(express.static(path.join(__dirname, 'public'))); - -//use nginx in production -//if (app.get('env') === 'development') { - log.debug("set Access-Control Header"); - app.all('*', function(req, res, next) { - res.header("Access-Control-Allow-Origin", "*"); - res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, Authorization, X-CodePush-Plugin-Version, X-CodePush-Plugin-Name, X-CodePush-SDK-Version"); - res.header("Access-Control-Allow-Methods","PUT,POST,GET,PATCH,DELETE,OPTIONS"); - log.debug("use set Access-Control Header"); - next(); - }); -//} - -log.debug("config common.storageType value: " + _.get(config, 'common.storageType')); - -if (_.get(config, 'common.storageType') === 'local') { - var localStorageDir = _.get(config, 'local.storageDir'); - if (localStorageDir) { - - log.debug("config common.storageDir value: " + localStorageDir); - - if (!fs.existsSync(localStorageDir)) { - var e = new Error(`Please create dir ${localStorageDir}`); - log.error(e); - throw e; - } - try { - log.debug('checking storageDir fs.W_OK | fs.R_OK'); - fs.accessSync(localStorageDir, fs.W_OK | fs.R_OK); - log.debug('storageDir fs.W_OK | fs.R_OK is ok'); - } catch (e) { - log.error(e); - throw e; - } - log.debug("static download uri value: " + _.get(config, 'local.public', '/download')); - app.use(_.get(config, 'local.public', '/download'), express.static(localStorageDir)); - } else { - log.error('please config local storageDir'); - } -} - -app.use('/', routes); -app.use('/v0.1/public/codepush', indexV1); -app.use('/auth', auth); -app.use('/accessKeys', accessKeys); -app.use('/account', account); -app.use('/users', users); -app.use('/apps', apps); - -// development error handler -// will print stacktrace -if (app.get('env') === 'development') { - app.use(function(req, res, next) { - var err = new AppError.NotFound(); - res.status(err.status || 404); - res.render('error', { - message: err.message, - error: err - }); - log.error(err); - }); - app.use(function(err, req, res, next) { - res.status(err.status || 500); - res.render('error', { - message: err.message, - error: err - }); - log.error(err); - }); -} else { - app.use(function(req, res, next) { - var e = new AppError.NotFound(); - res.status(404).send(e.message); - log.debug(e); - }); - // production error handler - // no stacktraces leaked to user - app.use(function(err, req, res, next) { - if (err instanceof AppError.AppError) { - res.send(err.message); - log.debug(err); - } else { - res.status(err.status || 500).send(err.message); - log.error(err); - } - }); -} - -module.exports = app; diff --git a/appveyor.yml b/appveyor.yml deleted file mode 100644 index 977b5a1e..00000000 --- a/appveyor.yml +++ /dev/null @@ -1,26 +0,0 @@ -init: - - git config --global core.autocrlf input - -environment: - matrix: - - nodejs_version: "8.10.0" - -services: - - mysql -install: - - ps: Install-Product node $env:nodejs_version - - npm install npm@next - - cmd: nuget install redis-64 -excludeversion - - cmd: redis-64\tools\redis-server.exe --service-install - - cmd: redis-64\tools\redis-server.exe --service-start - # - if exist node_modules node_modules\.bin\npm prune - # - if exist node_modules node_modules\.bin\npm rebuild - - node_modules\.bin\npm install -test_script: - - node --version - - node_modules\.bin\npm --version - - set NODE_ENV=test - - set CONFIG_FILE=config/config.testwin.js - - node_modules\.bin\npm run test-win -build: off -version: "{build}" diff --git a/bin/db b/bin/db deleted file mode 100755 index 005b8810..00000000 --- a/bin/db +++ /dev/null @@ -1,138 +0,0 @@ -#!/usr/bin/env node - -/** - * Module dependencies. - */ -var fs = require('fs'); -var path = require('path'); -var _ = require('lodash'); -var mysql = require('mysql2'); -var Promise = require("bluebird"); -var common = require("../core/utils/common"); -var constConfig = require('../core/const'); -var yargs = require('yargs') - .usage('Usage: $0 [options]') - .command('init', '初始化数据库', { - dbpassword: { - alias: 'dbpassword', - type: 'string' - } - }) - .command('upgrade', '升级数据库', { - dbpassword: { - alias: 'dbpassword', - type: 'string' - } - }) - .example('$0 init --dbname codepush --dbhost localhost --dbuser root --dbpassword 123456 --dbport 3306 --force', '初始化code-push-server数据库') - .example('$0 upgrade --dbname codepush --dbhost localhost --dbuser root --dbpassword 123456 --dbport 3306', '升级code-push-server数据库') - .default({dbname: 'codepush', dbhost: 'localhost', dbuser: 'root', dbpassword: null}) - .help('h') - .alias('h', 'help'); -var argv = yargs.argv; -var command = argv._[0]; -var dbname = argv.dbname ? argv.dbname : 'codepush'; -var dbhost = argv.dbhost ? argv.dbhost : 'localhost'; -var dbuser = argv.dbuser ? argv.dbuser : 'root'; -var dbport = argv.dbport ? argv.dbport : 3306; -var dbpassword = argv.dbpassword; - -if (command === 'init') { - var connection2; - var connection = mysql.createConnection({ - host: dbhost, - user: dbuser, - password: dbpassword, - port: dbport - }); - var createDatabaseSql = argv.force ? `CREATE DATABASE IF NOT EXISTS ${dbname}` : - `CREATE DATABASE ${dbname}`; - Promise.promisifyAll(connection); - connection.connect(); - connection.queryAsync(createDatabaseSql) - .then(function(){ - connection2 = mysql.createConnection({ - host: dbhost, - user: dbuser, - password: dbpassword, - database: dbname, - multipleStatements: true, - port: dbport - }); - connection2.connect(); - Promise.promisifyAll(connection2); - return connection2; - }) - .then(function(connection2){ - var sql = fs.readFileSync(path.resolve(__dirname, '../sql/codepush-all.sql'), 'utf-8'); - return connection2.queryAsync(sql); - }) - .then(function(){ - console.log('success.'); - }) - .catch(function(e){ - console.log(e); - }) - .finally(function(){ - if(connection) connection.end(); - if(connection2) connection2.end() - }); -} else if (command == 'upgrade'){ - try { - var connection = mysql.createConnection({ - host: dbhost, - user: dbuser, - password: dbpassword, - database: dbname, - multipleStatements: true, - port: dbport - }); - Promise.promisifyAll(connection); - connection.connect() - } catch(e) { - console.error('connect mysql error, check params',e); - return; - } - - return Promise.coroutine(function*(val){ - var version_no = '0.0.1'; - var rs = yield connection.queryAsync('select `version` from `versions` where `type`=1 limit 1'); - version_no = _.get(rs,'0.version', '0.0.1'); - if (version_no == constConfig.CURRENT_DB_VERSION) { - console.log('Everything up-to-date.'); - process.exit(0); - } - var allSqlFile = [ - {version:'0.2.14', 'path':path.resolve(__dirname, '../sql/codepush-v0.2.14-patch.sql')}, - {version:'0.2.15', 'path':path.resolve(__dirname, '../sql/codepush-v0.2.15-patch.sql')}, - {version:'0.3.0', 'path':path.resolve(__dirname, '../sql/codepush-v0.3.0-patch.sql')}, - {version:'0.4.0', 'path':path.resolve(__dirname, '../sql/codepush-v0.4.0-patch.sql')}, - {version:'0.5.0', 'path':path.resolve(__dirname, '../sql/codepush-v0.5.0-patch.sql')} - ]; - for (var i = 0; i < allSqlFile.length; i++) { - if(!_.gt(allSqlFile[i]['version'], version_no)) { - continue; - } - try { - var sql = fs.readFileSync(allSqlFile[i]['path'], 'utf-8'); - console.log('exec sql file:' + allSqlFile[i]['path']); - yield connection.queryAsync(sql); - console.log('success exec sql file:' + allSqlFile[i]['path']); - } catch (e) { - console.error('error exec sql file:' + allSqlFile[i]['path']); - throw e; - } - } - })() - .then(function(){ - console.log('Upgrade success.'); - }) - .catch(function(e){ - console.error(e); - }) - .finally(function(){ - if(connection) connection.end(); - }); -} else { - yargs.showHelp(); -} diff --git a/bin/www b/bin/www deleted file mode 100755 index 4f086a7b..00000000 --- a/bin/www +++ /dev/null @@ -1,127 +0,0 @@ -#!/usr/bin/env node - -/** - * Module dependencies. - */ - -var log4js = require('log4js'); -var http = require('http'); -var validator = require('validator') -var _ = require('lodash') -var config = require('../core/config'); -var constConfig = require('../core/const'); -log4js.configure(_.get(config, 'log4js', { - appenders: {console: { type: 'console'}}, - categories : { default: { appenders: ['console'], level: 'info' }} -})); -var log = log4js.getLogger("startup") - -var app = require('../app'); - -/** - * Get port from environment and store in Express. - */ - -var port = normalizePort(process.env.PORT || '3000'); -log.debug('port '+ port); - -var host = null; -if (process.env.HOST) { - log.debug('process.env.HOST '+ process.env.HOST); - if (validator.isIP(process.env.HOST)) { - log.trace(process.env.HOST + ' valid'); - host = process.env.HOST; - } else { - log.warn('process.env.HOST '+ process.env.HOST + ' invalid, use 0.0.0.0 instead'); - } -} -app.set('port', port); - -/** - * Create HTTP server. - */ - -var server = http.createServer(app); - -/** - * Listen on provided port, on all network interfaces. - */ -var models = require('../models'); -models.Versions.findOne({where:{type:1}}) -.then(function(v){ - if (!v || v.get('version') != constConfig.CURRENT_DB_VERSION) { - throw new Error('Please upgrade your database. usage `npm run upgrade` or `code-push-server-db upgrade`'); - } - server.listen(port, host); - server.on('error', onError); - server.on('listening', onListening); - return; -}) -.catch(function(e){ - if (_.startsWith(e.message, 'ER_NO_SUCH_TABLE')) { - log.error(new Error(`Please upgrade your database. usage bin/db upgrade or code-push-server-db upgrade`)); - } else { - log.error(e); - } - process.exit(1); -}); - -/** - * Normalize a port into a number, string, or false. - */ - -function normalizePort(val) { - var port = parseInt(val, 10); - - if (isNaN(port)) { - // named pipe - return val; - } - - if (port >= 0) { - // port number - return port; - } - - return false; -} - -/** - * Event listener for HTTP server "error" event. - */ - -function onError(error) { - if (error.syscall !== 'listen') { - throw error; - } - - var bind = typeof port === 'string' - ? 'Pipe ' + port - : 'Port ' + port; - - // handle specific listen errors with friendly messages - switch (error.code) { - case 'EACCES': - log.error(bind + ' requires elevated privileges'); - process.exit(1); - break; - case 'EADDRINUSE': - log.error(bind + ' is already in use'); - process.exit(1); - break; - default: - throw error; - } -} - -/** - * Event listener for HTTP server "listening" event. - */ - -function onListening() { - var addr = server.address(); - var bind = typeof addr === 'string' - ? 'pipe ' + addr - : 'port ' + addr.port; - log.info('Listening on ' + bind); -} diff --git a/config/config.js b/config/config.js deleted file mode 100644 index 0789b5ee..00000000 --- a/config/config.js +++ /dev/null @@ -1,136 +0,0 @@ -var os = require('os'); - -var config = {}; -config.development = { - // Config for database, only support mysql. - db: { - username: process.env.RDS_USERNAME || "root", - password: process.env.RDS_PASSWORD || null, - database: process.env.DATA_BASE || "codepush", - host: process.env.RDS_HOST || "127.0.0.1", - port: process.env.RDS_PORT || 3306, - dialect: "mysql", - logging: false, - operatorsAliases: false, - }, - // Config for qiniu (http://www.qiniu.com/) cloud storage when storageType value is "qiniu". - qiniu: { - accessKey: "", - secretKey: "", - bucketName: "", - downloadUrl: "" // Binary files download host address. - }, - // Config for upyun (https://www.upyun.com/) storage when storageType value is "upyun" - upyun: { - storageDir: process.env.UPYUN_STORAGE_DIR, - serviceName: process.env.UPYUN_SERVICE_NAME, - operatorName: process.env.UPYUN_OPERATOR_NAME, - operatorPass: process.env.UPYUN_OPERATOR_PASS, - downloadUrl: process.env.DOWNLOAD_URL, - }, - // Config for Amazon s3 (https://aws.amazon.com/cn/s3/) storage when storageType value is "s3". - s3: { - accessKeyId: process.env.AWS_ACCESS_KEY_ID, - secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY, - sessionToken: process.env.AWS_SESSION_TOKEN, //(optional) - bucketName: process.env.BUCKET_NAME, - region: process.env.REGION, - downloadUrl: process.env.DOWNLOAD_URL, // binary files download host address. - }, - // Config for Aliyun OSS (https://www.aliyun.com/product/oss) when storageType value is "oss". - oss: { - accessKeyId: "", - secretAccessKey: "", - endpoint: "", - bucketName: "", - prefix: "", // Key prefix in object key - downloadUrl: "", // binary files download host address. - }, - // Config for tencentyun COS (https://cloud.tencent.com/product/cos) when storageType value is "oss". - tencentcloud: { - accessKeyId: "", - secretAccessKey: "", - bucketName: "", - region: "", - downloadUrl: "", // binary files download host address. - }, - // Config for local storage when storageType value is "local". - local: { - // Binary files storage dir, Do not use tmpdir and it's public download dir. - storageDir: process.env.STORAGE_DIR || "/Users/tablee/workspaces/storage", - // Binary files download host address which Code Push Server listen to. the files storage in storageDir. - downloadUrl: process.env.LOCAL_DOWNLOAD_URL || "http://127.0.0.1:3000/download", - // public static download spacename. - public: '/download' - }, - jwt: { - // Recommended: 63 random alpha-numeric characters - // Generate using: https://www.grc.com/passwords.htm - tokenSecret: process.env.TOKEN_SECRET ||'INSERT_RANDOM_TOKEN_KEY' - }, - common: { - /* - * tryLoginTimes is control login error times to avoid force attack. - * if value is 0, no limit for login auth, it may not safe for account. when it's a number, it means you can - * try that times today. but it need config redis server. - */ - tryLoginTimes: 0, - // CodePush Web(https://github.com/lisong/code-push-web) login address. - //codePushWebUrl: "http://127.0.0.1:3001/login", - // create patch updates's number. default value is 3 - diffNums: 3, - // data dir for caclulate diff files. it's optimization. - dataDir: process.env.DATA_DIR || os.tmpdir(), - // storageType which is your binary package files store. options value is ("local" | "qiniu" | "s3"| "oss" || "tencentcloud") - storageType: process.env.STORAGE_TYPE || "local", - // options value is (true | false), when it's true, it will cache updateCheck results in redis. - updateCheckCache: false, - // options value is (true | false), when it's true, it will cache rollout results in redis - rolloutClientUniqueIdCache: false, - }, - // Config for smtp email,register module need validate user email project source https://github.com/nodemailer/nodemailer - smtpConfig:{ - host: "smtp.aliyun.com", - port: 465, - secure: true, - auth: { - user: "", - pass: "" - } - }, - // Config for redis (register module, tryLoginTimes module) - redis: { - default: { - host: "127.0.0.1", - port: 6379, - retry_strategy: function (options) { - if (options.error.code === 'ECONNREFUSED') { - // End reconnecting on a specific error and flush all commands with a individual error - return new Error('The server refused the connection'); - } - if (options.total_retry_time > 1000 * 60 * 60) { - // End reconnecting after a specific timeout and flush all commands with a individual error - return new Error('Retry time exhausted'); - } - if (options.times_connected > 10) { - // End reconnecting with built in error - return undefined; - } - // reconnect after - return Math.max(options.attempt * 100, 3000); - } - } - } -} - -config.development.log4js = { - appenders: {console: { type: 'console'}}, - categories : { - "default": { appenders: ['console'], level:'error'}, - "startup": { appenders: ['console'], level:'info'}, - "http": { appenders: ['console'], level:'info'} - } -} - -config.production = Object.assign({}, config.development); -module.exports = config; diff --git a/config/config.test.js b/config/config.test.js deleted file mode 100644 index 22990cff..00000000 --- a/config/config.test.js +++ /dev/null @@ -1,59 +0,0 @@ -var os = require('os'); - -var config = {}; -config.test = { - db: { - username: "root", - password: null, - database: "codepush_test", - host: "127.0.0.1", - port: 3306, - dialect: "mysql", - logging: false, - operatorsAliases: false, - }, - local: { - storageDir: os.tmpdir(), - downloadUrl: "http://127.0.0.1:3000/download", - public: '/download' - }, - jwt: { - tokenSecret: 'INSERT_RANDOM_TOKEN_KEY' - }, - common: { - tryLoginTimes: 10, - diffNums: 3, - dataDir: os.tmpdir(), - storageType: "local", - updateCheckCache: true, - rolloutClientUniqueIdCache: false, - }, - smtpConfig: false, - redis: { - default: { - host: "127.0.0.1", - port: 6379, - retry_strategy: function (options) { - if (options.error.code === 'ECONNREFUSED') { - return new Error('The server refused the connection'); - } - if (options.total_retry_time > 1000 * 60 * 60) { - return new Error('Retry time exhausted'); - } - if (options.times_connected > 10) { - return undefined; - } - return Math.max(options.attempt * 100, 3000); - } - } - } -} -config.test.log4js = { - appenders: {console: { type: 'console'}}, - categories : { - "default": { appenders: ['console'], level:'error'}, - "startup": { appenders: ['console'], level:'info'}, - "http": { appenders: ['console'], level:'info'} - } -} -module.exports = config; diff --git a/config/config.testwin.js b/config/config.testwin.js deleted file mode 100644 index 2f5fa96d..00000000 --- a/config/config.testwin.js +++ /dev/null @@ -1,60 +0,0 @@ -var os = require('os'); - -var config = {}; -config.test = { - db: { - username: "root", - password: "Password12!", - database: "codepush_test", - host: "127.0.0.1", - port: 3306, - dialect: "mysql", - logging: false, - operatorsAliases: false, - }, - local: { - storageDir: os.tmpdir(), - downloadUrl: "http://127.0.0.1:3000/download", - public: '/download' - }, - jwt: { - tokenSecret: 'INSERT_RANDOM_TOKEN_KEY' - }, - common: { - tryLoginTimes: 10, - diffNums: 3, - dataDir: os.tmpdir(), - storageType: "local", - updateCheckCache: true, - rolloutClientUniqueIdCache: false, - }, - smtpConfig: false, - redis: { - default: { - host: "127.0.0.1", - port: 6379, - retry_strategy: function (options) { - if (options.error.code === 'ECONNREFUSED') { - return new Error('The server refused the connection'); - } - if (options.total_retry_time > 1000 * 60 * 60) { - return new Error('Retry time exhausted'); - } - if (options.times_connected > 10) { - return undefined; - } - // reconnect after - return Math.max(options.attempt * 100, 3000); - } - } - } -} -config.test.log4js = { - appenders: {console: { type: 'console'}}, - categories : { - "default": { appenders: ['console'], level:'error'}, - "startup": { appenders: ['console'], level:'info'}, - "http": { appenders: ['console'], level:'info'} - } -} -module.exports = config; diff --git a/core/app-error.js b/core/app-error.js deleted file mode 100644 index 178a573b..00000000 --- a/core/app-error.js +++ /dev/null @@ -1,35 +0,0 @@ -var util = require('util') - -var AppError = function (msg, constr) { - if(msg) { - msg = msg.toString(); - } - Error.captureStackTrace(this, constr || this) - this.message = msg || 'Error' - this.name = 'AppError' - this.status = 200 -} -util.inherits(AppError, Error) - -var NotFoundError = function(msg) { - NotFoundError.super_.call(this, msg, this.constructor) - this.message = msg || 'Not Found'; - this.name = 'NotFoundError' - this.status = 404 -} -util.inherits(NotFoundError, AppError) - -var UnauthorizedError = function(msg) { - UnauthorizedError.super_.call(this, msg, this.constructor) - this.message = msg || `401 Unauthorized`; - this.name = 'UnauthorizedError' - this.status = 401 -} -util.inherits(UnauthorizedError, AppError) - -module.exports = { - AppError: AppError, - NotFound: NotFoundError, - Unauthorized: UnauthorizedError -} - diff --git a/core/config.js b/core/config.js deleted file mode 100644 index a67eae86..00000000 --- a/core/config.js +++ /dev/null @@ -1,17 +0,0 @@ -var env = process.env.NODE_ENV || 'development'; -var _ = require('lodash'); -var path = require('path'); -var log4js = require('log4js'); -var log = log4js.getLogger("cps:config"); -var CONFIG_PATH = path.join(__dirname, '../config/config.js'); -if (process.env.CONFIG_FILE) { - CONFIG_PATH = path.join(__dirname, path.relative(__dirname, process.env.CONFIG_FILE)); - log.info(`process.env.CONFIG_FILE value: ${process.env.CONFIG_FILE}`) -} -log.info(`use config file ${CONFIG_PATH}`) -log.info(`use env ${env}`) -var config = _.get(require(CONFIG_PATH), env); -if (_.isEmpty(config)) { - throw new Error(`config is {}, check the env and config`); -} -module.exports = config; diff --git a/core/const.js b/core/const.js deleted file mode 100644 index f1d9b23b..00000000 --- a/core/const.js +++ /dev/null @@ -1,49 +0,0 @@ -function define(name, value) { - Object.defineProperty(exports, name, { - value: value, - enumerable: true - }); -} - -//定义支持的平台 -define("IOS", 1); -define("IOS_NAME", 'iOS'); -define("ANDROID", 2); -define("ANDROID_NAME", 'Android'); -define("WINDOWS", 3); -define("WINDOWS_NAME", 'Windows'); - -//定义支持的应用类型 -define("REACT_NATIVE", 1); -define("REACT_NATIVE_NAME", 'React-Native'); -define("CORDOVA", 2); -define("CORDOVA_NAME", 'Cordova'); - -define("PRODUCTION", 'Production'); -define("STAGING", 'Staging'); - - -define("IS_MANDATORY_YES", 1); -define("IS_MANDATORY_NO", 0); - - -define("IS_DISABLED_YES", 1); -define("IS_DISABLED_NO", 0); - - -define("RELEAS_EMETHOD_PROMOTE", 'Promote'); -define("RELEAS_EMETHOD_UPLOAD", 'Upload'); - -define("DEPLOYMENT_SUCCEEDED", 1); -define("DEPLOYMENT_FAILED", 2); - -define("DIFF_MANIFEST_FILE_NAME", 'hotcodepush.json'); - -//文本文件是否使用google diff-match-patch 计算差异 -define("IS_USE_DIFF_TEXT_NO", 0); -define("IS_USE_DIFF_TEXT_YES", 1); - - -define("CURRENT_DB_VERSION", '0.5.0'); - - diff --git a/core/middleware.js b/core/middleware.js deleted file mode 100644 index fc4054f2..00000000 --- a/core/middleware.js +++ /dev/null @@ -1,120 +0,0 @@ -'use strict'; -var _ = require('lodash'); -var Promise = require('bluebird'); -var security = require('../core/utils/security'); -var models = require('../models'); -var moment = require('moment'); -var AppError = require('./app-error') - -var middleware = module.exports - -var checkAuthToken = function (authToken) { - var objToken = security.parseToken(authToken); - return models.Users.findOne({ - where: {identical: objToken.identical} - }) - .then((users) => { - if (_.isEmpty(users)) { - throw new AppError.Unauthorized(); - } - var Sequelize = require('sequelize'); - return models.UserTokens.findOne({ - where: {tokens: authToken, uid: users.id, expires_at: { [Sequelize.Op.gt]: moment().format('YYYY-MM-DD HH:mm:ss') }} - }) - .then((tokenInfo) => { - if (_.isEmpty(tokenInfo)){ - throw new AppError.Unauthorized() - } - return users; - }) - }).then((users) => { - return users; - }) -} - -var checkAccessToken = function (accessToken) { - return new Promise((resolve, reject) => { - if (_.isEmpty(accessToken)) { - return reject(new AppError.Unauthorized()); - } - var config = require('../core/config'); - var tokenSecret = _.get(config, 'jwt.tokenSecret'); - var jwt = require('jsonwebtoken'); - try { - var authData = jwt.verify(accessToken, tokenSecret); - } catch (e) { - return reject(new AppError.Unauthorized()); - } - var uid = _.get(authData, 'uid', null); - var hash = _.get(authData, 'hash', null); - if (parseInt(uid) > 0) { - return models.Users.findOne({ - where: {id: uid} - }) - .then((users) => { - if (_.isEmpty(users)) { - throw new AppError.Unauthorized(); - } - if (!_.eq(hash, security.md5(users.get('ack_code')))){ - throw new AppError.Unauthorized(); - } - resolve(users); - }) - .catch((e) => { - reject(e); - }); - } else { - reject(new AppError.Unauthorized()); - } - }); -} - -middleware.checkToken = function(req, res, next) { - var authArr = _.split(req.get('Authorization'), ' '); - var authType = 1; - var authToken = null; - if (_.eq(authArr[0], 'Bearer')) { - authToken = authArr[1]; //Bearer - if (authToken && authToken.length > 64) { - authType = 2; - } else { - authType = 1; - } - } else if(_.eq(authArr[0], 'Basic')) { - authType = 2; - var b = new Buffer(authArr[1], 'base64'); - var user = _.split(b.toString(), ':'); - authToken = _.get(user, '1'); - } - if (authToken && authType == 1) { - checkAuthToken(authToken) - .then((users) => { - req.users = users; - next(); - return users; - }) - .catch((e) => { - if (e instanceof AppError.AppError) { - res.status(e.status || 404).send(e.message); - } else { - next(e); - } - }); - } else if (authToken && authType == 2) { - checkAccessToken(authToken) - .then((users) => { - req.users = users; - next(); - return users; - }) - .catch((e) => { - if (e instanceof AppError.AppError) { - res.status(e.status || 404).send(e.message); - } else { - next(e); - } - }); - } else { - res.send(new AppError.Unauthorized(`Auth type not supported.`)); - } -}; diff --git a/core/services/account-manager.js b/core/services/account-manager.js deleted file mode 100644 index 0eae4a9e..00000000 --- a/core/services/account-manager.js +++ /dev/null @@ -1,263 +0,0 @@ -'use strict'; -var Promise = require('bluebird'); -var models = require('../../models'); -var _ = require('lodash'); -var validator = require('validator'); -var security = require('../utils/security'); -var factory = require('../utils/factory'); -var moment = require('moment'); -var EmailManager = require('./email-manager'); -var config = require('../config'); -var AppError = require('../app-error'); -var log4js = require('log4js'); -var log = log4js.getLogger("cps:AccountManager"); - -var proto = module.exports = function (){ - function AccountManager() { - - } - AccountManager.__proto__ = proto; - return AccountManager; -}; - -proto.collaboratorCan = function(uid, appName) { - return this.getCollaborator(uid, appName) - .then((data) => { - if (!data) { - log.debug(`collaboratorCan App ${appName} not exists.`); - throw new AppError.AppError(`App ${appName} not exists.`); - } - log.debug('collaboratorCan yes'); - return data; - }); -}; - -proto.ownerCan = function(uid, appName) { - return this.getCollaborator(uid, appName) - .then((data) => { - if (!data) { - log.debug(`ownerCan App ${appName} not exists.`); - throw new AppError.AppError(`App ${appName} not exists.`); - } - if (!_.eq(_.get(data,'roles'), 'Owner') ) { - log.debug(`ownerCan Permission Deny, You are not owner!`); - throw new AppError.AppError("Permission Deny, You are not owner!"); - } - return data; - }); -}; - -proto.getCollaborator = function (uid, appName) { - return models.Collaborators.findByAppNameAndUid(uid, appName); -}; - -proto.findUserByEmail = function (email) { - return models.Users.findOne({where: {email: email}}) - .then((data) => { - if (_.isEmpty(data)) { - throw new AppError.AppError(email + " does not exist."); - } else { - return data; - } - }); -}; - -proto.getAllAccessKeyByUid = function (uid) { - return models.UserTokens.findAll({where: {uid: uid}, order:[['id', 'DESC']]}) - .then((tokens) => { - return _.map(tokens, function(v){ - return { - name: '(hidden)', - createdTime: parseInt(moment(v.created_at).format('x')), - createdBy: v.created_by, - expires: parseInt(moment(v.expires_at).format('x')), - friendlyName: v.name, - description: v.description, - }; - }); - }); -}; - -proto.isExsitAccessKeyName = function (uid, friendlyName) { - return models.UserTokens.findOne({ - where: {uid: uid, name: friendlyName} - }); -}; - -proto.createAccessKey = function (uid, newAccessKey, ttl, friendlyName, createdBy, description) { - return models.UserTokens.create({ - uid: uid, - name: friendlyName, - tokens: newAccessKey, - description: description, - created_by: createdBy, - expires_at: moment().add(ttl/1000, 'seconds').format('YYYY-MM-DD HH:mm:ss'), - created_at: moment().format('YYYY-MM-DD HH:mm:ss'), - }); -}; - -const LOGIN_LIMIT_PRE = 'LOGIN_LIMIT_PRE_'; - -proto.login = function (account, password) { - if (_.isEmpty(account)) { - return Promise.reject(new AppError.AppError("请您输入邮箱地址")) - } - if (_.isEmpty(password)) { - return Promise.reject(new AppError.AppError("请您输入密码")) - } - var where = {}; - if (validator.isEmail(account)) { - where = {email: account}; - }else { - where = {username: account}; - } - var tryLoginTimes = _.get(config, 'common.tryLoginTimes', 0); - return models.Users.findOne({where: where}) - .then((users) => { - if (_.isEmpty(users)) { - throw new AppError.AppError("您输入的邮箱或密码有误"); - } - return users; - }) - .then((users) => { - if (tryLoginTimes > 0) { - var loginKey = `${LOGIN_LIMIT_PRE}${users.id}`; - var client = factory.getRedisClient("default"); - return client.getAsync(loginKey) - .then((loginErrorTimes) => { - if (loginErrorTimes > tryLoginTimes) { - throw new AppError.AppError(`您输入密码错误次数超过限制,帐户已经锁定`); - } - return users; - }) - .finally(() => client.quit()); - } else { - return users; - } - }) - .then((users) => { - if (!security.passwordVerifySync(password, users.password)) { - if (tryLoginTimes > 0) { - var loginKey = `${LOGIN_LIMIT_PRE}${users.id}`; - var client = factory.getRedisClient("default"); - client.existsAsync(loginKey) - .then((isExists) => { - if (!isExists) { - var expires = moment().endOf('day').format('X') - moment().format('X'); - return client.setexAsync(loginKey, expires, 0); - } - return isExists; - }) - .then(() => { - return client.incrAsync(loginKey); - }) - .finally(() => client.quit()); - } - throw new AppError.AppError("您输入的邮箱或密码有误"); - } else { - return users; - } - }); -}; - -const REGISTER_CODE = "REGISTER_CODE_"; -const EXPIRED = 1200; -const EXPIRED_SPEED = 10; - -proto.sendRegisterCode = function (email) { - if (_.isEmpty(email)) { - return Promise.reject(new AppError.AppError("请您输入邮箱地址")); - } - return models.Users.findOne({where: {email: email}}) - .then((u) => { - if (u) { - throw new AppError.AppError(`"${email}" 已经注册过,请更换邮箱注册`); - } - }) - .then(() => { - //将token临时存储到redis - var token = security.randToken(40); - var client = factory.getRedisClient("default"); - return client.setexAsync(`${REGISTER_CODE}${security.md5(email)}`, EXPIRED, token) - .then(() => { - return token; - }) - .finally(() => client.quit()); - }) - .then((token) => { - //将token发送到用户邮箱 - var emailManager = new EmailManager(); - return emailManager.sendRegisterCode(email, token); - }) -}; - -proto.checkRegisterCode = function (email, token) { - return models.Users.findOne({where: {email: email}}) - .then((u) => { - if (u) { - throw new AppError.AppError(`"${email}" 已经注册过,请更换邮箱注册`); - } - }) - .then(() => { - var registerKey = `${REGISTER_CODE}${security.md5(email)}`; - var client = factory.getRedisClient("default"); - return client.getAsync(registerKey) - .then((storageToken) => { - if (_.isEmpty(storageToken)) { - throw new AppError.AppError(`验证码已经失效,请您重新获取`); - } - if (!_.eq(token, storageToken)) { - client.ttlAsync(registerKey) - .then((ttl) => { - if (ttl > 0) { - return client.expireAsync(registerKey, ttl - EXPIRED_SPEED); - } - return ttl; - }) - .finally(() => client.quit()); - throw new AppError.AppError(`您输入的验证码不正确,请重新输入`); - } - return storageToken; - }) - }) -} - -proto.register = function (email, password) { - return models.Users.findOne({where: {email: email}}) - .then((u) => { - if (u) { - throw new AppError.AppError(`"${email}" 已经注册过,请更换邮箱注册`); - } - }) - .then(() => { - var identical = security.randToken(9); - return models.Users.create({ - email: email, - password: security.passwordHashSync(password), - identical: identical - }); - }) -} - -proto.changePassword = function (uid, oldPassword, newPassword) { - if (!_.isString(newPassword) || newPassword.length < 6) { - return Promise.reject(new AppError.AppError("请您输入6~20位长度的新密码")); - } - return models.Users.findOne({where: {id: uid}}) - .then((u) => { - if (!u) { - throw new AppError.AppError(`未找到用户信息`); - } - return u; - }) - .then((u) => { - var isEq = security.passwordVerifySync(oldPassword, u.get('password')); - if (!isEq) { - throw new AppError.AppError(`您输入的旧密码不正确,请重新输入`); - } - u.set('password', security.passwordHashSync(newPassword)); - u.set('ack_code', security.randToken(5)); - return u.save(); - }); -}; - diff --git a/core/services/app-manager.js b/core/services/app-manager.js deleted file mode 100644 index b3a56811..00000000 --- a/core/services/app-manager.js +++ /dev/null @@ -1,154 +0,0 @@ -'use strict'; -var Promise = require('bluebird'); -var models = require('../../models'); -var _ = require('lodash'); -var security = require('../../core/utils/security'); -var AppError = require('../app-error'); - -var proto = module.exports = function (){ - function AppManager() { - - } - AppManager.__proto__ = proto; - return AppManager; -}; - -proto.findAppByName = function (uid, appName) { - return models.Apps.findOne({where: {name: appName, uid: uid}}); -}; - -proto.addApp = function (uid, appName, os, platform, identical) { - return models.sequelize.transaction((t) => { - return models.Apps.create({ - name: appName, - uid: uid, - os: os, - platform: platform - },{ - transaction: t - }) - .then((apps) => { - var constName = require('../const'); - var appId = apps.id; - var deployments = []; - var deploymentKey = security.randToken(28) + identical; - deployments.push({ - appid: appId, - name: constName.PRODUCTION, - last_deployment_version_id: 0, - label_id: 0, - deployment_key: deploymentKey - }); - deploymentKey = security.randToken(28) + identical; - deployments.push({ - appid: appId, - name: constName.STAGING, - last_deployment_version_id: 0, - label_id: 0, - deployment_key: deploymentKey - }); - return Promise.all([ - models.Collaborators.create({appid: appId, uid: uid, roles: "Owner"}, {transaction: t}), - models.Deployments.bulkCreate(deployments, {transaction: t}) - ]); - }); - }); -}; - -proto.deleteApp = function (appId) { - return models.sequelize.transaction((t) => { - return Promise.all([ - models.Apps.destroy({where: {id: appId}, transaction: t}), - models.Collaborators.destroy({where: {appid: appId}, transaction: t}), - models.Deployments.destroy({where: {appid: appId}, transaction: t}) - ]); - }); -}; - -proto.modifyApp = function (appId, params) { - return models.Apps.update(params, {where: {id:appId}}) - .spread((affectedCount, affectedRows) => { - if (!_.gt(affectedCount, 0)) { - throw AppError.AppError('modify errors'); - } - return affectedCount; - }); -}; - -proto.transferApp = function (appId, fromUid, toUid) { - return models.sequelize.transaction((t) => { - return Promise.all([ - models.Apps.update({uid: toUid}, {where: {id: appId}, transaction: t}), - models.Collaborators.destroy({where: {appid: appId, uid: fromUid}, transaction: t}), - models.Collaborators.destroy({where: {appid: appId, uid: toUid}, transaction: t}), - models.Collaborators.create({appid: appId, uid: toUid, roles: "Owner"}, {transaction: t}) - ]); - }); -}; - -proto.listApps = function (uid) { - const self = this; - return models.Collaborators.findAll({where : {uid: uid}}) - .then((data) => { - if (_.isEmpty(data)){ - return []; - } else { - var appIds = _.map(data, (v) => { return v.appid }); - var Sequelize = require('sequelize'); - return models.Apps.findAll({where: {id: {[Sequelize.Op.in]: appIds}}}); - } - }) - .then((appInfos) => { - var rs = Promise.map(_.values(appInfos), (v) => { - return self.getAppDetailInfo(v, uid) - .then((info) => { - var constName = require('../const'); - if (info.os == constName.IOS) { - info.os = constName.IOS_NAME; - } else if (info.os == constName.ANDROID) { - info.os = constName.ANDROID_NAME; - } else if (info.os == constName.WINDOWS) { - info.os = constName.WINDOWS_NAME; - } - if (info.platform == constName.REACT_NATIVE) { - info.platform = constName.REACT_NATIVE_NAME; - } else if (info.platform == constName.CORDOVA) { - info.platform = constName.CORDOVA_NAME; - } - return info; - }); - }); - return rs; - }); -}; - -proto.getAppDetailInfo = function (appInfo, currentUid) { - var appId = appInfo.get('id'); - return Promise.all([ - models.Deployments.findAll({where: {appid: appId}}), - models.Collaborators.findAll({where: {appid: appId}}), - ]) - .spread((deploymentInfos, collaboratorInfos) => { - return Promise.props({ - collaborators: Promise.reduce(collaboratorInfos, (allCol, collaborator) => { - return models.Users.findOne({where: {id: collaborator.get('uid')}}) - .then((u) => { - var isCurrentAccount = false; - if (_.eq(u.get('id'), currentUid)) { - isCurrentAccount = true; - } - allCol[u.get('email')] = {permission: collaborator.get('roles'), isCurrentAccount: isCurrentAccount}; - return allCol; - }); - }, {}), - - deployments: _.map(deploymentInfos, (item) => { - return _.get(item, 'name'); - }), - os: appInfo.get('os'), - platform: appInfo.get('platform'), - name: appInfo.get('name'), - id: appInfo.get('id') - }); - }); -}; diff --git a/core/services/client-manager.js b/core/services/client-manager.js deleted file mode 100644 index 87a16625..00000000 --- a/core/services/client-manager.js +++ /dev/null @@ -1,320 +0,0 @@ -'use strict'; -var Promise = require('bluebird'); -var models = require('../../models'); -var _ = require('lodash'); -var common = require('../utils/common'); -var factory = require('../utils/factory'); -var AppError = require('../app-error'); -var config = require('../config'); -var log4js = require('log4js'); -var log = log4js.getLogger("cps:ClientManager"); -var Sequelize = require('sequelize'); - -var proto = module.exports = function (){ - function ClientManager() { - - } - ClientManager.__proto__ = proto; - return ClientManager; -}; - -const UPDATE_CHECK = "UPDATE_CHECK"; -const CHOSEN_MAN = "CHOSEN_MAN"; -const EXPIRED = 600; - -proto.getUpdateCheckCacheKey = function(deploymentKey, appVersion, label, packageHash) { - return [UPDATE_CHECK, deploymentKey, appVersion, label, packageHash].join(':'); -} - -proto.clearUpdateCheckCache = function(deploymentKey, appVersion, label, packageHash) { - log.debug('clear cache Deployments key:', deploymentKey); - let redisCacheKey = this.getUpdateCheckCacheKey(deploymentKey, appVersion, label, packageHash); - var client = factory.getRedisClient("default"); - return client.keysAsync(redisCacheKey) - .then((data) => { - if (_.isArray(data)) { - return Promise.map(data, (key) => { - return client.delAsync(key); - }); - } - return null; - }) - .finally(() => client.quit()); -} - -proto.updateCheckFromCache = function(deploymentKey, appVersion, label, packageHash, clientUniqueId) { - const self = this; - var updateCheckCache = _.get(config, 'common.updateCheckCache', false); - if (updateCheckCache === false) { - return self.updateCheck(deploymentKey, appVersion, label, packageHash); - } - let redisCacheKey = self.getUpdateCheckCacheKey(deploymentKey, appVersion, label, packageHash); - var client = factory.getRedisClient("default"); - return client.getAsync(redisCacheKey) - .then((data) => { - if (data) { - try { - log.debug('updateCheckFromCache read from catch'); - var obj = JSON.parse(data); - return obj; - } catch (e) { - } - } - return self.updateCheck(deploymentKey, appVersion, label, packageHash, clientUniqueId) - .then((rs) => { - try { - log.debug('updateCheckFromCache read from db'); - var strRs = JSON.stringify(rs); - client.setexAsync(redisCacheKey, EXPIRED, strRs); - } catch (e) { - } - return rs; - }); - }) - .finally(() => client.quit()); -} - -proto.getChosenManCacheKey = function(packageId, rollout, clientUniqueId) { - return [CHOSEN_MAN, packageId, rollout, clientUniqueId].join(':'); -} - -proto.random = function(rollout) { - var r = Math.ceil(Math.random()*10000); - if (r < rollout * 100) { - return Promise.resolve(true); - } else { - return Promise.resolve(false); - } -} - -proto.chosenMan = function (packageId, rollout, clientUniqueId) { - var self = this; - if (rollout >= 100) { - return Promise.resolve(true); - } - var rolloutClientUniqueIdCache = _.get(config, 'common.rolloutClientUniqueIdCache', false); - if (rolloutClientUniqueIdCache === false) { - return self.random(rollout); - } else { - var client = factory.getRedisClient("default"); - var redisCacheKey = self.getChosenManCacheKey(packageId, rollout, clientUniqueId); - return client.getAsync(redisCacheKey) - .then((data) => { - if (data == 1) { - return true; - } else if (data == 2) { - return false; - } else { - return self.random(rollout) - .then((r)=>{ - return client.setexAsync(redisCacheKey, 60*60*24*7, r ? 1:2) - .then(()=>{ - return r; - }); - }); - } - }) - .finally(() => client.quit()); - } -} - -proto.updateCheck = function(deploymentKey, appVersion, label, packageHash, clientUniqueId) { - var rs = { - packageId: 0, - downloadURL: "", - downloadUrl: "", - description: "", - isAvailable: false, - isDisabled: true, - isMandatory: false, - appVersion: appVersion, - targetBinaryRange: "", - packageHash: "", - label: "", - packageSize: 0, - updateAppVersion: false, - shouldRunBinaryVersion: false, - rollout: 100 - }; - var self = this; - if (_.isEmpty(deploymentKey) || _.isEmpty(appVersion)) { - return Promise.reject(new AppError.AppError("please input deploymentKey and appVersion")) - } - return models.Deployments.findOne({where: {deployment_key: deploymentKey}}) - .then((dep) => { - if (_.isEmpty(dep)) { - throw new AppError.AppError('Not found deployment, check deployment key is right.'); - } - var version = common.parseVersion(appVersion); - return models.DeploymentsVersions.findAll({where: { - deployment_id: dep.id, - min_version: { [Sequelize.Op.lte]: version }, - max_version: { [Sequelize.Op.gt]: version } - }}) - .then((deploymentsVersionsMore) => { - var distance = 0; - var item = null; - _.map(deploymentsVersionsMore, function(value, index) { - if (index == 0) { - item = value; - distance = value.max_version - value.min_version; - } else { - if (distance > (value.max_version - value.min_version)) { - distance = value.max_version - value.min_version; - item = value; - } - } - }); - log.debug(item); - return item; - }); - }) - .then((deploymentsVersions) => { - var packageId = _.get(deploymentsVersions, 'current_package_id', 0); - if (_.eq(packageId, 0) ) { - return; - } - return models.Packages.findById(packageId) - .then((packages) => { - if (packages - && _.eq(packages.deployment_id, deploymentsVersions.deployment_id) - && !_.eq(packages.package_hash, packageHash)) { - rs.packageId = packageId; - rs.targetBinaryRange = deploymentsVersions.app_version; - rs.downloadUrl = rs.downloadURL = common.getBlobDownloadUrl(_.get(packages, 'blob_url')); - rs.description = _.get(packages, 'description', ''); - rs.isAvailable = _.eq(packages.is_disabled, 1) ? false : true; - rs.isDisabled = _.eq(packages.is_disabled, 1) ? true : false; - rs.isMandatory = _.eq(packages.is_mandatory, 1) ? true : false; - rs.appVersion = appVersion; - rs.packageHash = _.get(packages, 'package_hash', ''); - rs.label = _.get(packages, 'label', ''); - rs.packageSize = _.get(packages, 'size', 0); - rs.rollout = _.get(packages, 'rollout', 100); - } - return packages; - }) - .then((packages) => { - //增量更新 - if (!_.isEmpty(packages) && !_.eq(_.get(packages, 'package_hash', ""), packageHash)) { - return models.PackagesDiff.findOne({where: {package_id:packages.id, diff_against_package_hash: packageHash}}) - .then((diffPackage) => { - if (!_.isEmpty(diffPackage)) { - rs.downloadURL = common.getBlobDownloadUrl(_.get(diffPackage, 'diff_blob_url')); - rs.downloadUrl = common.getBlobDownloadUrl(_.get(diffPackage, 'diff_blob_url')); - rs.packageSize = _.get(diffPackage, 'diff_size', 0); - } - return; - }); - } else { - return; - } - }); - }) - .then(() => { - return rs; - }); -}; - -proto.getPackagesInfo = function (deploymentKey, label) { - if (_.isEmpty(deploymentKey) || _.isEmpty(label)) { - return Promise.reject(new AppError.AppError("please input deploymentKey and label")) - } - return models.Deployments.findOne({where: {deployment_key: deploymentKey}}) - .then((dep) => { - if (_.isEmpty(dep)) { - throw new AppError.AppError('does not found deployment'); - } - return models.Packages.findOne({where: {deployment_id: dep.id, label: label}}); - }) - .then((packages) => { - if (_.isEmpty(packages)) { - throw new AppError.AppError('does not found packages'); - } - return packages; - }); -}; - -proto.reportStatusDownload = function(deploymentKey, label, clientUniqueId) { - return this.getPackagesInfo(deploymentKey, label) - .then((packages) => { - return Promise.all([ - models.PackagesMetrics.findOne({where: {package_id: packages.id}}) - .then((metrics)=>{ - if (metrics) { - return metrics.increment('downloaded'); - } - return; - }), - models.LogReportDownload.create({ - package_id: packages.id, - client_unique_id: clientUniqueId - }) - ]); - }); -}; - -proto.reportStatusDeploy = function (deploymentKey, label, clientUniqueId, others) { - return this.getPackagesInfo(deploymentKey, label) - .then((packages) => { - var constConfig = require('../const'); - var statusText = _.get(others, "status"); - var status = 0; - if (_.eq(statusText, "DeploymentSucceeded")) { - status = constConfig.DEPLOYMENT_SUCCEEDED; - } else if (_.eq(statusText, "DeploymentFailed")) { - status = constConfig.DEPLOYMENT_FAILED; - } - var packageId = packages.id; - var previous_deployment_key = _.get(others, 'previousDeploymentKey'); - var previous_label = _.get(others, 'previousLabelOrAppVersion'); - if (status > 0) { - return Promise.all([ - models.LogReportDeploy.create({ - package_id: packageId, - client_unique_id: clientUniqueId, - previous_label: previous_label, - previous_deployment_key: previous_deployment_key, - status: status - }), - models.PackagesMetrics.findOne({where: {package_id: packageId}}) - .then((metrics)=>{ - if (_.isEmpty(metrics)) { - return; - } - if (_.eq(status, constConfig.DEPLOYMENT_SUCCEEDED)) { - return metrics.increment(['installed', 'active'],{by: 1}); - } else { - return metrics.increment(['installed', 'failed'],{by: 1}); - } - }) - ]) - .then(()=>{ - if (previous_deployment_key && previous_label) { - return models.Deployments.findOne({where: {deployment_key: previous_deployment_key}}) - .then((dep)=>{ - if (_.isEmpty(dep)) { - return; - } - return models.Packages.findOne({where: {deployment_id: dep.id, label: previous_label}}) - .then((p)=>{ - if (_.isEmpty(p)) { - return; - } - return models.PackagesMetrics.findOne({where:{package_id: p.id}}); - }); - }) - .then((metrics)=>{ - if (metrics) { - return metrics.decrement('active'); - } - return; - }); - } - return; - }); - } else { - return; - } - }); -}; diff --git a/core/services/collaborators.js b/core/services/collaborators.js deleted file mode 100644 index b2371103..00000000 --- a/core/services/collaborators.js +++ /dev/null @@ -1,63 +0,0 @@ -'use strict'; -var models = require('../../models'); -var _ = require('lodash'); -var AppError = require('../app-error'); - -var proto = module.exports = function (){ - function Collaborators() { - - } - Collaborators.__proto__ = proto; - return Collaborators; -}; - -proto.listCollaborators = function (appId) { - return models.Collaborators.findAll({where: {appid: appId}}) - .then((data) => { - return _.reduce(data, function(result, value, key) { - (result['uids'] || (result['uids'] = [])).push(value.uid); - result[value.uid] = value; - return result; - }, []); - }) - .then((coInfo) => { - var Sequelize = require('sequelize'); - return models.Users.findAll({where: {id: {[Sequelize.Op.in]: coInfo.uids}}}) - .then((data2) => { - return _.reduce(data2, function (result, value, key) { - var permission = ""; - if (!_.isEmpty(coInfo[value.id])) { - permission = coInfo[value.id].roles; - } - result[value.email] = {permission: permission}; - return result; - }, {}); - }); - }); -}; - -proto.addCollaborator = function (appId, uid) { - return models.Collaborators.findOne({where: {appid: appId, uid: uid}}) - .then((data) => { - if (_.isEmpty(data)){ - return models.Collaborators.create({ - appid: appId, - uid: uid, - roles: "Collaborator" - }); - }else { - throw new AppError.AppError('user already is Collaborator.'); - } - }); -}; - -proto.deleteCollaborator = function (appId, uid) { - return models.Collaborators.findOne({where: {appid: appId, uid: uid}}) - .then((data) => { - if (_.isEmpty(data)){ - throw new AppError.AppError('user is not a Collaborator'); - }else { - return models.Collaborators.destroy({where: {id: data.id}}); - } - }); -}; diff --git a/core/services/datacenter-manager.js b/core/services/datacenter-manager.js deleted file mode 100644 index c59d29ff..00000000 --- a/core/services/datacenter-manager.js +++ /dev/null @@ -1,123 +0,0 @@ -'use strict'; -var Promise = require('bluebird'); -var models = require('../../models'); -var _ = require('lodash'); -var fs = require('fs'); -var os = require('os'); -var security = require('../utils/security'); -var common = require('../utils/common'); -const MANIFEST_FILE_NAME = 'manifest.json'; -const CONTENTS_NAME = 'contents'; -var AppError = require('../app-error'); -var log4js = require('log4js'); -var log = log4js.getLogger("cps:DataCenterManager"); -var path = require('path'); - -var proto = module.exports = function (){ - function DataCenterManager() { - - } - DataCenterManager.__proto__ = proto; - return DataCenterManager; -}; - -proto.getDataDir = function () { - var dataDir = _.get(require('../config'), 'common.dataDir', {}); - if (_.isEmpty(dataDir)) { - dataDir = os.tmpdir(); - } - return dataDir; -} - -proto.hasPackageStoreSync = function (packageHash) { - var dataDir = this.getDataDir(); - var packageHashPath = path.join(dataDir, packageHash); - var manifestFile = path.join(packageHashPath, MANIFEST_FILE_NAME); - var contentPath = path.join(packageHashPath, CONTENTS_NAME); - return fs.existsSync(manifestFile) && fs.existsSync(contentPath); -} - -proto.getPackageInfo = function (packageHash) { - if (this.hasPackageStoreSync(packageHash)){ - var dataDir = this.getDataDir(); - var packageHashPath = path.join(dataDir, packageHash); - var manifestFile = path.join(packageHashPath, MANIFEST_FILE_NAME); - var contentPath = path.join(packageHashPath, CONTENTS_NAME); - return this.buildPackageInfo(packageHash, packageHashPath, contentPath, manifestFile); - } else { - throw new AppError.AppError('can\'t get PackageInfo'); - } -} - -proto.buildPackageInfo = function (packageHash, packageHashPath, contentPath, manifestFile) { - return { - packageHash: packageHash, - path: packageHashPath, - contentPath: contentPath, - manifestFilePath:manifestFile - } -} - -proto.validateStore = function (providePackageHash) { - var dataDir = this.getDataDir(); - var packageHashPath = path.join(dataDir, providePackageHash); - var manifestFile = path.join(packageHashPath, MANIFEST_FILE_NAME); - var contentPath = path.join(packageHashPath, CONTENTS_NAME); - if (!this.hasPackageStoreSync(providePackageHash)) { - log.debug(`validateStore providePackageHash not exist`); - return Promise.resolve(false); - } - return security.calcAllFileSha256(contentPath) - .then((manifestJson) => { - var packageHash = security.packageHashSync(manifestJson); - log.debug(`validateStore packageHash:`, packageHash); - try { - var manifestJsonLocal = JSON.parse(fs.readFileSync(manifestFile)); - }catch(e) { - log.debug(`validateStore manifestFile contents invilad`); - return false; - } - var packageHashLocal = security.packageHashSync(manifestJsonLocal); - log.debug(`validateStore packageHashLocal:`, packageHashLocal); - if (_.eq(providePackageHash, packageHash) && _.eq(providePackageHash, packageHashLocal)) { - log.debug(`validateStore store files is ok`); - return true; - } - log.debug(`validateStore store files broken`); - return false; - }); -} - -proto.storePackage = function (sourceDst, force) { - log.debug(`storePackage sourceDst:`, sourceDst); - if (_.isEmpty(force)){ - force = false; - } - var self = this; - return security.calcAllFileSha256(sourceDst) - .then((manifestJson) => { - var packageHash = security.packageHashSync(manifestJson); - log.debug('storePackage manifestJson packageHash:', packageHash); - var dataDir = self.getDataDir(); - var packageHashPath = path.join(dataDir, packageHash); - var manifestFile = path.join(packageHashPath, MANIFEST_FILE_NAME); - var contentPath = path.join(packageHashPath, CONTENTS_NAME); - return self.validateStore(packageHash) - .then((isValidate) => { - if (!force && isValidate) { - return self.buildPackageInfo(packageHash, packageHashPath, contentPath, manifestFile); - } else { - log.debug(`storePackage cover from sourceDst:`, sourceDst); - return common.createEmptyFolder(packageHashPath) - .then(() => { - return common.copy(sourceDst, contentPath) - .then(() => { - var manifestString = JSON.stringify(manifestJson); - fs.writeFileSync(manifestFile, manifestString); - return self.buildPackageInfo(packageHash, packageHashPath, contentPath, manifestFile); - }); - }); - } - }); - }); -} diff --git a/core/services/deployments.js b/core/services/deployments.js deleted file mode 100644 index 6e0b19ea..00000000 --- a/core/services/deployments.js +++ /dev/null @@ -1,231 +0,0 @@ -'use strict'; -var Promise = require('bluebird'); -var models = require('../../models'); -var security = require('../../core/utils/security'); -var common = require('../../core/utils/common'); -var PackageManager = require('./package-manager'); -var _ = require('lodash'); -var moment = require('moment'); -var AppError = require('../app-error'); -var log4js = require('log4js'); -var log = log4js.getLogger("cps:deployments"); - -var proto = module.exports = function (){ - function Deployments() { - - } - Deployments.__proto__ = proto; - return Deployments; -}; - -proto.getAllPackageIdsByDeploymentsId = function(deploymentsId) { - return models.Packages.findAll({where: {deployment_id: deploymentsId}}); -}; - -proto.existDeloymentName = function (appId, name) { - return models.Deployments.findOne({where: {appid: appId, name: name}}) - .then((data) => { - if (!_.isEmpty(data)){ - throw new AppError.AppError(name + " name does Exist!") - } else { - return data; - } - }); -}; - -proto.addDeloyment = function (name, appId, uid) { - var self = this; - return models.Users.findById(uid) - .then((user) => { - if (_.isEmpty(user)) { - throw new AppError.AppError('can\'t find user'); - } - return self.existDeloymentName(appId, name) - .then(() => { - var identical = user.identical; - var deploymentKey = security.randToken(28) + identical; - return models.Deployments.create({ - appid: appId, - name: name, - deployment_key: deploymentKey, - last_deployment_version_id: 0, - label_id: 0 - }); - }); - }); -}; - -proto.renameDeloymentByName = function (deploymentName, appId, newName) { - return this.existDeloymentName(appId, newName) - .then(() => { - return models.Deployments.update( - {name: newName}, - {where: {name: deploymentName,appid: appId}} - ) - .spread((affectedCount, affectedRow) => { - if (_.gt(affectedCount, 0)) { - return {name: newName}; - } else { - throw new AppError.AppError(`does not find the deployment "${deploymentName}"`); - } - }); - }); -}; - -proto.deleteDeloymentByName = function (deploymentName, appId) { - return models.Deployments.destroy({ - where: {name: deploymentName, appid: appId} - }) - .then((rowNum) => { - if (_.gt(rowNum, 0)) { - return {name: `${deploymentName}`}; - } else { - throw new AppError.AppError(`does not find the deployment "${deploymentName}"`); - } - }); -}; - -proto.findDeloymentByName = function (deploymentName, appId) { - log.debug(`findDeloymentByName name:${deploymentName},appId: ${appId}`); - return models.Deployments.findOne({ - where: {name: deploymentName, appid: appId} - }); -}; - -proto.findPackagesAndOtherInfos = function (packageId) { - return models.Packages.findOne({ - where: {id: packageId} - }) - .then((packageInfo) => { - if (!packageInfo) { - return null; - } - return Promise.props({ - packageInfo: packageInfo, - packageDiffMap: models.PackagesDiff.findAll({where: {package_id: packageId}}) - .then((diffs) => { - if (diffs.length > 0) { - return _.reduce(diffs, (result, v) => { - result[_.get(v, 'diff_against_package_hash')] = { - size: _.get(v, 'diff_size'), - url: common.getBlobDownloadUrl(_.get(v, 'diff_blob_url')), - }; - return result; - }, {}); - } - return null; - }), - userInfo: models.Users.findOne({where: {id: packageInfo.released_by}}), - deploymentsVersions: models.DeploymentsVersions.findById(packageInfo.deployment_version_id) - }); - }); -}; - -proto.findDeloymentsPackages = function (deploymentsVersionsId) { - var self = this; - return models.DeploymentsVersions.findOne({where: {id: deploymentsVersionsId}}) - .then((deploymentsVersionsInfo) => { - if (deploymentsVersionsInfo) { - return self.findPackagesAndOtherInfos(deploymentsVersionsInfo.current_package_id); - } - return null; - }); -}; - -proto.formatPackage = function(packageVersion) { - if (!packageVersion) { - return null; - } - return { - description: _.get(packageVersion, "packageInfo.description"), - isDisabled: false, - isMandatory: _.get(packageVersion, "packageInfo.is_mandatory") == 1 ? true : false, - rollout: 100, - appVersion: _.get(packageVersion, "deploymentsVersions.app_version"), - packageHash: _.get(packageVersion, "packageInfo.package_hash"), - blobUrl: common.getBlobDownloadUrl(_.get(packageVersion, "packageInfo.blob_url")), - size: _.get(packageVersion, "packageInfo.size"), - manifestBlobUrl: common.getBlobDownloadUrl(_.get(packageVersion, "packageInfo.manifest_blob_url")), - diffPackageMap: _.get(packageVersion, 'packageDiffMap'), - releaseMethod: _.get(packageVersion, "packageInfo.release_method"), - uploadTime: parseInt(moment(_.get(packageVersion, "packageInfo.updated_at")).format('x')), - originalLabel: _.get(packageVersion, "packageInfo.original_label"), - originalDeployment: _.get(packageVersion, "packageInfo.original_deployment"), - label: _.get(packageVersion, "packageInfo.label"), - releasedBy: _.get(packageVersion, "userInfo.email"), - }; -}; - -proto.listDeloyments = function (appId) { - var self = this; - return models.Deployments.findAll({where: {appid: appId}}) - .then((deploymentsInfos) => { - if (_.isEmpty(deploymentsInfos)) { - return []; - } - return Promise.map(deploymentsInfos, (v) => { - return self.listDeloyment(v); - }) - }); -}; - -proto.listDeloyment = function (deploymentInfo) { - const self = this; - return Promise.props({ - createdTime: parseInt(moment(deploymentInfo.created_at).format('x')), - id: `${deploymentInfo.id}`, - key: deploymentInfo.deployment_key, - name: deploymentInfo.name, - package: self.findDeloymentsPackages([deploymentInfo.last_deployment_version_id]).then(self.formatPackage) - }); -} - -proto.getDeploymentHistory = function (deploymentId) { - var self = this; - return models.DeploymentsHistory.findAll({where: {deployment_id: deploymentId}, order: [['id','desc']], limit: 15}) - .then((history) => { - return _.map(history, (v) => { return v.package_id}); - }) - .then((packageIds) => { - return Promise.map(packageIds, (v) => { - return self.findPackagesAndOtherInfos(v).then(self.formatPackage); - }); - }); -}; - -proto.deleteDeploymentHistory = function(deploymentId) { - return models.sequelize.transaction((t) => { - return Promise.all([ - models.Deployments.update( - {last_deployment_version_id:0,label_id:0}, - {where: {id: deploymentId},transaction: t} - ), - models.DeploymentsHistory.findAll({where: {deployment_id: deploymentId}, order: [['id','desc']], limit: 1000}) - .then((rs) => { - return Promise.map(rs, (v) => { - return v.destroy({transaction: t}); - }); - }), - models.DeploymentsVersions.findAll({where: {deployment_id: deploymentId}, order: [['id','desc']], limit: 1000}) - .then((rs) => { - return Promise.map(rs, (v) => { - return v.destroy({transaction: t}); - }); - }), - models.Packages.findAll({where: {deployment_id: deploymentId}, order: [['id','desc']], limit: 1000}) - .then((rs) => { - return Promise.map(rs, (v) => { - return v.destroy({transaction: t}) - .then(() => { - return Promise.all([ - models.PackagesMetrics.destroy({where: {package_id: v.get('id')},transaction: t}), - models.PackagesDiff.destroy({where: {package_id: v.get('id')},transaction: t}) - ]); - }); - }); - }) - ]); - }); -} - - diff --git a/core/services/email-manager.js b/core/services/email-manager.js deleted file mode 100644 index 2ed3ef67..00000000 --- a/core/services/email-manager.js +++ /dev/null @@ -1,53 +0,0 @@ -'use strict'; -var Promise = require('bluebird'); -var models = require('../../models'); -var _ = require('lodash'); -var validator = require('validator'); -var security = require('../utils/security'); -var moment = require('moment'); -var nodemailer = require('nodemailer'); -var config = require('../config'); - -var proto = module.exports = function (){ - function EmailManager() { - - } - EmailManager.__proto__ = proto; - return EmailManager; -}; - -proto.sendMail = function (options) { - return new Promise((resolve, reject) => { - if(!_.get(options, 'to')) { - return reject(new AppError.AppError("to是必传参数")); - } - var smtpConfig = _.get(config, 'smtpConfig'); - if (!smtpConfig) { - resolve({}); - } - var transporter = nodemailer.createTransport(smtpConfig); - var sendEmailAddress = _.get(smtpConfig, 'auth.user'); - var defaultMailOptions = { - from: `"CodePush Server" <${sendEmailAddress}>`, // sender address - to: '', // list of receivers 必传参数 - subject: 'CodePush Server', // Subject line - html: '' // html body - }; - var mailOptions = _.assign(defaultMailOptions, options); - transporter.sendMail(mailOptions, function(error, info){ - if(error){ - return reject(error); - } - resolve(info); - }); - }); -}; - -proto.sendRegisterCode = function (email, code) { - return proto.sendMail({ - to: email, - html: `
您接收的验证码为: ${code} 20分钟内有效
` - }); -}; - - diff --git a/core/services/package-manager.js b/core/services/package-manager.js deleted file mode 100644 index fe259c7c..00000000 --- a/core/services/package-manager.js +++ /dev/null @@ -1,665 +0,0 @@ -'use strict'; -var Promise = require('bluebird'); -var models = require('../../models'); -var security = require('../utils/security'); -var _ = require('lodash'); -var qetag = require('../utils/qetag'); -var formidable = require('formidable'); -var yazl = require("yazl"); -var fs = require("fs"); -var slash = require("slash"); -var common = require('../utils/common'); -var os = require('os'); -var path = require('path'); -var AppError = require('../app-error'); -var constConfig = require('../const'); -var log4js = require('log4js'); -var log = log4js.getLogger("cps:PackageManager"); - -var proto = module.exports = function (){ - function PackageManager() { - - } - PackageManager.__proto__ = proto; - return PackageManager; -}; - -proto.getMetricsbyPackageId = function(packageId) { - return models.PackagesMetrics.findOne({where: {package_id: packageId}}); -} - -proto.findPackageInfoByDeploymentIdAndLabel = function (deploymentId, label) { - return models.Packages.findOne({where: {deployment_id: deploymentId, label:label}}); -} - -proto.findLatestPackageInfoByDeployVersion = function (deploymentsVersionsId) { - return models.DeploymentsVersions.findById(deploymentsVersionsId) - .then((deploymentsVersions)=>{ - if (!deploymentsVersions || deploymentsVersions.current_package_id < 0) { - var e = new AppError.AppError("not found last packages"); - log.debug(e); - throw e; - } - return models.Packages.findById(deploymentsVersions.current_package_id); - }); -} - -proto.parseReqFile = function (req) { - log.debug('parseReqFile'); - return new Promise((resolve, reject) => { - var form = new formidable.IncomingForm(); - form.maxFieldsSize = 200 * 1024 * 1024; - form.parse(req, (err, fields, files) => { - if (err) { - log.debug('parseReqFile:', err); - reject(new AppError.AppError("upload error")); - } else { - log.debug('parseReqFile fields:', fields); - log.debug('parseReqFile file location:', _.get(files,'package.path')); - if (_.isEmpty(fields.packageInfo) || _.isEmpty(_.get(files,'package'))) { - log.debug('parseReqFile upload info lack'); - reject(new AppError.AppError("upload info lack")); - } else { - log.debug('parseReqFile is ok'); - resolve({packageInfo: JSON.parse(fields.packageInfo), package: files.package}); - } - } - }); - }); -}; - -proto.createDeploymentsVersionIfNotExist = function (deploymentId, appVersion, minVersion, maxVersion, t) { - return models.DeploymentsVersions.findOrCreate({ - where: {deployment_id: deploymentId, app_version: appVersion, min_version:minVersion, max_version:maxVersion}, - defaults: {current_package_id: 0}, - transaction: t - }) - .spread((data, created)=>{ - if (created) { - log.debug(`createDeploymentsVersionIfNotExist findOrCreate version ${appVersion}`); - } - log.debug(`createDeploymentsVersionIfNotExist version data:`, data.get()); - return data; - }); -}; - -proto.isMatchPackageHash = function (packageId, packageHash) { - if (_.lt(packageId, 0)) { - log.debug(`isMatchPackageHash packageId is 0`); - return Promise.resolve(false); - } - return models.Packages.findById(packageId) - .then((data) => { - if (data && _.eq(data.get('package_hash'), packageHash)){ - log.debug(`isMatchPackageHash data:`, data.get()); - log.debug(`isMatchPackageHash packageHash exist`); - return true; - }else { - log.debug(`isMatchPackageHash package is null`); - return false; - } - }); -}; - -proto.createPackage = function (deploymentId, appVersion, packageHash, manifestHash, blobHash, params) { - var releaseMethod = params.releaseMethod || constConfig.RELEAS_EMETHOD_UPLOAD; - var releaseUid = params.releaseUid || 0; - var isMandatory = params.isMandatory || 0; - var size = params.size || 0; - var rollout = params.rollout || 100; - var description = params.description || ""; - var originalLabel = params.originalLabel || ""; - var isDisabled = params.isDisabled || 0; - var originalDeployment = params.originalDeployment || ""; - var self = this; - return models.Deployments.generateLabelId(deploymentId) - .then((labelId) => { - return models.sequelize.transaction((t) => { - return self.createDeploymentsVersionIfNotExist(deploymentId, appVersion, params.min_version, params.max_version, t) - .then((deploymentsVersions) => { - return models.Packages.create({ - deployment_version_id: deploymentsVersions.id, - deployment_id: deploymentId, - description: description, - package_hash: packageHash, - blob_url: blobHash, - size: size, - manifest_blob_url: manifestHash, - release_method: releaseMethod, - label: "v" + labelId, - released_by: releaseUid, - is_mandatory: isMandatory, - is_disabled: isDisabled, - rollout: rollout, - original_label: originalLabel, - original_deployment: originalDeployment - },{transaction: t}) - .then((packages) => { - deploymentsVersions.set('current_package_id', packages.id); - return Promise.all([ - deploymentsVersions.save({transaction: t}), - models.Deployments.update( - {last_deployment_version_id: deploymentsVersions.id}, - {where: {id: deploymentId}, transaction: t} - ), - models.PackagesMetrics.create( - {package_id: packages.id}, - {transaction: t} - ), - models.DeploymentsHistory.create( - {deployment_id: deploymentId,package_id: packages.id}, - {transaction: t} - ) - ]) - .then(() => packages); - }); - }); - }); - }); -}; - -proto.downloadPackageAndExtract = function (workDirectoryPath, packageHash, blobHash) { - var dataCenterManager = require('./datacenter-manager')(); - return dataCenterManager.validateStore(packageHash) - .then((isValidate) => { - if (isValidate) { - return dataCenterManager.getPackageInfo(packageHash); - } else { - var downloadURL = common.getBlobDownloadUrl(blobHash); - return common.createFileFromRequest(downloadURL, path.join(workDirectoryPath, blobHash)) - .then((download) => { - return common.unzipFile(path.join(workDirectoryPath, blobHash), path.join(workDirectoryPath, 'current')) - .then((outputPath) => { - return dataCenterManager.storePackage(outputPath, true); - }); - }); - } - }); -} - -proto.zipDiffPackage = function (fileName, files, baseDirectoryPath, hotCodePushFile) { - return new Promise((resolve, reject) => { - var zipFile = new yazl.ZipFile(); - var writeStream = fs.createWriteStream(fileName); - writeStream.on('error', (error) => { - reject(error); - }) - zipFile.outputStream.pipe(writeStream) - .on("error", (error) => { - reject(error); - }) - .on("close", () => { - resolve({ isTemporary: true, path: fileName }); - }); - for (var i = 0; i < files.length; ++i) { - var file = files[i]; - zipFile.addFile(path.join(baseDirectoryPath, file), slash(file)); - } - zipFile.addFile(hotCodePushFile, constConfig.DIFF_MANIFEST_FILE_NAME); - zipFile.end(); - }); -} - -proto.generateOneDiffPackage = function ( - workDirectoryPath, - packageId, - originDataCenter, - oldPackageDataCenter, - diffPackageHash, - diffManifestBlobHash, - isUseDiffText -) { - var self = this; - return models.PackagesDiff.findOne({ - where:{ - package_id: packageId, - diff_against_package_hash: diffPackageHash - } - }) - .then((diffPackage) => { - if (!_.isEmpty(diffPackage)) { - return; - } - log.debug('originDataCenter', originDataCenter); - log.debug('oldPackageDataCenter', oldPackageDataCenter); - var downloadURL = common.getBlobDownloadUrl(diffManifestBlobHash); - return common.createFileFromRequest(downloadURL, path.join(workDirectoryPath,diffManifestBlobHash)) - .then(() => { - var dataCenterContentPath = path.join(workDirectoryPath, 'dataCenter'); - common.copySync(originDataCenter.contentPath, dataCenterContentPath); - var oldPackageDataCenterContentPath = oldPackageDataCenter.contentPath; - var originManifestJson = JSON.parse(fs.readFileSync(originDataCenter.manifestFilePath, "utf8")) - var diffManifestJson = JSON.parse(fs.readFileSync(path.join(workDirectoryPath, diffManifestBlobHash), "utf8")) - var json = common.diffCollectionsSync(originManifestJson, diffManifestJson); - var files = _.concat(json.diff, json.collection1Only); - var hotcodepush = {deletedFiles: json.collection2Only, patchedFiles:[]}; - if (isUseDiffText == constConfig.IS_USE_DIFF_TEXT_YES) { - //使用google diff-match-patch - _.forEach(json.diff, function(tmpFilePath) { - var dataCenterContentPathTmpFilePath = path.join(dataCenterContentPath, tmpFilePath); - var oldPackageDataCenterContentPathTmpFilePath = path.join(oldPackageDataCenterContentPath, tmpFilePath); - if ( - fs.existsSync(dataCenterContentPathTmpFilePath) - && fs.existsSync(oldPackageDataCenterContentPathTmpFilePath) - && common.detectIsTextFile(dataCenterContentPathTmpFilePath) - && common.detectIsTextFile(oldPackageDataCenterContentPathTmpFilePath) - ) { - var textOld = fs.readFileSync(oldPackageDataCenterContentPathTmpFilePath, 'utf-8'); - var textNew = fs.readFileSync(dataCenterContentPathTmpFilePath, 'utf-8'); - if (!textOld || !textNew) { - return; - } - var DiffMatchPatch = require('diff-match-patch'); - var dmp = new DiffMatchPatch(); - var patchs = dmp.patch_make(textOld, textNew); - var patchText = dmp.patch_toText(patchs); - if (patchText && patchText.length < _.parseInt(textNew.length * 0.8)) { - fs.writeFileSync(dataCenterContentPathTmpFilePath, patchText); - hotcodepush.patchedFiles.push(tmpFilePath); - } - } - }); - } - var hotCodePushFile = path.join(workDirectoryPath,`${diffManifestBlobHash}_hotcodepush`);; - fs.writeFileSync(hotCodePushFile, JSON.stringify(hotcodepush)); - var fileName = path.join(workDirectoryPath,`${diffManifestBlobHash}.zip`);; - return self.zipDiffPackage(fileName, files, dataCenterContentPath, hotCodePushFile) - .then((data) => { - return security.qetag(data.path) - .then((diffHash) => { - return common.uploadFileToStorage(diffHash, fileName) - .then(() => { - var stats = fs.statSync(fileName); - return models.PackagesDiff.create({ - package_id: packageId, - diff_against_package_hash: diffPackageHash, - diff_blob_url: diffHash, - diff_size: stats.size - }); - }) - }); - }); - }); - }); -}; - -proto.createDiffPackagesByLastNums = function (appId, originalPackage, num) { - var self = this; - var Sequelize = require('sequelize'); - var packageId = originalPackage.id; - return Promise.all([ - models.Packages.findAll({ - where:{ - deployment_version_id: originalPackage.deployment_version_id, - id: {[Sequelize.Op.lt]: packageId}}, - order: [['id','desc']], - limit: num - }), - models.Packages.findAll({ - where:{ - deployment_version_id: originalPackage.deployment_version_id, - id: {[Sequelize.Op.lt]: packageId}}, - order: [['id','asc']], - limit: 2 - }), - models.Apps.findById(appId), - ]) - .spread((lastNumsPackages, basePackages, appInfo) => { - return [_.uniqBy(_.unionBy(lastNumsPackages, basePackages, 'id'), 'package_hash'), appInfo]; - }) - .spread((lastNumsPackages, appInfo) => { - return self.createDiffPackages(originalPackage, lastNumsPackages, _.get(appInfo, 'is_use_diff_text', constConfig.IS_USE_DIFF_TEXT_NO)); - }); -}; - -proto.createDiffPackages = function (originalPackage, destPackages, isUseDiffText) { - if (!_.isArray(destPackages)) { - return Promise.reject(new AppError.AppError('第二个参数必须是数组')); - } - if (destPackages.length <= 0) { - return null; - } - var self = this; - var package_hash = _.get(originalPackage, 'package_hash'); - var manifest_blob_url = _.get(originalPackage, 'manifest_blob_url'); - var blob_url = _.get(originalPackage, 'blob_url'); - var workDirectoryPath = path.join(os.tmpdir(), 'codepush_' + security.randToken(32)); - log.debug('workDirectoryPath', workDirectoryPath); - return common.createEmptyFolder(workDirectoryPath) - .then(() => self.downloadPackageAndExtract(workDirectoryPath, package_hash, blob_url)) - .then((originDataCenter) => Promise.map(destPackages, - (v) => { - var diffWorkDirectoryPath = path.join(workDirectoryPath, _.get(v, 'package_hash')); - common.createEmptyFolderSync(diffWorkDirectoryPath); - return self.downloadPackageAndExtract(diffWorkDirectoryPath, _.get(v, 'package_hash'), _.get(v, 'blob_url')) - .then((oldPackageDataCenter) => - self.generateOneDiffPackage( - diffWorkDirectoryPath, - originalPackage.id, - originDataCenter, - oldPackageDataCenter, - v.package_hash, - v.manifest_blob_url, - isUseDiffText - ) - ) - } - )) - .finally(() => common.deleteFolderSync(workDirectoryPath)); -} - -proto.releasePackage = function (appId, deploymentId, packageInfo, filePath, releaseUid) { - var self = this; - var appVersion = packageInfo.appVersion; - var versionInfo = common.validatorVersion(appVersion); - if (!versionInfo[0]) { - log.debug(`releasePackage targetBinaryVersion ${appVersion} not support.`); - return Promise.reject(new AppError.AppError(`targetBinaryVersion ${appVersion} not support.`)) - } - var description = packageInfo.description; //描述 - var isDisabled = packageInfo.isDisabled; //是否立刻下载 - var rollout = packageInfo.rollout; //灰度百分比 - var isMandatory = packageInfo.isMandatory; //是否强制更新,无法跳过 - var tmpDir = os.tmpdir(); - var directoryPathParent = path.join(tmpDir, 'codepuh_' + security.randToken(32)); - var directoryPath = path.join(directoryPathParent, 'current'); - log.debug(`releasePackage generate an random dir path: ${directoryPath}`); - return Promise.all([ - security.qetag(filePath), - common.createEmptyFolder(directoryPath) - .then(() => { - return common.unzipFile(filePath, directoryPath) - }) - ]) - .spread((blobHash) => { - return security.uploadPackageType(directoryPath) - .then((type) => { - return models.Apps.findById(appId).then((appInfo)=>{ - if (type > 0 && appInfo.os > 0 && appInfo.os != type) { - var e = new AppError.AppError("it must be publish it by ios type"); - log.debug(e); - throw e; - } else { - //不验证 - log.debug(`Unknown package type:`, type, ',db os:', appInfo.os); - } - return blobHash; - }); - }); - }) - .then((blobHash) => { - var dataCenterManager = require('./datacenter-manager')(); - return dataCenterManager.storePackage(directoryPath) - .then((dataCenter) => { - var packageHash = dataCenter.packageHash; - var manifestFile = dataCenter.manifestFilePath; - return models.DeploymentsVersions.findOne({where: {deployment_id: deploymentId, app_version:appVersion}}) - .then((deploymentsVersions) => { - if (!deploymentsVersions) { - return false; - } - return self.isMatchPackageHash(deploymentsVersions.get('current_package_id'), packageHash); - }) - .then((isExist) => { - if (isExist){ - var e = new AppError.AppError("The uploaded package is identical to the contents of the specified deployment's current release."); - log.debug(e.message); - throw e; - } - return security.qetag(manifestFile); - }) - .then((manifestHash) => { - return Promise.all([ - common.uploadFileToStorage(manifestHash, manifestFile), - common.uploadFileToStorage(blobHash, filePath) - ]) - .then(() => [packageHash, manifestHash, blobHash]); - }) - }); - }) - .spread((packageHash, manifestHash, blobHash) => { - var stats = fs.statSync(filePath); - var params = { - releaseMethod: constConfig.RELEAS_EMETHOD_UPLOAD, - releaseUid: releaseUid, - isMandatory: isMandatory ? constConfig.IS_MANDATORY_YES : constConfig.IS_MANDATORY_NO, - isDisabled: isDisabled ? constConfig.IS_DISABLED_YES : constConfig.IS_DISABLED_NO, - rollout: rollout, - size: stats.size, - description: description, - min_version: versionInfo[1], - max_version: versionInfo[2], - } - return self.createPackage(deploymentId, appVersion, packageHash, manifestHash, blobHash, params); - }) - .finally(() => common.deleteFolderSync(directoryPathParent)) -}; - -proto.modifyReleasePackage = function(packageId, params) { - var appVersion = _.get(params, 'appVersion'); - var description = _.get(params, 'description'); - var isMandatory = _.get(params, 'isMandatory'); - var isDisabled = _.get(params, 'isDisabled'); - var rollout = _.get(params, 'rollout'); - return models.Packages.findById(packageId) - .then((packageInfo) => { - if (!packageInfo) { - throw new AppError.AppError(`packageInfo not found`); - } - if (!_.isNull(appVersion)) { - var versionInfo = common.validatorVersion(appVersion); - if (!versionInfo[0]) { - throw new AppError.AppError(`--targetBinaryVersion ${appVersion} not support.`); - } - return Promise.all([ - models.DeploymentsVersions.findOne({where: {deployment_id:packageInfo.deployment_id, app_version:appVersion}}), - models.DeploymentsVersions.findById(packageInfo.deployment_version_id) - ]) - .spread((v1, v2) => { - if (v1 && !_.eq(v1.id, v2.id)) { - log.debug(v1); - throw new AppError.AppError(`${appVersion} already exist.`); - } - if (!v2) { - throw new AppError.AppError(`packages not found.`); - } - return models.DeploymentsVersions.update({ - app_version:appVersion, - min_version:versionInfo[1], - max_version:versionInfo[2] - },{where: {id:v2.id}}); - }) - .then(()=>{ - return packageInfo - }); - } - return packageInfo; - }) - .then((packageInfo) => { - var new_params = { - description: description || packageInfo.description, - }; - if (_.isInteger(rollout)) { - new_params.rollout = rollout; - } - if (_.isBoolean(isMandatory)) { - new_params.is_mandatory = isMandatory ? constConfig.IS_MANDATORY_YES : constConfig.IS_MANDATORY_NO; - } - if (_.isBoolean(isDisabled)) { - new_params.is_disabled = isDisabled ? constConfig.IS_DISABLED_YES : constConfig.IS_DISABLED_NO; - } - return models.Packages.update(new_params,{where: {id: packageId}}); - }); -}; - -proto.promotePackage = function (sourceDeploymentInfo, destDeploymentInfo, params) { - var self = this; - var appVersion = _.get(params,'appVersion', null); - var label = _.get(params,'label', null); - return new Promise((resolve, reject) => { - if (label) { - return models.Packages.findOne({where: {deployment_id: sourceDeploymentInfo.id, label:label}}) - .then((sourcePack)=>{ - if (!sourcePack) { - throw new AppError.AppError('label does not exist.'); - } - return models.DeploymentsVersions.findById(sourcePack.deployment_version_id) - .then((deploymentsVersions)=>{ - if (!deploymentsVersions) { - throw new AppError.AppError('deploymentsVersions does not exist.'); - } - resolve([sourcePack, deploymentsVersions]); - }); - }) - .catch((e) => { - reject(e); - }); - } else { - var lastDeploymentVersionId = _.get(sourceDeploymentInfo, 'last_deployment_version_id', 0); - if (_.lte(lastDeploymentVersionId, 0)) { - throw new AppError.AppError(`does not exist last_deployment_version_id.`); - } - return models.DeploymentsVersions.findById(lastDeploymentVersionId) - .then((deploymentsVersions)=>{ - var sourcePackId = _.get(deploymentsVersions, 'current_package_id', 0); - if (_.lte(sourcePackId, 0)) { - throw new AppError.AppError(`packageInfo not found.`); - } - return models.Packages.findById(sourcePackId) - .then((sourcePack) =>{ - if (!sourcePack) { - throw new AppError.AppError(`packageInfo not found.`); - } - resolve([sourcePack, deploymentsVersions]); - }); - }) - .catch((e) => { - reject(e); - }); - } - }) - .spread((sourcePack, deploymentsVersions)=>{ - var appFinalVersion = appVersion || deploymentsVersions.app_version; - log.debug('sourcePack',sourcePack); - log.debug('deploymentsVersions',deploymentsVersions); - log.debug('appFinalVersion', appFinalVersion); - return models.DeploymentsVersions.findOne({where: { - deployment_id:destDeploymentInfo.id, - app_version: appFinalVersion, - }}) - .then((destDeploymentsVersions)=>{ - if (!destDeploymentsVersions) { - return false; - } - return self.isMatchPackageHash(destDeploymentsVersions.get('current_package_id'), sourcePack.package_hash); - }) - .then((isExist) => { - if (isExist){ - throw new AppError.AppError("The uploaded package is identical to the contents of the specified deployment's current release."); - } - return [sourcePack, deploymentsVersions, appFinalVersion]; - }); - }) - .spread((sourcePack, deploymentsVersions, appFinalVersion) => { - var versionInfo = common.validatorVersion(appFinalVersion); - if (!versionInfo[0]) { - log.debug(`targetBinaryVersion ${appVersion} not support.`); - throw new AppError.AppError(`targetBinaryVersion ${appVersion} not support.`); - } - var create_params = { - releaseMethod: constConfig.RELEAS_EMETHOD_PROMOTE, - releaseUid: params.promoteUid || 0, - rollout: params.rollout || 100, - size: sourcePack.size, - description: params.description || sourcePack.description, - originalLabel: sourcePack.label, - originalDeployment: sourceDeploymentInfo.name, - min_version: versionInfo[1], - max_version: versionInfo[2], - }; - if (_.isBoolean(params.isMandatory)) { - create_params.isMandatory = params.isMandatory ? constConfig.IS_MANDATORY_YES : constConfig.IS_MANDATORY_NO; - } else { - create_params.isMandatory = sourcePack.is_mandatory - } - if (_.isBoolean(params.isDisabled)) { - create_params.isDisabled = params.isDisabled ? constConfig.IS_DISABLED_YES : constConfig.IS_DISABLED_NO; - } else { - create_params.isDisabled = sourcePack.is_disabled - } - return self.createPackage( - destDeploymentInfo.id, - appFinalVersion, - sourcePack.package_hash, - sourcePack.manifest_blob_url, - sourcePack.blob_url, - create_params - ); - }); -}; - -proto.rollbackPackage = function (deploymentVersionId, targetLabel, rollbackUid) { - var self = this; - return models.DeploymentsVersions.findById(deploymentVersionId) - .then((deploymentsVersions) => { - if (!deploymentsVersions) { - throw new AppError.AppError("您之前还没有发布过版本"); - } - return models.Packages.findById(deploymentsVersions.current_package_id) - .then((currentPackageInfo) => { - if (targetLabel) { - return models.Packages.findAll({where: {deployment_version_id: deploymentVersionId, label: targetLabel}, limit: 1}) - .then((rollbackPackageInfos) => { - return [currentPackageInfo, rollbackPackageInfos] - }); - } else { - return self.getCanRollbackPackages(deploymentVersionId) - .then((rollbackPackageInfos) => { - return [currentPackageInfo, rollbackPackageInfos] - }); - } - }) - .spread((currentPackageInfo, rollbackPackageInfos) => { - if (currentPackageInfo && rollbackPackageInfos.length > 0) { - for (var i = rollbackPackageInfos.length - 1; i >= 0; i--) { - if (rollbackPackageInfos[i].package_hash != currentPackageInfo.package_hash) { - return rollbackPackageInfos[i]; - } - } - } - throw new AppError.AppError("没有可供回滚的版本"); - }) - .then((rollbackPackage) => { - var params = { - releaseMethod: 'Rollback', - releaseUid: rollbackUid, - isMandatory: rollbackPackage.is_mandatory, - isDisabled: rollbackPackage.is_disabled, - rollout: rollbackPackage.rollout, - size: rollbackPackage.size, - description: rollbackPackage.description, - originalLabel: rollbackPackage.label, - originalDeployment: '', - min_version: deploymentsVersions.min_version, - max_version: deploymentsVersions.max_version, - }; - return self.createPackage(deploymentsVersions.deployment_id, - deploymentsVersions.app_version, - rollbackPackage.package_hash, - rollbackPackage.manifest_blob_url, - rollbackPackage.blob_url, - params - ); - }); - }); -} - -proto.getCanRollbackPackages = function (deploymentVersionId) { - var Sequelize = require('sequelize'); - return models.Packages.findAll({ - where: { - deployment_version_id: deploymentVersionId, - release_method: {[Sequelize.Op.in]: [constConfig.RELEAS_EMETHOD_UPLOAD, constConfig.RELEAS_EMETHOD_PROMOTE] } - }, order: [['id','desc']], limit: 2 - }); -} diff --git a/core/utils/common.js b/core/utils/common.js deleted file mode 100644 index 6d221535..00000000 --- a/core/utils/common.js +++ /dev/null @@ -1,493 +0,0 @@ -'use strict'; -var Promise = require('bluebird'); -var fs = require("fs"); -var fsextra = require("fs-extra"); -var extract = require('extract-zip') -var config = require('../config'); -var _ = require('lodash'); -var validator = require('validator'); -var qiniu = require("qiniu"); -var upyun = require('upyun'); -var common = {}; -var AppError = require('../app-error'); -var jschardet = require("jschardet"); -var log4js = require('log4js'); -var path = require('path'); -var log = log4js.getLogger("cps:utils:common"); -module.exports = common; - -common.detectIsTextFile = function(filePath) { - var fd = fs.openSync(filePath, 'r'); - var buffer = new Buffer(4096); - fs.readSync(fd, buffer, 0, 4096, 0); - fs.closeSync(fd); - var rs = jschardet.detect(buffer); - log.debug('detectIsTextFile:', filePath, rs); - if (rs.confidence == 1) { - return true; - } - return false; -} - -common.parseVersion = function (versionNo) { - var version = '0'; - var data = null; - if (data = versionNo.match(/^([0-9]{1,3}).([0-9]{1,5}).([0-9]{1,10})$/)) { - // "1.2.3" - version = data[1] + _.padStart(data[2], 5, '0') + _.padStart(data[3], 10, '0'); - } else if (data = versionNo.match(/^([0-9]{1,3}).([0-9]{1,5})$/)) { - // "1.2" - version = data[1] + _.padStart(data[2], 5, '0') + _.padStart('0', 10, '0'); - } - return version; -}; - -common.validatorVersion = function (versionNo) { - var flag = false; - var min = '0'; - var max = '9999999999999999999'; - var data = null; - if (versionNo == "*") { - // "*" - flag = true; - } else if (data = versionNo.match(/^([0-9]{1,3}).([0-9]{1,5}).([0-9]{1,10})$/)) { - // "1.2.3" - flag = true; - min = data[1] + _.padStart(data[2], 5, '0') + _.padStart(data[3], 10, '0'); - max = data[1] + _.padStart(data[2], 5, '0') + _.padStart((parseInt(data[3])+1), 10, '0'); - } else if (data = versionNo.match(/^([0-9]{1,3}).([0-9]{1,5})(\.\*){0,1}$/)) { - // "1.2" "1.2.*" - flag = true; - min = data[1] + _.padStart(data[2], 5, '0') + _.padStart('0', 10, '0'); - max = data[1] + _.padStart((parseInt(data[2])+1), 5, '0') + _.padStart('0', 10, '0'); - } else if (data = versionNo.match(/^\~([0-9]{1,3}).([0-9]{1,5}).([0-9]{1,10})$/)) { - //"~1.2.3" - flag = true; - min = data[1] + _.padStart(data[2], 5, '0') + _.padStart(data[3], 10, '0'); - max = data[1] + _.padStart((parseInt(data[2])+1), 5, '0') + _.padStart('0', 10, '0'); - } else if (data = versionNo.match(/^\^([0-9]{1,3}).([0-9]{1,5}).([0-9]{1,10})$/)) { - //"^1.2.3" - flag = true; - min = data[1] + _.padStart(data[2], 5, '0') + _.padStart(data[3], 10, '0'); - max = _.toString((parseInt(data[1])+1)) + _.padStart(0, 5, '0') + _.padStart('0', 10, '0'); - } else if (data = versionNo.match(/^([0-9]{1,3}).([0-9]{1,5}).([0-9]{1,10})\s?-\s?([0-9]{1,3}).([0-9]{1,5}).([0-9]{1,10})$/)) { - // "1.2.3 - 1.2.7" - flag = true; - min = data[1] + _.padStart(data[2], 5, '0') + _.padStart(data[3], 10, '0'); - max = data[4] + _.padStart(data[5], 5, '0') + _.padStart((parseInt(data[6])+1), 10, '0'); - } else if (data = versionNo.match(/^>=([0-9]{1,3}).([0-9]{1,5}).([0-9]{1,10})\s?<([0-9]{1,3}).([0-9]{1,5}).([0-9]{1,10})$/)) { - // ">=1.2.3 <1.2.7" - flag = true; - min = data[1] + _.padStart(data[2], 5, '0') + _.padStart(data[3], 10, '0'); - max = data[4] + _.padStart(data[5], 5, '0') + _.padStart(data[6], 10, '0'); - } - return [flag, min, max]; -}; - -common.createFileFromRequest = function (url, filePath) { - return new Promise((resolve, reject) => { - fs.exists(filePath, function (exists) { - if (!exists) { - var request = require('request'); - log.debug(`createFileFromRequest url:${url}`) - request(url).on('error', function (error) { - reject(error); - }) - .on('response', function (response) { - if (response.statusCode == 200) { - let stream = fs.createWriteStream(filePath); - response.pipe(stream); - stream.on('close',function(){ - resolve(null); - }); - stream.on('error', function (error) { - reject(error) - }) - } else { - reject({message:'request fail'}) - } - }); - }else { - resolve(null); - } - }); - }); -}; - -common.copySync = function (sourceDst, targertDst) { - return fsextra.copySync(sourceDst, targertDst, {overwrite: true}); -}; - -common.copy = function (sourceDst, targertDst) { - return new Promise((resolve, reject) => { - fsextra.copy(sourceDst, targertDst, {overwrite: true}, function (err) { - if (err) { - log.error(err); - reject(err); - } else { - log.debug(`copy success sourceDst:${sourceDst} targertDst:${targertDst}`); - resolve(); - } - }); - }); -}; - -common.move = function (sourceDst, targertDst) { - return new Promise((resolve, reject) => { - fsextra.move(sourceDst, targertDst, {overwrite: true}, function (err) { - if (err) { - log.error(err); - reject(err); - } else { - log.debug(`move success sourceDst:${sourceDst} targertDst:${targertDst}`); - resolve(); - } - }); - }); -}; - -common.deleteFolder = function (folderPath) { - return new Promise((resolve, reject) => { - fsextra.remove(folderPath, function (err) { - if (err) { - log.error(err); - reject(err); - }else { - log.debug(`deleteFolder delete ${folderPath} success.`); - resolve(null); - } - }); - }); -}; - -common.deleteFolderSync = function (folderPath) { - return fsextra.removeSync(folderPath); -}; - -common.createEmptyFolder = function (folderPath) { - return new Promise((resolve, reject) => { - log.debug(`createEmptyFolder Create dir ${folderPath}`); - return common.deleteFolder(folderPath) - .then((data) => { - fsextra.mkdirs(folderPath, (err) => { - if (err) { - log.error(err); - reject(new AppError.AppError(err.message)); - } else { - resolve(folderPath); - } - }); - }); - }); -}; - -common.createEmptyFolderSync = function (folderPath) { - common.deleteFolderSync(folderPath); - return fsextra.mkdirsSync(folderPath); -}; - -common.unzipFile = function (zipFile, outputPath) { - return new Promise((resolve, reject) => { - try { - log.debug(`unzipFile check zipFile ${zipFile} fs.R_OK`); - fs.accessSync(zipFile, fs.R_OK); - log.debug(`Pass unzipFile file ${zipFile}`); - } catch (e) { - log.error(e); - return reject(new AppError.AppError(e.message)) - } - extract(zipFile, {dir: outputPath}, function(err){ - if (err) { - log.error(err); - reject(new AppError.AppError(`it's not a zipFile`)) - } else { - log.debug(`unzipFile success`); - resolve(outputPath); - } - }); - }); -}; - -common.getUploadTokenQiniu = function (mac, bucket, key) { - var options = { - scope: bucket + ":" + key - } - var putPolicy = new qiniu.rs.PutPolicy(options); - return putPolicy.uploadToken(mac); -}; - -common.uploadFileToStorage = function (key, filePath) { - var storageType = _.get(config, 'common.storageType'); - if ( storageType === 'local') { - return common.uploadFileToLocal(key, filePath); - } else if (storageType === 's3') { - return common.uploadFileToS3(key, filePath); - } else if (storageType === 'oss') { - return common.uploadFileToOSS(key, filePath); - } else if (storageType === 'qiniu') { - return common.uploadFileToQiniu(key, filePath); - } else if (storageType === 'upyun') { - return common.uploadFileToUpyun(key, filePath); - } else if (storageType === 'tencentcloud') { - return common.uploadFileToTencentCloud(key, filePath); - } - throw new AppError.AppError(`${storageType} storageType does not support.`); -}; - -common.uploadFileToLocal = function (key, filePath) { - return new Promise((resolve, reject) => { - var storageDir = _.get(config, 'local.storageDir'); - if (!storageDir) { - throw new AppError.AppError('please set config local storageDir'); - } - if (key.length < 3) { - log.error(`generate key is too short, key value:${key}`); - throw new AppError.AppError('generate key is too short.'); - } - try { - log.debug(`uploadFileToLocal check directory ${storageDir} fs.R_OK`); - fs.accessSync(storageDir, fs.W_OK); - log.debug(`uploadFileToLocal directory ${storageDir} fs.R_OK is ok`); - } catch (e) { - log.error(e); - throw new AppError.AppError(e.message); - } - var subDir = key.substr(0, 2).toLowerCase(); - var finalDir = path.join(storageDir, subDir); - var fileName = path.join(finalDir, key); - if (fs.existsSync(fileName)) { - return resolve(key); - } - var stats = fs.statSync(storageDir); - if (!stats.isDirectory()) { - var e = new AppError.AppError(`${storageDir} must be directory`); - log.error(e); - throw e; - } - if (!fs.existsSync(`${finalDir}`)) { - fs.mkdirSync(`${finalDir}`); - log.debug(`uploadFileToLocal mkdir:${finalDir}`); - } - try { - fs.accessSync(filePath, fs.R_OK); - } catch (e) { - log.error(e); - throw new AppError.AppError(e.message); - } - stats = fs.statSync(filePath); - if (!stats.isFile()) { - var e = new AppError.AppError(`${filePath} must be file`); - log.error(e); - throw e; - } - fsextra.copy(filePath, fileName,(err) => { - if (err) { - log.error(new AppError.AppError(err.message)); - return reject(new AppError.AppError(err.message)); - } - log.debug(`uploadFileToLocal copy file ${key} success.`); - resolve(key); - }); - }); -}; - -common.getBlobDownloadUrl = function (blobUrl) { - var fileName = blobUrl; - var storageType = _.get(config, 'common.storageType'); - var downloadUrl = _.get(config, `${storageType}.downloadUrl`); - if ( storageType === 'local') { - fileName = blobUrl.substr(0, 2).toLowerCase() + '/' + blobUrl; - } - if (!validator.isURL(downloadUrl)) { - var e = new AppError.AppError(`Please config ${storageType}.downloadUrl in config.js`); - log.error(e); - throw e; - } - return `${downloadUrl}/${fileName}` -}; - - -common.uploadFileToQiniu = function (key, filePath) { - return new Promise((resolve, reject) => { - var accessKey = _.get(config, "qiniu.accessKey"); - var secretKey = _.get(config, "qiniu.secretKey"); - var bucket = _.get(config, "qiniu.bucketName", ""); - var mac = new qiniu.auth.digest.Mac(accessKey, secretKey); - var conf = new qiniu.conf.Config(); - var bucketManager = new qiniu.rs.BucketManager(mac, conf); - bucketManager.stat(bucket, key, (respErr, respBody, respInfo) => { - if (respErr) { - log.debug('uploadFileToQiniu file stat:', respErr); - return reject(new AppError.AppError(respErr.message)); - } - log.debug('uploadFileToQiniu file stat respBody:', respBody); - log.debug('uploadFileToQiniu file stat respInfo:', respInfo); - if (respInfo.statusCode == 200) { - resolve(respBody.hash); - } else { - try { - var uploadToken = common.getUploadTokenQiniu(mac, bucket, key); - } catch (e) { - return reject(new AppError.AppError(e.message)); - } - var formUploader = new qiniu.form_up.FormUploader(conf); - var putExtra = new qiniu.form_up.PutExtra(); - formUploader.putFile(uploadToken, key, filePath, putExtra, (respErr, respBody, respInfo) => { - if(respErr) { - log.error('uploadFileToQiniu putFile:', respErr); - // 上传失败, 处理返回代码 - return reject(new AppError.AppError(JSON.stringify(respErr))); - } else { - log.debug('uploadFileToQiniu putFile respBody:', respBody); - log.debug('uploadFileToQiniu putFile respInfo:', respInfo); - // 上传成功, 处理返回值 - if (respInfo.statusCode == 200) { - return resolve(respBody.hash); - } else { - return reject(new AppError.AppError(respBody.error)); - } - } - }); - } - }); - }); -}; - -common.uploadFileToUpyun = function (key, filePath) { - var serviceName = _.get(config, "upyun.serviceName"); - var operatorName = _.get(config, "upyun.operatorName"); - var operatorPass = _.get(config, "upyun.operatorPass", ""); - var storageDir = _.get(config, "upyun.storageDir", ""); - var service = new upyun.Service(serviceName, operatorName, operatorPass); - var client = new upyun.Client(service); - return ( - new Promise((resolve, reject) => { - client.makeDir(storageDir).then(result => { - if(!storageDir) { - reject(new AppError.AppError('Please config the upyun remoteDir!')); - return; - } - let remotePath = storageDir + '/' + key; - log.debug('uploadFileToUpyun remotePath:', remotePath); - log.debug('uploadFileToUpyun mkDir result:', result); - client.putFile(remotePath, fs.createReadStream(filePath)).then(data => { - log.debug('uploadFileToUpyun putFile response:', data); - if(data) { - resolve(key) - } else { - log.debug('uploadFileToUpyun putFile failed!', data); - reject(new AppError.AppError('Upload file to upyun failed!')); - } - }).catch(e1 => { - log.debug('uploadFileToUpyun putFile exception e1:', e1); - reject(new AppError.AppError(JSON.stringify(e1))); - }) - }).catch(e => { - log.debug('uploadFileToUpyun putFile exception e:', e); - reject(new AppError.AppError(JSON.stringify(e))); - }); - }) - ); -}; - -common.uploadFileToS3 = function (key, filePath) { - var AWS = require('aws-sdk'); - return ( - new Promise((resolve, reject) => { - AWS.config.update({ - accessKeyId: _.get(config, 's3.accessKeyId'), - secretAccessKey: _.get(config, 's3.secretAccessKey'), - sessionToken: _.get(config, 's3.sessionToken'), - region: _.get(config, 's3.region') - }); - var s3 = new AWS.S3({ - params: {Bucket: _.get(config, 's3.bucketName')} - }); - fs.readFile(filePath, (err, data) => { - s3.upload({ - Key: key, - Body: data, - ACL:'public-read', - }, (err, response) => { - if(err) { - reject(new AppError.AppError(JSON.stringify(err))); - } else { - resolve(response.ETag) - } - }) - }); - }) - ); -}; - -common.uploadFileToOSS = function (key, filePath) { - var ALY = require('aliyun-sdk'); - var ossStream = require('aliyun-oss-upload-stream')(new ALY.OSS({ - accessKeyId: _.get(config, 'oss.accessKeyId'), - secretAccessKey: _.get(config, 'oss.secretAccessKey'), - endpoint: _.get(config, 'oss.endpoint'), - apiVersion: '2013-10-15', - })); - if (!_.isEmpty(_.get(config, 'oss.prefix', ""))) { - key = `${_.get(config, 'oss.prefix')}/${key}`; - } - var upload = ossStream.upload({ - Bucket: _.get(config, 'oss.bucketName'), - Key: key, - }); - - return new Promise((resolve, reject) => { - upload.on('error', (error) => { - log.debug("uploadFileToOSS", error); - reject(error); - }); - - upload.on('uploaded', (details) => { - log.debug("uploadFileToOSS", details); - resolve(details.ETag); - }); - fs.createReadStream(filePath).pipe(upload); - }); -}; - -common.uploadFileToTencentCloud = function (key, filePath) { - return new Promise((resolve, reject) => { - var COS = require('cos-nodejs-sdk-v5'); - var cosIn = new COS({ - SecretId: _.get(config, 'tencentcloud.accessKeyId'), - SecretKey: _.get(config, 'tencentcloud.secretAccessKey') - }); - cosIn.sliceUploadFile({ - Bucket: _.get(config, 'tencentcloud.bucketName'), - Region: _.get(config, 'tencentcloud.region'), - Key: key, - FilePath: filePath - }, function (err, data) { - log.debug("uploadFileToTencentCloud", err, data); - if (err) { - reject(new AppError.AppError(JSON.stringify(err))); - }else { - resolve(data.Key); - } - }); - }); -} - -common.diffCollectionsSync = function (collection1, collection2) { - var diffFiles = []; - var collection1Only = []; - var newCollection2 = Object.assign({}, collection2); - if (collection1 instanceof Object) { - for(var key of Object.keys(collection1)) { - if (_.isEmpty(newCollection2[key])) { - collection1Only.push(key); - } else { - if (!_.eq(collection1[key], newCollection2[key])) { - diffFiles.push(key); - } - delete newCollection2[key]; - } - } - } - return {diff:diffFiles, collection1Only: collection1Only, collection2Only: Object.keys(newCollection2)} -}; diff --git a/core/utils/factory.js b/core/utils/factory.js deleted file mode 100644 index 17a2b99c..00000000 --- a/core/utils/factory.js +++ /dev/null @@ -1,13 +0,0 @@ -'use strict'; -var Promise = require('bluebird'); -var redis = require('redis'); -Promise.promisifyAll(redis.RedisClient.prototype); -Promise.promisifyAll(redis.Multi.prototype); -var config = require('../config'); -var _ = require('lodash'); -var factory = {}; -module.exports = factory; - -factory.getRedisClient = function (name) { - return redis.createClient(_.get(config, `redis.${name}`)); -}; diff --git a/core/utils/qetag.js b/core/utils/qetag.js deleted file mode 100644 index b846bab5..00000000 --- a/core/utils/qetag.js +++ /dev/null @@ -1,79 +0,0 @@ -// 计算文件的eTag,参数为buffer或者readableStream或者文件路径 -function getEtag(buffer,callback){ - - // 判断传入的参数是buffer还是stream还是filepath - var mode = 'buffer'; - - if(typeof buffer === 'string'){ - buffer = require('fs').createReadStream(buffer); - mode='stream'; - }else if(buffer instanceof require('stream')){ - mode='stream'; - } - - // sha1算法 - var sha1 = function(content){ - var crypto = require('crypto'); - var sha1 = crypto.createHash('sha1'); - sha1.update(content); - return sha1.digest(); - }; - - // 以4M为单位分割 - var blockSize = 4*1024*1024; - var sha1String = []; - var prefix = 0x16; - var blockCount = 0; - - switch(mode){ - case 'buffer': - var bufferSize = buffer.length; - blockCount = Math.ceil(bufferSize / blockSize); - - for(var i=0;i 1){ - prefix = 0x96; - sha1Buffer = sha1(sha1Buffer); - } - - sha1Buffer = Buffer.concat( - [new Buffer([prefix]),sha1Buffer], - sha1Buffer.length + 1 - ); - - return sha1Buffer.toString('base64') - .replace(/\//g,'_').replace(/\+/g,'-'); - - } - -} - -module.exports = getEtag; diff --git a/core/utils/security.js b/core/utils/security.js deleted file mode 100644 index a4054acd..00000000 --- a/core/utils/security.js +++ /dev/null @@ -1,227 +0,0 @@ -'use strict'; -var bcrypt = require('bcryptjs'); -var crypto = require('crypto'); -var fs = require('fs'); -var Promise = require('bluebird'); -var qetag = require('../utils/qetag'); -var _ = require('lodash'); -var log4js = require('log4js'); -var log = log4js.getLogger("cps:utils:security"); -var AppError = require('../app-error'); - -var randToken = require('rand-token').generator({ - chars: '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ', - source: crypto.randomBytes -}); -var security = {}; -module.exports = security; - -security.md5 = function (str) { - var md5sum = crypto.createHash('md5'); - md5sum.update(str); - str = md5sum.digest('hex'); - return str; -} - -security.passwordHashSync = function(password){ - return bcrypt.hashSync(password, bcrypt.genSaltSync(12)); -} - -security.passwordVerifySync = function(password, hash){ - return bcrypt.compareSync(password, hash) -} - -security.randToken = function(num) { - return randToken.generate(num); -} - -security.parseToken = function(token) { - return {identical: token.substr(-9,9), token:token.substr(0,28)} -} - -security.fileSha256 = function (file) { - return new Promise((resolve, reject) => { - var rs = fs.createReadStream(file); - var hash = crypto.createHash('sha256'); - rs.on('data', hash.update.bind(hash)); - rs.on('error', (e) => { - reject(e); - }); - rs.on('end', () => { - resolve(hash.digest('hex')); - }); - }); -} - -security.stringSha256Sync = function (contents) { - var sha256 = crypto.createHash('sha256'); - sha256.update(contents); - return sha256.digest('hex'); -} - -security.packageHashSync = function (jsonData) { - var sortedArr = security.sortJsonToArr(jsonData); - var manifestData = _.filter(sortedArr, (v) => { - return !security.isPackageHashIgnored(v.path); - }).map((v) => { - return v.path + ':' + v.hash; - }); - log.debug('packageHashSync manifestData:', manifestData); - var manifestString = JSON.stringify(manifestData.sort()); - manifestString = _.replace(manifestString, /\\\//g, '/'); - log.debug('packageHashSync manifestString:', manifestString); - return security.stringSha256Sync(manifestString); -} - -//参数为buffer或者readableStream或者文件路径 -security.qetag = function (buffer) { - if (typeof buffer === 'string') { - try { - log.debug(`Check upload file ${buffer} fs.R_OK`); - fs.accessSync(buffer, fs.R_OK); - log.debug(`Pass upload file ${buffer}`); - } catch (e) { - log.error(e); - return Promise.reject(new AppError.AppError(e.message)) - } - } - log.debug(`generate file identical`) - return new Promise((resolve, reject) => { - qetag(buffer, (data)=>{ - log.debug('identical:', data); - resolve(data) - }); - }); -} - -security.sha256AllFiles = function (files) { - return new Promise((resolve, reject) => { - var results = {}; - var length = files.length; - var count = 0; - files.forEach((file) => { - security.fileSha256(file) - .then((hash) => { - results[file] = hash; - count++; - if (count == length) { - resolve(results); - } - }); - }); - }); -} - -security.uploadPackageType = function (directoryPath) { - return new Promise((resolve, reject) => { - var recursive = require("recursive-readdir"); - var path = require('path'); - var slash = require("slash"); - recursive(directoryPath, (err, files) => { - if (err) { - log.error(new AppError.AppError(err.message)); - reject(new AppError.AppError(err.message)); - } else { - if (files.length == 0) { - log.debug(`uploadPackageType empty files`); - reject(new AppError.AppError("empty files")); - } else { - var constName = require('../const'); - const AREGEX=/android\.bundle/ - const AREGEX_IOS=/main\.jsbundle/ - var packageType = 0; - _.forIn(files, function (value) { - if (AREGEX.test(value)) { - packageType = constName.ANDROID; - return false; - } - if (AREGEX_IOS.test(value)) { - packageType = constName.IOS; - return false; - } - }); - log.debug(`uploadPackageType packageType: ${packageType}`); - resolve(packageType); - } - } - }); - }); -} - -// some files are ignored in calc hash in client sdk -// https://github.com/Microsoft/react-native-code-push/pull/974/files#diff-21b650f88429c071b217d46243875987R15 -security.isHashIgnored = function (relativePath) { - if (!relativePath) { - return true; - } - - const IgnoreMacOSX = '__MACOSX/'; - const IgnoreDSStore = '.DS_Store'; - - return relativePath.startsWith(IgnoreMacOSX) - || relativePath === IgnoreDSStore - || relativePath.endsWith(IgnoreDSStore); -} - -security.isPackageHashIgnored = function (relativePath) { - if (!relativePath) { - return true; - } - - // .codepushrelease contains code sign JWT - // it should be ignored in package hash but need to be included in package manifest - const IgnoreCodePushMetadata = '.codepushrelease'; - return relativePath === IgnoreCodePushMetadata - || relativePath.endsWith(IgnoreCodePushMetadata) - || security.isHashIgnored(relativePath); -} - - -security.calcAllFileSha256 = function (directoryPath) { - return new Promise((resolve, reject) => { - var recursive = require("recursive-readdir"); - var path = require('path'); - var slash = require("slash"); - recursive(directoryPath, (error, files) => { - if (error) { - log.error(error); - reject(new AppError.AppError(error.message)); - } else { - // filter files that should be ignored - files = files.filter((file) => { - var relative = path.relative(directoryPath, file); - return !security.isHashIgnored(relative); - }); - - if (files.length == 0) { - log.debug(`calcAllFileSha256 empty files in directoryPath:`, directoryPath); - reject(new AppError.AppError("empty files")); - }else { - security.sha256AllFiles(files) - .then((results) => { - var data = {}; - _.forIn(results, (value, key) => { - var relativePath = path.relative(directoryPath, key); - var matchresult = relativePath.match(/(\/|\\).*/); - if (matchresult) { - relativePath = path.join('CodePush', matchresult[0]); - } - relativePath = slash(relativePath); - data[relativePath] = value; - }); - log.debug(`calcAllFileSha256 files:`, data); - resolve(data); - }); - } - } - }); - }); -} - -security.sortJsonToArr = function (json) { - var rs = []; - _.forIn(json, (value, key) => { - rs.push({path:key, hash: value}) - }); - return _.sortBy(rs, (o) => o.path); -} diff --git a/data/.gitignore b/data/.gitignore new file mode 100644 index 00000000..c96a04f0 --- /dev/null +++ b/data/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 00000000..d97b720f --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,39 @@ +version: '3.7' +services: + server: + image: shmopen/code-push-server:latest + volumes: + - data-storage:/data/storage + - data-tmp:/data/tmp + environment: + DOWNLOAD_URL: 'http://YOUR_MACHINE_IP:3000/download' + TOKEN_SECRET: 'YOUR_JWT_TOKEN_SECRET' + RDS_HOST: 'mysql' + RDS_USERNAME: 'codepush' + RDS_PASSWORD: '123456' + RDS_DATABASE: 'codepush' + STORAGE_DIR: '/data/storage' + DATA_DIR: '/data/tmp' + NODE_ENV: 'production' + REDIS_HOST: 'redis' + ports: + - '3000:3000' + depends_on: + - mysql + - redis + mysql: + image: mysql:latest + volumes: + - data-mysql:/var/lib/mysql + - ./sql/codepush-all-docker.sql:/docker-entrypoint-initdb.d/codepush-all.sql + environment: + MYSQL_ALLOW_EMPTY_PASSWORD: 'On' + redis: + image: redis:latest + volumes: + - data-redis:/data +volumes: + data-storage: + data-tmp: + data-mysql: + data-redis: diff --git a/docker/README.md b/docker/README.md deleted file mode 100644 index d1fb6da1..00000000 --- a/docker/README.md +++ /dev/null @@ -1,137 +0,0 @@ -# docker 部署 code-push-server - ->该文档用于描述docker部署code-push-server,实例包含三个部分 - -- code-push-server部分 - - 更新包默认采用`local`存储(即存储在本地机器上)。使用docker volume存储方式,容器销毁不会导致数据丢失,除非人为删除volume。 - - 内部使用pm2 cluster模式管理进程,默认开启进程数为cpu数,可以根据自己机器配置设置docker-compose.yml文件中deploy参数。 - - docker-compose.yml只提供了应用的一部分参数设置,如需要设置其他配置,可以修改文件config.js。 -- mysql部分 - - 数据使用docker volume存储方式,容器销毁不会导致数据丢失,除非人为删除volume。 - - 应用请勿使用root用户,为了安全可以创建权限相对较小的权限供code-push-server使用,只需要给予`select,update,insert`权限即可。初始化数据库需要使用root或有建表权限用户 -- redis部分 - - `tryLoginTimes` 登录错误次数限制 - - `updateCheckCache` 提升应用性能 - - `rolloutClientUniqueIdCache` 灰度发布 - -## 安装docker - -参考docker官方安装教程 - -- [>>mac点这里](https://docs.docker.com/docker-for-mac/install/) -- [>>windows点这里](https://docs.docker.com/docker-for-windows/install/) -- [>>linux点这里](https://docs.docker.com/install/linux/docker-ce/ubuntu/) - - -`$ docker info` 能成功输出相关信息,则安装成功,才能继续下面步骤 - -## 启动swarm - -```shell -$ sudo docker swarm init -``` - - -## 获取代码 - -```shell -$ git clone https://github.com/lisong/code-push-server.git -$ cd code-push-server/docker -``` - -## 修改配置文件 - -```shell -$ vim docker-compose.yml -``` - -*将`DOWNLOAD_URL`中`YOU_MACHINE_IP`替换成本机外网ip或者域名* - -*将`MYSQL_HOST`中`YOU_MACHINE_IP`替换成本机内网ip* - -*将`REDIS_HOST`中`YOU_MACHINE_IP`替换成本机内网ip* - -## jwt.tokenSecret修改 - -> code-push-server 验证登录验证方式使用的json web token加密方式,该对称加密算法是公开的,所以修改config.js中tokenSecret值很重要。 - -*非常重要!非常重要! 非常重要!* - -> 可以打开连接`https://www.grc.com/passwords.htm`获取 `63 random alpha-numeric characters`类型的随机生成数作为密钥 - -## 部署 - -```shell -$ sudo docker stack deploy -c docker-compose.yml code-push-server -``` - -> 如果网速不佳,需要漫长而耐心的等待。。。去和妹子聊会天吧^_^ - - -## 查看进展 - -```shell -$ sudo docker service ls -$ sudo docker service ps code-push-server_db -$ sudo docker service ps code-push-server_redis -$ sudo docker service ps code-push-server_server -``` - -> 确认`CURRENT STATE` 为 `Running about ...`, 则已经部署完成 - -## 访问接口简单验证 - -`$ curl -I http://YOUR_CODE_PUSH_SERVER_IP:3000/` - -返回`200 OK` - -```http -HTTP/1.1 200 OK -X-DNS-Prefetch-Control: off -X-Frame-Options: SAMEORIGIN -Strict-Transport-Security: max-age=15552000; includeSubDomains -X-Download-Options: noopen -X-Content-Type-Options: nosniff -X-XSS-Protection: 1; mode=block -Content-Type: text/html; charset=utf-8 -Content-Length: 592 -ETag: W/"250-IiCMcM1ZUFSswSYCU0KeFYFEMO8" -Date: Sat, 25 Aug 2018 15:45:46 GMT -Connection: keep-alive -``` - -## 浏览器登录 - -> 默认用户名:admin 密码:123456 记得要修改默认密码哦 -> 如果登录连续输错密码超过一定次数,会限定无法再登录. 需要清空redis缓存 - -```shell -$ redis-cli -p6388 # 进入redis -> flushall -> quit -``` - - -## 查看服务日志 - -```shell -$ sudo docker service logs code-push-server_server -$ sudo docker service logs code-push-server_db -$ sudo docker service logs code-push-server_redis -``` - -## 查看存储 `docker volume ls` - -DRIVER | VOLUME NAME | 描述 ------- | ----- | ------- -local | code-push-server_data-mysql | 数据库存储数据目录 -local | code-push-server_data-storage | 存储打包文件目录 -local | code-push-server_data-tmp | 用于计算更新包差异文件临时目录 -local | code-push-server_data-redis | redis落地数据 - -## 销毁退出应用 - -```bash -$ sudo docker stack rm code-push-server -$ sudo docker swarm leave --force -``` diff --git a/docker/code-push-server/Dockerfile b/docker/code-push-server/Dockerfile deleted file mode 100644 index 004406ba..00000000 --- a/docker/code-push-server/Dockerfile +++ /dev/null @@ -1,10 +0,0 @@ -FROM node:8.11.4-alpine - -RUN npm config set registry https://registry.npm.taobao.org/ \ -&& npm i -g code-push-server@0.5.2 pm2@latest --no-optional - -COPY ./process.json /process.json - -EXPOSE 3000 - -CMD ["pm2-docker", "start", "/process.json"] diff --git a/docker/code-push-server/process.json b/docker/code-push-server/process.json deleted file mode 100644 index 493010d3..00000000 --- a/docker/code-push-server/process.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "apps" : [ - { - "name" : "code-push-server", - "max_memory_restart" : "500M", - "script" : "code-push-server", - "instances" : "max", //开启实例数量,max为cpu核数 - "exec_mode" : "cluster", //集群模式,最大提升网站并发 - } - ] -} \ No newline at end of file diff --git a/docker/config.js b/docker/config.js deleted file mode 100644 index f78fc3b6..00000000 --- a/docker/config.js +++ /dev/null @@ -1,93 +0,0 @@ -var config = {}; -config.development = { - // Config for database, only support mysql. - db: { - username: process.env.MYSQL_USERNAME, - password: process.env.MYSQL_PASSWORD, - database: process.env.MYSQL_DATABASE, - host: process.env.MYSQL_HOST, - port: process.env.MYSQL_PORT || 3306, - dialect: "mysql", - logging: false, - operatorsAliases: false, - }, - // Config for local storage when storageType value is "local". - local: { - // Binary files storage dir, Do not use tmpdir and it's public download dir. - storageDir: process.env.STORAGE_DIR, - // Binary files download host address which Code Push Server listen to. the files storage in storageDir. - downloadUrl: process.env.DOWNLOAD_URL, - // public static download spacename. - public: '/download' - }, - jwt: { - // Recommended: 63 random alpha-numeric characters - // Generate using: https://www.grc.com/passwords.htm - tokenSecret: 'INSERT_RANDOM_TOKEN_KEY' - }, - common: { - /* - * tryLoginTimes is control login error times to avoid force attack. - * if value is 0, no limit for login auth, it may not safe for account. when it's a number, it means you can - * try that times today. but it need config redis server. - */ - tryLoginTimes: 4, - // CodePush Web(https://github.com/lisong/code-push-web) login address. - //codePushWebUrl: "http://127.0.0.1:3001/login", - // create patch updates's number. default value is 3 - diffNums: 3, - // data dir for caclulate diff files. it's optimization. - dataDir: process.env.DATA_DIR, - // storageType which is your binary package files store. options value is ("local" | "qiniu" | "s3") - storageType: "local", - // options value is (true | false), when it's true, it will cache updateCheck results in redis. - updateCheckCache: false, - // options value is (true | false), when it's true, it will cache rollout results in redis - rolloutClientUniqueIdCache: false, - }, - // Config for smtp email,register module need validate user email project source https://github.com/nodemailer/nodemailer - smtpConfig:{ - host: "smtp.aliyun.com", - port: 465, - secure: true, - auth: { - user: "", - pass: "" - } - }, - // Config for redis (register module, tryLoginTimes module) - redis: { - default: { - host: process.env.REDIS_HOST, - port: process.env.REDIS_PORT || 6379, - retry_strategy: function (options) { - if (options.error.code === 'ECONNREFUSED') { - // End reconnecting on a specific error and flush all commands with a individual error - return new Error('The server refused the connection'); - } - if (options.total_retry_time > 1000 * 60 * 60) { - // End reconnecting after a specific timeout and flush all commands with a individual error - return new Error('Retry time exhausted'); - } - if (options.times_connected > 10) { - // End reconnecting with built in error - return undefined; - } - // reconnect after - return Math.max(options.attempt * 100, 3000); - } - } - } -} - -config.development.log4js = { - appenders: {console: { type: 'console'}}, - categories : { - "default": { appenders: ['console'], level:'error'}, - "startup": { appenders: ['console'], level:'info'}, - "http": { appenders: ['console'], level:'info'} - } -} - -config.production = Object.assign({}, config.development); -module.exports = config; diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml deleted file mode 100644 index 2b625f8f..00000000 --- a/docker/docker-compose.yml +++ /dev/null @@ -1,63 +0,0 @@ -version: "3.7" -services: - server: - image: tablee/code-push-server:v0.5.2 - volumes: - - data-storage:/data/storage - - data-tmp:/data/tmp - - ./config.js:/config.js - environment: - DOWNLOAD_URL: "http://YOU_MACHINE_IP:3000/download" - MYSQL_HOST: "YOU_MACHINE_IP" - MYSQL_PORT: "3308" - MYSQL_USERNAME: "codepush" - MYSQL_PASSWORD: "123456" - MYSQL_DATABASE: "codepush" - STORAGE_DIR: "/data/storage" - DATA_DIR: "/data/tmp" - NODE_ENV: "production" - CONFIG_FILE: "/config.js" - REDIS_HOST: "YOU_MACHINE_IP" - REDIS_PORT: "6388" - deploy: - resources: - limits: - cpus: "2" - memory: 1000M - restart_policy: - condition: on-failure - ports: - - "3000:3000" - networks: - - servernet - depends_on: - - db - - redis - db: - image: mysql:5.7.23 - volumes: - - data-mysql:/var/lib/mysql - - ./sql/codepush-all.sql:/docker-entrypoint-initdb.d/codepush-all.sql - ports: - - "3308:3306" - environment: - MYSQL_ALLOW_EMPTY_PASSWORD: "On" - networks: - - dbnet - redis: - image: redis:4.0.11-alpine - volumes: - - data-redis:/data - ports: - - "6388:6379" - networks: - - redisnet -networks: - servernet: - dbnet: - redisnet: -volumes: - data-storage: - data-tmp: - data-mysql: - data-redis: diff --git a/docs/README.md b/docs/README.md deleted file mode 100644 index 9419e94d..00000000 --- a/docs/README.md +++ /dev/null @@ -1,238 +0,0 @@ - -## INSTALL NODE AND NPM - -[see](https://nodejs.org/en/download/) - -> (chosen latest LTS version) - -## INSTALL PM2 - -```bash -$ sudo npm i -g pm2 -``` - -## INSTALL MYSQL - -- [Linux](https://dev.mysql.com/doc/refman/8.0/en/linux-installation.html) -- [macOS](https://dev.mysql.com/doc/refman/8.0/en/osx-installation.html) -- [Microsoft Windows](https://dev.mysql.com/doc/refman/8.0/en/windows-installation.html) -- [Others](https://dev.mysql.com/doc/refman/8.0/en/installing.html) - -> notice. mysql8.x default auth caching_sha2_pasword not support in node-mysql2 see [issue](https://github.com/mysqljs/mysql/pull/1962) - - - -## GET code-push-server FROM NPM - -```shell -$ npm install code-push-server@latest -g -``` - - -## GET code-push-server FROM SOURCE CODE - -```shell -$ git clone https://github.com/lisong/code-push-server.git -$ cd code-push-server -$ npm install -``` - -## INIT DATABASE - -```shell -$ code-push-server-db init --dbhost "your mysql host" --dbport "your mysql port" --dbuser "your mysql user" --dbpassword "your mysql password" -``` - -or from source code - -```shell -$ ./bin/db init --dbhost "your mysql host" --dbport "your mysql port" --dbuser "your mysql user" --dbpassword "your mysql password" -``` - -> output: success - -## CONFIGURE for code-push-server - -save the file [config.js](https://github.com/lisong/code-push-server/blob/master/config/config.js) - -some config have to change: - -- `local`.`storageDir` change to your directory,make sure have read/write permissions. -- `local`.`downloadUrl` replace `127.0.0.1` to your machine ip. -- `common`.`dataDir` change to your directory,make sure have read/write permissions. -- `jwt`.`tokenSecret` get the random string from `https://www.grc.com/passwords.htm`, and replace the value `INSERT_RANDOM_TOKEN_KEY`. -- `db` config: `username`,`password`,`host`,`port` change your own's - -## CONFIGURE for pm2 - -save the file [process.json](https://github.com/lisong/code-push-server/blob/master/docs/process.json) - -some config have to change: - -- `script` if you install code-push-server from npm use `code-push-server`,or use `"your source code dir"/bin/www` -- `CONFIG_FILE` above config.js file path,use absolute path. - -## START SERVICE - -```shell -$ pm2 start process.json -``` - -## RESTART SERVICE - -```shell -$ pm2 restart process.json -``` - -## STOP SERVICE - -```shell -$ pm2 stop process.json -``` - -## CHECK SERVICE IS OK - -```shell -$ curl -I http://YOUR_CODE_PUSH_SERVER_IP:3000/ -``` - -> return httpCode `200 OK` - -```http -HTTP/1.1 200 OK -X-DNS-Prefetch-Control: off -X-Frame-Options: SAMEORIGIN -Strict-Transport-Security: max-age=15552000; includeSubDomains -X-Download-Options: noopen -X-Content-Type-Options: nosniff -X-XSS-Protection: 1; mode=block -Content-Type: text/html; charset=utf-8 -Content-Length: 592 -ETag: W/"250-IiCMcM1ZUFSswSYCU0KeFYFEMO8" -Date: Sat, 25 Aug 2018 15:45:46 GMT -Connection: keep-alive -``` - - -## Use redis impove concurrent and security - -> config redis in config.js - -- `updateCheckCache` -- `rolloutClientUniqueIdCache` -- `tryLoginTimes` - - -## UPGRADE - -*from npm package* - -```shell -$ npm install -g code-push-server@latest -$ code-push-server-db upgrade --dbhost "your mysql host" --dbport "your mysql port" --dbuser "your mysql user" --dbpassword "your mysql password" # upgrade codepush database -$ pm2 restart code-push-server # restart service -``` - -*from source code* - -```shell -$ cd /path/to/code-push-server -$ git pull --rebase origin master -$ ./bin/db upgrade --dbhost "your mysql host" --dbport "your mysql port" --dbuser "your mysql user" --dbpassword "your mysql password" -# upgrade codepush database -$ pm2 restart code-push-server # restart service -``` - - -## view pm2 logs - -```shell -$ pm2 ls -$ pm2 show code-push-server -$ tail -f "output file path" -``` - - -## Support Storage mode - -- local (default) -- qiniu (qiniu) -- s3 (aws) -- oss (aliyun) -- tencentcloud - -## Default listen Host/Port 0.0.0.0/3000 - -> you can change it in process.json, env: PORT,HOST - - -## [code-push-cli](https://github.com/Microsoft/code-push) - -> Use code-push-cli manager CodePushServer - -```shell -$ npm install code-push-cli@latest -g -$ code-push login http://YOU_SERVICE_IP:3000 #login in browser account:admin password:123456 -``` - -> change admin password eg. - -```shell -$ curl -X PATCH -H "Authorization: Bearer mytoken" -H "Accept: application/json" -H "Content-Type:application/json" -d '{"oldPassword":"123456","newPassword":"654321"}' http://YOU_SERVICE_IP:3000/users/password -``` - - -## config react-native project - -> Follow the react-native-code-push docs, addition iOS add a new entry named CodePushServerURL, whose value is the key of ourself CodePushServer URL. Android use the new CodePush constructor in MainApplication point CodePushServerUrl - -iOS eg. in file Info.plist - -```xml -... -CodePushDeploymentKey -YourCodePushKey -CodePushServerURL -YourCodePushServerUrl -... -``` - -Android eg. in file MainApplication.java - -```java -@Override -protected List getPackages() { - return Arrays.asList( - new MainReactPackage(), - new CodePush( - "YourKey", - MainApplication.this, - BuildConfig.DEBUG, - "YourCodePushServerUrl" - ) - ); -} -``` - - -## [cordova-plugin-code-push](https://github.com/Microsoft/cordova-plugin-code-push) for cordova - -```shell -$ cd /path/to/project -$ cordova plugin add cordova-plugin-code-push@latest --save -``` - -## config cordova project - -edit config.xml. add code below. - -```xml - - - - - - - - -``` diff --git a/docs/install-server-by-docker.cn.md b/docs/install-server-by-docker.cn.md new file mode 100644 index 00000000..39f04661 --- /dev/null +++ b/docs/install-server-by-docker.cn.md @@ -0,0 +1,117 @@ +# docker 部署 code-push-server + +> 该文档用于描述 docker 部署 code-push-server,实例包含三个部分 + +- code-push-server 部分 + - 更新包默认采用`local`存储(即存储在本地机器上)。使用 docker volume 存储方式,容器销毁不会导致数据丢失,除非人为删除 volume。 + - 内部使用 pm2 cluster 模式管理进程,默认开启进程数为 cpu 数,可以根据自己机器配置设置 docker-compose.yml 文件中 deploy 参数。 + - docker-compose.yml 只提供了应用的一部分参数设置,如需要设置其他配置,可以修改文件 config.js。 +- mysql 部分 + - 数据使用 docker volume 存储方式,容器销毁不会导致数据丢失,除非人为删除 volume。 + - 应用请勿使用 root 用户,为了安全可以创建权限相对较小的权限供 code-push-server 使用,只需要给予`select,update,insert`权限即可。初始化数据库需要使用 root 或有建表权限用户 +- redis 部分 + - `tryLoginTimes` 登录错误次数限制 + - `updateCheckCache` 提升应用性能 + - `rolloutClientUniqueIdCache` 灰度发布 + +## 安装 Docker + +参考 Docker 官方安装教程 + +- [>>mac 点这里](https://docs.docker.com/docker-for-mac/install/) +- [>>windows 点这里](https://docs.docker.com/docker-for-windows/install/) +- [>>linux 点这里](https://docs.docker.com/install/linux/docker-ce/ubuntu/) + +`$ docker info` 能成功输出相关信息,则安装成功,才能继续下面步骤 + +## 获取代码 + +```shell +$ git clone https://github.com/shm-open/code-push-server.git +$ cd code-push-server +``` + +## 修改配置文件 + +```shell +$ vim docker-compose.yml +``` + +_将`DOWNLOAD_URL`中`YOUR_MACHINE_IP`替换成本机外网 ip 或者域名_ + +### jwt.tokenSecret 修改 + +> code-push-server 验证登录验证方式使用的 json web token 加密方式,该对称加密算法是公开的,所以修改 config.js 中 tokenSecret 值很重要。 + +_非常重要!非常重要! 非常重要!_ + +> 可以打开连接`https://www.grc.com/passwords.htm`获取 `63 random alpha-numeric characters`类型的随机生成数作为密钥 + +_将`TOKEN_SECRET`中`YOUR_JWT_TOKEN_SECRET`替换成密钥_ + +## 部署 + +```shell +$ docker-compose up -d +``` + +> 如果网速不佳,需要漫长而耐心的等待。。。去和妹子聊会天吧^\_^ + +## 查看进展 + +```shell +$ docker-compose ps +``` + +## 访问接口简单验证 + +`$ curl -I http://YOUR_CODE_PUSH_SERVER_IP:3000/` + +返回`200 OK` + +```http +HTTP/1.1 200 OK +X-DNS-Prefetch-Control: off +X-Frame-Options: SAMEORIGIN +Strict-Transport-Security: max-age=15552000; includeSubDomains +X-Download-Options: noopen +X-Content-Type-Options: nosniff +X-XSS-Protection: 1; mode=block +Content-Type: text/html; charset=utf-8 +Content-Length: 592 +ETag: W/"250-IiCMcM1ZUFSswSYCU0KeFYFEMO8" +Date: Sat, 25 Aug 2018 15:45:46 GMT +Connection: keep-alive +``` + +## 浏览器登录 + +> 默认用户名:admin 密码:123456 记得要修改默认密码哦 +> 如果登录连续输错密码超过一定次数,会限定无法再登录. 需要清空 redis 缓存 + +```shell +$ docker exec -it code-push-server_redis_1 redis-cli # 进入redis +> flushall +> quit +``` + +## 查看服务日志 + +```shell +$ docker-compose logs server +``` + +## 查看存储 `docker volume ls` + +| DRIVER | VOLUME NAME | 描述 | +| ------ | ----------------------------- | ------------------------------ | +| local | code-push-server_data-mysql | 数据库存储数据目录 | +| local | code-push-server_data-storage | 存储打包文件目录 | +| local | code-push-server_data-tmp | 用于计算更新包差异文件临时目录 | +| local | code-push-server_data-redis | redis 落地数据 | + +## 销毁退出应用 + +```shell +$ docker-compose down +``` diff --git a/docs/install-server-by-docker.md b/docs/install-server-by-docker.md new file mode 100644 index 00000000..76fd3514 --- /dev/null +++ b/docs/install-server-by-docker.md @@ -0,0 +1,119 @@ +# docker deploy code-push-server + +[[Chinese version 中文版]](./install-server-by-docker.cn.md) + +> This document is used to describe docker deployment code-push-server, the example consists of three parts + +- code-push-server section + - Update packages are stored in `local` by default (i.e. stored on the local machine). Using the docker volume storage method, container destruction will not cause data loss unless the volume is manually deleted. + - The pm2 cluster mode is used to manage processes internally. The default number of open processes is the number of cpus. You can set the deploy parameter in the docker-compose.yml file according to your own machine configuration. + - docker-compose.yml only provides some parameter settings of the application. If you need to set other configurations, you can modify the file config.js. +- mysql section + - Data is stored using docker volume, and container destruction will not cause data loss unless the volume is manually deleted. + - Do not use the root user for the application. For security, you can create permissions with relatively small permissions for use by code-push-server. You only need to give `select, update, insert` permissions. To initialize the database, you need to use root or a user with table building privileges +- redis part + - `tryLoginTimes` login error limit + - `updateCheckCache` improves application performance + - `rolloutClientUniqueIdCache` grayscale release + +## Install Docker + +Refer to the official Docker installation tutorial + +- [>>mac click here](https://docs.docker.com/docker-for-mac/install/) +- [>>windows click here](https://docs.docker.com/docker-for-windows/install/) +- [>>linux click here](https://docs.docker.com/install/linux/docker-ce/ubuntu/) + +`$ docker info` can successfully output relevant information, the installation is successful, and the following steps can be continued + +## get code + +```shell +$ git clone https://github.com/shm-open/code-push-server.git +$ cd code-push-server +```` + +## Modify the configuration file + +```shell +$ vim docker-compose.yml +```` + +_Replace `YOUR_MACHINE_IP` in `DOWNLOAD_URL` with your own external network ip or domain name_ + +### jwt.tokenSecret modification + +> code-push-server verifies the json web token encryption method used by the login authentication method. The symmetric encryption algorithm is public, so it is very important to modify the tokenSecret value in config.js. + +_Very important! Very important! Very important! _ + +> You can open the connection `https://www.grc.com/passwords.htm` to obtain a randomly generated number of type `63 random alpha-numeric characters` as the key + +_Replace `YOUR_JWT_TOKEN_SECRET` in `TOKEN_SECRET` with the key_ + +## deploy + +```shell +$ docker-compose up -d +```` + +> If the internet speed is not good, a long and patient wait is required. . . Let's chat with the girl for a while ^\_^ + +## View progress + +```shell +$ docker-compose ps +```` + +## Access interface simple verification + +`$ curl -I http://YOUR_CODE_PUSH_SERVER_IP:3000/` + +returns `200 OK` + +````http +HTTP/1.1 200 OK +X-DNS-Prefetch-Control: off +X-Frame-Options: SAMEORIGIN +Strict-Transport-Security: max-age=15552000; includeSubDomains +X-Download-Options: noopen +X-Content-Type-Options: nosniff +X-XSS-Protection: 1; mode=block +Content-Type: text/html; charset=utf-8 +Content-Length: 592 +ETag: W/"250-IiCMcM1ZUFSswSYCU0KeFYFEMO8" +Date: Sat, 25 Aug 2018 15:45:46 GMT +Connection: keep-alive +```` + +## Browser login + +> Default username: admin Password: 123456 Remember to change the default password +> If you log in and enter the wrong password for more than a certain number of times, you will no longer be able to log in. You need to clear the redis cache + +```shell +$ docker exec -it code-push-server_redis_1 redis-cli # Enter redis +> flushall +> quit +```` + +## View service log + +```shell +$ docker-compose logs server +```` + +## View storage `docker volume ls` + +| DRIVER | VOLUME NAME | DESCRIPTION | +| ------ | ----------------------------- | ------------ ------------------ | +| local | code-push-server_data-mysql | database storage data directory | +| local | code-push-server_data-storage | Storage package file directory | +| local | code-push-server_data-tmp | Temporary directory for calculating update package difference files | +| local | code-push-server_data-redis | redis landing data | + +## destroy exit application + +```shell +$ docker-compose down +``` diff --git a/docs/install-server.md b/docs/install-server.md new file mode 100644 index 00000000..43a7de13 --- /dev/null +++ b/docs/install-server.md @@ -0,0 +1,136 @@ +## Install Node and NPM + +[see](https://nodejs.org/en/download/) + +> (chosen latest LTS version) + +## Install PM2 + +```bash +$ sudo npm i -g pm2 +``` + +## Install MySQL + +- [Linux](https://dev.mysql.com/doc/refman/8.0/en/linux-installation.html) +- [macOS](https://dev.mysql.com/doc/refman/8.0/en/osx-installation.html) +- [Microsoft Windows](https://dev.mysql.com/doc/refman/8.0/en/windows-installation.html) +- [Others](https://dev.mysql.com/doc/refman/8.0/en/installing.html) + +> notice. mysql8.x default auth caching_sha2_pasword not support in node-mysql2 see [issue](https://github.com/mysqljs/mysql/pull/1962) + +## Install Redis + +- [Redis Quick Start](https://redis.io/topics/quickstart) + +## Get code-push-server from NPM + +```shell +$ npm install @shm-open/code-push-server@latest -g +``` + +## Init Database + +```shell +$ code-push-server-db init --dbhost "your mysql host" --dbport "your mysql port" --dbuser "your mysql user" --dbpassword "your mysql password" +``` + +> output: success + +## Configure code-push-server + +check out the supported config items in [config.ts](../src/core/config.ts) + +save the file [process.json](../process.json) for PM2, and add your config items to `"env"` + +some config items have to be changed: + +- `local`.`storageDir` change to your directory, make sure have read/write permissions. +- `local`.`downloadUrl` replace `127.0.0.1` to your machine ip. +- `common`.`dataDir` change to your directory,make sure have read/write permissions. +- `jwt`.`tokenSecret` get the random string from `https://www.grc.com/passwords.htm`, and replace the value `INSERT_RANDOM_TOKEN_KEY`. +- `db` config: `username`,`password`,`host`,`port` change to your own + +## Start Service + +```shell +$ pm2 start process.json +``` + +## Restart Service + +```shell +$ pm2 restart process.json +``` + +## Stop Service + +```shell +$ pm2 stop process.json +``` + +## Check Service is OK + +```shell +$ curl -I http://YOUR_CODE_PUSH_SERVER_IP:3000/ +``` + +> return httpCode `200 OK` + +```http +HTTP/1.1 200 OK +X-DNS-Prefetch-Control: off +X-Frame-Options: SAMEORIGIN +Strict-Transport-Security: max-age=15552000; includeSubDomains +X-Download-Options: noopen +X-Content-Type-Options: nosniff +X-XSS-Protection: 1; mode=block +Content-Type: text/html; charset=utf-8 +Content-Length: 592 +ETag: W/"250-IiCMcM1ZUFSswSYCU0KeFYFEMO8" +Date: Sat, 25 Aug 2018 15:45:46 GMT +Connection: keep-alive +``` + +## Use redis impove concurrent and security + +> config redis in config.js + +- `updateCheckCache` +- `rolloutClientUniqueIdCache` +- `tryLoginTimes` + +## Upgrade from old version + +```shell +$ npm install -g @shm-open/code-push-server@latest +$ code-push-server-db upgrade --dbhost "your mysql host" --dbport "your mysql port" --dbuser "your mysql user" --dbpassword "your mysql password" # upgrade codepush database +$ pm2 restart code-push-server # restart service +``` + +## view pm2 logs + +```shell +$ pm2 ls +$ pm2 show code-push-server +$ tail -f "output file path" +``` + +## Default listen Host/Port 0.0.0.0/3000 + +> you can change it in process.json, env: PORT,HOST + +## [code-push-cli](https://github.com/shm-open/code-push-cli) + +> Use code-push-cli manage CodePush Server + +```shell +$ npm install @shm-open/code-push-cli@latest -g +$ code-push login http://YOU_SERVICE_IP:3000 #login in browser account:admin password:123456 +``` + +## Change Admin Password + +```shell +$ curl -X PATCH -H "Authorization: Bearer mytoken" -H "Accept: application/json" -H "Content-Type:application/json" -d '{"oldPassword":"123456","newPassword":"654321"}' http://YOU_SERVICE_IP:3000/users/password +``` diff --git a/docs/process.json b/docs/process.json deleted file mode 100644 index 8ef0e3e1..00000000 --- a/docs/process.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "apps" : [ - { - "name" : "code-push-server", - "max_memory_restart" : "300M", - "script" : "/path/to/code-push-server/bin/www", - "instances" : "max", //开启实例数量,max为cpu核数 - "exec_mode" : "cluster", //集群模式,最大提升网站并发 - "env" : { - "NODE_ENV" : "production", - "PORT" : 3000, - "CONFIG_FILE" : "/path/to/production/config.js" - - // Must set add config when STORAGE_TYPE is upyun - // "STORAGE_TYPE" : "upyun", - // "DOWNLOAD_URL" : "", - // "UPYUN_STORAGE_DIR" : "", - // "UPYUN_SERVICE_NAME" : "", - // "UPYUN_OPERATOR_NAME" : "", - // "UPYUN_OPERATOR_PASS" : "" - } - } - ] -} \ No newline at end of file diff --git a/docs/react-native-code-push.md b/docs/react-native-code-push.md deleted file mode 100644 index 0b70bf37..00000000 --- a/docs/react-native-code-push.md +++ /dev/null @@ -1,158 +0,0 @@ -# `react-native` 如何使用 `code-push` 热更新 - -## 使用前须知 - - - Q: “苹果应用商店和android应用商店允不允许使用热更新?” - A: “都允许。” - - > 苹果允许使用热更新[Apple's developer agreement](https://developer.apple.com/programs/ios/information/iOS_Program_Information_4_3_15.pdf), 但是规定不能弹框提示用户更新,影响用户体验。 - > Google Play也允许热更新,但必须弹框告知用户更新。在中国的android市场发布时,都必须关闭更新弹框,否则会在审核应用时以“请上传最新版本的二进制应用包”驳回应用。 - - - Q: “react-native 开发环境更新模式是否可以直接用在生产环境下?” - A: “不能。” - - - Q: “code-push使用复杂么?” - A: “不复杂。很多网上的文章说复杂,是因为作者没有仔细理解官方文档,而且认为踩坑了。” - - - Q: “为什么推荐code-push?” - A: ”非常好。除了满足基本更新功能外,还有统计,hash计算容错和补丁更新功能。微软的项目,大公司技术有保障,而且开源。近几年微软在拥抱开源方面,让大家也是刮目相看。“ - -## 安装依赖包 - -#### 1. [react-native-cli](https://github.com/facebook/react-native) react-native命令行工具,安装后可以在终端使用`react-native`命令 - -```shell -$ npm install react-native-cli@latest -g -``` - -#### 2. [code-push-cli](https://github.com/Microsoft/code-push) 连接微软云端,管理发布更新版本命令行工具,安装后可以在终端使用`code-push`命令 - -```shell -$ npm install code-push-cli@latest -g -``` - -#### 3. [react-native-code-push](https://github.com/Microsoft/react-native-code-push) 集成到react-native项目,按照以下步骤安装并修改配置既可集成 - -```shell -$ react-native init CodePushDemo #初始化一个react-native项目 -$ cd CodePushDemo -$ npm install --save react-native-code-push@latest #安装react-native-code-push -$ react-native link react-native-code-push #连接到项目中,提示输入配置可以先行忽略 -``` - -#### 4. [code-push-server](https://github.com/lisong/code-push-server) 微软云服务在中国太慢,可以用它搭建自己的服务端。 - -- [docker](https://github.com/lisong/code-push-server/blob/master/docker/README.md) (recommend) -- [manual operation](https://github.com/lisong/code-push-server/blob/master/docs/README.md) - -## 创建服务端应用 - -基于code-push-server服务 - -```shell -$ code-push login http://YOUR_CODE_PUSH_SERVER_IP:3000 #浏览器中登录获取token,用户名:admin, 密码:123456 -$ code-push app add CodePushDemoiOS ios react-native #创建iOS版, 获取Production DeploymentKey -$ code-push app add CodePushDemoAndroid android react-native #创建android版,获取获取Production DeploymentKey -``` - -## 配置CodePushDemo react-native项目 - -#### iOS 配置 - -编辑`Info.plist`文件,添加`CodePushDeploymentKey`和`CodePushServerURL` - -1. `CodePushDeploymentKey`值设置为CodePushDemo-ios的Production DeploymentKey值。 - -2. `CodePushServerURL`值设置为code-push-server服务地址 http://YOUR_CODE_PUSH_SERVER_IP:3000/ 不在同一台机器的时候,请将YOUR_CODE_PUSH_SERVER_IP改成外网ip或者域名地址。 - -3. 将默认版本号1.0改成三位1.0.0 - -```xml -... -CodePushDeploymentKey -YourCodePushKey -CodePushServerURL -YourCodePushServerUrl -... -``` - -#### android 配置 - -编辑`MainApplication.java` - -1. `YourKey`替换成CodePushDemo-android的Production DeploymentKey值 - -2. `YourCodePushServerUrl`值设置为code-push-server服务地址 http://YOUR_CODE_PUSH_SERVER_IP:3000/ 不在同一台机器的时候,请将YOUR_CODE_PUSH_SERVER_IP改成外网ip或者域名地址。 - -3. 将默认版本号1.0改成三位1.0.0 - -```java -@Override -protected List getPackages() { - return Arrays.asList( - new MainReactPackage(), - new CodePush( - "YourKey", - MainApplication.this, - BuildConfig.DEBUG, - "YourCodePushServerUrl" - ) - ); -} -``` - -## 添加更新检查 - -可以参考[code-push-demo-app](https://github.com/lisong/code-push-demo-app/) -可以在入口componentDidMount添加 - -```javascript -CodePush.sync({ - installMode: CodePush.InstallMode.IMMEDIATE, - updateDialog: true -}); -``` - -不要忘记头部引入 - -```javascript -import CodePush from "react-native-code-push" -``` - -## 运行CodePushDemo react-native项目 - -#### iOS - -```shell -$ cd /path/to/CodePushDemo -$ open ios/CodePushDemo.xcodeproj -``` -在Xcode中打开菜单 Product > Scheme > Edit Scheme... > Run 选项中Build Configuration修改成Release, 然后运行编译 - -### android - -```shell -$ cd /path/to/CodePushDemo -$ cd android -$ ./gradlew assembleRelease -$ cd app/build/outputs/apk #将打好的包app-release.apk安装到您的手机上 -``` - -## 发布更新到服务上 - -iOS和android要分开发布,所以创建了`CodePushDemo-ios`和`CodePushDemo-android`应用 - -```shell -$ cd /path/to/CodePushDemo -$ code-push release-react CodePushDemo-ios ios -d Production #iOS版 -$ code-push release-react CodePushDemo-android android -d Production #android版 -``` - -## 例子 - -[code-push-demo-app](https://github.com/lisong/code-push-demo-app) - - -### 更多信息参考[code-push-server](https://github.com/lisong/code-push-server) - - diff --git a/models/apps.js b/models/apps.js deleted file mode 100644 index 00e0372f..00000000 --- a/models/apps.js +++ /dev/null @@ -1,24 +0,0 @@ -"use strict"; - -module.exports = function(sequelize, DataTypes) { - var Apps = sequelize.define("Apps", { - id: { - type: DataTypes.INTEGER(10), - allowNull: false, - autoIncrement: true, - primaryKey: true, - }, - name: DataTypes.STRING, - uid: DataTypes.BIGINT(20), - os: DataTypes.INTEGER(3), - platform: DataTypes.INTEGER(3), - is_use_diff_text: DataTypes.INTEGER(3), - created_at: DataTypes.DATE, - updated_at: DataTypes.DATE, - }, { - tableName: 'apps', - underscored: true, - paranoid: true, - }); - return Apps; -}; diff --git a/models/collaborators.js b/models/collaborators.js deleted file mode 100644 index c5f8d268..00000000 --- a/models/collaborators.js +++ /dev/null @@ -1,29 +0,0 @@ -"use strict"; - -module.exports = function(sequelize, DataTypes) { - var Collaborators = sequelize.define("Collaborators", { - id: { - type: DataTypes.BIGINT(20), - allowNull: false, - autoIncrement: true, - primaryKey: true - }, - appid: DataTypes.INTEGER(10), - uid: DataTypes.BIGINT(20), - roles : DataTypes.STRING, - created_at: DataTypes.DATE, - updated_at: DataTypes.DATE, - }, { - tableName: 'collaborators', - underscored: true, - paranoid: true - }); - Collaborators.findByAppNameAndUid = function (uid, appName) { - var sql = "SELECT b.* FROM `apps` as a left join `collaborators` as b on (a.id = b.appid) where a.name= :appName and b.uid = :uid and a.`deleted_at` IS NULL and b.`deleted_at` IS NULL limit 0,1"; - return sequelize.query(sql, { replacements: { appName: appName, uid: uid }, model: Collaborators}) - .then(function(data) { - return data.pop(); - }); - }; - return Collaborators; -}; diff --git a/models/deployments.js b/models/deployments.js deleted file mode 100644 index fade4b93..00000000 --- a/models/deployments.js +++ /dev/null @@ -1,45 +0,0 @@ -"use strict"; - -var _ = require('lodash'); -var AppError = require('../core/app-error'); - -module.exports = function(sequelize, DataTypes) { - var Deployments = sequelize.define("Deployments", { - id: { - type: DataTypes.INTEGER(10), - allowNull: false, - autoIncrement: true, - primaryKey: true - }, - appid: DataTypes.INTEGER(10), - name: DataTypes.STRING, - description: DataTypes.STRING, - deployment_key: DataTypes.STRING, - last_deployment_version_id: DataTypes.INTEGER(10), - label_id: DataTypes.INTEGER(10), - created_at: DataTypes.DATE, - updated_at: DataTypes.DATE, - }, { - tableName: 'deployments', - underscored: true, - paranoid: true - }); - - Deployments.generateLabelId = function(deploymentId) { - var self = this; - return sequelize.transaction(function (t) { - return self.findById(deploymentId, {transaction: t,lock: t.LOCK.UPDATE}).then(function (data) { - if (_.isEmpty(data)){ - throw new AppError.AppError("does not find deployment"); - } - data.label_id = data.label_id + 1; - return data.save({transaction: t}) - .then(function (data) { - return data.label_id; - }); - }); - }); - }; - - return Deployments; -}; diff --git a/models/deployments_history.js b/models/deployments_history.js deleted file mode 100644 index 18a1bcd4..00000000 --- a/models/deployments_history.js +++ /dev/null @@ -1,21 +0,0 @@ -"use strict"; -module.exports = function(sequelize, DataTypes) { - var DeploymentsHistory = sequelize.define("DeploymentsHistory", { - id: { - type: DataTypes.INTEGER(10), - allowNull: false, - autoIncrement: true, - primaryKey: true - }, - deployment_id: DataTypes.INTEGER(10), - package_id: DataTypes.INTEGER(10), - created_at: DataTypes.DATE - }, { - tableName: 'deployments_history', - underscored: true, - updatedAt: false, - paranoid: true - }); - - return DeploymentsHistory; -}; diff --git a/models/deployments_versions.js b/models/deployments_versions.js deleted file mode 100644 index 41105ec8..00000000 --- a/models/deployments_versions.js +++ /dev/null @@ -1,25 +0,0 @@ -"use strict"; - -module.exports = function(sequelize, DataTypes) { - var DeploymentsVersions = sequelize.define("DeploymentsVersions", { - id: { - type: DataTypes.INTEGER(10), - allowNull: false, - autoIncrement: true, - primaryKey: true - }, - deployment_id: DataTypes.INTEGER(10), - app_version: DataTypes.STRING, - current_package_id: DataTypes.INTEGER(10), - min_version: DataTypes.BIGINT(20), - max_version: DataTypes.BIGINT(20), - created_at: DataTypes.DATE, - updated_at: DataTypes.DATE, - }, { - tableName: 'deployments_versions', - underscored: true, - paranoid: true - }); - - return DeploymentsVersions; -}; diff --git a/models/index.js b/models/index.js deleted file mode 100644 index aa789b5d..00000000 --- a/models/index.js +++ /dev/null @@ -1,32 +0,0 @@ -'use strict'; - -var fs = require('fs'); -var path = require('path'); -var Sequelize = require('sequelize'); -var basename = path.basename(module.filename); -var _ = require('lodash'); -var config = _.get(require(__dirname + '/../core/config'), 'db', {}); -var db = {}; - -var sequelize = new Sequelize(config.database, config.username, config.password, config); - -fs - .readdirSync(__dirname) - .filter(function(file) { - return (file.indexOf('.') !== 0) && (file !== basename) && (file.slice(-3) === '.js'); - }) - .forEach(function(file) { - var model = sequelize['import'](path.join(__dirname, file)); - db[model.name] = model; - }); - -Object.keys(db).forEach(function(modelName) { - if (db[modelName].associate) { - db[modelName].associate(db); - } -}); - -db.sequelize = sequelize; -db.Sequelize = Sequelize; - -module.exports = db; diff --git a/models/log_report_deploy.js b/models/log_report_deploy.js deleted file mode 100644 index f8c39d5e..00000000 --- a/models/log_report_deploy.js +++ /dev/null @@ -1,24 +0,0 @@ -"use strict"; - -module.exports = function(sequelize, DataTypes) { - var LogReportDeploy = sequelize.define("LogReportDeploy", { - id: { - type: DataTypes.BIGINT(20), - allowNull: false, - autoIncrement: true, - primaryKey: true - }, - status: DataTypes.INTEGER(3), - package_id : DataTypes.INTEGER(10), - client_unique_id : DataTypes.STRING, - previous_label : DataTypes.STRING, - previous_deployment_key : DataTypes.STRING, - created_at: DataTypes.DATE, - }, { - tableName: 'log_report_deploy', - underscored: true, - updatedAt: false, - paranoid: true - }); - return LogReportDeploy; -}; diff --git a/models/log_report_download.js b/models/log_report_download.js deleted file mode 100644 index 62966cf9..00000000 --- a/models/log_report_download.js +++ /dev/null @@ -1,21 +0,0 @@ -"use strict"; - -module.exports = function(sequelize, DataTypes) { - var LogReportDownload = sequelize.define("LogReportDownload", { - id: { - type: DataTypes.BIGINT(20), - allowNull: false, - autoIncrement: true, - primaryKey: true - }, - package_id : DataTypes.INTEGER(10), - client_unique_id : DataTypes.STRING, - created_at: DataTypes.DATE, - }, { - tableName: 'log_report_download', - underscored: true, - updatedAt: false, - paranoid: true - }); - return LogReportDownload; -}; diff --git a/models/packages.js b/models/packages.js deleted file mode 100644 index 989eb32a..00000000 --- a/models/packages.js +++ /dev/null @@ -1,35 +0,0 @@ -"use strict"; - -module.exports = function(sequelize, DataTypes) { - var Packages = sequelize.define("Packages", { - id: { - type: DataTypes.INTEGER(10), - allowNull: false, - autoIncrement: true, - primaryKey: true - }, - deployment_version_id: DataTypes.INTEGER(10), - deployment_id: DataTypes.INTEGER(10), - description: DataTypes.STRING, - package_hash: DataTypes.STRING, - blob_url: DataTypes.STRING, - size: DataTypes.INTEGER(10), - manifest_blob_url: DataTypes.STRING, - release_method: DataTypes.STRING, - label: DataTypes.STRING, - original_label: DataTypes.STRING, - original_deployment: DataTypes.STRING, - released_by: DataTypes.STRING, - is_mandatory: DataTypes.INTEGER(3), - is_disabled: DataTypes.INTEGER(3), - rollout: DataTypes.INTEGER(3), - created_at: DataTypes.DATE, - updated_at: DataTypes.DATE, - }, { - tableName: 'packages', - underscored: true, - paranoid: true - }); - - return Packages; -}; diff --git a/models/packages_diff.js b/models/packages_diff.js deleted file mode 100644 index 869a320b..00000000 --- a/models/packages_diff.js +++ /dev/null @@ -1,24 +0,0 @@ -"use strict"; - -module.exports = function(sequelize, DataTypes) { - var PackagesDiff = sequelize.define("PackagesDiff", { - id: { - type: DataTypes.INTEGER(10), - allowNull: false, - autoIncrement: true, - primaryKey: true - }, - package_id: DataTypes.INTEGER(10), - diff_against_package_hash: DataTypes.STRING, - diff_blob_url: DataTypes.STRING, - diff_size: DataTypes.INTEGER(10), - created_at: DataTypes.DATE, - updated_at: DataTypes.DATE, - }, { - tableName: 'packages_diff', - underscored: true, - paranoid: true - }); - - return PackagesDiff; -}; diff --git a/models/packages_metrics.js b/models/packages_metrics.js deleted file mode 100644 index d95bce92..00000000 --- a/models/packages_metrics.js +++ /dev/null @@ -1,26 +0,0 @@ -"use strict"; - -var _ = require('lodash'); - -module.exports = function(sequelize, DataTypes) { - var PackagesMetrics = sequelize.define("PackagesMetrics", { - id: { - type: DataTypes.INTEGER(10), - allowNull: false, - autoIncrement: true, - primaryKey: true - }, - package_id: DataTypes.INTEGER(10), - active: DataTypes.INTEGER(10), - downloaded: DataTypes.INTEGER(10), - failed: DataTypes.INTEGER(10), - installed: DataTypes.INTEGER(10), - created_at: DataTypes.DATE, - updated_at: DataTypes.DATE, - }, { - tableName: 'packages_metrics', - underscored: true, - paranoid: true - }); - return PackagesMetrics; -}; diff --git a/models/user_tokens.js b/models/user_tokens.js deleted file mode 100644 index e3766670..00000000 --- a/models/user_tokens.js +++ /dev/null @@ -1,27 +0,0 @@ -"use strict"; - -module.exports = function(sequelize, DataTypes) { - var UserTokens = sequelize.define("UserTokens", { - id:{ - type: DataTypes.BIGINT(20), - allowNull: false, - autoIncrement: true, - primaryKey: true - }, - uid: DataTypes.BIGINT(20), - name: DataTypes.STRING, - tokens: DataTypes.STRING, - description: DataTypes.STRING, - is_session: DataTypes.INTEGER(3), - created_by: DataTypes.STRING, - created_at: DataTypes.DATE, - expires_at : DataTypes.DATE - }, { - updatedAt: false, - tableName: 'user_tokens', - underscored: true, - paranoid: true - }); - - return UserTokens; -}; diff --git a/models/users.js b/models/users.js deleted file mode 100644 index 6e253f2f..00000000 --- a/models/users.js +++ /dev/null @@ -1,24 +0,0 @@ -"use strict"; - -module.exports = function(sequelize, DataTypes) { - var Users = sequelize.define("Users", { - id: { - type: DataTypes.BIGINT(20), - allowNull: false, - autoIncrement: true, - primaryKey: true - }, - username: DataTypes.STRING, - password: DataTypes.STRING, - email: DataTypes.STRING, - identical: DataTypes.STRING, - ack_code: DataTypes.STRING, - created_at: DataTypes.DATE, - updated_at: DataTypes.DATE, - }, { - tableName: 'users', - underscored: true - }); - - return Users; -}; diff --git a/models/versions.js b/models/versions.js deleted file mode 100644 index 69279d1d..00000000 --- a/models/versions.js +++ /dev/null @@ -1,20 +0,0 @@ -"use strict"; - -module.exports = function(sequelize, DataTypes) { - var Versions = sequelize.define("Versions", { - id: { - type: DataTypes.INTEGER(10), - allowNull: false, - autoIncrement: true, - primaryKey: true - }, - type: DataTypes.INTEGER, - version: DataTypes.STRING - }, { - tableName: 'versions', - updatedAt: false, - createdAt: false - }); - - return Versions; -}; diff --git a/package-lock.json b/package-lock.json index 79668d14..e0b4832a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,3860 +1,12572 @@ { - "name": "code-push-server", - "version": "0.5.4", - "lockfileVersion": 1, + "name": "@shm-open/code-push-server", + "version": "2.1.6", + "lockfileVersion": 3, "requires": true, - "dependencies": { - "@types/babel-types": { - "version": "7.0.1", - "resolved": "http://registry.npm.taobao.org/@types/babel-types/download/@types/babel-types-7.0.1.tgz", - "integrity": "sha1-FAXlOWloxDAplLAWHOQFtyuHQlc=" - }, - "@types/babylon": { - "version": "6.16.2", - "resolved": "http://registry.npm.taobao.org/@types/babylon/download/@types/babylon-6.16.2.tgz", - "integrity": "sha1-BizmO2k9mvHCRvWu35KLycMFicg=", - "requires": { - "@types/babel-types": "*" + "packages": { + "": { + "name": "@shm-open/code-push-server", + "version": "2.1.6", + "license": "MIT", + "dependencies": { + "@aws-sdk/client-s3": "^3.932.0", + "@aws-sdk/lib-storage": "^3.932.0", + "aliyun-oss-upload-stream": "1.3.0", + "aliyun-sdk": "1.12.4", + "bcryptjs": "2.4.3", + "body-parser": "1.20.0", + "cookie-parser": "1.4.6", + "cos-nodejs-sdk-v5": "2.11.12", + "dotenv": "^17.2.3", + "express": "4.18.1", + "extract-zip": "2.0.1", + "formidable": "2.0.1", + "fs-extra": "10.1.0", + "helmet": "5.1.0", + "i18n": "0.15.0", + "jsonwebtoken": "8.5.1", + "kv-logger": "0.5.3", + "lodash": "4.17.21", + "moment": "2.29.3", + "mysql2": "2.3.3", + "node-fetch": "2.6.7", + "nodemailer": "6.7.7", + "pug": "3.0.2", + "qiniu": "7.7.0", + "rand-token": "1.0.1", + "recursive-readdir": "2.2.2", + "redis": "4.2.0", + "sequelize": "6.21.3", + "slash": "3.0.0", + "validator": "13.7.0", + "yargs": "17.5.1", + "yazl": "2.5.1" + }, + "bin": { + "code-push-server": "bin/www.js", + "code-push-server-db": "bin/db.js" + }, + "devDependencies": { + "@shm-open/eslint-config-bundle": "1.9.13", + "@types/bcryptjs": "2.4.2", + "@types/body-parser": "1.19.2", + "@types/cookie-parser": "1.4.3", + "@types/formidable": "2.0.5", + "@types/fs-extra": "9.0.13", + "@types/i18n": "0.13.4", + "@types/jsonwebtoken": "8.5.9", + "@types/lodash": "4.14.195", + "@types/node-fetch": "2.6.2", + "@types/nodemailer": "6.4.5", + "@types/recursive-readdir": "2.2.1", + "@types/validator": "13.7.10", + "@types/yazl": "2.4.2", + "concurrently": "7.4.0", + "mocha": "10.0.0", + "nyc": "15.1.0", + "should": "13.2.3", + "standard-version": "9.5.0", + "supertest": "6.2.4", + "supervisor": "0.12.0", + "typescript": "4.9.5" + }, + "engines": { + "node": "24.6.0", + "npm": "11.5.1" } }, - "@types/geojson": { - "version": "1.0.6", - "resolved": "http://registry.npm.taobao.org/@types/geojson/download/@types/geojson-1.0.6.tgz", - "integrity": "sha1-PgKXJyjGkkjCrwjWCkjLuGgP/98=" + "node_modules/@ampproject/remapping": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.1.2.tgz", + "integrity": "sha512-hoyByceqwKirw7w3Z7gnIIZC3Wx3J484Y3L/cMpXFbr7d9ZQj2mODrirNzcJa+SM3UlpWXYvKV4RlRpFXlWgXg==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.0" + }, + "engines": { + "node": ">=6.0.0" + } }, - "@types/node": { - "version": "9.4.7", - "resolved": "http://registry.npm.taobao.org/@types/node/download/@types/node-9.4.7.tgz", - "integrity": "sha1-V9gc2YcZ3yyd4Rjy1fOxEg3NcnU=" + "node_modules/@aws-crypto/crc32": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/crc32/-/crc32-5.2.0.tgz", + "integrity": "sha512-nLbCWqQNgUiwwtFsen1AdzAtvuLRsQS8rYgMuxCrdKf9kOssamGLuPwyTY9wyYblNr9+1XM8v6zoDTPPSIeANg==", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/util": "^5.2.0", + "@aws-sdk/types": "^3.222.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } }, - "abbrev": { - "version": "1.1.1", - "resolved": "http://registry.npm.taobao.org/abbrev/download/abbrev-1.1.1.tgz", - "integrity": "sha1-+PLIh60Qv2f2NPAFtph/7TF5qsg=" + "node_modules/@aws-crypto/crc32c": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/crc32c/-/crc32c-5.2.0.tgz", + "integrity": "sha512-+iWb8qaHLYKrNvGRbiYRHSdKRWhto5XlZUEBwDjYNf+ly5SVYG6zEoYIdxvf5R3zyeP16w4PLBn3rH1xc74Rag==", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/util": "^5.2.0", + "@aws-sdk/types": "^3.222.0", + "tslib": "^2.6.2" + } }, - "accepts": { - "version": "1.3.5", - "resolved": "http://registry.npm.taobao.org/accepts/download/accepts-1.3.5.tgz", - "integrity": "sha1-63d99gEXI6OxTopywIBcjoZ0a9I=", - "requires": { - "mime-types": "~2.1.18", - "negotiator": "0.6.1" + "node_modules/@aws-crypto/sha1-browser": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/sha1-browser/-/sha1-browser-5.2.0.tgz", + "integrity": "sha512-OH6lveCFfcDjX4dbAvCFSYUjJZjDr/3XJ3xHtjn3Oj5b9RjojQo8npoLeA/bNwkOkrSQ0wgrHzXk4tDRxGKJeg==", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/supports-web-crypto": "^5.2.0", + "@aws-crypto/util": "^5.2.0", + "@aws-sdk/types": "^3.222.0", + "@aws-sdk/util-locate-window": "^3.0.0", + "@smithy/util-utf8": "^2.0.0", + "tslib": "^2.6.2" } }, - "acorn": { - "version": "3.3.0", - "resolved": "http://registry.npm.taobao.org/acorn/download/acorn-3.3.0.tgz", - "integrity": "sha1-ReN/s56No/JbruP/U2niu18iAXo=" + "node_modules/@aws-crypto/sha1-browser/node_modules/@smithy/is-array-buffer": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-2.2.0.tgz", + "integrity": "sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } }, - "acorn-globals": { - "version": "3.1.0", - "resolved": "http://registry.npm.taobao.org/acorn-globals/download/acorn-globals-3.1.0.tgz", - "integrity": "sha1-/YJw9x+7SZawBPqIDuXUZXOnMb8=", - "requires": { - "acorn": "^4.0.4" + "node_modules/@aws-crypto/sha1-browser/node_modules/@smithy/util-buffer-from": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-2.2.0.tgz", + "integrity": "sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/is-array-buffer": "^2.2.0", + "tslib": "^2.6.2" }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-crypto/sha1-browser/node_modules/@smithy/util-utf8": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-2.3.0.tgz", + "integrity": "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==", + "license": "Apache-2.0", "dependencies": { - "acorn": { - "version": "4.0.13", - "resolved": "http://registry.npm.taobao.org/acorn/download/acorn-4.0.13.tgz", - "integrity": "sha1-EFSVrlNh1pe9GVyCUZLhrX8lN4c=" - } + "@smithy/util-buffer-from": "^2.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" } }, - "address": { - "version": "1.0.3", - "resolved": "http://registry.npm.taobao.org/address/download/address-1.0.3.tgz", - "integrity": "sha1-tfUGMfjWzsi9IMljljr7VeBsvOk=" + "node_modules/@aws-crypto/sha256-browser": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-browser/-/sha256-browser-5.2.0.tgz", + "integrity": "sha512-AXfN/lGotSQwu6HNcEsIASo7kWXZ5HYWvfOmSNKDsEqC4OashTp8alTmaz+F7TC2L083SFv5RdB+qU3Vs1kZqw==", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/sha256-js": "^5.2.0", + "@aws-crypto/supports-web-crypto": "^5.2.0", + "@aws-crypto/util": "^5.2.0", + "@aws-sdk/types": "^3.222.0", + "@aws-sdk/util-locate-window": "^3.0.0", + "@smithy/util-utf8": "^2.0.0", + "tslib": "^2.6.2" + } }, - "agentkeepalive": { - "version": "3.3.0", - "resolved": "http://registry.npm.taobao.org/agentkeepalive/download/agentkeepalive-3.3.0.tgz", - "integrity": "sha1-bV3lgpr9O+JxIgGjknX9EcZRhXw=", - "requires": { - "humanize-ms": "^1.2.1" + "node_modules/@aws-crypto/sha256-browser/node_modules/@smithy/is-array-buffer": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-2.2.0.tgz", + "integrity": "sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" } }, - "ajv": { - "version": "5.5.2", - "resolved": "http://registry.npm.taobao.org/ajv/download/ajv-5.5.2.tgz", - "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=", - "requires": { - "co": "^4.6.0", - "fast-deep-equal": "^1.0.0", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.3.0" + "node_modules/@aws-crypto/sha256-browser/node_modules/@smithy/util-buffer-from": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-2.2.0.tgz", + "integrity": "sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/is-array-buffer": "^2.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" } }, - "align-text": { - "version": "0.1.4", - "resolved": "http://registry.npm.taobao.org/align-text/download/align-text-0.1.4.tgz", - "integrity": "sha1-DNkKVhCT810KmSVsIrcGlDP60Rc=", - "requires": { - "kind-of": "^3.0.2", - "longest": "^1.0.1", - "repeat-string": "^1.5.2" + "node_modules/@aws-crypto/sha256-browser/node_modules/@smithy/util-utf8": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-2.3.0.tgz", + "integrity": "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/util-buffer-from": "^2.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" } }, - "aliyun-oss-upload-stream": { - "version": "1.3.0", - "resolved": "http://registry.npm.taobao.org/aliyun-oss-upload-stream/download/aliyun-oss-upload-stream-1.3.0.tgz", - "integrity": "sha1-ODAbGfA0QGhDjrY5d6DNldYEcMA=" + "node_modules/@aws-crypto/sha256-js": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-js/-/sha256-js-5.2.0.tgz", + "integrity": "sha512-FFQQyu7edu4ufvIZ+OadFpHHOt+eSTBaYaki44c+akjg7qZg9oOQeLlk77F6tSYqjDAFClrHJk9tMf0HdVyOvA==", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/util": "^5.2.0", + "@aws-sdk/types": "^3.222.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } }, - "aliyun-sdk": { - "version": "1.11.10", - "resolved": "http://registry.npm.taobao.org/aliyun-sdk/download/aliyun-sdk-1.11.10.tgz", - "integrity": "sha1-ZDvH+GDrv08F7mmfoGp05eQR8lA=", - "requires": { - "node_memcached": "1.1.3", - "pomelo-protobuf": "^0.4.0", - "protobufjs": "^4.1.2", - "xml2js": "0.4.4", - "xmlbuilder": "^2.4.5" + "node_modules/@aws-crypto/supports-web-crypto": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/supports-web-crypto/-/supports-web-crypto-5.2.0.tgz", + "integrity": "sha512-iAvUotm021kM33eCdNfwIN//F77/IADDSs58i+MDaOqFrVjZo9bAal0NK7HurRuWLLpF1iLX7gbWrjHjeo+YFg==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" } }, - "ambi": { - "version": "2.5.0", - "resolved": "http://registry.npm.taobao.org/ambi/download/ambi-2.5.0.tgz", - "integrity": "sha1-fI43K+SIkRV+fOoBy2+RQ9H3QiA=", - "requires": { - "editions": "^1.1.1", - "typechecker": "^4.3.0" - }, - "dependencies": { - "typechecker": { - "version": "4.5.0", - "resolved": "http://registry.npm.taobao.org/typechecker/download/typechecker-4.5.0.tgz", - "integrity": "sha1-w4KSAJeBI2S7r0WVsKtliCRBF6Y=", - "requires": { - "editions": "^1.3.4" - } - } + "node_modules/@aws-crypto/util": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/util/-/util-5.2.0.tgz", + "integrity": "sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "^3.222.0", + "@smithy/util-utf8": "^2.0.0", + "tslib": "^2.6.2" } }, - "amdefine": { - "version": "1.0.1", - "resolved": "http://registry.npm.taobao.org/amdefine/download/amdefine-1.0.1.tgz", - "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=" + "node_modules/@aws-crypto/util/node_modules/@smithy/is-array-buffer": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-2.2.0.tgz", + "integrity": "sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } }, - "ansi-regex": { - "version": "2.1.1", - "resolved": "http://registry.npm.taobao.org/ansi-regex/download/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" + "node_modules/@aws-crypto/util/node_modules/@smithy/util-buffer-from": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-2.2.0.tgz", + "integrity": "sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/is-array-buffer": "^2.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } }, - "ansicolors": { - "version": "0.2.1", - "resolved": "http://registry.npm.taobao.org/ansicolors/download/ansicolors-0.2.1.tgz", - "integrity": "sha1-vgiVmQl7dKXJxKhKDNvNtivYeu8=" + "node_modules/@aws-crypto/util/node_modules/@smithy/util-utf8": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-2.3.0.tgz", + "integrity": "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/util-buffer-from": "^2.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } }, - "any-promise": { - "version": "1.3.0", - "resolved": "http://registry.npm.taobao.org/any-promise/download/any-promise-1.3.0.tgz", - "integrity": "sha1-q8av7tzqUugJzcA3au0845Y10X8=" + "node_modules/@aws-sdk/client-s3": { + "version": "3.932.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-s3/-/client-s3-3.932.0.tgz", + "integrity": "sha512-qrlbJ3W5QR3Gzz2S+yaItH8ZhX7vaeA4j4fDAi8+0FmsVhXOfBbomWr+JO1wk/YojZMdyLfmfYRHrJvAQsLFVw==", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/sha1-browser": "5.2.0", + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "3.932.0", + "@aws-sdk/credential-provider-node": "3.932.0", + "@aws-sdk/middleware-bucket-endpoint": "3.930.0", + "@aws-sdk/middleware-expect-continue": "3.930.0", + "@aws-sdk/middleware-flexible-checksums": "3.932.0", + "@aws-sdk/middleware-host-header": "3.930.0", + "@aws-sdk/middleware-location-constraint": "3.930.0", + "@aws-sdk/middleware-logger": "3.930.0", + "@aws-sdk/middleware-recursion-detection": "3.930.0", + "@aws-sdk/middleware-sdk-s3": "3.932.0", + "@aws-sdk/middleware-ssec": "3.930.0", + "@aws-sdk/middleware-user-agent": "3.932.0", + "@aws-sdk/region-config-resolver": "3.930.0", + "@aws-sdk/signature-v4-multi-region": "3.932.0", + "@aws-sdk/types": "3.930.0", + "@aws-sdk/util-endpoints": "3.930.0", + "@aws-sdk/util-user-agent-browser": "3.930.0", + "@aws-sdk/util-user-agent-node": "3.932.0", + "@smithy/config-resolver": "^4.4.3", + "@smithy/core": "^3.18.2", + "@smithy/eventstream-serde-browser": "^4.2.5", + "@smithy/eventstream-serde-config-resolver": "^4.3.5", + "@smithy/eventstream-serde-node": "^4.2.5", + "@smithy/fetch-http-handler": "^5.3.6", + "@smithy/hash-blob-browser": "^4.2.6", + "@smithy/hash-node": "^4.2.5", + "@smithy/hash-stream-node": "^4.2.5", + "@smithy/invalid-dependency": "^4.2.5", + "@smithy/md5-js": "^4.2.5", + "@smithy/middleware-content-length": "^4.2.5", + "@smithy/middleware-endpoint": "^4.3.9", + "@smithy/middleware-retry": "^4.4.9", + "@smithy/middleware-serde": "^4.2.5", + "@smithy/middleware-stack": "^4.2.5", + "@smithy/node-config-provider": "^4.3.5", + "@smithy/node-http-handler": "^4.4.5", + "@smithy/protocol-http": "^5.3.5", + "@smithy/smithy-client": "^4.9.5", + "@smithy/types": "^4.9.0", + "@smithy/url-parser": "^4.2.5", + "@smithy/util-base64": "^4.3.0", + "@smithy/util-body-length-browser": "^4.2.0", + "@smithy/util-body-length-node": "^4.2.1", + "@smithy/util-defaults-mode-browser": "^4.3.8", + "@smithy/util-defaults-mode-node": "^4.2.11", + "@smithy/util-endpoints": "^3.2.5", + "@smithy/util-middleware": "^4.2.5", + "@smithy/util-retry": "^4.2.5", + "@smithy/util-stream": "^4.5.6", + "@smithy/util-utf8": "^4.2.0", + "@smithy/util-waiter": "^4.2.5", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } }, - "argparse": { - "version": "1.0.10", - "resolved": "http://registry.npm.taobao.org/argparse/download/argparse-1.0.10.tgz", - "integrity": "sha1-vNZ5HqWuCXJeF+WtmIE0zUCz2RE=", - "requires": { - "sprintf-js": "~1.0.2" + "node_modules/@aws-sdk/client-sso": { + "version": "3.932.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.932.0.tgz", + "integrity": "sha512-XHqHa5iv2OQsKoM2tUQXs7EAyryploC00Wg0XSFra/KAKqyGizUb5XxXsGlyqhebB29Wqur+zwiRwNmejmN0+Q==", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "3.932.0", + "@aws-sdk/middleware-host-header": "3.930.0", + "@aws-sdk/middleware-logger": "3.930.0", + "@aws-sdk/middleware-recursion-detection": "3.930.0", + "@aws-sdk/middleware-user-agent": "3.932.0", + "@aws-sdk/region-config-resolver": "3.930.0", + "@aws-sdk/types": "3.930.0", + "@aws-sdk/util-endpoints": "3.930.0", + "@aws-sdk/util-user-agent-browser": "3.930.0", + "@aws-sdk/util-user-agent-node": "3.932.0", + "@smithy/config-resolver": "^4.4.3", + "@smithy/core": "^3.18.2", + "@smithy/fetch-http-handler": "^5.3.6", + "@smithy/hash-node": "^4.2.5", + "@smithy/invalid-dependency": "^4.2.5", + "@smithy/middleware-content-length": "^4.2.5", + "@smithy/middleware-endpoint": "^4.3.9", + "@smithy/middleware-retry": "^4.4.9", + "@smithy/middleware-serde": "^4.2.5", + "@smithy/middleware-stack": "^4.2.5", + "@smithy/node-config-provider": "^4.3.5", + "@smithy/node-http-handler": "^4.4.5", + "@smithy/protocol-http": "^5.3.5", + "@smithy/smithy-client": "^4.9.5", + "@smithy/types": "^4.9.0", + "@smithy/url-parser": "^4.2.5", + "@smithy/util-base64": "^4.3.0", + "@smithy/util-body-length-browser": "^4.2.0", + "@smithy/util-body-length-node": "^4.2.1", + "@smithy/util-defaults-mode-browser": "^4.3.8", + "@smithy/util-defaults-mode-node": "^4.2.11", + "@smithy/util-endpoints": "^3.2.5", + "@smithy/util-middleware": "^4.2.5", + "@smithy/util-retry": "^4.2.5", + "@smithy/util-utf8": "^4.2.0", + "tslib": "^2.6.2" }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/core": { + "version": "3.932.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.932.0.tgz", + "integrity": "sha512-AS8gypYQCbNojwgjvZGkJocC2CoEICDx9ZJ15ILsv+MlcCVLtUJSRSx3VzJOUY2EEIaGLRrPNlIqyn/9/fySvA==", + "license": "Apache-2.0", "dependencies": { - "sprintf-js": { - "version": "1.0.3", - "resolved": "http://registry.npm.taobao.org/sprintf-js/download/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=" - } + "@aws-sdk/types": "3.930.0", + "@aws-sdk/xml-builder": "3.930.0", + "@smithy/core": "^3.18.2", + "@smithy/node-config-provider": "^4.3.5", + "@smithy/property-provider": "^4.2.5", + "@smithy/protocol-http": "^5.3.5", + "@smithy/signature-v4": "^5.3.5", + "@smithy/smithy-client": "^4.9.5", + "@smithy/types": "^4.9.0", + "@smithy/util-base64": "^4.3.0", + "@smithy/util-middleware": "^4.2.5", + "@smithy/util-utf8": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" } }, - "array-flatten": { - "version": "1.1.1", - "resolved": "http://registry.npm.taobao.org/array-flatten/download/array-flatten-1.1.1.tgz", - "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" + "node_modules/@aws-sdk/credential-provider-env": { + "version": "3.932.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.932.0.tgz", + "integrity": "sha512-ozge/c7NdHUDyHqro6+P5oHt8wfKSUBN+olttiVfBe9Mw3wBMpPa3gQ0pZnG+gwBkKskBuip2bMR16tqYvUSEA==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "3.932.0", + "@aws-sdk/types": "3.930.0", + "@smithy/property-provider": "^4.2.5", + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } }, - "asap": { - "version": "2.0.6", - "resolved": "http://registry.npm.taobao.org/asap/download/asap-2.0.6.tgz", - "integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=" + "node_modules/@aws-sdk/credential-provider-http": { + "version": "3.932.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.932.0.tgz", + "integrity": "sha512-b6N9Nnlg8JInQwzBkUq5spNaXssM3h3zLxGzpPrnw0nHSIWPJPTbZzA5Ca285fcDUFuKP+qf3qkuqlAjGOdWhg==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "3.932.0", + "@aws-sdk/types": "3.930.0", + "@smithy/fetch-http-handler": "^5.3.6", + "@smithy/node-http-handler": "^4.4.5", + "@smithy/property-provider": "^4.2.5", + "@smithy/protocol-http": "^5.3.5", + "@smithy/smithy-client": "^4.9.5", + "@smithy/types": "^4.9.0", + "@smithy/util-stream": "^4.5.6", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } }, - "ascli": { - "version": "1.0.1", - "resolved": "http://registry.npm.taobao.org/ascli/download/ascli-1.0.1.tgz", - "integrity": "sha1-vPpZdKYvGOgcq660lzKrSoj5Brw=", - "requires": { - "colour": "~0.7.1", - "optjs": "~3.2.2" + "node_modules/@aws-sdk/credential-provider-ini": { + "version": "3.932.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.932.0.tgz", + "integrity": "sha512-ZBjSAXVGy7danZRHCRMJQ7sBkG1Dz39thYlvTiUaf9BKZ+8ymeiFhuTeV1OkWUBBnY0ki2dVZJvboTqfINhNxA==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "3.932.0", + "@aws-sdk/credential-provider-env": "3.932.0", + "@aws-sdk/credential-provider-http": "3.932.0", + "@aws-sdk/credential-provider-process": "3.932.0", + "@aws-sdk/credential-provider-sso": "3.932.0", + "@aws-sdk/credential-provider-web-identity": "3.932.0", + "@aws-sdk/nested-clients": "3.932.0", + "@aws-sdk/types": "3.930.0", + "@smithy/credential-provider-imds": "^4.2.5", + "@smithy/property-provider": "^4.2.5", + "@smithy/shared-ini-file-loader": "^4.4.0", + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" } }, - "asn1": { - "version": "0.2.3", - "resolved": "http://registry.npm.taobao.org/asn1/download/asn1-0.2.3.tgz", - "integrity": "sha1-2sh4dxPJlmhJ/IGAd36+nB3fO4Y=" + "node_modules/@aws-sdk/credential-provider-node": { + "version": "3.932.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.932.0.tgz", + "integrity": "sha512-SEG9t2taBT86qe3gTunfrK8BxT710GVLGepvHr+X5Pw+qW225iNRaGN0zJH+ZE/j91tcW9wOaIoWnURkhR5wIg==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/credential-provider-env": "3.932.0", + "@aws-sdk/credential-provider-http": "3.932.0", + "@aws-sdk/credential-provider-ini": "3.932.0", + "@aws-sdk/credential-provider-process": "3.932.0", + "@aws-sdk/credential-provider-sso": "3.932.0", + "@aws-sdk/credential-provider-web-identity": "3.932.0", + "@aws-sdk/types": "3.930.0", + "@smithy/credential-provider-imds": "^4.2.5", + "@smithy/property-provider": "^4.2.5", + "@smithy/shared-ini-file-loader": "^4.4.0", + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } }, - "assert-plus": { - "version": "1.0.0", - "resolved": "http://registry.npm.taobao.org/assert-plus/download/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" + "node_modules/@aws-sdk/credential-provider-process": { + "version": "3.932.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.932.0.tgz", + "integrity": "sha512-BodZYKvT4p/Dkm28Ql/FhDdS1+p51bcZeMMu2TRtU8PoMDHnVDhHz27zASEKSZwmhvquxHrZHB0IGuVqjZUtSQ==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "3.932.0", + "@aws-sdk/types": "3.930.0", + "@smithy/property-provider": "^4.2.5", + "@smithy/shared-ini-file-loader": "^4.4.0", + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } }, - "async": { - "version": "1.5.2", - "resolved": "http://registry.npm.taobao.org/async/download/async-1.5.2.tgz", - "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=" + "node_modules/@aws-sdk/credential-provider-sso": { + "version": "3.932.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.932.0.tgz", + "integrity": "sha512-XYmkv+ltBjjmPZ6AmR1ZQZkQfD0uzG61M18/Lif3HAGxyg3dmod0aWx9aL6lj9SvxAGqzscrx5j4PkgLqjZruw==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/client-sso": "3.932.0", + "@aws-sdk/core": "3.932.0", + "@aws-sdk/token-providers": "3.932.0", + "@aws-sdk/types": "3.930.0", + "@smithy/property-provider": "^4.2.5", + "@smithy/shared-ini-file-loader": "^4.4.0", + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } }, - "asynckit": { - "version": "0.4.0", - "resolved": "http://registry.npm.taobao.org/asynckit/download/asynckit-0.4.0.tgz", - "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" + "node_modules/@aws-sdk/credential-provider-web-identity": { + "version": "3.932.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.932.0.tgz", + "integrity": "sha512-Yw/hYNnC1KHuVIQF9PkLXbuKN7ljx70OSbJYDRufllQvej3kRwNcqQSnzI1M4KaObccqKaE6srg22DqpPy9p8w==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "3.932.0", + "@aws-sdk/nested-clients": "3.932.0", + "@aws-sdk/types": "3.930.0", + "@smithy/property-provider": "^4.2.5", + "@smithy/shared-ini-file-loader": "^4.4.0", + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } }, - "aws-sdk": { - "version": "2.211.0", - "resolved": "http://registry.npm.taobao.org/aws-sdk/download/aws-sdk-2.211.0.tgz", - "integrity": "sha1-kCt1Jedv+fpyzQOLc7ikfIxnGmI=", - "requires": { - "buffer": "4.9.1", - "events": "^1.1.1", - "jmespath": "0.15.0", - "querystring": "0.2.0", - "sax": "1.2.1", - "url": "0.10.3", - "uuid": "3.1.0", - "xml2js": "0.4.17", - "xmlbuilder": "4.2.1" - }, - "dependencies": { - "sax": { - "version": "1.2.1", - "resolved": "http://registry.npm.taobao.org/sax/download/sax-1.2.1.tgz", - "integrity": "sha1-e45lYZCyKOgaZq6nSEgNgozS03o=" - }, - "xml2js": { - "version": "0.4.17", - "resolved": "http://registry.npm.taobao.org/xml2js/download/xml2js-0.4.17.tgz", - "integrity": "sha1-F76T6q4/O3eTWceVtBlwWogX6Gg=", - "requires": { - "sax": ">=0.6.0", - "xmlbuilder": "^4.1.0" - } - }, - "xmlbuilder": { - "version": "4.2.1", - "resolved": "http://registry.npm.taobao.org/xmlbuilder/download/xmlbuilder-4.2.1.tgz", - "integrity": "sha1-qlijBBoGb5DqoWwvU4n/GfP0YaU=", - "requires": { - "lodash": "^4.0.0" - } - } + "node_modules/@aws-sdk/lib-storage": { + "version": "3.932.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/lib-storage/-/lib-storage-3.932.0.tgz", + "integrity": "sha512-1HvVTtZQiFfPsvo/vGC15AQFFTJDlwQpKzNL3I8nfR4jDoJiJZ9IS+X0Z9YumZPYL4ZjvvhKyx3XesWblfLgQg==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/abort-controller": "^4.2.5", + "@smithy/middleware-endpoint": "^4.3.9", + "@smithy/smithy-client": "^4.9.5", + "buffer": "5.6.0", + "events": "3.3.0", + "stream-browserify": "3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + }, + "peerDependencies": { + "@aws-sdk/client-s3": "^3.932.0" } }, - "aws-sign2": { - "version": "0.7.0", - "resolved": "http://registry.npm.taobao.org/aws-sign2/download/aws-sign2-0.7.0.tgz", - "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=" + "node_modules/@aws-sdk/middleware-bucket-endpoint": { + "version": "3.930.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-bucket-endpoint/-/middleware-bucket-endpoint-3.930.0.tgz", + "integrity": "sha512-cnCLWeKPYgvV4yRYPFH6pWMdUByvu2cy2BAlfsPpvnm4RaVioztyvxmQj5PmVN5fvWs5w/2d6U7le8X9iye2sA==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.930.0", + "@aws-sdk/util-arn-parser": "3.893.0", + "@smithy/node-config-provider": "^4.3.5", + "@smithy/protocol-http": "^5.3.5", + "@smithy/types": "^4.9.0", + "@smithy/util-config-provider": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } }, - "aws4": { - "version": "1.6.0", - "resolved": "http://registry.npm.taobao.org/aws4/download/aws4-1.6.0.tgz", - "integrity": "sha1-g+9cqGCysy5KDe7e6MdxudtXRx4=" + "node_modules/@aws-sdk/middleware-expect-continue": { + "version": "3.930.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-expect-continue/-/middleware-expect-continue-3.930.0.tgz", + "integrity": "sha512-5HEQ+JU4DrLNWeY27wKg/jeVa8Suy62ivJHOSUf6e6hZdVIMx0h/kXS1fHEQNNiLu2IzSEP/bFXsKBaW7x7s0g==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.930.0", + "@smithy/protocol-http": "^5.3.5", + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } }, - "axios": { - "version": "0.18.1", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.18.1.tgz", - "integrity": "sha512-0BfJq4NSfQXd+SkFdrvFbG7addhYSBA2mQwISr46pD6E5iqkWg02RAs8vyTT/j0RTnoYmeXauBuSv1qKwR179g==", - "requires": { - "follow-redirects": "1.5.10", - "is-buffer": "^2.0.2" + "node_modules/@aws-sdk/middleware-flexible-checksums": { + "version": "3.932.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-flexible-checksums/-/middleware-flexible-checksums-3.932.0.tgz", + "integrity": "sha512-hyvRz/XS/0HTHp9/Ld1mKwpOi7bZu5olI42+T112rkCTbt1bewkygzEl4oflY4H7cKMamQusYoL0yBUD/QSEvA==", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/crc32": "5.2.0", + "@aws-crypto/crc32c": "5.2.0", + "@aws-crypto/util": "5.2.0", + "@aws-sdk/core": "3.932.0", + "@aws-sdk/types": "3.930.0", + "@smithy/is-array-buffer": "^4.2.0", + "@smithy/node-config-provider": "^4.3.5", + "@smithy/protocol-http": "^5.3.5", + "@smithy/types": "^4.9.0", + "@smithy/util-middleware": "^4.2.5", + "@smithy/util-stream": "^4.5.6", + "@smithy/util-utf8": "^4.2.0", + "tslib": "^2.6.2" }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/middleware-host-header": { + "version": "3.930.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.930.0.tgz", + "integrity": "sha512-x30jmm3TLu7b/b+67nMyoV0NlbnCVT5DI57yDrhXAPCtdgM1KtdLWt45UcHpKOm1JsaIkmYRh2WYu7Anx4MG0g==", + "license": "Apache-2.0", "dependencies": { - "is-buffer": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.3.tgz", - "integrity": "sha512-U15Q7MXTuZlrbymiz95PJpZxu8IlipAp4dtS3wOdgPXx3mqBnslrWU14kxfHB+Py/+2PVKSr37dMAgM2A4uArw==" - } + "@aws-sdk/types": "3.930.0", + "@smithy/protocol-http": "^5.3.5", + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" } }, - "babel-runtime": { - "version": "6.26.0", - "resolved": "http://registry.npm.taobao.org/babel-runtime/download/babel-runtime-6.26.0.tgz", - "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", - "requires": { - "core-js": "^2.4.0", - "regenerator-runtime": "^0.11.0" + "node_modules/@aws-sdk/middleware-location-constraint": { + "version": "3.930.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-location-constraint/-/middleware-location-constraint-3.930.0.tgz", + "integrity": "sha512-QIGNsNUdRICog+LYqmtJ03PLze6h2KCORXUs5td/hAEjVP5DMmubhtrGg1KhWyctACluUH/E/yrD14p4pRXxwA==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.930.0", + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" } }, - "babel-types": { - "version": "6.26.0", - "resolved": "http://registry.npm.taobao.org/babel-types/download/babel-types-6.26.0.tgz", - "integrity": "sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=", - "requires": { - "babel-runtime": "^6.26.0", - "esutils": "^2.0.2", - "lodash": "^4.17.4", - "to-fast-properties": "^1.0.3" + "node_modules/@aws-sdk/middleware-logger": { + "version": "3.930.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.930.0.tgz", + "integrity": "sha512-vh4JBWzMCBW8wREvAwoSqB2geKsZwSHTa0nSt0OMOLp2PdTYIZDi0ZiVMmpfnjcx9XbS6aSluLv9sKx4RrG46A==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.930.0", + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" } }, - "babylon": { - "version": "6.18.0", - "resolved": "http://registry.npm.taobao.org/babylon/download/babylon-6.18.0.tgz", - "integrity": "sha1-ry87iPpvXB5MY00aD46sT1WzleM=" + "node_modules/@aws-sdk/middleware-recursion-detection": { + "version": "3.930.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.930.0.tgz", + "integrity": "sha512-gv0sekNpa2MBsIhm2cjP3nmYSfI4nscx/+K9u9ybrWZBWUIC4kL2sV++bFjjUz4QxUIlvKByow3/a9ARQyCu7Q==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.930.0", + "@aws/lambda-invoke-store": "^0.1.1", + "@smithy/protocol-http": "^5.3.5", + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } }, - "balanced-match": { - "version": "1.0.0", - "resolved": "http://registry.npm.taobao.org/balanced-match/download/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" + "node_modules/@aws-sdk/middleware-sdk-s3": { + "version": "3.932.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-sdk-s3/-/middleware-sdk-s3-3.932.0.tgz", + "integrity": "sha512-bYMHxqQzseaAP9Z5qLI918z5AtbAnZRRtFi3POb4FLZyreBMgCgBNaPkIhdgywnkqaydTWvbMBX4s9f4gUwlTw==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "3.932.0", + "@aws-sdk/types": "3.930.0", + "@aws-sdk/util-arn-parser": "3.893.0", + "@smithy/core": "^3.18.2", + "@smithy/node-config-provider": "^4.3.5", + "@smithy/protocol-http": "^5.3.5", + "@smithy/signature-v4": "^5.3.5", + "@smithy/smithy-client": "^4.9.5", + "@smithy/types": "^4.9.0", + "@smithy/util-config-provider": "^4.2.0", + "@smithy/util-middleware": "^4.2.5", + "@smithy/util-stream": "^4.5.6", + "@smithy/util-utf8": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } }, - "base-64": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/base-64/-/base-64-0.1.0.tgz", - "integrity": "sha1-eAqZyE59YAJgNhURxId2E78k9rs=" + "node_modules/@aws-sdk/middleware-ssec": { + "version": "3.930.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-ssec/-/middleware-ssec-3.930.0.tgz", + "integrity": "sha512-N2/SvodmaDS6h7CWfuapt3oJyn1T2CBz0CsDIiTDv9cSagXAVFjPdm2g4PFJqrNBeqdDIoYBnnta336HmamWHg==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.930.0", + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } }, - "base64-js": { - "version": "1.2.3", - "resolved": "http://registry.npm.taobao.org/base64-js/download/base64-js-1.2.3.tgz", - "integrity": "sha1-+xNmgjPZYUz1+0vOlam6QJbN+AE=" + "node_modules/@aws-sdk/middleware-user-agent": { + "version": "3.932.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.932.0.tgz", + "integrity": "sha512-9BGTbJyA/4PTdwQWE9hAFIJGpsYkyEW20WON3i15aDqo5oRZwZmqaVageOD57YYqG8JDJjvcwKyDdR4cc38dvg==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "3.932.0", + "@aws-sdk/types": "3.930.0", + "@aws-sdk/util-endpoints": "3.930.0", + "@smithy/core": "^3.18.2", + "@smithy/protocol-http": "^5.3.5", + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } }, - "base64url": { - "version": "2.0.0", - "resolved": "http://registry.npm.taobao.org/base64url/download/base64url-2.0.0.tgz", - "integrity": "sha1-6sFuA+oUOO/5Qj1puqNiYu0fcLs=" + "node_modules/@aws-sdk/nested-clients": { + "version": "3.932.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/nested-clients/-/nested-clients-3.932.0.tgz", + "integrity": "sha512-E2ucBfiXSpxZflHTf3UFbVwao4+7v7ctAeg8SWuglc1UMqMlpwMFFgWiSONtsf0SR3+ZDoWGATyCXOfDWerJuw==", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "3.932.0", + "@aws-sdk/middleware-host-header": "3.930.0", + "@aws-sdk/middleware-logger": "3.930.0", + "@aws-sdk/middleware-recursion-detection": "3.930.0", + "@aws-sdk/middleware-user-agent": "3.932.0", + "@aws-sdk/region-config-resolver": "3.930.0", + "@aws-sdk/types": "3.930.0", + "@aws-sdk/util-endpoints": "3.930.0", + "@aws-sdk/util-user-agent-browser": "3.930.0", + "@aws-sdk/util-user-agent-node": "3.932.0", + "@smithy/config-resolver": "^4.4.3", + "@smithy/core": "^3.18.2", + "@smithy/fetch-http-handler": "^5.3.6", + "@smithy/hash-node": "^4.2.5", + "@smithy/invalid-dependency": "^4.2.5", + "@smithy/middleware-content-length": "^4.2.5", + "@smithy/middleware-endpoint": "^4.3.9", + "@smithy/middleware-retry": "^4.4.9", + "@smithy/middleware-serde": "^4.2.5", + "@smithy/middleware-stack": "^4.2.5", + "@smithy/node-config-provider": "^4.3.5", + "@smithy/node-http-handler": "^4.4.5", + "@smithy/protocol-http": "^5.3.5", + "@smithy/smithy-client": "^4.9.5", + "@smithy/types": "^4.9.0", + "@smithy/url-parser": "^4.2.5", + "@smithy/util-base64": "^4.3.0", + "@smithy/util-body-length-browser": "^4.2.0", + "@smithy/util-body-length-node": "^4.2.1", + "@smithy/util-defaults-mode-browser": "^4.3.8", + "@smithy/util-defaults-mode-node": "^4.2.11", + "@smithy/util-endpoints": "^3.2.5", + "@smithy/util-middleware": "^4.2.5", + "@smithy/util-retry": "^4.2.5", + "@smithy/util-utf8": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } }, - "basic-auth": { - "version": "2.0.0", - "resolved": "http://registry.npm.taobao.org/basic-auth/download/basic-auth-2.0.0.tgz", - "integrity": "sha1-AV2z81PgLlY3d1X5YnQuiYHnu7o=", - "requires": { - "safe-buffer": "5.1.1" + "node_modules/@aws-sdk/region-config-resolver": { + "version": "3.930.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/region-config-resolver/-/region-config-resolver-3.930.0.tgz", + "integrity": "sha512-KL2JZqH6aYeQssu1g1KuWsReupdfOoxD6f1as2VC+rdwYFUu4LfzMsFfXnBvvQWWqQ7rZHWOw1T+o5gJmg7Dzw==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.930.0", + "@smithy/config-resolver": "^4.4.3", + "@smithy/node-config-provider": "^4.3.5", + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" } }, - "bcrypt-pbkdf": { - "version": "1.0.1", - "resolved": "http://registry.npm.taobao.org/bcrypt-pbkdf/download/bcrypt-pbkdf-1.0.1.tgz", - "integrity": "sha1-Y7xdy2EzG5K8Bf1SiVPDNGKgb40=", - "optional": true, - "requires": { - "tweetnacl": "^0.14.3" + "node_modules/@aws-sdk/signature-v4-multi-region": { + "version": "3.932.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/signature-v4-multi-region/-/signature-v4-multi-region-3.932.0.tgz", + "integrity": "sha512-NCIRJvoRc9246RZHIusY1+n/neeG2yGhBGdKhghmrNdM+mLLN6Ii7CKFZjx3DhxtpHMpl1HWLTMhdVrGwP2upw==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/middleware-sdk-s3": "3.932.0", + "@aws-sdk/types": "3.930.0", + "@smithy/protocol-http": "^5.3.5", + "@smithy/signature-v4": "^5.3.5", + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" } }, - "bcryptjs": { - "version": "2.4.3", - "resolved": "http://registry.npm.taobao.org/bcryptjs/download/bcryptjs-2.4.3.tgz", - "integrity": "sha1-mrVie5PmBiH/fNrF2pczAn3x0Ms=" + "node_modules/@aws-sdk/token-providers": { + "version": "3.932.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.932.0.tgz", + "integrity": "sha512-43u82ulVuHK4zWhcSPyuPS18l0LNHi3QJQ1YtP2MfP8bPf5a6hMYp5e3lUr9oTDEWcpwBYtOW0m1DVmoU/3veA==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "3.932.0", + "@aws-sdk/nested-clients": "3.932.0", + "@aws-sdk/types": "3.930.0", + "@smithy/property-provider": "^4.2.5", + "@smithy/shared-ini-file-loader": "^4.4.0", + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } }, - "bluebird": { - "version": "3.5.1", - "resolved": "http://registry.npm.taobao.org/bluebird/download/bluebird-3.5.1.tgz", - "integrity": "sha1-2VUfnemPH82h5oPRfukaBgLuLrk=" - }, - "body-parser": { - "version": "1.18.2", - "resolved": "http://registry.npm.taobao.org/body-parser/download/body-parser-1.18.2.tgz", - "integrity": "sha1-h2eKGdhLR9hZuDGZvVm84iKxBFQ=", - "requires": { - "bytes": "3.0.0", - "content-type": "~1.0.4", - "debug": "2.6.9", - "depd": "~1.1.1", - "http-errors": "~1.6.2", - "iconv-lite": "0.4.19", - "on-finished": "~2.3.0", - "qs": "6.5.1", - "raw-body": "2.3.2", - "type-is": "~1.6.15" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "http://registry.npm.taobao.org/debug/download/debug-2.6.9.tgz", - "integrity": "sha1-XRKFFd8TT/Mn6QpMk/Tgd6U2NB8=", - "requires": { - "ms": "2.0.0" - } - } + "node_modules/@aws-sdk/types": { + "version": "3.930.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.930.0.tgz", + "integrity": "sha512-we/vaAgwlEFW7IeftmCLlLMw+6hFs3DzZPJw7lVHbj/5HJ0bz9gndxEsS2lQoeJ1zhiiLqAqvXxmM43s0MBg0A==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" } }, - "boom": { - "version": "4.3.1", - "resolved": "http://registry.npm.taobao.org/boom/download/boom-4.3.1.tgz", - "integrity": "sha1-T4owBctKfjiJ90kDD9JbluAdLjE=", - "requires": { - "hoek": "4.x.x" + "node_modules/@aws-sdk/util-arn-parser": { + "version": "3.893.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-arn-parser/-/util-arn-parser-3.893.0.tgz", + "integrity": "sha512-u8H4f2Zsi19DGnwj5FSZzDMhytYF/bCh37vAtBsn3cNDL3YG578X5oc+wSX54pM3tOxS+NY7tvOAo52SW7koUA==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" } }, - "brace-expansion": { - "version": "1.1.11", - "resolved": "http://registry.npm.taobao.org/brace-expansion/download/brace-expansion-1.1.11.tgz", - "integrity": "sha1-PH/L9SnYcibz0vUrlm/1Jx60Qd0=", - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "node_modules/@aws-sdk/util-endpoints": { + "version": "3.930.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.930.0.tgz", + "integrity": "sha512-M2oEKBzzNAYr136RRc6uqw3aWlwCxqTP1Lawps9E1d2abRPvl1p1ztQmmXp1Ak4rv8eByIZ+yQyKQ3zPdRG5dw==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.930.0", + "@smithy/types": "^4.9.0", + "@smithy/url-parser": "^4.2.5", + "@smithy/util-endpoints": "^3.2.5", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" } }, - "browser-stdout": { - "version": "1.3.0", - "resolved": "http://registry.npm.taobao.org/browser-stdout/download/browser-stdout-1.3.0.tgz", - "integrity": "sha1-81HTKWnTL6XXpVZxVCY9korjvR8=", - "dev": true + "node_modules/@aws-sdk/util-locate-window": { + "version": "3.893.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-locate-window/-/util-locate-window-3.893.0.tgz", + "integrity": "sha512-T89pFfgat6c8nMmpI8eKjBcDcgJq36+m9oiXbcUzeU55MP9ZuGgBomGjGnHaEyF36jenW9gmg3NfZDm0AO2XPg==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } }, - "buffer": { - "version": "4.9.1", - "resolved": "http://registry.npm.taobao.org/buffer/download/buffer-4.9.1.tgz", - "integrity": "sha1-bRu2AbB6TvztlwlBMgkwJ8lbwpg=", - "requires": { - "base64-js": "^1.0.2", - "ieee754": "^1.1.4", - "isarray": "^1.0.0" + "node_modules/@aws-sdk/util-user-agent-browser": { + "version": "3.930.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.930.0.tgz", + "integrity": "sha512-q6lCRm6UAe+e1LguM5E4EqM9brQlDem4XDcQ87NzEvlTW6GzmNCO0w1jS0XgCFXQHjDxjdlNFX+5sRbHijwklg==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.930.0", + "@smithy/types": "^4.9.0", + "bowser": "^2.11.0", + "tslib": "^2.6.2" } }, - "buffer-crc32": { - "version": "0.2.13", - "resolved": "http://registry.npm.taobao.org/buffer-crc32/download/buffer-crc32-0.2.13.tgz", - "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=" + "node_modules/@aws-sdk/util-user-agent-node": { + "version": "3.932.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.932.0.tgz", + "integrity": "sha512-/kC6cscHrZL74TrZtgiIL5jJNbVsw9duGGPurmaVgoCbP7NnxyaSWEurbNV3VPNPhNE3bV3g4Ci+odq+AlsYQg==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/middleware-user-agent": "3.932.0", + "@aws-sdk/types": "3.930.0", + "@smithy/node-config-provider": "^4.3.5", + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + }, + "peerDependencies": { + "aws-crt": ">=1.0.0" + }, + "peerDependenciesMeta": { + "aws-crt": { + "optional": true + } + } }, - "buffer-equal-constant-time": { - "version": "1.0.1", - "resolved": "http://registry.npm.taobao.org/buffer-equal-constant-time/download/buffer-equal-constant-time-1.0.1.tgz", - "integrity": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk=" + "node_modules/@aws-sdk/xml-builder": { + "version": "3.930.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/xml-builder/-/xml-builder-3.930.0.tgz", + "integrity": "sha512-YIfkD17GocxdmlUVc3ia52QhcWuRIUJonbF8A2CYfcWNV3HzvAqpcPeC0bYUhkK+8e8YO1ARnLKZQE0TlwzorA==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.9.0", + "fast-xml-parser": "5.2.5", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } }, - "bufferview": { - "version": "1.0.1", - "resolved": "http://registry.npm.taobao.org/bufferview/download/bufferview-1.0.1.tgz", - "integrity": "sha1-ev10pF+Tf6QiodM4wIu/3HbNcl0=" + "node_modules/@aws/lambda-invoke-store": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@aws/lambda-invoke-store/-/lambda-invoke-store-0.1.1.tgz", + "integrity": "sha512-RcLam17LdlbSOSp9VxmUu1eI6Mwxp+OwhD2QhiSNmNCzoDb0EeUXTD2n/WbcnrAYMGlmf05th6QYq23VqvJqpA==", + "license": "Apache-2.0", + "engines": { + "node": ">=18.0.0" + } }, - "bytebuffer": { - "version": "4.1.0", - "resolved": "http://registry.npm.taobao.org/bytebuffer/download/bytebuffer-4.1.0.tgz", - "integrity": "sha1-TFgmngUqseSx9/82T9+zzogpBqo=", - "requires": { - "bufferview": "~1", - "long": "~2 >=2.3.0" + "node_modules/@babel/code-frame": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.7.tgz", + "integrity": "sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg==", + "dev": true, + "dependencies": { + "@babel/highlight": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" } }, - "bytes": { - "version": "3.0.0", - "resolved": "http://registry.npm.taobao.org/bytes/download/bytes-3.0.0.tgz", - "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=" + "node_modules/@babel/compat-data": { + "version": "7.17.0", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.17.0.tgz", + "integrity": "sha512-392byTlpGWXMv4FbyWw3sAZ/FrW/DrwqLGXpy0mbyNe9Taqv1mg9yON5/o0cnr8XYCkFTZbC1eV+c+LAROgrng==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } }, - "camelcase": { - "version": "2.1.1", - "resolved": "http://registry.npm.taobao.org/camelcase/download/camelcase-2.1.1.tgz", - "integrity": "sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8=" + "node_modules/@babel/core": { + "version": "7.17.5", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.17.5.tgz", + "integrity": "sha512-/BBMw4EvjmyquN5O+t5eh0+YqB3XXJkYD2cjKpYtWOfFy4lQ4UozNSmxAcWT8r2XtZs0ewG+zrfsqeR15i1ajA==", + "dev": true, + "dependencies": { + "@ampproject/remapping": "^2.1.0", + "@babel/code-frame": "^7.16.7", + "@babel/generator": "^7.17.3", + "@babel/helper-compilation-targets": "^7.16.7", + "@babel/helper-module-transforms": "^7.16.7", + "@babel/helpers": "^7.17.2", + "@babel/parser": "^7.17.3", + "@babel/template": "^7.16.7", + "@babel/traverse": "^7.17.3", + "@babel/types": "^7.17.0", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.1.2", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } }, - "camelize": { - "version": "1.0.0", - "resolved": "http://registry.npm.taobao.org/camelize/download/camelize-1.0.0.tgz", - "integrity": "sha1-FkpUg+Yw+kMh5a8HAg5TGDGyYJs=" + "node_modules/@babel/core/node_modules/debug": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", + "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } }, - "cardinal": { - "version": "1.0.0", - "resolved": "http://registry.npm.taobao.org/cardinal/download/cardinal-1.0.0.tgz", - "integrity": "sha1-UOIcGwqjdyn5N33vGWtanOyTLuk=", - "requires": { - "ansicolors": "~0.2.1", - "redeyed": "~1.0.0" + "node_modules/@babel/core/node_modules/json5": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz", + "integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==", + "dev": true, + "dependencies": { + "minimist": "^1.2.5" + }, + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" } }, - "caseless": { - "version": "0.12.0", - "resolved": "http://registry.npm.taobao.org/caseless/download/caseless-0.12.0.tgz", - "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" + "node_modules/@babel/core/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true }, - "center-align": { - "version": "0.1.3", - "resolved": "http://registry.npm.taobao.org/center-align/download/center-align-0.1.3.tgz", - "integrity": "sha1-qg0yYptu6XIgBBHL1EYckHvCt60=", - "requires": { - "align-text": "^0.1.3", - "lazy-cache": "^1.0.3" + "node_modules/@babel/core/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" } }, - "character-parser": { - "version": "2.2.0", - "resolved": "http://registry.npm.taobao.org/character-parser/download/character-parser-2.2.0.tgz", - "integrity": "sha1-x84o821LzZdE5f/CxfzeHHMmH8A=", - "requires": { - "is-regex": "^1.0.3" + "node_modules/@babel/generator": { + "version": "7.17.3", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.17.3.tgz", + "integrity": "sha512-+R6Dctil/MgUsZsZAkYgK+ADNSZzJRRy0TvY65T71z/CR854xHQ1EweBYXdfT+HNeN7w0cSJJEzgxZMv40pxsg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.17.0", + "jsesc": "^2.5.1", + "source-map": "^0.5.0" + }, + "engines": { + "node": ">=6.9.0" } }, - "charenc": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/charenc/-/charenc-0.0.2.tgz", - "integrity": "sha1-wKHS86cJLgN3S/qD8UwPxXkKhmc=" - }, - "circular-json": { - "version": "0.5.5", - "resolved": "http://registry.npm.taobao.org/circular-json/download/circular-json-0.5.5.tgz", - "integrity": "sha1-ZBgu81kELTfNjnZ/yd6Hix6UR9M=" - }, - "clean-css": { - "version": "3.4.28", - "resolved": "http://registry.npm.taobao.org/clean-css/download/clean-css-3.4.28.tgz", - "integrity": "sha1-vxlF6C/ICPVWlebd6uwBQA79A/8=", - "requires": { - "commander": "2.8.x", - "source-map": "0.4.x" - }, - "dependencies": { - "commander": { - "version": "2.8.1", - "resolved": "http://registry.npm.taobao.org/commander/download/commander-2.8.1.tgz", - "integrity": "sha1-Br42f+v9oMMwqh4qBy09yXYkJdQ=", - "requires": { - "graceful-readlink": ">= 1.0.0" - } - }, - "source-map": { - "version": "0.4.4", - "resolved": "http://registry.npm.taobao.org/source-map/download/source-map-0.4.4.tgz", - "integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=", - "requires": { - "amdefine": ">=0.0.4" - } - } + "node_modules/@babel/generator/node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true, + "engines": { + "node": ">=0.10.0" } }, - "cliui": { - "version": "3.2.0", - "resolved": "http://registry.npm.taobao.org/cliui/download/cliui-3.2.0.tgz", - "integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=", - "requires": { - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1", - "wrap-ansi": "^2.0.0" + "node_modules/@babel/helper-compilation-targets": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.16.7.tgz", + "integrity": "sha512-mGojBwIWcwGD6rfqgRXVlVYmPAv7eOpIemUG3dGnDdCY4Pae70ROij3XmfrH6Fa1h1aiDylpglbZyktfzyo/hA==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.16.4", + "@babel/helper-validator-option": "^7.16.7", + "browserslist": "^4.17.5", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" } }, - "cls-bluebird": { - "version": "2.1.0", - "resolved": "http://registry.npm.taobao.org/cls-bluebird/download/cls-bluebird-2.1.0.tgz", - "integrity": "sha1-N+8eCAqP+1XC9BZPU28ZGeeWiu4=", - "requires": { - "is-bluebird": "^1.0.2", - "shimmer": "^1.1.0" + "node_modules/@babel/helper-compilation-targets/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" } }, - "co": { - "version": "4.6.0", - "resolved": "http://registry.npm.taobao.org/co/download/co-4.6.0.tgz", - "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=" + "node_modules/@babel/helper-environment-visitor": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.16.7.tgz", + "integrity": "sha512-SLLb0AAn6PkUeAfKJCCOl9e1R53pQlGAfc4y4XuMRZfqeMYLE0dM1LMhqbGAlGQY0lfw5/ohoYWAe9V1yibRag==", + "dev": true, + "dependencies": { + "@babel/types": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + } }, - "code-point-at": { - "version": "1.1.0", - "resolved": "http://registry.npm.taobao.org/code-point-at/download/code-point-at-1.1.0.tgz", - "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=" + "node_modules/@babel/helper-function-name": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.16.7.tgz", + "integrity": "sha512-QfDfEnIUyyBSR3HtrtGECuZ6DAyCkYFp7GHl75vFtTnn6pjKeK0T1DB5lLkFvBea8MdaiUABx3osbgLyInoejA==", + "dev": true, + "dependencies": { + "@babel/helper-get-function-arity": "^7.16.7", + "@babel/template": "^7.16.7", + "@babel/types": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + } }, - "coffee-script": { - "version": "1.12.7", - "resolved": "http://registry.npm.taobao.org/coffee-script/download/coffee-script-1.12.7.tgz", - "integrity": "sha1-wF2uDLeVkdBbMHCoQzqYyaiczFM=" + "node_modules/@babel/helper-get-function-arity": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.16.7.tgz", + "integrity": "sha512-flc+RLSOBXzNzVhcLu6ujeHUrD6tANAOU5ojrRx/as+tbzf8+stUCj7+IfRRoAbEZqj/ahXEMsjhOhgeZsrnTw==", + "dev": true, + "dependencies": { + "@babel/types": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + } }, - "colour": { - "version": "0.7.1", - "resolved": "http://registry.npm.taobao.org/colour/download/colour-0.7.1.tgz", - "integrity": "sha1-nLFpkX7F0SwHNtPoaFdG3xyt93g=" + "node_modules/@babel/helper-hoist-variables": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.16.7.tgz", + "integrity": "sha512-m04d/0Op34H5v7pbZw6pSKP7weA6lsMvfiIAMeIvkY/R4xQtBSMFEigu9QTZ2qB/9l22vsxtM8a+Q8CzD255fg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + } }, - "combined-stream": { - "version": "1.0.6", - "resolved": "http://registry.npm.taobao.org/combined-stream/download/combined-stream-1.0.6.tgz", - "integrity": "sha1-cj599ugBrFYTETp+RFqbactjKBg=", - "requires": { - "delayed-stream": "~1.0.0" + "node_modules/@babel/helper-module-imports": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.16.7.tgz", + "integrity": "sha512-LVtS6TqjJHFc+nYeITRo6VLXve70xmq7wPhWTqDJusJEgGmkAACWwMiTNrvfoQo6hEhFwAIixNkvB0jPXDL8Wg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" } }, - "component-emitter": { - "version": "1.2.1", - "resolved": "http://registry.npm.taobao.org/component-emitter/download/component-emitter-1.2.1.tgz", - "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=", - "dev": true + "node_modules/@babel/helper-module-transforms": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.16.7.tgz", + "integrity": "sha512-gaqtLDxJEFCeQbYp9aLAefjhkKdjKcdh6DB7jniIGU3Pz52WAmP268zK0VgPz9hUNkMSYeH976K2/Y6yPadpng==", + "dev": true, + "dependencies": { + "@babel/helper-environment-visitor": "^7.16.7", + "@babel/helper-module-imports": "^7.16.7", + "@babel/helper-simple-access": "^7.16.7", + "@babel/helper-split-export-declaration": "^7.16.7", + "@babel/helper-validator-identifier": "^7.16.7", + "@babel/template": "^7.16.7", + "@babel/traverse": "^7.16.7", + "@babel/types": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + } }, - "concat-map": { - "version": "0.0.1", - "resolved": "http://registry.npm.taobao.org/concat-map/download/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + "node_modules/@babel/helper-simple-access": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.16.7.tgz", + "integrity": "sha512-ZIzHVyoeLMvXMN/vok/a4LWRy8G2v205mNP0XOuf9XRLyX5/u9CnVulUtDgUTama3lT+bf/UqucuZjqiGuTS1g==", + "dev": true, + "dependencies": { + "@babel/types": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + } }, - "concat-stream": { - "version": "1.6.0", - "resolved": "http://registry.npm.taobao.org/concat-stream/download/concat-stream-1.6.0.tgz", - "integrity": "sha1-CqxmL9Ur54lk1VMvaUeE5wEQrPc=", - "requires": { - "inherits": "^2.0.3", - "readable-stream": "^2.2.2", - "typedarray": "^0.0.6" + "node_modules/@babel/helper-split-export-declaration": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.16.7.tgz", + "integrity": "sha512-xbWoy/PFoxSWazIToT9Sif+jJTlrMcndIsaOKvTA6u7QEo7ilkRZpjew18/W3c7nm8fXdUDXh02VXTbZ0pGDNw==", + "dev": true, + "dependencies": { + "@babel/types": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" } }, - "configstore": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/configstore/-/configstore-3.1.2.tgz", - "integrity": "sha512-vtv5HtGjcYUgFrXc6Kx747B83MRRVS5R1VTEQoXvuP+kMI+if6uywV0nDGoiydJRy4yk7h9od5Og0kxx4zUXmw==", - "requires": { - "dot-prop": "^4.1.0", - "graceful-fs": "^4.1.2", - "make-dir": "^1.0.0", - "unique-string": "^1.0.0", - "write-file-atomic": "^2.0.0", - "xdg-basedir": "^3.0.0" + "node_modules/@babel/helper-validator-identifier": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz", + "integrity": "sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw==", + "engines": { + "node": ">=6.9.0" } }, - "constantinople": { - "version": "3.1.2", - "resolved": "http://registry.npm.taobao.org/constantinople/download/constantinople-3.1.2.tgz", - "integrity": "sha1-1F7XJPV9PRBQABen06iJwTga5kc=", - "requires": { - "@types/babel-types": "^7.0.0", - "@types/babylon": "^6.16.2", - "babel-types": "^6.26.0", - "babylon": "^6.18.0" + "node_modules/@babel/helper-validator-option": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.16.7.tgz", + "integrity": "sha512-TRtenOuRUVo9oIQGPC5G9DgK4743cdxvtOw0weQNpZXaS16SCBi5MNjZF8vba3ETURjZpTbVn7Vvcf2eAwFozQ==", + "dev": true, + "engines": { + "node": ">=6.9.0" } }, - "content-disposition": { - "version": "0.5.2", - "resolved": "http://registry.npm.taobao.org/content-disposition/download/content-disposition-0.5.2.tgz", - "integrity": "sha1-DPaLud318r55YcOoUXjLhdunjLQ=" + "node_modules/@babel/helpers": { + "version": "7.17.2", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.17.2.tgz", + "integrity": "sha512-0Qu7RLR1dILozr/6M0xgj+DFPmi6Bnulgm9M8BVa9ZCWxDqlSnqt3cf8IDPB5m45sVXUZ0kuQAgUrdSFFH79fQ==", + "dev": true, + "dependencies": { + "@babel/template": "^7.16.7", + "@babel/traverse": "^7.17.0", + "@babel/types": "^7.17.0" + }, + "engines": { + "node": ">=6.9.0" + } }, - "content-security-policy-builder": { - "version": "2.0.0", - "resolved": "http://registry.npm.taobao.org/content-security-policy-builder/download/content-security-policy-builder-2.0.0.tgz", - "integrity": "sha1-h0mh1UL8voIjcoHqn3Fs5os5TdI=" + "node_modules/@babel/highlight": { + "version": "7.16.10", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.16.10.tgz", + "integrity": "sha512-5FnTQLSLswEj6IkgVw5KusNUUFY9ZGqe/TRFnP/BKYHYgfh7tc+C7mwiy95/yNP7Dh9x580Vv8r7u7ZfTBFxdw==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.16.7", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + }, + "engines": { + "node": ">=6.9.0" + } }, - "content-type": { - "version": "1.0.4", - "resolved": "http://registry.npm.taobao.org/content-type/download/content-type-1.0.4.tgz", - "integrity": "sha1-4TjMdeBAxyexlm/l5fjJruJW/js=" + "node_modules/@babel/parser": { + "version": "7.17.3", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.17.3.tgz", + "integrity": "sha512-7yJPvPV+ESz2IUTPbOL+YkIGyCqOyNIzdguKQuJGnH7bg1WTIifuM21YqokFt/THWh1AkCRn9IgoykTRCBVpzA==", + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } }, - "cookie": { - "version": "0.3.1", - "resolved": "http://registry.npm.taobao.org/cookie/download/cookie-0.3.1.tgz", - "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=" + "node_modules/@babel/runtime": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.18.6.tgz", + "integrity": "sha512-t9wi7/AW6XtKahAe20Yw0/mMljKq0B1r2fPdvaAdV/KPDZewFXdaaa6K7lxmZBZ8FBNpCiAT6iHPmd6QO9bKfQ==", + "dev": true, + "dependencies": { + "regenerator-runtime": "^0.13.4" + }, + "engines": { + "node": ">=6.9.0" + } }, - "cookie-parser": { - "version": "1.4.3", - "resolved": "http://registry.npm.taobao.org/cookie-parser/download/cookie-parser-1.4.3.tgz", - "integrity": "sha1-D+MfoZ0AC5X0qt8fU/3CuKIDuqU=", - "requires": { - "cookie": "0.3.1", - "cookie-signature": "1.0.6" + "node_modules/@babel/runtime-corejs3": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.18.6.tgz", + "integrity": "sha512-cOu5wH2JFBgMjje+a+fz2JNIWU4GzYpl05oSob3UDvBEh6EuIn+TXFHMmBbhSb+k/4HMzgKCQfEEDArAWNF9Cw==", + "dev": true, + "dependencies": { + "core-js-pure": "^3.20.2", + "regenerator-runtime": "^0.13.4" + }, + "engines": { + "node": ">=6.9.0" } }, - "cookie-signature": { - "version": "1.0.6", - "resolved": "http://registry.npm.taobao.org/cookie-signature/download/cookie-signature-1.0.6.tgz", - "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" + "node_modules/@babel/template": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.16.7.tgz", + "integrity": "sha512-I8j/x8kHUrbYRTUxXrrMbfCa7jxkE7tZre39x3kjr9hvI82cK1FfqLygotcWN5kdPGWcLdWMHpSBavse5tWw3w==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.16.7", + "@babel/parser": "^7.16.7", + "@babel/types": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + } }, - "cookiejar": { - "version": "2.1.1", - "resolved": "http://registry.npm.taobao.org/cookiejar/download/cookiejar-2.1.1.tgz", - "integrity": "sha1-Qa1XsbVVlR7BcUEqgZQrHoIA00o=", + "node_modules/@babel/traverse": { + "version": "7.17.3", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.17.3.tgz", + "integrity": "sha512-5irClVky7TxRWIRtxlh2WPUUOLhcPN06AGgaQSB8AEwuyEBgJVuJ5imdHm5zxk8w0QS5T+tDfnDxAlhWjpb7cw==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.16.7", + "@babel/generator": "^7.17.3", + "@babel/helper-environment-visitor": "^7.16.7", + "@babel/helper-function-name": "^7.16.7", + "@babel/helper-hoist-variables": "^7.16.7", + "@babel/helper-split-export-declaration": "^7.16.7", + "@babel/parser": "^7.17.3", + "@babel/types": "^7.17.0", + "debug": "^4.1.0", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse/node_modules/debug": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", + "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@babel/traverse/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true }, - "core-js": { - "version": "2.5.3", - "resolved": "http://registry.npm.taobao.org/core-js/download/core-js-2.5.3.tgz", - "integrity": "sha1-isw4NFgk8W2DZbfJtCWRaOjtYD4=" + "node_modules/@babel/types": { + "version": "7.17.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.17.0.tgz", + "integrity": "sha512-TmKSNO4D5rzhL5bjWFcVHHLETzfQ/AmbKpKPOSjlP0WoHZ6L911fgoOKY4Alp/emzG4cHJdyN49zpgkbXFEHHw==", + "dependencies": { + "@babel/helper-validator-identifier": "^7.16.7", + "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } }, - "core-util-is": { - "version": "1.0.2", - "resolved": "http://registry.npm.taobao.org/core-util-is/download/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" + "node_modules/@eslint/eslintrc": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.0.tgz", + "integrity": "sha512-UWW0TMTmk2d7hLcWD1/e2g5HDM/HQ3csaLSqXCfqwh4uNDuNqlaKWXmEsL4Cs41Z0KnILNvwbHAah3C2yt06kw==", + "dev": true, + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.3.2", + "globals": "^13.15.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } }, - "cos-nodejs-sdk-v5": { - "version": "2.4.10", - "resolved": "https://registry.npmjs.org/cos-nodejs-sdk-v5/-/cos-nodejs-sdk-v5-2.4.10.tgz", - "integrity": "sha512-espPlCyyOc4vBKKI6Mwb5ZKzjYDgd0GOK4H0msiryupc3wlQCfPqJM+PubVlUEssqK58wIiV9Bq4Bo/ts2irjg==", - "requires": { - "configstore": "^3.1.2", - "qcloudapi-sdk": "^0.2.0", - "request": "^2.81.0", - "xml2js": "^0.4.19" + "node_modules/@eslint/eslintrc/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/@eslint/eslintrc/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, "dependencies": { - "xml2js": { - "version": "0.4.19", - "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.19.tgz", - "integrity": "sha512-esZnJZJOiJR9wWKMyuvSE1y6Dq5LCuJanqhxslH2bxM6duahNZ+HMpCLhBQGZkbX6xRf8x1Y2eJlgt2q3qo49Q==", - "requires": { - "sax": ">=0.6.0", - "xmlbuilder": "~9.0.1" - } - }, - "xmlbuilder": { - "version": "9.0.7", - "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.7.tgz", - "integrity": "sha1-Ey7mPS7FVlxVfiD0wi35rKaGsQ0=" + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true } } }, - "crc32": { - "version": "0.2.2", - "resolved": "http://registry.npm.taobao.org/crc32/download/crc32-0.2.2.tgz", - "integrity": "sha1-etIg1v/c0Rn5/BJ6d3LKzqOQpLo=" - }, - "cross-spawn": { - "version": "5.1.0", - "resolved": "http://registry.npm.taobao.org/cross-spawn/download/cross-spawn-5.1.0.tgz", - "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", - "requires": { - "lru-cache": "^4.0.1", - "shebang-command": "^1.2.0", - "which": "^1.2.9" + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "13.16.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.16.0.tgz", + "integrity": "sha512-A1lrQfpNF+McdPOnnFqY3kSN0AFTy485bTi1bkLk4mVPODIUEcSfhHgRqA+QdXPksrSTTztYXx37NFV+GpGk3Q==", + "dev": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "crypt": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/crypt/-/crypt-0.0.2.tgz", - "integrity": "sha1-iNf/fsDfuG9xPch7u0LQRNPmxBs=" + "node_modules/@eslint/eslintrc/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true }, - "cryptiles": { + "node_modules/@eslint/eslintrc/node_modules/minimatch": { "version": "3.1.2", - "resolved": "http://registry.npm.taobao.org/cryptiles/download/cryptiles-3.1.2.tgz", - "integrity": "sha1-qJ+7Ig9c4l7FboxKqKT9e1sNKf4=", - "requires": { - "boom": "5.x.x" - }, - "dependencies": { - "boom": { - "version": "5.2.0", - "resolved": "http://registry.npm.taobao.org/boom/download/boom-5.2.0.tgz", - "integrity": "sha1-XdnabuOl8wIHdDYpDLcX0/SlTgI=", - "requires": { - "hoek": "4.x.x" - } - } + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" } }, - "crypto-random-string": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-1.0.0.tgz", - "integrity": "sha1-ojD2T1aDEOFJgAmUB5DsmVRbyn4=" + "node_modules/@eslint/eslintrc/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true }, - "csextends": { - "version": "1.1.1", - "resolved": "http://registry.npm.taobao.org/csextends/download/csextends-1.1.1.tgz", - "integrity": "sha1-zFPBNJ+vfwrmzfb2xKTZFW08TsE=", - "requires": { - "coffee-script": "^1.12.5" + "node_modules/@humanwhocodes/config-array": { + "version": "0.9.5", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.9.5.tgz", + "integrity": "sha512-ObyMyWxZiCu/yTisA7uzx81s40xR2fD5Cg/2Kq7G02ajkNubJf6BopgDTmDyc3U7sXpNKM8cYOw7s7Tyr+DnCw==", + "deprecated": "Use @eslint/config-array instead", + "dev": true, + "dependencies": { + "@humanwhocodes/object-schema": "^1.2.1", + "debug": "^4.1.1", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=10.10.0" } }, - "dashdash": { - "version": "1.14.1", - "resolved": "http://registry.npm.taobao.org/dashdash/download/dashdash-1.14.1.tgz", - "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", - "requires": { - "assert-plus": "^1.0.0" + "node_modules/@humanwhocodes/config-array/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } } }, - "dasherize": { - "version": "2.0.0", - "resolved": "http://registry.npm.taobao.org/dasherize/download/dasherize-2.0.0.tgz", - "integrity": "sha1-bYCcnNDPe7iVLYD8hPoT1H3bEwg=" + "node_modules/@humanwhocodes/config-array/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true }, - "date-format": { - "version": "1.2.0", - "resolved": "http://registry.npm.taobao.org/date-format/download/date-format-1.2.0.tgz", - "integrity": "sha1-YV6CjiM90aubua4JUODOzPpuytg=" + "node_modules/@humanwhocodes/object-schema": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", + "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", + "deprecated": "Use @eslint/object-schema instead", + "dev": true }, - "debug": { - "version": "3.1.0", - "resolved": "http://registry.npm.taobao.org/debug/download/debug-3.1.0.tgz", - "integrity": "sha1-W7WgZyYotkFJVmuhaBnmFRjGcmE=", - "requires": { - "ms": "2.0.0" + "node_modules/@hutson/parse-repository-url": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@hutson/parse-repository-url/-/parse-repository-url-3.0.2.tgz", + "integrity": "sha512-H9XAx3hc0BQHY6l+IFSWHDySypcXsvsuLhgYLUGywmJ5pswRVQJUHpOsobnLYp2ZUaUlKiKDrgWWhosOwAEM8Q==", + "dev": true, + "engines": { + "node": ">=6.9.0" } }, - "decamelize": { - "version": "1.2.0", - "resolved": "http://registry.npm.taobao.org/decamelize/download/decamelize-1.2.0.tgz", - "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=" + "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, + "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" + } }, - "deep-is": { - "version": "0.1.3", - "resolved": "http://registry.npm.taobao.org/deep-is/download/deep-is-0.1.3.tgz", - "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", - "dev": true + "node_modules/@istanbuljs/load-nyc-config/node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "dependencies": { + "sprintf-js": "~1.0.2" + } }, - "default-user-agent": { - "version": "1.0.0", - "resolved": "http://registry.npm.taobao.org/default-user-agent/download/default-user-agent-1.0.0.tgz", - "integrity": "sha1-FsRu/cq6PtxF8k8r1IaLAbfCrcY=", - "requires": { - "os-name": "~1.0.3" + "node_modules/@istanbuljs/load-nyc-config/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, + "engines": { + "node": ">=6" } }, - "delayed-stream": { - "version": "1.0.0", - "resolved": "http://registry.npm.taobao.org/delayed-stream/download/delayed-stream-1.0.0.tgz", - "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" + "node_modules/@istanbuljs/load-nyc-config/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } }, - "denque": { - "version": "1.2.3", - "resolved": "http://registry.npm.taobao.org/denque/download/denque-1.2.3.tgz", - "integrity": "sha1-mMUMjdjN+uMYzFhZzI7j2g+bDMI=" + "node_modules/@istanbuljs/load-nyc-config/node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } }, - "depd": { - "version": "1.1.2", - "resolved": "http://registry.npm.taobao.org/depd/download/depd-1.1.2.tgz", - "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" + "node_modules/@istanbuljs/load-nyc-config/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } }, - "destroy": { - "version": "1.0.4", - "resolved": "http://registry.npm.taobao.org/destroy/download/destroy-1.0.4.tgz", - "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" + "node_modules/@istanbuljs/load-nyc-config/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } }, - "diff": { - "version": "3.2.0", - "resolved": "http://registry.npm.taobao.org/diff/download/diff-3.2.0.tgz", - "integrity": "sha1-yc45Okt8vQsFinJck98pkCeGj/k=", - "dev": true + "node_modules/@istanbuljs/load-nyc-config/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, + "engines": { + "node": ">=8" + } }, - "diff-match-patch": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/diff-match-patch/-/diff-match-patch-1.0.1.tgz", - "integrity": "sha512-A0QEhr4PxGUMEtKxd6X+JLnOTFd3BfIPSDpsc4dMvj+CbSaErDwTpoTo/nFJDMSrjxLW4BiNq+FbNisAAHhWeQ==" + "node_modules/@istanbuljs/load-nyc-config/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, + "engines": { + "node": ">=8" + } }, - "digest-header": { - "version": "0.0.1", - "resolved": "http://registry.npm.taobao.org/digest-header/download/digest-header-0.0.1.tgz", - "integrity": "sha1-Ecz23uxXZqw3l0TZAcEsuklRS+Y=", - "requires": { - "utility": "0.1.11" + "node_modules/@istanbuljs/schema": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", + "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", + "dev": true, + "engines": { + "node": ">=8" } }, - "dns-prefetch-control": { - "version": "0.1.0", - "resolved": "http://registry.npm.taobao.org/dns-prefetch-control/download/dns-prefetch-control-0.1.0.tgz", - "integrity": "sha1-YN20V3dOF48flBXwyrsOhbCzALI=" + "node_modules/@jridgewell/resolve-uri": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.0.5.tgz", + "integrity": "sha512-VPeQ7+wH0itvQxnG+lIzWgkysKIr3L9sslimFW55rHMdGu/qCQ5z5h9zq4gI8uBtqkpHhsF4Z/OwExufUCThew==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } }, - "doctypes": { - "version": "1.1.0", - "resolved": "http://registry.npm.taobao.org/doctypes/download/doctypes-1.1.0.tgz", - "integrity": "sha1-6oCxBqh1OHdOijpKWv4pPeSJ4Kk=" + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.11", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.11.tgz", + "integrity": "sha512-Fg32GrJo61m+VqYSdRSjRXMjQ06j8YIYfcTqndLYVAaHmroZHLJZCydsWBOTDqXS2v+mjxohBWEMfg97GXmYQg==", + "dev": true }, - "dont-sniff-mimetype": { - "version": "1.0.0", - "resolved": "http://registry.npm.taobao.org/dont-sniff-mimetype/download/dont-sniff-mimetype-1.0.0.tgz", - "integrity": "sha1-WTKJDcn04vGeXrAqIAJuXl78j1g=" + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.4.tgz", + "integrity": "sha512-vFv9ttIedivx0ux3QSjhgtCVjPZd5l46ZOMDSCwnH1yUO2e964gO8LZGyv2QkqcgR6TnBU1v+1IFqmeoG+0UJQ==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } }, - "dot-prop": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-4.2.0.tgz", - "integrity": "sha512-tUMXrxlExSW6U2EXiiKGSBVdYgtV8qlHL+C10TsW4PURY/ic+eaysnSkwB4kA/mBlCyy/IKDJ+Lc3wbWeaXtuQ==", - "requires": { - "is-obj": "^1.0.0" + "node_modules/@messageformat/core": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@messageformat/core/-/core-3.0.1.tgz", + "integrity": "sha512-yxj2+0e46hcZqJfNf0ZYbC2q6WlcGoh4g11mCyRtTueR0AD8F9z4JMYAS1aOiFG8Vl1LZg/h5hZHKmWTAyZq8g==", + "dependencies": { + "@messageformat/date-skeleton": "^1.0.0", + "@messageformat/number-skeleton": "^1.0.0", + "@messageformat/parser": "^5.0.0", + "@messageformat/runtime": "^3.0.1", + "make-plural": "^7.0.0", + "safe-identifier": "^0.4.1" } }, - "dot-qs": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/dot-qs/-/dot-qs-0.2.0.tgz", - "integrity": "sha1-02UX/iS3zaYfznpQJqACSvr1pDk=" + "node_modules/@messageformat/date-skeleton": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@messageformat/date-skeleton/-/date-skeleton-1.0.1.tgz", + "integrity": "sha512-jPXy8fg+WMPIgmGjxSlnGJn68h/2InfT0TNSkVx0IGXgp4ynnvYkbZ51dGWmGySEK+pBiYUttbQdu5XEqX5CRg==" }, - "dottie": { - "version": "2.0.0", - "resolved": "http://registry.npm.taobao.org/dottie/download/dottie-2.0.0.tgz", - "integrity": "sha1-2hkZgci41xPKARXViYzzl8Lw3dA=" + "node_modules/@messageformat/number-skeleton": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@messageformat/number-skeleton/-/number-skeleton-1.1.0.tgz", + "integrity": "sha512-F0Io+GOSvFFxvp9Ze3L5kAoZ2NnOAT0Mr/jpGNd3fqo8A0t4NxNIAcCdggtl2B/gN2ErkIKSBVPrF7xcW1IGvA==" }, - "double-ended-queue": { - "version": "2.1.0-0", - "resolved": "http://registry.npm.taobao.org/double-ended-queue/download/double-ended-queue-2.1.0-0.tgz", - "integrity": "sha1-ED01J/0xUo9AGIEwyEHv3XgmTlw=" + "node_modules/@messageformat/parser": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@messageformat/parser/-/parser-5.0.0.tgz", + "integrity": "sha512-WiDKhi8F0zQaFU8cXgqq69eYFarCnTVxKcvhAONufKf0oUxbqLMW6JX6rV4Hqh+BEQWGyKKKHY4g1XA6bCLylA==", + "dependencies": { + "moo": "^0.5.1" + } }, - "eachr": { - "version": "2.0.4", - "resolved": "http://registry.npm.taobao.org/eachr/download/eachr-2.0.4.tgz", - "integrity": "sha1-Rm98qhBwj2EFCeMsgHqv5X/BIr8=", - "requires": { - "typechecker": "^2.0.8" + "node_modules/@messageformat/runtime": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@messageformat/runtime/-/runtime-3.0.1.tgz", + "integrity": "sha512-6RU5ol2lDtO8bD9Yxe6CZkl0DArdv0qkuoZC+ZwowU+cdRlVE1157wjCmlA5Rsf1Xc/brACnsZa5PZpEDfTFFg==", + "dependencies": { + "make-plural": "^7.0.0" } }, - "ecc-jsbn": { - "version": "0.1.1", - "resolved": "http://registry.npm.taobao.org/ecc-jsbn/download/ecc-jsbn-0.1.1.tgz", - "integrity": "sha1-D8c6ntXw1Tw4GTOYUj735UN3dQU=", - "optional": true, - "requires": { - "jsbn": "~0.1.0" + "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==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" } }, - "ecdsa-sig-formatter": { - "version": "1.0.9", - "resolved": "http://registry.npm.taobao.org/ecdsa-sig-formatter/download/ecdsa-sig-formatter-1.0.9.tgz", - "integrity": "sha1-S8kmJ07Dtau1AW5+HWCSGsJisqE=", - "requires": { - "base64url": "^2.0.0", - "safe-buffer": "^5.0.1" + "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==", + "dev": true, + "engines": { + "node": ">= 8" } }, - "editions": { - "version": "1.3.4", - "resolved": "http://registry.npm.taobao.org/editions/download/editions-1.3.4.tgz", - "integrity": "sha1-NmLLWSNHwxaOuOSYoP9zJx1n9Qs=" + "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==", + "dev": true, + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } }, - "ee-first": { - "version": "1.1.1", - "resolved": "http://registry.npm.taobao.org/ee-first/download/ee-first-1.1.1.tgz", - "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" + "node_modules/@protobufjs/aspromise": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", + "integrity": "sha1-m4sMxmPWaafY9vXQiToU00jzD78=" }, - "encodeurl": { - "version": "1.0.2", - "resolved": "http://registry.npm.taobao.org/encodeurl/download/encodeurl-1.0.2.tgz", - "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" + "node_modules/@protobufjs/base64": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", + "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==" }, - "entities": { - "version": "1.1.1", - "resolved": "http://registry.npm.taobao.org/entities/download/entities-1.1.1.tgz", - "integrity": "sha1-blwtClYhtdra7O+AuQ7ftc13cvA=" + "node_modules/@protobufjs/codegen": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", + "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==" }, - "escape-html": { - "version": "1.0.3", - "resolved": "http://registry.npm.taobao.org/escape-html/download/escape-html-1.0.3.tgz", - "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" + "node_modules/@protobufjs/eventemitter": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", + "integrity": "sha1-NVy8mLr61ZePntCV85diHx0Ga3A=" }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "http://registry.npm.taobao.org/escape-string-regexp/download/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "dev": true + "node_modules/@protobufjs/fetch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", + "integrity": "sha1-upn7WYYUr2VwDBYZ/wbUVLDYTEU=", + "dependencies": { + "@protobufjs/aspromise": "^1.1.1", + "@protobufjs/inquire": "^1.1.0" + } }, - "esutils": { - "version": "2.0.2", - "resolved": "http://registry.npm.taobao.org/esutils/download/esutils-2.0.2.tgz", - "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=" + "node_modules/@protobufjs/float": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", + "integrity": "sha1-Xp4avctz/Ap8uLKR33jIy9l7h9E=" + }, + "node_modules/@protobufjs/inquire": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", + "integrity": "sha1-/yAOPnzyQp4tyvwRQIKOjMY48Ik=" + }, + "node_modules/@protobufjs/path": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", + "integrity": "sha1-bMKyDFya1q0NzP0hynZz2Nf79o0=" + }, + "node_modules/@protobufjs/pool": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", + "integrity": "sha1-Cf0V8tbTq/qbZbw2ZQbWrXhG/1Q=" + }, + "node_modules/@protobufjs/utf8": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", + "integrity": "sha1-p3c2C1s5oaLlEG+OhY8v0tBgxXA=" + }, + "node_modules/@redis/bloom": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@redis/bloom/-/bloom-1.0.2.tgz", + "integrity": "sha512-EBw7Ag1hPgFzdznK2PBblc1kdlj5B5Cw3XwI9/oG7tSn85/HKy3X9xHy/8tm/eNXJYHLXHJL/pkwBpFMVVefkw==", + "peerDependencies": { + "@redis/client": "^1.0.0" + } + }, + "node_modules/@redis/client": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@redis/client/-/client-1.2.0.tgz", + "integrity": "sha512-a8Nlw5fv2EIAFJxTDSSDVUT7yfBGpZO96ybZXzQpgkyLg/dxtQ1uiwTc0EGfzg1mrPjZokeBSEGTbGXekqTNOg==", + "dependencies": { + "cluster-key-slot": "1.1.0", + "generic-pool": "3.8.2", + "yallist": "4.0.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@redis/graph": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@redis/graph/-/graph-1.0.1.tgz", + "integrity": "sha512-oDE4myMCJOCVKYMygEMWuriBgqlS5FqdWerikMoJxzmmTUErnTRRgmIDa2VcgytACZMFqpAOWDzops4DOlnkfQ==", + "peerDependencies": { + "@redis/client": "^1.0.0" + } + }, + "node_modules/@redis/json": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@redis/json/-/json-1.0.3.tgz", + "integrity": "sha512-4X0Qv0BzD9Zlb0edkUoau5c1bInWSICqXAGrpwEltkncUwcxJIGEcVryZhLgb0p/3PkKaLIWkjhHRtLe9yiA7Q==", + "peerDependencies": { + "@redis/client": "^1.0.0" + } + }, + "node_modules/@redis/search": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@redis/search/-/search-1.0.6.tgz", + "integrity": "sha512-pP+ZQRis5P21SD6fjyCeLcQdps+LuTzp2wdUbzxEmNhleighDDTD5ck8+cYof+WLec4csZX7ks+BuoMw0RaZrA==", + "peerDependencies": { + "@redis/client": "^1.0.0" + } + }, + "node_modules/@redis/time-series": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@redis/time-series/-/time-series-1.0.3.tgz", + "integrity": "sha512-OFp0q4SGrTH0Mruf6oFsHGea58u8vS/iI5+NpYdicaM+7BgqBZH8FFvNZ8rYYLrUO/QRqMq72NpXmxLVNcdmjA==", + "peerDependencies": { + "@redis/client": "^1.0.0" + } + }, + "node_modules/@shm-open/eslint-config-bundle": { + "version": "1.9.13", + "resolved": "https://registry.npmjs.org/@shm-open/eslint-config-bundle/-/eslint-config-bundle-1.9.13.tgz", + "integrity": "sha512-QwyV+aZm5aIcNV1payDz46z3yJE4tUvKFKUxtxLAqysPwJeSg6CklVXuWHc2e8hStcF5U0dMLEoKAg60EOxGBA==", + "dev": true, + "dependencies": { + "@typescript-eslint/eslint-plugin": "5.30.6", + "@typescript-eslint/parser": "5.30.6", + "babel-eslint": "10.1.0", + "eslint": "8.19.0", + "eslint-config-airbnb-base": "15.0.0", + "eslint-config-prettier": "8.5.0", + "eslint-import-resolver-typescript": "2.7.1", + "eslint-plugin-deprecation": "1.3.2", + "eslint-plugin-import": "2.26.0", + "eslint-plugin-jsx-a11y": "6.6.0", + "eslint-plugin-prettier": "4.2.1", + "eslint-plugin-react": "7.30.1", + "eslint-plugin-react-hooks": "4.6.0", + "eslint-plugin-react-native": "4.0.0", + "eslint-plugin-taro": "3.3.20", + "prettier": "2.7.1" + } + }, + "node_modules/@smithy/abort-controller": { + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-4.2.5.tgz", + "integrity": "sha512-j7HwVkBw68YW8UmFRcjZOmssE77Rvk0GWAIN1oFBhsaovQmZWYCIcGa9/pwRB0ExI8Sk9MWNALTjftjHZea7VA==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/chunked-blob-reader": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@smithy/chunked-blob-reader/-/chunked-blob-reader-5.2.0.tgz", + "integrity": "sha512-WmU0TnhEAJLWvfSeMxBNe5xtbselEO8+4wG0NtZeL8oR21WgH1xiO37El+/Y+H/Ie4SCwBy3MxYWmOYaGgZueA==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/chunked-blob-reader-native": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@smithy/chunked-blob-reader-native/-/chunked-blob-reader-native-4.2.1.tgz", + "integrity": "sha512-lX9Ay+6LisTfpLid2zZtIhSEjHMZoAR5hHCR4H7tBz/Zkfr5ea8RcQ7Tk4mi0P76p4cN+Btz16Ffno7YHpKXnQ==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/util-base64": "^4.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/config-resolver": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/@smithy/config-resolver/-/config-resolver-4.4.3.tgz", + "integrity": "sha512-ezHLe1tKLUxDJo2LHtDuEDyWXolw8WGOR92qb4bQdWq/zKenO5BvctZGrVJBK08zjezSk7bmbKFOXIVyChvDLw==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/node-config-provider": "^4.3.5", + "@smithy/types": "^4.9.0", + "@smithy/util-config-provider": "^4.2.0", + "@smithy/util-endpoints": "^3.2.5", + "@smithy/util-middleware": "^4.2.5", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/core": { + "version": "3.18.4", + "resolved": "https://registry.npmjs.org/@smithy/core/-/core-3.18.4.tgz", + "integrity": "sha512-o5tMqPZILBvvROfC8vC+dSVnWJl9a0u9ax1i1+Bq8515eYjUJqqk5XjjEsDLoeL5dSqGSh6WGdVx1eJ1E/Nwhw==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/middleware-serde": "^4.2.6", + "@smithy/protocol-http": "^5.3.5", + "@smithy/types": "^4.9.0", + "@smithy/util-base64": "^4.3.0", + "@smithy/util-body-length-browser": "^4.2.0", + "@smithy/util-middleware": "^4.2.5", + "@smithy/util-stream": "^4.5.6", + "@smithy/util-utf8": "^4.2.0", + "@smithy/uuid": "^1.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/credential-provider-imds": { + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/@smithy/credential-provider-imds/-/credential-provider-imds-4.2.5.tgz", + "integrity": "sha512-BZwotjoZWn9+36nimwm/OLIcVe+KYRwzMjfhd4QT7QxPm9WY0HiOV8t/Wlh+HVUif0SBVV7ksq8//hPaBC/okQ==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/node-config-provider": "^4.3.5", + "@smithy/property-provider": "^4.2.5", + "@smithy/types": "^4.9.0", + "@smithy/url-parser": "^4.2.5", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/eventstream-codec": { + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/@smithy/eventstream-codec/-/eventstream-codec-4.2.5.tgz", + "integrity": "sha512-Ogt4Zi9hEbIP17oQMd68qYOHUzmH47UkK7q7Gl55iIm9oKt27MUGrC5JfpMroeHjdkOliOA4Qt3NQ1xMq/nrlA==", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/crc32": "5.2.0", + "@smithy/types": "^4.9.0", + "@smithy/util-hex-encoding": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/eventstream-serde-browser": { + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-browser/-/eventstream-serde-browser-4.2.5.tgz", + "integrity": "sha512-HohfmCQZjppVnKX2PnXlf47CW3j92Ki6T/vkAT2DhBR47e89pen3s4fIa7otGTtrVxmj7q+IhH0RnC5kpR8wtw==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/eventstream-serde-universal": "^4.2.5", + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/eventstream-serde-config-resolver": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-config-resolver/-/eventstream-serde-config-resolver-4.3.5.tgz", + "integrity": "sha512-ibjQjM7wEXtECiT6my1xfiMH9IcEczMOS6xiCQXoUIYSj5b1CpBbJ3VYbdwDy8Vcg5JHN7eFpOCGk8nyZAltNQ==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/eventstream-serde-node": { + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-node/-/eventstream-serde-node-4.2.5.tgz", + "integrity": "sha512-+elOuaYx6F2H6x1/5BQP5ugv12nfJl66GhxON8+dWVUEDJ9jah/A0tayVdkLRP0AeSac0inYkDz5qBFKfVp2Gg==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/eventstream-serde-universal": "^4.2.5", + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/eventstream-serde-universal": { + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-universal/-/eventstream-serde-universal-4.2.5.tgz", + "integrity": "sha512-G9WSqbST45bmIFaeNuP/EnC19Rhp54CcVdX9PDL1zyEB514WsDVXhlyihKlGXnRycmHNmVv88Bvvt4EYxWef/Q==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/eventstream-codec": "^4.2.5", + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/fetch-http-handler": { + "version": "5.3.6", + "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-5.3.6.tgz", + "integrity": "sha512-3+RG3EA6BBJ/ofZUeTFJA7mHfSYrZtQIrDP9dI8Lf7X6Jbos2jptuLrAAteDiFVrmbEmLSuRG/bUKzfAXk7dhg==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/protocol-http": "^5.3.5", + "@smithy/querystring-builder": "^4.2.5", + "@smithy/types": "^4.9.0", + "@smithy/util-base64": "^4.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/hash-blob-browser": { + "version": "4.2.6", + "resolved": "https://registry.npmjs.org/@smithy/hash-blob-browser/-/hash-blob-browser-4.2.6.tgz", + "integrity": "sha512-8P//tA8DVPk+3XURk2rwcKgYwFvwGwmJH/wJqQiSKwXZtf/LiZK+hbUZmPj/9KzM+OVSwe4o85KTp5x9DUZTjw==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/chunked-blob-reader": "^5.2.0", + "@smithy/chunked-blob-reader-native": "^4.2.1", + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/hash-node": { + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/@smithy/hash-node/-/hash-node-4.2.5.tgz", + "integrity": "sha512-DpYX914YOfA3UDT9CN1BM787PcHfWRBB43fFGCYrZFUH0Jv+5t8yYl+Pd5PW4+QzoGEDvn5d5QIO4j2HyYZQSA==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.9.0", + "@smithy/util-buffer-from": "^4.2.0", + "@smithy/util-utf8": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/hash-stream-node": { + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/@smithy/hash-stream-node/-/hash-stream-node-4.2.5.tgz", + "integrity": "sha512-6+do24VnEyvWcGdHXomlpd0m8bfZePpUKBy7m311n+JuRwug8J4dCanJdTymx//8mi0nlkflZBvJe+dEO/O12Q==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.9.0", + "@smithy/util-utf8": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/invalid-dependency": { + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/@smithy/invalid-dependency/-/invalid-dependency-4.2.5.tgz", + "integrity": "sha512-2L2erASEro1WC5nV+plwIMxrTXpvpfzl4e+Nre6vBVRR2HKeGGcvpJyyL3/PpiSg+cJG2KpTmZmq934Olb6e5A==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/is-array-buffer": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-4.2.0.tgz", + "integrity": "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/md5-js": { + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/@smithy/md5-js/-/md5-js-4.2.5.tgz", + "integrity": "sha512-Bt6jpSTMWfjCtC0s79gZ/WZ1w90grfmopVOWqkI2ovhjpD5Q2XRXuecIPB9689L2+cCySMbaXDhBPU56FKNDNg==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.9.0", + "@smithy/util-utf8": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/middleware-content-length": { + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/@smithy/middleware-content-length/-/middleware-content-length-4.2.5.tgz", + "integrity": "sha512-Y/RabVa5vbl5FuHYV2vUCwvh/dqzrEY/K2yWPSqvhFUwIY0atLqO4TienjBXakoy4zrKAMCZwg+YEqmH7jaN7A==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/protocol-http": "^5.3.5", + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/middleware-endpoint": { + "version": "4.3.11", + "resolved": "https://registry.npmjs.org/@smithy/middleware-endpoint/-/middleware-endpoint-4.3.11.tgz", + "integrity": "sha512-eJXq9VJzEer1W7EQh3HY2PDJdEcEUnv6sKuNt4eVjyeNWcQFS4KmnY+CKkYOIR6tSqarn6bjjCqg1UB+8UJiPQ==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/core": "^3.18.4", + "@smithy/middleware-serde": "^4.2.6", + "@smithy/node-config-provider": "^4.3.5", + "@smithy/shared-ini-file-loader": "^4.4.0", + "@smithy/types": "^4.9.0", + "@smithy/url-parser": "^4.2.5", + "@smithy/util-middleware": "^4.2.5", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/middleware-retry": { + "version": "4.4.11", + "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-4.4.11.tgz", + "integrity": "sha512-EL5OQHvFOKneJVRgzRW4lU7yidSwp/vRJOe542bHgExN3KNThr1rlg0iE4k4SnA+ohC+qlUxoK+smKeAYPzfAQ==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/node-config-provider": "^4.3.5", + "@smithy/protocol-http": "^5.3.5", + "@smithy/service-error-classification": "^4.2.5", + "@smithy/smithy-client": "^4.9.7", + "@smithy/types": "^4.9.0", + "@smithy/util-middleware": "^4.2.5", + "@smithy/util-retry": "^4.2.5", + "@smithy/uuid": "^1.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/middleware-serde": { + "version": "4.2.6", + "resolved": "https://registry.npmjs.org/@smithy/middleware-serde/-/middleware-serde-4.2.6.tgz", + "integrity": "sha512-VkLoE/z7e2g8pirwisLz8XJWedUSY8my/qrp81VmAdyrhi94T+riBfwP+AOEEFR9rFTSonC/5D2eWNmFabHyGQ==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/protocol-http": "^5.3.5", + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/middleware-stack": { + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/@smithy/middleware-stack/-/middleware-stack-4.2.5.tgz", + "integrity": "sha512-bYrutc+neOyWxtZdbB2USbQttZN0mXaOyYLIsaTbJhFsfpXyGWUxJpEuO1rJ8IIJm2qH4+xJT0mxUSsEDTYwdQ==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/node-config-provider": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-4.3.5.tgz", + "integrity": "sha512-UTurh1C4qkVCtqggI36DGbLB2Kv8UlcFdMXDcWMbqVY2uRg0XmT9Pb4Vj6oSQ34eizO1fvR0RnFV4Axw4IrrAg==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/property-provider": "^4.2.5", + "@smithy/shared-ini-file-loader": "^4.4.0", + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/node-http-handler": { + "version": "4.4.5", + "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-4.4.5.tgz", + "integrity": "sha512-CMnzM9R2WqlqXQGtIlsHMEZfXKJVTIrqCNoSd/QpAyp+Dw0a1Vps13l6ma1fH8g7zSPNsA59B/kWgeylFuA/lw==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/abort-controller": "^4.2.5", + "@smithy/protocol-http": "^5.3.5", + "@smithy/querystring-builder": "^4.2.5", + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/property-provider": { + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-4.2.5.tgz", + "integrity": "sha512-8iLN1XSE1rl4MuxvQ+5OSk/Zb5El7NJZ1td6Tn+8dQQHIjp59Lwl6bd0+nzw6SKm2wSSriH2v/I9LPzUic7EOg==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/protocol-http": { + "version": "5.3.5", + "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-5.3.5.tgz", + "integrity": "sha512-RlaL+sA0LNMp03bf7XPbFmT5gN+w3besXSWMkA8rcmxLSVfiEXElQi4O2IWwPfxzcHkxqrwBFMbngB8yx/RvaQ==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/querystring-builder": { + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/@smithy/querystring-builder/-/querystring-builder-4.2.5.tgz", + "integrity": "sha512-y98otMI1saoajeik2kLfGyRp11e5U/iJYH/wLCh3aTV/XutbGT9nziKGkgCaMD1ghK7p6htHMm6b6scl9JRUWg==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.9.0", + "@smithy/util-uri-escape": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/querystring-parser": { + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/@smithy/querystring-parser/-/querystring-parser-4.2.5.tgz", + "integrity": "sha512-031WCTdPYgiQRYNPXznHXof2YM0GwL6SeaSyTH/P72M1Vz73TvCNH2Nq8Iu2IEPq9QP2yx0/nrw5YmSeAi/AjQ==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/service-error-classification": { + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/@smithy/service-error-classification/-/service-error-classification-4.2.5.tgz", + "integrity": "sha512-8fEvK+WPE3wUAcDvqDQG1Vk3ANLR8Px979te96m84CbKAjBVf25rPYSzb4xU4hlTyho7VhOGnh5i62D/JVF0JQ==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.9.0" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/shared-ini-file-loader": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-4.4.0.tgz", + "integrity": "sha512-5WmZ5+kJgJDjwXXIzr1vDTG+RhF9wzSODQBfkrQ2VVkYALKGvZX1lgVSxEkgicSAFnFhPj5rudJV0zoinqS0bA==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/signature-v4": { + "version": "5.3.5", + "resolved": "https://registry.npmjs.org/@smithy/signature-v4/-/signature-v4-5.3.5.tgz", + "integrity": "sha512-xSUfMu1FT7ccfSXkoLl/QRQBi2rOvi3tiBZU2Tdy3I6cgvZ6SEi9QNey+lqps/sJRnogIS+lq+B1gxxbra2a/w==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/is-array-buffer": "^4.2.0", + "@smithy/protocol-http": "^5.3.5", + "@smithy/types": "^4.9.0", + "@smithy/util-hex-encoding": "^4.2.0", + "@smithy/util-middleware": "^4.2.5", + "@smithy/util-uri-escape": "^4.2.0", + "@smithy/util-utf8": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/smithy-client": { + "version": "4.9.7", + "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-4.9.7.tgz", + "integrity": "sha512-pskaE4kg0P9xNQWihfqlTMyxyFR3CH6Sr6keHYghgyqqDXzjl2QJg5lAzuVe/LzZiOzcbcVtxKYi1/fZPt/3DA==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/core": "^3.18.4", + "@smithy/middleware-endpoint": "^4.3.11", + "@smithy/middleware-stack": "^4.2.5", + "@smithy/protocol-http": "^5.3.5", + "@smithy/types": "^4.9.0", + "@smithy/util-stream": "^4.5.6", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/types": { + "version": "4.9.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.9.0.tgz", + "integrity": "sha512-MvUbdnXDTwykR8cB1WZvNNwqoWVaTRA0RLlLmf/cIFNMM2cKWz01X4Ly6SMC4Kks30r8tT3Cty0jmeWfiuyHTA==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/url-parser": { + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/@smithy/url-parser/-/url-parser-4.2.5.tgz", + "integrity": "sha512-VaxMGsilqFnK1CeBX+LXnSuaMx4sTL/6znSZh2829txWieazdVxr54HmiyTsIbpOTLcf5nYpq9lpzmwRdxj6rQ==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/querystring-parser": "^4.2.5", + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-base64": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@smithy/util-base64/-/util-base64-4.3.0.tgz", + "integrity": "sha512-GkXZ59JfyxsIwNTWFnjmFEI8kZpRNIBfxKjv09+nkAWPt/4aGaEWMM04m4sxgNVWkbt2MdSvE3KF/PfX4nFedQ==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/util-buffer-from": "^4.2.0", + "@smithy/util-utf8": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-body-length-browser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@smithy/util-body-length-browser/-/util-body-length-browser-4.2.0.tgz", + "integrity": "sha512-Fkoh/I76szMKJnBXWPdFkQJl2r9SjPt3cMzLdOB6eJ4Pnpas8hVoWPYemX/peO0yrrvldgCUVJqOAjUrOLjbxg==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-body-length-node": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@smithy/util-body-length-node/-/util-body-length-node-4.2.1.tgz", + "integrity": "sha512-h53dz/pISVrVrfxV1iqXlx5pRg3V2YWFcSQyPyXZRrZoZj4R4DeWRDo1a7dd3CPTcFi3kE+98tuNyD2axyZReA==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-buffer-from": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-4.2.0.tgz", + "integrity": "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/is-array-buffer": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-config-provider": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@smithy/util-config-provider/-/util-config-provider-4.2.0.tgz", + "integrity": "sha512-YEjpl6XJ36FTKmD+kRJJWYvrHeUvm5ykaUS5xK+6oXffQPHeEM4/nXlZPe+Wu0lsgRUcNZiliYNh/y7q9c2y6Q==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-defaults-mode-browser": { + "version": "4.3.10", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-4.3.10.tgz", + "integrity": "sha512-3iA3JVO1VLrP21FsZZpMCeF93aqP3uIOMvymAT3qHIJz2YlgDeRvNUspFwCNqd/j3qqILQJGtsVQnJZICh/9YA==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/property-provider": "^4.2.5", + "@smithy/smithy-client": "^4.9.7", + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-defaults-mode-node": { + "version": "4.2.13", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-4.2.13.tgz", + "integrity": "sha512-PTc6IpnpSGASuzZAgyUtaVfOFpU0jBD2mcGwrgDuHf7PlFgt5TIPxCYBDbFQs06jxgeV3kd/d/sok1pzV0nJRg==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/config-resolver": "^4.4.3", + "@smithy/credential-provider-imds": "^4.2.5", + "@smithy/node-config-provider": "^4.3.5", + "@smithy/property-provider": "^4.2.5", + "@smithy/smithy-client": "^4.9.7", + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-endpoints": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/@smithy/util-endpoints/-/util-endpoints-3.2.5.tgz", + "integrity": "sha512-3O63AAWu2cSNQZp+ayl9I3NapW1p1rR5mlVHcF6hAB1dPZUQFfRPYtplWX/3xrzWthPGj5FqB12taJJCfH6s8A==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/node-config-provider": "^4.3.5", + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-hex-encoding": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@smithy/util-hex-encoding/-/util-hex-encoding-4.2.0.tgz", + "integrity": "sha512-CCQBwJIvXMLKxVbO88IukazJD9a4kQ9ZN7/UMGBjBcJYvatpWk+9g870El4cB8/EJxfe+k+y0GmR9CAzkF+Nbw==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-middleware": { + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/@smithy/util-middleware/-/util-middleware-4.2.5.tgz", + "integrity": "sha512-6Y3+rvBF7+PZOc40ybeZMcGln6xJGVeY60E7jy9Mv5iKpMJpHgRE6dKy9ScsVxvfAYuEX4Q9a65DQX90KaQ3bA==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-retry": { + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/@smithy/util-retry/-/util-retry-4.2.5.tgz", + "integrity": "sha512-GBj3+EZBbN4NAqJ/7pAhsXdfzdlznOh8PydUijy6FpNIMnHPSMO2/rP4HKu+UFeikJxShERk528oy7GT79YiJg==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/service-error-classification": "^4.2.5", + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-stream": { + "version": "4.5.6", + "resolved": "https://registry.npmjs.org/@smithy/util-stream/-/util-stream-4.5.6.tgz", + "integrity": "sha512-qWw/UM59TiaFrPevefOZ8CNBKbYEP6wBAIlLqxn3VAIo9rgnTNc4ASbVrqDmhuwI87usnjhdQrxodzAGFFzbRQ==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/fetch-http-handler": "^5.3.6", + "@smithy/node-http-handler": "^4.4.5", + "@smithy/types": "^4.9.0", + "@smithy/util-base64": "^4.3.0", + "@smithy/util-buffer-from": "^4.2.0", + "@smithy/util-hex-encoding": "^4.2.0", + "@smithy/util-utf8": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-uri-escape": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@smithy/util-uri-escape/-/util-uri-escape-4.2.0.tgz", + "integrity": "sha512-igZpCKV9+E/Mzrpq6YacdTQ0qTiLm85gD6N/IrmyDvQFA4UnU3d5g3m8tMT/6zG/vVkWSU+VxeUyGonL62DuxA==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-utf8": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-4.2.0.tgz", + "integrity": "sha512-zBPfuzoI8xyBtR2P6WQj63Rz8i3AmfAaJLuNG8dWsfvPe8lO4aCPYLn879mEgHndZH1zQ2oXmG8O1GGzzaoZiw==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/util-buffer-from": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-waiter": { + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/@smithy/util-waiter/-/util-waiter-4.2.5.tgz", + "integrity": "sha512-Dbun99A3InifQdIrsXZ+QLcC0PGBPAdrl4cj1mTgJvyc9N2zf7QSxg8TBkzsCmGJdE3TLbO9ycwpY0EkWahQ/g==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/abort-controller": "^4.2.5", + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/uuid": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@smithy/uuid/-/uuid-1.1.0.tgz", + "integrity": "sha512-4aUIteuyxtBUhVdiQqcDhKFitwfd9hqoSDYY2KRXiWtgoWJ9Bmise+KfEPDiVHWeJepvF8xJO9/9+WDIciMFFw==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.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==", + "engines": { + "node": ">= 6" + } + }, + "node_modules/@types/bcryptjs": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/@types/bcryptjs/-/bcryptjs-2.4.2.tgz", + "integrity": "sha512-LiMQ6EOPob/4yUL66SZzu6Yh77cbzJFYll+ZfaPiPPFswtIlA/Fs1MzdKYA7JApHU49zQTbJGX3PDmCpIdDBRQ==", + "dev": true + }, + "node_modules/@types/body-parser": { + "version": "1.19.2", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.2.tgz", + "integrity": "sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==", + "dev": true, + "dependencies": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "node_modules/@types/connect": { + "version": "3.4.35", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz", + "integrity": "sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/cookie-parser": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/@types/cookie-parser/-/cookie-parser-1.4.3.tgz", + "integrity": "sha512-CqSKwFwefj4PzZ5n/iwad/bow2hTCh0FlNAeWLtQM3JA/NX/iYagIpWG2cf1bQKQ2c9gU2log5VUCrn7LDOs0w==", + "dev": true, + "dependencies": { + "@types/express": "*" + } + }, + "node_modules/@types/debug": { + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.7.tgz", + "integrity": "sha512-9AonUzyTjXXhEOa0DnqpzZi6VHlqKMswga9EXjpXnnqxwLtdvPPtlO8evrI5D9S6asFRCQ6v+wpiUKbw+vKqyg==", + "dependencies": { + "@types/ms": "*" + } + }, + "node_modules/@types/express": { + "version": "4.17.13", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.13.tgz", + "integrity": "sha512-6bSZTPaTIACxn48l50SR+axgrqm6qXFIxrdAKaG6PaJk3+zuUr35hBlgT7vOmJcum+OEaIBLtHV/qloEAFITeA==", + "dev": true, + "dependencies": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^4.17.18", + "@types/qs": "*", + "@types/serve-static": "*" + } + }, + "node_modules/@types/express-serve-static-core": { + "version": "4.17.28", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.28.tgz", + "integrity": "sha512-P1BJAEAW3E2DJUlkgq4tOL3RyMunoWXqbSCygWo5ZIWTjUgN1YnaXWW4VWl/oc8vs/XoYibEGBKP0uZyF4AHig==", + "dev": true, + "dependencies": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*" + } + }, + "node_modules/@types/formidable": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@types/formidable/-/formidable-2.0.5.tgz", + "integrity": "sha512-uvMcdn/KK3maPOaVUAc3HEYbCEhjaGFwww4EsX6IJfWIJ1tzHtDHczuImH3GKdusPnAAmzB07St90uabZeCKPA==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/fs-extra": { + "version": "9.0.13", + "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-9.0.13.tgz", + "integrity": "sha512-nEnwB++1u5lVDM2UI4c1+5R+FYaKfaAzS4OococimjVm3nQw3TuzH5UNsocrcTBbhnerblyHj4A49qXbIiZdpA==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/i18n": { + "version": "0.13.4", + "resolved": "https://registry.npmjs.org/@types/i18n/-/i18n-0.13.4.tgz", + "integrity": "sha512-PN4ZsplbpHZ2eaYixFNWkZKN51pcB02K2UKvqHVbrzq2jTO0sChPMuKKYAW1ZbElyHUvPgFeYsz9rqktChGyMw==", + "dev": true + }, + "node_modules/@types/json-schema": { + "version": "7.0.11", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", + "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", + "dev": true + }, + "node_modules/@types/json5": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", + "dev": true + }, + "node_modules/@types/jsonwebtoken": { + "version": "8.5.9", + "resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-8.5.9.tgz", + "integrity": "sha512-272FMnFGzAVMGtu9tkr29hRL6bZj4Zs1KZNeHLnKqAvp06tAIcarTMwOh8/8bz4FmKRcMxZhZNeUAQsNLoiPhg==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/lodash": { + "version": "4.14.195", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.195.tgz", + "integrity": "sha512-Hwx9EUgdwf2GLarOjQp5ZH8ZmblzcbTBC2wtQWNKARBSxM9ezRIAUpeDTgoQRAFB0+8CNWXVA9+MaSOzOF3nPg==", + "dev": true + }, + "node_modules/@types/long": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.1.tgz", + "integrity": "sha512-5tXH6Bx/kNGd3MgffdmP4dy2Z+G4eaXw0SE81Tq3BNadtnMR5/ySMzX4SLEzHJzSmPNn4HIdpQsBvXMUykr58w==" + }, + "node_modules/@types/mime": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz", + "integrity": "sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==", + "dev": true + }, + "node_modules/@types/minimist": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.2.tgz", + "integrity": "sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ==", + "dev": true + }, + "node_modules/@types/ms": { + "version": "0.7.31", + "resolved": "https://registry.npmjs.org/@types/ms/-/ms-0.7.31.tgz", + "integrity": "sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA==" + }, + "node_modules/@types/node": { + "version": "17.0.18", + "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.18.tgz", + "integrity": "sha512-eKj4f/BsN/qcculZiRSujogjvp5O/k4lOW5m35NopjZM/QwLOR075a8pJW5hD+Rtdm2DaCVPENS6KtSQnUD6BA==" + }, + "node_modules/@types/node-fetch": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.2.tgz", + "integrity": "sha512-DHqhlq5jeESLy19TYhLakJ07kNumXWjcDdxXsLUMJZ6ue8VZJj4kLPQVE/2mdHh3xZziNF1xppu5lwmS53HR+A==", + "dev": true, + "dependencies": { + "@types/node": "*", + "form-data": "^3.0.0" + } + }, + "node_modules/@types/node-fetch/node_modules/form-data": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz", + "integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==", + "dev": true, + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/@types/nodemailer": { + "version": "6.4.5", + "resolved": "https://registry.npmjs.org/@types/nodemailer/-/nodemailer-6.4.5.tgz", + "integrity": "sha512-zuP3nBRQHI6M2PkXnGGy1Ww4VB+MyYHGgnfV2T+JR9KLkeWqPJuyVUgLpKXuFnA/b7pZaIDFh2sV4759B7jK1g==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/normalize-package-data": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.1.tgz", + "integrity": "sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw==", + "dev": true + }, + "node_modules/@types/qs": { + "version": "6.9.7", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz", + "integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==", + "dev": true + }, + "node_modules/@types/range-parser": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.4.tgz", + "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==", + "dev": true + }, + "node_modules/@types/recursive-readdir": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@types/recursive-readdir/-/recursive-readdir-2.2.1.tgz", + "integrity": "sha512-Xd+Ptc4/F2ueInqy5yK2FI5FxtwwbX2+VZpcg+9oYsFJVen8qQKGapCr+Bi5wQtHU1cTXT8s+07lo/nKPgu8Gg==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/serve-static": { + "version": "1.13.10", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.10.tgz", + "integrity": "sha512-nCkHGI4w7ZgAdNkrEu0bv+4xNV/XDqW+DydknebMOQwkpDGx8G+HTlj7R7ABI8i8nKxVw0wtKPi1D+lPOkh4YQ==", + "dev": true, + "dependencies": { + "@types/mime": "^1", + "@types/node": "*" + } + }, + "node_modules/@types/validator": { + "version": "13.7.10", + "resolved": "https://registry.npmjs.org/@types/validator/-/validator-13.7.10.tgz", + "integrity": "sha512-t1yxFAR2n0+VO6hd/FJ9F2uezAZVWHLmpmlJzm1eX03+H7+HsuTAp7L8QJs+2pQCfWkP1+EXsGK9Z9v7o/qPVQ==" + }, + "node_modules/@types/yauzl": { + "version": "2.9.2", + "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.9.2.tgz", + "integrity": "sha512-8uALY5LTvSuHgloDVUvWP3pIauILm+8/0pDMokuDYIoNsOkSwd5AiHBTSEJjKTDcZr5z8UpgOWZkxBF4iJftoA==", + "optional": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/yazl": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/@types/yazl/-/yazl-2.4.2.tgz", + "integrity": "sha512-T+9JH8O2guEjXNxqmybzQ92mJUh2oCwDDMSSimZSe1P+pceZiFROZLYmcbqkzV5EUwz6VwcKXCO2S2yUpra6XQ==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "5.30.6", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.30.6.tgz", + "integrity": "sha512-J4zYMIhgrx4MgnZrSDD7sEnQp7FmhKNOaqaOpaoQ/SfdMfRB/0yvK74hTnvH+VQxndZynqs5/Hn4t+2/j9bADg==", + "dev": true, + "dependencies": { + "@typescript-eslint/scope-manager": "5.30.6", + "@typescript-eslint/type-utils": "5.30.6", + "@typescript-eslint/utils": "5.30.6", + "debug": "^4.3.4", + "functional-red-black-tree": "^1.0.1", + "ignore": "^5.2.0", + "regexpp": "^3.2.0", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^5.0.0", + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/semver": { + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/experimental-utils": { + "version": "5.30.6", + "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-5.30.6.tgz", + "integrity": "sha512-bqvT+0L8IjtW7MCrMgm9oVNxs4g7mESro1mm5c1/SNfTnHuFTf9OUX1WzVkTz75M9cp//UrTrSmGvK48NEKshQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/utils": "5.30.6" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "5.30.6", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.30.6.tgz", + "integrity": "sha512-gfF9lZjT0p2ZSdxO70Xbw8w9sPPJGfAdjK7WikEjB3fcUI/yr9maUVEdqigBjKincUYNKOmf7QBMiTf719kbrA==", + "dev": true, + "dependencies": { + "@typescript-eslint/scope-manager": "5.30.6", + "@typescript-eslint/types": "5.30.6", + "@typescript-eslint/typescript-estree": "5.30.6", + "debug": "^4.3.4" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/parser/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/parser/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "5.30.6", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.30.6.tgz", + "integrity": "sha512-Hkq5PhLgtVoW1obkqYH0i4iELctEKixkhWLPTYs55doGUKCASvkjOXOd/pisVeLdO24ZX9D6yymJ/twqpJiG3g==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.30.6", + "@typescript-eslint/visitor-keys": "5.30.6" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "5.30.6", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.30.6.tgz", + "integrity": "sha512-GFVVzs2j0QPpM+NTDMXtNmJKlF842lkZKDSanIxf+ArJsGeZUIaeT4jGg+gAgHt7AcQSFwW7htzF/rbAh2jaVA==", + "dev": true, + "dependencies": { + "@typescript-eslint/utils": "5.30.6", + "debug": "^4.3.4", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/type-utils/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/type-utils/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/@typescript-eslint/types": { + "version": "5.30.6", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.30.6.tgz", + "integrity": "sha512-HdnP8HioL1F7CwVmT4RaaMX57RrfqsOMclZc08wGMiDYJBsLGBM7JwXM4cZJmbWLzIR/pXg1kkrBBVpxTOwfUg==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "5.30.6", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.30.6.tgz", + "integrity": "sha512-Z7TgPoeYUm06smfEfYF0RBkpF8csMyVnqQbLYiGgmUSTaSXTP57bt8f0UFXstbGxKIreTwQCujtaH0LY9w9B+A==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.30.6", + "@typescript-eslint/visitor-keys": "5.30.6", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "5.30.6", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.30.6.tgz", + "integrity": "sha512-xFBLc/esUbLOJLk9jKv0E9gD/OH966M40aY9jJ8GiqpSkP2xOV908cokJqqhVd85WoIvHVHYXxSFE4cCSDzVvA==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.9", + "@typescript-eslint/scope-manager": "5.30.6", + "@typescript-eslint/types": "5.30.6", + "@typescript-eslint/typescript-estree": "5.30.6", + "eslint-scope": "^5.1.1", + "eslint-utils": "^3.0.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "5.30.6", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.30.6.tgz", + "integrity": "sha512-41OiCjdL2mCaSDi2SvYbzFLlqqlm5v1ZW9Ym55wXKL/Rx6OOB1IbuFGo71Fj6Xy90gJDFTlgOS+vbmtGHPTQQA==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.30.6", + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@ungap/promise-all-settled": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz", + "integrity": "sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q==", + "dev": 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==", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/acorn-walk": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", + "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/add-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/add-stream/-/add-stream-1.0.0.tgz", + "integrity": "sha1-anmQQ3ynNtXhKI25K9MmbV9csqo=", + "dev": true + }, + "node_modules/address": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/address/-/address-1.2.0.tgz", + "integrity": "sha512-tNEZYz5G/zYunxFm7sfhAxkXEuLj3K6BKwv6ZURlsF6yiUQ65z0Q2wZW9L5cPUl9ocofGvXOdFYbFHp0+6MOig==", + "engines": { + "node": ">= 10.0.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==", + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/agent-base/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/agent-base/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/agentkeepalive": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.2.1.tgz", + "integrity": "sha512-Zn4cw2NEqd+9fiSVWMscnjyQ1a8Yfoc5oBajLeo5w+YBHgDUcEBY2hS4YpTz6iN5f/2zQiktcuM6tS8x1p9dpA==", + "dependencies": { + "debug": "^4.1.0", + "depd": "^1.1.2", + "humanize-ms": "^1.2.1" + }, + "engines": { + "node": ">= 8.0.0" + } + }, + "node_modules/agentkeepalive/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/agentkeepalive/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/aggregate-error": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", + "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", + "dev": true, + "dependencies": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ajv": { + "version": "7.2.4", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-7.2.4.tgz", + "integrity": "sha512-nBeQgg/ZZA3u3SYxyaDvpvDtgZ/EZPF547ARgZBrG9Bhu1vKDwAIjtIf+sDtJUKa2zOcEbmRLBRSyMraS/Oy1A==", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-1.6.1.tgz", + "integrity": "sha512-4CjkH20If1lhR5CGtqkrVg3bbOtFEG80X9v6jDOIUhbzzbB+UzPBGy8GQhUNVZ0yvMHdMpawCOcy5ydGMsagGQ==", + "dependencies": { + "ajv": "^7.0.0" + }, + "peerDependencies": { + "ajv": "^7.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/aliyun-oss-upload-stream": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/aliyun-oss-upload-stream/-/aliyun-oss-upload-stream-1.3.0.tgz", + "integrity": "sha1-ODAbGfA0QGhDjrY5d6DNldYEcMA=" + }, + "node_modules/aliyun-sdk": { + "version": "1.12.4", + "resolved": "https://registry.npmjs.org/aliyun-sdk/-/aliyun-sdk-1.12.4.tgz", + "integrity": "sha512-g8BQkmWO3clzWMp49MuXVUKqEQl2IV19/SaIyyoQXq6e0UjqFGTZsn5PFN9C4UQeGDO9cxsGlgWZE8ZOD3Au5Q==", + "dependencies": { + "node_memcached": "1.1.3", + "pomelo-protobuf": "^0.4.0", + "protobufjs": ">=5.0.3", + "xml2js": "0.4.4", + "xmlbuilder": "^13.0.2" + }, + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/ansi-colors": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", + "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "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==", + "engines": { + "node": ">=8" + } + }, + "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==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/any-promise": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", + "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==" + }, + "node_modules/anymatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", + "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", + "dev": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/append-transform": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/append-transform/-/append-transform-2.0.0.tgz", + "integrity": "sha512-7yeyCEurROLQJFv5Xj4lEGTy0borxepjFv1g22oAdqFu//SrAlDl1O1Nxx15SH1RoliUml6p8dwJW9jvZughhg==", + "dev": true, + "dependencies": { + "default-require-extensions": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/archy": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz", + "integrity": "sha1-+cjBN1fMHde8N5rHeyxipcKGjEA=", + "dev": true + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/aria-query": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-4.2.2.tgz", + "integrity": "sha512-o/HelwhuKpTj/frsOsbNLNgnNGVIFsVP/SW2BSF14gVl7kAfMOJ6/8wUAUvG1R1NHKrfG+2sHZTu0yauT1qBrA==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.10.2", + "@babel/runtime-corejs3": "^7.10.2" + }, + "engines": { + "node": ">=6.0" + } + }, + "node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" + }, + "node_modules/array-ify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-ify/-/array-ify-1.0.0.tgz", + "integrity": "sha1-nlKHYrSpBmrRY6aWKjZEGOlibs4=", + "dev": true + }, + "node_modules/array-includes": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.5.tgz", + "integrity": "sha512-iSDYZMMyTPkiFasVqfuAQnWAYcvO/SeBSCGKePoEthjp4LEMTe4uLc7b025o4jAZpHhihh8xPo99TNWUWWkGDQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.19.5", + "get-intrinsic": "^1.1.1", + "is-string": "^1.0.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/array.prototype.flat": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.0.tgz", + "integrity": "sha512-12IUEkHsAhA4DY5s0FPgNXIdc8VRSqD9Zp78a5au9abH/SOBrsp082JOWFNTjkMozh8mqcdiKuaLGhPeYztxSw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.2", + "es-shim-unscopables": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flatmap": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.0.tgz", + "integrity": "sha512-PZC9/8TKAIxcWKdyeb77EzULHPrIX/tIZebLJUQOMR1OwYosT8yggdfWScfTBCDj5utONvOuPQQumYsU2ULbkg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.2", + "es-shim-unscopables": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/arrify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/asap": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", + "integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=" + }, + "node_modules/asn1": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz", + "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==", + "dependencies": { + "safer-buffer": "~2.1.0" + } + }, + "node_modules/assert-never": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/assert-never/-/assert-never-1.2.1.tgz", + "integrity": "sha512-TaTivMB6pYI1kXwrFlEhLeGfOqoDNdTxjCdwRfFFkEA30Eu+k48W34nlok2EYWJfFFzqaEmichdNM7th6M5HNw==" + }, + "node_modules/assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/ast-types": { + "version": "0.13.4", + "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.13.4.tgz", + "integrity": "sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w==", + "dependencies": { + "tslib": "^2.0.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/ast-types-flow": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.7.tgz", + "integrity": "sha512-eBvWn1lvIApYMhzQMsu9ciLfkBY499mFZlNqG+/9WR7PVlroQw0vG30cOQQbaKz3sCEc44TAOu2ykzqXSNnwag==", + "dev": true + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" + }, + "node_modules/atomically": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/atomically/-/atomically-1.7.0.tgz", + "integrity": "sha512-Xcz9l0z7y9yQ9rdDaxlmaI4uJHf/T8g9hOEzJcsEqX2SjCj4J20uK7+ldkDHMbpJDK76wF7xEIgxc/vSlsfw5w==", + "engines": { + "node": ">=10.12.0" + } + }, + "node_modules/aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==", + "engines": { + "node": "*" + } + }, + "node_modules/aws4": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz", + "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==" + }, + "node_modules/axe-core": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.4.3.tgz", + "integrity": "sha512-32+ub6kkdhhWick/UjvEwRchgoetXqTK14INLqbGm5U2TzBkBNF3nQtLYm8ovxSkQWArjEQvftCKryjZaATu3w==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/axobject-query": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-2.2.0.tgz", + "integrity": "sha512-Td525n+iPOOyUQIeBfcASuG6uJsDOITl7Mds5gFyerkWiX7qhUTdYUBlSgNMyVqtSJqwpt1kXGLdUt6SykLMRA==", + "dev": true + }, + "node_modules/babel-eslint": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/babel-eslint/-/babel-eslint-10.1.0.tgz", + "integrity": "sha512-ifWaTHQ0ce+448CYop8AdrQiBsGrnC+bMgfyKFdi6EsPLTAWG+QfyDeM6OH+FmWnKvEq5NnBMLvlBUPKQZoDSg==", + "deprecated": "babel-eslint is now @babel/eslint-parser. This package will no longer receive updates.", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.0.0", + "@babel/parser": "^7.7.0", + "@babel/traverse": "^7.7.0", + "@babel/types": "^7.7.0", + "eslint-visitor-keys": "^1.0.0", + "resolve": "^1.12.0" + }, + "engines": { + "node": ">=6" + }, + "peerDependencies": { + "eslint": ">= 4.12.1" + } + }, + "node_modules/babel-eslint/node_modules/eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/babel-walk": { + "version": "3.0.0-canary-5", + "resolved": "https://registry.npmjs.org/babel-walk/-/babel-walk-3.0.0-canary-5.tgz", + "integrity": "sha512-GAwkz0AihzY5bkwIY5QDR+LvsRQgB/B+1foMPvi0FZPMl5fjD7ICiznUiBdLYMH1QYe6vqu4gWYytZOccLouFw==", + "dependencies": { + "@babel/types": "^7.9.6" + }, + "engines": { + "node": ">= 10.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==" + }, + "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/bcrypt-pbkdf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==", + "dependencies": { + "tweetnacl": "^0.14.3" + } + }, + "node_modules/bcryptjs": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/bcryptjs/-/bcryptjs-2.4.3.tgz", + "integrity": "sha1-mrVie5PmBiH/fNrF2pczAn3x0Ms=" + }, + "node_modules/before": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/before/-/before-0.0.1.tgz", + "integrity": "sha512-1J5SWbkoVJH9DTALN8igB4p+nPKZzPrJ/HomqBDLpfUvDXCdjdBmBUcH5McZfur0lftVssVU6BZug5NYh87zTw==", + "engines": { + "node": "*" + } + }, + "node_modules/binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/block-stream2": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/block-stream2/-/block-stream2-2.1.0.tgz", + "integrity": "sha512-suhjmLI57Ewpmq00qaygS8UgEq2ly2PCItenIyhMqVjo4t4pGzqMvfgJuX8iWTeSDdfSSqS6j38fL4ToNL7Pfg==", + "dependencies": { + "readable-stream": "^3.4.0" + } + }, + "node_modules/body-parser": { + "version": "1.20.0", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.0.tgz", + "integrity": "sha512-DfJ+q6EPcGKZD1QWUjSpqp+Q7bDQTsQIF4zfUAtZ6qk+H/3/QRhg9CEp39ss+/T2vw0+HaidC0ecJj/DRLIaKg==", + "dependencies": { + "bytes": "3.1.2", + "content-type": "~1.0.4", + "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.10.3", + "raw-body": "2.5.1", + "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/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/body-parser/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==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/body-parser/node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/body-parser/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==", + "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/body-parser/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==", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/body-parser/node_modules/qs": { + "version": "6.10.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.3.tgz", + "integrity": "sha512-wr7M2E0OFRfIfJZjKGieI8lBKb7fRCH4Fv5KNPEs7gJ8jadvotdsS08PzOKR7opXhZ/Xkjtt3WF9g38drmyRqQ==", + "dependencies": { + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/body-parser/node_modules/raw-body": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", + "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", + "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/body-parser/node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/boolean": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/boolean/-/boolean-3.2.0.tgz", + "integrity": "sha512-d0II/GO9uf9lfUHH2BQsjxzRJZBdsjgsBiW4BvhWk/3qoKwQFjIDVN19PfX8F2D/r9PCMTtLWjYVCFrpeYUzsw==", + "deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info." + }, + "node_modules/bowser": { + "version": "2.12.1", + "resolved": "https://registry.npmjs.org/bowser/-/bowser-2.12.1.tgz", + "integrity": "sha512-z4rE2Gxh7tvshQ4hluIT7XcFrgLIQaw9X3A+kTTRdovCz5PMukm/0QC/BKSYPj3omF5Qfypn9O/c5kgpmvYUCw==", + "license": "MIT" + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browser-stdout": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", + "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", + "dev": true + }, + "node_modules/browserslist": { + "version": "4.19.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.19.1.tgz", + "integrity": "sha512-u2tbbG5PdKRTUoctO3NBD8FQ5HdPh1ZXPHzp1rwaa5jTc+RV9/+RlWiAIKmjRPQF+xbGM9Kklj5bZQFa2s/38A==", + "dev": true, + "dependencies": { + "caniuse-lite": "^1.0.30001286", + "electron-to-chromium": "^1.4.17", + "escalade": "^3.1.1", + "node-releases": "^2.0.1", + "picocolors": "^1.0.0" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + } + }, + "node_modules/buffer": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.6.0.tgz", + "integrity": "sha512-/gDYp/UtU0eA1ys8bOs9J6a+E/KWIY+DZ+Q2WESNUA0jFRsJOc0SNUO6xJ5SGA1xueg3NL65W6s+NY5l9cunuw==", + "license": "MIT", + "dependencies": { + "base64-js": "^1.0.2", + "ieee754": "^1.1.4" + } + }, + "node_modules/buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=", + "engines": { + "node": "*" + } + }, + "node_modules/buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk=" + }, + "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==", + "dev": true + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/caching-transform": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/caching-transform/-/caching-transform-4.0.0.tgz", + "integrity": "sha512-kpqOvwXnjjN44D89K5ccQC+RUrsy7jB/XLlRrx0D7/2HNcTPqzsb6XgYoErwko6QsV184CA2YgS1fxDiiDZMWA==", + "dev": true, + "dependencies": { + "hasha": "^5.0.0", + "make-dir": "^3.0.0", + "package-hash": "^4.0.0", + "write-file-atomic": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "dependencies": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + }, + "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, + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/camelcase-keys": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-6.2.2.tgz", + "integrity": "sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg==", + "dev": true, + "dependencies": { + "camelcase": "^5.3.1", + "map-obj": "^4.0.0", + "quick-lru": "^4.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/camelcase-keys/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, + "engines": { + "node": ">=6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001312", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001312.tgz", + "integrity": "sha512-Wiz1Psk2MEK0pX3rUzWaunLTZzqS2JYZFzNKqAiJGiuxIjRPLgV6+VDPOg6lQOUxmDwhTlh198JsTTi8Hzw6aQ==", + "dev": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + } + }, + "node_modules/caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==" + }, + "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==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/chalk/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==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/chalk/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==", + "dev": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/chalk/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "node_modules/character-parser": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/character-parser/-/character-parser-2.2.0.tgz", + "integrity": "sha1-x84o821LzZdE5f/CxfzeHHMmH8A=", + "dependencies": { + "is-regex": "^1.0.3" + } + }, + "node_modules/chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "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" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "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==", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/cluster-key-slot": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.0.tgz", + "integrity": "sha512-2Nii8p3RwAPiFwsnZvukotvow2rIHM+yQ6ZcBXGHdniadkYGZYiGmkHJIbZPIV9nfv7m/U1IPMVVcAhoWFeklw==", + "engines": { + "node": ">=0.10.0" + } + }, + "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==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "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==", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", + "dev": true + }, + "node_modules/compare-func": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/compare-func/-/compare-func-2.0.0.tgz", + "integrity": "sha512-zHig5N+tPWARooBnb0Zx1MFcdfpyJrfTJ3Y5L+IFvUm8rM74hHz66z0gw0x4tijh5CorKkKUCnW82R2vmpeCRA==", + "dev": true, + "dependencies": { + "array-ify": "^1.0.0", + "dot-prop": "^5.1.0" + } + }, + "node_modules/compare-func/node_modules/dot-prop": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", + "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==", + "dev": true, + "dependencies": { + "is-obj": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/component-emitter": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", + "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==", + "dev": true + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + }, + "node_modules/concat-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-2.0.0.tgz", + "integrity": "sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==", + "dev": true, + "engines": [ + "node >= 6.0" + ], + "dependencies": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.0.2", + "typedarray": "^0.0.6" + } + }, + "node_modules/concurrently": { + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/concurrently/-/concurrently-7.4.0.tgz", + "integrity": "sha512-M6AfrueDt/GEna/Vg9BqQ+93yuvzkSKmoTixnwEJkH0LlcGrRC2eCmjeG1tLLHIYfpYJABokqSGyMcXjm96AFA==", + "dev": true, + "dependencies": { + "chalk": "^4.1.0", + "date-fns": "^2.29.1", + "lodash": "^4.17.21", + "rxjs": "^7.0.0", + "shell-quote": "^1.7.3", + "spawn-command": "^0.0.2-1", + "supports-color": "^8.1.0", + "tree-kill": "^1.2.2", + "yargs": "^17.3.1" + }, + "bin": { + "conc": "dist/bin/concurrently.js", + "concurrently": "dist/bin/concurrently.js" + }, + "engines": { + "node": "^12.20.0 || ^14.13.0 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/open-cli-tools/concurrently?sponsor=1" + } + }, + "node_modules/concurrently/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, + "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/concurrently/node_modules/chalk/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/concurrently/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, + "engines": { + "node": ">=8" + } + }, + "node_modules/concurrently/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, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/conf": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/conf/-/conf-9.0.2.tgz", + "integrity": "sha512-rLSiilO85qHgaTBIIHQpsv8z+NnVfZq3cKuYNCXN1AOqPzced0GWZEe/A517VldRLyQYXUMyV+vszavE2jSAqw==", + "dependencies": { + "ajv": "^7.0.3", + "ajv-formats": "^1.5.1", + "atomically": "^1.7.0", + "debounce-fn": "^4.0.0", + "dot-prop": "^6.0.1", + "env-paths": "^2.2.0", + "json-schema-typed": "^7.0.3", + "make-dir": "^3.1.0", + "onetime": "^5.1.2", + "pkg-up": "^3.1.0", + "semver": "^7.3.4" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/confusing-browser-globals": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/confusing-browser-globals/-/confusing-browser-globals-1.0.11.tgz", + "integrity": "sha512-JsPKdmh8ZkmnHxDk55FZ1TqVLvEQTvoByJZRN9jzI0UjxK/QgAmsphz7PGtqgPieQZ/CQcHWXCR7ATDNhGe+YA==", + "dev": true + }, + "node_modules/constantinople": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/constantinople/-/constantinople-4.0.1.tgz", + "integrity": "sha512-vCrqcSIq4//Gx74TXXCGnHpulY1dskqLTFGDmhrGxzeXL8lF8kvXv6mpNWlJj1uD4DW23D4ljAqbY4RRaaUZIw==", + "dependencies": { + "@babel/parser": "^7.6.0", + "@babel/types": "^7.6.1" + } + }, + "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==", + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-type": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/conventional-changelog": { + "version": "3.1.25", + "resolved": "https://registry.npmjs.org/conventional-changelog/-/conventional-changelog-3.1.25.tgz", + "integrity": "sha512-ryhi3fd1mKf3fSjbLXOfK2D06YwKNic1nC9mWqybBHdObPd8KJ2vjaXZfYj1U23t+V8T8n0d7gwnc9XbIdFbyQ==", + "dev": true, + "dependencies": { + "conventional-changelog-angular": "^5.0.12", + "conventional-changelog-atom": "^2.0.8", + "conventional-changelog-codemirror": "^2.0.8", + "conventional-changelog-conventionalcommits": "^4.5.0", + "conventional-changelog-core": "^4.2.1", + "conventional-changelog-ember": "^2.0.9", + "conventional-changelog-eslint": "^3.0.9", + "conventional-changelog-express": "^2.0.6", + "conventional-changelog-jquery": "^3.0.11", + "conventional-changelog-jshint": "^2.0.9", + "conventional-changelog-preset-loader": "^2.3.4" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/conventional-changelog-angular": { + "version": "5.0.13", + "resolved": "https://registry.npmjs.org/conventional-changelog-angular/-/conventional-changelog-angular-5.0.13.tgz", + "integrity": "sha512-i/gipMxs7s8L/QeuavPF2hLnJgH6pEZAttySB6aiQLWcX3puWDL3ACVmvBhJGxnAy52Qc15ua26BufY6KpmrVA==", + "dev": true, + "dependencies": { + "compare-func": "^2.0.0", + "q": "^1.5.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/conventional-changelog-atom": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/conventional-changelog-atom/-/conventional-changelog-atom-2.0.8.tgz", + "integrity": "sha512-xo6v46icsFTK3bb7dY/8m2qvc8sZemRgdqLb/bjpBsH2UyOS8rKNTgcb5025Hri6IpANPApbXMg15QLb1LJpBw==", + "dev": true, + "dependencies": { + "q": "^1.5.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/conventional-changelog-codemirror": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/conventional-changelog-codemirror/-/conventional-changelog-codemirror-2.0.8.tgz", + "integrity": "sha512-z5DAsn3uj1Vfp7po3gpt2Boc+Bdwmw2++ZHa5Ak9k0UKsYAO5mH1UBTN0qSCuJZREIhX6WU4E1p3IW2oRCNzQw==", + "dev": true, + "dependencies": { + "q": "^1.5.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/conventional-changelog-config-spec": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/conventional-changelog-config-spec/-/conventional-changelog-config-spec-2.1.0.tgz", + "integrity": "sha512-IpVePh16EbbB02V+UA+HQnnPIohgXvJRxHcS5+Uwk4AT5LjzCZJm5sp/yqs5C6KZJ1jMsV4paEV13BN1pvDuxQ==", + "dev": true + }, + "node_modules/conventional-changelog-conventionalcommits": { + "version": "4.6.3", + "resolved": "https://registry.npmjs.org/conventional-changelog-conventionalcommits/-/conventional-changelog-conventionalcommits-4.6.3.tgz", + "integrity": "sha512-LTTQV4fwOM4oLPad317V/QNQ1FY4Hju5qeBIM1uTHbrnCE+Eg4CdRZ3gO2pUeR+tzWdp80M2j3qFFEDWVqOV4g==", + "dev": true, + "dependencies": { + "compare-func": "^2.0.0", + "lodash": "^4.17.15", + "q": "^1.5.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/conventional-changelog-core": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/conventional-changelog-core/-/conventional-changelog-core-4.2.4.tgz", + "integrity": "sha512-gDVS+zVJHE2v4SLc6B0sLsPiloR0ygU7HaDW14aNJE1v4SlqJPILPl/aJC7YdtRE4CybBf8gDwObBvKha8Xlyg==", + "dev": true, + "dependencies": { + "add-stream": "^1.0.0", + "conventional-changelog-writer": "^5.0.0", + "conventional-commits-parser": "^3.2.0", + "dateformat": "^3.0.0", + "get-pkg-repo": "^4.0.0", + "git-raw-commits": "^2.0.8", + "git-remote-origin-url": "^2.0.0", + "git-semver-tags": "^4.1.1", + "lodash": "^4.17.15", + "normalize-package-data": "^3.0.0", + "q": "^1.5.1", + "read-pkg": "^3.0.0", + "read-pkg-up": "^3.0.0", + "through2": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/conventional-changelog-ember": { + "version": "2.0.9", + "resolved": "https://registry.npmjs.org/conventional-changelog-ember/-/conventional-changelog-ember-2.0.9.tgz", + "integrity": "sha512-ulzIReoZEvZCBDhcNYfDIsLTHzYHc7awh+eI44ZtV5cx6LVxLlVtEmcO+2/kGIHGtw+qVabJYjdI5cJOQgXh1A==", + "dev": true, + "dependencies": { + "q": "^1.5.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/conventional-changelog-eslint": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/conventional-changelog-eslint/-/conventional-changelog-eslint-3.0.9.tgz", + "integrity": "sha512-6NpUCMgU8qmWmyAMSZO5NrRd7rTgErjrm4VASam2u5jrZS0n38V7Y9CzTtLT2qwz5xEChDR4BduoWIr8TfwvXA==", + "dev": true, + "dependencies": { + "q": "^1.5.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/conventional-changelog-express": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/conventional-changelog-express/-/conventional-changelog-express-2.0.6.tgz", + "integrity": "sha512-SDez2f3iVJw6V563O3pRtNwXtQaSmEfTCaTBPCqn0oG0mfkq0rX4hHBq5P7De2MncoRixrALj3u3oQsNK+Q0pQ==", + "dev": true, + "dependencies": { + "q": "^1.5.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/conventional-changelog-jquery": { + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/conventional-changelog-jquery/-/conventional-changelog-jquery-3.0.11.tgz", + "integrity": "sha512-x8AWz5/Td55F7+o/9LQ6cQIPwrCjfJQ5Zmfqi8thwUEKHstEn4kTIofXub7plf1xvFA2TqhZlq7fy5OmV6BOMw==", + "dev": true, + "dependencies": { + "q": "^1.5.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/conventional-changelog-jshint": { + "version": "2.0.9", + "resolved": "https://registry.npmjs.org/conventional-changelog-jshint/-/conventional-changelog-jshint-2.0.9.tgz", + "integrity": "sha512-wMLdaIzq6TNnMHMy31hql02OEQ8nCQfExw1SE0hYL5KvU+JCTuPaDO+7JiogGT2gJAxiUGATdtYYfh+nT+6riA==", + "dev": true, + "dependencies": { + "compare-func": "^2.0.0", + "q": "^1.5.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/conventional-changelog-preset-loader": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/conventional-changelog-preset-loader/-/conventional-changelog-preset-loader-2.3.4.tgz", + "integrity": "sha512-GEKRWkrSAZeTq5+YjUZOYxdHq+ci4dNwHvpaBC3+ENalzFWuCWa9EZXSuZBpkr72sMdKB+1fyDV4takK1Lf58g==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/conventional-changelog-writer": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/conventional-changelog-writer/-/conventional-changelog-writer-5.0.1.tgz", + "integrity": "sha512-5WsuKUfxW7suLblAbFnxAcrvf6r+0b7GvNaWUwUIk0bXMnENP/PEieGKVUQrjPqwPT4o3EPAASBXiY6iHooLOQ==", + "dev": true, + "dependencies": { + "conventional-commits-filter": "^2.0.7", + "dateformat": "^3.0.0", + "handlebars": "^4.7.7", + "json-stringify-safe": "^5.0.1", + "lodash": "^4.17.15", + "meow": "^8.0.0", + "semver": "^6.0.0", + "split": "^1.0.0", + "through2": "^4.0.0" + }, + "bin": { + "conventional-changelog-writer": "cli.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/conventional-changelog-writer/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/conventional-commits-filter": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/conventional-commits-filter/-/conventional-commits-filter-2.0.7.tgz", + "integrity": "sha512-ASS9SamOP4TbCClsRHxIHXRfcGCnIoQqkvAzCSbZzTFLfcTqJVugB0agRgsEELsqaeWgsXv513eS116wnlSSPA==", + "dev": true, + "dependencies": { + "lodash.ismatch": "^4.4.0", + "modify-values": "^1.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/conventional-commits-parser": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/conventional-commits-parser/-/conventional-commits-parser-3.2.4.tgz", + "integrity": "sha512-nK7sAtfi+QXbxHCYfhpZsfRtaitZLIA6889kFIouLvz6repszQDgxBu7wf2WbU+Dco7sAnNCJYERCwt54WPC2Q==", + "dev": true, + "dependencies": { + "is-text-path": "^1.0.1", + "JSONStream": "^1.0.4", + "lodash": "^4.17.15", + "meow": "^8.0.0", + "split2": "^3.0.0", + "through2": "^4.0.0" + }, + "bin": { + "conventional-commits-parser": "cli.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/conventional-recommended-bump": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/conventional-recommended-bump/-/conventional-recommended-bump-6.1.0.tgz", + "integrity": "sha512-uiApbSiNGM/kkdL9GTOLAqC4hbptObFo4wW2QRyHsKciGAfQuLU1ShZ1BIVI/+K2BE/W1AWYQMCXAsv4dyKPaw==", + "dev": true, + "dependencies": { + "concat-stream": "^2.0.0", + "conventional-changelog-preset-loader": "^2.3.4", + "conventional-commits-filter": "^2.0.7", + "conventional-commits-parser": "^3.2.0", + "git-raw-commits": "^2.0.8", + "git-semver-tags": "^4.1.1", + "meow": "^8.0.0", + "q": "^1.5.1" + }, + "bin": { + "conventional-recommended-bump": "cli.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/convert-source-map": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz", + "integrity": "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.1.1" + } + }, + "node_modules/convert-source-map/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==", + "dev": true + }, + "node_modules/cookie": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.1.tgz", + "integrity": "sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-parser": { + "version": "1.4.6", + "resolved": "https://registry.npmjs.org/cookie-parser/-/cookie-parser-1.4.6.tgz", + "integrity": "sha512-z3IzaNjdwUC2olLIB5/ITd0/setiaFMLYiZJle7xg5Fe9KWAceil7xszYfHHBtDFYLSgJduS2Ty0P1uJdPDJeA==", + "dependencies": { + "cookie": "0.4.1", + "cookie-signature": "1.0.6" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" + }, + "node_modules/cookiejar": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.3.tgz", + "integrity": "sha512-JxbCBUdrfr6AQjOXrxoTvAMJO4HBTUIlBzslcJPAz+/KT8yk53fXun51u+RenNYvad/+Vc2DIz5o9UxlCDymFQ==", + "dev": true + }, + "node_modules/copy-to": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/copy-to/-/copy-to-2.0.1.tgz", + "integrity": "sha512-3DdaFaU/Zf1AnpLiFDeNCD4TOWe3Zl2RZaTzUvWiIk5ERzcCodOE20Vqq4fzCbNoHURFHT4/us/Lfq+S2zyY4w==" + }, + "node_modules/core-js-pure": { + "version": "3.23.4", + "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.23.4.tgz", + "integrity": "sha512-lizxkcgj3XDmi7TUBFe+bQ1vNpD5E4t76BrBWI3HdUxdw/Mq1VF4CkiHzIKyieECKtcODK2asJttoofEeUKICQ==", + "dev": true, + "hasInstallScript": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" + }, + "node_modules/cos-nodejs-sdk-v5": { + "version": "2.11.12", + "resolved": "https://registry.npmjs.org/cos-nodejs-sdk-v5/-/cos-nodejs-sdk-v5-2.11.12.tgz", + "integrity": "sha512-XtSlcrwgcyO8K0LCwNmimtkBErC1yJ55cvZ7nWFWsT0c2AWBw8F/ftGvUhZIZhh7B2SlPdXsFZg+QOU7cwI2GQ==", + "dependencies": { + "conf": "^9.0.0", + "mime-types": "^2.1.24", + "request": "^2.88.2", + "xml2js": "^0.4.19" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/cos-nodejs-sdk-v5/node_modules/xml2js": { + "version": "0.4.23", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz", + "integrity": "sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==", + "dependencies": { + "sax": ">=0.6.0", + "xmlbuilder": "~11.0.0" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/cos-nodejs-sdk-v5/node_modules/xmlbuilder": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", + "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/crc32": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/crc32/-/crc32-0.2.2.tgz", + "integrity": "sha512-PFZEGbDUeoNbL2GHIEpJRQGheXReDody/9axKTxhXtQqIL443wnNigtVZO9iuCIMPApKZRv7k2xr8euXHqNxQQ==", + "bin": { + "crc32": "bin/runner.js" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/damerau-levenshtein": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz", + "integrity": "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==", + "dev": true + }, + "node_modules/dargs": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/dargs/-/dargs-7.0.0.tgz", + "integrity": "sha512-2iy1EkLdlBzQGvbweYRFxmFath8+K7+AKB0TlhHWkNuH+TmovaMH/Wp7V7R4u7f4SnX3OgLsU9t1NI9ioDnUpg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==", + "dependencies": { + "assert-plus": "^1.0.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/data-uri-to-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-3.0.1.tgz", + "integrity": "sha512-WboRycPNsVw3B3TL559F7kuBUM4d8CgMEvk6xEJlOp7OBPjt6G7z8WMWlD2rOFZLk6OYfFIUGsCOWzcQH9K2og==", + "engines": { + "node": ">= 6" + } + }, + "node_modules/date-fns": { + "version": "2.29.2", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.29.2.tgz", + "integrity": "sha512-0VNbwmWJDS/G3ySwFSJA3ayhbURMTJLtwM2DTxf9CWondCnh6DTNlO9JgRSq6ibf4eD0lfMJNBxUdEAHHix+bA==", + "dev": true, + "engines": { + "node": ">=0.11" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/date-fns" + } + }, + "node_modules/dateformat": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-3.0.3.tgz", + "integrity": "sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/debounce-fn": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/debounce-fn/-/debounce-fn-4.0.0.tgz", + "integrity": "sha512-8pYCQiL9Xdcg0UPSD3d+0KMlOjp+KGU5EPwYddgzQ7DATsg4fuUDjQtsYLmWjnk2obnNHgV3vE2Y4jejSOJVBQ==", + "dependencies": { + "mimic-fn": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/decamelize": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", + "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/decamelize-keys": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/decamelize-keys/-/decamelize-keys-1.1.0.tgz", + "integrity": "sha1-0XGoeTMlKAfrPLYdwcFEXQeN8tk=", + "dev": true, + "dependencies": { + "decamelize": "^1.1.0", + "map-obj": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/decamelize-keys/node_modules/decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/decamelize-keys/node_modules/map-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", + "integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==" + }, + "node_modules/default-require-extensions": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/default-require-extensions/-/default-require-extensions-3.0.0.tgz", + "integrity": "sha512-ek6DpXq/SCpvjhpFsLFRVtIxJCRw6fUR42lYMVZuUMK7n8eMz4Uh5clckdBjEpLhn/gEBZo7hDJnJcwdKLKQjg==", + "dev": true, + "dependencies": { + "strip-bom": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/default-require-extensions/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, + "engines": { + "node": ">=8" + } + }, + "node_modules/default-user-agent": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/default-user-agent/-/default-user-agent-1.0.0.tgz", + "integrity": "sha512-bDF7bg6OSNcSwFWPu4zYKpVkJZQYVrAANMYB8bc9Szem1D0yKdm4sa/rOCs2aC9+2GMqQ7KnwtZRvDhmLF0dXw==", + "dependencies": { + "os-name": "~1.0.3" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/define-properties": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.4.tgz", + "integrity": "sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA==", + "dev": true, + "dependencies": { + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/degenerator": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/degenerator/-/degenerator-3.0.2.tgz", + "integrity": "sha512-c0mef3SNQo56t6urUU6tdQAs+ThoD0o9B9MJ8HEt7NQcGEILCRFqQb7ZbP9JAv+QF1Ky5plydhMR/IrqWDm+TQ==", + "dependencies": { + "ast-types": "^0.13.2", + "escodegen": "^1.8.1", + "esprima": "^4.0.0", + "vm2": "^3.9.8" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/denque": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/denque/-/denque-2.0.1.tgz", + "integrity": "sha512-tfiWc6BQLXNLpNiR5iGd0Ocu3P3VpxfzFiqubLgMfhfOw9WyvgJBd46CClNn9k3qfbjvT//0cf7AlYRX/OslMQ==", + "engines": { + "node": ">=0.10" + } + }, + "node_modules/depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/detect-indent": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-6.1.0.tgz", + "integrity": "sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==", + "dev": 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, + "engines": { + "node": ">=8" + } + }, + "node_modules/dezalgo": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.3.tgz", + "integrity": "sha1-f3Qt4Gb8dIvI24IFad3c5Jvw1FY=", + "dependencies": { + "asap": "^2.0.0", + "wrappy": "1" + } + }, + "node_modules/diff": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", + "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/digest-header": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/digest-header/-/digest-header-0.0.1.tgz", + "integrity": "sha512-Qi0KOZgRnkQJuvMWbs1ZRRajEnbsMU8xlJI4rHIbPC+skHQ30heO5cIHpUFT4jAvAe+zPtdavLSAxASqoyZ3cg==", + "dependencies": { + "utility": "0.1.11" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/digest-header/node_modules/utility": { + "version": "0.1.11", + "resolved": "https://registry.npmjs.org/utility/-/utility-0.1.11.tgz", + "integrity": "sha1-/eYM+bTkdRlHoM9dEEzik2ciZxU=", + "dependencies": { + "address": ">=0.0.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/doctypes": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/doctypes/-/doctypes-1.1.0.tgz", + "integrity": "sha1-6oCxBqh1OHdOijpKWv4pPeSJ4Kk=" + }, + "node_modules/dot-prop": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-6.0.1.tgz", + "integrity": "sha512-tE7ztYzXHIeyvc7N+hR3oi7FIbf/NIjVP9hmAt3yMXzrQ072/fpjGLx2GxNxGxUl5V73MEqYzioOMoVhGMJ5cA==", + "dependencies": { + "is-obj": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/dotenv": { + "version": "17.2.3", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.2.3.tgz", + "integrity": "sha512-JVUnt+DUIzu87TABbhPmNfVdBDt18BLOWjMUFJMSi/Qqg7NTYtabbvSNJGOJ7afbRuv9D/lngizHtP7QyLQ+9w==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, + "node_modules/dotgitignore": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/dotgitignore/-/dotgitignore-2.1.0.tgz", + "integrity": "sha512-sCm11ak2oY6DglEPpCB8TixLjWAxd3kJTs6UIcSasNYxXdFPV+YKlye92c8H4kKFqV5qYMIh7d+cYecEg0dIkA==", + "dev": true, + "dependencies": { + "find-up": "^3.0.0", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/dottie": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/dottie/-/dottie-2.0.2.tgz", + "integrity": "sha512-fmrwR04lsniq/uSr8yikThDTrM7epXHBAAjH9TbeH3rEA8tdCO7mRzB9hdmdGyJCxF8KERo9CITcm3kGuoyMhg==" + }, + "node_modules/ecc-jsbn": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", + "integrity": "sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==", + "dependencies": { + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" + } + }, + "node_modules/ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" + }, + "node_modules/electron-to-chromium": { + "version": "1.4.71", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.71.tgz", + "integrity": "sha512-Hk61vXXKRb2cd3znPE9F+2pLWdIOmP7GjiTj45y6L3W/lO+hSnUSUhq+6lEaERWBdZOHbk2s3YV5c9xVl3boVw==", + "dev": true + }, + "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==" + }, + "node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", + "engines": { + "node": ">=6" + } + }, + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/es-abstract": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.20.1.tgz", + "integrity": "sha512-WEm2oBhfoI2sImeM4OF2zE2V3BYdSF+KnSi9Sidz51fQHd7+JuF8Xgcj9/0o+OWeIeIS/MiuNnlruQrJf16GQA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "function.prototype.name": "^1.1.5", + "get-intrinsic": "^1.1.1", + "get-symbol-description": "^1.0.0", + "has": "^1.0.3", + "has-property-descriptors": "^1.0.0", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.3", + "is-callable": "^1.2.4", + "is-negative-zero": "^2.0.2", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.2", + "is-string": "^1.0.7", + "is-weakref": "^1.0.2", + "object-inspect": "^1.12.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.2", + "regexp.prototype.flags": "^1.4.3", + "string.prototype.trimend": "^1.0.5", + "string.prototype.trimstart": "^1.0.5", + "unbox-primitive": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-abstract/node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-shim-unscopables": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz", + "integrity": "sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==", + "dev": true, + "dependencies": { + "has": "^1.0.3" + } + }, + "node_modules/es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "dependencies": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es6-error": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz", + "integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==", + "dev": true + }, + "node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "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": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" + }, + "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": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/escodegen": { + "version": "1.14.3", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.14.3.tgz", + "integrity": "sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw==", + "dependencies": { + "esprima": "^4.0.1", + "estraverse": "^4.2.0", + "esutils": "^2.0.2", + "optionator": "^0.8.1" + }, + "bin": { + "escodegen": "bin/escodegen.js", + "esgenerate": "bin/esgenerate.js" + }, + "engines": { + "node": ">=4.0" + }, + "optionalDependencies": { + "source-map": "~0.6.1" + } + }, + "node_modules/eslint": { + "version": "8.19.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.19.0.tgz", + "integrity": "sha512-SXOPj3x9VKvPe81TjjUJCYlV4oJjQw68Uek+AM0X4p+33dj2HY5bpTZOgnQHcG2eAm1mtCU9uNMnJi7exU/kYw==", + "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.", + "dev": true, + "dependencies": { + "@eslint/eslintrc": "^1.3.0", + "@humanwhocodes/config-array": "^0.9.2", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.1.1", + "eslint-utils": "^3.0.0", + "eslint-visitor-keys": "^3.3.0", + "espree": "^9.3.2", + "esquery": "^1.4.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^6.0.1", + "globals": "^13.15.0", + "ignore": "^5.2.0", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.1", + "regexpp": "^3.2.0", + "strip-ansi": "^6.0.1", + "strip-json-comments": "^3.1.0", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-config-airbnb-base": { + "version": "15.0.0", + "resolved": "https://registry.npmjs.org/eslint-config-airbnb-base/-/eslint-config-airbnb-base-15.0.0.tgz", + "integrity": "sha512-xaX3z4ZZIcFLvh2oUNvcX5oEofXda7giYmuplVxoOg5A7EXJMrUyqRgR+mhDhPK8LZ4PttFOBvCYDbX3sUoUig==", + "dev": true, + "dependencies": { + "confusing-browser-globals": "^1.0.10", + "object.assign": "^4.1.2", + "object.entries": "^1.1.5", + "semver": "^6.3.0" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + }, + "peerDependencies": { + "eslint": "^7.32.0 || ^8.2.0", + "eslint-plugin-import": "^2.25.2" + } + }, + "node_modules/eslint-config-airbnb-base/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/eslint-config-prettier": { + "version": "8.5.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.5.0.tgz", + "integrity": "sha512-obmWKLUNCnhtQRKc+tmnYuQl0pFU1ibYJQ5BGhTVB08bHe9wC8qUeG7c08dj9XX+AuPj1YSGSQIHl1pnDHZR0Q==", + "dev": true, + "bin": { + "eslint-config-prettier": "bin/cli.js" + }, + "peerDependencies": { + "eslint": ">=7.0.0" + } + }, + "node_modules/eslint-import-resolver-node": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.6.tgz", + "integrity": "sha512-0En0w03NRVMn9Uiyn8YRPDKvWjxCWkslUEhGNTdGx15RvPJYQ+lbOlqrlNI2vEAs4pDYK4f/HN2TbDmk5TP0iw==", + "dev": true, + "dependencies": { + "debug": "^3.2.7", + "resolve": "^1.20.0" + } + }, + "node_modules/eslint-import-resolver-node/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-import-resolver-node/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==", + "dev": true + }, + "node_modules/eslint-import-resolver-typescript": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-2.7.1.tgz", + "integrity": "sha512-00UbgGwV8bSgUv34igBDbTOtKhqoRMy9bFjNehT40bXg6585PNIct8HhXZ0SybqB9rWtXj9crcku8ndDn/gIqQ==", + "dev": true, + "dependencies": { + "debug": "^4.3.4", + "glob": "^7.2.0", + "is-glob": "^4.0.3", + "resolve": "^1.22.0", + "tsconfig-paths": "^3.14.1" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "*", + "eslint-plugin-import": "*" + } + }, + "node_modules/eslint-import-resolver-typescript/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/eslint-import-resolver-typescript/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/eslint-module-utils": { + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.7.3.tgz", + "integrity": "sha512-088JEC7O3lDZM9xGe0RerkOMd0EjFl+Yvd1jPWIkMT5u3H9+HC34mWWPnqPrN13gieT9pBOO+Qt07Nb/6TresQ==", + "dev": true, + "dependencies": { + "debug": "^3.2.7", + "find-up": "^2.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-module-utils/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-module-utils/node_modules/find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha512-NWzkk0jSJtTt08+FBFMvXoeZnOJD+jTtsRmBYbAIzJdX6l7dLgR7CTubCM5/eDdPUBvLCeVasP1brfVR/9/EZQ==", + "dev": true, + "dependencies": { + "locate-path": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-module-utils/node_modules/locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha512-NCI2kiDkyR7VeEKm27Kda/iQHyKJe1Bu0FlTbYp3CqJu+9IFe9bLyAjMxf5ZDDbEg+iMPzB5zYyUTSm8wVTKmA==", + "dev": true, + "dependencies": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-module-utils/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==", + "dev": true + }, + "node_modules/eslint-module-utils/node_modules/p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dev": true, + "dependencies": { + "p-try": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-module-utils/node_modules/p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha512-nQja7m7gSKuewoVRen45CtVfODR3crN3goVQ0DDZ9N3yHxgpkuBhZqsaiotSQRrADUrne346peY7kT3TSACykg==", + "dev": true, + "dependencies": { + "p-limit": "^1.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-module-utils/node_modules/p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha512-U1etNYuMJoIz3ZXSrrySFjsXQTWOx2/jdi86L+2pRvph/qMKL6sbcCYdH23fqsbm8TH2Gn0OybpT4eSFlCVHww==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-plugin-deprecation": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-deprecation/-/eslint-plugin-deprecation-1.3.2.tgz", + "integrity": "sha512-z93wbx9w7H/E3ogPw6AZMkkNJ6m51fTZRNZPNQqxQLmx+KKt7aLkMU9wN67s71i+VVHN4tLOZ3zT3QLbnlC0Mg==", + "dev": true, + "dependencies": { + "@typescript-eslint/experimental-utils": "^5.0.0", + "tslib": "^2.3.1", + "tsutils": "^3.21.0" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0", + "typescript": "^3.7.5 || ^4.0.0" + } + }, + "node_modules/eslint-plugin-import": { + "version": "2.26.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.26.0.tgz", + "integrity": "sha512-hYfi3FXaM8WPLf4S1cikh/r4IxnO6zrhZbEGz2b660EJRbuxgpDS5gkCuYgGWg2xxh2rBuIr4Pvhve/7c31koA==", + "dev": true, + "dependencies": { + "array-includes": "^3.1.4", + "array.prototype.flat": "^1.2.5", + "debug": "^2.6.9", + "doctrine": "^2.1.0", + "eslint-import-resolver-node": "^0.3.6", + "eslint-module-utils": "^2.7.3", + "has": "^1.0.3", + "is-core-module": "^2.8.1", + "is-glob": "^4.0.3", + "minimatch": "^3.1.2", + "object.values": "^1.1.5", + "resolve": "^1.22.0", + "tsconfig-paths": "^3.14.1" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8" + } + }, + "node_modules/eslint-plugin-import/node_modules/doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint-plugin-import/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/eslint-plugin-jsx-a11y": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.6.0.tgz", + "integrity": "sha512-kTeLuIzpNhXL2CwLlc8AHI0aFRwWHcg483yepO9VQiHzM9bZwJdzTkzBszbuPrbgGmq2rlX/FaT2fJQsjUSHsw==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.18.3", + "aria-query": "^4.2.2", + "array-includes": "^3.1.5", + "ast-types-flow": "^0.0.7", + "axe-core": "^4.4.2", + "axobject-query": "^2.2.0", + "damerau-levenshtein": "^1.0.8", + "emoji-regex": "^9.2.2", + "has": "^1.0.3", + "jsx-ast-utils": "^3.3.1", + "language-tags": "^1.0.5", + "minimatch": "^3.1.2", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=4.0" + }, + "peerDependencies": { + "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8" + } + }, + "node_modules/eslint-plugin-jsx-a11y/node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true + }, + "node_modules/eslint-plugin-jsx-a11y/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/eslint-plugin-jsx-a11y/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/eslint-plugin-prettier": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-4.2.1.tgz", + "integrity": "sha512-f/0rXLXUt0oFYs8ra4w49wYZBG5GKZpAYsJSm6rnYL5uVDjd+zowwMwVZHnAjf4edNrKpCDYfXDgmRE/Ak7QyQ==", + "dev": true, + "dependencies": { + "prettier-linter-helpers": "^1.0.0" + }, + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "eslint": ">=7.28.0", + "prettier": ">=2.0.0" + }, + "peerDependenciesMeta": { + "eslint-config-prettier": { + "optional": true + } + } + }, + "node_modules/eslint-plugin-react": { + "version": "7.30.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.30.1.tgz", + "integrity": "sha512-NbEvI9jtqO46yJA3wcRF9Mo0lF9T/jhdHqhCHXiXtD+Zcb98812wvokjWpU7Q4QH5edo6dmqrukxVvWWXHlsUg==", + "dev": true, + "dependencies": { + "array-includes": "^3.1.5", + "array.prototype.flatmap": "^1.3.0", + "doctrine": "^2.1.0", + "estraverse": "^5.3.0", + "jsx-ast-utils": "^2.4.1 || ^3.0.0", + "minimatch": "^3.1.2", + "object.entries": "^1.1.5", + "object.fromentries": "^2.0.5", + "object.hasown": "^1.1.1", + "object.values": "^1.1.5", + "prop-types": "^15.8.1", + "resolve": "^2.0.0-next.3", + "semver": "^6.3.0", + "string.prototype.matchall": "^4.0.7" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8" + } + }, + "node_modules/eslint-plugin-react-hooks": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.0.tgz", + "integrity": "sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g==", + "dev": true, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0" + } + }, + "node_modules/eslint-plugin-react-native": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-native/-/eslint-plugin-react-native-4.0.0.tgz", + "integrity": "sha512-kMmdxrSY7A1WgdqaGC+rY/28rh7kBGNBRsk48ovqkQmdg5j4K+DaFmegENDzMrdLkoufKGRNkKX6bgSwQTCAxQ==", + "dev": true, + "dependencies": { + "@babel/traverse": "^7.7.4", + "eslint-plugin-react-native-globals": "^0.1.1" + }, + "peerDependencies": { + "eslint": "^3.17.0 || ^4 || ^5 || ^6 || ^7 || ^8" + } + }, + "node_modules/eslint-plugin-react-native-globals": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-native-globals/-/eslint-plugin-react-native-globals-0.1.2.tgz", + "integrity": "sha512-9aEPf1JEpiTjcFAmmyw8eiIXmcNZOqaZyHO77wgm0/dWfT/oxC1SrIq8ET38pMxHYrcB6Uew+TzUVsBeczF88g==", + "dev": true + }, + "node_modules/eslint-plugin-react/node_modules/doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint-plugin-react/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, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/eslint-plugin-react/node_modules/is-core-module": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.9.0.tgz", + "integrity": "sha512-+5FPy5PnwmO3lvfMb0AsoPaBG+5KHUI0wYFXOtYPnVVVspTFUuMZNfNaNVRt3FZadstu2c8x23vykRW/NBoU6A==", + "dev": true, + "dependencies": { + "has": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/eslint-plugin-react/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/eslint-plugin-react/node_modules/resolve": { + "version": "2.0.0-next.4", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.4.tgz", + "integrity": "sha512-iMDbmAWtfU+MHpxt/I5iWI7cY6YVEZUQ3MBgPQ++XD1PELuJHIl82xBmObyP2KyQmkNB2dsqF7seoQQiAn5yDQ==", + "dev": true, + "dependencies": { + "is-core-module": "^2.9.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/eslint-plugin-react/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/eslint-plugin-taro": { + "version": "3.3.20", + "resolved": "https://registry.npmjs.org/eslint-plugin-taro/-/eslint-plugin-taro-3.3.20.tgz", + "integrity": "sha512-Pse/peAk2s+6DTrD9VnkE4IcHQZ4JWgIKI3tcYbt7pPbAtNWSQJd0+IKAwqvxmNoGepsr5o5JeYOIXVsdZzMPg==", + "dev": true, + "dependencies": { + "has": "^1.0.1" + }, + "peerDependencies": { + "babel-eslint": "*", + "eslint": "*" + } + }, + "node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/eslint-utils": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", + "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^2.0.0" + }, + "engines": { + "node": "^10.0.0 || ^12.0.0 || >= 14.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + }, + "peerDependencies": { + "eslint": ">=5" + } + }, + "node_modules/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", + "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/eslint/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/eslint/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, + "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/eslint/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/eslint/node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/eslint-scope": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", + "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/eslint/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, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/eslint/node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/eslint/node_modules/globals": { + "version": "13.16.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.16.0.tgz", + "integrity": "sha512-A1lrQfpNF+McdPOnnFqY3kSN0AFTy485bTi1bkLk4mVPODIUEcSfhHgRqA+QdXPksrSTTztYXx37NFV+GpGk3Q==", + "dev": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/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, + "engines": { + "node": ">=8" + } + }, + "node_modules/eslint/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/eslint/node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/eslint/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/eslint/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/eslint/node_modules/optionator": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", + "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "dev": true, + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.3" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/eslint/node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/eslint/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, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/eslint/node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/espree": { + "version": "9.3.2", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.3.2.tgz", + "integrity": "sha512-D211tC7ZwouTIuY5x9XnS0E9sWNChB7IYKX/Xp5eQj3nFXhqmiUDB9q27y76oFl8jTg3pXcQx/bpxMfs3CIZbA==", + "dev": true, + "dependencies": { + "acorn": "^8.7.1", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/espree/node_modules/acorn": { + "version": "8.7.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.1.tgz", + "integrity": "sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "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==", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/esquery": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", + "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", + "dev": true, + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esquery/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, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse/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, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "license": "MIT", + "engines": { + "node": ">=0.8.x" + } + }, + "node_modules/express": { + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/express/-/express-4.18.1.tgz", + "integrity": "sha512-zZBcOX9TfehHQhtupq57OF8lFZ3UZi08Y97dwFCkD8p9d/d2Y3M+ykKcwaMDEL+4qyUolgBDX6AblpR3fL212Q==", + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.0", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.5.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~1.0.2", + "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.1", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.7", + "qs": "6.10.3", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.18.0", + "serve-static": "1.15.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/cookie": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", + "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/express/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==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/express/node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" + }, + "node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/extract-zip": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz", + "integrity": "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==", + "dependencies": { + "debug": "^4.1.1", + "get-stream": "^5.1.0", + "yauzl": "^2.10.0" + }, + "bin": { + "extract-zip": "cli.js" + }, + "engines": { + "node": ">= 10.17.0" + }, + "optionalDependencies": { + "@types/yauzl": "^2.9.1" + } + }, + "node_modules/extract-zip/node_modules/debug": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", + "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/extract-zip/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==", + "engines": [ + "node >=0.6.0" + ] + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" + }, + "node_modules/fast-diff": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.2.0.tgz", + "integrity": "sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==", + "dev": true + }, + "node_modules/fast-glob": { + "version": "3.2.11", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz", + "integrity": "sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew==", + "dev": true, + "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.4" + }, + "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==" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=" + }, + "node_modules/fast-printf": { + "version": "1.6.9", + "resolved": "https://registry.npmjs.org/fast-printf/-/fast-printf-1.6.9.tgz", + "integrity": "sha512-FChq8hbz65WMj4rstcQsFB0O7Cy++nmbNfLYnD9cYv2cRn8EG6k/MGn9kO/tjO66t09DLDugj3yL+V2o6Qftrg==", + "dependencies": { + "boolean": "^3.1.4" + }, + "engines": { + "node": ">=10.0" + } + }, + "node_modules/fast-safe-stringify": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz", + "integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==", + "dev": true + }, + "node_modules/fast-xml-parser": { + "version": "5.2.5", + "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-5.2.5.tgz", + "integrity": "sha512-pfX9uG9Ki0yekDHx2SiuRIyFdyAr1kMIMitPvb0YBo8SUfKvia7w7FIyd/l6av85pFYRhZscS75MwMnbvY+hcQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT", + "dependencies": { + "strnum": "^2.1.0" + }, + "bin": { + "fxparser": "src/cli/cli.js" + } + }, + "node_modules/fastq": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", + "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", + "dev": true, + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fd-slicer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", + "integrity": "sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4=", + "dependencies": { + "pend": "~1.2.0" + } + }, + "node_modules/figures": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", + "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", + "dev": true, + "dependencies": { + "escape-string-regexp": "^1.0.5" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/file-uri-to-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-2.0.0.tgz", + "integrity": "sha512-hjPFI8oE/2iQPVe4gbrJ73Pp+Xfub2+WI2LlXDbsaJBwT5wuMh35WNWVYYTpnz895shtwfyutMFLFywpQAFdLg==", + "engines": { + "node": ">= 6" + } + }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "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==", + "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/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/find-cache-dir": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz", + "integrity": "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==", + "dev": true, + "dependencies": { + "commondir": "^1.0.1", + "make-dir": "^3.0.2", + "pkg-dir": "^4.1.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/avajs/find-cache-dir?sponsor=1" + } + }, + "node_modules/find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dependencies": { + "locate-path": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "dev": true, + "bin": { + "flat": "cli.js" + } + }, + "node_modules/flat-cache": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", + "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "dev": true, + "dependencies": { + "flatted": "^3.1.0", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/flatted": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.6.tgz", + "integrity": "sha512-0sQoMh9s0BYsm+12Huy/rkKxVu4R1+r96YX5cG44rHV0pQ6iC3Q+mkoMFaGWObMFYQxCVT+ssG1ksneA2MI9KQ==", + "dev": true + }, + "node_modules/foreground-child": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-2.0.0.tgz", + "integrity": "sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.0", + "signal-exit": "^3.0.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==", + "engines": { + "node": "*" + } + }, + "node_modules/form-data": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", + "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 0.12" + } + }, + "node_modules/formidable": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/formidable/-/formidable-2.0.1.tgz", + "integrity": "sha512-rjTMNbp2BpfQShhFbR3Ruk3qk2y9jKpvMW78nJgx8QKtxjDVrwbZG+wvDOmVbifHyOUOQJXxqEy6r0faRrPzTQ==", + "deprecated": "ACTION REQUIRED: SWITCH TO v3 - v1 and v2 are VULNERABLE! v1 is DEPRECATED FOR OVER 2 YEARS! Use formidable@latest or try formidable-mini for fresh projects", + "dependencies": { + "dezalgo": "1.0.3", + "hexoid": "1.0.0", + "once": "1.4.0", + "qs": "6.9.3" + }, + "funding": { + "url": "https://ko-fi.com/tunnckoCore/commissions" + } + }, + "node_modules/formidable/node_modules/qs": { + "version": "6.9.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.3.tgz", + "integrity": "sha512-EbZYNarm6138UKKq46tdx08Yo/q9ZhFoAXAI1meAFd2GtbRDhbZY2WQSICskT0c5q99aFzLG1D4nvTk9tqfXIw==", + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/formstream": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/formstream/-/formstream-1.1.1.tgz", + "integrity": "sha512-yHRxt3qLFnhsKAfhReM4w17jP+U1OlhUjnKPPtonwKbIJO7oBP0MvoxkRUwb8AU9n0MIkYy5X5dK6pQnbj+R2Q==", + "dependencies": { + "destroy": "^1.0.4", + "mime": "^2.5.2", + "pause-stream": "~0.0.11" + } + }, + "node_modules/formstream/node_modules/mime": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", + "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fromentries": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/fromentries/-/fromentries-1.3.2.tgz", + "integrity": "sha512-cHEpEQHUg0f8XdtZCc2ZAhrHzKzT0MrFUTcvx+hfxYu7rGMDc5SKoXFh+n4YigxsHXRzc6OrCshdR1bWH6HHyg==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "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==", + "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": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/ftp": { + "version": "0.3.10", + "resolved": "https://registry.npmjs.org/ftp/-/ftp-0.3.10.tgz", + "integrity": "sha512-faFVML1aBx2UoDStmLwv2Wptt4vw5x03xxX172nhA5Y5HBshW5JweqQ2W4xL4dezQTG8inJsuYcpPHHU3X5OTQ==", + "dependencies": { + "readable-stream": "1.1.x", + "xregexp": "2.0.0" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/ftp/node_modules/isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==" + }, + "node_modules/ftp/node_modules/readable-stream": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "integrity": "sha512-+MeVjFf4L44XUkhM1eYbD8fyEsxcV81pqMSR5gblfcLCHfZvbrqy4/qYHE+/R5HoBUT11WV5O08Cr1n3YXkWVQ==", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } + }, + "node_modules/ftp/node_modules/string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" + }, + "node_modules/function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + }, + "node_modules/function.prototype.name": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.5.tgz", + "integrity": "sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.0", + "functions-have-names": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==", + "dev": true + }, + "node_modules/functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "dev": true, + "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==", + "dependencies": { + "is-property": "^1.0.2" + } + }, + "node_modules/generic-pool": { + "version": "3.8.2", + "resolved": "https://registry.npmjs.org/generic-pool/-/generic-pool-3.8.2.tgz", + "integrity": "sha512-nGToKy6p3PAbYQ7p1UlWl6vSPwfwU6TMSWK7TTu+WUY4ZjyZQGniGGt2oNVvyNSpyZYSB43zMXVLcBm08MTMkg==", + "engines": { + "node": ">= 4" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "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==", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-intrinsic": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", + "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", + "dependencies": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1" + }, + "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, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/get-pkg-repo": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/get-pkg-repo/-/get-pkg-repo-4.2.1.tgz", + "integrity": "sha512-2+QbHjFRfGB74v/pYWjd5OhU3TDIC2Gv/YKUTk/tCvAz0pkn/Mz6P3uByuBimLOcPvN2jYdScl3xGFSrx0jEcA==", + "dev": true, + "dependencies": { + "@hutson/parse-repository-url": "^3.0.0", + "hosted-git-info": "^4.0.0", + "through2": "^2.0.0", + "yargs": "^16.2.0" + }, + "bin": { + "get-pkg-repo": "src/cli.js" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-pkg-repo/node_modules/readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dev": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/get-pkg-repo/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==", + "dev": true + }, + "node_modules/get-pkg-repo/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/get-pkg-repo/node_modules/through2": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "dev": true, + "dependencies": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + }, + "node_modules/get-pkg-repo/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, + "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/get-pkg-repo/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, + "engines": { + "node": ">=10" + } + }, + "node_modules/get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "dependencies": { + "pump": "^3.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-symbol-description": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", + "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-uri": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/get-uri/-/get-uri-3.0.2.tgz", + "integrity": "sha512-+5s0SJbGoyiJTZZ2JTpFPLMPSch72KEqGOTvQsBqg0RBWvwhWUSYZFAtz3TPW0GXJuLBJPts1E241iHg+VRfhg==", + "dependencies": { + "@tootallnate/once": "1", + "data-uri-to-buffer": "3", + "debug": "4", + "file-uri-to-path": "2", + "fs-extra": "^8.1.0", + "ftp": "^0.3.10" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/get-uri/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/get-uri/node_modules/fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, + "node_modules/get-uri/node_modules/jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/get-uri/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/get-uri/node_modules/universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==", + "dependencies": { + "assert-plus": "^1.0.0" + } + }, + "node_modules/git-raw-commits": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/git-raw-commits/-/git-raw-commits-2.0.11.tgz", + "integrity": "sha512-VnctFhw+xfj8Va1xtfEqCUD2XDrbAPSJx+hSrE5K7fGdjZruW7XV+QOrN7LF/RJyvspRiD2I0asWsxFp0ya26A==", + "dev": true, + "dependencies": { + "dargs": "^7.0.0", + "lodash": "^4.17.15", + "meow": "^8.0.0", + "split2": "^3.0.0", + "through2": "^4.0.0" + }, + "bin": { + "git-raw-commits": "cli.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/git-remote-origin-url": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/git-remote-origin-url/-/git-remote-origin-url-2.0.0.tgz", + "integrity": "sha1-UoJlna4hBxRaERJhEq0yFuxfpl8=", + "dev": true, + "dependencies": { + "gitconfiglocal": "^1.0.0", + "pify": "^2.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/git-semver-tags": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/git-semver-tags/-/git-semver-tags-4.1.1.tgz", + "integrity": "sha512-OWyMt5zBe7xFs8vglMmhM9lRQzCWL3WjHtxNNfJTMngGym7pC1kh8sP6jevfydJ6LP3ZvGxfb6ABYgPUM0mtsA==", + "dev": true, + "dependencies": { + "meow": "^8.0.0", + "semver": "^6.0.0" + }, + "bin": { + "git-semver-tags": "cli.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/git-semver-tags/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/gitconfiglocal": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/gitconfiglocal/-/gitconfiglocal-1.0.0.tgz", + "integrity": "sha1-QdBF84UaXqiPA/JMocYXgRRGS5s=", + "dev": true, + "dependencies": { + "ini": "^1.3.2" + } + }, + "node_modules/glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "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==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.9", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.9.tgz", + "integrity": "sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ==" + }, + "node_modules/handlebars": { + "version": "4.7.7", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.7.tgz", + "integrity": "sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA==", + "dev": true, + "dependencies": { + "minimist": "^1.2.5", + "neo-async": "^2.6.0", + "source-map": "^0.6.1", + "wordwrap": "^1.0.0" + }, + "bin": { + "handlebars": "bin/handlebars" + }, + "engines": { + "node": ">=0.4.7" + }, + "optionalDependencies": { + "uglify-js": "^3.1.4" + } + }, + "node_modules/har-schema": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q==", + "engines": { + "node": ">=4" + } + }, + "node_modules/har-validator": { + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", + "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", + "deprecated": "this library is no longer supported", + "dependencies": { + "ajv": "^6.12.3", + "har-schema": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/har-validator/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/har-validator/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + }, + "node_modules/hard-rejection": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/hard-rejection/-/hard-rejection-2.1.0.tgz", + "integrity": "sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dependencies": { + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/has-bigints": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", + "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", + "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.1.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz", + "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", + "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasha": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/hasha/-/hasha-5.2.2.tgz", + "integrity": "sha512-Hrp5vIK/xr5SkeN2onO32H0MgNZ0f17HRNH39WfL0SYUNOTZ5Lz1TJ8Pajo/87dYGEFlLMm7mIc/k/s6Bvz9HQ==", + "dev": true, + "dependencies": { + "is-stream": "^2.0.0", + "type-fest": "^0.8.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/hasha/node_modules/type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true, + "bin": { + "he": "bin/he" + } + }, + "node_modules/helmet": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/helmet/-/helmet-5.1.0.tgz", + "integrity": "sha512-klsunXs8rgNSZoaUrNeuCiWUxyc+wzucnEnFejUg3/A+CaF589k9qepLZZ1Jehnzig7YbD4hEuscGXuBY3fq+g==", + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/hexoid": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/hexoid/-/hexoid-1.0.0.tgz", + "integrity": "sha512-QFLV0taWQOZtvIRIAdBChesmogZrtuXvVWsFHZTk2SU+anspqZ2vMnoLg7IE1+Uk16N19APic1BuF8bC8c2m5g==", + "engines": { + "node": ">=8" + } + }, + "node_modules/hosted-git-info": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz", + "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "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 + }, + "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==", + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/http-errors/node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/http-errors/node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "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==", + "dependencies": { + "@tootallnate/once": "1", + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/http-proxy-agent/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/http-proxy-agent/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/http-signature": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha512-CAbnr6Rz4CYQkLYUtSNXxQPUH2gK8f3iWexVlsnMeD+GjlsQ0Xsy1cOX+mN3dtxYomRy21CiOzU8Uhw6OwncEQ==", + "dependencies": { + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + }, + "engines": { + "node": ">=0.8", + "npm": ">=1.3.7" + } + }, + "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==", + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/https-proxy-agent/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/https-proxy-agent/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/humanize-ms": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", + "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==", + "dependencies": { + "ms": "^2.0.0" + } + }, + "node_modules/i18n": { + "version": "0.15.0", + "resolved": "https://registry.npmjs.org/i18n/-/i18n-0.15.0.tgz", + "integrity": "sha512-TUOkuFbl8Y/q7zF0tHdtpk1/TtxH0T+Drp2NFrHhmN1Qs0Sob9/0uVLS2BPVkEXNh2jZrimOiFJk+tkaOumzog==", + "dependencies": { + "@messageformat/core": "^3.0.0", + "debug": "^4.3.3", + "fast-printf": "^1.6.9", + "make-plural": "^7.0.0", + "math-interval-parser": "^2.0.1", + "mustache": "^4.2.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/mashpie" + } + }, + "node_modules/i18n/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/i18n/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "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==", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/ignore": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", + "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "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": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "dev": true, + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/inflection": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/inflection/-/inflection-1.13.2.tgz", + "integrity": "sha512-cmZlljCRTBFouT8UzMzrGcVEvkv6D/wBdcdKG7J1QH5cXjtU75Dm+P27v9EKu/Y43UYyCJd1WC4zLebRrC8NBw==", + "engines": [ + "node >= 0.4.0" + ] + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "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, + "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==" + }, + "node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true + }, + "node_modules/internal-slot": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz", + "integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.1.0", + "has": "^1.0.3", + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/ip": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.8.tgz", + "integrity": "sha512-PuExPYUiu6qMBQb4l06ecm6T6ujzhmh+MeJcW9wa89PoAz5pvd4zPgN5WJV104mb6S2T1AwNIAaB70JNrLQWhg==" + }, + "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==", + "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": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", + "dev": true + }, + "node_modules/is-bigint": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", + "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "dev": true, + "dependencies": { + "has-bigints": "^1.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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==", + "dev": true, + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-boolean-object": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", + "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-callable": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz", + "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-core-module": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.1.tgz", + "integrity": "sha512-SdNCUs284hr40hFTFP6l0IfZ/RSrMXF3qgoRHd3/79unUTvrFO/JoXwkGm+5J/Oe3E/b5GsnG330uUNgRpu1PA==", + "dependencies": { + "has": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-date-object": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", + "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-expression": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-expression/-/is-expression-4.0.0.tgz", + "integrity": "sha512-zMIXX63sxzG3XrkHkrAPvm/OVZVSCPNkwMHU8oTX7/U3AL78I0QXCEICXUM13BIa8TYGZ68PiTKfQz3yaTNr4A==", + "dependencies": { + "acorn": "^7.1.1", + "object-assign": "^4.1.1" + } + }, + "node_modules/is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true, + "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==", + "engines": { + "node": ">=8" + } + }, + "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, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-negative-zero": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", + "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-number-object": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", + "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-obj": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", + "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-plain-obj": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", + "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-promise": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.2.2.tgz", + "integrity": "sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==" + }, + "node_modules/is-property": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz", + "integrity": "sha1-V/4cTkhHTt1lsJkR8msc1Ald2oQ=" + }, + "node_modules/is-regex": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-shared-array-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", + "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-string": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-symbol": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", + "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "dev": true, + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-text-path": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-text-path/-/is-text-path-1.0.1.tgz", + "integrity": "sha1-Thqg+1G/vLPpJogAE5cgLBd1tm4=", + "dev": true, + "dependencies": { + "text-extensions": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" + }, + "node_modules/is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-weakref": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", + "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-windows": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "node_modules/isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==" + }, + "node_modules/istanbul-lib-coverage": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz", + "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-hook": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-hook/-/istanbul-lib-hook-3.0.0.tgz", + "integrity": "sha512-Pt/uge1Q9s+5VAZ+pCo16TYMWPBIl+oaNIjgLQxcX0itS6ueeaA+pEfThZpH8WxhFgCiEb8sAJY6MdUKgiIWaQ==", + "dev": true, + "dependencies": { + "append-transform": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-instrument": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.3.tgz", + "integrity": "sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ==", + "dev": true, + "dependencies": { + "@babel/core": "^7.7.5", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.0.0", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-instrument/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/istanbul-lib-processinfo": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-processinfo/-/istanbul-lib-processinfo-2.0.2.tgz", + "integrity": "sha512-kOwpa7z9hme+IBPZMzQ5vdQj8srYgAtaRqeI48NGmAQ+/5yKiHLV0QbYqQpxsdEF0+w14SoB8YbnHKcXE2KnYw==", + "dev": true, + "dependencies": { + "archy": "^1.0.0", + "cross-spawn": "^7.0.0", + "istanbul-lib-coverage": "^3.0.0-alpha.1", + "make-dir": "^3.0.0", + "p-map": "^3.0.0", + "rimraf": "^3.0.0", + "uuid": "^3.3.3" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-processinfo/node_modules/uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", + "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", + "dev": true, + "bin": { + "uuid": "bin/uuid" + } + }, + "node_modules/istanbul-lib-report": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", + "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==", + "dev": true, + "dependencies": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^3.0.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "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, + "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, + "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, + "dependencies": { + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-source-maps/node_modules/debug": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", + "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/istanbul-lib-source-maps/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/istanbul-reports": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.4.tgz", + "integrity": "sha512-r1/DshN4KSE7xWEknZLLLLDn5CJybV3nw01VTkp6D5jzLuELlcbudfj/eSQFvrKsJuTVCGnePO7ho82Nw9zzfw==", + "dev": true, + "dependencies": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/js-stringify": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/js-stringify/-/js-stringify-1.0.2.tgz", + "integrity": "sha1-Fzb939lyTyijaCrcYjCufk6Weds=" + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==" + }, + "node_modules/jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true, + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/json-parse-better-errors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", + "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", + "dev": true + }, + "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 + }, + "node_modules/json-schema": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", + "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==" + }, + "node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" + }, + "node_modules/json-schema-typed": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/json-schema-typed/-/json-schema-typed-7.0.3.tgz", + "integrity": "sha512-7DE8mpG+/fVw+dTpjbxnx47TaMnDfOI1jwft9g1VybltZCduyRQPJPvc+zzKY9WPHxhPWczyFuYa6I8Mw4iU5A==" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true + }, + "node_modules/json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" + }, + "node_modules/json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "dev": true, + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, + "node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/jsonparse": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", + "integrity": "sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA=", + "dev": true, + "engines": [ + "node >= 0.2.0" + ] + }, + "node_modules/JSONStream": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.5.tgz", + "integrity": "sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==", + "dev": true, + "dependencies": { + "jsonparse": "^1.2.0", + "through": ">=2.2.7 <3" + }, + "bin": { + "JSONStream": "bin.js" + }, + "engines": { + "node": "*" + } + }, + "node_modules/jsonwebtoken": { + "version": "8.5.1", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz", + "integrity": "sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w==", + "dependencies": { + "jws": "^3.2.2", + "lodash.includes": "^4.3.0", + "lodash.isboolean": "^3.0.3", + "lodash.isinteger": "^4.0.4", + "lodash.isnumber": "^3.0.3", + "lodash.isplainobject": "^4.0.6", + "lodash.isstring": "^4.0.1", + "lodash.once": "^4.0.0", + "ms": "^2.1.1", + "semver": "^5.6.0" + }, + "engines": { + "node": ">=4", + "npm": ">=1.4.28" + } + }, + "node_modules/jsonwebtoken/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, + "node_modules/jsonwebtoken/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/jsprim": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz", + "integrity": "sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==", + "dependencies": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.4.0", + "verror": "1.10.0" + }, + "engines": { + "node": ">=0.6.0" + } + }, + "node_modules/jstransformer": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/jstransformer/-/jstransformer-1.0.0.tgz", + "integrity": "sha1-7Yvwkh4vPx7U1cGkT2hwntJHIsM=", + "dependencies": { + "is-promise": "^2.0.0", + "promise": "^7.0.1" + } + }, + "node_modules/jsx-ast-utils": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.2.tgz", + "integrity": "sha512-4ZCADZHRkno244xlNnn4AOG6sRQ7iBZ5BbgZ4vW4y5IZw7cVUD1PPeblm1xx/nfmMxPdt/LHsXZW8z/j58+l9Q==", + "dev": true, + "dependencies": { + "array-includes": "^3.1.5", + "object.assign": "^4.1.2" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/jwa": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", + "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==", + "dependencies": { + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/jws": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", + "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", + "dependencies": { + "jwa": "^1.4.1", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/kv-logger": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/kv-logger/-/kv-logger-0.5.3.tgz", + "integrity": "sha512-ToBlw7HfX9/2MD1ek85tMa2Q3gSU/n5TXaoPPBuyZ8JX+f2w5OGjE10H+YzolJpMXbxsa0fVtj41Vq/MJPhUlQ==" + }, + "node_modules/language-subtag-registry": { + "version": "0.3.22", + "resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.22.tgz", + "integrity": "sha512-tN0MCzyWnoz/4nHS6uxdlFWoUZT7ABptwKPQ52Ea7URk6vll88bWBVhodtnlfEuCcKWNGoc+uGbw1cwa9IKh/w==", + "dev": true + }, + "node_modules/language-tags": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/language-tags/-/language-tags-1.0.5.tgz", + "integrity": "sha512-qJhlO9cGXi6hBGKoxEG/sKZDAHD5Hnu9Hs4WbOY3pCWXDhw0N8x1NenNzm2EnNLkLkk7J2SdxAkDSbb6ftT+UQ==", + "dev": true, + "dependencies": { + "language-subtag-registry": "~0.3.2" + } + }, + "node_modules/levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==", + "dependencies": { + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "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 + }, + "node_modules/load-json-file": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", + "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.2", + "parse-json": "^4.0.0", + "pify": "^3.0.0", + "strip-bom": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/load-json-file/node_modules/parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", + "dev": true, + "dependencies": { + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/load-json-file/node_modules/pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dependencies": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, + "node_modules/lodash.flattendeep": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz", + "integrity": "sha1-+wMJF/hqMTTlvJvsDWngAT3f7bI=", + "dev": true + }, + "node_modules/lodash.includes": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", + "integrity": "sha1-YLuYqHy5I8aMoeUTJUgzFISfVT8=" + }, + "node_modules/lodash.isboolean": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", + "integrity": "sha1-bC4XHbKiV82WgC/UOwGyDV9YcPY=" + }, + "node_modules/lodash.isinteger": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", + "integrity": "sha1-YZwK89A/iwTDH1iChAt3sRzWg0M=" + }, + "node_modules/lodash.ismatch": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.ismatch/-/lodash.ismatch-4.4.0.tgz", + "integrity": "sha1-dWy1FQyjum8RCFp4hJZF8Yj4Xzc=", + "dev": true + }, + "node_modules/lodash.isnumber": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", + "integrity": "sha1-POdoEMWSjQM1IwGsKHMX8RwLH/w=" + }, + "node_modules/lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs=" + }, + "node_modules/lodash.isstring": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", + "integrity": "sha1-1SfftUVuynzJu5XV2ur4i6VKVFE=" + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "node_modules/lodash.once": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", + "integrity": "sha1-DdOXEhPHxW34gJd9UEyI+0cal6w=" + }, + "node_modules/log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "dev": true, + "dependencies": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-symbols/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, + "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/log-symbols/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, + "engines": { + "node": ">=8" + } + }, + "node_modules/log-symbols/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, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/long": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", + "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==" + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "dev": true, + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dependencies": { + "semver": "^6.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/make-dir/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/make-plural": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/make-plural/-/make-plural-7.1.0.tgz", + "integrity": "sha512-PKkwVlAxYVo98NrbclaQIT4F5Oy+X58PZM5r2IwUSCe3syya6PXkIRCn2XCdz7p58Scgpp50PBeHmepXVDG3hg==" + }, + "node_modules/map-obj": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-4.3.0.tgz", + "integrity": "sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/math-interval-parser": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/math-interval-parser/-/math-interval-parser-2.0.1.tgz", + "integrity": "sha512-VmlAmb0UJwlvMyx8iPhXUDnVW1F9IrGEd9CIOmv+XL8AErCUUuozoDMrgImvnYt2A+53qVX/tPW6YJurMKYsvA==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/meow": { + "version": "8.1.2", + "resolved": "https://registry.npmjs.org/meow/-/meow-8.1.2.tgz", + "integrity": "sha512-r85E3NdZ+mpYk1C6RjPFEMSE+s1iZMuHtsHAqY0DT3jZczl0diWUZ8g6oU7h0M9cD2EL+PzaYghhCLzR0ZNn5Q==", + "dev": true, + "dependencies": { + "@types/minimist": "^1.2.0", + "camelcase-keys": "^6.2.2", + "decamelize-keys": "^1.1.0", + "hard-rejection": "^2.1.0", + "minimist-options": "4.1.0", + "normalize-package-data": "^3.0.0", + "read-pkg-up": "^7.0.1", + "redent": "^3.0.0", + "trim-newlines": "^3.0.0", + "type-fest": "^0.18.0", + "yargs-parser": "^20.2.3" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/meow/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, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/meow/node_modules/hosted-git-info": { + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", + "dev": true + }, + "node_modules/meow/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, + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/meow/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, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/meow/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, + "engines": { + "node": ">=8" + } + }, + "node_modules/meow/node_modules/read-pkg": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", + "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", + "dev": true, + "dependencies": { + "@types/normalize-package-data": "^2.4.0", + "normalize-package-data": "^2.5.0", + "parse-json": "^5.0.0", + "type-fest": "^0.6.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/meow/node_modules/read-pkg-up": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz", + "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==", + "dev": true, + "dependencies": { + "find-up": "^4.1.0", + "read-pkg": "^5.2.0", + "type-fest": "^0.8.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/meow/node_modules/read-pkg-up/node_modules/type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/meow/node_modules/read-pkg/node_modules/normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dev": true, + "dependencies": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "node_modules/meow/node_modules/read-pkg/node_modules/type-fest": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", + "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/meow/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/meow/node_modules/type-fest": { + "version": "0.18.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.18.1.tgz", + "integrity": "sha512-OIAYXk8+ISY+qTOwkHtKqzAuxchoMiD9Udx+FSGQDuiRR+PJKJHc2NJAXlbhkGwTt/4/nKZxELY1w3ReWOL8mw==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/meow/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, + "engines": { + "node": ">=10" + } + }, + "node_modules/merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dev": true, + "dependencies": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/mime-db": { + "version": "1.51.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.51.0.tgz", + "integrity": "sha512-5y8A56jg7XVQx2mbv1lu49NR4dokRnhZYTtL+KGfaa27uq4pSTXkwQkFJl4pkRMyNFz/EtYDSkiiEHx3F7UN6g==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.34", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.34.tgz", + "integrity": "sha512-6cP692WwGIs9XXdOO4++N+7qjqv0rqxxVvJ3VHPh/Sc9mVZcQP+ZGhkKiTvWMQRr2tbHkJP/Yn7Y0npb3ZBs4A==", + "dependencies": { + "mime-db": "1.51.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-fn": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-3.1.0.tgz", + "integrity": "sha512-Ysbi9uYW9hFyfrThdDEQuykN4Ey6BuwPD2kpI5ES/nFTDn/98yxYNLZJcgUAKPT/mcrLLKaGzJR9YVxJrIdASQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/min-indent": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", + "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" + }, + "node_modules/minimist-options": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/minimist-options/-/minimist-options-4.1.0.tgz", + "integrity": "sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A==", + "dev": true, + "dependencies": { + "arrify": "^1.0.1", + "is-plain-obj": "^1.1.0", + "kind-of": "^6.0.3" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/minimist-options/node_modules/is-plain-obj": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", + "integrity": "sha1-caUMhCnfync8kqOQpKA7OfzVHT4=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "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==", + "dependencies": { + "minimist": "^1.2.6" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/mkdirp/node_modules/minimist": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", + "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==" + }, + "node_modules/mocha": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.0.0.tgz", + "integrity": "sha512-0Wl+elVUD43Y0BqPZBzZt8Tnkw9CMUdNYnUsTfOM1vuhJVZL+kiesFYsqwBkEEuEixaiPe5ZQdqDgX2jddhmoA==", + "dev": true, + "dependencies": { + "@ungap/promise-all-settled": "1.1.2", + "ansi-colors": "4.1.1", + "browser-stdout": "1.3.1", + "chokidar": "3.5.3", + "debug": "4.3.4", + "diff": "5.0.0", + "escape-string-regexp": "4.0.0", + "find-up": "5.0.0", + "glob": "7.2.0", + "he": "1.2.0", + "js-yaml": "4.1.0", + "log-symbols": "4.1.0", + "minimatch": "5.0.1", + "ms": "2.1.3", + "nanoid": "3.3.3", + "serialize-javascript": "6.0.0", + "strip-json-comments": "3.1.1", + "supports-color": "8.1.1", + "workerpool": "6.2.1", + "yargs": "16.2.0", + "yargs-parser": "20.2.4", + "yargs-unparser": "2.0.0" + }, + "bin": { + "_mocha": "bin/_mocha", + "mocha": "bin/mocha.js" + }, + "engines": { + "node": ">= 14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mochajs" + } + }, + "node_modules/mocha/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/mocha/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/mocha/node_modules/debug/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/mocha/node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mocha/node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mocha/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, + "engines": { + "node": ">=8" + } + }, + "node_modules/mocha/node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, - "etag": { - "version": "1.8.1", - "resolved": "http://registry.npm.taobao.org/etag/download/etag-1.8.1.tgz", - "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" + "node_modules/mocha/node_modules/minimatch": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz", + "integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/mocha/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==", + "dev": true + }, + "node_modules/mocha/node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mocha/node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mocha/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, + "engines": { + "node": ">=8" + } + }, + "node_modules/mocha/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, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/mocha/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, + "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/mocha/node_modules/yargs-parser": { + "version": "20.2.4", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", + "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/mockdate": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/mockdate/-/mockdate-3.0.5.tgz", + "integrity": "sha512-iniQP4rj1FhBdBYS/+eQv7j1tadJ9lJtdzgOpvsOHng/GbcDh2Fhdeq+ZRldrPYdXvCyfFUmFeEwEGXZB5I/AQ==" + }, + "node_modules/modify-values": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/modify-values/-/modify-values-1.0.1.tgz", + "integrity": "sha512-xV2bxeN6F7oYjZWTe/YPAy6MN2M+sL4u/Rlm2AHCIVGfo2p1yGmBHQ6vHehl4bRTZBdHu3TSkWdYgkwpYzAGSw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/moment": { + "version": "2.29.3", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.3.tgz", + "integrity": "sha512-c6YRvhEo//6T2Jz/vVtYzqBzwvPT95JBQ+smCytzf7c50oMZRsR/a4w88aD34I+/QVSfnoAnSBFPJHItlOMJVw==", + "engines": { + "node": "*" + } + }, + "node_modules/moment-timezone": { + "version": "0.5.34", + "resolved": "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.5.34.tgz", + "integrity": "sha512-3zAEHh2hKUs3EXLESx/wsgw6IQdusOT8Bxm3D9UrHPQR7zlMmzwybC8zHEM1tQ4LJwP7fcxrWr8tuBg05fFCbg==", + "dependencies": { + "moment": ">= 2.9.0" + }, + "engines": { + "node": "*" + } + }, + "node_modules/moo": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/moo/-/moo-0.5.1.tgz", + "integrity": "sha512-I1mnb5xn4fO80BH9BLcF0yLypy2UKl+Cb01Fu0hJRkJjlCRtxZMWkTdAtDd5ZqCOxtCkhmRwyI57vWT+1iZ67w==" + }, + "node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "node_modules/mustache": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/mustache/-/mustache-4.2.0.tgz", + "integrity": "sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ==", + "bin": { + "mustache": "bin/mustache" + } + }, + "node_modules/mysql2": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/mysql2/-/mysql2-2.3.3.tgz", + "integrity": "sha512-wxJUev6LgMSgACDkb/InIFxDprRa6T95+VEoR+xPvtngtccNH2dGjEB/fVZ8yg1gWv1510c9CvXuJHi5zUm0ZA==", + "dependencies": { + "denque": "^2.0.1", + "generate-function": "^2.3.1", + "iconv-lite": "^0.6.3", + "long": "^4.0.0", + "lru-cache": "^6.0.0", + "named-placeholders": "^1.1.2", + "seq-queue": "^0.0.5", + "sqlstring": "^2.3.2" + }, + "engines": { + "node": ">= 8.0" + } + }, + "node_modules/mysql2/node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/mz": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", + "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", + "dependencies": { + "any-promise": "^1.0.0", + "object-assign": "^4.0.1", + "thenify-all": "^1.0.0" + } + }, + "node_modules/named-placeholders": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/named-placeholders/-/named-placeholders-1.1.2.tgz", + "integrity": "sha512-wiFWqxoLL3PGVReSZpjLVxyJ1bRqe+KKJVbr4hGs1KWfTZTQyezHFBbuKj9hsizHyGV2ne7EMjHdxEGAybD5SA==", + "dependencies": { + "lru-cache": "^4.1.3" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/named-placeholders/node_modules/lru-cache": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", + "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", + "dependencies": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + } + }, + "node_modules/named-placeholders/node_modules/yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=" + }, + "node_modules/nanoid": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.3.tgz", + "integrity": "sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w==", + "dev": true, + "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 + }, + "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==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "dev": true + }, + "node_modules/netmask": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/netmask/-/netmask-2.0.2.tgz", + "integrity": "sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg==", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/node_memcached": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/node_memcached/-/node_memcached-1.1.3.tgz", + "integrity": "sha1-icFSr4itKIF/ANiRyZBFHV1xLqg=", + "dependencies": { + "debug": "^2.1.0" + } + }, + "node_modules/node-fetch": { + "version": "2.6.7", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", + "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/node-preload": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/node-preload/-/node-preload-0.2.1.tgz", + "integrity": "sha512-RM5oyBy45cLEoHqCeh+MNuFAxO0vTFBLskvQbOKnEE7YTTSN4tbN8QWDIPQ6L+WvKsB/qLEGpYe2ZZ9d4W9OIQ==", + "dev": true, + "dependencies": { + "process-on-spawn": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/node-releases": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.2.tgz", + "integrity": "sha512-XxYDdcQ6eKqp/YjI+tb2C5WM2LgjnZrfYg4vgQt49EK268b6gYCHsBLrK2qvJo4FmCtqmKezb0WZFK4fkrZNsg==", + "dev": true }, - "events": { + "node_modules/nodemailer": { + "version": "6.7.7", + "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.7.7.tgz", + "integrity": "sha512-pOLC/s+2I1EXuSqO5Wa34i3kXZG3gugDssH+ZNCevHad65tc8vQlCQpOLaUjopvkRQKm2Cki2aME7fEOPRy3bA==", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/normalize-package-data": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-3.0.3.tgz", + "integrity": "sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA==", + "dev": true, + "dependencies": { + "hosted-git-info": "^4.0.1", + "is-core-module": "^2.5.0", + "semver": "^7.3.4", + "validate-npm-package-license": "^3.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "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==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/nyc": { + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/nyc/-/nyc-15.1.0.tgz", + "integrity": "sha512-jMW04n9SxKdKi1ZMGhvUTHBN0EICCRkHemEoE5jm6mTYcqcdas0ATzgUgejlQUHMvpnOZqGB5Xxsv9KxJW1j8A==", + "dev": true, + "dependencies": { + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.2", + "caching-transform": "^4.0.0", + "convert-source-map": "^1.7.0", + "decamelize": "^1.2.0", + "find-cache-dir": "^3.2.0", + "find-up": "^4.1.0", + "foreground-child": "^2.0.0", + "get-package-type": "^0.1.0", + "glob": "^7.1.6", + "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-hook": "^3.0.0", + "istanbul-lib-instrument": "^4.0.0", + "istanbul-lib-processinfo": "^2.0.2", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^4.0.0", + "istanbul-reports": "^3.0.2", + "make-dir": "^3.0.0", + "node-preload": "^0.2.1", + "p-map": "^3.0.0", + "process-on-spawn": "^1.0.0", + "resolve-from": "^5.0.0", + "rimraf": "^3.0.0", + "signal-exit": "^3.0.2", + "spawn-wrap": "^2.0.0", + "test-exclude": "^6.0.0", + "yargs": "^15.0.2" + }, + "bin": { + "nyc": "bin/nyc.js" + }, + "engines": { + "node": ">=8.9" + } + }, + "node_modules/nyc/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, + "engines": { + "node": ">=6" + } + }, + "node_modules/nyc/node_modules/cliui": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", + "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^6.2.0" + } + }, + "node_modules/nyc/node_modules/decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/nyc/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/nyc/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/nyc/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/nyc/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, + "engines": { + "node": ">=8" + } + }, + "node_modules/nyc/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, + "engines": { + "node": ">=8" + } + }, + "node_modules/nyc/node_modules/wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/nyc/node_modules/y18n": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", + "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", + "dev": true + }, + "node_modules/nyc/node_modules/yargs": { + "version": "15.4.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", + "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", + "dev": true, + "dependencies": { + "cliui": "^6.0.0", + "decamelize": "^1.2.0", + "find-up": "^4.1.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^4.2.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^18.1.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/nyc/node_modules/yargs-parser": { + "version": "18.1.3", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", + "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", + "dev": true, + "dependencies": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/oauth-sign": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", + "engines": { + "node": "*" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.0.tgz", + "integrity": "sha512-Ho2z80bVIvJloH+YzRmpZVQe87+qASmBUKZDWgx9cu+KDrX2ZDH/3tMy+gXbZETVGs2M8YdxObOh7XAtim9Y0g==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-keys": { "version": "1.1.1", - "resolved": "http://registry.npm.taobao.org/events/download/events-1.1.1.tgz", - "integrity": "sha1-nr23Y1rQmccNzEwqH1AEKI6L2SQ=" + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true, + "engines": { + "node": ">= 0.4" + } }, - "execa": { - "version": "0.7.0", - "resolved": "http://registry.npm.taobao.org/execa/download/execa-0.7.0.tgz", - "integrity": "sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c=", - "requires": { - "cross-spawn": "^5.0.1", - "get-stream": "^3.0.0", - "is-stream": "^1.1.0", - "npm-run-path": "^2.0.0", - "p-finally": "^1.0.0", - "signal-exit": "^3.0.0", - "strip-eof": "^1.0.0" - } - }, - "expect-ct": { - "version": "0.1.0", - "resolved": "http://registry.npm.taobao.org/expect-ct/download/expect-ct-0.1.0.tgz", - "integrity": "sha1-UnNWeN4YUwiQ2Ne5XwrGNkCVgJQ=" - }, - "express": { - "version": "4.16.3", - "resolved": "http://registry.npm.taobao.org/express/download/express-4.16.3.tgz", - "integrity": "sha1-avilAjUNsyRuzEvs9rWjTSL37VM=", - "requires": { - "accepts": "~1.3.5", - "array-flatten": "1.1.1", - "body-parser": "1.18.2", - "content-disposition": "0.5.2", - "content-type": "~1.0.4", - "cookie": "0.3.1", - "cookie-signature": "1.0.6", - "debug": "2.6.9", - "depd": "~1.1.2", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "finalhandler": "1.1.1", - "fresh": "0.5.2", - "merge-descriptors": "1.0.1", - "methods": "~1.1.2", - "on-finished": "~2.3.0", - "parseurl": "~1.3.2", - "path-to-regexp": "0.1.7", - "proxy-addr": "~2.0.3", - "qs": "6.5.1", - "range-parser": "~1.2.0", - "safe-buffer": "5.1.1", - "send": "0.16.2", - "serve-static": "1.13.2", - "setprototypeof": "1.1.0", - "statuses": "~1.4.0", - "type-is": "~1.6.16", - "utils-merge": "1.0.1", - "vary": "~1.1.2" + "node_modules/object.assign": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", + "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3", + "has-symbols": "^1.0.1", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.entries": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.5.tgz", + "integrity": "sha512-TyxmjUoZggd4OrrU1W66FMDG6CuqJxsFvymeyXI51+vQLN67zYfZseptRge703kKQdo4uccgAKebXFcRCzk4+g==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.fromentries": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.5.tgz", + "integrity": "sha512-CAyG5mWQRRiBU57Re4FKoTBjXfDoNwdFVH2Y1tS9PqCsfUTymAohOkEMSG3aRNKmv4lV3O7p1et7c187q6bynw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.hasown": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object.hasown/-/object.hasown-1.1.1.tgz", + "integrity": "sha512-LYLe4tivNQzq4JdaWW6WO3HMZZJWzkkH8fnI6EebWl0VZth2wL2Lovm74ep2/gZzlaTdV62JZHEqHQ2yVn8Q/A==", + "dev": true, + "dependencies": { + "define-properties": "^1.1.4", + "es-abstract": "^1.19.5" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.values": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.5.tgz", + "integrity": "sha512-QUZRW0ilQ3PnPpbNtgdNV1PDbEqLIiSFB3l+EnGtBQ/8SUTLj1PZwtQHABZtLgwpJZTSZhuGLOGk57Drx2IvYg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.1" + }, + "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==", + "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": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "http://registry.npm.taobao.org/debug/download/debug-2.6.9.tgz", - "integrity": "sha1-XRKFFd8TT/Mn6QpMk/Tgd6U2NB8=", - "requires": { - "ms": "2.0.0" - } - }, - "setprototypeof": { - "version": "1.1.0", - "resolved": "http://registry.npm.taobao.org/setprototypeof/download/setprototypeof-1.1.0.tgz", - "integrity": "sha1-0L2FU2iHtv58DYGMuWLZ2RxU5lY=" - } + "wrappy": "1" } }, - "extend": { - "version": "3.0.1", - "resolved": "http://registry.npm.taobao.org/extend/download/extend-3.0.1.tgz", - "integrity": "sha1-p1Xqe8Gt/MWjHOfnYtuq3F5jZEQ=" + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, - "extendr": { + "node_modules/onetime/node_modules/mimic-fn": { "version": "2.1.0", - "resolved": "http://registry.npm.taobao.org/extendr/download/extendr-2.1.0.tgz", - "integrity": "sha1-MBqgu+pWX00tyPVw8qImEahSe1Y=", - "requires": { - "typechecker": "~2.0.1" + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "engines": { + "node": ">=6" + } + }, + "node_modules/optionator": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", + "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", + "dependencies": { + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.6", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "word-wrap": "~1.2.3" }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/os-name": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/os-name/-/os-name-1.0.3.tgz", + "integrity": "sha512-f5estLO2KN8vgtTRaILIgEGBoBrMnZ3JQ7W9TMZCnOIGwHe8TRGSpcagnWDo+Dfhd/z08k9Xe75hvciJJ8Qaew==", "dependencies": { - "typechecker": { - "version": "2.0.8", - "resolved": "http://registry.npm.taobao.org/typechecker/download/typechecker-2.0.8.tgz", - "integrity": "sha1-6D2oS7ZMWEzLNFg4V2xAsDN9uC4=" - } + "osx-release": "^1.0.0", + "win-release": "^1.0.0" + }, + "bin": { + "os-name": "cli.js" + }, + "engines": { + "node": ">=0.10.0" } }, - "extract-opts": { - "version": "2.2.0", - "resolved": "http://registry.npm.taobao.org/extract-opts/download/extract-opts-2.2.0.tgz", - "integrity": "sha1-H6KOunNSxttID4hc63GkaBC+bX0=", - "requires": { - "typechecker": "~2.0.1" + "node_modules/osx-release": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/osx-release/-/osx-release-1.1.0.tgz", + "integrity": "sha512-ixCMMwnVxyHFQLQnINhmIpWqXIfS2YOXchwQrk+OFzmo6nDjQ0E4KXAyyUh0T0MZgV4bUhkRrAbVqlE4yLVq4A==", + "dependencies": { + "minimist": "^1.1.0" + }, + "bin": { + "osx-release": "cli.js" }, + "engines": { + "node": ">=0.10.0" + } + }, + "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==", "dependencies": { - "typechecker": { - "version": "2.0.8", - "resolved": "http://registry.npm.taobao.org/typechecker/download/typechecker-2.0.8.tgz", - "integrity": "sha1-6D2oS7ZMWEzLNFg4V2xAsDN9uC4=" - } + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "extract-zip": { - "version": "1.6.6", - "resolved": "http://registry.npm.taobao.org/extract-zip/download/extract-zip-1.6.6.tgz", - "integrity": "sha1-EpDt6NINCHK0Kf0/NRyhKOxe+Fw=", - "requires": { - "concat-stream": "1.6.0", - "debug": "2.6.9", - "mkdirp": "0.5.0", - "yauzl": "2.4.1" + "node_modules/p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dependencies": { + "p-limit": "^2.0.0" }, + "engines": { + "node": ">=6" + } + }, + "node_modules/p-map": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-3.0.0.tgz", + "integrity": "sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ==", + "dev": true, "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "http://registry.npm.taobao.org/debug/download/debug-2.6.9.tgz", - "integrity": "sha1-XRKFFd8TT/Mn6QpMk/Tgd6U2NB8=", - "requires": { - "ms": "2.0.0" - } - } + "aggregate-error": "^3.0.0" + }, + "engines": { + "node": ">=8" } }, - "extsprintf": { - "version": "1.3.0", - "resolved": "http://registry.npm.taobao.org/extsprintf/download/extsprintf-1.3.0.tgz", - "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=" + "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==", + "engines": { + "node": ">=6" + } }, - "fast-deep-equal": { - "version": "1.1.0", - "resolved": "http://registry.npm.taobao.org/fast-deep-equal/download/fast-deep-equal-1.1.0.tgz", - "integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ=" + "node_modules/pac-proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-5.0.0.tgz", + "integrity": "sha512-CcFG3ZtnxO8McDigozwE3AqAw15zDvGH+OjXO4kzf7IkEKkQ4gxQ+3sdF50WmhQ4P/bVusXcqNE2S3XrNURwzQ==", + "dependencies": { + "@tootallnate/once": "1", + "agent-base": "6", + "debug": "4", + "get-uri": "3", + "http-proxy-agent": "^4.0.1", + "https-proxy-agent": "5", + "pac-resolver": "^5.0.0", + "raw-body": "^2.2.0", + "socks-proxy-agent": "5" + }, + "engines": { + "node": ">= 8" + } }, - "fast-json-stable-stringify": { - "version": "2.0.0", - "resolved": "http://registry.npm.taobao.org/fast-json-stable-stringify/download/fast-json-stable-stringify-2.0.0.tgz", - "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=" + "node_modules/pac-proxy-agent/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } }, - "fast-levenshtein": { - "version": "2.0.6", - "resolved": "http://registry.npm.taobao.org/fast-levenshtein/download/fast-levenshtein-2.0.6.tgz", - "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", - "dev": true + "node_modules/pac-proxy-agent/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, - "fd-slicer": { - "version": "1.0.1", - "resolved": "http://registry.npm.taobao.org/fd-slicer/download/fd-slicer-1.0.1.tgz", - "integrity": "sha1-i1vL2ewyfFBBv5qwI/1nUPEXfmU=", - "requires": { - "pend": "~1.2.0" + "node_modules/pac-resolver": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/pac-resolver/-/pac-resolver-5.0.1.tgz", + "integrity": "sha512-cy7u00ko2KVgBAjuhevqpPeHIkCIqPe1v24cydhWjmeuzaBfmUWFCZJ1iAh5TuVzVZoUzXIW7K8sMYOZ84uZ9Q==", + "dependencies": { + "degenerator": "^3.0.2", + "ip": "^1.1.5", + "netmask": "^2.0.2" + }, + "engines": { + "node": ">= 8" } }, - "finalhandler": { - "version": "1.1.1", - "resolved": "http://registry.npm.taobao.org/finalhandler/download/finalhandler-1.1.1.tgz", - "integrity": "sha1-7r9O2EAHnIP0JJA4ydcDAIMBsQU=", - "requires": { - "debug": "2.6.9", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "on-finished": "~2.3.0", - "parseurl": "~1.3.2", - "statuses": "~1.4.0", - "unpipe": "~1.0.0" - }, + "node_modules/package-hash": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/package-hash/-/package-hash-4.0.0.tgz", + "integrity": "sha512-whdkPIooSu/bASggZ96BWVvZTRMOFxnyUG5PnTSGKoJE2gd5mbVNmR2Nj20QFzxYYgAXpoqC+AiXzl+UMRh7zQ==", + "dev": true, "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "http://registry.npm.taobao.org/debug/download/debug-2.6.9.tgz", - "integrity": "sha1-XRKFFd8TT/Mn6QpMk/Tgd6U2NB8=", - "requires": { - "ms": "2.0.0" - } - } + "graceful-fs": "^4.1.15", + "hasha": "^5.0.0", + "lodash.flattendeep": "^4.4.0", + "release-zalgo": "^1.0.0" + }, + "engines": { + "node": ">=8" } }, - "find-up": { - "version": "3.0.0", - "resolved": "http://registry.npm.taobao.org/find-up/download/find-up-3.0.0.tgz", - "integrity": "sha1-SRafHXmTQwZG2mHsxa41XCHJe3M=", - "requires": { - "locate-path": "^3.0.0" + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" } }, - "follow-redirects": { - "version": "1.5.10", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.5.10.tgz", - "integrity": "sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ==", - "requires": { - "debug": "=3.1.0" + "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, + "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" } }, - "forever-agent": { - "version": "0.6.1", - "resolved": "http://registry.npm.taobao.org/forever-agent/download/forever-agent-0.6.1.tgz", - "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=" + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "engines": { + "node": ">= 0.8" + } }, - "form-data": { - "version": "2.3.2", - "resolved": "http://registry.npm.taobao.org/form-data/download/form-data-2.3.2.tgz", - "integrity": "sha1-SXBJi+YEwgwAXU9cI67NIda0kJk=", - "requires": { - "asynckit": "^0.4.0", - "combined-stream": "1.0.6", - "mime-types": "^2.1.12" + "node_modules/path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "engines": { + "node": ">=4" } }, - "formidable": { - "version": "1.2.1", - "resolved": "http://registry.npm.taobao.org/formidable/download/formidable-1.2.1.tgz", - "integrity": "sha1-cPt8oCkO5v+WEJBBX0s989IIJlk=" + "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": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } }, - "formstream": { - "version": "1.1.0", - "resolved": "http://registry.npm.taobao.org/formstream/download/formstream-1.1.0.tgz", - "integrity": "sha1-UfOXDyYTbrCtRDBN5M67UCB7RHk=", - "requires": { - "destroy": "^1.0.4", - "mime": "^1.3.4", - "pause-stream": "~0.0.11" - }, - "dependencies": { - "mime": { - "version": "1.6.0", - "resolved": "http://registry.npm.taobao.org/mime/download/mime-1.6.0.tgz", - "integrity": "sha1-Ms2eXGRVO9WNGaVor0Uqz/BJgbE=" - } + "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, + "engines": { + "node": ">=8" } }, - "forwarded": { - "version": "0.1.2", - "resolved": "http://registry.npm.taobao.org/forwarded/download/forwarded-0.1.2.tgz", - "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=" + "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==" }, - "frameguard": { - "version": "3.0.0", - "resolved": "http://registry.npm.taobao.org/frameguard/download/frameguard-3.0.0.tgz", - "integrity": "sha1-e8rUae57lukdEs6zlZx4I1qScuk=" + "node_modules/path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" }, - "fresh": { - "version": "0.5.2", - "resolved": "http://registry.npm.taobao.org/fresh/download/fresh-0.5.2.tgz", - "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true, + "engines": { + "node": ">=8" + } }, - "fs-extra": { - "version": "7.0.0", - "resolved": "http://registry.npm.taobao.org/fs-extra/download/fs-extra-7.0.0.tgz", - "integrity": "sha1-jMP0fOB+97NZOhG5+yRffjTAQdY=", - "requires": { - "graceful-fs": "^4.1.2", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" + "node_modules/pause-stream": { + "version": "0.0.11", + "resolved": "https://registry.npmjs.org/pause-stream/-/pause-stream-0.0.11.tgz", + "integrity": "sha512-e3FBlXLmN/D1S+zHzanP4E/4Z60oFAa3O051qt1pxa7DEJWKAyil6upYVXCWadEnuoqa4Pkc9oUx9zsxYeRv8A==", + "dependencies": { + "through": "~2.3" } }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "http://registry.npm.taobao.org/fs.realpath/download/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", - "dev": true + "node_modules/pend": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", + "integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA=" }, - "function-bind": { - "version": "1.1.1", - "resolved": "http://registry.npm.taobao.org/function-bind/download/function-bind-1.1.1.tgz", - "integrity": "sha1-pWiZ0+o8m6uHS7l3O3xe3pL0iV0=" + "node_modules/performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==" }, - "generate-function": { - "version": "2.0.0", - "resolved": "http://registry.npm.taobao.org/generate-function/download/generate-function-2.0.0.tgz", - "integrity": "sha1-aFj+fAlpt9TpCTM3ZHrHn2DfvnQ=" + "node_modules/pg-connection-string": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.5.0.tgz", + "integrity": "sha512-r5o/V/ORTA6TmUnyWZR9nCj1klXCO2CEKNRlVuJptZe85QuhFayC7WeMic7ndayT5IRIR0S0xFxFi2ousartlQ==" }, - "generic-pool": { - "version": "3.4.2", - "resolved": "http://registry.npm.taobao.org/generic-pool/download/generic-pool-3.4.2.tgz", - "integrity": "sha1-kv9xllINZwg5pnMICSoSqt8valk=" + "node_modules/picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true }, - "get-caller-file": { - "version": "1.0.3", - "resolved": "http://registry.npm.taobao.org/get-caller-file/download/get-caller-file-1.0.3.tgz", - "integrity": "sha1-+Xj6TJDR3+f/LWvtoqUV5xO9z0o=" + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } }, - "get-stream": { - "version": "3.0.0", - "resolved": "http://registry.npm.taobao.org/get-stream/download/get-stream-3.0.0.tgz", - "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=" + "node_modules/pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } }, - "getpass": { - "version": "0.1.7", - "resolved": "http://registry.npm.taobao.org/getpass/download/getpass-0.1.7.tgz", - "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", - "requires": { - "assert-plus": "^1.0.0" + "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, + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" } }, - "glob": { - "version": "5.0.15", - "resolved": "http://registry.npm.taobao.org/glob/download/glob-5.0.15.tgz", - "integrity": "sha1-G8k2ueAvSmA/zCIuz3Yz0wuLk7E=", - "requires": { - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "2 || 3", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" + "node_modules/pkg-dir/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" } }, - "graceful-fs": { - "version": "4.1.11", - "resolved": "http://registry.npm.taobao.org/graceful-fs/download/graceful-fs-4.1.11.tgz", - "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=" + "node_modules/pkg-dir/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } }, - "graceful-readlink": { - "version": "1.0.1", - "resolved": "http://registry.npm.taobao.org/graceful-readlink/download/graceful-readlink-1.0.1.tgz", - "integrity": "sha1-TK+tdrxi8C+gObL5Tpo906ORpyU=" - }, - "growl": { - "version": "1.9.2", - "resolved": "http://registry.npm.taobao.org/growl/download/growl-1.9.2.tgz", - "integrity": "sha1-Dqd0NxXbjY3ixe3hd14bRayFwC8=", - "dev": true - }, - "handlebars": { - "version": "4.0.11", - "resolved": "http://registry.npm.taobao.org/handlebars/download/handlebars-4.0.11.tgz", - "integrity": "sha1-Ywo13+ApS8KB7a5v/F0yn8eYLcw=", - "dev": true, - "requires": { - "async": "^1.4.0", - "optimist": "^0.6.1", - "source-map": "^0.4.4", - "uglify-js": "^2.6" - }, - "dependencies": { - "source-map": { - "version": "0.4.4", - "resolved": "http://registry.npm.taobao.org/source-map/download/source-map-0.4.4.tgz", - "integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=", - "dev": true, - "requires": { - "amdefine": ">=0.0.4" - } - } + "node_modules/pkg-dir/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" } }, - "har-schema": { - "version": "2.0.0", - "resolved": "http://registry.npm.taobao.org/har-schema/download/har-schema-2.0.0.tgz", - "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=" - }, - "har-validator": { - "version": "5.0.3", - "resolved": "http://registry.npm.taobao.org/har-validator/download/har-validator-5.0.3.tgz", - "integrity": "sha1-ukAsJmGU8VlW7xXg/PJCmT9qff0=", - "requires": { - "ajv": "^5.1.0", - "har-schema": "^2.0.0" + "node_modules/pkg-dir/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, + "engines": { + "node": ">=8" } }, - "has": { - "version": "1.0.1", - "resolved": "http://registry.npm.taobao.org/has/download/has-1.0.1.tgz", - "integrity": "sha1-hGFzP1OLCDfJNh45qauelwTcLyg=", - "requires": { - "function-bind": "^1.0.2" + "node_modules/pkg-up": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/pkg-up/-/pkg-up-3.1.0.tgz", + "integrity": "sha512-nDywThFk1i4BQK4twPQ6TA4RT8bDY96yeuCVBWL3ePARCiEKDRSrNGbFIgUJpLp+XeIR65v8ra7WuJOFUBtkMA==", + "dependencies": { + "find-up": "^3.0.0" + }, + "engines": { + "node": ">=8" } }, - "has-flag": { - "version": "1.0.0", - "resolved": "http://registry.npm.taobao.org/has-flag/download/has-flag-1.0.0.tgz", - "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=", - "dev": true + "node_modules/pomelo-protobuf": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/pomelo-protobuf/-/pomelo-protobuf-0.4.0.tgz", + "integrity": "sha1-5F6aCkRusYZn4MbhPutT1Hrdvag=" }, - "hawk": { - "version": "6.0.2", - "resolved": "http://registry.npm.taobao.org/hawk/download/hawk-6.0.2.tgz", - "integrity": "sha1-r02RTrBl+bXOTZ0RwcshJu7MMDg=", - "requires": { - "boom": "4.x.x", - "cryptiles": "3.x.x", - "hoek": "4.x.x", - "sntp": "2.x.x" + "node_modules/prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==", + "engines": { + "node": ">= 0.8.0" } }, - "he": { - "version": "1.1.1", - "resolved": "http://registry.npm.taobao.org/he/download/he-1.1.1.tgz", - "integrity": "sha1-k0EP0hsAlzUVH4howvJx80J+I/0=", - "dev": true - }, - "helmet": { - "version": "3.12.0", - "resolved": "http://registry.npm.taobao.org/helmet/download/helmet-3.12.0.tgz", - "integrity": "sha1-IJjjXPTlHGTC8dOGcLfTgqN32Sw=", - "requires": { - "dns-prefetch-control": "0.1.0", - "dont-sniff-mimetype": "1.0.0", - "expect-ct": "0.1.0", - "frameguard": "3.0.0", - "helmet-csp": "2.7.0", - "hide-powered-by": "1.0.0", - "hpkp": "2.0.0", - "hsts": "2.1.0", - "ienoopen": "1.0.0", - "nocache": "2.0.0", - "referrer-policy": "1.1.0", - "x-xss-protection": "1.1.0" - } - }, - "helmet-csp": { - "version": "2.7.0", - "resolved": "http://registry.npm.taobao.org/helmet-csp/download/helmet-csp-2.7.0.tgz", - "integrity": "sha1-eTQJRhfR/re7LcQ7t9nogw93RxY=", - "requires": { - "camelize": "1.0.0", - "content-security-policy-builder": "2.0.0", - "dasherize": "2.0.0", - "lodash.reduce": "4.6.0", - "platform": "1.3.5" + "node_modules/prettier": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.7.1.tgz", + "integrity": "sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g==", + "dev": true, + "bin": { + "prettier": "bin-prettier.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" } }, - "hide-powered-by": { + "node_modules/prettier-linter-helpers": { "version": "1.0.0", - "resolved": "http://registry.npm.taobao.org/hide-powered-by/download/hide-powered-by-1.0.0.tgz", - "integrity": "sha1-SoWtZYgfYoV/xwr3F0oRhNzM4ys=" - }, - "hmacsha1": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/hmacsha1/-/hmacsha1-1.0.0.tgz", - "integrity": "sha1-wbeuA6TqEWNICQrxT4FIwSk4qRc=" - }, - "hoek": { - "version": "4.2.1", - "resolved": "http://registry.npm.taobao.org/hoek/download/hoek-4.2.1.tgz", - "integrity": "sha1-ljRQKqEsRF3Vp8VzS1cruHOKrLs=" + "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", + "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", + "dev": true, + "dependencies": { + "fast-diff": "^1.1.2" + }, + "engines": { + "node": ">=6.0.0" + } }, - "hpkp": { - "version": "2.0.0", - "resolved": "http://registry.npm.taobao.org/hpkp/download/hpkp-2.0.0.tgz", - "integrity": "sha1-EOFCJk52IVpdMMROxD3mTe5tFnI=" + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "dev": true }, - "hsts": { - "version": "2.1.0", - "resolved": "http://registry.npm.taobao.org/hsts/download/hsts-2.1.0.tgz", - "integrity": "sha1-y9bJGKI4X+4d1WgL+ys6GUwBIcw=" - }, - "http-errors": { - "version": "1.6.2", - "resolved": "http://registry.npm.taobao.org/http-errors/download/http-errors-1.6.2.tgz", - "integrity": "sha1-CgAsyFcHGSp+eUbO7cERVfYOxzY=", - "requires": { - "depd": "1.1.1", - "inherits": "2.0.3", - "setprototypeof": "1.0.3", - "statuses": ">= 1.3.1 < 2" - }, - "dependencies": { - "depd": { - "version": "1.1.1", - "resolved": "http://registry.npm.taobao.org/depd/download/depd-1.1.1.tgz", - "integrity": "sha1-V4O04cRZ8G+lyif5kfPQbnoxA1k=" - } + "node_modules/process-on-spawn": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/process-on-spawn/-/process-on-spawn-1.0.0.tgz", + "integrity": "sha512-1WsPDsUSMmZH5LeMLegqkPDrsGgsWwk1Exipy2hvB0o/F0ASzbpIctSCcZIK1ykJvtTJULEH+20WOFjMvGnCTg==", + "dev": true, + "dependencies": { + "fromentries": "^1.2.0" + }, + "engines": { + "node": ">=8" } }, - "http-signature": { - "version": "1.2.0", - "resolved": "http://registry.npm.taobao.org/http-signature/download/http-signature-1.2.0.tgz", - "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", - "requires": { - "assert-plus": "^1.0.0", - "jsprim": "^1.2.2", - "sshpk": "^1.7.0" + "node_modules/promise": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz", + "integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==", + "dependencies": { + "asap": "~2.0.3" } }, - "humanize-ms": { - "version": "1.2.1", - "resolved": "http://registry.npm.taobao.org/humanize-ms/download/humanize-ms-1.2.1.tgz", - "integrity": "sha1-xG4xWaKT9riW2ikxbYtv6Lt5u+0=", - "requires": { - "ms": "^2.0.0" + "node_modules/prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "dev": true, + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" } }, - "i18n": { - "version": "0.8.3", - "resolved": "http://registry.npm.taobao.org/i18n/download/i18n-0.8.3.tgz", - "integrity": "sha1-LYzxwkciYCwgQdAbpq5eqlE4jw4=", - "requires": { - "debug": "*", - "make-plural": "^3.0.3", - "math-interval-parser": "^1.1.0", - "messageformat": "^0.3.1", - "mustache": "*", - "sprintf-js": ">=1.0.3" - } - }, - "iconv-lite": { - "version": "0.4.19", - "resolved": "http://registry.npm.taobao.org/iconv-lite/download/iconv-lite-0.4.19.tgz", - "integrity": "sha1-90aPYBNfXl2tM5nAqBvpoWA6CCs=" - }, - "ieee754": { - "version": "1.1.10", - "resolved": "http://registry.npm.taobao.org/ieee754/download/ieee754-1.1.10.tgz", - "integrity": "sha1-cZpvewJoMeZL24OLDeG7ACm79xY=" - }, - "ienoopen": { - "version": "1.0.0", - "resolved": "http://registry.npm.taobao.org/ienoopen/download/ienoopen-1.0.0.tgz", - "integrity": "sha1-NGpCj0dKrI9QzzeE6i0PFvYr2ms=" + "node_modules/protobufjs": { + "version": "6.11.2", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.11.2.tgz", + "integrity": "sha512-4BQJoPooKJl2G9j3XftkIXjoC9C0Av2NOrWmbLWT1vH32GcSUHjM0Arra6UfTsVyfMAuFzaLucXn1sadxJydAw==", + "hasInstallScript": true, + "dependencies": { + "@protobufjs/aspromise": "^1.1.2", + "@protobufjs/base64": "^1.1.2", + "@protobufjs/codegen": "^2.0.4", + "@protobufjs/eventemitter": "^1.1.0", + "@protobufjs/fetch": "^1.1.0", + "@protobufjs/float": "^1.0.2", + "@protobufjs/inquire": "^1.1.0", + "@protobufjs/path": "^1.1.2", + "@protobufjs/pool": "^1.1.0", + "@protobufjs/utf8": "^1.1.0", + "@types/long": "^4.0.1", + "@types/node": ">=13.7.0", + "long": "^4.0.0" + }, + "bin": { + "pbjs": "bin/pbjs", + "pbts": "bin/pbts" + } }, - "ignorefs": { - "version": "1.2.0", - "resolved": "http://registry.npm.taobao.org/ignorefs/download/ignorefs-1.2.0.tgz", - "integrity": "sha1-2ln7hYl25KXkNwLM0fKC/byeV1Y=", - "requires": { - "editions": "^1.3.3", - "ignorepatterns": "^1.1.0" + "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==", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" } }, - "ignorepatterns": { - "version": "1.1.0", - "resolved": "http://registry.npm.taobao.org/ignorepatterns/download/ignorepatterns-1.1.0.tgz", - "integrity": "sha1-rI9DbyI5td+2bV8NOpBKh6xnzF4=" + "node_modules/proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-5.0.0.tgz", + "integrity": "sha512-gkH7BkvLVkSfX9Dk27W6TyNOWWZWRilRfk1XxGNWOYJ2TuedAv1yFpCaU9QSBmBe716XOTNpYNOzhysyw8xn7g==", + "dependencies": { + "agent-base": "^6.0.0", + "debug": "4", + "http-proxy-agent": "^4.0.0", + "https-proxy-agent": "^5.0.0", + "lru-cache": "^5.1.1", + "pac-proxy-agent": "^5.0.0", + "proxy-from-env": "^1.0.0", + "socks-proxy-agent": "^5.0.0" + }, + "engines": { + "node": ">= 8" + } }, - "imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=" + "node_modules/proxy-agent/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } }, - "inflight": { - "version": "1.0.6", - "resolved": "http://registry.npm.taobao.org/inflight/download/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "requires": { - "once": "^1.3.0", - "wrappy": "1" + "node_modules/proxy-agent/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==", + "dependencies": { + "yallist": "^3.0.2" } }, - "inherits": { - "version": "2.0.3", - "resolved": "http://registry.npm.taobao.org/inherits/download/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + "node_modules/proxy-agent/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, - "invert-kv": { - "version": "1.0.0", - "resolved": "http://registry.npm.taobao.org/invert-kv/download/invert-kv-1.0.0.tgz", - "integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY=" + "node_modules/proxy-agent/node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" }, - "ipaddr.js": { - "version": "1.6.0", - "resolved": "http://registry.npm.taobao.org/ipaddr.js/download/ipaddr.js-1.6.0.tgz", - "integrity": "sha1-4/o1e3c9phnybpXwSdBVxyeW+Gs=" + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" }, - "is-bluebird": { + "node_modules/pseudomap": { "version": "1.0.2", - "resolved": "http://registry.npm.taobao.org/is-bluebird/download/is-bluebird-1.0.2.tgz", - "integrity": "sha1-CWQ5Bg9KpBGr7hkUOoTWpVNG1uI=" + "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", + "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=" }, - "is-buffer": { - "version": "1.1.6", - "resolved": "http://registry.npm.taobao.org/is-buffer/download/is-buffer-1.1.6.tgz", - "integrity": "sha1-76ouqdqg16suoTqXsritUf776L4=" + "node_modules/psl": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", + "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==" }, - "is-expression": { - "version": "3.0.0", - "resolved": "http://registry.npm.taobao.org/is-expression/download/is-expression-3.0.0.tgz", - "integrity": "sha1-Oayqa+f9HzRx3ELHQW5hwkMXrJ8=", - "requires": { - "acorn": "~4.0.2", - "object-assign": "^4.0.1" - }, + "node_modules/pug": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/pug/-/pug-3.0.2.tgz", + "integrity": "sha512-bp0I/hiK1D1vChHh6EfDxtndHji55XP/ZJKwsRqrz6lRia6ZC2OZbdAymlxdVFwd1L70ebrVJw4/eZ79skrIaw==", "dependencies": { - "acorn": { - "version": "4.0.13", - "resolved": "http://registry.npm.taobao.org/acorn/download/acorn-4.0.13.tgz", - "integrity": "sha1-EFSVrlNh1pe9GVyCUZLhrX8lN4c=" - } + "pug-code-gen": "^3.0.2", + "pug-filters": "^4.0.0", + "pug-lexer": "^5.0.1", + "pug-linker": "^4.0.0", + "pug-load": "^3.0.0", + "pug-parser": "^6.0.0", + "pug-runtime": "^3.0.1", + "pug-strip-comments": "^2.0.0" } }, - "is-fullwidth-code-point": { - "version": "1.0.0", - "resolved": "http://registry.npm.taobao.org/is-fullwidth-code-point/download/is-fullwidth-code-point-1.0.0.tgz", - "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", - "requires": { - "number-is-nan": "^1.0.0" + "node_modules/pug-attrs": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pug-attrs/-/pug-attrs-3.0.0.tgz", + "integrity": "sha512-azINV9dUtzPMFQktvTXciNAfAuVh/L/JCl0vtPCwvOA21uZrC08K/UnmrL+SXGEVc1FwzjW62+xw5S/uaLj6cA==", + "dependencies": { + "constantinople": "^4.0.1", + "js-stringify": "^1.0.2", + "pug-runtime": "^3.0.0" } }, - "is-obj": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", - "integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8=" - }, - "is-promise": { - "version": "2.1.0", - "resolved": "http://registry.npm.taobao.org/is-promise/download/is-promise-2.1.0.tgz", - "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=" - }, - "is-regex": { - "version": "1.0.4", - "resolved": "http://registry.npm.taobao.org/is-regex/download/is-regex-1.0.4.tgz", - "integrity": "sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=", - "requires": { - "has": "^1.0.1" + "node_modules/pug-code-gen": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/pug-code-gen/-/pug-code-gen-3.0.2.tgz", + "integrity": "sha512-nJMhW16MbiGRiyR4miDTQMRWDgKplnHyeLvioEJYbk1RsPI3FuA3saEP8uwnTb2nTJEKBU90NFVWJBk4OU5qyg==", + "dependencies": { + "constantinople": "^4.0.1", + "doctypes": "^1.1.0", + "js-stringify": "^1.0.2", + "pug-attrs": "^3.0.0", + "pug-error": "^2.0.0", + "pug-runtime": "^3.0.0", + "void-elements": "^3.1.0", + "with": "^7.0.0" } }, - "is-stream": { - "version": "1.1.0", - "resolved": "http://registry.npm.taobao.org/is-stream/download/is-stream-1.1.0.tgz", - "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=" - }, - "is-typedarray": { - "version": "1.0.0", - "resolved": "http://registry.npm.taobao.org/is-typedarray/download/is-typedarray-1.0.0.tgz", - "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" - }, - "isarray": { - "version": "1.0.0", - "resolved": "http://registry.npm.taobao.org/isarray/download/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" - }, - "isexe": { + "node_modules/pug-error": { "version": "2.0.0", - "resolved": "http://registry.npm.taobao.org/isexe/download/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" + "resolved": "https://registry.npmjs.org/pug-error/-/pug-error-2.0.0.tgz", + "integrity": "sha512-sjiUsi9M4RAGHktC1drQfCr5C5eriu24Lfbt4s+7SykztEOwVZtbFk1RRq0tzLxcMxMYTBR+zMQaG07J/btayQ==" }, - "isstream": { - "version": "0.1.2", - "resolved": "http://registry.npm.taobao.org/isstream/download/isstream-0.1.2.tgz", - "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" - }, - "istanbul": { - "version": "0.4.5", - "resolved": "http://registry.npm.taobao.org/istanbul/download/istanbul-0.4.5.tgz", - "integrity": "sha1-ZcfXPUxNqE1POsMQuRj7C4Azczs=", - "dev": true, - "requires": { - "abbrev": "1.0.x", - "async": "1.x", - "escodegen": "1.8.x", - "esprima": "2.7.x", - "glob": "^5.0.15", - "handlebars": "^4.0.1", - "js-yaml": "3.x", - "mkdirp": "0.5.x", - "nopt": "3.x", - "once": "1.x", - "resolve": "1.1.x", - "supports-color": "^3.1.0", - "which": "^1.1.1", - "wordwrap": "^1.0.0" - }, + "node_modules/pug-filters": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/pug-filters/-/pug-filters-4.0.0.tgz", + "integrity": "sha512-yeNFtq5Yxmfz0f9z2rMXGw/8/4i1cCFecw/Q7+D0V2DdtII5UvqE12VaZ2AY7ri6o5RNXiweGH79OCq+2RQU4A==", "dependencies": { - "abbrev": { - "version": "1.0.9", - "resolved": "http://registry.npm.taobao.org/abbrev/download/abbrev-1.0.9.tgz", - "integrity": "sha1-kbR5JYinc4wl813W9jdSovh3YTU=", - "dev": true - }, - "escodegen": { - "version": "1.8.1", - "resolved": "http://registry.npm.taobao.org/escodegen/download/escodegen-1.8.1.tgz", - "integrity": "sha1-WltTr0aTEQvrsIZ6o0MN07cKEBg=", - "dev": true, - "requires": { - "esprima": "^2.7.1", - "estraverse": "^1.9.1", - "esutils": "^2.0.2", - "optionator": "^0.8.1", - "source-map": "~0.2.0" - } - }, - "esprima": { - "version": "2.7.3", - "resolved": "http://registry.npm.taobao.org/esprima/download/esprima-2.7.3.tgz", - "integrity": "sha1-luO3DVd59q1JzQMmc9HDEnZ7pYE=", - "dev": true - }, - "estraverse": { - "version": "1.9.3", - "resolved": "http://registry.npm.taobao.org/estraverse/download/estraverse-1.9.3.tgz", - "integrity": "sha1-r2fy3JIlgkFZUJJgkaQAXSnJu0Q=", - "dev": true - }, - "resolve": { - "version": "1.1.7", - "resolved": "http://registry.npm.taobao.org/resolve/download/resolve-1.1.7.tgz", - "integrity": "sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=", - "dev": true - }, - "source-map": { - "version": "0.2.0", - "resolved": "http://registry.npm.taobao.org/source-map/download/source-map-0.2.0.tgz", - "integrity": "sha1-2rc/vPwrqBm03gO9b26qSBZLP50=", - "dev": true, - "optional": true, - "requires": { - "amdefine": ">=0.0.4" - } - }, - "supports-color": { - "version": "3.2.3", - "resolved": "http://registry.npm.taobao.org/supports-color/download/supports-color-3.2.3.tgz", - "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=", - "dev": true, - "requires": { - "has-flag": "^1.0.0" - } - } + "constantinople": "^4.0.1", + "jstransformer": "1.0.0", + "pug-error": "^2.0.0", + "pug-walk": "^2.0.0", + "resolve": "^1.15.1" } }, - "jmespath": { - "version": "0.15.0", - "resolved": "http://registry.npm.taobao.org/jmespath/download/jmespath-0.15.0.tgz", - "integrity": "sha1-o/Iiqarp+Wb10nx5ZRDigJF2Qhc=" + "node_modules/pug-lexer": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/pug-lexer/-/pug-lexer-5.0.1.tgz", + "integrity": "sha512-0I6C62+keXlZPZkOJeVam9aBLVP2EnbeDw3An+k0/QlqdwH6rv8284nko14Na7c0TtqtogfWXcRoFE4O4Ff20w==", + "dependencies": { + "character-parser": "^2.2.0", + "is-expression": "^4.0.0", + "pug-error": "^2.0.0" + } }, - "js-stringify": { - "version": "1.0.2", - "resolved": "http://registry.npm.taobao.org/js-stringify/download/js-stringify-1.0.2.tgz", - "integrity": "sha1-Fzb939lyTyijaCrcYjCufk6Weds=" + "node_modules/pug-linker": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/pug-linker/-/pug-linker-4.0.0.tgz", + "integrity": "sha512-gjD1yzp0yxbQqnzBAdlhbgoJL5qIFJw78juN1NpTLt/mfPJ5VgC4BvkoD3G23qKzJtIIXBbcCt6FioLSFLOHdw==", + "dependencies": { + "pug-error": "^2.0.0", + "pug-walk": "^2.0.0" + } }, - "js-yaml": { - "version": "3.11.0", - "resolved": "http://registry.npm.taobao.org/js-yaml/download/js-yaml-3.11.0.tgz", - "integrity": "sha1-WXwai9VxUvJtYizkEXhRpR9euu8=", - "dev": true, - "requires": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - }, + "node_modules/pug-load": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pug-load/-/pug-load-3.0.0.tgz", + "integrity": "sha512-OCjTEnhLWZBvS4zni/WUMjH2YSUosnsmjGBB1An7CsKQarYSWQ0GCVyd4eQPMFJqZ8w9xgs01QdiZXKVjk92EQ==", "dependencies": { - "esprima": { - "version": "4.0.0", - "resolved": "http://registry.npm.taobao.org/esprima/download/esprima-4.0.0.tgz", - "integrity": "sha1-RJnt3NERDgshi6zy+n9/WfVcqAQ=", - "dev": true - } + "object-assign": "^4.1.1", + "pug-walk": "^2.0.0" } }, - "jsbn": { - "version": "0.1.1", - "resolved": "http://registry.npm.taobao.org/jsbn/download/jsbn-0.1.1.tgz", - "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", - "optional": true + "node_modules/pug-parser": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/pug-parser/-/pug-parser-6.0.0.tgz", + "integrity": "sha512-ukiYM/9cH6Cml+AOl5kETtM9NR3WulyVP2y4HOU45DyMim1IeP/OOiyEWRr6qk5I5klpsBnbuHpwKmTx6WURnw==", + "dependencies": { + "pug-error": "^2.0.0", + "token-stream": "1.0.0" + } }, - "jschardet": { - "version": "1.6.0", - "resolved": "http://registry.npm.taobao.org/jschardet/download/jschardet-1.6.0.tgz", - "integrity": "sha1-x9GnHtz/KDnbL57DD8XV69PBpng=" + "node_modules/pug-runtime": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/pug-runtime/-/pug-runtime-3.0.1.tgz", + "integrity": "sha512-L50zbvrQ35TkpHwv0G6aLSuueDRwc/97XdY8kL3tOT0FmhgG7UypU3VztfV/LATAvmUfYi4wNxSajhSAeNN+Kg==" }, - "json-schema": { - "version": "0.2.3", - "resolved": "http://registry.npm.taobao.org/json-schema/download/json-schema-0.2.3.tgz", - "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=" + "node_modules/pug-strip-comments": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pug-strip-comments/-/pug-strip-comments-2.0.0.tgz", + "integrity": "sha512-zo8DsDpH7eTkPHCXFeAk1xZXJbyoTfdPlNR0bK7rpOMuhBYb0f5qUVCO1xlsitYd3w5FQTK7zpNVKb3rZoUrrQ==", + "dependencies": { + "pug-error": "^2.0.0" + } }, - "json-schema-traverse": { - "version": "0.3.1", - "resolved": "http://registry.npm.taobao.org/json-schema-traverse/download/json-schema-traverse-0.3.1.tgz", - "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=" + "node_modules/pug-walk": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pug-walk/-/pug-walk-2.0.0.tgz", + "integrity": "sha512-yYELe9Q5q9IQhuvqsZNwA5hfPkMJ8u92bQLIMcsMxf/VADjNtEYptU+inlufAFYcWdHlwNfZOEnOOQrZrcyJCQ==" }, - "json-stringify-safe": { - "version": "5.0.1", - "resolved": "http://registry.npm.taobao.org/json-stringify-safe/download/json-stringify-safe-5.0.1.tgz", - "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" + "node_modules/pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } }, - "json3": { - "version": "3.3.2", - "resolved": "http://registry.npm.taobao.org/json3/download/json3-3.3.2.tgz", - "integrity": "sha1-PAQ0dD35Pi9cQq7nsZvLSDV19OE=", - "dev": true + "node_modules/q": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", + "integrity": "sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=", + "deprecated": "You or someone you depend on is using Q, the JavaScript Promise library that gave JavaScript developers strong feelings about promises. They can almost certainly migrate to the native JavaScript promise now. Thank you literally everyone for joining me in this bet against the odds. Be excellent to each other.\n\n(For a CapTP with native promises, see @endo/eventual-send and @endo/captp)", + "dev": true, + "engines": { + "node": ">=0.6.0", + "teleport": ">=0.2.0" + } }, - "jsonfile": { - "version": "4.0.0", - "resolved": "http://registry.npm.taobao.org/jsonfile/download/jsonfile-4.0.0.tgz", - "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", - "requires": { - "graceful-fs": "^4.1.6" + "node_modules/qiniu": { + "version": "7.7.0", + "resolved": "https://registry.npmjs.org/qiniu/-/qiniu-7.7.0.tgz", + "integrity": "sha512-p8wZHDXzqCVtlPIygqIzpO6P59e5KcNAOf85oi6O7K5M4xjnwoi6L3e0F8IXgd38nb2PzWOH3XUkSbNAYW0g7Q==", + "dependencies": { + "agentkeepalive": "^4.0.2", + "before": "^0.0.1", + "block-stream2": "^2.0.0", + "crc32": "^0.2.2", + "destroy": "^1.0.4", + "encodeurl": "^1.0.1", + "formstream": "^1.1.0", + "mime": "^2.4.4", + "mockdate": "^3.0.5", + "tunnel-agent": "^0.6.0", + "urllib": "^2.34.1" + }, + "engines": { + "node": ">= 6" } }, - "jsonwebtoken": { - "version": "8.2.0", - "resolved": "http://registry.npm.taobao.org/jsonwebtoken/download/jsonwebtoken-8.2.0.tgz", - "integrity": "sha1-aQ7DqefpXiiENHzj6eudOJqlmLM=", - "requires": { - "jws": "^3.1.4", - "lodash.includes": "^4.3.0", - "lodash.isboolean": "^3.0.3", - "lodash.isinteger": "^4.0.4", - "lodash.isnumber": "^3.0.3", - "lodash.isplainobject": "^4.0.6", - "lodash.isstring": "^4.0.1", - "lodash.once": "^4.0.0", - "ms": "^2.1.1", - "xtend": "^4.0.1" + "node_modules/qiniu/node_modules/mime": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", + "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", + "bin": { + "mime": "cli.js" }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/qs": { + "version": "6.10.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.3.tgz", + "integrity": "sha512-wr7M2E0OFRfIfJZjKGieI8lBKb7fRCH4Fv5KNPEs7gJ8jadvotdsS08PzOKR7opXhZ/Xkjtt3WF9g38drmyRqQ==", "dependencies": { - "ms": { - "version": "2.1.1", - "resolved": "http://registry.npm.taobao.org/ms/download/ms-2.1.1.tgz", - "integrity": "sha1-MKWGTrPrsKZvLr5tcnrwagnYbgo=" - } + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "jsprim": { - "version": "1.4.1", - "resolved": "http://registry.npm.taobao.org/jsprim/download/jsprim-1.4.1.tgz", - "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", - "requires": { - "assert-plus": "1.0.0", - "extsprintf": "1.3.0", - "json-schema": "0.2.3", - "verror": "1.10.0" + "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==", + "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" + } + ] + }, + "node_modules/quick-lru": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-4.0.1.tgz", + "integrity": "sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==", + "dev": true, + "engines": { + "node": ">=8" } }, - "jstransformer": { - "version": "1.0.0", - "resolved": "http://registry.npm.taobao.org/jstransformer/download/jstransformer-1.0.0.tgz", - "integrity": "sha1-7Yvwkh4vPx7U1cGkT2hwntJHIsM=", - "requires": { - "is-promise": "^2.0.0", - "promise": "^7.0.1" + "node_modules/rand-token": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/rand-token/-/rand-token-1.0.1.tgz", + "integrity": "sha512-Zri5SfJmEzBJ3IexFdigvPSCamslJ7UjLkUn0tlgH7COJvaUr5V7FyUYgKifEMTw7gFO8ZLcWjcU+kq8akipzg==", + "engines": { + "node": ">= 10" } }, - "jwa": { - "version": "1.1.5", - "resolved": "http://registry.npm.taobao.org/jwa/download/jwa-1.1.5.tgz", - "integrity": "sha1-oFUs4CIHQs1S4VN3SjKQXDDnVuU=", - "requires": { - "base64url": "2.0.0", - "buffer-equal-constant-time": "1.0.1", - "ecdsa-sig-formatter": "1.0.9", - "safe-buffer": "^5.0.1" + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "dependencies": { + "safe-buffer": "^5.1.0" } }, - "jws": { - "version": "3.1.4", - "resolved": "http://registry.npm.taobao.org/jws/download/jws-3.1.4.tgz", - "integrity": "sha1-+ei5M46KhHJ31kRLFGT2GIDgUKI=", - "requires": { - "base64url": "^2.0.0", - "jwa": "^1.1.4", - "safe-buffer": "^5.0.1" + "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==", + "engines": { + "node": ">= 0.6" } }, - "kind-of": { - "version": "3.2.2", - "resolved": "http://registry.npm.taobao.org/kind-of/download/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "requires": { - "is-buffer": "^1.1.5" + "node_modules/raw-body": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", + "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" } }, - "lazy-cache": { - "version": "1.0.4", - "resolved": "http://registry.npm.taobao.org/lazy-cache/download/lazy-cache-1.0.4.tgz", - "integrity": "sha1-odePw6UEdMuAhF07O24dpJpEbo4=" + "node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "dev": true }, - "lcid": { - "version": "1.0.0", - "resolved": "http://registry.npm.taobao.org/lcid/download/lcid-1.0.0.tgz", - "integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=", - "requires": { - "invert-kv": "^1.0.0" + "node_modules/read-pkg": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", + "integrity": "sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=", + "dev": true, + "dependencies": { + "load-json-file": "^4.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^3.0.0" + }, + "engines": { + "node": ">=4" } }, - "levn": { - "version": "0.3.0", - "resolved": "http://registry.npm.taobao.org/levn/download/levn-0.3.0.tgz", - "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", + "node_modules/read-pkg-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-3.0.0.tgz", + "integrity": "sha1-PtSWaF26D4/hGNBpHcUfSh/5bwc=", "dev": true, - "requires": { - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2" + "dependencies": { + "find-up": "^2.0.0", + "read-pkg": "^3.0.0" + }, + "engines": { + "node": ">=4" } }, - "linkify-it": { - "version": "2.0.3", - "resolved": "http://registry.npm.taobao.org/linkify-it/download/linkify-it-2.0.3.tgz", - "integrity": "sha1-2UpGSPmxwXnWT6lykSaL22zpQ08=", - "requires": { - "uc.micro": "^1.0.1" + "node_modules/read-pkg-up/node_modules/find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dev": true, + "dependencies": { + "locate-path": "^2.0.0" + }, + "engines": { + "node": ">=4" } }, - "locate-path": { - "version": "3.0.0", - "resolved": "http://registry.npm.taobao.org/locate-path/download/locate-path-3.0.0.tgz", - "integrity": "sha1-2+w7OrdZdYBxtY/ln8QYca8hQA4=", - "requires": { - "p-locate": "^3.0.0", + "node_modules/read-pkg-up/node_modules/locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "dev": true, + "dependencies": { + "p-locate": "^2.0.0", "path-exists": "^3.0.0" + }, + "engines": { + "node": ">=4" } }, - "lodash": { - "version": "4.17.5", - "resolved": "http://registry.npm.taobao.org/lodash/download/lodash-4.17.5.tgz", - "integrity": "sha1-maktZcAnLevoyWtgV7yPv6O+1RE=" - }, - "lodash._baseassign": { - "version": "3.2.0", - "resolved": "http://registry.npm.taobao.org/lodash._baseassign/download/lodash._baseassign-3.2.0.tgz", - "integrity": "sha1-jDigmVAPIVrQnlnxci/QxSv+Ck4=", + "node_modules/read-pkg-up/node_modules/p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", "dev": true, - "requires": { - "lodash._basecopy": "^3.0.0", - "lodash.keys": "^3.0.0" + "dependencies": { + "p-try": "^1.0.0" + }, + "engines": { + "node": ">=4" } }, - "lodash._basecopy": { - "version": "3.0.1", - "resolved": "http://registry.npm.taobao.org/lodash._basecopy/download/lodash._basecopy-3.0.1.tgz", - "integrity": "sha1-jaDmqHbPNEwK2KVIghEd08XHyjY=", - "dev": true - }, - "lodash._basecreate": { - "version": "3.0.3", - "resolved": "http://registry.npm.taobao.org/lodash._basecreate/download/lodash._basecreate-3.0.3.tgz", - "integrity": "sha1-G8ZhYU2qf8MRt9A78WgGoCE8+CE=", - "dev": true + "node_modules/read-pkg-up/node_modules/p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "dev": true, + "dependencies": { + "p-limit": "^1.1.0" + }, + "engines": { + "node": ">=4" + } }, - "lodash._getnative": { - "version": "3.9.1", - "resolved": "http://registry.npm.taobao.org/lodash._getnative/download/lodash._getnative-3.9.1.tgz", - "integrity": "sha1-VwvH3t5G1hzc3mh9ZdPuy6o6r/U=", - "dev": true + "node_modules/read-pkg-up/node_modules/p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", + "dev": true, + "engines": { + "node": ">=4" + } }, - "lodash._isiterateecall": { - "version": "3.0.9", - "resolved": "http://registry.npm.taobao.org/lodash._isiterateecall/download/lodash._isiterateecall-3.0.9.tgz", - "integrity": "sha1-UgOte6Ql+uhCRg5pbbnPPmqsBXw=", + "node_modules/read-pkg/node_modules/hosted-git-info": { + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", "dev": true }, - "lodash.create": { - "version": "3.1.1", - "resolved": "http://registry.npm.taobao.org/lodash.create/download/lodash.create-3.1.1.tgz", - "integrity": "sha1-1/KEnw29p+BGgruM1yqwIkYd6+c=", + "node_modules/read-pkg/node_modules/normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", "dev": true, - "requires": { - "lodash._baseassign": "^3.0.0", - "lodash._basecreate": "^3.0.0", - "lodash._isiterateecall": "^3.0.0" + "dependencies": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" } }, - "lodash.includes": { - "version": "4.3.0", - "resolved": "http://registry.npm.taobao.org/lodash.includes/download/lodash.includes-4.3.0.tgz", - "integrity": "sha1-YLuYqHy5I8aMoeUTJUgzFISfVT8=" - }, - "lodash.isarguments": { - "version": "3.1.0", - "resolved": "http://registry.npm.taobao.org/lodash.isarguments/download/lodash.isarguments-3.1.0.tgz", - "integrity": "sha1-L1c9hcaiQon/AGY7SRwdM4/zRYo=", - "dev": true - }, - "lodash.isarray": { - "version": "3.0.4", - "resolved": "http://registry.npm.taobao.org/lodash.isarray/download/lodash.isarray-3.0.4.tgz", - "integrity": "sha1-eeTriMNqgSKvhvhEqpvNhRtfu1U=", - "dev": true + "node_modules/read-pkg/node_modules/path-type": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", + "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", + "dev": true, + "dependencies": { + "pify": "^3.0.0" + }, + "engines": { + "node": ">=4" + } }, - "lodash.isboolean": { - "version": "3.0.3", - "resolved": "http://registry.npm.taobao.org/lodash.isboolean/download/lodash.isboolean-3.0.3.tgz", - "integrity": "sha1-bC4XHbKiV82WgC/UOwGyDV9YcPY=" + "node_modules/read-pkg/node_modules/pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true, + "engines": { + "node": ">=4" + } }, - "lodash.isinteger": { - "version": "4.0.4", - "resolved": "http://registry.npm.taobao.org/lodash.isinteger/download/lodash.isinteger-4.0.4.tgz", - "integrity": "sha1-YZwK89A/iwTDH1iChAt3sRzWg0M=" + "node_modules/read-pkg/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, + "bin": { + "semver": "bin/semver" + } }, - "lodash.isnumber": { - "version": "3.0.3", - "resolved": "http://registry.npm.taobao.org/lodash.isnumber/download/lodash.isnumber-3.0.3.tgz", - "integrity": "sha1-POdoEMWSjQM1IwGsKHMX8RwLH/w=" + "node_modules/readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } }, - "lodash.isplainobject": { - "version": "4.0.6", - "resolved": "http://registry.npm.taobao.org/lodash.isplainobject/download/lodash.isplainobject-4.0.6.tgz", - "integrity": "sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs=" + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } }, - "lodash.isstring": { - "version": "4.0.1", - "resolved": "http://registry.npm.taobao.org/lodash.isstring/download/lodash.isstring-4.0.1.tgz", - "integrity": "sha1-1SfftUVuynzJu5XV2ur4i6VKVFE=" + "node_modules/recursive-readdir": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/recursive-readdir/-/recursive-readdir-2.2.2.tgz", + "integrity": "sha512-nRCcW9Sj7NuZwa2XvH9co8NPeXUBhZP7CRKJtU+cS6PW9FpCIFoI5ib0NT1ZrbNuPoRy0ylyCaUL8Gih4LSyFg==", + "dependencies": { + "minimatch": "3.0.4" + }, + "engines": { + "node": ">=0.10.0" + } }, - "lodash.keys": { - "version": "3.1.2", - "resolved": "http://registry.npm.taobao.org/lodash.keys/download/lodash.keys-3.1.2.tgz", - "integrity": "sha1-TbwEcrFWvlCgsoaFXRvQsMZWCYo=", + "node_modules/redent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", + "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==", "dev": true, - "requires": { - "lodash._getnative": "^3.0.0", - "lodash.isarguments": "^3.0.0", - "lodash.isarray": "^3.0.0" + "dependencies": { + "indent-string": "^4.0.0", + "strip-indent": "^3.0.0" + }, + "engines": { + "node": ">=8" } }, - "lodash.once": { - "version": "4.1.1", - "resolved": "http://registry.npm.taobao.org/lodash.once/download/lodash.once-4.1.1.tgz", - "integrity": "sha1-DdOXEhPHxW34gJd9UEyI+0cal6w=" + "node_modules/redis": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/redis/-/redis-4.2.0.tgz", + "integrity": "sha512-bCR0gKVhIXFg8zCQjXEANzgI01DDixtPZgIUZHBCmwqixnu+MK3Tb2yqGjh+HCLASQVVgApiwhNkv+FoedZOGQ==", + "dependencies": { + "@redis/bloom": "1.0.2", + "@redis/client": "1.2.0", + "@redis/graph": "1.0.1", + "@redis/json": "1.0.3", + "@redis/search": "1.0.6", + "@redis/time-series": "1.0.3" + } + }, + "node_modules/regenerator-runtime": { + "version": "0.13.9", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz", + "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==", + "dev": true }, - "lodash.reduce": { - "version": "4.6.0", - "resolved": "http://registry.npm.taobao.org/lodash.reduce/download/lodash.reduce-4.6.0.tgz", - "integrity": "sha1-8atrg5KZrUj3hKu/R2WW8DuRTTs=" + "node_modules/regexp.prototype.flags": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz", + "integrity": "sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "functions-have-names": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "log4js": { - "version": "3.0.5", - "resolved": "http://registry.npm.taobao.org/log4js/download/log4js-3.0.5.tgz", - "integrity": "sha1-uAFGv+utaLQw1PNWlVbYpu3+8wM=", - "requires": { - "circular-json": "^0.5.5", - "date-format": "^1.2.0", - "debug": "^3.1.0", - "rfdc": "^1.1.2", - "streamroller": "0.7.0" - } - }, - "long": { - "version": "2.4.0", - "resolved": "http://registry.npm.taobao.org/long/download/long-2.4.0.tgz", - "integrity": "sha1-n6GAux2VAM3CnEFWdmoZleH0Uk8=" - }, - "longest": { - "version": "1.0.1", - "resolved": "http://registry.npm.taobao.org/longest/download/longest-1.0.1.tgz", - "integrity": "sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc=" - }, - "lru-cache": { - "version": "4.1.3", - "resolved": "http://registry.npm.taobao.org/lru-cache/download/lru-cache-4.1.3.tgz", - "integrity": "sha1-oRdc80lt/IQ2wVbDNLSVWZK85pw=", - "requires": { - "pseudomap": "^1.0.2", - "yallist": "^2.1.2" + "node_modules/regexpp": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", + "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" } }, - "make-dir": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz", - "integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==", - "requires": { - "pify": "^3.0.0" + "node_modules/release-zalgo": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/release-zalgo/-/release-zalgo-1.0.0.tgz", + "integrity": "sha1-CXALflB0Mpc5Mw5TXFqQ+2eFFzA=", + "dev": true, + "dependencies": { + "es6-error": "^4.0.1" + }, + "engines": { + "node": ">=4" } }, - "make-plural": { - "version": "3.0.6", - "resolved": "http://registry.npm.taobao.org/make-plural/download/make-plural-3.0.6.tgz", - "integrity": "sha1-IDOgO6wpC487uRJY9lud9+iwHKc=", - "requires": { - "minimist": "^1.2.0" + "node_modules/request": { + "version": "2.88.2", + "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", + "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", + "deprecated": "request has been deprecated, see https://github.com/request/request/issues/3142", + "dependencies": { + "aws-sign2": "~0.7.0", + "aws4": "^1.8.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", + "forever-agent": "~0.6.1", + "form-data": "~2.3.2", + "har-validator": "~5.1.3", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.19", + "oauth-sign": "~0.9.0", + "performance-now": "^2.1.0", + "qs": "~6.5.2", + "safe-buffer": "^5.1.2", + "tough-cookie": "~2.5.0", + "tunnel-agent": "^0.6.0", + "uuid": "^3.3.2" }, - "dependencies": { - "minimist": { - "version": "1.2.0", - "resolved": "http://registry.npm.taobao.org/minimist/download/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", - "optional": true - } + "engines": { + "node": ">= 6" } }, - "markdown-it": { - "version": "8.4.1", - "resolved": "http://registry.npm.taobao.org/markdown-it/download/markdown-it-8.4.1.tgz", - "integrity": "sha1-IG/lmw5OG3inxzJQr5s0pK0Kr0Q=", - "requires": { - "argparse": "^1.0.7", - "entities": "~1.1.1", - "linkify-it": "^2.0.0", - "mdurl": "^1.0.1", - "uc.micro": "^1.0.5" + "node_modules/request/node_modules/qs": { + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz", + "integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==", + "engines": { + "node": ">=0.6" } }, - "math-interval-parser": { - "version": "1.1.0", - "resolved": "http://registry.npm.taobao.org/math-interval-parser/download/math-interval-parser-1.1.0.tgz", - "integrity": "sha1-2+2lsGsySZc8bfYXD94jhvCv2JM=", - "requires": { - "xregexp": "^2.0.0" + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", + "engines": { + "node": ">=0.10.0" } }, - "md5": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/md5/-/md5-2.2.1.tgz", - "integrity": "sha1-U6s41f48iJG6RlMp6iP6wFQBJvk=", - "requires": { - "charenc": "~0.0.1", - "crypt": "~0.0.1", - "is-buffer": "~1.1.1" + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "engines": { + "node": ">=0.10.0" } }, - "mdurl": { - "version": "1.0.1", - "resolved": "http://registry.npm.taobao.org/mdurl/download/mdurl-1.0.1.tgz", - "integrity": "sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4=" - }, - "media-typer": { - "version": "0.3.0", - "resolved": "http://registry.npm.taobao.org/media-typer/download/media-typer-0.3.0.tgz", - "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" + "node_modules/require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", + "dev": true }, - "mem": { - "version": "1.1.0", - "resolved": "http://registry.npm.taobao.org/mem/download/mem-1.1.0.tgz", - "integrity": "sha1-Xt1StIXKHZAP5kiVUFOZoN+kX3Y=", - "requires": { - "mimic-fn": "^1.0.0" + "node_modules/resolve": { + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz", + "integrity": "sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==", + "dependencies": { + "is-core-module": "^2.8.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "merge-descriptors": { - "version": "1.0.1", - "resolved": "http://registry.npm.taobao.org/merge-descriptors/download/merge-descriptors-1.0.1.tgz", - "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" - }, - "messageformat": { - "version": "0.3.1", - "resolved": "http://registry.npm.taobao.org/messageformat/download/messageformat-0.3.1.tgz", - "integrity": "sha1-5Y//gkXps5cXmeW0PbWLPpQX9aI=", - "requires": { - "async": "~1.5.2", - "glob": "~6.0.4", - "make-plural": "~3.0.3", - "nopt": "~3.0.6", - "watchr": "~2.4.13" - }, - "dependencies": { - "glob": { - "version": "6.0.4", - "resolved": "http://registry.npm.taobao.org/glob/download/glob-6.0.4.tgz", - "integrity": "sha1-DwiGD2oVUSey+t1PnOJLGqtuTSI=", - "requires": { - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "2 || 3", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - } + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "engines": { + "node": ">=4" } }, - "methods": { - "version": "1.1.2", - "resolved": "http://registry.npm.taobao.org/methods/download/methods-1.1.2.tgz", - "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" + "node_modules/retry-as-promised": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/retry-as-promised/-/retry-as-promised-5.0.0.tgz", + "integrity": "sha512-6S+5LvtTl2ggBumk04hBo/4Uf6fRJUwIgunGZ7CYEBCeufGFW1Pu6ucUf/UskHeWOIsUcLOGLFXPig5tR5V1nA==" }, - "mime-db": { - "version": "1.33.0", - "resolved": "http://registry.npm.taobao.org/mime-db/download/mime-db-1.33.0.tgz", - "integrity": "sha1-o0kgUKXLm2NFBUHjnZeI0icng9s=" + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } }, - "mime-types": { - "version": "2.1.18", - "resolved": "http://registry.npm.taobao.org/mime-types/download/mime-types-2.1.18.tgz", - "integrity": "sha1-bzI/YKg9ERRvgx/xH9ZuL+VQO7g=", - "requires": { - "mime-db": "~1.33.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, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "mimic-fn": { + "node_modules/run-parallel": { "version": "1.2.0", - "resolved": "http://registry.npm.taobao.org/mimic-fn/download/mimic-fn-1.2.0.tgz", - "integrity": "sha1-ggyGo5M0ZA6ZUWkovQP8qIBX0CI=" - }, - "minimatch": { - "version": "3.0.4", - "resolved": "http://registry.npm.taobao.org/minimatch/download/minimatch-3.0.4.tgz", - "integrity": "sha1-UWbihkV/AzBgZL5Ul+jbsMPTIIM=", - "requires": { - "brace-expansion": "^1.1.7" + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" } }, - "minimist": { - "version": "0.0.8", - "resolved": "http://registry.npm.taobao.org/minimist/download/minimist-0.0.8.tgz", - "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" - }, - "mkdirp": { - "version": "0.5.0", - "resolved": "http://registry.npm.taobao.org/mkdirp/download/mkdirp-0.5.0.tgz", - "integrity": "sha1-HXMHam35hs2TROFecfzAWkyavxI=", - "requires": { - "minimist": "0.0.8" + "node_modules/rxjs": { + "version": "7.5.6", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.5.6.tgz", + "integrity": "sha512-dnyv2/YsXhnm461G+R/Pe5bWP41Nm6LBXEYWI6eiFP4fiwx6WRI/CD0zbdVAudd9xwLEF2IDcKXLHit0FYjUzw==", + "dev": true, + "dependencies": { + "tslib": "^2.1.0" } }, - "mocha": { - "version": "3.5.3", - "resolved": "http://registry.npm.taobao.org/mocha/download/mocha-3.5.3.tgz", - "integrity": "sha1-HgSA/jbS2lhY0etqzDhBiybqog0=", - "dev": true, - "requires": { - "browser-stdout": "1.3.0", - "commander": "2.9.0", - "debug": "2.6.8", - "diff": "3.2.0", - "escape-string-regexp": "1.0.5", - "glob": "7.1.1", - "growl": "1.9.2", - "he": "1.1.1", - "json3": "3.3.2", - "lodash.create": "3.1.1", - "mkdirp": "0.5.1", - "supports-color": "3.1.2" - }, - "dependencies": { - "commander": { - "version": "2.9.0", - "resolved": "http://registry.npm.taobao.org/commander/download/commander-2.9.0.tgz", - "integrity": "sha1-nJkJQXbhIkDLItbFFGCYQA/g99Q=", - "dev": true, - "requires": { - "graceful-readlink": ">= 1.0.0" - } - }, - "debug": { - "version": "2.6.8", - "resolved": "http://registry.npm.taobao.org/debug/download/debug-2.6.8.tgz", - "integrity": "sha1-5zFTHKLt4n0YgiJCfaF4IdaP9Pw=", - "dev": true, - "requires": { - "ms": "2.0.0" - } + "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" }, - "glob": { - "version": "7.1.1", - "resolved": "http://registry.npm.taobao.org/glob/download/glob-7.1.1.tgz", - "integrity": "sha1-gFIR3wT6rxxjo2ADBs31reULLsg=", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.2", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } + { + "type": "patreon", + "url": "https://www.patreon.com/feross" }, - "mkdirp": { - "version": "0.5.1", - "resolved": "http://registry.npm.taobao.org/mkdirp/download/mkdirp-0.5.1.tgz", - "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", - "dev": true, - "requires": { - "minimist": "0.0.8" - } - }, - "supports-color": { - "version": "3.1.2", - "resolved": "http://registry.npm.taobao.org/supports-color/download/supports-color-3.1.2.tgz", - "integrity": "sha1-cqJiiU2dQIuVbKBf83su2KbiotU=", - "dev": true, - "requires": { - "has-flag": "^1.0.0" - } + { + "type": "consulting", + "url": "https://feross.org/support" } - } + ] }, - "moment": { - "version": "2.21.0", - "resolved": "http://registry.npm.taobao.org/moment/download/moment-2.21.0.tgz", - "integrity": "sha1-KhFLUdKm7J5tg8+AP4OKh42KAjo=" + "node_modules/safe-identifier": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/safe-identifier/-/safe-identifier-0.4.2.tgz", + "integrity": "sha512-6pNbSMW6OhAi9j+N8V+U715yBQsaWJ7eyEUaOrawX+isg5ZxhUlV1NipNtgaKHmFGiABwt+ZF04Ii+3Xjkg+8w==" }, - "moment-timezone": { - "version": "0.5.14", - "resolved": "http://registry.npm.taobao.org/moment-timezone/download/moment-timezone-0.5.14.tgz", - "integrity": "sha1-TrOP+VOLgBCLpGekWPPtQmjM/LE=", - "requires": { - "moment": ">= 2.9.0" + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "node_modules/sax": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/sax/-/sax-0.6.1.tgz", + "integrity": "sha1-VjsZx8HeiS4Jv8Ty/DDjwn8JUrk=" + }, + "node_modules/semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" } }, - "morgan": { - "version": "1.9.0", - "resolved": "http://registry.npm.taobao.org/morgan/download/morgan-1.9.0.tgz", - "integrity": "sha1-0B+mxlhZt2/PMbPLU6OCGjEdgFE=", - "requires": { - "basic-auth": "~2.0.0", + "node_modules/send": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", + "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "dependencies": { "debug": "2.6.9", - "depd": "~1.1.1", - "on-finished": "~2.3.0", - "on-headers": "~1.0.1" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "http://registry.npm.taobao.org/debug/download/debug-2.6.9.tgz", - "integrity": "sha1-XRKFFd8TT/Mn6QpMk/Tgd6U2NB8=", - "requires": { - "ms": "2.0.0" - } - } + "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" } }, - "ms": { + "node_modules/send/node_modules/depd": { "version": "2.0.0", - "resolved": "http://registry.npm.taobao.org/ms/download/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "engines": { + "node": ">= 0.8" + } }, - "mustache": { - "version": "2.3.0", - "resolved": "http://registry.npm.taobao.org/mustache/download/mustache-2.3.0.tgz", - "integrity": "sha1-QCj3d4sXcIpImTCm5SrDvKDaQdA=" - }, - "mysql2": { - "version": "1.5.2", - "resolved": "http://registry.npm.taobao.org/mysql2/download/mysql2-1.5.2.tgz", - "integrity": "sha1-5OBzg5uxCXJmmyQOx3Bh1/9Vz1k=", - "requires": { - "cardinal": "1.0.0", - "denque": "^1.1.1", - "generate-function": "^2.0.0", - "iconv-lite": "^0.4.18", - "long": "^4.0.0", - "lru-cache": "^4.1.1", - "named-placeholders": "1.1.1", - "object-assign": "^4.1.1", - "readable-stream": "2.3.2", - "safe-buffer": "^5.0.1", - "seq-queue": "0.0.5", - "sqlstring": "^2.2.0" - }, + "node_modules/send/node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "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==" + }, + "node_modules/send/node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/seq-queue": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/seq-queue/-/seq-queue-0.0.5.tgz", + "integrity": "sha1-1WgS4cAXpuTnw+Ojeh2m143TyT4=" + }, + "node_modules/sequelize": { + "version": "6.21.3", + "resolved": "https://registry.npmjs.org/sequelize/-/sequelize-6.21.3.tgz", + "integrity": "sha512-cJPrTTVCofUxaaNKoIETiXCYh2xJ+OFq5jMHJQqftp34M4kNoLpTfUMPSwYtRUeTcSh1/5HodfJXIBi7troIFA==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/sequelize" + } + ], "dependencies": { - "long": { - "version": "4.0.0", - "resolved": "http://registry.npm.taobao.org/long/download/long-4.0.0.tgz", - "integrity": "sha1-mntxz7fTYaGU6lVSQckvdGjVvyg=" + "@types/debug": "^4.1.7", + "@types/validator": "^13.7.1", + "debug": "^4.3.3", + "dottie": "^2.0.2", + "inflection": "^1.13.2", + "lodash": "^4.17.21", + "moment": "^2.29.1", + "moment-timezone": "^0.5.34", + "pg-connection-string": "^2.5.0", + "retry-as-promised": "^5.0.0", + "semver": "^7.3.5", + "sequelize-pool": "^7.1.0", + "toposort-class": "^1.0.1", + "uuid": "^8.3.2", + "validator": "^13.7.0", + "wkx": "^0.5.0" + }, + "engines": { + "node": ">=10.0.0" + }, + "peerDependenciesMeta": { + "ibm_db": { + "optional": true + }, + "mariadb": { + "optional": true + }, + "mysql2": { + "optional": true + }, + "pg": { + "optional": true + }, + "pg-hstore": { + "optional": true }, - "lru-cache": { - "version": "4.1.2", - "resolved": "http://registry.npm.taobao.org/lru-cache/download/lru-cache-4.1.2.tgz", - "integrity": "sha1-RSNLLm4vKzPaElYkxGZJKaAiTD8=", - "requires": { - "pseudomap": "^1.0.2", - "yallist": "^2.1.2" - } + "snowflake-sdk": { + "optional": true }, - "process-nextick-args": { - "version": "1.0.7", - "resolved": "http://registry.npm.taobao.org/process-nextick-args/download/process-nextick-args-1.0.7.tgz", - "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=" + "sqlite3": { + "optional": true }, - "readable-stream": { - "version": "2.3.2", - "resolved": "http://registry.npm.taobao.org/readable-stream/download/readable-stream-2.3.2.tgz", - "integrity": "sha1-WgTfBeT1f+Pw3Gj90R3FyXx+b00=", - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~1.0.6", - "safe-buffer": "~5.1.0", - "string_decoder": "~1.0.0", - "util-deprecate": "~1.0.1" - } + "tedious": { + "optional": true } } }, - "named-placeholders": { - "version": "1.1.1", - "resolved": "http://registry.npm.taobao.org/named-placeholders/download/named-placeholders-1.1.1.tgz", - "integrity": "sha1-O3oNJiA910s6nfTJz7gnsvuQfmQ=", - "requires": { - "lru-cache": "2.5.0" - }, - "dependencies": { - "lru-cache": { - "version": "2.5.0", - "resolved": "http://registry.npm.taobao.org/lru-cache/download/lru-cache-2.5.0.tgz", - "integrity": "sha1-2COIrpyWC+y+oMc7uet5tsbOmus=" - } + "node_modules/sequelize-pool": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/sequelize-pool/-/sequelize-pool-7.1.0.tgz", + "integrity": "sha512-G9c0qlIWQSK29pR/5U2JF5dDQeqqHRragoyahj/Nx4KOOQ3CPPfzxnfqFPCSB7x5UgjOgnZ61nSxz+fjDpRlJg==", + "engines": { + "node": ">= 10.0.0" } }, - "negotiator": { - "version": "0.6.1", - "resolved": "http://registry.npm.taobao.org/negotiator/download/negotiator-0.6.1.tgz", - "integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk=" - }, - "nocache": { - "version": "2.0.0", - "resolved": "http://registry.npm.taobao.org/nocache/download/nocache-2.0.0.tgz", - "integrity": "sha1-ICtIAhoMTL3i34DeFaF0Q8i0OYA=" - }, - "node_memcached": { - "version": "1.1.3", - "resolved": "http://registry.npm.taobao.org/node_memcached/download/node_memcached-1.1.3.tgz", - "integrity": "sha1-icFSr4itKIF/ANiRyZBFHV1xLqg=", - "requires": { - "debug": "^2.1.0" - }, + "node_modules/sequelize/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "http://registry.npm.taobao.org/debug/download/debug-2.6.9.tgz", - "integrity": "sha1-XRKFFd8TT/Mn6QpMk/Tgd6U2NB8=", - "requires": { - "ms": "2.0.0" - } + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true } } }, - "nodemailer": { - "version": "4.6.3", - "resolved": "http://registry.npm.taobao.org/nodemailer/download/nodemailer-4.6.3.tgz", - "integrity": "sha1-w7fpf7cvRtSkdcQGoV7SOkXbzdw=" + "node_modules/sequelize/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, - "nopt": { - "version": "3.0.6", - "resolved": "http://registry.npm.taobao.org/nopt/download/nopt-3.0.6.tgz", - "integrity": "sha1-xkZdvwirzU2zWTF/eaxopkayj/k=", - "requires": { - "abbrev": "1" + "node_modules/sequelize/node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "bin": { + "uuid": "dist/bin/uuid" } }, - "npm-run-path": { - "version": "2.0.2", - "resolved": "http://registry.npm.taobao.org/npm-run-path/download/npm-run-path-2.0.2.tgz", - "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", - "requires": { - "path-key": "^2.0.0" + "node_modules/serialize-javascript": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", + "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", + "dev": true, + "dependencies": { + "randombytes": "^2.1.0" } }, - "number-is-nan": { - "version": "1.0.1", - "resolved": "http://registry.npm.taobao.org/number-is-nan/download/number-is-nan-1.0.1.tgz", - "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=" - }, - "oauth-sign": { - "version": "0.8.2", - "resolved": "http://registry.npm.taobao.org/oauth-sign/download/oauth-sign-0.8.2.tgz", - "integrity": "sha1-Rqarfwrq2N6unsBWV4C31O/rnUM=" - }, - "object-assign": { - "version": "4.1.1", - "resolved": "http://registry.npm.taobao.org/object-assign/download/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" - }, - "on-finished": { - "version": "2.3.0", - "resolved": "http://registry.npm.taobao.org/on-finished/download/on-finished-2.3.0.tgz", - "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", - "requires": { - "ee-first": "1.1.1" + "node_modules/serve-static": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", + "dependencies": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.18.0" + }, + "engines": { + "node": ">= 0.8.0" } }, - "on-headers": { - "version": "1.0.1", - "resolved": "http://registry.npm.taobao.org/on-headers/download/on-headers-1.0.1.tgz", - "integrity": "sha1-ko9dD0cNSTQmUepnlLCFfBAGk/c=" + "node_modules/set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", + "dev": true }, - "once": { - "version": "1.4.0", - "resolved": "http://registry.npm.taobao.org/once/download/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "requires": { - "wrappy": "1" - } + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" }, - "optimist": { - "version": "0.6.1", - "resolved": "http://registry.npm.taobao.org/optimist/download/optimist-0.6.1.tgz", - "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=", + "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, - "requires": { - "minimist": "~0.0.1", - "wordwrap": "~0.0.2" - }, "dependencies": { - "wordwrap": { - "version": "0.0.3", - "resolved": "http://registry.npm.taobao.org/wordwrap/download/wordwrap-0.0.3.tgz", - "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=", - "dev": true - } + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" } }, - "optionator": { - "version": "0.8.2", - "resolved": "http://registry.npm.taobao.org/optionator/download/optionator-0.8.2.tgz", - "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=", + "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, - "requires": { - "deep-is": "~0.1.3", - "fast-levenshtein": "~2.0.4", - "levn": "~0.3.0", - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2", - "wordwrap": "~1.0.0" + "engines": { + "node": ">=8" } }, - "optjs": { - "version": "3.2.2", - "resolved": "http://registry.npm.taobao.org/optjs/download/optjs-3.2.2.tgz", - "integrity": "sha1-aabOicRCpEQDFBrS+bNwvVu29O4=" + "node_modules/shell-quote": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.7.3.tgz", + "integrity": "sha512-Vpfqwm4EnqGdlsBFNmHhxhElJYrdfcxPThu+ryKS5J8L/fhAwLazFZtq+S+TWZ9ANj2piSQLGj6NQg+lKPmxrw==", + "dev": true }, - "os-locale": { - "version": "1.4.0", - "resolved": "http://registry.npm.taobao.org/os-locale/download/os-locale-1.4.0.tgz", - "integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=", - "requires": { - "lcid": "^1.0.0" + "node_modules/should": { + "version": "13.2.3", + "resolved": "https://registry.npmjs.org/should/-/should-13.2.3.tgz", + "integrity": "sha512-ggLesLtu2xp+ZxI+ysJTmNjh2U0TsC+rQ/pfED9bUZZ4DKefP27D+7YJVVTvKsmjLpIi9jAa7itwDGkDDmt1GQ==", + "dev": true, + "dependencies": { + "should-equal": "^2.0.0", + "should-format": "^3.0.3", + "should-type": "^1.4.0", + "should-type-adaptors": "^1.0.1", + "should-util": "^1.0.0" } }, - "os-name": { - "version": "1.0.3", - "resolved": "http://registry.npm.taobao.org/os-name/download/os-name-1.0.3.tgz", - "integrity": "sha1-GzefZINa98Wn9JizV8uVIVwVnt8=", - "requires": { - "osx-release": "^1.0.0", - "win-release": "^1.0.0" + "node_modules/should-equal": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/should-equal/-/should-equal-2.0.0.tgz", + "integrity": "sha512-ZP36TMrK9euEuWQYBig9W55WPC7uo37qzAEmbjHz4gfyuXrEUgF8cUvQVO+w+d3OMfPvSRQJ22lSm8MQJ43LTA==", + "dev": true, + "dependencies": { + "should-type": "^1.4.0" } }, - "osx-release": { - "version": "1.1.0", - "resolved": "http://registry.npm.taobao.org/osx-release/download/osx-release-1.1.0.tgz", - "integrity": "sha1-8heRGigTaUmvG/kwiyQeJzfTzWw=", - "requires": { - "minimist": "^1.1.0" - }, + "node_modules/should-format": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/should-format/-/should-format-3.0.3.tgz", + "integrity": "sha1-m/yPdPo5IFxT04w01xcwPidxJPE=", + "dev": true, "dependencies": { - "minimist": { - "version": "1.2.0", - "resolved": "http://registry.npm.taobao.org/minimist/download/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=" - } + "should-type": "^1.3.0", + "should-type-adaptors": "^1.0.1" } }, - "p-finally": { - "version": "1.0.0", - "resolved": "http://registry.npm.taobao.org/p-finally/download/p-finally-1.0.0.tgz", - "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=" + "node_modules/should-type": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/should-type/-/should-type-1.4.0.tgz", + "integrity": "sha1-B1bYzoRt/QmEOmlHcZ36DUz/XPM=", + "dev": true }, - "p-limit": { - "version": "2.0.0", - "resolved": "http://registry.npm.taobao.org/p-limit/download/p-limit-2.0.0.tgz", - "integrity": "sha1-5iTtVO6MRgp3izyfNnBJb/ileuw=", - "requires": { - "p-try": "^2.0.0" + "node_modules/should-type-adaptors": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/should-type-adaptors/-/should-type-adaptors-1.1.0.tgz", + "integrity": "sha512-JA4hdoLnN+kebEp2Vs8eBe9g7uy0zbRo+RMcU0EsNy+R+k049Ki+N5tT5Jagst2g7EAja+euFuoXFCa8vIklfA==", + "dev": true, + "dependencies": { + "should-type": "^1.3.0", + "should-util": "^1.0.0" } }, - "p-locate": { - "version": "3.0.0", - "resolved": "http://registry.npm.taobao.org/p-locate/download/p-locate-3.0.0.tgz", - "integrity": "sha1-Mi1poFwCZLJZl9n0DNiokasAZKQ=", - "requires": { - "p-limit": "^2.0.0" - } + "node_modules/should-util": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/should-util/-/should-util-1.0.1.tgz", + "integrity": "sha512-oXF8tfxx5cDk8r2kYqlkUJzZpDBqVY/II2WhvU0n9Y3XYvAYRmeaf1PvvIvTgPnv4KJ+ES5M0PyDq5Jp+Ygy2g==", + "dev": true }, - "p-try": { - "version": "2.0.0", - "resolved": "http://registry.npm.taobao.org/p-try/download/p-try-2.0.0.tgz", - "integrity": "sha1-hQgLuHxkaI+keZb+j3376CEXYLE=" + "node_modules/side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "dependencies": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "parseurl": { - "version": "1.3.2", - "resolved": "http://registry.npm.taobao.org/parseurl/download/parseurl-1.3.2.tgz", - "integrity": "sha1-/CidTtiZMRlGDBViUyYs3I3mW/M=" + "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 }, - "path-exists": { + "node_modules/slash": { "version": "3.0.0", - "resolved": "http://registry.npm.taobao.org/path-exists/download/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=" - }, - "path-is-absolute": { - "version": "1.0.1", - "resolved": "http://registry.npm.taobao.org/path-is-absolute/download/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "engines": { + "node": ">=8" + } }, - "path-key": { - "version": "2.0.1", - "resolved": "http://registry.npm.taobao.org/path-key/download/path-key-2.0.1.tgz", - "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=" + "node_modules/smart-buffer": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", + "engines": { + "node": ">= 6.0.0", + "npm": ">= 3.0.0" + } }, - "path-parse": { - "version": "1.0.5", - "resolved": "http://registry.npm.taobao.org/path-parse/download/path-parse-1.0.5.tgz", - "integrity": "sha1-PBrfhx6pzWyUMbbqK9dKD/BVxME=" + "node_modules/socks": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.6.2.tgz", + "integrity": "sha512-zDZhHhZRY9PxRruRMR7kMhnf3I8hDs4S3f9RecfnGxvcBHQcKcIH/oUcEWffsfl1XxdYlA7nnlGbbTvPz9D8gA==", + "dependencies": { + "ip": "^1.1.5", + "smart-buffer": "^4.2.0" + }, + "engines": { + "node": ">= 10.13.0", + "npm": ">= 3.0.0" + } }, - "path-to-regexp": { - "version": "0.1.7", - "resolved": "http://registry.npm.taobao.org/path-to-regexp/download/path-to-regexp-0.1.7.tgz", - "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" + "node_modules/socks-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-5.0.1.tgz", + "integrity": "sha512-vZdmnjb9a2Tz6WEQVIurybSwElwPxMZaIc7PzqbJTrezcKNznv6giT7J7tZDZ1BojVaa1jvO/UiUdhDVB0ACoQ==", + "dependencies": { + "agent-base": "^6.0.2", + "debug": "4", + "socks": "^2.3.3" + }, + "engines": { + "node": ">= 6" + } }, - "pause-stream": { - "version": "0.0.11", - "resolved": "http://registry.npm.taobao.org/pause-stream/download/pause-stream-0.0.11.tgz", - "integrity": "sha1-/lo0sMvOErWqaitAPuLnO2AvFEU=", - "requires": { - "through": "~2.3" + "node_modules/socks-proxy-agent/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } } }, - "pend": { - "version": "1.2.0", - "resolved": "http://registry.npm.taobao.org/pend/download/pend-1.2.0.tgz", - "integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA=" + "node_modules/socks-proxy-agent/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, - "performance-now": { - "version": "2.1.0", - "resolved": "http://registry.npm.taobao.org/performance-now/download/performance-now-2.1.0.tgz", - "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" + "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==", + "devOptional": true, + "engines": { + "node": ">=0.10.0" + } }, - "pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=" + "node_modules/spawn-command": { + "version": "0.0.2-1", + "resolved": "https://registry.npmjs.org/spawn-command/-/spawn-command-0.0.2-1.tgz", + "integrity": "sha512-n98l9E2RMSJ9ON1AKisHzz7V42VDiBQGY6PB1BwRglz99wpVsSuGzQ+jOi6lFXBGVTCrRpltvjm+/XA+tpeJrg==", + "dev": true }, - "platform": { - "version": "1.3.5", - "resolved": "http://registry.npm.taobao.org/platform/download/platform-1.3.5.tgz", - "integrity": "sha1-+2lYxpbgfikY0u7aDwvJRI1zNEQ=" + "node_modules/spawn-wrap": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/spawn-wrap/-/spawn-wrap-2.0.0.tgz", + "integrity": "sha512-EeajNjfN9zMnULLwhZZQU3GWBoFNkbngTUPfaawT4RkMiviTxcX0qfhVbGey39mfctfDHkWtuecgQ8NJcyQWHg==", + "dev": true, + "dependencies": { + "foreground-child": "^2.0.0", + "is-windows": "^1.0.2", + "make-dir": "^3.0.0", + "rimraf": "^3.0.0", + "signal-exit": "^3.0.2", + "which": "^2.0.1" + }, + "engines": { + "node": ">=8" + } }, - "pomelo-protobuf": { - "version": "0.4.0", - "resolved": "http://registry.npm.taobao.org/pomelo-protobuf/download/pomelo-protobuf-0.4.0.tgz", - "integrity": "sha1-5F6aCkRusYZn4MbhPutT1Hrdvag=" + "node_modules/spdx-correct": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", + "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==", + "dev": true, + "dependencies": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } }, - "prelude-ls": { - "version": "1.1.2", - "resolved": "http://registry.npm.taobao.org/prelude-ls/download/prelude-ls-1.1.2.tgz", - "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", + "node_modules/spdx-exceptions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", + "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", "dev": true }, - "process-nextick-args": { - "version": "2.0.0", - "resolved": "http://registry.npm.taobao.org/process-nextick-args/download/process-nextick-args-2.0.0.tgz", - "integrity": "sha1-o31zL0JxtKsa0HDTVQjoKQeI/6o=" - }, - "promise": { - "version": "7.3.1", - "resolved": "http://registry.npm.taobao.org/promise/download/promise-7.3.1.tgz", - "integrity": "sha1-BktyYCsY+Q8pGSuLG8QY/9Hr078=", - "requires": { - "asap": "~2.0.3" + "node_modules/spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "dev": true, + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" } }, - "protobufjs": { - "version": "4.1.3", - "resolved": "http://registry.npm.taobao.org/protobufjs/download/protobufjs-4.1.3.tgz", - "integrity": "sha1-jjbRsCJsu2jWR+S0TCoUTzfyd54=", - "requires": { - "ascli": "~1", - "bytebuffer": "~4 >=4.1", - "glob": "^5.0.10", - "yargs": "^3.10.0" - }, - "dependencies": { - "yargs": { - "version": "3.32.0", - "resolved": "http://registry.npm.taobao.org/yargs/download/yargs-3.32.0.tgz", - "integrity": "sha1-AwiOnr+edWtpdRYR0qXvWRSCyZU=", - "requires": { - "camelcase": "^2.0.1", - "cliui": "^3.0.3", - "decamelize": "^1.1.1", - "os-locale": "^1.4.0", - "string-width": "^1.0.1", - "window-size": "^0.1.4", - "y18n": "^3.2.0" - } - } + "node_modules/spdx-license-ids": { + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.11.tgz", + "integrity": "sha512-Ctl2BrFiM0X3MANYgj3CkygxhRmr9mi6xhejbdO960nF6EDJApTYpn0BQnDKlnNBULKiCN1n3w9EBkHK8ZWg+g==", + "dev": true + }, + "node_modules/split": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/split/-/split-1.0.1.tgz", + "integrity": "sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg==", + "dev": true, + "dependencies": { + "through": "2" + }, + "engines": { + "node": "*" } }, - "proxy-addr": { - "version": "2.0.3", - "resolved": "http://registry.npm.taobao.org/proxy-addr/download/proxy-addr-2.0.3.tgz", - "integrity": "sha1-NV8mJQWmIWRrMTCnKOtkfiIFU0E=", - "requires": { - "forwarded": "~0.1.2", - "ipaddr.js": "1.6.0" + "node_modules/split2": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/split2/-/split2-3.2.2.tgz", + "integrity": "sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg==", + "dev": true, + "dependencies": { + "readable-stream": "^3.0.0" } }, - "pseudomap": { - "version": "1.0.2", - "resolved": "http://registry.npm.taobao.org/pseudomap/download/pseudomap-1.0.2.tgz", - "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=" + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true }, - "pug": { - "version": "2.0.1", - "resolved": "http://registry.npm.taobao.org/pug/download/pug-2.0.1.tgz", - "integrity": "sha1-J8FRYStT1ymr6OgoWqxryJNFtdA=", - "requires": { - "pug-code-gen": "^2.0.1", - "pug-filters": "^3.0.1", - "pug-lexer": "^4.0.0", - "pug-linker": "^3.0.5", - "pug-load": "^2.0.11", - "pug-parser": "^5.0.0", - "pug-runtime": "^2.0.4", - "pug-strip-comments": "^1.0.3" - } - }, - "pug-attrs": { - "version": "2.0.3", - "resolved": "http://registry.npm.taobao.org/pug-attrs/download/pug-attrs-2.0.3.tgz", - "integrity": "sha1-owlflw5kFR972tlX7vVftdeQXRU=", - "requires": { - "constantinople": "^3.0.1", - "js-stringify": "^1.0.1", - "pug-runtime": "^2.0.4" + "node_modules/sqlstring": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/sqlstring/-/sqlstring-2.3.2.tgz", + "integrity": "sha512-vF4ZbYdKS8OnoJAWBmMxCQDkiEBkGQYU7UZPtL8flbDRSNkhaXvRJ279ZtI6M+zDaQovVU4tuRgzK5fVhvFAhg==", + "engines": { + "node": ">= 0.6" } }, - "pug-code-gen": { - "version": "2.0.1", - "resolved": "http://registry.npm.taobao.org/pug-code-gen/download/pug-code-gen-2.0.1.tgz", - "integrity": "sha1-CVHsgyJddNjPxHan+Zolm199BQw=", - "requires": { - "constantinople": "^3.0.1", - "doctypes": "^1.1.0", - "js-stringify": "^1.0.1", - "pug-attrs": "^2.0.3", - "pug-error": "^1.3.2", - "pug-runtime": "^2.0.4", - "void-elements": "^2.0.1", - "with": "^5.0.0" + "node_modules/sshpk": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.17.0.tgz", + "integrity": "sha512-/9HIEs1ZXGhSPE8X6Ccm7Nam1z8KcoCqPdI7ecm1N33EzAetWahvQWVqLZtaZQ+IDKX4IyA2o0gBzqIMkAagHQ==", + "dependencies": { + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "bcrypt-pbkdf": "^1.0.0", + "dashdash": "^1.12.0", + "ecc-jsbn": "~0.1.1", + "getpass": "^0.1.1", + "jsbn": "~0.1.0", + "safer-buffer": "^2.0.2", + "tweetnacl": "~0.14.0" + }, + "bin": { + "sshpk-conv": "bin/sshpk-conv", + "sshpk-sign": "bin/sshpk-sign", + "sshpk-verify": "bin/sshpk-verify" + }, + "engines": { + "node": ">=0.10.0" } }, - "pug-error": { - "version": "1.3.2", - "resolved": "http://registry.npm.taobao.org/pug-error/download/pug-error-1.3.2.tgz", - "integrity": "sha1-U659nSm7A89WRJOgJhCfVMR/XyY=" - }, - "pug-filters": { - "version": "3.0.1", - "resolved": "http://registry.npm.taobao.org/pug-filters/download/pug-filters-3.0.1.tgz", - "integrity": "sha1-Fj73O/ux8VRNAysrQPRRMOtS3Ms=", - "requires": { - "clean-css": "^3.3.0", - "constantinople": "^3.0.1", - "jstransformer": "1.0.0", - "pug-error": "^1.3.2", - "pug-walk": "^1.1.7", - "resolve": "^1.1.6", - "uglify-js": "^2.6.1" + "node_modules/standard-version": { + "version": "9.5.0", + "resolved": "https://registry.npmjs.org/standard-version/-/standard-version-9.5.0.tgz", + "integrity": "sha512-3zWJ/mmZQsOaO+fOlsa0+QK90pwhNd042qEcw6hKFNoLFs7peGyvPffpEBbK/DSGPbyOvli0mUIFv5A4qTjh2Q==", + "dev": true, + "dependencies": { + "chalk": "^2.4.2", + "conventional-changelog": "3.1.25", + "conventional-changelog-config-spec": "2.1.0", + "conventional-changelog-conventionalcommits": "4.6.3", + "conventional-recommended-bump": "6.1.0", + "detect-indent": "^6.0.0", + "detect-newline": "^3.1.0", + "dotgitignore": "^2.1.0", + "figures": "^3.1.0", + "find-up": "^5.0.0", + "git-semver-tags": "^4.0.0", + "semver": "^7.1.1", + "stringify-package": "^1.0.1", + "yargs": "^16.0.0" + }, + "bin": { + "standard-version": "bin/cli.js" + }, + "engines": { + "node": ">=10" } }, - "pug-lexer": { - "version": "4.0.0", - "resolved": "http://registry.npm.taobao.org/pug-lexer/download/pug-lexer-4.0.0.tgz", - "integrity": "sha1-IQwYRX7y4XYCQnQMXmR715TOwng=", - "requires": { - "character-parser": "^2.1.1", - "is-expression": "^3.0.0", - "pug-error": "^1.3.2" + "node_modules/standard-version/node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "pug-linker": { - "version": "3.0.5", - "resolved": "http://registry.npm.taobao.org/pug-linker/download/pug-linker-3.0.5.tgz", - "integrity": "sha1-npp65ABWgtAn3uuWsAD4juuDoC8=", - "requires": { - "pug-error": "^1.3.2", - "pug-walk": "^1.1.7" + "node_modules/standard-version/node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "pug-load": { - "version": "2.0.11", - "resolved": "http://registry.npm.taobao.org/pug-load/download/pug-load-2.0.11.tgz", - "integrity": "sha1-5kjlftET/iwfRdV4WOorrWvAFSc=", - "requires": { - "object-assign": "^4.1.0", - "pug-walk": "^1.1.7" + "node_modules/standard-version/node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "pug-parser": { + "node_modules/standard-version/node_modules/p-locate": { "version": "5.0.0", - "resolved": "http://registry.npm.taobao.org/pug-parser/download/pug-parser-5.0.0.tgz", - "integrity": "sha1-45Stmz/KkxI5QK/4hcBuRKt+aOQ=", - "requires": { - "pug-error": "^1.3.2", - "token-stream": "0.0.1" + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "pug-runtime": { - "version": "2.0.4", - "resolved": "http://registry.npm.taobao.org/pug-runtime/download/pug-runtime-2.0.4.tgz", - "integrity": "sha1-4XjhvaaKsujArPybztLFT9iM61g=" - }, - "pug-strip-comments": { - "version": "1.0.3", - "resolved": "http://registry.npm.taobao.org/pug-strip-comments/download/pug-strip-comments-1.0.3.tgz", - "integrity": "sha1-8VWVkiBu3G+FMQ2s9K+0igJa9Z8=", - "requires": { - "pug-error": "^1.3.2" + "node_modules/standard-version/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, + "engines": { + "node": ">=8" } }, - "pug-walk": { - "version": "1.1.7", - "resolved": "http://registry.npm.taobao.org/pug-walk/download/pug-walk-1.1.7.tgz", - "integrity": "sha1-wA1cUSi6xYBr7BXSt+fNq+QlMfM=" + "node_modules/standard-version/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, + "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" + } }, - "punycode": { - "version": "1.3.2", - "resolved": "http://registry.npm.taobao.org/punycode/download/punycode-1.3.2.tgz", - "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=" + "node_modules/standard-version/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, + "engines": { + "node": ">=10" + } }, - "qcloudapi-sdk": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/qcloudapi-sdk/-/qcloudapi-sdk-0.2.0.tgz", - "integrity": "sha512-Hy6a+95zDheaeMbA/N/7AEuAoOhwjR1POPI9xCwfsPc3b24ZzyH1M4PKgO9sq7Rq62+14ZTessHMdXJ+6NaeQg==", - "requires": { - "dot-qs": "^0.2.0", - "object-assign": "^3.0.0", - "request": ">= 2.33.0" - }, - "dependencies": { - "object-assign": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-3.0.0.tgz", - "integrity": "sha1-m+3VygiXlJvKR+f/QIBi1Un1h/I=" - } + "node_modules/statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=", + "engines": { + "node": ">= 0.6" } }, - "qiniu": { - "version": "7.1.3", - "resolved": "http://registry.npm.taobao.org/qiniu/download/qiniu-7.1.3.tgz", - "integrity": "sha1-Zk2FDSvmndSMEldV2O1XTUh/kzI=", - "requires": { - "agentkeepalive": "3.3.0", - "crc32": "0.2.2", - "encodeurl": "^1.0.1", - "formstream": "1.1.0", - "mime": "1.3.6", - "tunnel-agent": "0.6.0", - "urllib": "2.22.0" - }, + "node_modules/stream-browserify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-3.0.0.tgz", + "integrity": "sha512-H73RAHsVBapbim0tU2JwwOiXUj+fikfiaoYAKHF3VJfA0pe2BCzkhAHBlLG6REzE+2WNZcxOXjK7lkso+9euLA==", + "license": "MIT", "dependencies": { - "mime": { - "version": "1.3.6", - "resolved": "http://registry.npm.taobao.org/mime/download/mime-1.3.6.tgz", - "integrity": "sha1-WR2E02U6awtKO5343lqoEI5y5eA=" - } + "inherits": "~2.0.4", + "readable-stream": "^3.5.0" } }, - "qs": { - "version": "6.5.1", - "resolved": "http://registry.npm.taobao.org/qs/download/qs-6.5.1.tgz", - "integrity": "sha1-NJzfbu+J7EXBLX1es/wMhwNDptg=" - }, - "querystring": { - "version": "0.2.0", - "resolved": "http://registry.npm.taobao.org/querystring/download/querystring-0.2.0.tgz", - "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=" - }, - "rand-token": { - "version": "0.4.0", - "resolved": "http://registry.npm.taobao.org/rand-token/download/rand-token-0.4.0.tgz", - "integrity": "sha1-GlZbatEtkt1LMMTE5ZReiqJKWzs=" - }, - "range-parser": { - "version": "1.2.0", - "resolved": "http://registry.npm.taobao.org/range-parser/download/range-parser-1.2.0.tgz", - "integrity": "sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4=" - }, - "raw-body": { - "version": "2.3.2", - "resolved": "http://registry.npm.taobao.org/raw-body/download/raw-body-2.3.2.tgz", - "integrity": "sha1-vNYMd9Prk83gBQKVw/N5OJvIj4k=", - "requires": { - "bytes": "3.0.0", - "http-errors": "1.6.2", - "iconv-lite": "0.4.19", - "unpipe": "1.0.0" + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dependencies": { + "safe-buffer": "~5.2.0" } }, - "readable-stream": { - "version": "2.3.5", - "resolved": "http://registry.npm.taobao.org/readable-stream/download/readable-stream-2.3.5.tgz", - "integrity": "sha1-tPhQA6k4y7bsvOKhJPsQEr0ag40=", - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.0.3", - "util-deprecate": "~1.0.1" + "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==", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" } }, - "recursive-readdir": { - "version": "2.2.2", - "resolved": "http://registry.npm.taobao.org/recursive-readdir/download/recursive-readdir-2.2.2.tgz", - "integrity": "sha1-mUb7MnThYo3m42svZxSVO0hFCU8=", - "requires": { - "minimatch": "3.0.4" + "node_modules/string.prototype.matchall": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.7.tgz", + "integrity": "sha512-f48okCX7JiwVi1NXCVWcFnZgADDC/n2vePlQ/KUCNqCikLLilQvwjMO8+BHVKvgzH0JB0J9LEPgxOGT02RoETg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.1", + "get-intrinsic": "^1.1.1", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.3", + "regexp.prototype.flags": "^1.4.1", + "side-channel": "^1.0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "redeyed": { - "version": "1.0.1", - "resolved": "http://registry.npm.taobao.org/redeyed/download/redeyed-1.0.1.tgz", - "integrity": "sha1-6WwZO0DAgWsArshCaY5hGF5VSYo=", - "requires": { - "esprima": "~3.0.0" + "node_modules/string.prototype.matchall/node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "dev": true, + "engines": { + "node": ">= 0.4" }, - "dependencies": { - "esprima": { - "version": "3.0.0", - "resolved": "http://registry.npm.taobao.org/esprima/download/esprima-3.0.0.tgz", - "integrity": "sha1-U88kes2ncxPlUcOqLnM0LT+099k=" - } + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "redis": { - "version": "2.8.0", - "resolved": "http://registry.npm.taobao.org/redis/download/redis-2.8.0.tgz", - "integrity": "sha1-ICKI4/WMSfYHnZevehDhMDrhSwI=", - "requires": { - "double-ended-queue": "^2.1.0-0", - "redis-commands": "^1.2.0", - "redis-parser": "^2.6.0" + "node_modules/string.prototype.trimend": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.5.tgz", + "integrity": "sha512-I7RGvmjV4pJ7O3kdf+LXFpVfdNOxtCW/2C8f6jNiW4+PQchwxkCDzlk1/7p+Wl4bqFIZeF47qAHXLuHHWKAxog==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.19.5" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "redis-commands": { - "version": "1.3.5", - "resolved": "http://registry.npm.taobao.org/redis-commands/download/redis-commands-1.3.5.tgz", - "integrity": "sha1-RJWIlBTx6IYmEYCxRC5ylWAtg6I=" - }, - "redis-parser": { - "version": "2.6.0", - "resolved": "http://registry.npm.taobao.org/redis-parser/download/redis-parser-2.6.0.tgz", - "integrity": "sha1-Uu0J2srBCPGmMcB+m2mUHnoZUEs=" - }, - "referrer-policy": { - "version": "1.1.0", - "resolved": "http://registry.npm.taobao.org/referrer-policy/download/referrer-policy-1.1.0.tgz", - "integrity": "sha1-NXdOtzW/UPtsB46DM0tHI1AgfXk=" - }, - "regenerator-runtime": { - "version": "0.11.1", - "resolved": "http://registry.npm.taobao.org/regenerator-runtime/download/regenerator-runtime-0.11.1.tgz", - "integrity": "sha1-vgWtf5v30i4Fb5cmzuUBf78Z4uk=" - }, - "repeat-string": { - "version": "1.6.1", - "resolved": "http://registry.npm.taobao.org/repeat-string/download/repeat-string-1.6.1.tgz", - "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=" - }, - "request": { - "version": "2.85.0", - "resolved": "http://registry.npm.taobao.org/request/download/request-2.85.0.tgz", - "integrity": "sha1-WgNhWkfGFCCz65m326IE+DYD4fo=", - "requires": { - "aws-sign2": "~0.7.0", - "aws4": "^1.6.0", - "caseless": "~0.12.0", - "combined-stream": "~1.0.5", - "extend": "~3.0.1", - "forever-agent": "~0.6.1", - "form-data": "~2.3.1", - "har-validator": "~5.0.3", - "hawk": "~6.0.2", - "http-signature": "~1.2.0", - "is-typedarray": "~1.0.0", - "isstream": "~0.1.2", - "json-stringify-safe": "~5.0.1", - "mime-types": "~2.1.17", - "oauth-sign": "~0.8.2", - "performance-now": "^2.1.0", - "qs": "~6.5.1", - "safe-buffer": "^5.1.1", - "stringstream": "~0.0.5", - "tough-cookie": "~2.3.3", - "tunnel-agent": "^0.6.0", - "uuid": "^3.1.0" + "node_modules/string.prototype.trimstart": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.5.tgz", + "integrity": "sha512-THx16TJCGlsN0o6dl2o6ncWUsdgnLRSA23rRE5pyGBw/mLr3Ej/R2LaqCtgP8VNMGZsvMWnf9ooZPyY2bHvUFg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.19.5" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "require-directory": { - "version": "2.1.1", - "resolved": "http://registry.npm.taobao.org/require-directory/download/require-directory-2.1.1.tgz", - "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=" - }, - "require-main-filename": { + "node_modules/stringify-package": { "version": "1.0.1", - "resolved": "http://registry.npm.taobao.org/require-main-filename/download/require-main-filename-1.0.1.tgz", - "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=" - }, - "resolve": { - "version": "1.5.0", - "resolved": "http://registry.npm.taobao.org/resolve/download/resolve-1.5.0.tgz", - "integrity": "sha1-HwmsznlsmnYlefMbLBzEw83fnzY=", - "requires": { - "path-parse": "^1.0.5" - } + "resolved": "https://registry.npmjs.org/stringify-package/-/stringify-package-1.0.1.tgz", + "integrity": "sha512-sa4DUQsYciMP1xhKWGuFM04fB0LG/9DlluZoSVywUMRNvzid6XucHK0/90xGxRoHrAaROrcHK1aPKaijCtSrhg==", + "deprecated": "This module is not used anymore, and has been replaced by @npmcli/package-json", + "dev": true }, - "retry-as-promised": { - "version": "2.3.2", - "resolved": "http://registry.npm.taobao.org/retry-as-promised/download/retry-as-promised-2.3.2.tgz", - "integrity": "sha1-zZdO5P2bX+A8vzGHHuSCIcB3N7c=", - "requires": { - "bluebird": "^3.4.6", - "debug": "^2.6.9" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "http://registry.npm.taobao.org/debug/download/debug-2.6.9.tgz", - "integrity": "sha1-XRKFFd8TT/Mn6QpMk/Tgd6U2NB8=", - "requires": { - "ms": "2.0.0" - } - } + "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==", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" } }, - "rfdc": { - "version": "1.1.2", - "resolved": "http://registry.npm.taobao.org/rfdc/download/rfdc-1.1.2.tgz", - "integrity": "sha1-5uctdPXcOd6PU49l4Aw2wYAY40k=" - }, - "right-align": { - "version": "0.1.3", - "resolved": "http://registry.npm.taobao.org/right-align/download/right-align-0.1.3.tgz", - "integrity": "sha1-YTObci/mo1FWiSENJOFMlhSGE+8=", - "requires": { - "align-text": "^0.1.1" + "node_modules/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true, + "engines": { + "node": ">=4" } }, - "safe-buffer": { - "version": "5.1.1", - "resolved": "http://registry.npm.taobao.org/safe-buffer/download/safe-buffer-5.1.1.tgz", - "integrity": "sha1-iTMSr2myEj3vcfV4iQAWce6yyFM=" - }, - "safefs": { - "version": "3.2.2", - "resolved": "http://registry.npm.taobao.org/safefs/download/safefs-3.2.2.tgz", - "integrity": "sha1-gXDBRE1wOOCMrqBaN0+uL6NJ4Vw=", - "requires": { - "graceful-fs": "*" + "node_modules/strip-indent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", + "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", + "dev": true, + "dependencies": { + "min-indent": "^1.0.0" + }, + "engines": { + "node": ">=8" } }, - "sax": { - "version": "0.6.1", - "resolved": "http://registry.npm.taobao.org/sax/download/sax-0.6.1.tgz", - "integrity": "sha1-VjsZx8HeiS4Jv8Ty/DDjwn8JUrk=" - }, - "scandirectory": { - "version": "2.5.0", - "resolved": "http://registry.npm.taobao.org/scandirectory/download/scandirectory-2.5.0.tgz", - "integrity": "sha1-bOA/VKCQtmjjy+2/IO354xBZPnI=", - "requires": { - "ignorefs": "^1.0.0", - "safefs": "^3.1.2", - "taskgroup": "^4.0.5" + "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, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "semver": { - "version": "5.5.0", - "resolved": "http://registry.npm.taobao.org/semver/download/semver-5.5.0.tgz", - "integrity": "sha1-3Eu8emyp2Rbe5dQ1FvAJK1j3uKs=" - }, - "send": { - "version": "0.16.2", - "resolved": "http://registry.npm.taobao.org/send/download/send-0.16.2.tgz", - "integrity": "sha1-bsyh4PjBVtFBWXVZhI32RzCmu8E=", - "requires": { - "debug": "2.6.9", - "depd": "~1.1.2", - "destroy": "~1.0.4", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "fresh": "0.5.2", - "http-errors": "~1.6.2", - "mime": "1.4.1", - "ms": "2.0.0", - "on-finished": "~2.3.0", - "range-parser": "~1.2.0", - "statuses": "~1.4.0" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "http://registry.npm.taobao.org/debug/download/debug-2.6.9.tgz", - "integrity": "sha1-XRKFFd8TT/Mn6QpMk/Tgd6U2NB8=", - "requires": { - "ms": "2.0.0" - } - }, - "mime": { - "version": "1.4.1", - "resolved": "http://registry.npm.taobao.org/mime/download/mime-1.4.1.tgz", - "integrity": "sha1-Eh+evEnjdm8xGnbh+hyAA8SwOqY=" + "node_modules/strnum": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/strnum/-/strnum-2.1.1.tgz", + "integrity": "sha512-7ZvoFTiCnGxBtDqJ//Cu6fWtZtc7Y3x+QOirG15wztbdngGSkht27o2pyGWrVy0b4WAy3jbKmnoK6g5VlVNUUw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" } + ], + "license": "MIT" + }, + "node_modules/superagent": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/superagent/-/superagent-8.0.0.tgz", + "integrity": "sha512-iudipXEel+SzlP9y29UBWGDjB+Zzag+eeA1iLosaR2YHBRr1Q1kC29iBrF2zIVD9fqVbpZnXkN/VJmwFMVyNWg==", + "deprecated": "Please upgrade to superagent v10.2.2+, see release notes at https://github.com/forwardemail/superagent/releases/tag/v10.2.2 - maintenance is supported by Forward Email @ https://forwardemail.net", + "dev": true, + "dependencies": { + "component-emitter": "^1.3.0", + "cookiejar": "^2.1.3", + "debug": "^4.3.4", + "fast-safe-stringify": "^2.1.1", + "form-data": "^4.0.0", + "formidable": "^2.0.1", + "methods": "^1.1.2", + "mime": "2.6.0", + "qs": "^6.10.3", + "readable-stream": "^3.6.0", + "semver": "^7.3.7" + }, + "engines": { + "node": ">=6.4.0 <13 || >=14" } }, - "seq-queue": { - "version": "0.0.5", - "resolved": "http://registry.npm.taobao.org/seq-queue/download/seq-queue-0.0.5.tgz", - "integrity": "sha1-1WgS4cAXpuTnw+Ojeh2m143TyT4=" - }, - "sequelize": { - "version": "4.37.1", - "resolved": "http://registry.npm.taobao.org/sequelize/download/sequelize-4.37.1.tgz", - "integrity": "sha1-F6qX8mm3YhAVxz53qmshNPRdp9c=", - "requires": { - "bluebird": "^3.5.0", - "cls-bluebird": "^2.1.0", - "debug": "^3.1.0", - "depd": "^1.1.0", - "dottie": "^2.0.0", - "generic-pool": "^3.4.0", - "inflection": "1.12.0", - "lodash": "^4.17.1", - "moment": "^2.20.0", - "moment-timezone": "^0.5.14", - "retry-as-promised": "^2.3.2", - "semver": "^5.5.0", - "terraformer-wkt-parser": "^1.1.2", - "toposort-class": "^1.0.1", - "uuid": "^3.2.1", - "validator": "^9.4.1", - "wkx": "^0.4.1" - }, - "dependencies": { - "debug": { - "version": "3.1.0", - "resolved": "http://registry.npm.taobao.org/debug/download/debug-3.1.0.tgz", - "integrity": "sha1-W7WgZyYotkFJVmuhaBnmFRjGcmE=", - "requires": { - "ms": "2.0.0" - } - }, - "inflection": { - "version": "1.12.0", - "resolved": "http://registry.npm.taobao.org/inflection/download/inflection-1.12.0.tgz", - "integrity": "sha1-ogCTVlbW9fa8TcdQLhrstwMihBY=" - }, - "uuid": { - "version": "3.2.1", - "resolved": "http://registry.npm.taobao.org/uuid/download/uuid-3.2.1.tgz", - "integrity": "sha1-EsUou51Y0LkmXZovbw/ovhf/HxQ=" - }, - "validator": { - "version": "9.4.1", - "resolved": "http://registry.npm.taobao.org/validator/download/validator-9.4.1.tgz", - "integrity": "sha1-q/Rm05i1Yc0kMFARLG/x3mzBJmM=" + "node_modules/superagent/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true } } }, - "serve-favicon": { - "version": "2.4.5", - "resolved": "http://registry.npm.taobao.org/serve-favicon/download/serve-favicon-2.4.5.tgz", - "integrity": "sha1-SdmkaGMVOpJAaRyJPSsOfYXW1DY=", - "requires": { - "etag": "~1.8.1", - "fresh": "0.5.2", - "ms": "2.0.0", - "parseurl": "~1.3.2", - "safe-buffer": "5.1.1" - } - }, - "serve-static": { - "version": "1.13.2", - "resolved": "http://registry.npm.taobao.org/serve-static/download/serve-static-1.13.2.tgz", - "integrity": "sha1-CV6Ecv1bRiN9tQzkhqQ/S4bGzsE=", - "requires": { - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "parseurl": "~1.3.2", - "send": "0.16.2" + "node_modules/superagent/node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dev": true, + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" } }, - "set-blocking": { - "version": "2.0.0", - "resolved": "http://registry.npm.taobao.org/set-blocking/download/set-blocking-2.0.0.tgz", - "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=" - }, - "setprototypeof": { - "version": "1.0.3", - "resolved": "http://registry.npm.taobao.org/setprototypeof/download/setprototypeof-1.0.3.tgz", - "integrity": "sha1-ZlZ+NwQ+608E2RvWWMDL77VbjgQ=" - }, - "shebang-command": { - "version": "1.2.0", - "resolved": "http://registry.npm.taobao.org/shebang-command/download/shebang-command-1.2.0.tgz", - "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", - "requires": { - "shebang-regex": "^1.0.0" + "node_modules/superagent/node_modules/mime": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", + "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", + "dev": true, + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4.0.0" } }, - "shebang-regex": { - "version": "1.0.0", - "resolved": "http://registry.npm.taobao.org/shebang-regex/download/shebang-regex-1.0.0.tgz", - "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=" - }, - "shimmer": { - "version": "1.2.0", - "resolved": "http://registry.npm.taobao.org/shimmer/download/shimmer-1.2.0.tgz", - "integrity": "sha1-+Wb3VVeJdj502IQRk2haXnhzZmU=" + "node_modules/superagent/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true }, - "should": { - "version": "11.2.1", - "resolved": "http://registry.npm.taobao.org/should/download/should-11.2.1.tgz", - "integrity": "sha1-kPVRRVUtAc/CAGZuToGKHJZw7aI=", + "node_modules/superagent/node_modules/semver": { + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", "dev": true, - "requires": { - "should-equal": "^1.0.0", - "should-format": "^3.0.2", - "should-type": "^1.4.0", - "should-type-adaptors": "^1.0.1", - "should-util": "^1.0.0" + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" } }, - "should-equal": { - "version": "1.0.1", - "resolved": "http://registry.npm.taobao.org/should-equal/download/should-equal-1.0.1.tgz", - "integrity": "sha1-C26VFvJgGp+wuy3MNpr6HH4gCvc=", + "node_modules/supertest": { + "version": "6.2.4", + "resolved": "https://registry.npmjs.org/supertest/-/supertest-6.2.4.tgz", + "integrity": "sha512-M8xVnCNv+q2T2WXVzxDECvL2695Uv2uUj2O0utxsld/HRyJvOU8W9f1gvsYxSNU4wmIe0/L/ItnpU4iKq0emDA==", + "deprecated": "Please upgrade to supertest v7.1.3+, see release notes at https://github.com/forwardemail/supertest/releases/tag/v7.1.3 - maintenance is supported by Forward Email @ https://forwardemail.net", "dev": true, - "requires": { - "should-type": "^1.0.0" + "dependencies": { + "methods": "^1.1.2", + "superagent": "^8.0.0" + }, + "engines": { + "node": ">=6.4.0" } }, - "should-format": { - "version": "3.0.3", - "resolved": "http://registry.npm.taobao.org/should-format/download/should-format-3.0.3.tgz", - "integrity": "sha1-m/yPdPo5IFxT04w01xcwPidxJPE=", + "node_modules/supervisor": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/supervisor/-/supervisor-0.12.0.tgz", + "integrity": "sha1-3n5jNwFbKRhRwQ81OMSn8EkX7ME=", "dev": true, - "requires": { - "should-type": "^1.3.0", - "should-type-adaptors": "^1.0.1" + "bin": { + "node-supervisor": "lib/cli-wrapper.js", + "supervisor": "lib/cli-wrapper.js" + }, + "engines": { + "node": ">=0.6.0" } }, - "should-type": { - "version": "1.4.0", - "resolved": "http://registry.npm.taobao.org/should-type/download/should-type-1.4.0.tgz", - "integrity": "sha1-B1bYzoRt/QmEOmlHcZ36DUz/XPM=", - "dev": true - }, - "should-type-adaptors": { - "version": "1.1.0", - "resolved": "http://registry.npm.taobao.org/should-type-adaptors/download/should-type-adaptors-1.1.0.tgz", - "integrity": "sha1-QB5/M7VTMDOUTVzYvytlAneS4no=", + "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==", "dev": true, - "requires": { - "should-type": "^1.3.0", - "should-util": "^1.0.0" + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" } }, - "should-util": { + "node_modules/supports-preserve-symlinks-flag": { "version": "1.0.0", - "resolved": "http://registry.npm.taobao.org/should-util/download/should-util-1.0.0.tgz", - "integrity": "sha1-yYzaN0qmsZDfi6h8mInCtNtiAGM=", - "dev": true - }, - "signal-exit": { - "version": "3.0.2", - "resolved": "http://registry.npm.taobao.org/signal-exit/download/signal-exit-3.0.2.tgz", - "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=" - }, - "slash": { - "version": "2.0.0", - "resolved": "http://registry.npm.taobao.org/slash/download/slash-2.0.0.tgz", - "integrity": "sha1-3lUoUaF1nfOo8gZTVEL17E3eq0Q=" - }, - "sntp": { - "version": "2.1.0", - "resolved": "http://registry.npm.taobao.org/sntp/download/sntp-2.1.0.tgz", - "integrity": "sha1-LGzsFP7cIiJznK+bXD2F0cxaLMg=", - "requires": { - "hoek": "4.x.x" + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "sprintf-js": { - "version": "1.1.1", - "resolved": "http://registry.npm.taobao.org/sprintf-js/download/sprintf-js-1.1.1.tgz", - "integrity": "sha1-Nr54Mgr+WAH2zqPueLblqrlA6gw=" - }, - "sqlstring": { - "version": "2.3.1", - "resolved": "http://registry.npm.taobao.org/sqlstring/download/sqlstring-2.3.1.tgz", - "integrity": "sha1-R1OT/56RR5rqYtyvDKPRSYOn+0A=" - }, - "sshpk": { - "version": "1.14.1", - "resolved": "http://registry.npm.taobao.org/sshpk/download/sshpk-1.14.1.tgz", - "integrity": "sha1-Ew9Zde3a2WPx1W+SuaxsUfqfg+s=", - "requires": { - "asn1": "~0.2.3", - "assert-plus": "^1.0.0", - "bcrypt-pbkdf": "^1.0.0", - "dashdash": "^1.12.0", - "ecc-jsbn": "~0.1.1", - "getpass": "^0.1.1", - "jsbn": "~0.1.0", - "tweetnacl": "~0.14.0" + "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, + "dependencies": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=8" } }, - "statuses": { - "version": "1.4.0", - "resolved": "http://registry.npm.taobao.org/statuses/download/statuses-1.4.0.tgz", - "integrity": "sha1-u3PURtonlhBu/MG2AaJT1sRr0Ic=" + "node_modules/text-extensions": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/text-extensions/-/text-extensions-1.9.0.tgz", + "integrity": "sha512-wiBrwC1EhBelW12Zy26JeOUkQ5mRu+5o8rpsJk5+2t+Y5vE7e842qtZDQ2g1NpX/29HdyFeJ4nSIhI47ENSxlQ==", + "dev": true, + "engines": { + "node": ">=0.10" + } }, - "streamroller": { - "version": "0.7.0", - "resolved": "http://registry.npm.taobao.org/streamroller/download/streamroller-0.7.0.tgz", - "integrity": "sha1-odG3z4PTmvsNYwSaWsv5NJO99ks=", - "requires": { - "date-format": "^1.2.0", - "debug": "^3.1.0", - "mkdirp": "^0.5.1", - "readable-stream": "^2.3.0" - }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true + }, + "node_modules/thenify": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", + "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", "dependencies": { - "mkdirp": { - "version": "0.5.1", - "resolved": "http://registry.npm.taobao.org/mkdirp/download/mkdirp-0.5.1.tgz", - "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", - "requires": { - "minimist": "0.0.8" - } - } + "any-promise": "^1.0.0" } }, - "string-width": { - "version": "1.0.2", - "resolved": "http://registry.npm.taobao.org/string-width/download/string-width-1.0.2.tgz", - "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", - "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" + "node_modules/thenify-all": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", + "integrity": "sha1-GhkY1ALY/D+Y+/I02wvMjMEOlyY=", + "dependencies": { + "thenify": ">= 3.1.0 < 4" + }, + "engines": { + "node": ">=0.8" } }, - "string_decoder": { - "version": "1.0.3", - "resolved": "http://registry.npm.taobao.org/string_decoder/download/string_decoder-1.0.3.tgz", - "integrity": "sha1-D8Z9fBQYJd6UKC3VNr7GubzoYKs=", - "requires": { - "safe-buffer": "~5.1.0" + "node_modules/through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=" + }, + "node_modules/through2": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/through2/-/through2-4.0.2.tgz", + "integrity": "sha512-iOqSav00cVxEEICeD7TjLB1sueEL+81Wpzp2bY17uZjZN0pWZPuo4suZ/61VujxmqSGFfgOcNuTZ85QJwNZQpw==", + "dev": true, + "dependencies": { + "readable-stream": "3" } }, - "stringstream": { - "version": "0.0.5", - "resolved": "http://registry.npm.taobao.org/stringstream/download/stringstream-0.0.5.tgz", - "integrity": "sha1-TkhM1N5aC7vuGORjB3EKioFiGHg=" + "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": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", + "engines": { + "node": ">=4" + } }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "http://registry.npm.taobao.org/strip-ansi/download/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "requires": { - "ansi-regex": "^2.0.0" + "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==", + "dev": true, + "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==", + "engines": { + "node": ">=0.6" } }, - "strip-eof": { + "node_modules/token-stream": { "version": "1.0.0", - "resolved": "http://registry.npm.taobao.org/strip-eof/download/strip-eof-1.0.0.tgz", - "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=" + "resolved": "https://registry.npmjs.org/token-stream/-/token-stream-1.0.0.tgz", + "integrity": "sha1-zCAOqyYT9BZtJ/+a/HylbUnfbrQ=" }, - "superagent": { - "version": "3.8.2", - "resolved": "http://registry.npm.taobao.org/superagent/download/superagent-3.8.2.tgz", - "integrity": "sha1-5KEbnQR/fT7+s7vlNtnsACHRZAM=", - "dev": true, - "requires": { - "component-emitter": "^1.2.0", - "cookiejar": "^2.1.0", - "debug": "^3.1.0", - "extend": "^3.0.0", - "form-data": "^2.3.1", - "formidable": "^1.1.1", - "methods": "^1.1.1", - "mime": "^1.4.1", - "qs": "^6.5.1", - "readable-stream": "^2.0.5" - }, - "dependencies": { - "debug": { - "version": "3.1.0", - "resolved": "http://registry.npm.taobao.org/debug/download/debug-3.1.0.tgz", - "integrity": "sha1-W7WgZyYotkFJVmuhaBnmFRjGcmE=", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "mime": { - "version": "1.6.0", - "resolved": "http://registry.npm.taobao.org/mime/download/mime-1.6.0.tgz", - "integrity": "sha1-Ms2eXGRVO9WNGaVor0Uqz/BJgbE=", - "dev": true - } + "node_modules/toposort-class": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toposort-class/-/toposort-class-1.0.1.tgz", + "integrity": "sha512-OsLcGGbYF3rMjPUf8oKktyvCiUxSbqMMS39m33MAjLTC1DVIH6x3WSt63/M77ihI09+Sdfk1AXvfhCEeUmC7mg==" + }, + "node_modules/tough-cookie": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", + "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", + "dependencies": { + "psl": "^1.1.28", + "punycode": "^2.1.1" + }, + "engines": { + "node": ">=0.8" } }, - "supertest": { - "version": "3.0.0", - "resolved": "http://registry.npm.taobao.org/supertest/download/supertest-3.0.0.tgz", - "integrity": "sha1-jUu2j9GDDuBwM7HFpamkAhyWUpY=", - "dev": true, - "requires": { - "methods": "~1.1.2", - "superagent": "^3.0.0" + "node_modules/tough-cookie/node_modules/punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "engines": { + "node": ">=6" } }, - "supervisor": { - "version": "0.12.0", - "resolved": "http://registry.npm.taobao.org/supervisor/download/supervisor-0.12.0.tgz", - "integrity": "sha1-3n5jNwFbKRhRwQ81OMSn8EkX7ME=", - "dev": true + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=" }, - "taskgroup": { - "version": "4.3.1", - "resolved": "http://registry.npm.taobao.org/taskgroup/download/taskgroup-4.3.1.tgz", - "integrity": "sha1-feGT/r12gnPEV3MElwJNUSwnkVo=", - "requires": { - "ambi": "^2.2.0", - "csextends": "^1.0.3" + "node_modules/tree-kill": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", + "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", + "dev": true, + "bin": { + "tree-kill": "cli.js" } }, - "terraformer": { - "version": "1.0.8", - "resolved": "http://registry.npm.taobao.org/terraformer/download/terraformer-1.0.8.tgz", - "integrity": "sha1-UeCtiXRvzyFh3G9lqnDkI3fItZM=", - "requires": { - "@types/geojson": "^1.0.0" + "node_modules/trim-newlines": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-3.0.1.tgz", + "integrity": "sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==", + "dev": true, + "engines": { + "node": ">=8" } }, - "terraformer-wkt-parser": { - "version": "1.1.2", - "resolved": "http://registry.npm.taobao.org/terraformer-wkt-parser/download/terraformer-wkt-parser-1.1.2.tgz", - "integrity": "sha1-M2oMj8gglKWv+DKI9prt7NNpvww=", - "requires": { - "terraformer": "~1.0.5" + "node_modules/tsconfig-paths": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz", + "integrity": "sha512-fxDhWnFSLt3VuTwtvJt5fpwxBHg5AdKWMsgcPOOIilyjymcYVZoCQF8fvFRezCNfblEXmi+PcM1eYHeOAgXCOQ==", + "dev": true, + "dependencies": { + "@types/json5": "^0.0.29", + "json5": "^1.0.1", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" } }, - "through": { - "version": "2.3.8", - "resolved": "http://registry.npm.taobao.org/through/download/through-2.3.8.tgz", - "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=" - }, - "to-fast-properties": { - "version": "1.0.3", - "resolved": "http://registry.npm.taobao.org/to-fast-properties/download/to-fast-properties-1.0.3.tgz", - "integrity": "sha1-uDVx+k2MJbguIxsG46MFXeTKGkc=" - }, - "token-stream": { - "version": "0.0.1", - "resolved": "http://registry.npm.taobao.org/token-stream/download/token-stream-0.0.1.tgz", - "integrity": "sha1-zu78cXp2xDFvEm0LnbqlXX598Bo=" + "node_modules/tsconfig-paths/node_modules/minimist": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", + "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", + "dev": true }, - "toposort-class": { - "version": "1.0.1", - "resolved": "http://registry.npm.taobao.org/toposort-class/download/toposort-class-1.0.1.tgz", - "integrity": "sha1-f/0feMi+KMO6Rc1OGj9e4ZO9mYg=" + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" }, - "tough-cookie": { - "version": "2.3.4", - "resolved": "http://registry.npm.taobao.org/tough-cookie/download/tough-cookie-2.3.4.tgz", - "integrity": "sha1-7GDO44rGdQY//JelwYlwV47oNlU=", - "requires": { - "punycode": "^1.4.1" - }, + "node_modules/tsutils": { + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", + "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", + "dev": true, "dependencies": { - "punycode": { - "version": "1.4.1", - "resolved": "http://registry.npm.taobao.org/punycode/download/punycode-1.4.1.tgz", - "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=" - } + "tslib": "^1.8.1" + }, + "engines": { + "node": ">= 6" + }, + "peerDependencies": { + "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" } }, - "tunnel-agent": { + "node_modules/tsutils/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + }, + "node_modules/tunnel-agent": { "version": "0.6.0", - "resolved": "http://registry.npm.taobao.org/tunnel-agent/download/tunnel-agent-0.6.0.tgz", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", - "requires": { + "dependencies": { "safe-buffer": "^5.0.1" + }, + "engines": { + "node": "*" } }, - "tweetnacl": { + "node_modules/tweetnacl": { "version": "0.14.5", - "resolved": "http://registry.npm.taobao.org/tweetnacl/download/tweetnacl-0.14.5.tgz", - "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", - "optional": true + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==" }, - "type-check": { + "node_modules/type-check": { "version": "0.3.2", - "resolved": "http://registry.npm.taobao.org/type-check/download/type-check-0.3.2.tgz", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", - "dev": true, - "requires": { + "dependencies": { "prelude-ls": "~1.1.2" + }, + "engines": { + "node": ">= 0.8.0" } }, - "type-is": { - "version": "1.6.16", - "resolved": "http://registry.npm.taobao.org/type-is/download/type-is-1.6.16.tgz", - "integrity": "sha1-+JzjQVQcZysl7nrjxz3uOyvlAZQ=", - "requires": { - "media-typer": "0.3.0", - "mime-types": "~2.1.18" + "node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "typechecker": { - "version": "2.1.0", - "resolved": "http://registry.npm.taobao.org/typechecker/download/typechecker-2.1.0.tgz", - "integrity": "sha1-0cIJOlT/ihn1jP+HfuqlTyJC04M=" + "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==", + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } }, - "typedarray": { + "node_modules/typedarray": { "version": "0.0.6", - "resolved": "http://registry.npm.taobao.org/typedarray/download/typedarray-0.0.6.tgz", - "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=" + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", + "dev": true }, - "uc.micro": { - "version": "1.0.5", - "resolved": "http://registry.npm.taobao.org/uc.micro/download/uc.micro-1.0.5.tgz", - "integrity": "sha1-DGXxX4FaoItWCmHOi023/8P0U3Y=" - }, - "uglify-js": { - "version": "2.8.29", - "resolved": "http://registry.npm.taobao.org/uglify-js/download/uglify-js-2.8.29.tgz", - "integrity": "sha1-KcVzMUgFe7Th913zW3qcty5qWd0=", - "requires": { - "source-map": "~0.5.1", - "uglify-to-browserify": "~1.0.0", - "yargs": "~3.10.0" - }, - "dependencies": { - "camelcase": { - "version": "1.2.1", - "resolved": "http://registry.npm.taobao.org/camelcase/download/camelcase-1.2.1.tgz", - "integrity": "sha1-m7UwTS4LVmmLLHWLCKPqqdqlijk=" - }, - "cliui": { - "version": "2.1.0", - "resolved": "http://registry.npm.taobao.org/cliui/download/cliui-2.1.0.tgz", - "integrity": "sha1-S0dXYP+AJkx2LDoXGQMukcf+oNE=", - "requires": { - "center-align": "^0.1.1", - "right-align": "^0.1.1", - "wordwrap": "0.0.2" - } - }, - "source-map": { - "version": "0.5.7", - "resolved": "http://registry.npm.taobao.org/source-map/download/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=" - }, - "window-size": { - "version": "0.1.0", - "resolved": "http://registry.npm.taobao.org/window-size/download/window-size-0.1.0.tgz", - "integrity": "sha1-VDjNLqk7IC76Ohn+iIeu58lPnJ0=" - }, - "wordwrap": { - "version": "0.0.2", - "resolved": "http://registry.npm.taobao.org/wordwrap/download/wordwrap-0.0.2.tgz", - "integrity": "sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8=" - }, - "yargs": { - "version": "3.10.0", - "resolved": "http://registry.npm.taobao.org/yargs/download/yargs-3.10.0.tgz", - "integrity": "sha1-9+572FfdfB0tOMDnTvvWgdFDH9E=", - "requires": { - "camelcase": "^1.0.2", - "cliui": "^2.1.0", - "decamelize": "^1.0.0", - "window-size": "0.1.0" - } - } + "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, + "dependencies": { + "is-typedarray": "^1.0.0" } }, - "uglify-to-browserify": { + "node_modules/typescript": { + "version": "4.9.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", + "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "node_modules/uglify-js": { + "version": "3.15.5", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.15.5.tgz", + "integrity": "sha512-hNM5q5GbBRB5xB+PMqVRcgYe4c8jbyZ1pzZhS6jbq54/4F2gFK869ZheiE5A8/t+W5jtTNpWef/5Q9zk639FNQ==", + "dev": true, + "optional": true, + "bin": { + "uglifyjs": "bin/uglifyjs" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/unbox-primitive": { "version": "1.0.2", - "resolved": "http://registry.npm.taobao.org/uglify-to-browserify/download/uglify-to-browserify-1.0.2.tgz", - "integrity": "sha1-bgkk1r2mta/jSeOabWMoUKD4grc=", - "optional": true + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", + "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-bigints": "^1.0.2", + "has-symbols": "^1.0.3", + "which-boxed-primitive": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "unique-string": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-1.0.0.tgz", - "integrity": "sha1-nhBXzKhRq7kzmPizOuGHuZyuwRo=", - "requires": { - "crypto-random-string": "^1.0.0" + "node_modules/unbox-primitive/node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "universalify": { - "version": "0.1.2", - "resolved": "http://registry.npm.taobao.org/universalify/download/universalify-0.1.2.tgz", - "integrity": "sha1-tkb2m+OULavOzJ1mOcgNwQXvqmY=" + "node_modules/unescape": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/unescape/-/unescape-1.0.1.tgz", + "integrity": "sha512-O0+af1Gs50lyH1nUu3ZyYS1cRh01Q/kUKatTOkSs7jukXE6/NebucDVxyiDsA9AQ4JC1V1jUH9EO8JX2nMDgGQ==", + "dependencies": { + "extend-shallow": "^2.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/universalify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", + "engines": { + "node": ">= 10.0.0" + } }, - "unpipe": { + "node_modules/unpipe": { "version": "1.0.0", - "resolved": "http://registry.npm.taobao.org/unpipe/download/unpipe-1.0.0.tgz", - "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" - }, - "upyun": { - "version": "3.3.9", - "resolved": "https://registry.npmjs.org/upyun/-/upyun-3.3.9.tgz", - "integrity": "sha512-UqvSKvvFgbQwLI+yjTO0WUnmS2i2KIvX4N2Je6ZTRN4cja17DHX7ARd13DO6h65/JOQJPs/Nua2zlnixNFIdWA==", - "requires": { - "axios": "^0.18.0", - "base-64": "^0.1.0", - "form-data": "^2.1.4", - "hmacsha1": "^1.0.0", - "is-promise": "^2.1.0", - "md5": "^2.2.1", - "mime-types": "^2.1.15" - } - }, - "url": { - "version": "0.10.3", - "resolved": "http://registry.npm.taobao.org/url/download/url-0.10.3.tgz", - "integrity": "sha1-Ah5NnHcF8hu/N9A861h2dAJ3TGQ=", - "requires": { - "punycode": "1.3.2", - "querystring": "0.2.0" - } - }, - "urllib": { - "version": "2.22.0", - "resolved": "http://registry.npm.taobao.org/urllib/download/urllib-2.22.0.tgz", - "integrity": "sha1-KWXcSuEnpvtpW32yfTGE8X2Cy0I=", - "requires": { + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/uri-js/node_modules/punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "engines": { + "node": ">=6" + } + }, + "node_modules/urllib": { + "version": "2.38.0", + "resolved": "https://registry.npmjs.org/urllib/-/urllib-2.38.0.tgz", + "integrity": "sha512-8nim/hlS5GXtWe2BJ6usPimKx5VE3nenXgcG26ip5Ru+MKPddINH8uLpZ948n6ADhlus6A0AYj8xTYNmGQi8yA==", + "dependencies": { "any-promise": "^1.3.0", "content-type": "^1.0.2", - "debug": "^2.6.0", + "debug": "^2.6.9", "default-user-agent": "^1.0.0", "digest-header": "^0.0.1", "ee-first": "~1.1.1", + "formstream": "^1.1.0", "humanize-ms": "^1.2.0", "iconv-lite": "^0.4.15", + "ip": "^1.1.5", + "proxy-agent": "^5.0.0", + "pump": "^3.0.0", "qs": "^6.4.0", - "statuses": "^1.3.1" + "statuses": "^1.3.1", + "utility": "^1.16.1" }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "http://registry.npm.taobao.org/debug/download/debug-2.6.9.tgz", - "integrity": "sha1-XRKFFd8TT/Mn6QpMk/Tgd6U2NB8=", - "requires": { - "ms": "2.0.0" - } - } + "engines": { + "node": ">= 0.10.0" } }, - "util-deprecate": { + "node_modules/util-deprecate": { "version": "1.0.2", - "resolved": "http://registry.npm.taobao.org/util-deprecate/download/util-deprecate-1.0.2.tgz", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" }, - "utility": { - "version": "0.1.11", - "resolved": "http://registry.npm.taobao.org/utility/download/utility-0.1.11.tgz", - "integrity": "sha1-/eYM+bTkdRlHoM9dEEzik2ciZxU=", - "requires": { - "address": ">=0.0.1" + "node_modules/utility": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/utility/-/utility-1.17.0.tgz", + "integrity": "sha512-KdVkF9An/0239BJ4+dqOa7NPrPIOeQE9AGfx0XS16O9DBiHNHRJMoeU5nL6pRGAkgJOqdOu8R4gBRcXnAocJKw==", + "dependencies": { + "copy-to": "^2.0.1", + "escape-html": "^1.0.3", + "mkdirp": "^0.5.1", + "mz": "^2.7.0", + "unescape": "^1.0.1" + }, + "engines": { + "node": ">= 0.12.0" } }, - "utils-merge": { + "node_modules/utils-merge": { "version": "1.0.1", - "resolved": "http://registry.npm.taobao.org/utils-merge/download/utils-merge-1.0.1.tgz", - "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=", + "engines": { + "node": ">= 0.4.0" + } }, - "uuid": { - "version": "3.1.0", - "resolved": "http://registry.npm.taobao.org/uuid/download/uuid-3.1.0.tgz", - "integrity": "sha1-PdPT55Crwk17DToDT/q6vijrvAQ=" + "node_modules/uuid": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", + "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==", + "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", + "bin": { + "uuid": "bin/uuid" + } + }, + "node_modules/v8-compile-cache": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", + "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", + "dev": true + }, + "node_modules/validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "dependencies": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } }, - "validator": { - "version": "10.6.0", - "resolved": "http://registry.npm.taobao.org/validator/download/validator-10.6.0.tgz", - "integrity": "sha1-qb3OaFs8PoSA5+u7nrlcVM2XM7A=" + "node_modules/validator": { + "version": "13.7.0", + "resolved": "https://registry.npmjs.org/validator/-/validator-13.7.0.tgz", + "integrity": "sha512-nYXQLCBkpJ8X6ltALua9dRrZDHVYxjJ1wgskNt1lH9fzGjs3tgojGSCBjmEPwkWS1y29+DrizMTW19Pr9uB2nw==", + "engines": { + "node": ">= 0.10" + } }, - "vary": { + "node_modules/vary": { "version": "1.1.2", - "resolved": "http://registry.npm.taobao.org/vary/download/vary-1.1.2.tgz", - "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=", + "engines": { + "node": ">= 0.8" + } }, - "verror": { + "node_modules/verror": { "version": "1.10.0", - "resolved": "http://registry.npm.taobao.org/verror/download/verror-1.10.0.tgz", - "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", - "requires": { + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==", + "engines": [ + "node >=0.6.0" + ], + "dependencies": { "assert-plus": "^1.0.0", "core-util-is": "1.0.2", "extsprintf": "^1.2.0" } }, - "void-elements": { - "version": "2.0.1", - "resolved": "http://registry.npm.taobao.org/void-elements/download/void-elements-2.0.1.tgz", - "integrity": "sha1-wGavtYK7HLQSjWDqkjkulNXp2+w=" - }, - "watchr": { - "version": "2.4.13", - "resolved": "http://registry.npm.taobao.org/watchr/download/watchr-2.4.13.tgz", - "integrity": "sha1-10hHu01vkPYf4sdPn2hmKqDgdgE=", - "requires": { - "eachr": "^2.0.2", - "extendr": "^2.1.0", - "extract-opts": "^2.2.0", - "ignorefs": "^1.0.0", - "safefs": "^3.1.2", - "scandirectory": "^2.5.0", - "taskgroup": "^4.2.0", - "typechecker": "^2.0.8" - } - }, - "which": { - "version": "1.3.0", - "resolved": "http://registry.npm.taobao.org/which/download/which-1.3.0.tgz", - "integrity": "sha1-/wS9/AEO5UfXgL7DjhrBwnd9JTo=", - "requires": { + "node_modules/vm2": { + "version": "3.9.9", + "resolved": "https://registry.npmjs.org/vm2/-/vm2-3.9.9.tgz", + "integrity": "sha512-xwTm7NLh/uOjARRBs8/95H0e8fT3Ukw5D/JJWhxMbhKzNh1Nu981jQKvkep9iKYNxzlVrdzD0mlBGkDKZWprlw==", + "deprecated": "The library contains critical security issues and should not be used for production! The maintenance of the project has been discontinued. Consider migrating your code to isolated-vm.", + "dependencies": { + "acorn": "^8.7.0", + "acorn-walk": "^8.2.0" + }, + "bin": { + "vm2": "bin/vm2" + }, + "engines": { + "node": ">=6.0" + } + }, + "node_modules/vm2/node_modules/acorn": { + "version": "8.7.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.1.tgz", + "integrity": "sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A==", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/void-elements": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-3.1.0.tgz", + "integrity": "sha1-YU9/v42AHwu18GYfWy9XhXUOTwk=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=" + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "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, + "dependencies": { "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/which-boxed-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", + "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "dev": true, + "dependencies": { + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "which-module": { + "node_modules/which-module": { "version": "2.0.0", - "resolved": "http://registry.npm.taobao.org/which-module/download/which-module-2.0.0.tgz", - "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=" + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", + "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", + "dev": true }, - "win-release": { + "node_modules/win-release": { "version": "1.1.1", - "resolved": "http://registry.npm.taobao.org/win-release/download/win-release-1.1.1.tgz", + "resolved": "https://registry.npmjs.org/win-release/-/win-release-1.1.1.tgz", "integrity": "sha1-X6VeAr58qTTt/BJmVjLoSbcuUgk=", - "requires": { + "dependencies": { "semver": "^5.0.1" + }, + "engines": { + "node": ">=0.10.0" } }, - "window-size": { - "version": "0.1.4", - "resolved": "http://registry.npm.taobao.org/window-size/download/window-size-0.1.4.tgz", - "integrity": "sha1-+OGqHuWlPsW/FR/6CXQqatdpeHY=" + "node_modules/win-release/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "bin": { + "semver": "bin/semver" + } }, - "with": { - "version": "5.1.1", - "resolved": "http://registry.npm.taobao.org/with/download/with-5.1.1.tgz", - "integrity": "sha1-+k2qktrzLE6pTtRTyB8EaGtXXf4=", - "requires": { - "acorn": "^3.1.0", - "acorn-globals": "^3.0.0" + "node_modules/with": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/with/-/with-7.0.2.tgz", + "integrity": "sha512-RNGKj82nUPg3g5ygxkQl0R937xLyho1J24ItRCBTr/m1YnZkzJy1hUiHUJrc/VlsDQzsCnInEGSg3bci0Lmd4w==", + "dependencies": { + "@babel/parser": "^7.9.6", + "@babel/types": "^7.9.6", + "assert-never": "^1.2.1", + "babel-walk": "3.0.0-canary-5" + }, + "engines": { + "node": ">= 10.0.0" } }, - "wkx": { - "version": "0.4.4", - "resolved": "http://registry.npm.taobao.org/wkx/download/wkx-0.4.4.tgz", - "integrity": "sha1-z3UbZy5LReFi+f0wEkh45z2WybI=", - "requires": { + "node_modules/wkx": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/wkx/-/wkx-0.5.0.tgz", + "integrity": "sha512-Xng/d4Ichh8uN4l0FToV/258EjMGU9MGcA0HV2d9B/ZpZB3lqQm7nkOdZdm5GhKtLLhAE7PiVQwN4eN+2YJJUg==", + "dependencies": { "@types/node": "*" } }, - "wordwrap": { + "node_modules/word-wrap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wordwrap": { "version": "1.0.0", - "resolved": "http://registry.npm.taobao.org/wordwrap/download/wordwrap-1.0.0.tgz", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", "dev": true }, - "wrap-ansi": { - "version": "2.1.0", - "resolved": "http://registry.npm.taobao.org/wrap-ansi/download/wrap-ansi-2.1.0.tgz", - "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", - "requires": { - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1" + "node_modules/workerpool": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz", + "integrity": "sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==", + "dev": true + }, + "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==", + "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" } }, - "wrappy": { + "node_modules/wrappy": { "version": "1.0.2", - "resolved": "http://registry.npm.taobao.org/wrappy/download/wrappy-1.0.2.tgz", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" }, - "write-file-atomic": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.3.0.tgz", - "integrity": "sha512-xuPeK4OdjWqtfi59ylvVL0Yn35SF3zgcAcv7rBPFHVaEapaDr4GdGgm3j7ckTwH9wHL7fGmgfAnb0+THrHb8tA==", - "requires": { - "graceful-fs": "^4.1.11", + "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, + "dependencies": { "imurmurhash": "^0.1.4", - "signal-exit": "^3.0.2" + "is-typedarray": "^1.0.0", + "signal-exit": "^3.0.2", + "typedarray-to-buffer": "^3.1.5" } }, - "x-xss-protection": { - "version": "1.1.0", - "resolved": "http://registry.npm.taobao.org/x-xss-protection/download/x-xss-protection-1.1.0.tgz", - "integrity": "sha1-TxiYwzLesefyvhKA77PixT1pwac=" - }, - "xdg-basedir": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-3.0.0.tgz", - "integrity": "sha1-SWsswQnsqNus/i3HK2A8F8WHCtQ=" - }, - "xml2js": { + "node_modules/xml2js": { "version": "0.4.4", - "resolved": "http://registry.npm.taobao.org/xml2js/download/xml2js-0.4.4.tgz", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.4.tgz", "integrity": "sha1-MREBAAMAiuGSQOuhdJe1fHKcVV0=", - "requires": { + "dependencies": { "sax": "0.6.x", "xmlbuilder": ">=1.0.0" } }, - "xmlbuilder": { - "version": "2.6.5", - "resolved": "http://registry.npm.taobao.org/xmlbuilder/download/xmlbuilder-2.6.5.tgz", - "integrity": "sha1-b/etYPty0idk8AehZLd/K/FABSY=", - "requires": { - "lodash": "^3.5.0" - }, - "dependencies": { - "lodash": { - "version": "3.10.1", - "resolved": "http://registry.npm.taobao.org/lodash/download/lodash-3.10.1.tgz", - "integrity": "sha1-W/Rejkm6QYnhfUgnid/RW9FAt7Y=" - } + "node_modules/xmlbuilder": { + "version": "13.0.2", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-13.0.2.tgz", + "integrity": "sha512-Eux0i2QdDYKbdbA6AM6xE4m6ZTZr4G4xF9kahI2ukSEMCzwce2eX9WlTI5J3s+NU7hpasFsr8hWIONae7LluAQ==", + "engines": { + "node": ">=6.0" } }, - "xregexp": { + "node_modules/xregexp": { "version": "2.0.0", - "resolved": "http://registry.npm.taobao.org/xregexp/download/xregexp-2.0.0.tgz", - "integrity": "sha1-UqY+VsoLhKfzpfPWGHLxJq16WUM=" + "resolved": "https://registry.npmjs.org/xregexp/-/xregexp-2.0.0.tgz", + "integrity": "sha1-UqY+VsoLhKfzpfPWGHLxJq16WUM=", + "engines": { + "node": "*" + } }, - "xtend": { - "version": "4.0.1", - "resolved": "http://registry.npm.taobao.org/xtend/download/xtend-4.0.1.tgz", - "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=" + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "dev": true, + "engines": { + "node": ">=0.4" + } }, - "y18n": { - "version": "3.2.1", - "resolved": "http://registry.npm.taobao.org/y18n/download/y18n-3.2.1.tgz", - "integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE=" + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "engines": { + "node": ">=10" + } }, - "yallist": { - "version": "2.1.2", - "resolved": "http://registry.npm.taobao.org/yallist/download/yallist-2.1.2.tgz", - "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=" + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" }, - "yargs": { - "version": "12.0.1", - "resolved": "http://registry.npm.taobao.org/yargs/download/yargs-12.0.1.tgz", - "integrity": "sha1-ZDLlYSO7Tnw1YhFUAemDdAYCYcI=", - "requires": { - "cliui": "^4.0.0", - "decamelize": "^2.0.0", - "find-up": "^3.0.0", - "get-caller-file": "^1.0.1", - "os-locale": "^2.0.0", + "node_modules/yargs": { + "version": "17.5.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.5.1.tgz", + "integrity": "sha512-t6YAJcxDkNX7NFYiVtKvWUz8l+PaKTLiL63mJYWR2GnHq2gjEWISzsLp9wg3aY36dY1j+gfIEL3pIF+XlJJfbA==", + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", - "require-main-filename": "^1.0.1", - "set-blocking": "^2.0.0", - "string-width": "^2.0.0", - "which-module": "^2.0.0", - "y18n": "^3.2.1 || ^4.0.0", - "yargs-parser": "^10.1.0" + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.0.0" }, - "dependencies": { - "ansi-regex": { - "version": "3.0.0", - "resolved": "http://registry.npm.taobao.org/ansi-regex/download/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=" - }, - "cliui": { - "version": "4.1.0", - "resolved": "http://registry.npm.taobao.org/cliui/download/cliui-4.1.0.tgz", - "integrity": "sha1-NIQi2+gtgAswIu709qwQvy5NG0k=", - "requires": { - "string-width": "^2.1.1", - "strip-ansi": "^4.0.0", - "wrap-ansi": "^2.0.0" - } - }, - "decamelize": { - "version": "2.0.0", - "resolved": "http://registry.npm.taobao.org/decamelize/download/decamelize-2.0.0.tgz", - "integrity": "sha1-ZW17vICUxMeI6lPFhAkIycfQY8c=", - "requires": { - "xregexp": "4.0.0" - } - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "http://registry.npm.taobao.org/is-fullwidth-code-point/download/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=" - }, - "os-locale": { - "version": "2.1.0", - "resolved": "http://registry.npm.taobao.org/os-locale/download/os-locale-2.1.0.tgz", - "integrity": "sha1-QrwpAKa1uL0XN2yOiCtlr8zyS/I=", - "requires": { - "execa": "^0.7.0", - "lcid": "^1.0.0", - "mem": "^1.1.0" - } - }, - "string-width": { - "version": "2.1.1", - "resolved": "http://registry.npm.taobao.org/string-width/download/string-width-2.1.1.tgz", - "integrity": "sha1-q5Pyeo3BPSjKyBXEYhQ6bZASrp4=", - "requires": { - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" - } - }, - "strip-ansi": { - "version": "4.0.0", - "resolved": "http://registry.npm.taobao.org/strip-ansi/download/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", - "requires": { - "ansi-regex": "^3.0.0" - } - }, - "xregexp": { - "version": "4.0.0", - "resolved": "http://registry.npm.taobao.org/xregexp/download/xregexp-4.0.0.tgz", - "integrity": "sha1-5pgYneSd0qGMxWh7BeF8jkOUMCA=" - } + "engines": { + "node": ">=12" } }, - "yargs-parser": { - "version": "10.1.0", - "resolved": "http://registry.npm.taobao.org/yargs-parser/download/yargs-parser-10.1.0.tgz", - "integrity": "sha1-cgImW4n36eny5XZeD+c1qQXtuqg=", - "requires": { - "camelcase": "^4.1.0" - }, + "node_modules/yargs-parser": { + "version": "21.0.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.0.1.tgz", + "integrity": "sha512-9BK1jFpLzJROCI5TzwZL/TU4gqjK5xiHV/RfWLOahrjAko/e4DJkRDZQXfvqAsiZzzYhgAzbgz6lg48jcm4GLg==", + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-unparser": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", + "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", + "dev": true, "dependencies": { - "camelcase": { - "version": "4.1.0", - "resolved": "http://registry.npm.taobao.org/camelcase/download/camelcase-4.1.0.tgz", - "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=" - } + "camelcase": "^6.0.0", + "decamelize": "^4.0.0", + "flat": "^5.0.2", + "is-plain-obj": "^2.1.0" + }, + "engines": { + "node": ">=10" } }, - "yauzl": { - "version": "2.4.1", - "resolved": "http://registry.npm.taobao.org/yauzl/download/yauzl-2.4.1.tgz", - "integrity": "sha1-lSj0QtqxsihOWLQ3m7GU4i4MQAU=", - "requires": { - "fd-slicer": "~1.0.1" + "node_modules/yauzl": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", + "integrity": "sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk=", + "dependencies": { + "buffer-crc32": "~0.2.3", + "fd-slicer": "~1.1.0" } }, - "yazl": { - "version": "2.4.3", - "resolved": "http://registry.npm.taobao.org/yazl/download/yazl-2.4.3.tgz", - "integrity": "sha1-7CblzIfVYBud+EMtvdPNLlFzoHE=", - "requires": { + "node_modules/yazl": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/yazl/-/yazl-2.5.1.tgz", + "integrity": "sha512-phENi2PLiHnHb6QBVot+dJnaAZ0xosj7p3fWl+znIjBDlnMI2PsZCJZ306BPTFOaHf5qdDEI8x5qFrSOBN5vrw==", + "dependencies": { "buffer-crc32": "~0.2.3" } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } } } } diff --git a/package.json b/package.json index 1e3fc19a..8f484853 100644 --- a/package.json +++ b/package.json @@ -1,11 +1,11 @@ { - "name": "code-push-server", + "name": "@shm-open/code-push-server", "description": "CodePush service is hotupdate services which adapter react-native-code-push and cordova-plugin-code-push", - "version": "0.5.4", + "version": "2.1.6", "license": "MIT", "repository": { "type": "git", - "url": "git://github.com/lisong/code-push-server.git" + "url": "https://github.com/shm-open/code-push-server.git" }, "keywords": [ "code-push", @@ -15,87 +15,94 @@ "code", "push" ], - "author": { - "name": "Tab Lee", - "email": "lisong2010@gmail.com", - "url": "https://github.com/lisong/" - }, + "author": "shihuimiao", "bin": { - "code-push-server": "./bin/www", - "code-push-server-db": "./bin/db" + "code-push-server": "./bin/www.js", + "code-push-server-db": "./bin/db.js" }, "engines": { - "node": ">= 6.0", - "npm": ">= 3.10.8" + "node": "24.6.0", + "npm": "11.5.1" }, "scripts": { - "dev": "supervisor ./bin/www", - "start": "node ./bin/www", - "init": "node ./bin/db init", - "upgrade": "node ./bin/db upgrade", + "dev": "npm run build && concurrently npm:dev:tsc npm:dev:run", + "dev:tsc": "tsc --watch", + "dev:run": "LOG_LEVEL=debug supervisor -e 'node|js|ts|pug|json' ./bin/www.js", + "start": "node ./bin/www.js", + "init": "node ./bin/db.js init", + "upgrade": "node ./bin/db.js upgrade", + "build": "rm -rf bin && tsc", + "release": "npm run build && npm test && standard-version && git push --follow-tags origin master && npm publish", + "release-docker": "make release-docker", "test": "make test", - "test-win": "mocha test/api/init test/api/users test/api/auth test/api/account test/api/accessKeys test/api/apps test/api/index --recursive --timeout 15000", - "coverage": "make coverage" + "coverage": "make coverage", + "lint": "eslint src" }, "dependencies": { - "aliyun-oss-upload-stream": "^1.3.0", - "aliyun-sdk": "^1.11.10", - "aws-sdk": "^2.7.0", - "bcryptjs": "^2.3.0", - "bluebird": "^3.4.1", - "body-parser": "^1.15.2", - "cookie-parser": "^1.4.3", - "cos-nodejs-sdk-v5": "^2.4.10", - "debug": "^3.1.0", - "diff-match-patch": "^1.0.1", - "express": "^4.14.0", - "extract-zip": "^1.6.0", - "formidable": "^1.2.1", - "fs-extra": "^7.0.0", - "helmet": "^3.1.0", - "i18n": "^0.8.3", - "jschardet": "^1.6.0", - "jsonwebtoken": "^8.2.0", - "lodash": "^4.17.5", - "log4js": "^3.0.5", - "markdown-it": "^8.0.1", - "moment": "^2.14.1", - "morgan": "^1.7.0", - "mysql2": "^1.3.5", - "nodemailer": "^4.0.1", - "pug": "^2.0.1", - "qiniu": "^7.1.3", - "upyun": "^3.3.9", - "rand-token": "^0.4.0", - "recursive-readdir": "^2.1.1", - "redis": "^2.6.2", - "request": "^2.72.0", - "sequelize": "^4.37.1", - "serve-favicon": "^2.4.0", - "slash": "^2.0.0", - "validator": "^10.6.0", - "yargs": "^12.0.1", - "yazl": "^2.3.0" + "@aws-sdk/client-s3": "^3.932.0", + "@aws-sdk/lib-storage": "^3.932.0", + "aliyun-oss-upload-stream": "1.3.0", + "aliyun-sdk": "1.12.4", + "bcryptjs": "2.4.3", + "body-parser": "1.20.0", + "cookie-parser": "1.4.6", + "cos-nodejs-sdk-v5": "2.11.12", + "dotenv": "^17.2.3", + "express": "4.18.1", + "extract-zip": "2.0.1", + "formidable": "2.0.1", + "fs-extra": "10.1.0", + "helmet": "5.1.0", + "i18n": "0.15.0", + "jsonwebtoken": "8.5.1", + "kv-logger": "0.5.3", + "lodash": "4.17.21", + "moment": "2.29.3", + "mysql2": "2.3.3", + "node-fetch": "2.6.7", + "nodemailer": "6.7.7", + "pug": "3.0.2", + "qiniu": "7.7.0", + "rand-token": "1.0.1", + "recursive-readdir": "2.2.2", + "redis": "4.2.0", + "sequelize": "6.21.3", + "slash": "3.0.0", + "validator": "13.7.0", + "yargs": "17.5.1", + "yazl": "2.5.1" }, "devDependencies": { - "istanbul": "^0.4.5", - "mocha": "^3.2.0", - "should": "^11.2.0", - "supertest": "^3.0.0", - "supervisor": "^0.12.0" + "@shm-open/eslint-config-bundle": "1.9.13", + "@types/bcryptjs": "2.4.2", + "@types/body-parser": "1.19.2", + "@types/cookie-parser": "1.4.3", + "@types/formidable": "2.0.5", + "@types/fs-extra": "9.0.13", + "@types/i18n": "0.13.4", + "@types/jsonwebtoken": "8.5.9", + "@types/lodash": "4.14.195", + "@types/node-fetch": "2.6.2", + "@types/nodemailer": "6.4.5", + "@types/recursive-readdir": "2.2.1", + "@types/validator": "13.7.10", + "@types/yazl": "2.4.2", + "concurrently": "7.4.0", + "mocha": "10.0.0", + "nyc": "15.1.0", + "should": "13.2.3", + "standard-version": "9.5.0", + "supertest": "6.2.4", + "supervisor": "0.12.0", + "typescript": "4.9.5" }, "files": [ "bin", - "config", - "core", "docs", - "docker", - "models", + "locales", "public", - "routes", "sql", "views", - "app.js", "README.md", "LICENSE" ] diff --git a/process.json b/process.json new file mode 100644 index 00000000..197e8d1a --- /dev/null +++ b/process.json @@ -0,0 +1,14 @@ +{ + "apps": [ + { + "name": "code-push-server", + "max_memory_restart": "500M", + "script": "code-push-server", + "instances": "max", + "exec_mode": "cluster", + "env": { + "NODE_ENV": "production" + } + } + ] +} diff --git a/public/favicon.ico b/public/favicon.ico new file mode 100644 index 00000000..0a88c596 Binary files /dev/null and b/public/favicon.ico differ diff --git a/public/stylesheets/index.css b/public/stylesheets/common.css similarity index 100% rename from public/stylesheets/index.css rename to public/stylesheets/common.css diff --git a/public/stylesheets/style.css b/public/stylesheets/style.css deleted file mode 100644 index 9453385b..00000000 --- a/public/stylesheets/style.css +++ /dev/null @@ -1,8 +0,0 @@ -body { - padding: 50px; - font: 14px "Lucida Grande", Helvetica, Arial, sans-serif; -} - -a { - color: #00B7FF; -} diff --git a/public/stylesheets/tokens.css b/public/stylesheets/tokens.css deleted file mode 100644 index 62a96c37..00000000 --- a/public/stylesheets/tokens.css +++ /dev/null @@ -1,5 +0,0 @@ -.site-notice { - padding: 5px 0; - text-align: center; - background-color: #fff; -} diff --git a/renovate.json b/renovate.json new file mode 100644 index 00000000..4ab34f0b --- /dev/null +++ b/renovate.json @@ -0,0 +1,6 @@ +{ + "extends": ["config:base"], + "devDependencies": { + "automerge": true + } +} diff --git a/routes/accessKeys.js b/routes/accessKeys.js deleted file mode 100644 index b7239b41..00000000 --- a/routes/accessKeys.js +++ /dev/null @@ -1,84 +0,0 @@ -var express = require('express'); -var router = express.Router(); -var _ = require('lodash'); -var Promise = require('bluebird'); -var security = require('../core/utils/security'); -var models = require('../models'); -var middleware = require('../core/middleware'); -var accountManager = require('../core/services/account-manager')(); -var AppError = require('../core/app-error') -var log4js = require('log4js'); -var log = log4js.getLogger("cps:accessKey"); - -router.get('/', middleware.checkToken, (req, res, next) => { - log.debug('request get acceesKeys') - var uid = req.users.id; - accountManager.getAllAccessKeyByUid(uid) - .then((accessKeys) => { - log.debug('acceesKeys:', accessKeys) - res.send({accessKeys: accessKeys}); - }) - .catch((e) => { - next(e); - }); -}); - -router.post('/', middleware.checkToken, (req, res, next) => { - var uid = req.users.id; - var identical = req.users.identical; - var createdBy = _.trim(req.body.createdBy); - var friendlyName = _.trim(req.body.friendlyName); - var ttl = parseInt(req.body.ttl); - var description = _.trim(req.body.description); - log.debug(req.body) - var newAccessKey = security.randToken(28).concat(identical); - return accountManager.isExsitAccessKeyName(uid, friendlyName) - .then((data) => { - if (!_.isEmpty(data)) { - throw new AppError.AppError(`The access key "${friendlyName}" already exists.`); - } - }) - .then(() => { - return accountManager.createAccessKey(uid, newAccessKey, ttl, friendlyName, createdBy, description); - }) - .then((newToken) => { - var moment = require("moment"); - var info = { - name : newToken.tokens, - createdTime : parseInt(moment(newToken.created_at).format('x')), - createdBy : newToken.created_by, - expires : parseInt(moment(newToken.expires_at).format('x')), - description : newToken.description, - friendlyName: newToken.name, - }; - log.debug(info); - res.send({accessKey:info}); - }) - .catch((e) => { - if (e instanceof AppError.AppError) { - log.debug(e) - res.status(406).send(e.message); - } else { - next(e); - } - }); -}); - -router.delete('/:name', middleware.checkToken, (req, res, next) => { - var name = _.trim(decodeURI(req.params.name)); - var uid = req.users.id; - return models.UserTokens.destroy({where: {name:name, uid: uid}}) - .then((rowNum) => { - log.debug('delete acceesKey:', name) - res.send({friendlyName:name}); - }) - .catch((e) => { - if (e instanceof AppError.AppError) { - log.debug(e) - res.status(406).send(e.message); - } else { - next(e); - } - }); -}); -module.exports = router; diff --git a/routes/account.js b/routes/account.js deleted file mode 100644 index edae56f1..00000000 --- a/routes/account.js +++ /dev/null @@ -1,20 +0,0 @@ -var express = require('express'); -var router = express.Router(); -var models = require('../models'); -var _ = require('lodash'); -var security = require('../core/utils/security'); -var middleware = require('../core/middleware'); -var log4js = require('log4js'); -var log = log4js.getLogger("cps:account"); - -router.get('/', middleware.checkToken, (req, res) => { - var userInfo = { - email:req.users.email, - linkedProviders: [], - name:req.users.username, - }; - log.debug(userInfo); - res.send({account:userInfo}); -}); - -module.exports = router; diff --git a/routes/apps.js b/routes/apps.js deleted file mode 100644 index 8fd7d832..00000000 --- a/routes/apps.js +++ /dev/null @@ -1,727 +0,0 @@ -var express = require('express'); -var Promise = require('bluebird'); -var router = express.Router(); -var _ = require('lodash'); -var middleware = require('../core/middleware'); -var validator = require('validator'); -var accountManager = require('../core/services/account-manager')(); -var Deployments = require('../core/services/deployments'); -var Collaborators = require('../core/services/collaborators'); -var AppManager = require('../core/services/app-manager'); -var PackageManager = require('../core/services/package-manager'); -var AppError = require('../core/app-error'); -var common = require('../core/utils/common'); -var config = require('../core/config'); -const REGEX = /^(\w+)(-android|-ios)$/; -const REGEX_ANDROID = /^(\w+)(-android)$/; -const REGEX_IOS = /^(\w+)(-ios)$/; -var log4js = require('log4js'); -var log = log4js.getLogger("cps:apps"); - -router.get('/', middleware.checkToken, (req, res, next) => { - var uid = req.users.id; - var appManager = new AppManager(); - appManager.listApps(uid) - .then((data) => { - res.send({apps: data}); - }) - .catch((e) => { - if (e instanceof AppError.AppError) { - res.status(406).send(e.message); - } else { - next(e); - } - }); -}); - -router.get('/:appName/deployments', - middleware.checkToken, (req, res, next) => { - var uid = req.users.id; - var appName = _.trim(req.params.appName); - var deployments = new Deployments(); - accountManager.collaboratorCan(uid, appName) - .then((col) => { - return deployments.listDeloyments(col.appid); - }) - .then((data) => { - res.send({deployments: data}); - }) - .catch((e) => { - if (e instanceof AppError.AppError) { - res.status(406).send(e.message); - } else { - next(e); - } - }); -}); - -router.get('/:appName/deployments/:deploymentName', - middleware.checkToken, (req, res, next) => { - var uid = req.users.id; - var appName = _.trim(req.params.appName); - var deploymentName = _.trim(req.params.deploymentName); - var deployments = new Deployments(); - accountManager.collaboratorCan(uid, appName) - .then((col) => { - return deployments.findDeloymentByName(deploymentName, col.appid) - }) - .then((deploymentInfo) => { - if (_.isEmpty(deploymentInfo)) { - throw new AppError.AppError("does not find the deployment"); - } - res.send({deployment: deployments.listDeloyment(deploymentInfo)}); - return true; - }) - .catch((e) => { - if (e instanceof AppError.AppError) { - res.status(406).send(e.message); - } else { - next(e); - } - }); -}); - -router.post('/:appName/deployments', - middleware.checkToken, (req, res, next) => { - var uid = req.users.id; - var appName = _.trim(req.params.appName); - var name = req.body.name; - var deployments = new Deployments(); - accountManager.ownerCan(uid, appName) - .then((col) => { - return deployments.addDeloyment(name, col.appid, uid); - }) - .then((data) => { - res.send({deployment: {name: data.name, key: data.deployment_key}}); - }) - .catch((e) => { - if (e instanceof AppError.AppError) { - res.status(406).send(e.message); - } else { - next(e); - } - }); -}); - -router.get('/:appName/deployments/:deploymentName/metrics', - middleware.checkToken, (req, res, next) => { - var uid = req.users.id; - var appName = _.trim(req.params.appName); - var deploymentName = _.trim(req.params.deploymentName); - var deployments = new Deployments(); - var packageManager = new PackageManager(); - accountManager.collaboratorCan(uid, appName) - .then((col) => { - return deployments.findDeloymentByName(deploymentName, col.appid) - .then((deploymentInfo) => { - if (_.isEmpty(deploymentInfo)) { - throw new AppError.AppError("does not find the deployment"); - } - return deploymentInfo; - }) - }) - .then((deploymentInfo) => { - return deployments.getAllPackageIdsByDeploymentsId(deploymentInfo.id); - }) - .then((packagesInfos) => { - return Promise.reduce(packagesInfos, (result, v) => { - return packageManager.getMetricsbyPackageId(v.get('id')) - .then((metrics) => { - if (metrics) { - result[v.get('label')] = { - active: metrics.get('active'), - downloaded: metrics.get('downloaded'), - failed: metrics.get('failed'), - installed: metrics.get('installed'), - }; - } - return result; - }); - }, {}); - }) - .then((rs) => { - res.send({"metrics": rs}); - }) - .catch((e) => { - if (e instanceof AppError.AppError) { - res.send({"metrics": null}); - } else { - next(e); - } - }); -}); - -router.get('/:appName/deployments/:deploymentName/history', - middleware.checkToken, (req, res, next) => { - var uid = req.users.id; - var appName = _.trim(req.params.appName); - var deploymentName = _.trim(req.params.deploymentName); - var deployments = new Deployments(); - accountManager.collaboratorCan(uid, appName) - .then((col) => { - return deployments.findDeloymentByName(deploymentName, col.appid) - .then((deploymentInfo) => { - if (_.isEmpty(deploymentInfo)) { - throw new AppError.AppError("does not find the deployment"); - } - return deploymentInfo; - }); - }) - .then((deploymentInfo) => { - return deployments.getDeploymentHistory(deploymentInfo.id); - }) - .then((rs) => { - res.send({history: _.pullAll(rs, [null, false])}); - }) - .catch((e) => { - if (e instanceof AppError.AppError) { - res.status(406).send(e.message); - } else { - next(e); - } - }); -}); - -router.delete('/:appName/deployments/:deploymentName/history', - middleware.checkToken, (req, res, next) => { - var uid = req.users.id; - var appName = _.trim(req.params.appName); - var deploymentName = _.trim(req.params.deploymentName); - var deployments = new Deployments(); - accountManager.ownerCan(uid, appName) - .then((col) => { - return deployments.findDeloymentByName(deploymentName, col.appid) - .then((deploymentInfo) => { - if (_.isEmpty(deploymentInfo)) { - throw new AppError.AppError("does not find the deployment"); - } - return deploymentInfo; - }); - }) - .then((deploymentInfo) => { - return deployments.deleteDeploymentHistory(deploymentInfo.id); - }) - .then((rs) => { - res.send("ok"); - }) - .catch((e) => { - if (e instanceof AppError.AppError) { - res.status(406).send(e.message); - } else { - next(e); - } - }); -}); - -router.patch('/:appName/deployments/:deploymentName', - middleware.checkToken, (req, res, next) => { - var name = req.body.name; - var appName = _.trim(req.params.appName); - var deploymentName = _.trim(req.params.deploymentName); - var uid = req.users.id; - var deployments = new Deployments(); - accountManager.ownerCan(uid, appName) - .then((col) => { - return deployments.renameDeloymentByName(deploymentName, col.appid, name); - }) - .then((data) => { - res.send({deployment: data}); - }) - .catch((e) => { - if (e instanceof AppError.AppError) { - res.status(406).send(e.message); - } else { - next(e); - } - }); -}); - -router.delete('/:appName/deployments/:deploymentName', - middleware.checkToken, (req, res, next) => { - var appName = _.trim(req.params.appName); - var deploymentName = _.trim(req.params.deploymentName); - var uid = req.users.id; - var deployments = new Deployments(); - accountManager.ownerCan(uid, appName) - .then((col) => { - return deployments.deleteDeloymentByName(deploymentName, col.appid); - }) - .then((data) => { - res.send({deployment: data}); - }) - .catch((e) => { - if (e instanceof AppError.AppError) { - res.status(406).send(e.message); - } else { - next(e); - } - }); -}); - -router.post('/:appName/deployments/:deploymentName/release', - middleware.checkToken, (req, res, next) => { - var appName = _.trim(req.params.appName); - var deploymentName = _.trim(req.params.deploymentName); - var uid = req.users.id; - var deployments = new Deployments(); - var packageManager = new PackageManager(); - accountManager.collaboratorCan(uid, appName) - .then((col) => { - log.debug(col); - return deployments.findDeloymentByName(deploymentName, col.appid) - .then((deploymentInfo) => { - if (_.isEmpty(deploymentInfo)) { - log.debug(`does not find the deployment`); - throw new AppError.AppError("does not find the deployment"); - } - return packageManager.parseReqFile(req) - .then((data) => { - if (data.package.type != "application/zip") { - log.debug(`upload file type is invlidate`, data.package); - throw new AppError.AppError("upload file type is invalidate"); - } - log.debug('packageInfo:', data.packageInfo); - return packageManager.releasePackage(deploymentInfo.appid, deploymentInfo.id, data.packageInfo, data.package.path, uid) - .finally(() => { - common.deleteFolderSync(data.package.path); - }); - }) - .then((packages) => { - if (packages) { - Promise.delay(1000) - .then(() => { - packageManager.createDiffPackagesByLastNums(deploymentInfo.appid, packages, _.get(config, 'common.diffNums', 1)) - .catch((e) => { - log.error(e); - }); - }); - } - //clear cache if exists. - if (_.get(config, 'common.updateCheckCache', false) !== false) { - Promise.delay(2500) - .then(() => { - var ClientManager = require('../core/services/client-manager'); - var clientManager = new ClientManager(); - clientManager.clearUpdateCheckCache(deploymentInfo.deployment_key, '*', '*', '*'); - }); - } - return null; - }); - }); - }) - .then(() => { - res.send('{"msg": "succeed"}'); - }) - .catch((e) => { - if (e instanceof AppError.AppError) { - res.status(406).send(e.message); - } else { - next(e); - } - }); -}); - -router.patch('/:appName/deployments/:deploymentName/release', - middleware.checkToken, (req, res, next) => { - log.debug('req.body', req.body); - var appName = _.trim(req.params.appName); - var deploymentName = _.trim(req.params.deploymentName); - var uid = req.users.id; - var deployments = new Deployments(); - var packageManager = new PackageManager(); - var label = _.get(req, 'body.packageInfo.label'); - accountManager.collaboratorCan(uid, appName) - .then((col) => { - return deployments.findDeloymentByName(deploymentName, col.appid) - .then((deploymentInfo) => { - if (_.isEmpty(deploymentInfo)) { - throw new AppError.AppError("does not find the deployment"); - } - if (label) { - return packageManager.findPackageInfoByDeploymentIdAndLabel(deploymentInfo.id, label) - .then((data)=>{ - return [deploymentInfo, data]; - }); - } else { - var deploymentVersionId = deploymentInfo.last_deployment_version_id; - return packageManager.findLatestPackageInfoByDeployVersion(deploymentVersionId) - .then((data)=>{ - return [deploymentInfo, data]; - });; - } - }) - .spread((deploymentInfo, packageInfo)=>{ - if (!packageInfo) { - throw new AppError.AppError("does not find the packageInfo"); - } - return packageManager.modifyReleasePackage(packageInfo.id, _.get(req, 'body.packageInfo')) - .then(()=>{ - //clear cache if exists. - if (_.get(config, 'common.updateCheckCache', false) !== false) { - Promise.delay(2500) - .then(() => { - var ClientManager = require('../core/services/client-manager'); - var clientManager = new ClientManager(); - clientManager.clearUpdateCheckCache(deploymentInfo.deployment_key, '*', '*', '*'); - }); - } - }); - }); - }).then((data) => { - res.send(""); - }) - .catch((e) => { - if (e instanceof AppError.AppError) { - res.status(406).send(e.message); - } else { - next(e); - } - }); -}); - - -router.post('/:appName/deployments/:sourceDeploymentName/promote/:destDeploymentName', - middleware.checkToken, (req, res, next) => { - log.debug('req.body:', req.body); - var appName = _.trim(req.params.appName); - var sourceDeploymentName = _.trim(req.params.sourceDeploymentName); - var destDeploymentName = _.trim(req.params.destDeploymentName); - var uid = req.users.id; - var packageManager = new PackageManager(); - var deployments = new Deployments(); - accountManager.collaboratorCan(uid, appName) - .then((col) => { - var appId = col.appid; - return Promise.all([ - deployments.findDeloymentByName(sourceDeploymentName, appId), - deployments.findDeloymentByName(destDeploymentName, appId) - ]) - .spread((sourceDeploymentInfo, destDeploymentInfo) => { - if (!sourceDeploymentInfo) { - throw new AppError.AppError(`${sourceDeploymentName} does not exist.`); - } - if (!destDeploymentInfo) { - throw new AppError.AppError(`${destDeploymentName} does not exist.`); - } - return [sourceDeploymentInfo, destDeploymentInfo]; - }) - .spread((sourceDeploymentInfo, destDeploymentInfo) => { - var params = _.get(req.body, 'packageInfo', {}); - _.set(params, 'promoteUid', uid); - return [packageManager.promotePackage(sourceDeploymentInfo, destDeploymentInfo, params),destDeploymentInfo]; - }) - .spread((packages, destDeploymentInfo) => { - if (packages) { - Promise.delay(1000) - .then(() => { - packageManager.createDiffPackagesByLastNums(destDeploymentInfo.appid, packages, _.get(config, 'common.diffNums', 1)) - .catch((e) => { - log.error(e); - }); - }); - } - //clear cache if exists. - if (_.get(config, 'common.updateCheckCache', false) !== false) { - Promise.delay(2500) - .then(() => { - var ClientManager = require('../core/services/client-manager'); - var clientManager = new ClientManager(); - clientManager.clearUpdateCheckCache(destDeploymentInfo.deployment_key, '*', '*', '*'); - }); - } - return packages; - }) - }) - .then((packages) => { - res.send({package:packages}); - }) - .catch((e) => { - if (e instanceof AppError.AppError) { - res.status(406).send(e.message); - } else { - next(e); - } - }); -}); - -var rollbackCb = function (req, res, next) { - var appName = _.trim(req.params.appName); - var deploymentName = _.trim(req.params.deploymentName); - var uid = req.users.id; - var targetLabel = _.trim(_.get(req, 'params.label')); - var deployments = new Deployments(); - var packageManager = new PackageManager(); - accountManager.collaboratorCan(uid, appName) - .then((col) => { - return deployments.findDeloymentByName(deploymentName, col.appid); - }) - .then((dep) => { - return packageManager.rollbackPackage(dep.last_deployment_version_id, targetLabel, uid) - .then((packageInfo)=>{ - if (packageInfo) { - Promise.delay(1000) - .then(() => { - packageManager.createDiffPackagesByLastNums(dep.appid, packageInfo, 1) - .catch((e) => { - log.error(e); - }); - }); - } - //clear cache if exists. - if (_.get(config, 'common.updateCheckCache', false) !== false) { - Promise.delay(2500) - .then(() => { - var ClientManager = require('../core/services/client-manager'); - var clientManager = new ClientManager(); - clientManager.clearUpdateCheckCache(dep.deployment_key, '*', '*', '*'); - }); - } - return packageInfo; - }); - }) - .then(() => { - res.send('ok'); - }) - .catch((e) => { - if (e instanceof AppError.AppError) { - res.status(406).send(e.message); - } else { - next(e); - } - }); -}; - -router.post('/:appName/deployments/:deploymentName/rollback', - middleware.checkToken, rollbackCb); - -router.post('/:appName/deployments/:deploymentName/rollback/:label', - middleware.checkToken, rollbackCb); - -router.get('/:appName/collaborators', - middleware.checkToken, (req, res, next) => { - var appName = _.trim(req.params.appName); - var uid = req.users.id; - var collaborators = new Collaborators(); - accountManager.collaboratorCan(uid, appName) - .then((col) => { - return collaborators.listCollaborators(col.appid); - }) - .then((data) => { - rs = _.reduce(data, (result, value, key) => { - if (_.eq(key, req.users.email)) { - value.isCurrentAccount = true; - }else { - value.isCurrentAccount = false; - } - result[key] = value; - return result; - },{}); - res.send({collaborators: rs}); - }) - .catch((e) => { - if (e instanceof AppError.AppError) { - res.status(406).send(e.message); - } else { - next(e); - } - }); -}); - -router.post('/:appName/collaborators/:email', - middleware.checkToken, (req, res, next) => { - var appName = _.trim(req.params.appName); - var email = _.trim(req.params.email); - var uid = req.users.id; - if (!validator.isEmail(email)){ - return res.status(406).send("Invalid Email!"); - } - var collaborators = new Collaborators(); - accountManager.ownerCan(uid, appName) - .then((col) => { - return accountManager.findUserByEmail(email) - .then((data) => { - return collaborators.addCollaborator(col.appid, data.id); - }); - }) - .then((data) => { - res.send(data); - }) - .catch((e) => { - if (e instanceof AppError.AppError) { - res.status(406).send(e.message); - } else { - next(e); - } - }); -}); - -router.delete('/:appName/collaborators/:email', - middleware.checkToken, (req, res, next) => { - var appName = _.trim(req.params.appName); - var email = _.trim(decodeURI(req.params.email)); - var uid = req.users.id; - if (!validator.isEmail(email)){ - return res.status(406).send("Invalid Email!"); - } - var collaborators = new Collaborators(); - accountManager.ownerCan(uid, appName) - .then((col) => { - return accountManager.findUserByEmail(email) - .then((data) => { - if (_.eq(data.id, uid)) { - throw new AppError.AppError("can't delete yourself!"); - } else { - return collaborators.deleteCollaborator(col.appid, data.id); - } - }); - }) - .then(() => { - res.send(""); - }) - .catch((e) => { - if (e instanceof AppError.AppError) { - res.status(406).send(e.message); - } else { - next(e); - } - }); -}); - -router.delete('/:appName', - middleware.checkToken, (req, res, next) => { - var appName = _.trim(req.params.appName); - var uid = req.users.id; - var appManager = new AppManager(); - accountManager.ownerCan(uid, appName) - .then((col) => { - return appManager.deleteApp(col.appid); - }) - .then((data) => { - res.send(data); - }) - .catch((e) => { - if (e instanceof AppError.AppError) { - res.status(406).send(e.message); - } else { - next(e); - } - }); -}); - -router.patch('/:appName', - middleware.checkToken, (req, res, next) => { - var newAppName = _.trim(req.body.name); - var appName = _.trim(req.params.appName); - var uid = req.users.id; - if (_.isEmpty(newAppName)) { - return res.status(406).send("Please input name!"); - } else { - var appManager = new AppManager(); - return accountManager.ownerCan(uid, appName) - .then((col) => { - return appManager.findAppByName(uid, newAppName) - .then((appInfo) => { - if (!_.isEmpty(appInfo)){ - throw new AppError.AppError(newAppName + " Exist!"); - } - return appManager.modifyApp(col.appid, {name: newAppName}); - }); - }) - .then(() => { - res.send(""); - }) - .catch((e) => { - if (e instanceof AppError.AppError) { - res.status(406).send(e.message); - } else { - next(e); - } - }); - } -}); - -router.post('/:appName/transfer/:email', - middleware.checkToken, (req, res, next) => { - var appName = _.trim(req.params.appName); - var email = _.trim(req.params.email); - var uid = req.users.id; - if (!validator.isEmail(email)){ - return res.status(406).send("Invalid Email!"); - } - return accountManager.ownerCan(uid, appName) - .then((col) => { - return accountManager.findUserByEmail(email) - .then((data) => { - if (_.eq(data.id, uid)) { - throw new AppError.AppError("You can't transfer to yourself!"); - } - var appManager = new AppManager(); - return appManager.transferApp(col.appid, uid, data.id); - }); - }) - .then((data) => { - res.send(data); - }) - .catch((e) => { - if (e instanceof AppError.AppError) { - res.status(406).send(e.message); - } else { - next(e); - } - }); -}); - -router.post('/', middleware.checkToken, (req, res, next) => { - log.debug("addApp params:",req.body); - var constName = require('../core/const'); - var appName = req.body.name; - if (_.isEmpty(appName)) { - return res.status(406).send("Please input name!"); - } - var osName = _.toLower(req.body.os); - var os; - if (osName == _.toLower(constName.IOS_NAME)) { - os = constName.IOS; - } else if (osName == _.toLower(constName.ANDROID_NAME)) { - os = constName.ANDROID; - } else if (osName == _.toLower(constName.WINDOWS_NAME)) { - os = constName.WINDOWS; - } else { - return res.status(406).send("Please input os [iOS|Android|Windows]!"); - } - var platformName = _.toLower(req.body.platform); - var platform; - if (platformName == _.toLower(constName.REACT_NATIVE_NAME)) { - platform = constName.REACT_NATIVE; - } else if (platformName == _.toLower(constName.CORDOVA_NAME)) { - platform = constName.CORDOVA; - } else { - return res.status(406).send("Please input platform [React-Native|Cordova]!"); - } - var manuallyProvisionDeployments = req.body.manuallyProvisionDeployments; - var uid = req.users.id; - var appManager = new AppManager(); - - appManager.findAppByName(uid, appName) - .then((appInfo) => { - if (!_.isEmpty(appInfo)){ - throw new AppError.AppError(appName + " Exist!"); - } - return appManager.addApp(uid, appName, os, platform, req.users.identical) - .then(() => { - return {name: appName, collaborators: {[req.users.email]: {permission: "Owner"}}}; - }); - }) - .then((data) => { - res.send({app: data}); - }) - .catch((e) => { - if (e instanceof AppError.AppError) { - res.status(406).send(e.message); - } else { - next(e); - } - }); -}); - -module.exports = router; diff --git a/routes/auth.js b/routes/auth.js deleted file mode 100644 index 7bdd96c2..00000000 --- a/routes/auth.js +++ /dev/null @@ -1,69 +0,0 @@ -var express = require('express'); -var router = express.Router(); -var _ = require('lodash'); -var config = require('../core/config'); -var validator = require('validator'); -var log4js = require('log4js'); -var log = log4js.getLogger("cps:auth"); - -router.get('/password', (req, res) => { - res.render('auth/password', { title: 'CodePushServer' }); -}); - -router.get('/login', (req, res) => { - var codePushWebUrl = _.get(config, 'common.codePushWebUrl'); - if (codePushWebUrl && validator.isURL(codePushWebUrl)) { - log.debug(`login redirect:${codePushWebUrl}`); - res.redirect(`${codePushWebUrl}/login`); - } else { - res.render('auth/login', { title: 'CodePushServer' }); - } -}); - -router.get('/link', (req, res) => { - res.redirect(`/auth/login`); -}); - -router.get('/register', (req, res) => { - var codePushWebUrl = _.get(config, 'common.codePushWebUrl'); - var isRedirect = false; - if (codePushWebUrl && validator.isURL(codePushWebUrl)) { - log.debug(`register redirect:${codePushWebUrl}`); - res.redirect(`${codePushWebUrl}/register`); - } else { - res.render('auth/login', { title: 'CodePushServer' }); - } -}); - -router.post('/logout', (req, res) => { - res.send("ok"); -}); - -router.post('/login', (req, res, next) => { - var AppError = require('../core/app-error'); - var accountManager = require('../core/services/account-manager')(); - var security = require('../core/utils/security'); - var account = _.trim(req.body.account); - var password = _.trim(req.body.password); - var tokenSecret = _.get(config, 'jwt.tokenSecret'); - log.debug(`login:${account}`); - accountManager.login(account, password) - .then((users) => { - var jwt = require('jsonwebtoken'); - return jwt.sign({ uid: users.id, hash: security.md5(users.ack_code), expiredIn: 7200 }, tokenSecret); - }) - .then((token) => { - log.debug(token); - res.send({status:'OK', results: {tokens: token}}); - }) - .catch((e) => { - if (e instanceof AppError.AppError) { - log.debug(e); - res.send({status:'ERROR', errorMessage: e.message}); - } else { - next(e); - } - }); -}); - -module.exports = router; diff --git a/routes/index.js b/routes/index.js deleted file mode 100644 index d070b551..00000000 --- a/routes/index.js +++ /dev/null @@ -1,107 +0,0 @@ -var express = require('express'); -var router = express.Router(); -var Promise = require('bluebird'); -var AppError = require('../core/app-error'); -var middleware = require('../core/middleware'); -var ClientManager = require('../core/services/client-manager'); -var _ = require('lodash'); -var log4js = require('log4js'); -var log = log4js.getLogger("cps:index"); - -router.get('/', (req, res, next) => { - res.render('index', { title: 'CodePushServer' }); -}); - -router.get('/README.md', (req, res, next) => { - var MarkdownIt = require('markdown-it'); - const path = require('path'); - const fs = require('fs'); - const readFile = Promise.promisify(fs.readFile); - const README = path.join(__dirname, '../README.md'); - readFile(README, { encoding: 'utf8' }) - .then(source => { - var md = new MarkdownIt(); - res.send(md.render(source)); - }) - .catch(e=>{ - if (e instanceof AppError.AppError) { - res.send(e.message); - } else { - next(e); - } - }); -}); - -router.get('/tokens', (req, res) => { - res.render('tokens', { title: '获取token' }); -}); - -router.get('/updateCheck', (req, res, next) => { - var deploymentKey = _.get(req, "query.deploymentKey"); - var appVersion = _.get(req, "query.appVersion"); - var label = _.get(req, "query.label"); - var packageHash = _.get(req, "query.packageHash") - var clientUniqueId = _.get(req, "query.clientUniqueId") - var clientManager = new ClientManager(); - log.debug('req.query', req.query); - clientManager.updateCheckFromCache(deploymentKey, appVersion, label, packageHash, clientUniqueId) - .then((rs) => { - //灰度检测 - return clientManager.chosenMan(rs.packageId, rs.rollout, clientUniqueId) - .then((data)=>{ - if (!data) { - rs.isAvailable = false; - return rs; - } - return rs; - }); - }) - .then((rs) => { - delete rs.packageId; - delete rs.rollout; - res.send({"updateInfo":rs}); - }) - .catch((e) => { - if (e instanceof AppError.AppError) { - res.status(404).send(e.message); - } else { - next(e); - } - }); -}); - -router.post('/reportStatus/download', (req, res) => { - log.debug('req.body', req.body); - var clientUniqueId = _.get(req, "body.clientUniqueId"); - var label = _.get(req, "body.label"); - var deploymentKey = _.get(req, "body.deploymentKey"); - var clientManager = new ClientManager(); - clientManager.reportStatusDownload(deploymentKey, label, clientUniqueId) - .catch((err) => { - if (!err instanceof AppError.AppError) { - console.error(err.stack) - } - }); - res.send('OK'); -}); - -router.post('/reportStatus/deploy', (req, res) => { - log.debug('req.body', req.body); - var clientUniqueId = _.get(req, "body.clientUniqueId"); - var label = _.get(req, "body.label"); - var deploymentKey = _.get(req, "body.deploymentKey"); - var clientManager = new ClientManager(); - clientManager.reportStatusDeploy(deploymentKey, label, clientUniqueId, req.body) - .catch((err) => { - if (!err instanceof AppError.AppError) { - console.error(err.stack) - } - }); - res.send('OK'); -}); - -router.get('/authenticated', middleware.checkToken, (req, res) => { - return res.send({authenticated: true}); -}) - -module.exports = router; diff --git a/routes/indexV1.js b/routes/indexV1.js deleted file mode 100644 index 1720f1a8..00000000 --- a/routes/indexV1.js +++ /dev/null @@ -1,89 +0,0 @@ -var express = require('express'); -var router = express.Router(); -var Promise = require('bluebird'); -var AppError = require('../core/app-error'); -var middleware = require('../core/middleware'); -var ClientManager = require('../core/services/client-manager'); -var _ = require('lodash'); -var log4js = require('log4js'); -var log = log4js.getLogger("cps:indexV1"); - -router.get('/update_check', (req, res, next) => { - var deploymentKey = _.get(req, "query.deployment_key"); - var appVersion = _.get(req, "query.app_version"); - var label = _.get(req, "query.label"); - var packageHash = _.get(req, "query.package_hash") - var isCompanion = _.get(req, "query.is_companion") - var clientUniqueId = _.get(req, "query.client_unique_id") - var clientManager = new ClientManager(); - log.debug('req.query', req.query); - clientManager.updateCheckFromCache(deploymentKey, appVersion, label, packageHash, clientUniqueId) - .then((rs) => { - //灰度检测 - return clientManager.chosenMan(rs.packageId, rs.rollout, clientUniqueId) - .then((data)=>{ - if (!data) { - rs.isAvailable = false; - return rs; - } - return rs; - }); - }) - .then((rs) => { - delete rs.packageId; - delete rs.rollout; - var update_info = { - download_url : rs.downloadUrl, - description : rs.description, - is_available : rs.isAvailable, - is_disabled : rs.isDisabled, - target_binary_range: rs.targetBinaryRange, - label: rs.label, - package_hash: rs.packageHash, - package_size: rs.packageSize, - should_run_binary_version: rs.shouldRunBinaryVersion, - update_app_version: rs.updateAppVersion, - is_mandatory: rs.isMandatory, - }; - res.send({"update_info": update_info}); - }) - .catch((e) => { - if (e instanceof AppError.AppError) { - res.status(404).send(e.message); - } else { - next(e); - } - }); -}); - -router.post('/report_status/download', (req, res) => { - log.debug('req.body', req.body); - var clientUniqueId = _.get(req, "body.client_unique_id"); - var label = _.get(req, "body.label"); - var deploymentKey = _.get(req, "body.deployment_key"); - var clientManager = new ClientManager(); - clientManager.reportStatusDownload(deploymentKey, label, clientUniqueId) - .catch((err) => { - if (!err instanceof AppError.AppError) { - console.error(err.stack) - } - }); - res.send('OK'); -}); - -router.post('/report_status/deploy', (req, res) => { - log.debug('req.body', req.body); - var clientUniqueId = _.get(req, "body.client_unique_id"); - var label = _.get(req, "body.label"); - var deploymentKey = _.get(req, "body.deployment_key"); - var clientManager = new ClientManager(); - clientManager.reportStatusDeploy(deploymentKey, label, clientUniqueId, req.body) - .catch((err) => { - if (!err instanceof AppError.AppError) { - console.error(err.stack) - } - }); - res.send('OK'); -}); - -module.exports = router; diff --git a/routes/users.js b/routes/users.js deleted file mode 100644 index c4664f3f..00000000 --- a/routes/users.js +++ /dev/null @@ -1,108 +0,0 @@ -var express = require('express'); -var router = express.Router(); -var Promise = require('bluebird'); -var _ = require('lodash'); -var models = require('../models'); -var middleware = require('../core/middleware'); -var AccountManager = require('../core/services/account-manager'); -var AppError = require('../core/app-error') - -router.get('/', middleware.checkToken, (req, res) => { - res.send({ title: 'CodePushServer' }); -}); - -router.post('/', (req, res, next) => { - var email = _.trim(_.get(req, 'body.email')); - var token = _.trim(_.get(req, 'body.token')); - var password = _.trim(_.get(req, 'body.password')); - var accountManager = new AccountManager(); - return accountManager.checkRegisterCode(email, token) - .then((u) => { - if (_.isString(password) && password.length < 6) { - throw new AppError.AppError('请您输入6~20位长度的密码'); - } - return accountManager.register(email, password); - }) - .then(() => { - res.send({status: "OK"}); - }) - .catch((e) => { - if (e instanceof AppError.AppError) { - res.send({status: "ERROR", message: e.message}); - } else { - next(e); - } - }); -}); - -router.get('/exists', (req, res, next) => { - var email = _.trim(_.get(req, 'query.email')); - models.Users.findOne({where: {email: email}}) - .then((u) => { - if (!email) { - throw new AppError.AppError(`请您输入邮箱地址`); - } - res.send({status: "OK", exists: u ? true : false}); - }) - .catch((e) => { - if (e instanceof AppError.AppError) { - res.send({status: "ERROR", message: e.message}); - } else { - next(e); - } - }); -}); - -router.post('/registerCode', (req, res, next) => { - var email = _.get(req, 'body.email'); - var accountManager = new AccountManager(); - return accountManager.sendRegisterCode(email) - .then(() => { - res.send({status: "OK"}); - }) - .catch((e) => { - if (e instanceof AppError.AppError) { - res.send({status: "ERROR", message: e.message}); - } else { - next(e); - } - }); -}); - -router.get('/registerCode/exists', (req, res, next) => { - var email = _.trim(_.get(req, 'query.email')); - var token = _.trim(_.get(req, 'query.token')); - var accountManager = new AccountManager(); - return accountManager.checkRegisterCode(email, token) - .then(() => { - res.send({status: "OK"}); - }) - .catch((e) => { - if (e instanceof AppError.AppError) { - res.send({status: "ERROR", message: e.message}); - } else { - next(e); - } - }); -}); - -//修改密码 -router.patch('/password', middleware.checkToken, (req, res, next) => { - var oldPassword = _.trim(_.get(req, 'body.oldPassword')); - var newPassword = _.trim(_.get(req, 'body.newPassword')); - var uid = req.users.id; - var accountManager = new AccountManager(); - return accountManager.changePassword(uid, oldPassword, newPassword) - .then(() => { - res.send({status: "OK"}); - }) - .catch((e) => { - if (e instanceof AppError.AppError) { - res.send({status: "ERROR", message: e.message}); - } else { - next(e); - } - }); -}); - -module.exports = router; diff --git a/docker/sql/codepush-all.sql b/sql/codepush-all-docker.sql similarity index 98% rename from docker/sql/codepush-all.sql rename to sql/codepush-all-docker.sql index 7bf4047d..9981a26a 100644 --- a/docker/sql/codepush-all.sql +++ b/sql/codepush-all-docker.sql @@ -1,7 +1,7 @@ CREATE DATABASE IF NOT EXISTS `codepush`; -GRANT SELECT,UPDATE,INSERT ON `codepush`.* TO 'codepush'@'%' IDENTIFIED BY '123456' WITH GRANT OPTION; - +CREATE USER IF NOT EXISTS 'codepush'@'%' IDENTIFIED BY '123456'; +GRANT SELECT,UPDATE,INSERT ON `codepush`.* TO 'codepush'@'%'; flush privileges; use `codepush`; diff --git a/src/app.ts b/src/app.ts new file mode 100644 index 00000000..22a76101 --- /dev/null +++ b/src/app.ts @@ -0,0 +1,119 @@ +import fs from 'fs'; +import path from 'path'; +import bodyParser from 'body-parser'; +import cookieParser from 'cookie-parser'; +import express, { NextFunction } from 'express'; +import helmet from 'helmet'; +import { logger } from 'kv-logger'; +import { AppError, NotFound } from './core/app-error'; +import { config } from './core/config'; +import { i18n } from './core/i18n'; +import { + i18nMiddleware, + ipWhitelistOnly, + Req, + Res, + webUiGuard, + withLogger, +} from './core/middleware'; +import { accessKeysRouter } from './routes/accessKeys'; +import { accountRouter } from './routes/account'; +import { appsRouter } from './routes/apps'; +import { authRouter } from './routes/auth'; +import { indexRouter } from './routes/index'; +import { indexV1Router } from './routes/indexV1'; +import { usersRouter } from './routes/users'; + +export const app = express(); + +app.use( + helmet({ + contentSecurityPolicy: false, + }), +); + +// view engine setup +app.set('views', path.join(__dirname, '../views')); +app.set('view engine', 'pug'); + +// translations +app.use(i18n.init); + +app.use(bodyParser.json()); +app.use(bodyParser.urlencoded({ extended: false })); +app.use(cookieParser()); +app.use(express.static(path.join(__dirname, '../public'))); +app.use(withLogger); + +app.all('*', (req, res, next) => { + res.header('Access-Control-Allow-Origin', '*'); + res.header( + 'Access-Control-Allow-Headers', + 'Origin, X-Requested-With, Content-Type, Accept, Authorization, X-CodePush-Plugin-Version, X-CodePush-Plugin-Name, X-CodePush-SDK-Version, X-Request-Id', + ); + res.header('Access-Control-Allow-Methods', 'PUT,POST,GET,PATCH,DELETE,OPTIONS'); + next(); +}); + +// i18n 미들웨어 (req.lang, req.t 세팅) +app.use(i18nMiddleware); + +logger.debug(`config common.storageType value: ${config.common.storageType}`); + +// config local storage +if (config.common.storageType === 'local') { + const localStorageDir = config.local.storageDir; + if (localStorageDir) { + logger.debug(`config common.storageDir value: ${localStorageDir}`); + + if (!fs.existsSync(localStorageDir)) { + const e = new Error(`Please create dir ${localStorageDir}`); + logger.error(e); + throw e; + } + try { + logger.debug('checking storageDir fs.W_OK | fs.R_OK'); + // eslint-disable-next-line no-bitwise + fs.accessSync(localStorageDir, fs.constants.W_OK | fs.constants.R_OK); + logger.debug('storageDir fs.W_OK | fs.R_OK is ok'); + } catch (e) { + logger.error(e); + throw e; + } + logger.debug(`static download uri value: ${config.local.public}`); + app.use(config.local.public, express.static(localStorageDir)); + } else { + logger.error('please config local storageDir'); + } +} + +// config routes +// code-push-client routes +app.use('/', indexRouter); +app.use('/v0.1/public/codepush', indexV1Router); +// code-push-cli routes +app.use('/accessKeys', accessKeysRouter); +app.use('/apps', appsRouter); +app.use('/account', accountRouter); +// code-push-server routes +app.use('/auth', [ipWhitelistOnly, webUiGuard], authRouter); +app.use('/users', [ipWhitelistOnly, webUiGuard], usersRouter); + +// 404 handler +// eslint-disable-next-line @typescript-eslint/no-unused-vars +app.use((req, res, next) => { + throw new NotFound(`${req.method} ${req.url} not found`); +}); + +// error handler +// eslint-disable-next-line @typescript-eslint/no-unused-vars +app.use((err: Error, req: Req, res: Res, next: NextFunction) => { + const thisLogger = req.logger || logger; + if (err instanceof AppError) { + res.status(err.status).send(err.message); + thisLogger.debug(err); + } else { + res.status(500).send(err.message); + thisLogger.error(err); + } +}); diff --git a/src/core/app-error.ts b/src/core/app-error.ts new file mode 100644 index 00000000..c52b4b34 --- /dev/null +++ b/src/core/app-error.ts @@ -0,0 +1,44 @@ +/* eslint-disable max-classes-per-file */ +export class AppError extends Error { + constructor(message: string | Error) { + super(message instanceof Error ? message.message : message); + this.name = 'AppError'; + } + + public status = 200; +} + +/** i18n 에러 메시지 번역 포함 */ +export class AppErrorI18n extends Error { + public readonly messageKey: string; + public readonly messageVars?: Record; + + constructor(messageKey: string, messageVars?: Record) { + // Error.message에는 일단 key만 넣어둠 (실제 표현은 나중에 req.t로 처리) + super(messageKey); + + this.messageKey = messageKey; + this.messageVars = messageVars; + + Object.setPrototypeOf(this, new.target.prototype); // Error 상속시 필수 처리 + this.name = 'AppErrorI18n'; + } +} + +export class NotFound extends AppError { + constructor(message?: string | Error) { + super(message || 'Not Found'); + this.name = 'NotFoundError'; + } + + public status = 404; +} + +export class Unauthorized extends AppError { + constructor(message?: string | Error) { + super(message || 'Unauthorized'); + this.name = 'UnauthorizedError'; + } + + public status = 401; +} diff --git a/src/core/config.ts b/src/core/config.ts new file mode 100644 index 00000000..fd84a4b3 --- /dev/null +++ b/src/core/config.ts @@ -0,0 +1,174 @@ +import os from 'os'; +import { + setLogTransports, + ConsoleLogTransport, + logger, + LogLevel, + withLogLevelFilter, +} from 'kv-logger'; + +const env = process.env.NODE_ENV || 'development'; + +function toBool(str: string): boolean { + return str === 'true' || str === '1'; +} + +function toNumber(str: string, defaultValue: number): number { + const num = Number(str); + if (Number.isNaN(num)) { + return defaultValue; + } + return num; +} + +export const config = { + // Config for log + log: { + // debug, info, warn, error + level: process.env.LOG_LEVEL || 'info', + // text, json + format: process.env.LOG_FORMAT || 'text', + }, + // Config for database, only support mysql. + db: { + username: process.env.RDS_USERNAME || 'codepush', + password: process.env.RDS_PASSWORD || 'codepush', + database: process.env.RDS_DATABASE || 'codepush', + host: process.env.RDS_HOST || '127.0.0.1', + port: toNumber(process.env.RDS_PORT, 3306), + dialect: 'mysql', + logging: false, + dialectOptions: toBool(process.env.DB_SSL_REQUIRED) + ? { + ssl: { + require: false, + // 관리형 MySQL에서 self-signed 또는 CA 정보 안 주는 경우가 많아서, 일단 빠르게 붙는 용도로 false. 추후 CA 넣어서 true로 바꾸는 게 베스트. + rejectUnauthorized: toBool(process.env.DB_SSL_REJECT_UNAUTHORIZED) ?? false, + }, + } + : {}, + }, + // Config for qiniu (http://www.qiniu.com/) cloud storage when storageType value is "qiniu". + qiniu: { + accessKey: process.env.QINIU_ACCESS_KEY, + secretKey: process.env.QINIU_SECRET_KEY, + bucketName: process.env.QINIU_BUCKET_NAME, + downloadUrl: process.env.QINIU_DOWNLOAD_URL || process.env.DOWNLOAD_URL, + }, + // Config for Amazon s3 (https://aws.amazon.com/cn/s3/) storage when storageType value is "s3". + s3: { + accessKeyId: process.env.AWS_ACCESS_KEY_ID, + secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY, + sessionToken: process.env.AWS_SESSION_TOKEN, // (optional) + bucketName: process.env.AWS_BUCKET_NAME, + region: process.env.AWS_REGION, + // binary files download host address. + downloadUrl: process.env.AWS_DOWNLOAD_URL || process.env.DOWNLOAD_URL, + prefix: process.env.AWS_S3_KEY_PREFIX, // (optional) + }, + // Config for Aliyun OSS (https://www.aliyun.com/product/oss) when storageType value is "oss". + oss: { + accessKeyId: process.env.OSS_ACCESS_KEY_ID, + secretAccessKey: process.env.OSS_SECRET_ACCESS_KEY, + endpoint: process.env.OSS_ENDPOINT, + bucketName: process.env.OSS_BUCKET_NAME, + // Key prefix in object key + prefix: process.env.OSS_PREFIX, + // binary files download host address + downloadUrl: process.env.OSS_DOWNLOAD_URL || process.env.DOWNLOAD_URL, + }, + // Config for tencentyun COS (https://cloud.tencent.com/product/cos) when storageType value is "oss". + tencentcloud: { + accessKeyId: process.env.COS_ACCESS_KEY_ID, + secretAccessKey: process.env.COS_SECRET_ACCESS_KEY, + bucketName: process.env.COS_BUCKET_NAME, + region: process.env.COS_REGION, + // binary files download host address + downloadUrl: process.env.COS_DOWNLOAD_URL || process.env.DOWNLOAD_URL, + }, + // Config for local storage when storageType value is "local". + local: { + // Binary files storage dir, Do not use tmpdir and it's public download dir. + storageDir: process.env.STORAGE_DIR || os.tmpdir(), + // Binary files download host address which Code Push Server listen to. the files storage in storageDir. + downloadUrl: + process.env.LOCAL_DOWNLOAD_URL || + process.env.DOWNLOAD_URL || + 'http://172.30.1.85:3000/download', + // public static download spacename. + public: '/download', + }, + jwt: { + // Recommended: 63 random alpha-numeric characters + // Generate using: https://www.grc.com/passwords.htm + tokenSecret: process.env.TOKEN_SECRET || 'INSERT_RANDOM_TOKEN_KEY', + }, + common: { + // determine whether new account registrations are allowed + allowRegistration: toBool(process.env.ALLOW_REGISTRATION), + /* + * tryLoginTimes is control login error times to avoid force attack. + * if value is 0, no limit for login auth, it may not safe for account. when it's a number, it means you can + * try that times today. but it need config redis server. + */ + tryLoginTimes: toNumber(process.env.TRY_LOGIN_TIMES, 4), + // create patch updates's number. default value is 3 + diffNums: toNumber(process.env.DIFF_NUMS, 3), + // data dir for caclulate diff files. it's optimization. + dataDir: process.env.DATA_DIR || os.tmpdir(), + // storageType which is your binary package files store. options value is ("local" | "qiniu" | "s3"| "oss" || "tencentcloud") + storageType: (process.env.STORAGE_TYPE || 'local') as + | 'local' + | 'qiniu' + | 's3' + | 'oss' + | 'tencentcloud', + // options value is (true | false), when it's true, it will cache updateCheck results in redis. + updateCheckCache: toBool(process.env.UPDATE_CHECK_CACHE), + // options value is (true | false), when it's true, it will cache rollout results in redis + rolloutClientUniqueIdCache: toBool(process.env.ROLLOUT_CLIENT_UNIQUE_ID_CACHE), + // NODE_ENV value. This determines the current running environment (e.g., development, staging, production). + env, + /** + * whitelist for allowing access to the web UI. + * When in production or when registration is disabled, only IPs listed here will be allowed to access the web UI. + * The value should be a comma-separated list of IP addresses, e.g., "127.0.0.1,10.0.0.1". + */ + webUIWhitelist: (process.env.WEB_UI_WHITELIST || '') + .split(',') + .map((ip) => ip.trim()) + .filter(Boolean), + // options value is (true | false), when it's true, web UI routes are enabled (still restricted by IP whitelist if configured) + webUIAllow: toBool(process.env.WEB_UI_ALLOW), + }, + // Config for smtp email, register module need validate user email project source https://github.com/nodemailer/nodemailer + smtpConfig: { + host: process.env.SMTP_HOST, + port: toNumber(process.env.SMTP_PORT, 465), + secure: true, + auth: { + user: process.env.SMTP_USERNAME, + pass: process.env.SMTP_PASSWORD, + }, + }, + // Config for redis (register module, tryLoginTimes module) + redis: { + host: process.env.REDIS_HOST || '127.0.0.1', + port: toNumber(process.env.REDIS_PORT, 6379), + password: process.env.REDIS_PASSWORD, + db: toNumber(process.env.REDIS_DB, 0), + tlsUrl: process.env.REDIS_TLS_URL || process.env.REDIS_URL, + }, +} as const; + +// config logger - make sure its ready before anyting else +setLogTransports( + withLogLevelFilter(config.log.level as LogLevel)( + new ConsoleLogTransport(config.log.format as 'text' | 'json'), + ), +); + +logger.info(`use config`, { + env, + storageType: config.common.storageType, +}); diff --git a/src/core/const.ts b/src/core/const.ts new file mode 100644 index 00000000..916104b9 --- /dev/null +++ b/src/core/const.ts @@ -0,0 +1,35 @@ +// supported platforms +// TODO: refactor to enums and put name mapping into util method +export const IOS = 1; +export const IOS_NAME = 'iOS'; +export const ANDROID = 2; +export const ANDROID_NAME = 'Android'; +export const WINDOWS = 3; +export const WINDOWS_NAME = 'Windows'; + +// supported apps +export const REACT_NATIVE = 1; +export const REACT_NATIVE_NAME = 'React-Native'; +export const CORDOVA = 2; +export const CORDOVA_NAME = 'Cordova'; + +// supported env +export const PRODUCTION = 'Production'; +export const STAGING = 'Staging'; + +// flags +export const IS_MANDATORY_YES = 1; +export const IS_MANDATORY_NO = 0; + +export const IS_DISABLED_YES = 1; +export const IS_DISABLED_NO = 0; + +export const DEPLOYMENT_SUCCEEDED = 1; +export const DEPLOYMENT_FAILED = 2; + +export const RELEASE_METHOD_PROMOTE = 'Promote'; +export const RELEASE_METHOD_UPLOAD = 'Upload'; + +export const DIFF_MANIFEST_FILE_NAME = 'hotcodepush.json'; + +export const CURRENT_DB_VERSION = '0.5.0'; diff --git a/src/core/i18n.ts b/src/core/i18n.ts new file mode 100644 index 00000000..82b432d6 --- /dev/null +++ b/src/core/i18n.ts @@ -0,0 +1,46 @@ +import path from 'path'; +import { I18n } from 'i18n'; + +import en from '../locales/en.json'; +import ko from '../locales/ko.json'; +import zh from '../locales/zh.json'; +import type { LocaleI18n } from './middleware'; + +const resources: Record> = { + en, + ko, + zh, +}; + +export const i18n = new I18n(); + +i18n.configure({ + directory: path.join(__dirname, '../locales'), + defaultLocale: 'en', +}); + +/** + * @description 모던 i18next 라이브러리의 t함수와 유사함 동작 보장 + * - 이 프로젝트의 i18n 의 번역함수 사용법 예시 + * - e.g., req.__("greeting") OR res.__("greeting") + * - 위 방법 외에 t("greeting") 호출로도 동일한 스트링 리턴 보장 + */ +export function t(locale: LocaleI18n, key: string, vars?: Record): string { + const dict = resources[locale] ?? resources.zh; + + // 키에 해당하는 문장 (없으면 key 자체 반환) + const template = dict[key] ?? key; + + // 변수 치환 없음 -> 그대로 반환 + if (!vars) { + return template; + } + + // Interpolation 처리: {{varName}} -> vars[varName] + return template.replace(/\{\{\s*(\w+)\s*\}\}/g, (_, varName) => { + if (vars[varName] == null) { + return ''; // 없는 변수를 치환하면 빈문자열 (i18next 기본 동작과 유사) + } + return String(vars[varName]); + }); +} diff --git a/src/core/middleware.ts b/src/core/middleware.ts new file mode 100644 index 00000000..294982cc --- /dev/null +++ b/src/core/middleware.ts @@ -0,0 +1,213 @@ +import { randomUUID } from 'crypto'; +import type { Request, Response, NextFunction } from 'express'; +import jwt from 'jsonwebtoken'; +import { logger, Logger } from 'kv-logger'; +import _ from 'lodash'; +import moment from 'moment'; +import { Op } from 'sequelize'; +import { UserTokens } from '../models/user_tokens'; +import { Users, UsersInterface } from '../models/users'; +import { AppError, Unauthorized } from './app-error'; +import { config } from './config'; +import { t } from './i18n'; +import { shouldHideWebUI } from './utils/common'; +import { parseToken, md5 } from './utils/security'; + +export type LocaleI18n = 'en' | 'ko' | 'zh'; + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +export interface Req

, B = any, Q = Record> + // eslint-disable-next-line @typescript-eslint/no-explicit-any + extends Request> { + users: UsersInterface; + logger: Logger; + lang?: LocaleI18n; + t?: (key: string, vars?: Record) => string; +} + +// eslint-disable-next-line @typescript-eslint/no-empty-interface, @typescript-eslint/no-explicit-any +export interface Res extends Response {} + +/** + * bind logger to request + */ +export function withLogger(req: Req, res: Res, next: NextFunction) { + const { method, path, headers } = req; + const requestId = headers['x-request-id'] || randomUUID(); + req.logger = logger.bindContext({ + path, + method, + requestId, + }); + res.header('X-Request-Id', requestId); + next(); +} + +async function checkAuthToken(authToken: string) { + const objToken = parseToken(authToken); + const users = await Users.findOne({ + where: { identical: objToken.identical }, + }); + if (_.isEmpty(users)) { + throw new Unauthorized(); + } + + const tokenInfo = await UserTokens.findOne({ + where: { + tokens: authToken, + uid: users.id, + expires_at: { + [Op.gt]: moment().format('YYYY-MM-DD HH:mm:ss'), + }, + }, + }); + if (_.isEmpty(tokenInfo)) { + throw new Unauthorized(); + } + + return users; +} + +async function checkAccessToken(accessToken: string) { + if (_.isEmpty(accessToken)) { + throw new Unauthorized(); + } + + let authData: { uid: number; hash: string }; + try { + authData = jwt.verify(accessToken, config.jwt.tokenSecret) as { + uid: number; + hash: string; + }; + } catch (e) { + throw new Unauthorized(); + } + + const { uid, hash } = authData; + if (uid <= 0) { + throw new Unauthorized(); + } + + const users = await Users.findOne({ + where: { id: uid }, + }); + if (_.isEmpty(users)) { + throw new Unauthorized(); + } + + if (hash !== md5(users.get('ack_code'))) { + throw new Unauthorized(); + } + return users; +} + +/** + * check user token and bind user to request + */ +export function checkToken(req: Req, res: Res, next: NextFunction) { + // get token and type + let authType: 1 | 2 = 1; + let authToken = ''; + const authArr = _.split(req.get('Authorization'), ' '); + if (authArr[0] === 'Bearer') { + [, authToken] = authArr; // Bearer + if (authToken && authToken.length > 64) { + authType = 2; + } else { + authType = 1; + } + } else if (authArr[0] === 'Basic') { + authType = 2; + const b = Buffer.from(authArr[1], 'base64'); + const user = _.split(b.toString(), ':'); + [, authToken] = user; + } + + // do check token + let checkTokenResult: Promise; + if (authToken && authType === 1) { + checkTokenResult = checkAuthToken(authToken); + } else if (authToken && authType === 2) { + checkTokenResult = checkAccessToken(authToken); + } else { + res.send(new Unauthorized(`Auth type not supported.`)); + return; + } + + checkTokenResult + .then((users) => { + req.users = users; + next(); + }) + .catch((e) => { + if (e instanceof AppError) { + res.status(e.status || 404).send(e.message); + } else { + next(e); + } + }); +} + +function getLocaleFromReq(req: Req): LocaleI18n { + const langHeader = (req.headers['x-lang'] || req.headers['accept-language'] || '').toString(); + + if (langHeader.startsWith('ko')) { + return 'ko'; + } + return 'en'; +} + +export function i18nMiddleware(req: Req, res: Res, next: NextFunction) { + const locale = getLocaleFromReq(req); + + req.lang = locale; + req.t = (key: string, vars?: Record) => t(locale, key, vars); + + next(); +} + +export function webUiGuard(req: Req, res: Response, next: NextFunction) { + if (!shouldHideWebUI()) { + return next(); + } + + req.logger?.info?.('blocked web UI access', { + path: req.path, + method: req.method, + }); + + return res.status(405).send('Method Not Allowed'); +} + +export function ipWhitelistOnly(req: Req, res: Response, next: NextFunction) { + const whitelist = config.common.webUIWhitelist || []; + + if (!Array.isArray(whitelist) || whitelist.length === 0) { + return next(); + } + + const defaultIp = req.ip; + const forwardedFor = req.headers['x-forwarded-for']; + + const realIp = Array.isArray(forwardedFor) + ? forwardedFor[0] + : forwardedFor?.split(',')[0]?.trim() || defaultIp; + + const isAllowed = whitelist.includes(realIp); + + if (!isAllowed) { + req.logger?.info?.('IP whitelist blocked', { + requestIp: realIp, + path: req.path, + }); + + return res.status(403).send('Forbidden'); + } + + req.logger?.info?.('IP whitelist allowed', { + requestIp: realIp, + path: req.path, + }); + + return next(); +} diff --git a/src/core/services/account-manager.ts b/src/core/services/account-manager.ts new file mode 100644 index 00000000..20f3523a --- /dev/null +++ b/src/core/services/account-manager.ts @@ -0,0 +1,247 @@ +import { Logger } from 'kv-logger'; +import _ from 'lodash'; +import moment from 'moment'; +import validator from 'validator'; +import { findCollaboratorsByAppNameAndUid } from '../../models/collaborators'; +import { UserTokens } from '../../models/user_tokens'; +import { Users } from '../../models/users'; +import { AppError, AppErrorI18n } from '../app-error'; +import { config } from '../config'; +import { redisClient } from '../utils/connections'; +import { passwordVerifySync, randToken, md5, passwordHashSync } from '../utils/security'; +import { emailManager } from './email-manager'; + +const LOGIN_LIMIT_PRE = 'LOGIN_LIMIT_PRE_'; +const REGISTER_CODE = 'REGISTER_CODE_'; +const EXPIRED = 1200; +const EXPIRED_SPEED = 10; + +class AccountManager { + collaboratorCan(uid: number, appName: string, logger: Logger) { + return this.getCollaborator(uid, appName).then((data) => { + if (!data) { + logger.debug(`collaboratorCan App ${appName} not exists.`); + throw new AppError(`App ${appName} not exists.`); + } + return data; + }); + } + + ownerCan(uid: number, appName: string, logger: Logger) { + return this.getCollaborator(uid, appName).then((data) => { + if (!data) { + logger.debug(`ownerCan App ${appName} not exists.`); + throw new AppError(`App ${appName} not exists.`); + } + if (!_.eq(_.get(data, 'roles'), 'Owner')) { + logger.debug(`ownerCan Permission Deny, You are not owner!`); + throw new AppError('Permission Deny, You are not owner!'); + } + return data; + }); + } + + findUserByEmail(email: string) { + return Users.findOne({ where: { email } }).then((data) => { + if (_.isEmpty(data)) { + throw new AppError(`${email} does not exist.`); + } else { + return data; + } + }); + } + + getAllAccessKeyByUid(uid: number) { + return UserTokens.findAll({ + where: { uid }, + order: [['id', 'DESC']], + }).then((tokens) => { + return _.map(tokens, (v) => { + return { + name: '(hidden)', + createdTime: moment(v.created_at).valueOf(), + createdBy: v.created_by, + expires: moment(v.expires_at).valueOf(), + friendlyName: v.name, + description: v.description, + }; + }); + }); + } + + isExistAccessKeyName(uid: number, friendlyName: string) { + return UserTokens.findOne({ + where: { uid, name: friendlyName }, + }); + } + + createAccessKey( + uid: number, + newAccessKey: string, + ttl: number, + friendlyName: string, + createdBy: string, + description: string, + ) { + return UserTokens.create({ + uid, + name: friendlyName, + tokens: newAccessKey, + description, + created_by: createdBy, + expires_at: moment() + .add(ttl / 1000, 'seconds') + .format('YYYY-MM-DD HH:mm:ss'), + created_at: moment().format('YYYY-MM-DD HH:mm:ss'), + }); + } + + login(account: string, password: string) { + if (_.isEmpty(account)) { + return Promise.reject(new AppErrorI18n('error.input_email_required')); + } + if (_.isEmpty(password)) { + return Promise.reject(new AppErrorI18n('error.input_password_required')); + } + let where = {}; + if (validator.isEmail(account)) { + where = { email: account }; + } else { + where = { username: account }; + } + const { tryLoginTimes } = config.common; + return Users.findOne({ where }) + .then((users) => { + if (_.isEmpty(users)) { + throw new AppErrorI18n('error.invalid_credentials'); + } + return users; + }) + .then((users) => { + if (tryLoginTimes > 0) { + const loginKey = `${LOGIN_LIMIT_PRE}${users.id}`; + return redisClient.get(loginKey).then((loginErrorTimes) => { + if (Number(loginErrorTimes) > tryLoginTimes) { + throw new AppErrorI18n('error.password_retry_limit_exceeded'); + } + return users; + }); + } + return users; + }) + .then((users) => { + if (!passwordVerifySync(password, users.password)) { + if (tryLoginTimes > 0) { + const loginKey = `${LOGIN_LIMIT_PRE}${users.id}`; + redisClient.exists(loginKey).then((isExists) => { + if (!isExists) { + const expires = moment().endOf('day').unix() - moment().unix(); + redisClient.setEx(loginKey, expires, '1'); + return; + } + redisClient.incr(loginKey); + }); + } + throw new AppErrorI18n('error.invalid_credentials'); + } else { + return users; + } + }); + } + + sendRegisterCode(email: string) { + if (_.isEmpty(email)) { + return Promise.reject(new AppErrorI18n('error.input_email_required')); + } + return Users.findOne({ where: { email } }) + .then((u) => { + if (u) { + throw new AppErrorI18n('error.email_already_registered', { email }); + } + }) + .then(() => { + // Store the token temporarily in Redis + const token = randToken(40); + return redisClient + .setEx(`${REGISTER_CODE}${md5(email)}`, EXPIRED, token) + .then(() => { + return token; + }); + }) + .then((token) => { + // Send the token to user's email + return emailManager.sendRegisterCodeMail(email, token); + }); + } + + checkRegisterCode(email: string, token: string) { + return Users.findOne({ where: { email } }) + .then((u) => { + if (u) { + throw new AppErrorI18n('error.email_already_registered', { email }); + } + }) + .then(() => { + const registerKey = `${REGISTER_CODE}${md5(email)}`; + return redisClient.get(registerKey).then((storageToken) => { + if (_.isEmpty(storageToken)) { + throw new AppErrorI18n('error.verify_code_expired'); + } + if (!_.eq(token, storageToken)) { + redisClient.ttl(registerKey).then((ttl) => { + if (ttl > 0) { + redisClient.expire(registerKey, ttl - EXPIRED_SPEED); + } + }); + throw new AppErrorI18n('error.verify_code_invalid'); + } + return storageToken; + }); + }); + } + + register(email: string, password: string) { + return Users.findOne({ where: { email } }) + .then((u) => { + if (u) { + throw new AppErrorI18n('error.email_already_registered', { email }); + } + }) + .then(() => { + const identical = randToken(9); + return Users.create({ + email, + password: passwordHashSync(password), + identical, + }); + }); + } + + changePassword(uid: number, oldPassword: string, newPassword: string) { + if (!_.isString(newPassword) || newPassword.length < 6) { + return Promise.reject(new AppErrorI18n('error.new_password_length')); + } + return Users.findOne({ where: { id: uid } }) + .then((u) => { + if (!u) { + throw new AppErrorI18n('error.user_not_found'); + } + return u; + }) + .then((u) => { + const isEq = passwordVerifySync(oldPassword, u.get('password')); + if (!isEq) { + throw new AppErrorI18n('error.old_password_incorrect'); + } + u.set('password', passwordHashSync(newPassword)); + u.set('ack_code', randToken(5)); + return u.save(); + }); + } + + private getCollaborator(uid: number, appName: string) { + return findCollaboratorsByAppNameAndUid(uid, appName); + } +} + +export const accountManager = new AccountManager(); diff --git a/src/core/services/app-manager.ts b/src/core/services/app-manager.ts new file mode 100644 index 00000000..b458c0e2 --- /dev/null +++ b/src/core/services/app-manager.ts @@ -0,0 +1,182 @@ +import _ from 'lodash'; +import { Op } from 'sequelize'; +import { Apps, AppsInterface } from '../../models/apps'; +import { Collaborators } from '../../models/collaborators'; +import { Deployments } from '../../models/deployments'; +import { Users } from '../../models/users'; +import { AppError } from '../app-error'; +import { + IOS, + IOS_NAME, + ANDROID, + ANDROID_NAME, + WINDOWS, + WINDOWS_NAME, + CORDOVA, + CORDOVA_NAME, + REACT_NATIVE, + REACT_NATIVE_NAME, + STAGING, + PRODUCTION, +} from '../const'; +import { sequelize } from '../utils/connections'; +import { randToken } from '../utils/security'; + +class AppManager { + findAppByName(uid: number, appName: string) { + return Apps.findOne({ where: { name: appName, uid } }); + } + + addApp(uid: number, appName: string, os, platform, identical: string) { + return sequelize.transaction((t) => { + return Apps.create( + { + name: appName, + uid, + os, + platform, + }, + { + transaction: t, + }, + ).then((apps) => { + const appId = apps.id; + const deployments = []; + let deploymentKey = randToken(28) + identical; + deployments.push({ + appid: appId, + name: PRODUCTION, + last_deployment_version_id: 0, + label_id: 0, + deployment_key: deploymentKey, + }); + deploymentKey = randToken(28) + identical; + deployments.push({ + appid: appId, + name: STAGING, + last_deployment_version_id: 0, + label_id: 0, + deployment_key: deploymentKey, + }); + return Promise.all([ + Collaborators.create({ appid: appId, uid, roles: 'Owner' }, { transaction: t }), + Deployments.bulkCreate(deployments, { transaction: t }), + ]); + }); + }); + } + + deleteApp(appId) { + return sequelize.transaction((t) => { + return Promise.all([ + Apps.destroy({ where: { id: appId }, transaction: t }), + Collaborators.destroy({ where: { appid: appId }, transaction: t }), + Deployments.destroy({ where: { appid: appId }, transaction: t }), + ]); + }); + } + + modifyApp(appId, params) { + return Apps.update(params, { where: { id: appId } }).then(([affectedCount]) => { + if (!_.gt(affectedCount, 0)) { + throw new AppError('modify errors'); + } + return affectedCount; + }); + } + + transferApp(appId: number, fromUid: number, toUid: number) { + return sequelize.transaction((t) => { + return Promise.all([ + Apps.update({ uid: toUid }, { where: { id: appId }, transaction: t }), + Collaborators.destroy({ where: { appid: appId, uid: fromUid }, transaction: t }), + Collaborators.destroy({ where: { appid: appId, uid: toUid }, transaction: t }), + Collaborators.create( + { appid: appId, uid: toUid, roles: 'Owner' }, + { transaction: t }, + ), + ]); + }); + } + + listApps(uid: number) { + return Collaborators.findAll({ where: { uid } }) + .then((data) => { + if (_.isEmpty(data)) { + return [] as AppsInterface[]; + } + const appIds = _.map(data, (v) => { + return v.appid; + }); + return Apps.findAll({ where: { id: { [Op.in]: appIds } } }); + }) + .then((appInfos) => { + const rs = Promise.all( + _.values(appInfos).map((v) => { + return this.getAppDetailInfo(v, uid).then((info) => { + let os = ''; + if (info.os === IOS) { + os = IOS_NAME; + } else if (info.os === ANDROID) { + os = ANDROID_NAME; + } else if (info.os === WINDOWS) { + os = WINDOWS_NAME; + } + + let platform = ''; + if (info.platform === REACT_NATIVE) { + platform = REACT_NATIVE_NAME; + } else if (info.platform === CORDOVA) { + platform = CORDOVA_NAME; + } + return { + ...info, + os, + platform, + }; + }); + }), + ); + return rs; + }); + } + + private getAppDetailInfo(appInfo: AppsInterface, currentUid: number) { + const appId = appInfo.get('id'); + return Promise.all([ + Deployments.findAll({ where: { appid: appId } }), + Collaborators.findAll({ where: { appid: appId } }).then((collaboratorInfos) => { + return collaboratorInfos.reduce((prev, collaborator) => { + return prev.then((allCol) => { + return Users.findOne({ where: { id: collaborator.get('uid') } }).then( + (u) => { + let isCurrentAccount = false; + if (_.eq(u.get('id'), currentUid)) { + isCurrentAccount = true; + } + allCol[u.get('email')] = { + permission: collaborator.get('roles'), + isCurrentAccount, + }; + return allCol; + }, + ); + }); + }, Promise.resolve({})); + }), + ]).then(([deploymentInfos, collaborators]) => { + return { + collaborators, + deployments: _.map(deploymentInfos, (item) => { + return _.get(item, 'name'); + }), + os: appInfo.get('os'), + platform: appInfo.get('platform'), + name: appInfo.get('name'), + id: appInfo.get('id'), + }; + }); + } +} + +export const appManager = new AppManager(); diff --git a/src/core/services/client-manager.ts b/src/core/services/client-manager.ts new file mode 100644 index 00000000..38cd62ee --- /dev/null +++ b/src/core/services/client-manager.ts @@ -0,0 +1,376 @@ +import { Logger } from 'kv-logger'; +import _ from 'lodash'; +import { Op } from 'sequelize'; +import { Deployments } from '../../models/deployments'; +import { DeploymentsVersions } from '../../models/deployments_versions'; +import { LogReportDeploy } from '../../models/log_report_deploy'; +import { LogReportDownload } from '../../models/log_report_download'; +import { Packages } from '../../models/packages'; +import { PackagesDiff } from '../../models/packages_diff'; +import { PackagesMetrics } from '../../models/packages_metrics'; +import { AppError } from '../app-error'; +import { config } from '../config'; +import { DEPLOYMENT_FAILED, DEPLOYMENT_SUCCEEDED } from '../const'; +import { parseVersion, getBlobDownloadUrl } from '../utils/common'; +import { redisClient } from '../utils/connections'; + +const UPDATE_CHECK = 'UPDATE_CHECK'; +const CHOSEN_MAN = 'CHOSEN_MAN'; +const EXPIRED = 600; + +interface UpdateCheckInfo { + packageId: number; + downloadURL: string; + downloadUrl: string; + description: string; + isAvailable: boolean; + isDisabled: boolean; + isMandatory: boolean; + appVersion: string; + targetBinaryRange: string; + packageHash: string; + label: string; + packageSize: number; + updateAppVersion: boolean; + shouldRunBinaryVersion: boolean; + rollout: number; +} + +class ClientManager { + private getUpdateCheckCacheKey(deploymentKey, appVersion, label, packageHash) { + return [UPDATE_CHECK, deploymentKey, appVersion, label, packageHash].join(':'); + } + + clearUpdateCheckCache(deploymentKey, appVersion, label, packageHash, logger: Logger) { + logger.info('clear cache Deployments key', { + key: deploymentKey, + }); + const redisCacheKey = this.getUpdateCheckCacheKey( + deploymentKey, + appVersion, + label, + packageHash, + ); + return redisClient.keys(redisCacheKey).then((data) => { + if (_.isArray(data)) { + return Promise.all( + data.map((key) => { + return redisClient.del(key); + }), + ); + } + return null; + }); + } + + updateCheckFromCache( + deploymentKey: string, + appVersion: string, + label: string, + packageHash: string, + clientUniqueId: string, + logger: Logger, + ) { + if (!config.common.updateCheckCache) { + return this.updateCheck( + deploymentKey, + appVersion, + label, + packageHash, + clientUniqueId, + logger, + ); + } + const redisCacheKey = this.getUpdateCheckCacheKey( + deploymentKey, + appVersion, + label, + packageHash, + ); + return redisClient.get(redisCacheKey).then((data) => { + if (data) { + try { + logger.debug('updateCheckFromCache read from cache'); + const obj = JSON.parse(data) as UpdateCheckInfo; + return obj; + } catch (e) { + // do nothing + } + } + return this.updateCheck( + deploymentKey, + appVersion, + label, + packageHash, + clientUniqueId, + logger, + ).then((rs) => { + try { + logger.debug('updateCheckFromCache read from db'); + const strRs = JSON.stringify(rs); + redisClient.setEx(redisCacheKey, EXPIRED, strRs); + } catch (e) { + // do nothing + } + return rs; + }); + }); + } + + private getChosenManCacheKey(packageId, rollout, clientUniqueId) { + return [CHOSEN_MAN, packageId, rollout, clientUniqueId].join(':'); + } + + private random(rollout) { + const r = Math.ceil(Math.random() * 10000); + if (r < rollout * 100) { + return Promise.resolve(true); + } + return Promise.resolve(false); + } + + chosenMan(packageId, rollout, clientUniqueId: string) { + if (rollout >= 100) { + return Promise.resolve(true); + } + const rolloutClientUniqueIdCache = _.get( + config, + 'common.rolloutClientUniqueIdCache', + false, + ); + if (rolloutClientUniqueIdCache === false) { + return this.random(rollout); + } + const redisCacheKey = this.getChosenManCacheKey(packageId, rollout, clientUniqueId); + return redisClient.get(redisCacheKey).then((data) => { + if (data === '1') { + return true; + } + if (data === '2') { + return false; + } + return this.random(rollout).then((r) => { + return redisClient + .setEx(redisCacheKey, 60 * 60 * 24 * 7, r ? '1' : '2') + .then(() => { + return r; + }); + }); + }); + } + + // eslint-disable-next-line max-lines-per-function + private updateCheck( + deploymentKey: string, + appVersion: string, + label: string, + packageHash: string, + clientUniqueId: string, + logger: Logger, + ) { + const rs: UpdateCheckInfo = { + packageId: 0, + downloadURL: '', + downloadUrl: '', + description: '', + isAvailable: false, + isDisabled: true, + isMandatory: false, + appVersion, + targetBinaryRange: '', + packageHash: '', + label: '', + packageSize: 0, + updateAppVersion: false, + shouldRunBinaryVersion: false, + rollout: 100, + }; + if (_.isEmpty(deploymentKey) || _.isEmpty(appVersion)) { + return Promise.reject(new AppError('please input deploymentKey and appVersion')); + } + return Deployments.findOne({ where: { deployment_key: deploymentKey } }) + .then((dep) => { + if (_.isEmpty(dep)) { + throw new AppError('Not found deployment, check deployment key is right.'); + } + logger.info('updateCheck.beforeParseVersion', { version: appVersion }); + const version = parseVersion(appVersion); + logger.info('updateCheck.afterParseVersion', { version }); + return DeploymentsVersions.findAll({ + where: { + deployment_id: dep.id, + min_version: { [Op.lte]: version }, + max_version: { [Op.gt]: version }, + }, + }).then((deploymentsVersionsMore) => { + const item = _.last(_.sortBy(deploymentsVersionsMore, 'created_at')); + logger.debug({ + item, + }); + return item; + }); + }) + .then((deploymentsVersions) => { + const packageId = _.get(deploymentsVersions, 'current_package_id', 0); + if (_.eq(packageId, 0)) { + return undefined; + } + return Packages.findByPk(packageId) + .then((packages) => { + if ( + packages && + _.eq(packages.deployment_id, deploymentsVersions.deployment_id) && + !_.eq(packages.package_hash, packageHash) + ) { + rs.packageId = packageId; + rs.targetBinaryRange = deploymentsVersions.app_version; + rs.downloadURL = getBlobDownloadUrl(packages.blob_url); + rs.downloadUrl = rs.downloadURL; + rs.description = _.get(packages, 'description', ''); + rs.isAvailable = !_.eq(packages.is_disabled, 1); + rs.isDisabled = !!_.eq(packages.is_disabled, 1); + rs.isMandatory = !!_.eq(packages.is_mandatory, 1); + rs.appVersion = appVersion; + rs.packageHash = _.get(packages, 'package_hash', ''); + rs.label = _.get(packages, 'label', ''); + rs.packageSize = _.get(packages, 'size', 0); + rs.rollout = _.get(packages, 'rollout', 100); + } + return packages; + }) + .then((packages) => { + // 尝试增量更新 + if ( + packageHash && + !_.isEmpty(packages) && + !_.eq(_.get(packages, 'package_hash', ''), packageHash) + ) { + return PackagesDiff.findOne({ + where: { + package_id: packages.id, + diff_against_package_hash: packageHash, + }, + }).then((diffPackage) => { + if (!_.isEmpty(diffPackage)) { + rs.downloadURL = getBlobDownloadUrl( + _.get(diffPackage, 'diff_blob_url'), + ); + rs.downloadUrl = getBlobDownloadUrl( + _.get(diffPackage, 'diff_blob_url'), + ); + rs.packageSize = _.get(diffPackage, 'diff_size', 0); + } + }); + } + return undefined; + }); + }) + .then(() => { + return rs; + }); + } + + private getPackagesInfo(deploymentKey, label) { + if (_.isEmpty(deploymentKey) || _.isEmpty(label)) { + return Promise.reject(new AppError('please input deploymentKey and label')); + } + return Deployments.findOne({ where: { deployment_key: deploymentKey } }) + .then((dep) => { + if (_.isEmpty(dep)) { + throw new AppError('does not found deployment'); + } + return Packages.findOne({ where: { deployment_id: dep.id, label } }); + }) + .then((packages) => { + if (_.isEmpty(packages)) { + throw new AppError('does not found packages'); + } + return packages; + }); + } + + reportStatusDownload(deploymentKey, label, clientUniqueId) { + return this.getPackagesInfo(deploymentKey, label).then((packages) => { + return Promise.all([ + PackagesMetrics.findOne({ where: { package_id: packages.id } }).then((metrics) => { + if (metrics) { + return metrics.increment('downloaded'); + } + return undefined; + }), + LogReportDownload.create({ + package_id: packages.id, + client_unique_id: clientUniqueId, + }), + ]); + }); + } + + reportStatusDeploy(deploymentKey: string, label, clientUniqueId: string, others) { + return this.getPackagesInfo(deploymentKey, label).then((packages) => { + const statusText = _.get(others, 'status'); + let status = 0; + if (_.eq(statusText, 'DeploymentSucceeded')) { + status = DEPLOYMENT_SUCCEEDED; + } else if (_.eq(statusText, 'DeploymentFailed')) { + status = DEPLOYMENT_FAILED; + } + const packageId = packages.id; + const previousDeploymentKey = _.get(others, 'previousDeploymentKey'); + const previousLabel = _.get(others, 'previousLabelOrAppVersion'); + if (status > 0) { + return Promise.all([ + LogReportDeploy.create({ + package_id: packageId, + client_unique_id: clientUniqueId, + previous_label: previousLabel, + previous_deployment_key: previousDeploymentKey, + status, + }), + PackagesMetrics.findOne({ where: { package_id: packageId } }).then( + (metrics) => { + if (_.isEmpty(metrics)) { + return undefined; + } + if (_.eq(status, DEPLOYMENT_SUCCEEDED)) { + return metrics.increment(['installed', 'active'], { by: 1 }); + } + return metrics.increment(['installed', 'failed'], { by: 1 }); + }, + ), + ]).then(() => { + if (previousDeploymentKey && previousLabel) { + return Deployments.findOne({ + where: { deployment_key: previousDeploymentKey }, + }) + .then((dep) => { + if (_.isEmpty(dep)) { + return undefined; + } + return Packages.findOne({ + where: { deployment_id: dep.id, label: previousLabel }, + }).then((p) => { + if (_.isEmpty(p)) { + return undefined; + } + return PackagesMetrics.findOne({ + where: { package_id: p.id }, + }); + }); + }) + .then((metrics) => { + if (metrics) { + return metrics.decrement('active'); + } + return undefined; + }); + } + return undefined; + }); + } + return undefined; + }); + } +} + +export const clientManager = new ClientManager(); diff --git a/src/core/services/collaborators-manager.ts b/src/core/services/collaborators-manager.ts new file mode 100644 index 00000000..b4eee7e8 --- /dev/null +++ b/src/core/services/collaborators-manager.ts @@ -0,0 +1,73 @@ +import _ from 'lodash'; +import { Op } from 'sequelize'; +import { Collaborators, CollaboratorsInterface } from '../../models/collaborators'; +import { Users } from '../../models/users'; +import { AppError } from '../app-error'; + +class CollaboratorsManager { + listCollaborators(appId: number) { + return Collaborators.findAll({ where: { appid: appId } }) + .then( + ( + data, + ): { + uids: number[]; + colByUid: Record; + } => { + return _.reduce( + data, + (result, value) => { + result.uids.push(value.uid); + result.colByUid[value.uid] = value; + return result; + }, + { + uids: [], + colByUid: {}, + }, + ); + }, + ) + .then((coInfo) => { + return Users.findAll({ where: { id: { [Op.in]: coInfo.uids } } }).then((data2) => { + return _.reduce( + data2, + (result, value) => { + let permission = ''; + if (!_.isEmpty(coInfo.colByUid[value.id])) { + permission = coInfo.colByUid[value.id].roles; + } + result[value.email] = { permission }; + return result; + }, + {} as Record, + ); + }); + }); + } + + addCollaborator(appId: number, uid: number) { + return Collaborators.findOne({ where: { appid: appId, uid } }).then((data) => { + if (_.isEmpty(data)) { + return Collaborators.create({ + appid: appId, + uid, + roles: 'Collaborator', + }); + } + throw new AppError('user already is Collaborator.'); + }); + } + + deleteCollaborator(appId: number, uid: number) { + return Collaborators.findOne({ where: { appid: appId, uid } }).then((data) => { + if (_.isEmpty(data)) { + throw new AppError('user is not a Collaborator'); + } else { + return Collaborators.destroy({ where: { id: data.id } }); + } + }); + } +} + +export const collaboratorsManager = new CollaboratorsManager(); diff --git a/src/core/services/datacenter-manager.ts b/src/core/services/datacenter-manager.ts new file mode 100644 index 00000000..30b1f47d --- /dev/null +++ b/src/core/services/datacenter-manager.ts @@ -0,0 +1,115 @@ +import fs from 'fs'; +import path from 'path'; +import { Logger } from 'kv-logger'; +import _ from 'lodash'; +import { AppError } from '../app-error'; +import { config } from '../config'; +import { createEmptyFolder, copy } from '../utils/common'; +import { calcAllFileSha256, packageHashSync } from '../utils/security'; + +const MANIFEST_FILENAME = 'manifest.json'; +const CONTENTS_NAME = 'contents'; + +class DataCenterManager { + getDataDir() { + return config.common.dataDir; + } + + hasPackageStoreSync(packageHash: string) { + const dataDir = this.getDataDir(); + const packageHashPath = path.join(dataDir, packageHash); + const manifestFile = path.join(packageHashPath, MANIFEST_FILENAME); + const contentPath = path.join(packageHashPath, CONTENTS_NAME); + return fs.existsSync(manifestFile) && fs.existsSync(contentPath); + } + + getPackageInfo(packageHash: string) { + if (this.hasPackageStoreSync(packageHash)) { + const dataDir = this.getDataDir(); + const packageHashPath = path.join(dataDir, packageHash); + const manifestFile = path.join(packageHashPath, MANIFEST_FILENAME); + const contentPath = path.join(packageHashPath, CONTENTS_NAME); + return this.buildPackageInfo(packageHash, packageHashPath, contentPath, manifestFile); + } + throw new AppError("can't get PackageInfo"); + } + + buildPackageInfo( + packageHash: string, + packageHashPath: string, + contentPath: string, + manifestFile: string, + ) { + return { + packageHash, + path: packageHashPath, + contentPath, + manifestFilePath: manifestFile, + }; + } + + validateStore(providePackageHash: string, logger: Logger) { + const dataDir = this.getDataDir(); + const packageHashPath = path.join(dataDir, providePackageHash); + const manifestFile = path.join(packageHashPath, MANIFEST_FILENAME); + const contentPath = path.join(packageHashPath, CONTENTS_NAME); + if (!this.hasPackageStoreSync(providePackageHash)) { + logger.debug(`validateStore providePackageHash not exist`); + return Promise.resolve(false); + } + return calcAllFileSha256(contentPath).then((manifestJson) => { + const packageHash = packageHashSync(manifestJson); + let manifestJsonLocal; + try { + manifestJsonLocal = JSON.parse(fs.readFileSync(manifestFile, { encoding: 'utf8' })); + } catch (e) { + logger.debug(`validateStore manifestFile contents invilad`); + return false; + } + const packageHashLocal = packageHashSync(manifestJsonLocal); + if ( + _.eq(providePackageHash, packageHash) && + _.eq(providePackageHash, packageHashLocal) + ) { + logger.debug(`validateStore store files is ok`); + return true; + } + logger.debug(`validateStore store files broken`); + return false; + }); + } + + storePackage(sourceDst: string, force: boolean, logger: Logger) { + return calcAllFileSha256(sourceDst).then((manifestJson) => { + const packageHash = packageHashSync(manifestJson); + const dataDir = this.getDataDir(); + const packageHashPath = path.join(dataDir, packageHash); + const manifestFile = path.join(packageHashPath, MANIFEST_FILENAME); + const contentPath = path.join(packageHashPath, CONTENTS_NAME); + return this.validateStore(packageHash, logger).then((isValidate) => { + if (!force && isValidate) { + return this.buildPackageInfo( + packageHash, + packageHashPath, + contentPath, + manifestFile, + ); + } + return createEmptyFolder(packageHashPath).then(() => { + return copy(sourceDst, contentPath).then(() => { + const manifestString = JSON.stringify(manifestJson); + fs.writeFileSync(manifestFile, manifestString); + return this.buildPackageInfo( + packageHash, + packageHashPath, + contentPath, + manifestFile, + ); + }); + }); + }); + }); + } +} + +export const dataCenterManager = new DataCenterManager(); diff --git a/src/core/services/deployments-manager.ts b/src/core/services/deployments-manager.ts new file mode 100644 index 00000000..108fcf27 --- /dev/null +++ b/src/core/services/deployments-manager.ts @@ -0,0 +1,277 @@ +import { Logger } from 'kv-logger'; +import _ from 'lodash'; +import moment from 'moment'; +import { Deployments } from '../../models/deployments'; +import { DeploymentsHistory } from '../../models/deployments_history'; +import { + DeploymentsVersions, + DeploymentsVersionsInterface, +} from '../../models/deployments_versions'; +import { Packages, PackagesInterface } from '../../models/packages'; +import { PackagesDiff } from '../../models/packages_diff'; +import { PackagesMetrics } from '../../models/packages_metrics'; +import { Users, UsersInterface } from '../../models/users'; +import { AppError } from '../app-error'; +import { getBlobDownloadUrl } from '../utils/common'; +import { sequelize } from '../utils/connections'; +import { randToken } from '../utils/security'; + +class DeploymentsManager { + getAllPackageIdsByDeploymentsId(deploymentsId: number) { + return Packages.findAll({ where: { deployment_id: deploymentsId } }); + } + + existDeloymentName(appId: number, name: string) { + return Deployments.findOne({ + where: { appid: appId, name }, + }).then((data) => { + if (!_.isEmpty(data)) { + throw new AppError(`${name} name does Exist!`); + } else { + return data; + } + }); + } + + addDeloyment(name: string, appId: number, uid: number) { + return Users.findByPk(uid).then((user) => { + if (_.isEmpty(user)) { + throw new AppError("can't find user"); + } + return this.existDeloymentName(appId, name).then(() => { + const { identical } = user; + const deploymentKey = randToken(28) + identical; + return Deployments.create({ + appid: appId, + name, + deployment_key: deploymentKey, + last_deployment_version_id: 0, + label_id: 0, + }); + }); + }); + } + + renameDeloymentByName(deploymentName: string, appId: number, newName: string) { + return this.existDeloymentName(appId, newName).then(() => { + return Deployments.update( + { name: newName }, + { where: { name: deploymentName, appid: appId } }, + ).then(([affectedCount]) => { + if (_.gt(affectedCount, 0)) { + return { name: newName }; + } + throw new AppError(`does not find the deployment "${deploymentName}"`); + }); + }); + } + + deleteDeloymentByName(deploymentName: string, appId: number) { + return Deployments.destroy({ + where: { name: deploymentName, appid: appId }, + }).then((rowNum) => { + if (_.gt(rowNum, 0)) { + return { name: `${deploymentName}` }; + } + throw new AppError(`does not find the deployment "${deploymentName}"`); + }); + } + + findDeloymentByName(deploymentName: string, appId: number, logger: Logger) { + logger.debug('findDeloymentByName', { + name: deploymentName, + appId, + }); + return Deployments.findOne({ + where: { name: deploymentName, appid: appId }, + }); + } + + findPackagesAndOtherInfos(packageId: number) { + return Packages.findOne({ + where: { id: packageId }, + }) + .then((packageInfo) => { + if (!packageInfo) { + return null; + } + return Promise.all([ + Promise.resolve(packageInfo), + PackagesDiff.findAll({ + where: { package_id: packageId }, + }).then((diffs) => { + if (diffs.length > 0) { + return _.reduce( + diffs, + (result, v) => { + result[v.diff_against_package_hash] = { + size: v.diff_size, + url: getBlobDownloadUrl(v.diff_blob_url), + }; + return result; + }, + {} as Record, + ); + } + return null; + }), + Users.findOne({ + where: { id: packageInfo.released_by }, + }), + DeploymentsVersions.findByPk(packageInfo.deployment_version_id), + ]); + }) + .then(([packageInfo, packageDiffMap, userInfo, deploymentsVersions]) => { + return { + packageInfo, + packageDiffMap, + userInfo, + deploymentsVersions, + }; + }); + } + + findDeloymentsPackages(deploymentsVersionsId) { + return DeploymentsVersions.findOne({ + where: { id: deploymentsVersionsId }, + }).then((deploymentsVersionsInfo) => { + if (deploymentsVersionsInfo) { + return this.findPackagesAndOtherInfos(deploymentsVersionsInfo.current_package_id); + } + return null; + }); + } + + formatPackage(packageVersion: { + packageInfo: PackagesInterface; + userInfo: UsersInterface; + packageDiffMap: Record; + deploymentsVersions: DeploymentsVersionsInterface; + }) { + if (!packageVersion) { + return null; + } + return { + description: packageVersion.packageInfo.description, + isDisabled: false, + isMandatory: packageVersion.packageInfo.is_mandatory === 1, + rollout: 100, + appVersion: packageVersion.deploymentsVersions.app_version, + packageHash: packageVersion.packageInfo.package_hash, + blobUrl: getBlobDownloadUrl(packageVersion.packageInfo.blob_url), + size: packageVersion.packageInfo.size, + manifestBlobUrl: getBlobDownloadUrl(packageVersion.packageInfo.manifest_blob_url), + diffPackageMap: packageVersion.packageDiffMap, + releaseMethod: packageVersion.packageInfo.release_method, + uploadTime: moment(packageVersion.packageInfo.updated_at).valueOf(), + originalLabel: packageVersion.packageInfo.original_label, + originalDeployment: packageVersion.packageInfo.original_deployment, + label: packageVersion.packageInfo.label, + releasedBy: packageVersion.userInfo.email, + }; + } + + listDeloyments(appId: number) { + return Deployments.findAll({ where: { appid: appId } }).then((deploymentsInfos) => { + if (_.isEmpty(deploymentsInfos)) { + return []; + } + return Promise.all( + deploymentsInfos.map((v) => { + return this.listDeloyment(v); + }), + ); + }); + } + + listDeloyment(deploymentInfo) { + return this.findDeloymentsPackages([deploymentInfo.last_deployment_version_id]) + .then(this.formatPackage) + .then((packageInfo) => { + return { + createdTime: moment(deploymentInfo.created_at).valueOf(), + id: `${deploymentInfo.id}`, + key: deploymentInfo.deployment_key, + name: deploymentInfo.name, + package: packageInfo, + }; + }); + } + + getDeploymentHistory(deploymentId) { + return DeploymentsHistory.findAll({ + where: { deployment_id: deploymentId }, + order: [['id', 'desc']], + limit: 15, + }) + .then((history) => { + return _.map(history, (v) => { + return v.package_id; + }); + }) + .then((packageIds) => { + return Promise.all( + packageIds.map((v) => { + return this.findPackagesAndOtherInfos(v).then(this.formatPackage); + }), + ); + }); + } + + deleteDeploymentHistory(deploymentId) { + return sequelize.transaction((t) => { + return Promise.all([ + Deployments.update( + { last_deployment_version_id: 0, label_id: 0 }, + { where: { id: deploymentId }, transaction: t }, + ), + DeploymentsHistory.findAll({ + where: { deployment_id: deploymentId }, + order: [['id', 'desc']], + limit: 1000, + }).then((rs) => { + return Promise.all( + rs.map((v) => { + return v.destroy({ transaction: t }); + }), + ); + }), + DeploymentsVersions.findAll({ + where: { deployment_id: deploymentId }, + order: [['id', 'desc']], + limit: 1000, + }).then((rs) => { + return Promise.all( + rs.map((v) => { + return v.destroy({ transaction: t }); + }), + ); + }), + Packages.findAll({ + where: { deployment_id: deploymentId }, + order: [['id', 'desc']], + limit: 1000, + }).then((rs) => { + return Promise.all( + rs.map((v) => { + return v.destroy({ transaction: t }).then(() => { + return Promise.all([ + PackagesMetrics.destroy({ + where: { package_id: v.get('id') }, + transaction: t, + }), + PackagesDiff.destroy({ + where: { package_id: v.get('id') }, + transaction: t, + }), + ]); + }); + }), + ); + }), + ]); + }); + } +} + +export const deploymentsManager = new DeploymentsManager(); diff --git a/src/core/services/email-manager.ts b/src/core/services/email-manager.ts new file mode 100644 index 00000000..06082b78 --- /dev/null +++ b/src/core/services/email-manager.ts @@ -0,0 +1,45 @@ +import _ from 'lodash'; +import nodemailer from 'nodemailer'; +import { AppError } from '../app-error'; +import { config } from '../config'; + +class EmailManager { + sendMail(options: { to: string; html: string; subject?: string; from?: string }) { + return new Promise((resolve, reject) => { + if (!_.get(options, 'to')) { + reject(new AppError('to是必传参数')); + return; + } + const { smtpConfig } = config; + if (!smtpConfig || !smtpConfig.host) { + resolve({}); + return; + } + const transporter = nodemailer.createTransport(smtpConfig); + const sendEmailAddress = smtpConfig.auth.user; + const defaultMailOptions = { + from: `"CodePush Server" <${sendEmailAddress}>`, // sender address + to: '', // list of receivers 必传参数 + subject: 'CodePush Server', // Subject line + html: '', // html body + }; + const mailOptions = _.assign(defaultMailOptions, options); + transporter.sendMail(mailOptions, (error, info) => { + if (error) { + reject(error); + return; + } + resolve(info); + }); + }); + } + + sendRegisterCodeMail(email: string, code: string) { + return this.sendMail({ + to: email, + html: `

您接收的验证码为: ${code} 20分钟内有效
`, + }); + } +} + +export const emailManager = new EmailManager(); diff --git a/src/core/services/package-manager.ts b/src/core/services/package-manager.ts new file mode 100644 index 00000000..ee3a3ec7 --- /dev/null +++ b/src/core/services/package-manager.ts @@ -0,0 +1,784 @@ +/* eslint-disable max-lines */ +import { EventEmitter } from 'events'; +import fs from 'fs'; +import os from 'os'; +import path from 'path'; +import { Request } from 'express'; +import formidable from 'formidable'; +import { Logger } from 'kv-logger'; +import _ from 'lodash'; +import { Op } from 'sequelize'; +import slash from 'slash'; +import yazl from 'yazl'; +import { Apps } from '../../models/apps'; +import { Deployments, generateDeploymentsLabelId } from '../../models/deployments'; +import { DeploymentsHistory } from '../../models/deployments_history'; +import { DeploymentsVersions } from '../../models/deployments_versions'; +import { Packages, PackagesInterface } from '../../models/packages'; +import { PackagesDiff } from '../../models/packages_diff'; +import { PackagesMetrics } from '../../models/packages_metrics'; +import { AppError } from '../app-error'; +import { + DIFF_MANIFEST_FILE_NAME, + IS_DISABLED_NO, + IS_DISABLED_YES, + IS_MANDATORY_NO, + IS_MANDATORY_YES, + RELEASE_METHOD_PROMOTE, + RELEASE_METHOD_UPLOAD, +} from '../const'; +import { + getBlobDownloadUrl, + createFileFromRequest, + unzipFile, + copySync, + diffCollectionsSync, + createEmptyFolder, + createEmptyFolderSync, + deleteFolderSync, + validatorVersion, +} from '../utils/common'; +import { sequelize } from '../utils/connections'; +import { qetag } from '../utils/qetag'; +import { randToken, uploadPackageType } from '../utils/security'; +import { uploadFileToStorage } from '../utils/storage'; +import { dataCenterManager } from './datacenter-manager'; + +class PackageManager { + getMetricsbyPackageId(packageId) { + return PackagesMetrics.findOne({ where: { package_id: packageId } }); + } + + findPackageInfoByDeploymentIdAndLabel(deploymentId, label) { + return Packages.findOne({ where: { deployment_id: deploymentId, label } }); + } + + findLatestPackageInfoByDeployVersion(deploymentsVersionsId, logger: Logger) { + return DeploymentsVersions.findByPk(deploymentsVersionsId).then((deploymentsVersions) => { + if (!deploymentsVersions || deploymentsVersions.current_package_id < 0) { + const e = new AppError('not found last packages'); + logger.debug(e); + throw e; + } + return Packages.findByPk(deploymentsVersions.current_package_id); + }); + } + + parseReqFile(req: Request, logger: Logger) { + logger.debug('parseReqFile'); + return new Promise<{ packageInfo: string; package: formidable.File }>((resolve, reject) => { + const form = formidable(); + form.parse(req, (err, fields, files) => { + if (err) { + reject(new AppError('upload error')); + return; + } + + if (_.isEmpty(fields.packageInfo) || _.isEmpty(_.get(files, 'package'))) { + logger.debug('parseReqFile upload info lack'); + reject(new AppError('upload info lack')); + return; + } + + logger.debug('parseReqFile is ok'); + resolve({ + packageInfo: JSON.parse(fields.packageInfo as string), + package: files.package as formidable.File, + }); + }); + }); + } + + createDeploymentsVersionIfNotExist( + deploymentId, + appVersion, + minVersion, + maxVersion, + t, + logger: Logger, + ) { + return DeploymentsVersions.findOrCreate({ + where: { + deployment_id: deploymentId, + app_version: appVersion, + min_version: minVersion, + max_version: maxVersion, + }, + defaults: { current_package_id: 0 }, + transaction: t, + }).then(([data, created]) => { + if (created) { + logger.debug( + `createDeploymentsVersionIfNotExist findOrCreate version ${appVersion}`, + ); + } + logger.debug(`createDeploymentsVersionIfNotExist version data:`, data.get()); + return data; + }); + } + + isMatchPackageHash(packageId, packageHash, logger: Logger) { + if (_.lt(packageId, 0)) { + logger.debug(`isMatchPackageHash packageId is 0`); + return Promise.resolve(false); + } + return Packages.findByPk(packageId).then((data) => { + if (data && _.eq(data.get('package_hash'), packageHash)) { + logger.debug(`isMatchPackageHash data:`, data.get()); + logger.debug(`isMatchPackageHash packageHash exist`); + return true; + } + logger.debug(`isMatchPackageHash package is null`); + return false; + }); + } + + createPackage( + deploymentId, + appVersion, + packageHash, + manifestHash: string, + blobHash: string, + params, + logger: Logger, + ) { + const releaseMethod = params.releaseMethod || RELEASE_METHOD_UPLOAD; + const releaseUid = params.releaseUid || 0; + const isMandatory = params.isMandatory || 0; + const size = params.size || 0; + const rollout = params.rollout || 100; + const description = params.description || ''; + const originalLabel = params.originalLabel || ''; + const isDisabled = params.isDisabled || 0; + const originalDeployment = params.originalDeployment || ''; + return generateDeploymentsLabelId(deploymentId).then((labelId) => { + return sequelize.transaction((t) => { + return this.createDeploymentsVersionIfNotExist( + deploymentId, + appVersion, + params.min_version, + params.max_version, + t, + logger, + ).then((deploymentsVersions) => { + return Packages.create( + { + deployment_version_id: deploymentsVersions.id, + deployment_id: deploymentId, + description, + package_hash: packageHash, + blob_url: blobHash, + size, + manifest_blob_url: manifestHash, + release_method: releaseMethod, + label: `v${labelId}`, + released_by: releaseUid, + is_mandatory: isMandatory, + is_disabled: isDisabled, + rollout, + original_label: originalLabel, + original_deployment: originalDeployment, + }, + { transaction: t }, + ).then((packages) => { + deploymentsVersions.set('current_package_id', packages.id); + return Promise.all([ + deploymentsVersions.save({ transaction: t }), + Deployments.update( + { last_deployment_version_id: deploymentsVersions.id }, + { where: { id: deploymentId }, transaction: t }, + ), + PackagesMetrics.create({ package_id: packages.id }, { transaction: t }), + DeploymentsHistory.create( + { deployment_id: deploymentId, package_id: packages.id }, + { transaction: t }, + ), + ]).then(() => packages); + }); + }); + }); + }); + } + + downloadPackageAndExtract(workDirectoryPath, packageHash, blobHash, logger: Logger) { + return dataCenterManager.validateStore(packageHash, logger).then((isValidate) => { + if (isValidate) { + return dataCenterManager.getPackageInfo(packageHash); + } + const downloadURL = getBlobDownloadUrl(blobHash); + return createFileFromRequest( + downloadURL, + path.join(workDirectoryPath, blobHash), + logger, + ).then(() => { + return unzipFile( + path.join(workDirectoryPath, blobHash), + path.join(workDirectoryPath, 'current'), + logger, + ).then((outputPath) => { + return dataCenterManager.storePackage(outputPath, true, logger); + }); + }); + }); + } + + zipDiffPackage(fileName, files, baseDirectoryPath, hotCodePushFile) { + return new Promise<{ isTemporary: boolean; path: string }>((resolve, reject) => { + const zipFile = new yazl.ZipFile(); + const writeStream = fs.createWriteStream(fileName); + writeStream.on('error', (error) => { + reject(error); + }); + (zipFile as unknown as EventEmitter).on('error', (error) => { + reject(error); + }); + zipFile.outputStream + .pipe(writeStream) + .on('error', (error) => { + reject(error); + }) + .on('close', () => { + resolve({ isTemporary: true, path: fileName }); + }); + for (let i = 0; i < files.length; i += 1) { + const file = files[i]; + zipFile.addFile(path.join(baseDirectoryPath, file), slash(file)); + } + zipFile.addFile(hotCodePushFile, DIFF_MANIFEST_FILE_NAME); + zipFile.end(); + }); + } + + generateOneDiffPackage( + workDirectoryPath, + packageId, + originDataCenter, + oldPackageDataCenter, + diffPackageHash, + diffManifestBlobHash, + logger: Logger, + ) { + return PackagesDiff.findOne({ + where: { + package_id: packageId, + diff_against_package_hash: diffPackageHash, + }, + }).then((diffPackage) => { + if (!_.isEmpty(diffPackage)) { + return undefined; + } + logger.debug('generateOneDiffPackage', { + packageId, + originDataCenter, + oldPackageDataCenter, + }); + const downloadURL = getBlobDownloadUrl(diffManifestBlobHash); + return createFileFromRequest( + downloadURL, + path.join(workDirectoryPath, diffManifestBlobHash), + logger, + ).then(() => { + const dataCenterContentPath = path.join(workDirectoryPath, 'dataCenter'); + copySync(originDataCenter.contentPath, dataCenterContentPath); + // const oldPackageDataCenterContentPath = oldPackageDataCenter.contentPath; + const originManifestJson = JSON.parse( + fs.readFileSync(originDataCenter.manifestFilePath, 'utf8'), + ); + const diffManifestJson = JSON.parse( + fs.readFileSync(path.join(workDirectoryPath, diffManifestBlobHash), 'utf8'), + ); + const json = diffCollectionsSync(originManifestJson, diffManifestJson); + const files = _.concat(json.diff, json.collection1Only); + const hotcodepush = { deletedFiles: json.collection2Only, patchedFiles: [] }; + const hotCodePushFile = path.join( + workDirectoryPath, + `${diffManifestBlobHash}_hotcodepush`, + ); + fs.writeFileSync(hotCodePushFile, JSON.stringify(hotcodepush)); + const fileName = path.join(workDirectoryPath, `${diffManifestBlobHash}.zip`); + return this.zipDiffPackage( + fileName, + files, + dataCenterContentPath, + hotCodePushFile, + ).then((data) => { + return qetag(data.path, logger).then((diffHash) => { + return uploadFileToStorage(diffHash, fileName, logger).then(() => { + const stats = fs.statSync(fileName); + return PackagesDiff.create({ + package_id: packageId, + diff_against_package_hash: diffPackageHash, + diff_blob_url: diffHash, + diff_size: stats.size, + }); + }); + }); + }); + }); + }); + } + + createDiffPackagesByLastNums( + appId, + originalPackage: PackagesInterface, + num: number, + logger: Logger, + ) { + const packageId = originalPackage.id; + return Promise.all([ + Packages.findAll({ + where: { + deployment_version_id: originalPackage.deployment_version_id, + id: { [Op.lt]: packageId }, + }, + order: [['id', 'desc']], + limit: num, + }), + Packages.findAll({ + where: { + deployment_version_id: originalPackage.deployment_version_id, + id: { [Op.lt]: packageId }, + }, + order: [['id', 'asc']], + limit: 2, + }), + ]) + .then(([lastNumsPackages, basePackages]) => { + return _.uniqBy(_.unionBy(lastNumsPackages, basePackages, 'id'), 'package_hash'); + }) + .then((lastNumsPackages) => { + return this.createDiffPackages(originalPackage, lastNumsPackages, logger); + }); + } + + createDiffPackages(originalPackage, destPackages, logger: Logger) { + if (!_.isArray(destPackages)) { + return Promise.reject(new AppError('第二个参数必须是数组')); + } + if (destPackages.length <= 0) { + return null; + } + const packageHash = _.get(originalPackage, 'package_hash'); + // const manifest_blob_url = _.get(originalPackage, 'manifest_blob_url'); + const blobUrl = _.get(originalPackage, 'blob_url'); + const workDirectoryPath = path.join(os.tmpdir(), `codepush_${randToken(32)}`); + logger.debug('createDiffPackages using dir', { workDirectoryPath }); + return createEmptyFolder(workDirectoryPath) + .then(() => + this.downloadPackageAndExtract(workDirectoryPath, packageHash, blobUrl, logger), + ) + .then((originDataCenter) => + Promise.all( + destPackages.map((v) => { + const diffWorkDirectoryPath = path.join( + workDirectoryPath, + _.get(v, 'package_hash'), + ); + createEmptyFolderSync(diffWorkDirectoryPath); + return this.downloadPackageAndExtract( + diffWorkDirectoryPath, + _.get(v, 'package_hash'), + _.get(v, 'blob_url'), + logger, + ).then((oldPackageDataCenter) => + this.generateOneDiffPackage( + diffWorkDirectoryPath, + originalPackage.id, + originDataCenter, + oldPackageDataCenter, + v.package_hash, + v.manifest_blob_url, + logger, + ), + ); + }), + ), + ) + .finally(() => deleteFolderSync(workDirectoryPath)); + } + + // eslint-disable-next-line max-lines-per-function + releasePackage( + appId, + deploymentId, + packageInfo, + filePath: string, + releaseUid: number, + logger: Logger, + ) { + const { appVersion } = packageInfo; + const versionInfo = validatorVersion(appVersion); + if (!versionInfo[0]) { + logger.debug(`releasePackage targetBinaryVersion ${appVersion} not support.`); + return Promise.reject(new AppError(`targetBinaryVersion ${appVersion} not support.`)); + } + const { description } = packageInfo; // 描述 + const { isDisabled } = packageInfo; // 是否立刻下载 + const { rollout } = packageInfo; // 灰度百分比 + const { isMandatory } = packageInfo; // 是否强制更新,无法跳过 + const tmpDir = os.tmpdir(); + const directoryPathParent = path.join(tmpDir, `codepuh_${randToken(32)}`); + const directoryPath = path.join(directoryPathParent, 'current'); + logger.debug(`releasePackage generate an random dir path: ${directoryPath}`); + return Promise.all([ + qetag(filePath, logger), + createEmptyFolder(directoryPath).then(() => { + return unzipFile(filePath, directoryPath, logger); + }), + ]) + .then(([blobHash]) => { + return uploadPackageType(directoryPath).then((type) => { + return Apps.findByPk(appId).then((appInfo) => { + if (type > 0 && appInfo.os > 0 && appInfo.os !== type) { + const e = new AppError('it must be publish it by ios type'); + logger.debug(e); + throw e; + } else { + // 不验证 + logger.debug(`Unknown package type:`, { + type, + os: appInfo.os, + }); + } + return blobHash; + }); + }); + }) + .then((blobHash) => { + return dataCenterManager + .storePackage(directoryPath, false, logger) + .then((dataCenter) => { + const { packageHash } = dataCenter; + const manifestFile = dataCenter.manifestFilePath; + return DeploymentsVersions.findOne({ + where: { deployment_id: deploymentId, app_version: appVersion }, + }) + .then((deploymentsVersions) => { + if (!deploymentsVersions) { + return false; + } + return this.isMatchPackageHash( + deploymentsVersions.get('current_package_id'), + packageHash, + logger, + ); + }) + .then((isExist) => { + if (isExist) { + const e = new AppError( + "The uploaded package is identical to the contents of the specified deployment's current release.", + ); + logger.debug(e.message); + throw e; + } + return qetag(manifestFile, logger); + }) + .then((manifestHash) => { + return Promise.all([ + uploadFileToStorage(manifestHash, manifestFile, logger), + uploadFileToStorage(blobHash, filePath, logger), + ]).then(() => [packageHash, manifestHash, blobHash]); + }); + }); + }) + .then(([packageHash, manifestHash, blobHash]) => { + const stats = fs.statSync(filePath); + const params = { + releaseMethod: RELEASE_METHOD_UPLOAD, + releaseUid, + isMandatory: isMandatory ? IS_MANDATORY_YES : IS_MANDATORY_NO, + isDisabled: isDisabled ? IS_DISABLED_YES : IS_DISABLED_NO, + rollout, + size: stats.size, + description, + min_version: versionInfo[1], + max_version: versionInfo[2], + }; + return this.createPackage( + deploymentId, + appVersion, + packageHash, + manifestHash, + blobHash, + params, + logger, + ); + }) + .finally(() => deleteFolderSync(directoryPathParent)); + } + + modifyReleasePackage(packageId, params) { + const appVersion = _.get(params, 'appVersion'); + const description = _.get(params, 'description'); + const isMandatory = _.get(params, 'isMandatory'); + const isDisabled = _.get(params, 'isDisabled'); + const rollout = _.get(params, 'rollout'); + return Packages.findByPk(packageId) + .then((packageInfo) => { + if (!packageInfo) { + throw new AppError(`packageInfo not found`); + } + if (!_.isNull(appVersion)) { + const versionInfo = validatorVersion(appVersion); + if (!versionInfo[0]) { + throw new AppError(`--targetBinaryVersion ${appVersion} not support.`); + } + return Promise.all([ + DeploymentsVersions.findOne({ + where: { + deployment_id: packageInfo.deployment_id, + app_version: appVersion, + }, + }), + DeploymentsVersions.findByPk(packageInfo.deployment_version_id), + ]) + .then(([v1, v2]) => { + if (v1 && !_.eq(v1.id, v2.id)) { + throw new AppError(`${appVersion} already exist.`); + } + if (!v2) { + throw new AppError(`packages not found.`); + } + return DeploymentsVersions.update( + { + app_version: appVersion, + min_version: versionInfo[1], + max_version: versionInfo[2], + }, + { where: { id: v2.id } }, + ); + }) + .then(() => { + return packageInfo; + }); + } + return packageInfo; + }) + .then((packageInfo) => { + const newParams = { + description: description || packageInfo.description, + } as PackagesInterface; + if (_.isInteger(rollout)) { + newParams.rollout = rollout; + } + if (_.isBoolean(isMandatory)) { + newParams.is_mandatory = isMandatory ? IS_MANDATORY_YES : IS_MANDATORY_NO; + } + if (_.isBoolean(isDisabled)) { + newParams.is_disabled = isDisabled ? IS_DISABLED_YES : IS_DISABLED_NO; + } + return Packages.update(newParams, { where: { id: packageId } }); + }); + } + + // eslint-disable-next-line max-lines-per-function + promotePackage(sourceDeploymentInfo, destDeploymentInfo, params, logger: Logger) { + const appVersion = _.get(params, 'appVersion', null); + const label = _.get(params, 'label', null); + return new Promise((resolve, reject) => { + if (label) { + Packages.findOne({ + where: { deployment_id: sourceDeploymentInfo.id, label }, + }) + .then((sourcePack) => { + if (!sourcePack) { + throw new AppError('label does not exist.'); + } + return DeploymentsVersions.findByPk(sourcePack.deployment_version_id).then( + (deploymentsVersions) => { + if (!deploymentsVersions) { + throw new AppError('deploymentsVersions does not exist.'); + } + resolve([sourcePack, deploymentsVersions]); + }, + ); + }) + .catch((e) => { + reject(e); + }); + return; + } + const lastDeploymentVersionId = _.get( + sourceDeploymentInfo, + 'last_deployment_version_id', + 0, + ); + if (_.lte(lastDeploymentVersionId, 0)) { + throw new AppError(`does not exist last_deployment_version_id.`); + } + + DeploymentsVersions.findByPk(lastDeploymentVersionId) + .then((deploymentsVersions) => { + const sourcePackId = _.get(deploymentsVersions, 'current_package_id', 0); + if (_.lte(sourcePackId, 0)) { + throw new AppError(`packageInfo not found.`); + } + return Packages.findByPk(sourcePackId).then((sourcePack) => { + if (!sourcePack) { + throw new AppError(`packageInfo not found.`); + } + resolve([sourcePack, deploymentsVersions]); + }); + }) + .catch((e) => { + reject(e); + }); + }) + .then(([sourcePack, deploymentsVersions]) => { + const appFinalVersion = appVersion || deploymentsVersions.app_version; + logger.debug('sourcePack', sourcePack); + logger.debug('deploymentsVersions', deploymentsVersions); + logger.debug('appFinalVersion', appFinalVersion); + return DeploymentsVersions.findOne({ + where: { + deployment_id: destDeploymentInfo.id, + app_version: appFinalVersion, + }, + }) + .then((destDeploymentsVersions) => { + if (!destDeploymentsVersions) { + return false; + } + return this.isMatchPackageHash( + destDeploymentsVersions.get('current_package_id'), + sourcePack.package_hash, + logger, + ); + }) + .then((isExist) => { + if (isExist) { + throw new AppError( + "The uploaded package is identical to the contents of the specified deployment's current release.", + ); + } + return [sourcePack, appFinalVersion]; + }); + }) + .then(([sourcePack, appFinalVersion]) => { + const versionInfo = validatorVersion(appFinalVersion); + if (!versionInfo[0]) { + logger.debug(`targetBinaryVersion ${appVersion} not support.`); + throw new AppError(`targetBinaryVersion ${appVersion} not support.`); + } + + const createParams = { + releaseMethod: RELEASE_METHOD_PROMOTE, + releaseUid: params.promoteUid || 0, + rollout: params.rollout || 100, + size: sourcePack.size, + description: params.description || sourcePack.description, + originalLabel: sourcePack.label, + originalDeployment: sourceDeploymentInfo.name, + min_version: versionInfo[1], + max_version: versionInfo[2], + isMandatory: 0, + isDisabled: 0, + }; + if (_.isBoolean(params.isMandatory)) { + createParams.isMandatory = params.isMandatory + ? IS_MANDATORY_YES + : IS_MANDATORY_NO; + } else { + createParams.isMandatory = sourcePack.is_mandatory; + } + if (_.isBoolean(params.isDisabled)) { + createParams.isDisabled = params.isDisabled ? IS_DISABLED_YES : IS_DISABLED_NO; + } else { + createParams.isDisabled = sourcePack.is_disabled; + } + return this.createPackage( + destDeploymentInfo.id, + appFinalVersion, + sourcePack.package_hash, + sourcePack.manifest_blob_url, + sourcePack.blob_url, + createParams, + logger, + ); + }); + } + + rollbackPackage( + deploymentVersionId: number, + targetLabel: string | undefined, + rollbackUid: number, + logger: Logger, + ) { + return DeploymentsVersions.findByPk(deploymentVersionId).then((deploymentsVersions) => { + if (!deploymentsVersions) { + throw new AppError('您之前还没有发布过版本'); + } + return Packages.findByPk(deploymentsVersions.current_package_id) + .then((currentPackageInfo): Promise<[PackagesInterface, PackagesInterface[]]> => { + if (targetLabel) { + return Packages.findAll({ + where: { + deployment_version_id: deploymentVersionId, + label: targetLabel, + }, + limit: 1, + }).then((rollbackPackageInfos) => { + return [currentPackageInfo, rollbackPackageInfos]; + }); + } + return this.getCanRollbackPackages(deploymentVersionId).then( + (rollbackPackageInfos) => { + return [currentPackageInfo, rollbackPackageInfos]; + }, + ); + }) + .then(([currentPackageInfo, rollbackPackageInfos]) => { + if (currentPackageInfo && rollbackPackageInfos.length > 0) { + for (let i = rollbackPackageInfos.length - 1; i >= 0; i -= 1) { + if ( + rollbackPackageInfos[i].package_hash !== + currentPackageInfo.package_hash + ) { + return rollbackPackageInfos[i]; + } + } + } + throw new AppError('没有可供回滚的版本'); + }) + .then((rollbackPackage) => { + const params = { + releaseMethod: 'Rollback', + releaseUid: rollbackUid, + isMandatory: rollbackPackage.is_mandatory, + isDisabled: rollbackPackage.is_disabled, + rollout: rollbackPackage.rollout, + size: rollbackPackage.size, + description: rollbackPackage.description, + originalLabel: rollbackPackage.label, + originalDeployment: '', + min_version: deploymentsVersions.min_version, + max_version: deploymentsVersions.max_version, + }; + return this.createPackage( + deploymentsVersions.deployment_id, + deploymentsVersions.app_version, + rollbackPackage.package_hash, + rollbackPackage.manifest_blob_url, + rollbackPackage.blob_url, + params, + logger, + ); + }); + }); + } + + getCanRollbackPackages(deploymentVersionId) { + return Packages.findAll({ + where: { + deployment_version_id: deploymentVersionId, + release_method: { + [Op.in]: [RELEASE_METHOD_UPLOAD, RELEASE_METHOD_PROMOTE], + }, + }, + order: [['id', 'desc']], + limit: 2, + }); + } +} + +export const packageManager = new PackageManager(); diff --git a/src/core/utils/common.ts b/src/core/utils/common.ts new file mode 100644 index 00000000..69fa14ca --- /dev/null +++ b/src/core/utils/common.ts @@ -0,0 +1,211 @@ +/* eslint-disable no-cond-assign */ +import fs from 'fs'; +import { pipeline } from 'stream'; +import util from 'util'; +import extract from 'extract-zip'; +import fsextra from 'fs-extra'; +import { Logger } from 'kv-logger'; +import _ from 'lodash'; +import fetch from 'node-fetch'; +import validator from 'validator'; +import { AppError } from '../app-error'; +import { config } from '../config'; + +const streamPipeline = util.promisify(pipeline); + +/** WEB_UI_ALLOW !== true 이면 UI 숨김 */ +export function shouldHideWebUI(): boolean { + const allowWebUiInProd = config.common.webUIAllow; + + return !allowWebUiInProd; +} + +function cleanVersion(versionNo?: string) { + if (typeof versionNo !== 'string') { + return versionNo as any; + } + // 2.10.2-dev-01 -> 2.10.2 + return versionNo.replace(/-.*$/, ''); +} + +/** + * SEMVER 스트링을 마이너와 패치 부분 자리수가 늘어난 스트링으로 변환 + * - 다수의 패치 횟수 보장을 위한 작업 + */ +export function parseVersion(versionNo: string) { + let version = '0'; + let data = null; + const normalized = cleanVersion(versionNo); + if ((data = normalized.match(/^([0-9]{1,3}).([0-9]{1,5}).([0-9]{1,10})$/))) { + // "1.2.3" + version = data[1] + _.padStart(data[2], 5, '0') + _.padStart(data[3], 10, '0'); + } else if ((data = normalized.match(/^([0-9]{1,3}).([0-9]{1,5})$/))) { + // "1.2" + version = data[1] + _.padStart(data[2], 5, '0') + _.padStart('0', 10, '0'); + } + return version; +} + +export function validatorVersion(versionNo: string) { + let flag = false; + let min = '0'; + let max = '9999999999999999999'; + let data = null; + if (versionNo === '*') { + // "*" + flag = true; + } else if ((data = versionNo.match(/^([0-9]{1,3}).([0-9]{1,5}).([0-9]{1,10})$/))) { + // "1.2.3" + flag = true; + min = data[1] + _.padStart(data[2], 5, '0') + _.padStart(data[3], 10, '0'); + max = + data[1] + + _.padStart(data[2], 5, '0') + + _.padStart(`${parseInt(data[3], 10) + 1}`, 10, '0'); + } else if ((data = versionNo.match(/^([0-9]{1,3}).([0-9]{1,5})(\.\*){0,1}$/))) { + // "1.2" "1.2.*" + flag = true; + min = data[1] + _.padStart(data[2], 5, '0') + _.padStart('0', 10, '0'); + max = + data[1] + _.padStart(`${parseInt(data[2], 10) + 1}`, 5, '0') + _.padStart('0', 10, '0'); + } else if ((data = versionNo.match(/^~([0-9]{1,3}).([0-9]{1,5}).([0-9]{1,10})$/))) { + // "~1.2.3" + flag = true; + min = data[1] + _.padStart(data[2], 5, '0') + _.padStart(data[3], 10, '0'); + max = + data[1] + _.padStart(`${parseInt(data[2], 10) + 1}`, 5, '0') + _.padStart('0', 10, '0'); + } else if ((data = versionNo.match(/^\^([0-9]{1,3}).([0-9]{1,5}).([0-9]{1,10})$/))) { + // "^1.2.3" + flag = true; + min = data[1] + _.padStart(data[2], 5, '0') + _.padStart(data[3], 10, '0'); + max = + _.toString(parseInt(data[1], 10) + 1) + + _.padStart('0', 5, '0') + + _.padStart('0', 10, '0'); + } else if ( + (data = versionNo.match( + /^([0-9]{1,3}).([0-9]{1,5}).([0-9]{1,10})\s?-\s?([0-9]{1,3}).([0-9]{1,5}).([0-9]{1,10})$/, + )) + ) { + // "1.2.3 - 1.2.7" + flag = true; + min = data[1] + _.padStart(data[2], 5, '0') + _.padStart(data[3], 10, '0'); + max = + data[4] + + _.padStart(data[5], 5, '0') + + _.padStart(`${parseInt(data[6], 10) + 1}`, 10, '0'); + } else if ( + (data = versionNo.match( + /^>=([0-9]{1,3}).([0-9]{1,5}).([0-9]{1,10})\s?<([0-9]{1,3}).([0-9]{1,5}).([0-9]{1,10})$/, + )) + ) { + // ">=1.2.3 <1.2.7" + flag = true; + min = data[1] + _.padStart(data[2], 5, '0') + _.padStart(data[3], 10, '0'); + max = data[4] + _.padStart(data[5], 5, '0') + _.padStart(data[6], 10, '0'); + } + return [flag, min, max]; +} + +export async function createFileFromRequest(url: string, filePath: string, logger: Logger) { + try { + await fs.promises.stat(filePath); + return; + } catch (err) { + if (err.code !== 'ENOENT') { + throw err; + } + } + + logger.debug(`createFileFromRequest url:${url}`); + const response = await fetch(url); + if (!response.ok) { + throw new AppError(`unexpected response ${response.statusText}`); + } + await streamPipeline(response.body, fs.createWriteStream(filePath)); +} + +export function copySync(sourceDst: string, targertDst: string) { + return fsextra.copySync(sourceDst, targertDst, { overwrite: true }); +} + +export function copy(sourceDst: string, targertDst: string) { + return fsextra.copy(sourceDst, targertDst, { overwrite: true }); +} + +function deleteFolder(folderPath: string) { + return fsextra.remove(folderPath); +} + +export function deleteFolderSync(folderPath: string) { + return fsextra.removeSync(folderPath); +} + +export async function createEmptyFolder(folderPath: string) { + await deleteFolder(folderPath); + await fsextra.mkdirs(folderPath); +} + +export function createEmptyFolderSync(folderPath: string) { + deleteFolderSync(folderPath); + fsextra.mkdirsSync(folderPath); +} + +export async function unzipFile(zipFile: string, outputPath: string, logger: Logger) { + try { + logger.debug(`unzipFile check zipFile ${zipFile} fs.R_OK`); + fs.accessSync(zipFile, fs.constants.R_OK); + logger.debug(`Pass unzipFile file ${zipFile}`); + } catch (err) { + throw new AppError(err.message); + } + + try { + await extract(zipFile, { dir: outputPath }); + logger.debug(`unzipFile success`); + } catch (err) { + throw new AppError(`it's not a zipFile`); + } + return outputPath; +} + +export function getBlobDownloadUrl(blobUrl: string): string { + let fileName = blobUrl; + const { storageType } = config.common; + const { downloadUrl } = config[storageType]; + if (storageType === 'local') { + fileName = `${blobUrl.substring(0, 2).toLowerCase()}/${blobUrl}`; + } + if (!validator.isURL(downloadUrl)) { + throw new AppError(`Please config ${storageType}.downloadUrl in config.js`); + } + return `${downloadUrl}/${fileName}`; +} + +export function diffCollectionsSync( + collection1: Record, + collection2: Record, +) { + const diff: string[] = []; + const collection1Only: string[] = []; + const collection2Keys = new Set(Object.keys(collection2)); + if (collection1 instanceof Object) { + const keys = Object.keys(collection1); + for (let i = 0; i < keys.length; i += 1) { + const key = keys[i]; + if (!collection2Keys.has(key)) { + collection1Only.push(key); + } else { + collection2Keys.delete(key); + if (!_.eq(collection1[key], collection2[key])) { + diff.push(key); + } + } + } + } + return { + diff, + collection1Only, + collection2Only: Array.from(collection2Keys), + }; +} diff --git a/src/core/utils/connections.ts b/src/core/utils/connections.ts new file mode 100644 index 00000000..5ace8000 --- /dev/null +++ b/src/core/utils/connections.ts @@ -0,0 +1,71 @@ +import { logger } from 'kv-logger'; +import { createClient } from 'redis'; +import { Sequelize } from 'sequelize'; +import { config } from '../config'; + +export const sequelize = new Sequelize( + config.db.database, + config.db.username, + config.db.password, + config.db, +); + +const redisTlsUrl = config.redis.tlsUrl; // REDIS_TLS_URL 또는 REDIS_URL +const isTlsSupported = !!redisTlsUrl && redisTlsUrl.startsWith('rediss://'); + +export const redisClient = redisTlsUrl + ? createClient({ + url: redisTlsUrl, + socket: { + tls: isTlsSupported, + rejectUnauthorized: false, // `Redis Client Error: self-signed certificate in certificate chain` 오류 우회; 헤로쿠 공식문서도 이 옵션 사용으로 명시되어 있음 + reconnectStrategy: (retries: number) => { + if (retries > 10) { + return new Error('Retry count exhausted'); + } + return retries * 100; + }, + }, + }) + : createClient({ + socket: { + host: config.redis.host, + port: config.redis.port, + reconnectStrategy: (retries: number) => { + if (retries > 10) { + return new Error('Retry count exhausted'); + } + + return retries * 100; + }, + }, + password: config.redis.password, + database: config.redis.db, + }); + +// 에러 로깅 (Unhandled 'error' 로 인한 앱크래시 방지) +redisClient.on('error', (err) => { + const msg = err?.message || ''; + + // 무시할 에러 메시지 패턴들 + const ignorablePatterns = [ + 'Socket closed unexpectedly', + // 'Connection is closed', + ]; + + // 무시 패턴과 매칭되면 스택 제외하고 info 레벨 로깅 + if (ignorablePatterns.some((p) => msg.includes(p))) { + logger.info(`Redis ignorable error: ${msg}`); + return; + } + + // 그 외 에러+스택 로깅 + logger.error('Redis Client Error', { + message: msg, + stack: err?.stack, + }); +}); +// connect 시도 (커넥션 실패시 앱크래시 방지) +redisClient.connect().catch((err) => { + logger.error('Redis connect error', { message: err?.message, stack: err?.stack }); +}); diff --git a/src/core/utils/qetag.ts b/src/core/utils/qetag.ts new file mode 100644 index 00000000..12ef0990 --- /dev/null +++ b/src/core/utils/qetag.ts @@ -0,0 +1,114 @@ +import { Buffer } from 'buffer'; +import crypto from 'crypto'; +import fs from 'fs'; +import { Stream, Readable } from 'stream'; +import { Logger } from 'kv-logger'; +import { AppError } from '../app-error'; + +// 计算文件的eTag,参数为buffer或者readableStream或者文件路径 +function getEtag(buffer: string | Stream | Buffer, callback: (etag: string) => void) { + // 判断传入的参数是buffer还是stream还是filepath + let mode = 'buffer'; + + if (typeof buffer === 'string') { + // eslint-disable-next-line no-param-reassign + buffer = fs.createReadStream(buffer); + mode = 'stream'; + } else if (buffer instanceof Stream) { + mode = 'stream'; + } + + // sha1算法 + const sha1 = (content) => { + const sha1Hash = crypto.createHash('sha1'); + sha1Hash.update(content); + return sha1Hash.digest(); + }; + + // 以4M为单位分割 + const blockSize = 4 * 1024 * 1024; + const sha1String = []; + let prefix = 0x16; + let blockCount = 0; + + const calcEtag = () => { + if (!sha1String.length) { + return 'Fto5o-5ea0sNMlW_75VgGJCv2AcJ'; + } + let sha1Buffer = Buffer.concat(sha1String, blockCount * 20); + + // 如果大于4M,则对各个块的sha1结果再次sha1 + if (blockCount > 1) { + prefix = 0x96; + sha1Buffer = sha1(sha1Buffer); + } + + sha1Buffer = Buffer.concat([Buffer.from([prefix]), sha1Buffer], sha1Buffer.length + 1); + + return sha1Buffer.toString('base64').replace(/\//g, '_').replace(/\+/g, '-'); + }; + + switch (mode) { + case 'buffer': { + const buf = buffer as Buffer; + const bufferSize = buf.length; + blockCount = Math.ceil(bufferSize / blockSize); + + for (let i = 0; i < blockCount; i += 1) { + sha1String.push(sha1(buf.slice(i * blockSize, (i + 1) * blockSize))); + } + process.nextTick(() => { + callback(calcEtag()); + }); + break; + } + case 'stream': { + const stream = buffer as Readable; + stream.on('readable', () => { + for (;;) { + const chunk = stream.read(blockSize); + if (!chunk) { + break; + } + sha1String.push(sha1(chunk)); + blockCount += 1; + } + }); + stream.on('end', () => { + callback(calcEtag()); + }); + + break; + } + default: + // cannot be here + break; + } +} + +// TODO: support only files (string)? +export function qetag(buffer: string | Stream | Buffer, logger: Logger): Promise { + if (typeof buffer === 'string') { + // it's a file + try { + logger.debug(`Check upload file ${buffer} fs.R_OK`); + fs.accessSync(buffer, fs.constants.R_OK); + logger.debug(`Check upload file ${buffer} fs.R_OK pass`); + } catch (e) { + logger.error(e); + return Promise.reject(new AppError(e.message)); + } + } + logger.debug(`generate file identical`); + return new Promise((resolve) => { + getEtag(buffer, (data) => { + if (typeof buffer === 'string') { + logger.debug('identical:', { + file: buffer, + etag: data, + }); + } + resolve(data); + }); + }); +} diff --git a/src/core/utils/security.ts b/src/core/utils/security.ts new file mode 100644 index 00000000..5cf76528 --- /dev/null +++ b/src/core/utils/security.ts @@ -0,0 +1,196 @@ +import crypto from 'crypto'; +import fs from 'fs'; +import path from 'path'; +import bcrypt from 'bcryptjs'; +import { logger } from 'kv-logger'; +import _ from 'lodash'; +import { generator } from 'rand-token'; +import recursive from 'recursive-readdir'; +import slash from 'slash'; +import { AppError } from '../app-error'; +import { ANDROID, IOS } from '../const'; + +export function md5(str: string) { + const md5sum = crypto.createHash('md5'); + md5sum.update(str); + return md5sum.digest('hex'); +} + +export function passwordHashSync(password: string) { + return bcrypt.hashSync(password, bcrypt.genSaltSync(12)); +} + +export function passwordVerifySync(password: string, hash: string) { + return bcrypt.compareSync(password, hash); +} + +const randTokenGen = generator({ + chars: '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ', + source: 'crypto', +}); + +export function randToken(num: number) { + return randTokenGen.generate(num); +} + +export function parseToken(token: string) { + return { identical: token.substring(token.length - 9), token: token.substring(0, 28) }; +} + +function fileSha256(file: string): Promise { + return new Promise((resolve, reject) => { + const rs = fs.createReadStream(file); + const hash = crypto.createHash('sha256'); + rs.on('data', hash.update.bind(hash)); + rs.on('error', (e) => { + reject(e); + }); + rs.on('end', () => { + resolve(hash.digest('hex')); + }); + }); +} + +function stringSha256Sync(contents: string) { + const sha256 = crypto.createHash('sha256'); + sha256.update(contents); + return sha256.digest('hex'); +} + +function sortJsonToArr(json: Record) { + const rs: { path: string; hash: string }[] = []; + _.forIn(json, (value, key) => { + rs.push({ path: key, hash: value }); + }); + return _.sortBy(rs, (o) => o.path); +} + +// some files are ignored in calc hash in client sdk +// https://github.com/Microsoft/react-native-code-push/pull/974/files#diff-21b650f88429c071b217d46243875987R15 +function isHashIgnored(relativePath: string) { + if (!relativePath) { + return true; + } + + const IgnoreMacOSX = '__MACOSX/'; + const IgnoreDSStore = '.DS_Store'; + + return ( + relativePath.startsWith(IgnoreMacOSX) || + relativePath === IgnoreDSStore || + relativePath.endsWith(IgnoreDSStore) + ); +} + +function isPackageHashIgnored(relativePath: string) { + if (!relativePath) { + return true; + } + + // .codepushrelease contains code sign JWT + // it should be ignored in package hash but need to be included in package manifest + const IgnoreCodePushMetadata = '.codepushrelease'; + return ( + relativePath === IgnoreCodePushMetadata || + relativePath.endsWith(IgnoreCodePushMetadata) || + isHashIgnored(relativePath) + ); +} + +export function packageHashSync(jsonData: Record) { + const sortedArr = sortJsonToArr(jsonData); + const manifestData = _.filter(sortedArr, (v) => { + return !isPackageHashIgnored(v.path); + }).map((v) => { + return `${v.path}:${v.hash}`; + }); + let manifestString = JSON.stringify(manifestData.sort()); + manifestString = _.replace(manifestString, /\\\//g, '/'); + logger.debug('packageHashSync manifestString', { + manifestString, + }); + return stringSha256Sync(manifestString); +} + +function sha256AllFiles(files: string[]): Promise> { + return new Promise((resolve) => { + const results: Record = {}; + const { length } = files; + let count = 0; + files.forEach((file) => { + fileSha256(file).then((hash) => { + results[file] = hash; + count += 1; + if (count === length) { + resolve(results); + } + }); + }); + }); +} + +export function uploadPackageType(directoryPath: string) { + return new Promise((resolve, reject) => { + recursive(directoryPath, (err, files) => { + if (err) { + logger.error(new AppError(err.message)); + reject(new AppError(err.message)); + } else if (files.length === 0) { + logger.debug(`uploadPackageType empty files`); + reject(new AppError('empty files')); + } else { + const aregex = /android\.bundle/; + const aregexIOS = /main\.jsbundle/; + let packageType = 0; + _.forIn(files, (value: string) => { + if (aregex.test(value)) { + packageType = ANDROID; + return false; + } + if (aregexIOS.test(value)) { + packageType = IOS; + return false; + } + + return undefined; + }); + logger.debug(`uploadPackageType packageType: ${packageType}`); + resolve(packageType); + } + }); + }); +} + +export function calcAllFileSha256(directoryPath: string): Promise> { + return new Promise((resolve, reject) => { + recursive(directoryPath, (error, files) => { + if (error) { + logger.error(error); + reject(new AppError(error.message)); + } else { + // filter files that should be ignored + // eslint-disable-next-line no-param-reassign + files = files.filter((file) => { + const relative = path.relative(directoryPath, file); + return !isHashIgnored(relative); + }); + + if (files.length === 0) { + logger.debug(`calcAllFileSha256 empty files in directory`, { directoryPath }); + reject(new AppError('empty files')); + } else { + sha256AllFiles(files).then((results) => { + const data: Record = {}; + _.forIn(results, (value, key) => { + let relativePath = path.relative(directoryPath, key); + relativePath = slash(relativePath); + data[relativePath] = value; + }); + logger.debug(`calcAllFileSha256 files:`, data); + resolve(data); + }); + } + } + }); + }); +} diff --git a/src/core/utils/storage.ts b/src/core/utils/storage.ts new file mode 100644 index 00000000..ca9d0087 --- /dev/null +++ b/src/core/utils/storage.ts @@ -0,0 +1,276 @@ +import fs from 'fs'; +import path from 'path'; + +import { S3Client } from '@aws-sdk/client-s3'; +import { Upload } from '@aws-sdk/lib-storage'; + +import ALYOSSStream from 'aliyun-oss-upload-stream'; +import ALY from 'aliyun-sdk'; +import COS from 'cos-nodejs-sdk-v5'; +import fsextra from 'fs-extra'; +import { Logger } from 'kv-logger'; +import _ from 'lodash'; +import qiniu from 'qiniu'; +import { AppError } from '../app-error'; +import { config } from '../config'; + +function uploadFileToLocal(key: string, filePath: string, logger: Logger): Promise { + return new Promise((resolve, reject) => { + logger.info(`try uploadFileToLocal`, { + key, + }); + + const storageDir = _.get(config, 'local.storageDir'); + if (!storageDir) { + throw new AppError('please set config local storageDir'); + } + if (key.length < 3) { + logger.error(`generate key is too short, key value:${key}`); + throw new AppError('generate key is too short.'); + } + try { + logger.debug(`uploadFileToLocal check directory ${storageDir} fs.W_OK`); + fs.accessSync(storageDir, fs.constants.W_OK); + logger.debug(`uploadFileToLocal directory ${storageDir} fs.W_OK is ok`); + } catch (err) { + throw new AppError(err); + } + const subDir = key.substring(0, 2).toLowerCase(); + const finalDir = path.join(storageDir, subDir); + const fileName = path.join(finalDir, key); + if (fs.existsSync(fileName)) { + logger.info(`uploadFileToLocal file exists, skip copy`, { + key, + }); + + resolve(); + return; + } + let stats = fs.statSync(storageDir); + if (!stats.isDirectory()) { + throw new AppError(`${storageDir} must be directory`); + } + if (!fs.existsSync(`${finalDir}`)) { + fs.mkdirSync(`${finalDir}`); + logger.info(`uploadFileToLocal mkdir:${finalDir}`, { + key, + }); + } + try { + fs.accessSync(filePath, fs.constants.R_OK); + } catch (err) { + throw new AppError(err); + } + stats = fs.statSync(filePath); + if (!stats.isFile()) { + throw new AppError(`${filePath} must be file`); + } + fsextra.copy(filePath, fileName, (err) => { + if (err) { + reject(new AppError(err)); + return; + } + logger.info(`uploadFileToLocal copy file success.`, { + key, + }); + resolve(); + }); + }); +} + +function uploadFileToS3(key: string, filePath: string, logger: Logger): Promise { + return new Promise((resolve, reject) => { + logger.info('try uploadFileToS3', { key }); + + // config.s3.prefix에서 prefix 읽기 + let prefix = _.get(config, 's3.prefix', '') as string | undefined; + prefix = (prefix || '').trim(); + + if (prefix.length > 0 && !prefix.endsWith('/')) { + prefix += '/'; + } + + const finalKey = prefix ? `${prefix}${key}` : key; + logger.info('uploadFileToS3 resolved finalKey', { key: finalKey }); + + const accessKeyId = _.get(config, 's3.accessKeyId'); + const secretAccessKey = _.get(config, 's3.secretAccessKey'); + const sessionToken = _.get(config, 's3.sessionToken'); + const region = _.get(config, 's3.region'); + const bucketName = _.get(config, 's3.bucketName'); + + if (!accessKeyId || !secretAccessKey) { + reject(new AppError('Invalid AWS Credentials')); + return; + } + + const s3Client = new S3Client({ + region, + credentials: { + accessKeyId, + secretAccessKey, + ...(sessionToken && { sessionToken }), + }, + }); + + const bodyStream = fs.createReadStream(filePath); + + const upload = new Upload({ + client: s3Client, + params: { + Bucket: bucketName, + Key: finalKey, // prefix 적용된 key + Body: bodyStream, + ACL: 'public-read', // 구버전 함수의 ACL 유지 + }, + }); + + upload + .done() + .then(() => { + logger.info('uploadFileToS3 success', { key: finalKey }); + resolve(); + }) + .catch((error: unknown) => { + if (error instanceof Error) { + reject(new AppError(error)); + } + reject(new AppError(String(error))); + }); + }); +} + +function uploadFileToOSS(key: string, filePath: string, logger: Logger): Promise { + logger.info('try uploadFileToOSS', { key }); + const ossStream = ALYOSSStream( + new ALY.OSS({ + accessKeyId: _.get(config, 'oss.accessKeyId'), + secretAccessKey: _.get(config, 'oss.secretAccessKey'), + endpoint: _.get(config, 'oss.endpoint'), + apiVersion: '2013-10-15', + }), + ); + if (!_.isEmpty(_.get(config, 'oss.prefix', ''))) { + // eslint-disable-next-line no-param-reassign + key = `${_.get(config, 'oss.prefix')}/${key}`; + } + const upload = ossStream.upload({ + Bucket: _.get(config, 'oss.bucketName'), + Key: key, + }); + + return new Promise((resolve, reject) => { + upload.on('error', (error) => { + reject(new AppError(JSON.stringify(error))); + }); + + upload.on('uploaded', () => { + logger.info('uploadFileToOSS success', { key }); + resolve(); + }); + fs.createReadStream(filePath).pipe(upload); + }); +} + +function getUploadTokenQiniu(mac: qiniu.auth.digest.Mac, bucket: string, key: string) { + const options = { + scope: `${bucket}:${key}`, + }; + const putPolicy = new qiniu.rs.PutPolicy(options); + return putPolicy.uploadToken(mac); +} + +function uploadFileToQiniu(key: string, filePath: string, logger: Logger): Promise { + return new Promise((resolve, reject) => { + logger.info('try uploadFileToQiniu', { key }); + const accessKey = _.get(config, 'qiniu.accessKey'); + const secretKey = _.get(config, 'qiniu.secretKey'); + const bucket = _.get(config, 'qiniu.bucketName', ''); + const mac = new qiniu.auth.digest.Mac(accessKey, secretKey); + const conf = new qiniu.conf.Config(); + const bucketManager = new qiniu.rs.BucketManager(mac, conf); + bucketManager.stat(bucket, key, (respErr, respBody, respInfo) => { + if (respErr) { + reject(new AppError(respErr.message)); + return; + } + if (respInfo.statusCode === 200) { + logger.info('uploadFileToQiniu file exists, skip upload', { key }); + resolve(); + return; + } + + let uploadToken: string; + try { + uploadToken = getUploadTokenQiniu(mac, bucket, key); + } catch (e) { + reject(new AppError(e.message)); + return; + } + const formUploader = new qiniu.form_up.FormUploader(conf); + const putExtra = new qiniu.form_up.PutExtra(); + formUploader.putFile( + uploadToken, + key, + filePath, + putExtra, + (resErr, resBody, resInfo) => { + if (resErr) { + // 上传失败, 处理返回代码 + return reject(new AppError(resErr)); + } + // 上传成功, 处理返回值 + if (resInfo.statusCode === 200) { + logger.info('uploadFileToQiniu success', { key }); + return resolve(); + } + return reject(new AppError(resBody.error)); + }, + ); + }); + }); +} + +function uploadFileToTencentCloud(key: string, filePath: string, logger: Logger): Promise { + return new Promise((resolve, reject) => { + logger.info('try uploadFileToTencentCloud', { key }); + const cosIn = new COS({ + SecretId: _.get(config, 'tencentcloud.accessKeyId'), + SecretKey: _.get(config, 'tencentcloud.secretAccessKey'), + }); + cosIn.sliceUploadFile( + { + Bucket: _.get(config, 'tencentcloud.bucketName'), + Region: _.get(config, 'tencentcloud.region'), + Key: key, + FilePath: filePath, + }, + (err) => { + if (err) { + reject(new AppError(err.message)); + } else { + logger.info('uploadFileToTencentCloud success', { key }); + resolve(); + } + }, + ); + }); +} + +export function uploadFileToStorage(key: string, filePath: string, logger: Logger): Promise { + const { storageType } = config.common; + switch (storageType) { + case 'local': + return uploadFileToLocal(key, filePath, logger); + case 's3': + return uploadFileToS3(key, filePath, logger); + case 'oss': + return uploadFileToOSS(key, filePath, logger); + case 'qiniu': + return uploadFileToQiniu(key, filePath, logger); + case 'tencentcloud': + return uploadFileToTencentCloud(key, filePath, logger); + default: + throw new AppError(`${storageType} storageType does not support.`); + } +} diff --git a/src/db.ts b/src/db.ts new file mode 100755 index 00000000..33aee675 --- /dev/null +++ b/src/db.ts @@ -0,0 +1,172 @@ +#!/usr/bin/env node +/* eslint-disable no-console */ + +/** + * Module dependencies. + */ +import fs from 'fs'; +import path from 'path'; +import _ from 'lodash'; +import mysql from 'mysql2'; +import yargs from 'yargs'; +import { CURRENT_DB_VERSION } from './core/const'; + +const argv = yargs + .usage('Usage: $0 [options]') + .command('init', '데이터베이스 초기화', { + dbpassword: { + alias: 'dbpassword', + type: 'string', + }, + }) + .command('upgrade', '데이터베이스 업그레이드', { + dbpassword: { + alias: 'dbpassword', + type: 'string', + }, + }) + .example( + '$0 init --dbname codepush --dbhost localhost --dbuser root --dbpassword 123456 --dbport 3306 --force', + 'code-push-server 데이터베이스 초기화', + ) + .example( + '$0 upgrade --dbname codepush --dbhost localhost --dbuser root --dbpassword 123456 --dbport 3306', + 'code-push-server 데이터베이스 업그레이드', + ) + .default({ + dbname: 'codepush', + dbhost: 'localhost', + dbuser: 'codepush', + dbpassword: 'codepush', + }) + .help('h') + .alias('h', 'help') + .parseSync(); + +const command = argv._[0]; +const dbname = argv.dbname ? argv.dbname : 'codepush'; +const dbhost = argv.dbhost ? argv.dbhost : 'localhost'; +const dbuser = argv.dbuser ? argv.dbuser : 'codepush'; +const dbport = argv.dbport ? argv.dbport : 3306; +const { dbpassword } = argv; + +if (command === 'init') { + let connection2; + const connection = mysql + .createConnection({ + host: dbhost, + user: dbuser, + password: dbpassword, + port: dbport, + }) + .promise(); + const createDatabaseSql = argv.force + ? `CREATE DATABASE IF NOT EXISTS ${dbname}` + : `CREATE DATABASE ${dbname}`; + connection.connect(); + connection + .query(createDatabaseSql) + .then(() => { + connection2 = mysql + .createConnection({ + host: dbhost, + user: dbuser, + password: dbpassword, + database: dbname, + multipleStatements: true, + port: dbport, + }) + .promise(); + connection2.connect(); + return connection2; + }) + .then(() => { + const sql = fs.readFileSync( + path.resolve(__dirname, '../sql/codepush-all.sql'), + 'utf-8', + ); + return connection2.query(sql); + }) + .then(() => { + console.log('success.'); + }) + .catch((e) => { + console.log(e); + }) + .finally(() => { + if (connection) connection.end(); + if (connection2) connection2.end(); + }); +} else if (command === 'upgrade') { + let connection; + try { + connection = mysql + .createConnection({ + host: dbhost, + user: dbuser, + password: dbpassword, + database: dbname, + multipleStatements: true, + port: dbport, + }) + .promise(); + connection.connect(); + } catch (e) { + console.error('MySQL 연결 오류, 입력한 설정을 확인하세요.', e); + process.exit(1); + } + + let versionNo = '0.0.1'; + connection + .query('select `version` from `versions` where `type`=1 limit 1') + .then((rs) => { + versionNo = _.get(rs, '0.version', '0.0.1'); + if (versionNo === CURRENT_DB_VERSION) { + console.log('모든 항목이 최신 버전입니다.'); + process.exit(0); + } + const allSqlFile = [ + { + version: '0.2.14', + path: path.resolve(__dirname, '../sql/codepush-v0.2.14-patch.sql'), + }, + { + version: '0.2.15', + path: path.resolve(__dirname, '../sql/codepush-v0.2.15-patch.sql'), + }, + { + version: '0.3.0', + path: path.resolve(__dirname, '../sql/codepush-v0.3.0-patch.sql'), + }, + { + version: '0.4.0', + path: path.resolve(__dirname, '../sql/codepush-v0.4.0-patch.sql'), + }, + { + version: '0.5.0', + path: path.resolve(__dirname, '../sql/codepush-v0.5.0-patch.sql'), + }, + ]; + return allSqlFile.reduce((prev, sqlFile) => { + if (!_.gt(sqlFile.version, versionNo)) { + return prev; + } + const sql = fs.readFileSync(sqlFile.path, 'utf-8'); + console.log(`SQL 파일 실행 중: ${sqlFile.path}`); + return connection.query(sql).then(() => { + console.log(`SQL 파일 실행 성공: ${sqlFile.path}`); + }); + }, Promise.resolve()); + }) + .then(() => { + console.log('업그레이드 성공.'); + }) + .catch((e) => { + console.error(e); + }) + .finally(() => { + if (connection) connection.end(); + }); +} else { + yargs.showHelp(); +} diff --git a/src/locales/en.json b/src/locales/en.json new file mode 100644 index 00000000..d30da7e8 --- /dev/null +++ b/src/locales/en.json @@ -0,0 +1,32 @@ +{ + "Please sign in": "Please sign in", + "email address": "email address", + "username": "username", + "password": "password", + "Remember me": "Remember me", + "Log in": "Log in", + "hot update server": "hot update server", + "Change Password": "Change Password", + "Obtain": "Obtain", + "old password": "old password", + "new password": "new password", + "please login again": "please login again", + "change success": "change success", + "Logout": "Logout", + "Register": "Register", + "server.name": "CodePush Server", + "error.input_email_required": "Please enter your email address.", + "error.input_password_required": "Please enter your password.", + "error.invalid_credentials": "The email or password you entered is incorrect.", + "error.password_retry_limit_exceeded": "Your account has been locked due to too many failed login attempts.", + "error.email_already_registered": "{{email}} is already registered. Please use a different email address.", + "error.verify_code_expired": "The verification code has expired. Please request a new one.", + "error.verify_code_invalid": "The verification code is incorrect. Please try again.", + "error.new_password_length": "Please enter a new password between 6 and 20 characters.", + "error.password_length_register": "Please enter a password between 6 and 20 characters.", + "error.user_not_found": "User information could not be found.", + "error.old_password_incorrect": "The current password you entered is incorrect.", + "error.app_not_exists": "The app information could not be found.", + "error.permission_denied_not_owner": "Permission denied. You are not the owner.", + "error.email_not_exists": "The specified email address does not exist." +} diff --git a/src/locales/ko.json b/src/locales/ko.json new file mode 100644 index 00000000..ca90eefd --- /dev/null +++ b/src/locales/ko.json @@ -0,0 +1,32 @@ +{ + "Please sign in": "로그인을 해주세요", + "email address": "이메일 주소", + "username": "사용자명", + "password": "비밀번호", + "Remember me": "로그인 상태 유지", + "Log in": "로그인", + "hot update server": "OTA 업데이트 서버", + "Change Password": "비밀번호 변경", + "Obtain": "발급", + "old password": "현재 비밀번호", + "new password": "새 비밀번호", + "please login again": "다시 로그인해주세요", + "change success": "변경되었습니다", + "Logout": "로그아웃", + "Register": "회원가입", + "server.name": "코드푸시 서버", + "error.input_email_required": "이메일 주소를 입력해주세요.", + "error.input_password_required": "비밀번호를 입력해주세요.", + "error.invalid_credentials": "이메일 또는 비밀번호가 올바르지 않습니다.", + "error.password_retry_limit_exceeded": "비밀번호 오류 횟수가 제한을 초과하여 계정이 잠겼습니다.", + "error.email_already_registered": "{{email}}은 이미 등록된 이메일입니다. 다른 이메일을 사용해주세요.", + "error.verify_code_expired": "인증 코드가 만료되었습니다. 다시 발급받아주세요.", + "error.verify_code_invalid": "인증 코드가 올바르지 않습니다. 다시 입력해주세요.", + "error.new_password_length": "새 비밀번호는 6~20자 사이로 입력해주세요.", + "error.password_length_register": "비밀번호는 6~20자 사이로 입력해주세요.", + "error.user_not_found": "사용자 정보를 찾을 수 없습니다.", + "error.old_password_incorrect": "현재 비밀번호가 올바르지 않습니다. 다시 입력해주세요.", + "error.app_not_exists": "앱 정보를 찾을 수 없습니다.", + "error.permission_denied_not_owner": "권한이 없습니다. Owner 계정이 아닙니다.", + "error.email_not_exists": "해당 이메일을 찾을 수 없습니다." +} diff --git a/src/locales/zh.json b/src/locales/zh.json new file mode 100644 index 00000000..d7b47394 --- /dev/null +++ b/src/locales/zh.json @@ -0,0 +1,32 @@ +{ + "Please sign in": "请登录", + "email address": "邮箱地址", + "username": "用户名", + "password": "密码", + "Remember me": "记住我", + "Log in": "登录", + "hot update server": "热更新服务器", + "Change Password": "修改密码", + "Obtain": "获取", + "old password": "原密码", + "new password": "新密码", + "please login again": "请重新登录", + "change success": "修改成功", + "Logout": "登出", + "Register": "注册", + "server.name": "CodePush 服务器", + "error.input_email_required": "请您输入邮箱地址", + "error.input_password_required": "请您输入密码", + "error.invalid_credentials": "您输入的邮箱或密码有误", + "error.password_retry_limit_exceeded": "您输入密码错误次数超过限制,帐户已经锁定", + "error.email_already_registered": "{{email}}已经注册过,请更换邮箱注册", + "error.verify_code_expired": "验证码已经失效,请您重新获取", + "error.verify_code_invalid": "您输入的验证码不正确,请重新输入", + "error.new_password_length": "请您输入6~20位长度的新密码", + "error.password_length_register": "请您输入6~20位长度的密码", + "error.user_not_found": "未找到用户信息", + "error.old_password_incorrect": "您输入的旧密码不正确,请重新输入", + "error.app_not_exists": "应用不存在", + "error.permission_denied_not_owner": "权限不足,您不是该应用的 Owner", + "error.email_not_exists": "该邮箱不存在" +} diff --git a/src/models/apps.ts b/src/models/apps.ts new file mode 100644 index 00000000..78264ed0 --- /dev/null +++ b/src/models/apps.ts @@ -0,0 +1,40 @@ +import { DataTypes, Model } from 'sequelize'; +import { sequelize } from '../core/utils/connections'; + +export interface AppsInterface extends Model { + id: number; + name: string; + uid: number; + os: number; + platform: number; + /** + * @deprecated is_use_diff_text is no longer supported + */ + is_use_diff_text: number; + created_at: Date; + updated_at: Date; +} + +export const Apps = sequelize.define( + 'Apps', + { + id: { + type: DataTypes.INTEGER({ length: 10 }), + allowNull: false, + autoIncrement: true, + primaryKey: true, + }, + name: DataTypes.STRING, + uid: DataTypes.BIGINT({ length: 20 }), + os: DataTypes.INTEGER({ length: 3 }), + platform: DataTypes.INTEGER({ length: 3 }), + is_use_diff_text: DataTypes.INTEGER({ length: 3 }), + created_at: DataTypes.DATE, + updated_at: DataTypes.DATE, + }, + { + tableName: 'apps', + underscored: true, + paranoid: true, + }, +); diff --git a/src/models/collaborators.ts b/src/models/collaborators.ts new file mode 100644 index 00000000..3f38cb0a --- /dev/null +++ b/src/models/collaborators.ts @@ -0,0 +1,43 @@ +import { DataTypes, Model } from 'sequelize'; +import { sequelize } from '../core/utils/connections'; + +export interface CollaboratorsInterface extends Model { + id: number; + appid: number; + uid: number; + roles: string; + created_at: Date; + updated_at: Date; +} + +export const Collaborators = sequelize.define( + 'Collaborators', + { + id: { + type: DataTypes.BIGINT({ length: 20 }), + allowNull: false, + autoIncrement: true, + primaryKey: true, + }, + appid: DataTypes.INTEGER({ length: 10 }), + uid: DataTypes.BIGINT({ length: 20 }), + roles: DataTypes.STRING, + created_at: DataTypes.DATE, + updated_at: DataTypes.DATE, + }, + { + tableName: 'collaborators', + underscored: true, + paranoid: true, + }, +); + +export async function findCollaboratorsByAppNameAndUid(uid: number, appName: string) { + const sql = + 'SELECT b.* FROM `apps` as a left join `collaborators` as b on (a.id = b.appid) where a.name= :appName and b.uid = :uid and a.`deleted_at` IS NULL and b.`deleted_at` IS NULL limit 0,1'; + const data = await sequelize.query(sql, { + replacements: { appName, uid }, + model: Collaborators, + }); + return data.pop(); +} diff --git a/src/models/deployments.ts b/src/models/deployments.ts new file mode 100644 index 00000000..b1e1dbb2 --- /dev/null +++ b/src/models/deployments.ts @@ -0,0 +1,58 @@ +import _ from 'lodash'; +import { DataTypes, Model } from 'sequelize'; +import { AppError } from '../core/app-error'; +import { sequelize } from '../core/utils/connections'; + +interface DeploymentsInterface extends Model { + id: number; + appid: number; + name: string; + description: string; + deployment_key: string; + last_deployment_version_id: number; + label_id: number; + created_at: Date; + updated_at: Date; +} + +export const Deployments = sequelize.define( + 'Deployments', + { + id: { + type: DataTypes.INTEGER({ length: 10 }), + allowNull: false, + autoIncrement: true, + primaryKey: true, + }, + appid: DataTypes.INTEGER({ length: 10 }), + name: DataTypes.STRING, + description: DataTypes.STRING, + deployment_key: DataTypes.STRING, + last_deployment_version_id: DataTypes.INTEGER({ length: 10 }), + label_id: DataTypes.INTEGER({ length: 10 }), + created_at: DataTypes.DATE, + updated_at: DataTypes.DATE, + }, + { + tableName: 'deployments', + underscored: true, + paranoid: true, + }, +); + +export function generateDeploymentsLabelId(deploymentId: number) { + return sequelize.transaction((t) => { + return Deployments.findByPk(deploymentId, { + transaction: t, + lock: t.LOCK.UPDATE, + }).then((data) => { + if (_.isEmpty(data)) { + throw new AppError('does not find deployment'); + } + data.label_id += 1; + return data.save({ transaction: t }).then((d) => { + return d.label_id; + }); + }); + }); +} diff --git a/src/models/deployments_history.ts b/src/models/deployments_history.ts new file mode 100644 index 00000000..fae17b99 --- /dev/null +++ b/src/models/deployments_history.ts @@ -0,0 +1,30 @@ +import { DataTypes, Model } from 'sequelize'; +import { sequelize } from '../core/utils/connections'; + +interface DeploymentsHistoryInterface extends Model { + id: number; + deployment_id: number; + package_id: number; + created_at: Date; +} + +export const DeploymentsHistory = sequelize.define( + 'DeploymentsHistory', + { + id: { + type: DataTypes.INTEGER({ length: 10 }), + allowNull: false, + autoIncrement: true, + primaryKey: true, + }, + deployment_id: DataTypes.INTEGER({ length: 10 }), + package_id: DataTypes.INTEGER({ length: 10 }), + created_at: DataTypes.DATE, + }, + { + tableName: 'deployments_history', + underscored: true, + updatedAt: false, + paranoid: true, + }, +); diff --git a/src/models/deployments_versions.ts b/src/models/deployments_versions.ts new file mode 100644 index 00000000..af45c387 --- /dev/null +++ b/src/models/deployments_versions.ts @@ -0,0 +1,37 @@ +import { DataTypes, Model } from 'sequelize'; +import { sequelize } from '../core/utils/connections'; + +export interface DeploymentsVersionsInterface extends Model { + id: number; + deployment_id: number; + app_version: string; + current_package_id: number; + min_version: number; + max_version: number; + created_at: Date; + updated_at: Date; +} + +export const DeploymentsVersions = sequelize.define( + 'DeploymentsVersions', + { + id: { + type: DataTypes.INTEGER({ length: 10 }), + allowNull: false, + autoIncrement: true, + primaryKey: true, + }, + deployment_id: DataTypes.INTEGER({ length: 10 }), + app_version: DataTypes.STRING, + current_package_id: DataTypes.INTEGER({ length: 10 }), + min_version: DataTypes.BIGINT({ length: 20 }), + max_version: DataTypes.BIGINT({ length: 20 }), + created_at: DataTypes.DATE, + updated_at: DataTypes.DATE, + }, + { + tableName: 'deployments_versions', + underscored: true, + paranoid: true, + }, +); diff --git a/src/models/log_report_deploy.ts b/src/models/log_report_deploy.ts new file mode 100644 index 00000000..4a6341b1 --- /dev/null +++ b/src/models/log_report_deploy.ts @@ -0,0 +1,36 @@ +import { DataTypes, Model } from 'sequelize'; +import { sequelize } from '../core/utils/connections'; + +interface LogReportDeployInterface extends Model { + id: number; + status: number; + package_id: number; + client_unique_id: string; + previous_label: string; + previous_deployment_key: string; + created_at: Date; +} + +export const LogReportDeploy = sequelize.define( + 'LogReportDeploy', + { + id: { + type: DataTypes.BIGINT({ length: 20 }), + allowNull: false, + autoIncrement: true, + primaryKey: true, + }, + status: DataTypes.INTEGER({ length: 3 }), + package_id: DataTypes.INTEGER({ length: 10 }), + client_unique_id: DataTypes.STRING, + previous_label: DataTypes.STRING, + previous_deployment_key: DataTypes.STRING, + created_at: DataTypes.DATE, + }, + { + tableName: 'log_report_deploy', + underscored: true, + updatedAt: false, + paranoid: true, + }, +); diff --git a/src/models/log_report_download.ts b/src/models/log_report_download.ts new file mode 100644 index 00000000..1a3b20b7 --- /dev/null +++ b/src/models/log_report_download.ts @@ -0,0 +1,30 @@ +import { DataTypes, Model } from 'sequelize'; +import { sequelize } from '../core/utils/connections'; + +interface LogReportDownloadInterface extends Model { + id: number; + package_id: number; + client_unique_id: string; + created_at: Date; +} + +export const LogReportDownload = sequelize.define( + 'LogReportDownload', + { + id: { + type: DataTypes.BIGINT({ length: 20 }), + allowNull: false, + autoIncrement: true, + primaryKey: true, + }, + package_id: DataTypes.INTEGER({ length: 10 }), + client_unique_id: DataTypes.STRING, + created_at: DataTypes.DATE, + }, + { + tableName: 'log_report_download', + underscored: true, + updatedAt: false, + paranoid: true, + }, +); diff --git a/src/models/packages.ts b/src/models/packages.ts new file mode 100644 index 00000000..5d66b644 --- /dev/null +++ b/src/models/packages.ts @@ -0,0 +1,57 @@ +import { DataTypes, Model } from 'sequelize'; +import { sequelize } from '../core/utils/connections'; + +export interface PackagesInterface extends Model { + id: number; + deployment_version_id: number; + deployment_id: number; + description: string; + package_hash: string; + blob_url: string; + size: number; + manifest_blob_url: string; + release_method: string; + label: string; + original_label: string; + original_deployment: string; + released_by: number; + is_mandatory: number; + is_disabled: number; + rollout: number; + created_at: Date; + updated_at: Date; +} + +export const Packages = sequelize.define( + 'Packages', + { + id: { + type: DataTypes.INTEGER({ length: 10 }), + allowNull: false, + autoIncrement: true, + primaryKey: true, + }, + deployment_version_id: DataTypes.INTEGER({ length: 10 }), + deployment_id: DataTypes.INTEGER({ length: 10 }), + description: DataTypes.STRING, + package_hash: DataTypes.STRING, + blob_url: DataTypes.STRING, + size: DataTypes.INTEGER({ length: 10 }), + manifest_blob_url: DataTypes.STRING, + release_method: DataTypes.STRING, + label: DataTypes.STRING, + original_label: DataTypes.STRING, + original_deployment: DataTypes.STRING, + released_by: DataTypes.BIGINT({ length: 20 }), + is_mandatory: DataTypes.INTEGER({ length: 3 }), + is_disabled: DataTypes.INTEGER({ length: 3 }), + rollout: DataTypes.INTEGER({ length: 3 }), + created_at: DataTypes.DATE, + updated_at: DataTypes.DATE, + }, + { + tableName: 'packages', + underscored: true, + paranoid: true, + }, +); diff --git a/src/models/packages_diff.ts b/src/models/packages_diff.ts new file mode 100644 index 00000000..32d5807c --- /dev/null +++ b/src/models/packages_diff.ts @@ -0,0 +1,35 @@ +import { DataTypes, Model } from 'sequelize'; +import { sequelize } from '../core/utils/connections'; + +interface PackagesDiffInterface extends Model { + id: number; + package_id: number; + diff_against_package_hash: string; + diff_blob_url: string; + diff_size: number; + created_at: Date; + updated_at: Date; +} + +export const PackagesDiff = sequelize.define( + 'PackagesDiff', + { + id: { + type: DataTypes.INTEGER({ length: 10 }), + allowNull: false, + autoIncrement: true, + primaryKey: true, + }, + package_id: DataTypes.INTEGER({ length: 10 }), + diff_against_package_hash: DataTypes.STRING, + diff_blob_url: DataTypes.STRING, + diff_size: DataTypes.INTEGER({ length: 10 }), + created_at: DataTypes.DATE, + updated_at: DataTypes.DATE, + }, + { + tableName: 'packages_diff', + underscored: true, + paranoid: true, + }, +); diff --git a/src/models/packages_metrics.ts b/src/models/packages_metrics.ts new file mode 100644 index 00000000..5108aed3 --- /dev/null +++ b/src/models/packages_metrics.ts @@ -0,0 +1,37 @@ +import { DataTypes, Model } from 'sequelize'; +import { sequelize } from '../core/utils/connections'; + +interface PackagesMetricsInterface extends Model { + id: number; + package_id: number; + active: number; + downloaded: number; + failed: number; + installed: number; + created_at: Date; + updated_at: Date; +} + +export const PackagesMetrics = sequelize.define( + 'PackagesMetrics', + { + id: { + type: DataTypes.INTEGER({ length: 10 }), + allowNull: false, + autoIncrement: true, + primaryKey: true, + }, + package_id: DataTypes.INTEGER({ length: 10 }), + active: DataTypes.INTEGER({ length: 10 }), + downloaded: DataTypes.INTEGER({ length: 10 }), + failed: DataTypes.INTEGER({ length: 10 }), + installed: DataTypes.INTEGER({ length: 10 }), + created_at: DataTypes.DATE, + updated_at: DataTypes.DATE, + }, + { + tableName: 'packages_metrics', + underscored: true, + paranoid: true, + }, +); diff --git a/src/models/user_tokens.ts b/src/models/user_tokens.ts new file mode 100644 index 00000000..4b723633 --- /dev/null +++ b/src/models/user_tokens.ts @@ -0,0 +1,40 @@ +import { DataTypes, Model } from 'sequelize'; +import { sequelize } from '../core/utils/connections'; + +interface UserTokensInterface extends Model { + id: number; + uid: number; + name: string; + tokens: string; + description: string; + is_session: number; + created_by: string; + created_at: Date; + expires_at: Date; +} + +export const UserTokens = sequelize.define( + 'UserTokens', + { + id: { + type: DataTypes.BIGINT({ length: 20 }), + allowNull: false, + autoIncrement: true, + primaryKey: true, + }, + uid: DataTypes.BIGINT({ length: 20 }), + name: DataTypes.STRING, + tokens: DataTypes.STRING, + description: DataTypes.STRING, + is_session: DataTypes.INTEGER({ length: 3 }), + created_by: DataTypes.STRING, + created_at: DataTypes.DATE, + expires_at: DataTypes.DATE, + }, + { + updatedAt: false, + tableName: 'user_tokens', + underscored: true, + paranoid: true, + }, +); diff --git a/src/models/users.ts b/src/models/users.ts new file mode 100644 index 00000000..9228b4a5 --- /dev/null +++ b/src/models/users.ts @@ -0,0 +1,36 @@ +import { DataTypes, Model } from 'sequelize'; +import { sequelize } from '../core/utils/connections'; + +export interface UsersInterface extends Model { + id: number; + username: string; + password: string; + email: string; + identical: string; + ack_code: string; + created_at: Date; + updated_at: Date; +} + +export const Users = sequelize.define( + 'Users', + { + id: { + type: DataTypes.BIGINT({ length: 20 }), + allowNull: false, + autoIncrement: true, + primaryKey: true, + }, + username: DataTypes.STRING, + password: DataTypes.STRING, + email: DataTypes.STRING, + identical: DataTypes.STRING, + ack_code: DataTypes.STRING, + created_at: DataTypes.DATE, + updated_at: DataTypes.DATE, + }, + { + tableName: 'users', + underscored: true, + }, +); diff --git a/src/models/versions.ts b/src/models/versions.ts new file mode 100644 index 00000000..8a12172e --- /dev/null +++ b/src/models/versions.ts @@ -0,0 +1,27 @@ +import { DataTypes, Model } from 'sequelize'; +import { sequelize } from '../core/utils/connections'; + +interface VersionsInterface extends Model { + id: number; + type: number; + version: string; +} + +export const Versions = sequelize.define( + 'Versions', + { + id: { + type: DataTypes.INTEGER({ length: 10 }), + allowNull: false, + autoIncrement: true, + primaryKey: true, + }, + type: DataTypes.INTEGER, + version: DataTypes.STRING, + }, + { + tableName: 'versions', + updatedAt: false, + createdAt: false, + }, +); diff --git a/src/routes/accessKeys.ts b/src/routes/accessKeys.ts new file mode 100644 index 00000000..55bdba95 --- /dev/null +++ b/src/routes/accessKeys.ts @@ -0,0 +1,123 @@ +import express from 'express'; +import _ from 'lodash'; +import moment from 'moment'; +import { AppError } from '../core/app-error'; +import { checkToken, Req } from '../core/middleware'; +import { accountManager } from '../core/services/account-manager'; +import { randToken } from '../core/utils/security'; +import { UserTokens } from '../models/user_tokens'; + +export const accessKeysRouter = express.Router(); + +accessKeysRouter.get('/', checkToken, (req: Req, res, next) => { + const { logger } = req; + const uid = req.users.id; + logger.info('try get accessKeys', { uid }); + accountManager + .getAllAccessKeyByUid(uid) + .then((accessKeys) => { + logger.info('get accessKeys success', { uid }); + res.send({ accessKeys }); + }) + .catch((e) => { + next(e); + }); +}); + +accessKeysRouter.post( + '/', + checkToken, + ( + req: Req< + Record, + { + createdBy: string; + friendlyName: string; + ttl: string; + description: string; + } + >, + res, + next, + ) => { + const { logger, body } = req; + const uid = req.users.id; + const createdBy = _.trim(body.createdBy); + const friendlyName = _.trim(body.friendlyName); + // TODO: 엑세스토큰 만료일을 수정하고 싶은 경우 tokens.pug 에서 전송되는 ttl을 수정 + const ttl = parseInt(body.ttl, 10); // 현재 호출부 기본값 30일 = 60*60*24*30*1000 + const description = _.trim(body.description); + logger.info('try to generate access key', { + uid, + name: friendlyName, + body: JSON.stringify(body), + }); + return accountManager + .isExistAccessKeyName(uid, friendlyName) + .then((data) => { + if (!_.isEmpty(data)) { + throw new AppError(`The access key "${friendlyName}" already exists.`); + } + }) + .then(() => { + const { identical } = req.users; + const newAccessKey = randToken(28).concat(identical); + return accountManager.createAccessKey( + uid, + newAccessKey, + ttl, + friendlyName, + createdBy, + description, + ); + }) + .then((newToken) => { + const info = { + name: newToken.tokens, + createdTime: moment(newToken.created_at).valueOf(), + createdBy: newToken.created_by, + expires: moment(newToken.expires_at).valueOf(), + description: newToken.description, + friendlyName: newToken.name, + }; + logger.info('create access key success', { + uid, + name: newToken.name, + }); + res.send({ accessKey: info }); + }) + .catch((e) => { + if (e instanceof AppError) { + logger.info('create access key failed', { + uid, + name: friendlyName, + error: e.message, + }); + + res.status(406).send(e.message); + } else { + next(e); + } + }); + }, +); + +accessKeysRouter.delete('/:name', checkToken, (req: Req<{ name: string }>, res, next) => { + const { logger, params } = req; + const name = _.trim(params.name); + const uid = req.users.id; + logger.info('try to delete access key', { uid, name }); + return UserTokens.destroy({ where: { name, uid } }) + .then(() => { + logger.info('delete acceesKey success', { uid, name }); + res.send({ friendlyName: name }); + }) + .catch((e) => { + if (e instanceof AppError) { + logger.info('delete acceesKey failed', { uid, name }); + res.status(406).send(e.message); + } else { + next(e); + } + }); +}); diff --git a/src/routes/account.ts b/src/routes/account.ts new file mode 100644 index 00000000..5b7d5274 --- /dev/null +++ b/src/routes/account.ts @@ -0,0 +1,15 @@ +import express from 'express'; +import { checkToken, Req } from '../core/middleware'; + +export const accountRouter = express.Router(); + +accountRouter.get('/', checkToken, (req: Req, res) => { + const { logger } = req; + const account = { + email: req.users.email, + linkedProviders: [], + name: req.users.username, + }; + logger.info('check account info', { account: JSON.stringify(account) }); + res.send({ account }); +}); diff --git a/src/routes/apps.ts b/src/routes/apps.ts new file mode 100644 index 00000000..0e2d3ca6 --- /dev/null +++ b/src/routes/apps.ts @@ -0,0 +1,1265 @@ +/* eslint-disable max-lines */ +import express from 'express'; +import _ from 'lodash'; +import validator from 'validator'; +import { AppError } from '../core/app-error'; +import { config } from '../core/config'; +import { + IOS, + IOS_NAME, + ANDROID, + ANDROID_NAME, + WINDOWS, + WINDOWS_NAME, + REACT_NATIVE, + REACT_NATIVE_NAME, + CORDOVA, + CORDOVA_NAME, +} from '../core/const'; +import { checkToken, Req } from '../core/middleware'; +import { accountManager } from '../core/services/account-manager'; +import { appManager } from '../core/services/app-manager'; +import { clientManager } from '../core/services/client-manager'; +import { collaboratorsManager } from '../core/services/collaborators-manager'; +import { deploymentsManager } from '../core/services/deployments-manager'; +import { packageManager } from '../core/services/package-manager'; +import { deleteFolderSync } from '../core/utils/common'; +import { PackagesInterface } from '../models/packages'; + +function delay(ms: number) { + return new Promise((resolve) => { + setTimeout(resolve, ms); + }); +} + +export const appsRouter = express.Router(); + +appsRouter.get('/', checkToken, (req: Req, res, next) => { + const { logger } = req; + const uid = req.users.id; + logger.info('try list apps', { uid }); + appManager + .listApps(uid) + .then((data) => { + logger.info('list apps success', { uid }); + res.send({ apps: data }); + }) + .catch((e) => { + if (e instanceof AppError) { + logger.info('list apps failed', { uid, error: e.message }); + res.status(406).send(e.message); + } else { + next(e); + } + }); +}); + +appsRouter.get('/:appName/deployments', checkToken, (req: Req<{ appName: string }>, res, next) => { + const { logger, params } = req; + const uid = req.users.id; + const appName = _.trim(params.appName); + logger.info('try list deployments', { + uid, + appName, + }); + accountManager + .collaboratorCan(uid, appName, logger) + .then((col) => { + return deploymentsManager.listDeloyments(col.appid); + }) + .then((data) => { + logger.info('list deployments success', { + uid, + appName, + }); + res.send({ deployments: data }); + }) + .catch((e) => { + if (e instanceof AppError) { + logger.info('list deployments failed', { + uid, + appName, + error: e.message, + }); + res.status(406).send(e.message); + } else { + next(e); + } + }); +}); + +appsRouter.get( + '/:appName/deployments/:deploymentName', + checkToken, + (req: Req<{ appName: string; deploymentName: string }>, res, next) => { + const { logger, params } = req; + const uid = req.users.id; + const appName = _.trim(params.appName); + const deploymentName = _.trim(params.deploymentName); + logger.info('try to get deployment', { + uid, + appName, + deploymentName, + }); + accountManager + .collaboratorCan(uid, appName, logger) + .then((col) => { + return deploymentsManager.findDeloymentByName(deploymentName, col.appid, logger); + }) + .then((deploymentInfo) => { + if (_.isEmpty(deploymentInfo)) { + throw new AppError('does not find the deployment'); + } + logger.info('get deployment success', { + uid, + appName, + deploymentName, + }); + + // TODO: check if this works as expected + res.send({ deployment: deploymentsManager.listDeloyment(deploymentInfo) }); + return true; + }) + .catch((e) => { + if (e instanceof AppError) { + logger.info('get deployment failed', { + uid, + appName, + deploymentName, + error: e.message, + }); + + res.status(406).send(e.message); + } else { + next(e); + } + }); + }, +); + +appsRouter.post( + '/:appName/deployments', + checkToken, + (req: Req<{ appName: string }, { name: string }>, res, next) => { + const { logger, params, body } = req; + const uid = req.users.id; + const appName = _.trim(params.appName); + const { name } = body; + logger.info('try to create deployment', { + uid, + appName, + deploymentName: name, + }); + accountManager + .ownerCan(uid, appName, logger) + .then((col) => { + return deploymentsManager.addDeloyment(name, col.appid, uid); + }) + .then((data) => { + logger.info('create deployment success', { + uid, + appName, + deploymentName: data.name, + }); + + res.send({ deployment: { name: data.name, key: data.deployment_key } }); + }) + .catch((e) => { + if (e instanceof AppError) { + logger.info('create deployment failed', { + uid, + appName, + deploymentName: name, + }); + + res.status(406).send(e.message); + } else { + next(e); + } + }); + }, +); + +appsRouter.get( + '/:appName/deployments/:deploymentName/metrics', + checkToken, + (req: Req<{ appName: string; deploymentName: string }>, res, next) => { + const { logger, params } = req; + const uid = req.users.id; + const appName = _.trim(params.appName); + const deploymentName = _.trim(params.deploymentName); + logger.info('try to get deployment metrics', { + uid, + appName, + deploymentName, + }); + accountManager + .collaboratorCan(uid, appName, logger) + .then((col) => { + return deploymentsManager + .findDeloymentByName(deploymentName, col.appid, logger) + .then((deploymentInfo) => { + if (_.isEmpty(deploymentInfo)) { + throw new AppError('does not find the deployment'); + } + return deploymentInfo; + }); + }) + .then((deploymentInfo) => { + return deploymentsManager.getAllPackageIdsByDeploymentsId(deploymentInfo.id); + }) + .then((packagesInfos) => { + return packagesInfos.reduce( + (prev, v) => { + return prev.then((result) => { + return packageManager + .getMetricsbyPackageId(v.get('id')) + .then((metrics) => { + if (metrics) { + result[v.get('label')] = { + active: metrics.get('active'), + downloaded: metrics.get('downloaded'), + failed: metrics.get('failed'), + installed: metrics.get('installed'), + }; + } + return result; + }); + }); + }, + Promise.resolve( + {} as Record< + string, + { + active: number; + downloaded: number; + failed: number; + installed: number; + } + >, + ), + ); + }) + .then((rs) => { + logger.info('get deployment metrics success', { + uid, + appName, + deploymentName, + }); + + res.send({ metrics: rs }); + }) + .catch((e) => { + if (e instanceof AppError) { + logger.info('get deployment metrics failed', { + uid, + appName, + deploymentName, + error: e.message, + }); + + res.send({ metrics: null }); + } else { + next(e); + } + }); + }, +); + +appsRouter.get( + '/:appName/deployments/:deploymentName/history', + checkToken, + (req: Req<{ appName: string; deploymentName: string }>, res, next) => { + const { logger, params } = req; + const uid = req.users.id; + const appName = _.trim(params.appName); + const deploymentName = _.trim(params.deploymentName); + logger.info('try to get deployment history', { + uid, + appName, + deploymentName, + }); + accountManager + .collaboratorCan(uid, appName, logger) + .then((col) => { + return deploymentsManager + .findDeloymentByName(deploymentName, col.appid, logger) + .then((deploymentInfo) => { + if (_.isEmpty(deploymentInfo)) { + throw new AppError('does not find the deployment'); + } + return deploymentInfo; + }); + }) + .then((deploymentInfo) => { + return deploymentsManager.getDeploymentHistory(deploymentInfo.id); + }) + .then((rs) => { + logger.info('get deployment history success', { + uid, + appName, + deploymentName, + }); + + res.send({ history: _.pull(rs, null) }); + }) + .catch((e) => { + if (e instanceof AppError) { + logger.info('get deployment history failed', { + uid, + appName, + deploymentName, + error: e.message, + }); + + res.status(406).send(e.message); + } else { + next(e); + } + }); + }, +); + +appsRouter.delete( + '/:appName/deployments/:deploymentName/history', + checkToken, + (req: Req<{ appName: string; deploymentName: string }>, res, next) => { + const { logger, params } = req; + const uid = req.users.id; + const appName = _.trim(params.appName); + const deploymentName = _.trim(params.deploymentName); + logger.info('try to delete deployment history', { + uid, + appName, + deploymentName, + }); + accountManager + .ownerCan(uid, appName, logger) + .then((col) => { + return deploymentsManager + .findDeloymentByName(deploymentName, col.appid, logger) + .then((deploymentInfo) => { + if (_.isEmpty(deploymentInfo)) { + throw new AppError('does not find the deployment'); + } + return deploymentInfo; + }); + }) + .then((deploymentInfo) => { + return deploymentsManager.deleteDeploymentHistory(deploymentInfo.id); + }) + .then(() => { + logger.info('delete deployment history success', { + uid, + appName, + deploymentName, + }); + + res.send('ok'); + }) + .catch((e) => { + if (e instanceof AppError) { + logger.info('delete deployment history failed', { + uid, + appName, + deploymentName, + error: e.message, + }); + + res.status(406).send(e.message); + } else { + next(e); + } + }); + }, +); + +appsRouter.patch( + '/:appName/deployments/:deploymentName', + checkToken, + (req: Req<{ appName: string; deploymentName: string }, { name: string }>, res, next) => { + const { logger, params, body } = req; + const { name } = body; + const appName = _.trim(params.appName); + const deploymentName = _.trim(params.deploymentName); + const uid = req.users.id; + logger.info('try to update deployment', { + uid, + appName, + deploymentName, + newName: name, + }); + accountManager + .ownerCan(uid, appName, logger) + .then((col) => { + return deploymentsManager.renameDeloymentByName(deploymentName, col.appid, name); + }) + .then((data) => { + logger.info('update deployment success', { + uid, + appName, + deploymentName, + newName: name, + }); + + res.send({ deployment: data }); + }) + .catch((e) => { + if (e instanceof AppError) { + logger.info('update deployment failed', { + uid, + appName, + deploymentName, + newName: name, + error: e.message, + }); + + res.status(406).send(e.message); + } else { + next(e); + } + }); + }, +); + +appsRouter.delete( + '/:appName/deployments/:deploymentName', + checkToken, + (req: Req<{ appName: string; deploymentName: string }>, res, next) => { + const { logger, params } = req; + const appName = _.trim(params.appName); + const deploymentName = _.trim(params.deploymentName); + const uid = req.users.id; + logger.info('try to delete deployment', { + uid, + appName, + deploymentName, + }); + accountManager + .ownerCan(uid, appName, logger) + .then((col) => { + return deploymentsManager.deleteDeloymentByName(deploymentName, col.appid); + }) + .then((data) => { + logger.info('delete deployment success', { + uid, + appName, + deploymentName, + }); + + res.send({ deployment: data }); + }) + .catch((e) => { + if (e instanceof AppError) { + logger.info('delete deployment failed', { + uid, + appName, + deploymentName, + error: e.message, + }); + + res.status(406).send(e.message); + } else { + next(e); + } + }); + }, +); + +appsRouter.post( + '/:appName/deployments/:deploymentName/release', + checkToken, + // eslint-disable-next-line max-lines-per-function + (req: Req<{ appName: string; deploymentName: string }>, res, next) => { + const { logger, params } = req; + const appName = _.trim(params.appName); + const deploymentName = _.trim(params.deploymentName); + const uid = req.users.id; + logger.info('try to release', { + uid, + appName, + deploymentName, + }); + accountManager + .collaboratorCan(uid, appName, logger) + .then((col) => { + logger.info('release user check ok', { + uid, + appName, + deploymentName, + }); + + return deploymentsManager + .findDeloymentByName(deploymentName, col.appid, logger) + .then((deploymentInfo) => { + if (_.isEmpty(deploymentInfo)) { + throw new AppError('does not find the deployment'); + } + logger.info('release deployment check ok', { + uid, + appName, + deploymentName, + }); + + return packageManager + .parseReqFile(req, logger) + .then((data) => { + if (data.package.mimetype !== 'application/zip') { + throw new AppError( + `upload file type is invalidate: ${data.package.mimetype}`, + ); + } + logger.info('release packagee parse ok', { + uid, + appName, + deploymentName, + }); + + return packageManager + .releasePackage( + deploymentInfo.appid, + deploymentInfo.id, + data.packageInfo, + data.package.filepath, + uid, + logger, + ) + .finally(() => { + deleteFolderSync(data.package.filepath); + }); + }) + .then((packages) => { + if (packages) { + delay(1000).then(() => { + packageManager + .createDiffPackagesByLastNums( + deploymentInfo.appid, + packages, + config.common.diffNums, + logger, + ) + .catch((e) => { + logger.error(e); + }); + }); + } + // clear cache if exists. + if (config.common.updateCheckCache) { + delay(2500).then(() => { + clientManager.clearUpdateCheckCache( + deploymentInfo.deployment_key, + '*', + '*', + '*', + logger, + ); + }); + } + return null; + }); + }); + }) + .then(() => { + logger.info('release success', { + uid, + appName, + deploymentName, + }); + + res.send('{"msg": "succeed"}'); + }) + .catch((e) => { + if (e instanceof AppError) { + logger.info('release failed', { + uid, + appName, + deploymentName, + error: e.message, + }); + + res.status(406).send(e.message); + } else { + next(e); + } + }); + }, +); + +appsRouter.patch( + '/:appName/deployments/:deploymentName/release', + checkToken, + // eslint-disable-next-line max-lines-per-function + ( + req: Req<{ appName: string; deploymentName: string }, { packageInfo: { label: string } }>, + res, + next, + ) => { + const { logger, params, body } = req; + const appName = _.trim(params.appName); + const deploymentName = _.trim(params.deploymentName); + const uid = req.users.id; + logger.info('try modify release package', { + uid, + appName, + deploymentName, + body: JSON.stringify(body), + }); + accountManager + .collaboratorCan(uid, appName, logger) + .then((col) => { + return deploymentsManager + .findDeloymentByName(deploymentName, col.appid, logger) + .then((deploymentInfo) => { + if (_.isEmpty(deploymentInfo)) { + throw new AppError('does not find the deployment'); + } + const label = _.get(body, 'packageInfo.label'); + if (label) { + return packageManager + .findPackageInfoByDeploymentIdAndLabel(deploymentInfo.id, label) + .then((data) => { + return [deploymentInfo, data] as const; + }); + } + const deploymentVersionId = deploymentInfo.last_deployment_version_id; + return packageManager + .findLatestPackageInfoByDeployVersion(deploymentVersionId, logger) + .then((data) => { + return [deploymentInfo, data] as const; + }); + }) + .then(([deploymentInfo, packageInfo]) => { + if (!packageInfo) { + throw new AppError('does not find the packageInfo'); + } + return packageManager + .modifyReleasePackage(packageInfo.id, body.packageInfo) + .then(() => { + // clear cache if exists. + if (config.common.updateCheckCache) { + delay(2500).then(() => { + clientManager.clearUpdateCheckCache( + deploymentInfo.deployment_key, + '*', + '*', + '*', + logger, + ); + }); + } + }); + }); + }) + .then(() => { + logger.info('modify release package success', { + uid, + appName, + deploymentName, + }); + + res.send(''); + }) + .catch((e) => { + if (e instanceof AppError) { + logger.info('modify release package failed', { + uid, + appName, + deploymentName, + error: e.message, + }); + + res.status(406).send(e.message); + } else { + next(e); + } + }); + }, +); + +appsRouter.post( + '/:appName/deployments/:sourceDeploymentName/promote/:destDeploymentName', + checkToken, + // eslint-disable-next-line max-lines-per-function + ( + req: Req< + { appName: string; sourceDeploymentName: string; destDeploymentName: string }, + { packageInfo: unknown } + >, + res, + next, + ) => { + const { logger, params, body } = req; + const appName = _.trim(params.appName); + const sourceDeploymentName = _.trim(params.sourceDeploymentName); + const destDeploymentName = _.trim(params.destDeploymentName); + const uid = req.users.id; + + logger.info('try promote package', { + uid, + appName, + sourceDeploymentName, + destDeploymentName, + body: JSON.stringify(body), + }); + accountManager + .collaboratorCan(uid, appName, logger) + .then((col) => { + const appId = col.appid; + return Promise.all([ + deploymentsManager.findDeloymentByName(sourceDeploymentName, appId, logger), + deploymentsManager.findDeloymentByName(destDeploymentName, appId, logger), + ]) + .then(([sourceDeploymentInfo, destDeploymentInfo]) => { + if (!sourceDeploymentInfo) { + throw new AppError(`${sourceDeploymentName} does not exist.`); + } + if (!destDeploymentInfo) { + throw new AppError(`${destDeploymentName} does not exist.`); + } + return [sourceDeploymentInfo, destDeploymentInfo]; + }) + .then(([sourceDeploymentInfo, destDeploymentInfo]) => { + const promoteParams = _.get(body, 'packageInfo', {}); + // TODO: define packageInfo interface in packageManager + _.set(promoteParams as any, 'promoteUid', uid); + return packageManager + .promotePackage( + sourceDeploymentInfo, + destDeploymentInfo, + promoteParams, + logger, + ) + .then((packages) => { + return [packages, destDeploymentInfo] as const; + }); + }) + .then(([packages, destDeploymentInfo]) => { + if (packages) { + delay(1000).then(() => { + packageManager + .createDiffPackagesByLastNums( + destDeploymentInfo.appid, + packages, + config.common.diffNums, + logger, + ) + .catch((e) => { + logger.error(e); + }); + }); + } + // clear cache if exists. + if (config.common.updateCheckCache) { + delay(2500).then(() => { + clientManager.clearUpdateCheckCache( + destDeploymentInfo.deployment_key, + '*', + '*', + '*', + logger, + ); + }); + } + return packages; + }); + }) + .then((packages) => { + logger.info('promote package success', { + uid, + appName, + sourceDeploymentName, + destDeploymentName, + }); + + res.send({ package: packages }); + }) + .catch((e) => { + if (e instanceof AppError) { + logger.info('promote package failed', { + uid, + appName, + sourceDeploymentName, + destDeploymentName, + error: e.message, + }); + + res.status(406).send(e.message); + } else { + next(e); + } + }); + }, +); + +function rollbackCb( + req: Req<{ appName: string; deploymentName: string; label?: string }>, + res, + next, +) { + const { logger, params } = req; + const appName = _.trim(params.appName); + const deploymentName = _.trim(params.deploymentName); + const targetLabel = _.trim(params.label); + const uid = req.users.id; + logger.info('try to rollback', { + uid, + appName, + deploymentName, + targetLabel, + }); + accountManager + .collaboratorCan(uid, appName, logger) + .then((col) => { + return deploymentsManager.findDeloymentByName(deploymentName, col.appid, logger); + }) + .then((dep) => { + return packageManager + .rollbackPackage(dep.last_deployment_version_id, targetLabel, uid, logger) + .then((packageInfo: PackagesInterface) => { + if (packageInfo) { + delay(1000).then(() => { + packageManager + .createDiffPackagesByLastNums(dep.appid, packageInfo, 1, logger) + .catch((e) => { + logger.error(e); + }); + }); + } + // clear cache if exists. + if (config.common.updateCheckCache) { + delay(2500).then(() => { + logger.info('try clear update check cache'); + clientManager.clearUpdateCheckCache( + dep.deployment_key, + '*', + '*', + '*', + logger, + ); + }); + } + return packageInfo; + }); + }) + .then(() => { + logger.info('rollback success', { + uid, + appName, + deploymentName, + targetLabel, + }); + + res.send('ok'); + }) + .catch((e) => { + if (e instanceof AppError) { + logger.info('rollback failed', { + uid, + appName, + deploymentName, + targetLabel, + error: e.message, + }); + + res.status(406).send(e.message); + } else { + next(e); + } + }); +} + +appsRouter.post('/:appName/deployments/:deploymentName/rollback', checkToken, rollbackCb); + +appsRouter.post('/:appName/deployments/:deploymentName/rollback/:label', checkToken, rollbackCb); + +appsRouter.get( + '/:appName/collaborators', + checkToken, + (req: Req<{ appName: string }>, res, next) => { + const { logger, params } = req; + const appName = _.trim(params.appName); + const uid = req.users.id; + logger.info('try list collaborators', { + uid, + appName, + }); + accountManager + .collaboratorCan(uid, appName, logger) + .then((col) => { + return collaboratorsManager.listCollaborators(col.appid); + }) + .then((data) => { + const rs = _.reduce( + data, + (result, value, key) => { + let isCurrentAccount = false; + if (_.eq(key, req.users.email)) { + isCurrentAccount = true; + } + + result[key] = { + ...value, + isCurrentAccount, + }; + return result; + }, + {} as Record, + ); + + logger.info('list collaborators success', { + uid, + appName, + }); + + res.send({ collaborators: rs }); + }) + .catch((e) => { + if (e instanceof AppError) { + logger.info('list collaborators failed', { + uid, + appName, + error: e.message, + }); + + res.status(406).send(e.message); + } else { + next(e); + } + }); + }, +); + +appsRouter.post( + '/:appName/collaborators/:email', + checkToken, + (req: Req<{ appName: string; email: string }>, res, next) => { + const { logger, params } = req; + const appName = _.trim(params.appName); + const email = _.trim(params.email); + const uid = req.users.id; + logger.info('try to add collaborator', { + uid, + appName, + email, + }); + if (!validator.isEmail(email)) { + res.status(406).send('Invalid Email!'); + return; + } + accountManager + .ownerCan(uid, appName, logger) + .then((col) => { + return accountManager.findUserByEmail(email).then((data) => { + return collaboratorsManager.addCollaborator(col.appid, data.id); + }); + }) + .then((data) => { + logger.info('add collaborator success', { + uid, + appName, + email, + }); + + res.send(data); + }) + .catch((e) => { + if (e instanceof AppError) { + logger.info('add collaborator failed', { + uid, + appName, + email, + error: e.message, + }); + + res.status(406).send(e.message); + } else { + next(e); + } + }); + }, +); + +appsRouter.delete( + '/:appName/collaborators/:email', + checkToken, + (req: Req<{ appName: string; email: string }>, res, next) => { + const { logger, params } = req; + const appName = _.trim(params.appName); + const email = _.trim(params.email); + const uid = req.users.id; + logger.info('try remove app collaborator', { + uid, + appName, + email, + }); + + if (!validator.isEmail(email)) { + res.status(406).send('Invalid Email!'); + return; + } + accountManager + .ownerCan(uid, appName, logger) + .then((col) => { + return accountManager.findUserByEmail(email).then((data) => { + if (_.eq(data.id, uid)) { + throw new AppError("can't delete yourself!"); + } else { + return collaboratorsManager.deleteCollaborator(col.appid, data.id); + } + }); + }) + .then(() => { + logger.info('remove app collaborator success', { + uid, + appName, + email, + }); + + res.send(''); + }) + .catch((e) => { + if (e instanceof AppError) { + logger.info('remove app collaborator failed', { + uid, + appName, + email, + error: e.message, + }); + + res.status(406).send(e.message); + } else { + next(e); + } + }); + }, +); + +appsRouter.delete('/:appName', checkToken, (req: Req<{ appName: string }>, res, next) => { + const { logger, params } = req; + const appName = _.trim(params.appName); + const uid = req.users.id; + logger.info('try remove app', { + uid, + appName, + }); + + accountManager + .ownerCan(uid, appName, logger) + .then((col) => { + return appManager.deleteApp(col.appid); + }) + .then((data) => { + logger.info('remove app success', { + uid, + appName, + }); + + res.send(data); + }) + .catch((e) => { + if (e instanceof AppError) { + logger.info('remove app failed', { + uid, + appName, + error: e.message, + }); + + res.status(406).send(e.message); + } else { + next(e); + } + }); +}); + +appsRouter.patch('/:appName', checkToken, (req: Req<{ appName }, { name }>, res, next) => { + const { logger, params, body } = req; + const appName = _.trim(params.appName); + const newAppName = _.trim(body.name); + const uid = req.users.id; + logger.info('try rename app', { + uid, + appName, + newAppName, + }); + if (_.isEmpty(newAppName)) { + res.status(406).send('Please input name!'); + return; + } + accountManager + .ownerCan(uid, appName, logger) + .then((col) => { + return appManager.findAppByName(uid, newAppName).then((appInfo) => { + if (!_.isEmpty(appInfo)) { + throw new AppError(`${newAppName} Exist!`); + } + return appManager.modifyApp(col.appid, { name: newAppName }); + }); + }) + .then(() => { + logger.info('rename app success', { + uid, + appName, + newAppName, + }); + + res.send(''); + }) + .catch((e) => { + if (e instanceof AppError) { + logger.info('rename app failed', { + uid, + appName, + newAppName, + error: e.message, + }); + + res.status(406).send(e.message); + } else { + next(e); + } + }); +}); + +appsRouter.post( + '/:appName/transfer/:email', + checkToken, + (req: Req<{ appName: string; email: string }>, res, next) => { + const { logger, params } = req; + const appName = _.trim(params.appName); + const email = _.trim(params.email); + const uid = req.users.id; + logger.info('try transfer app', { + uid, + appName, + to: email, + }); + if (!validator.isEmail(email)) { + res.status(406).send('Invalid Email!'); + return; + } + accountManager + .ownerCan(uid, appName, logger) + .then((col) => { + return accountManager.findUserByEmail(email).then((data) => { + if (_.eq(data.id, uid)) { + throw new AppError("You can't transfer to yourself!"); + } + return appManager.transferApp(col.appid, uid, data.id); + }); + }) + .then((data) => { + logger.info('transfer app success', { + uid, + appName, + to: email, + }); + + res.send(data); + }) + .catch((e) => { + if (e instanceof AppError) { + logger.info('transfer app failed', { + uid, + appName, + to: email, + error: e.message, + }); + + res.status(406).send(e.message); + } else { + next(e); + } + }); + }, +); + +appsRouter.post( + '/', + checkToken, + // eslint-disable-next-line max-lines-per-function + ( + req: Req< + Record, + { + name: string; + os: string; + platform: string; + manuallyProvisionDeployments: unknown; + } + >, + res, + next, + ) => { + const { logger, body } = req; + const uid = req.users.id; + logger.info('try add app', { + uid, + body: JSON.stringify(body), + }); + const appName = body.name; + if (_.isEmpty(appName)) { + res.status(406).send('Please input name!'); + return; + } + const osName = _.toLower(body.os); + let os; + if (osName === _.toLower(IOS_NAME)) { + os = IOS; + } else if (osName === _.toLower(ANDROID_NAME)) { + os = ANDROID; + } else if (osName === _.toLower(WINDOWS_NAME)) { + os = WINDOWS; + } else { + res.status(406).send('Please input os [iOS|Android|Windows]!'); + return; + } + const platformName = _.toLower(body.platform); + let platform; + if (platformName === _.toLower(REACT_NATIVE_NAME)) { + platform = REACT_NATIVE; + } else if (platformName === _.toLower(CORDOVA_NAME)) { + platform = CORDOVA; + } else { + res.status(406).send('Please input platform [React-Native|Cordova]!'); + return; + } + logger.info('try add app params check pass', { + uid, + appName, + }); + + appManager + .findAppByName(uid, appName) + .then((appInfo) => { + if (!_.isEmpty(appInfo)) { + throw new AppError(`${appName} Exist!`); + } + return appManager.addApp(uid, appName, os, platform, req.users.identical); + }) + .then(() => { + logger.info('add app success', { + uid, + name: appName, + }); + + const data = { + name: appName, + collaborators: { [req.users.email]: { permission: 'Owner' } }, + }; + res.send({ app: data }); + }) + .catch((e) => { + if (e instanceof AppError) { + logger.info('add app failed', { + uid, + name: appName, + error: e.message, + }); + + res.status(406).send(e.message); + } else { + next(e); + } + }); + }, +); diff --git a/src/routes/auth.ts b/src/routes/auth.ts new file mode 100644 index 00000000..dd8a77fe --- /dev/null +++ b/src/routes/auth.ts @@ -0,0 +1,93 @@ +import express from 'express'; +import jwt from 'jsonwebtoken'; +import _ from 'lodash'; +import { AppErrorI18n } from '../core/app-error'; +import { config } from '../core/config'; +import { Req } from '../core/middleware'; +import { accountManager } from '../core/services/account-manager'; +import { md5 } from '../core/utils/security'; + +// route for auth web pages +export const authRouter = express.Router(); + +authRouter.get('/password', (req: Req, res) => { + res.render('auth/password', { title: 'CodePushServer' }); +}); + +authRouter.get('/login', (req: Req, res) => { + res.render('auth/login', { + title: 'CodePushServer', + email: req.query.email || '', + showRegister: config.common.allowRegistration, + }); +}); + +authRouter.get('/link', (req: Req, res) => { + res.redirect(`/auth/login`); +}); + +authRouter.get('/register', (req: Req, res) => { + if (config.common.allowRegistration) { + res.render('auth/register', { title: 'CodePushServer', email: req.query.email || '' }); + } else { + res.redirect(`/auth/login`); + } +}); + +authRouter.get('/confirm', (req: Req, res) => { + res.render('auth/confirm', { title: 'CodePushServer', email: req.query.email || '' }); +}); + +authRouter.post('/logout', (req: Req, res) => { + res.send('ok'); +}); + +authRouter.post( + '/login', + (req: Req, res, next) => { + const { logger, body } = req; + const account = _.trim(body.account); + const password = _.trim(body.password); + logger.info('try login', { + account, + }); + accountManager + .login(account, password) + .then((users) => { + logger.info('login success', { + account, + uid: users.id, + }); + return jwt.sign( + { uid: users.id, hash: md5(users.ack_code), expiredIn: 7200 }, + config.jwt.tokenSecret, + ); + }) + .then((token) => { + logger.info('jwt token signed', { + account, + }); + res.send({ status: 'OK', results: { tokens: token } }); + }) + .catch((e) => { + if (e instanceof AppErrorI18n) { + const { messageKey, messageVars } = e; + const message = + typeof req.t === 'function' ? req.t(messageKey, messageVars) : messageKey; // fallback + + logger.info('login failed', { + account, + error: message, + messageKey, + }); + res.send({ + status: 'ERROR', + message, + code: messageKey, + }); + } else { + next(e); + } + }); + }, +); diff --git a/src/routes/index.ts b/src/routes/index.ts new file mode 100644 index 00000000..d738e854 --- /dev/null +++ b/src/routes/index.ts @@ -0,0 +1,166 @@ +import express from 'express'; +import { AppError } from '../core/app-error'; +import { i18n } from '../core/i18n'; +import { checkToken, ipWhitelistOnly, Req, webUiGuard } from '../core/middleware'; +import { clientManager } from '../core/services/client-manager'; + +export const indexRouter = express.Router(); + +/** + * 프로덕션 레벨 미들웨어 적용 + * - ipWhitelistOnly: IP주소 검사 + * - webUiGuard: WEB_UI_ALLOW='true' + */ +indexRouter.get('/', [ipWhitelistOnly, webUiGuard], (req, res) => { + res.render('index', { title: 'CodePushServer' }); +}); + +indexRouter.get('/healthcheck', (req: Req, res) => { + const message = req.t('hot update server'); + const timestamp = new Date().toISOString(); + + res.status(200).json({ + success: true, + lang: req.lang, + message, + timestamp, + }); +}); + +indexRouter.get('/tokens', (req, res) => { + // eslint-disable-next-line no-underscore-dangle + res.render('tokens', { title: `${i18n.__('Obtain')} token` }); +}); + +indexRouter.get( + '/updateCheck', + ( + req: Req< + void, + void, + { + deploymentKey: string; + appVersion: string; + label: string; + packageHash: string; + clientUniqueId: string; + } + >, + res, + next, + ) => { + const { logger, query } = req; + logger.info('updateCheck', { + query: JSON.stringify(query), + }); + const { deploymentKey, appVersion, label, packageHash, clientUniqueId } = query; + clientManager + .updateCheckFromCache( + deploymentKey, + appVersion, + label, + packageHash, + clientUniqueId, + logger, + ) + .then((rs) => { + // 그레이 릴리즈(Gray Release, 灰度检测, 점진적 배포대상) 체크 === 현재 유저가 이 업데이트를 받을 대상인지 판별하는 과정 + return clientManager + .chosenMan(rs.packageId, rs.rollout, clientUniqueId) + .then((data) => { + if (!data) { + rs.isAvailable = false; + return rs; + } + return rs; + }); + }) + .then((rs) => { + logger.info('updateCheck success'); + + delete rs.packageId; + delete rs.rollout; + res.send({ updateInfo: rs }); + }) + .catch((e) => { + if (e instanceof AppError) { + logger.info('updateCheck failed', { + error: e.message, + }); + res.status(404).send(e.message); + } else { + next(e); + } + }); + }, +); + +indexRouter.post( + '/reportStatus/download', + ( + req: Req< + void, + { + clientUniqueId: string; + label: string; + deploymentKey: string; + }, + void + >, + res, + ) => { + const { logger, body } = req; + logger.info('reportStatus/download', { + body: JSON.stringify(body), + }); + const { clientUniqueId, label, deploymentKey } = body; + clientManager.reportStatusDownload(deploymentKey, label, clientUniqueId).catch((err) => { + if (err instanceof AppError) { + logger.info('reportStatus/deploy failed', { + error: err.message, + }); + } else { + logger.error(err); + } + }); + res.send('OK'); + }, +); + +indexRouter.post( + '/reportStatus/deploy', + ( + req: Req< + void, + { + clientUniqueId: string; + label: string; + deploymentKey: string; + }, + void + >, + res, + ) => { + const { logger, body } = req; + logger.info('reportStatus/deploy', { + body: JSON.stringify(body), + }); + const { clientUniqueId, label, deploymentKey } = body; + clientManager + .reportStatusDeploy(deploymentKey, label, clientUniqueId, req.body) + .catch((err) => { + if (err instanceof AppError) { + logger.info('reportStatus/deploy failed', { + error: err.message, + }); + } else { + logger.error(err); + } + }); + res.send('OK'); + }, +); + +indexRouter.get('/authenticated', checkToken, (req, res) => { + return res.send({ authenticated: true }); +}); diff --git a/src/routes/indexV1.ts b/src/routes/indexV1.ts new file mode 100644 index 00000000..7131becb --- /dev/null +++ b/src/routes/indexV1.ts @@ -0,0 +1,153 @@ +import express from 'express'; +import { AppError } from '../core/app-error'; +import { Req } from '../core/middleware'; +import { clientManager } from '../core/services/client-manager'; + +// routes for latest code push client +export const indexV1Router = express.Router(); + +indexV1Router.get( + '/update_check', + ( + req: Req< + void, + void, + { + deployment_key: string; + app_version: string; + label: string; + package_hash: string; + is_companion: unknown; + client_unique_id: string; + } + >, + res, + next, + ) => { + const { logger, query } = req; + logger.info('try update_check', { + query: JSON.stringify(query), + }); + const { + deployment_key: deploymentKey, + app_version: appVersion, + label, + package_hash: packageHash, + client_unique_id: clientUniqueId, + } = query; + clientManager + .updateCheckFromCache( + deploymentKey, + appVersion, + label, + packageHash, + clientUniqueId, + logger, + ) + .then((rs) => { + // 그레이 릴리즈(Gray Release, 灰度检测, 점진적 배포대상) 체크 === 현재 유저가 이 업데이트를 받을 대상인지 판별하는 과정 + return clientManager + .chosenMan(rs.packageId, rs.rollout, clientUniqueId) + .then((data) => { + if (!data) { + rs.isAvailable = false; + return rs; + } + return rs; + }); + }) + .then((rs) => { + logger.info('update_check success'); + + res.send({ + update_info: { + download_url: rs.downloadUrl, + description: rs.description, + is_available: rs.isAvailable, + is_disabled: rs.isDisabled, + // Note: need to use appVersion here to get it compatible with client side change... + // https://github.com/microsoft/code-push/commit/7d2ffff395cc54db98aefba7c67889f509e8c249#diff-a937c637a47cbd31cbb52c89bef7d197R138 + target_binary_range: rs.appVersion, + label: rs.label, + package_hash: rs.packageHash, + package_size: rs.packageSize, + should_run_binary_version: rs.shouldRunBinaryVersion, + update_app_version: rs.updateAppVersion, + is_mandatory: rs.isMandatory, + }, + }); + }) + .catch((e) => { + if (e instanceof AppError) { + logger.info('update check failed', { + error: e.message, + }); + res.status(404).send(e.message); + } else { + next(e); + } + }); + }, +); + +indexV1Router.post( + '/report_status/download', + ( + req: Req< + void, + { + client_unique_id: string; + label: string; + deployment_key: string; + }, + void + >, + res, + ) => { + const { logger, body } = req; + logger.info('report_status/download', { body: JSON.stringify(body) }); + const { client_unique_id: clientUniqueId, label, deployment_key: deploymentKey } = body; + clientManager.reportStatusDownload(deploymentKey, label, clientUniqueId).catch((err) => { + if (err instanceof AppError) { + logger.info('report_status/download failed', { + error: err.message, + }); + } else { + logger.error(err); + } + }); + res.send('OK'); + }, +); + +indexV1Router.post( + '/report_status/deploy', + ( + req: Req< + void, + { + client_unique_id: string; + label: string; + deployment_key: string; + }, + void + >, + res, + ) => { + const { logger, body } = req; + logger.info('report_status/deploy', { body: JSON.stringify(body) }); + const { client_unique_id: clientUniqueId, label, deployment_key: deploymentKey } = body; + clientManager + .reportStatusDeploy(deploymentKey, label, clientUniqueId, req.body) + .catch((err) => { + if (err instanceof AppError) { + logger.info('report_status/deploy failed', { + error: err.message, + }); + } else { + logger.error(err); + } + }); + res.send('OK'); + }, +); diff --git a/src/routes/users.ts b/src/routes/users.ts new file mode 100644 index 00000000..e47c42f4 --- /dev/null +++ b/src/routes/users.ts @@ -0,0 +1,153 @@ +import express from 'express'; +import _ from 'lodash'; +import { AppError, AppErrorI18n } from '../core/app-error'; +import { checkToken, Req } from '../core/middleware'; +import { accountManager } from '../core/services/account-manager'; +import { Users } from '../models/users'; + +export const usersRouter = express.Router(); + +usersRouter.get('/', checkToken, (req: Req, res) => { + res.send({ title: 'CodePushServer' }); +}); + +usersRouter.post( + '/', + ( + req: Req< + void, + { + email: string; + token: string; + password: string; + }, + void + >, + res, + next, + ) => { + const { logger, body } = req; + const email = _.trim(body.email); + const token = _.trim(body.token); + const password = _.trim(body.password); + logger.info('try register account', { email, token }); + return accountManager + .checkRegisterCode(email, token) + .then(() => { + if (_.isString(password) && password.length < 6) { + throw new AppErrorI18n('error.password_length_register'); + } + return accountManager.register(email, password); + }) + .then(() => { + logger.info('register account success', { email }); + res.send({ status: 'OK' }); + }) + .catch((e) => { + if (e instanceof AppError) { + logger.info('register account failed', { email, error: e.message }); + res.send({ status: 'ERROR', message: e.message }); + } else { + next(e); + } + }); + }, +); + +usersRouter.get('/exists', (req: Req, res, next) => { + const email = _.trim(req.query.email); + const emailRequiredMessage = req.t('error.input_email_required'); + if (!email) { + res.send({ status: 'ERROR', message: emailRequiredMessage }); + return; + } + Users.findOne({ where: { email } }) + .then((u) => { + res.send({ status: 'OK', exists: !!u }); + }) + .catch((e) => { + if (e instanceof AppError) { + res.send({ status: 'ERROR', message: e.message }); + } else { + next(e); + } + }); +}); + +usersRouter.post('/registerCode', (req: Req, res, next) => { + const { logger, body } = req; + const { email } = body; + logger.info('try send register code', { email }); + return accountManager + .sendRegisterCode(email) + .then(() => { + logger.info('send register code success', { email }); + res.send({ status: 'OK' }); + }) + .catch((e) => { + if (e instanceof AppError) { + logger.info('send register code error', { email, error: e.message }); + res.send({ status: 'ERROR', message: e.message }); + } else { + next(e); + } + }); +}); + +usersRouter.get( + '/registerCode/exists', + (req: Req, res, next) => { + const { query } = req; + const email = _.trim(query.email); + const token = _.trim(query.token); + return accountManager + .checkRegisterCode(email, token) + .then(() => { + res.send({ status: 'OK' }); + }) + .catch((e) => { + if (e instanceof AppError) { + res.send({ status: 'ERROR', message: e.message }); + } else { + next(e); + } + }); + }, +); + +// Change Password +usersRouter.patch( + '/password', + checkToken, + ( + req: Req< + Record, + { + oldPassword: string; + newPassword: string; + } + >, + res, + next, + ) => { + const { logger, body } = req; + const oldPassword = _.trim(body.oldPassword); + const newPassword = _.trim(body.newPassword); + const uid = req.users.id; + logger.info('try change password', { uid }); + return accountManager + .changePassword(uid, oldPassword, newPassword) + .then(() => { + logger.info('change password success', { uid }); + res.send({ status: 'OK' }); + }) + .catch((e) => { + if (e instanceof AppError) { + logger.info('change password failed', { uid }); + res.send({ status: 'ERROR', message: e.message }); + } else { + next(e); + } + }); + }, +); diff --git a/src/www.ts b/src/www.ts new file mode 100755 index 00000000..9f37e305 --- /dev/null +++ b/src/www.ts @@ -0,0 +1,94 @@ +#!/usr/bin/env node +import 'dotenv/config'; +import http from 'http'; +import { logger } from 'kv-logger'; +import _ from 'lodash'; +import validator from 'validator'; +import { app } from './app'; +import { CURRENT_DB_VERSION } from './core/const'; +import { Versions } from './models/versions'; + +/** + * Normalize a port into a number, string, or false. + */ +function normalizePort(val): number | string | false { + const port = parseInt(val, 10); + + if (Number.isNaN(port)) { + // named pipe + return val; + } + + if (port >= 0) { + // port number + return port; + } + + return false; +} + +// check if the db is initialized +Versions.findOne({ where: { type: 1 } }) + .then((v) => { + if (!v || v.version !== CURRENT_DB_VERSION) { + throw new Error( + 'Please upgrade your database. use `npm run upgrade` or `code-push-server-db upgrade`', + ); + } + // create server and listen + const server = http.createServer(app); + + const port = normalizePort(process.env.PORT || '3000'); + + let host = null; + if (process.env.HOST) { + logger.debug(`process.env.HOST ${process.env.HOST}`); + if (validator.isIP(process.env.HOST)) { + logger.debug(`${process.env.HOST} valid`); + host = process.env.HOST; + } else { + logger.warn(`process.env.HOST ${process.env.HOST} is invalid, use 0.0.0.0 instead`); + } + } + + server.listen(port, host); + + server.on('error', (error: Error & { syscall: string; code: string }) => { + if (error.syscall === 'listen') { + const bind = typeof port === 'string' ? `Pipe ${port}` : `Port ${port}`; + + // handle specific listen errors with friendly messages + switch (error.code) { + case 'EACCES': + logger.error(`${bind} requires elevated privileges`); + process.exit(1); + break; + case 'EADDRINUSE': + logger.error(`${bind} is already in use`); + process.exit(1); + break; + default: + break; + } + } + logger.error(error); + throw error; + }); + + server.on('listening', () => { + const addr = server.address(); + logger.info(`server is listening on ${JSON.stringify(addr)}`); + }); + }) + .catch((e) => { + if (_.startsWith(e.message, 'ER_NO_SUCH_TABLE')) { + logger.error( + new Error( + 'Please upgrade your database. use `npm run upgrade` or `code-push-server-db upgrade`', + ), + ); + } else { + logger.error(e); + } + process.exit(1); + }); diff --git a/storage/.gitignore b/storage/.gitignore new file mode 100644 index 00000000..02c52c7b --- /dev/null +++ b/storage/.gitignore @@ -0,0 +1,3 @@ +* +!README.md +!.gitignore \ No newline at end of file diff --git a/storage/README.md b/storage/README.md new file mode 100644 index 00000000..a47c0e94 --- /dev/null +++ b/storage/README.md @@ -0,0 +1,7 @@ +## 다운로드 에셋 저장용 디렉토리 + +- storageType = 'local' 한정 사용 +- 런타임 오류 해결용 + ``` + [dev:run] level=error, time=2025-11-16 14:34:04.503, msg=Please create dir ./storage, name=Error, stack=Error: Please create dir ./storage + ``` diff --git a/tea.yaml b/tea.yaml new file mode 100644 index 00000000..aad4b70f --- /dev/null +++ b/tea.yaml @@ -0,0 +1,6 @@ +# https://tea.xyz/what-is-this-file +--- +version: 1.0.0 +codeOwners: + - '0x6498bd929aA09f9a8ccdF8F176E09B24136388cb' +quorum: 1 diff --git a/test/api/accessKeys/accessKeys.test.js b/test/api/accessKeys/accessKeys.test.js deleted file mode 100644 index 69dc2fd6..00000000 --- a/test/api/accessKeys/accessKeys.test.js +++ /dev/null @@ -1,93 +0,0 @@ -var app = require('../../../app'); -var request = require('supertest')(app); -var should = require("should"); -var security = require('../../../core/utils/security'); -var factory = require('../../../core/utils/factory'); -var _ = require('lodash'); - -describe('api/accessKeys/accessKeys.test.js', function() { - var account = '522539441@qq.com'; - var password = '123456'; - var authToken; - var friendlyName = 'test'; - var newFriendlyName = 'newtest'; - before(function(done){ - request.post('/auth/login') - .send({ - account: account, - password: password - }) - .end(function(err, res) { - should.not.exist(err); - var rs = JSON.parse(res.text); - rs.should.containEql({status:"OK"}); - authToken = (new Buffer(`auth:${_.get(rs, 'results.tokens')}`)).toString('base64'); - done(); - }); - }); - - describe('create accessKeys', function(done) { - it('should create accessKeys successful', function(done) { - request.post(`/accessKeys`) - .set('Authorization', `Basic ${authToken}`) - .send({createdBy: 'tablee', friendlyName: friendlyName, ttl: 30*24*60*60}) - .end(function(err, res) { - should.not.exist(err); - res.status.should.equal(200); - var rs = JSON.parse(res.text); - rs.should.have.properties('accessKey'); - rs.accessKey.should.have.properties(['name', 'createdTime', 'createdBy', - 'expires', 'description', 'friendlyName']); - done(); - }); - }); - - it('should not create accessKeys successful when friendlyName exist', function(done) { - request.post(`/accessKeys`) - .set('Authorization', `Basic ${authToken}`) - .send({createdBy: 'tablee', friendlyName: friendlyName, ttl: 30*24*60*60}) - .end(function(err, res) { - should.not.exist(err); - res.status.should.equal(406); - res.text.should.equal(`The access key "${friendlyName}" already exists.`); - done(); - }); - }); - }); - - describe('list accessKeys', function(done) { - it('should list accessKeys successful', function(done) { - request.get(`/accessKeys`) - .set('Authorization', `Basic ${authToken}`) - .send() - .end(function(err, res) { - should.not.exist(err); - res.status.should.equal(200); - var rs = JSON.parse(res.text); - rs.should.have.properties('accessKeys'); - rs.accessKeys.should.be.an.instanceOf(Array); - rs.accessKeys.should.matchEach(function(it) { - return it.should.have.properties(['name', 'createdTime', 'createdBy', - 'expires', 'description', 'friendlyName']); - }); - done(); - }); - }); - }); - - describe('delete accessKeys', function(done) { - it('should delete accessKeys successful', function(done) { - request.delete(`/accessKeys/${encodeURI(newFriendlyName)}`) - .set('Authorization', `Basic ${authToken}`) - .send() - .end(function(err, res) { - should.not.exist(err); - res.status.should.equal(200); - var rs = JSON.parse(res.text); - rs.should.have.properties('friendlyName'); - done(); - }); - }); - }); - -}); diff --git a/test/api/account/account.test.js b/test/api/account/account.test.js deleted file mode 100644 index 62e262a3..00000000 --- a/test/api/account/account.test.js +++ /dev/null @@ -1,45 +0,0 @@ -var app = require('../../../app'); -var request = require('supertest')(app); -var should = require("should"); -var security = require('../../../core/utils/security'); -var factory = require('../../../core/utils/factory'); -var _ = require('lodash'); - -describe('api/account/account.test.js', function() { - var account = '522539441@qq.com'; - var password = '123456'; - - describe('user modules', function(done) { - var authToken; - before(function(done){ - request.post('/auth/login') - .send({ - account: account, - password: password - }) - .end(function(err, res) { - should.not.exist(err); - var rs = JSON.parse(res.text); - rs.should.containEql({status:"OK"}); - authToken = (new Buffer(`auth:${_.get(rs, 'results.tokens')}`)).toString('base64'); - done(); - }); - }); - - it('should get account info successful', function(done) { - request.get(`/account`) - .set('Authorization', `Basic ${authToken}`) - .send() - .end(function(err, res) { - should.not.exist(err); - res.status.should.equal(200); - var rs = JSON.parse(res.text); - rs.should.have.properties('account'); - rs.account.should.have.properties(['email', 'linkedProviders', 'name']); - done(); - }); - }); - - }); - -}); diff --git a/test/api/apps/apps.test.js b/test/api/apps/apps.test.js deleted file mode 100644 index d393a42f..00000000 --- a/test/api/apps/apps.test.js +++ /dev/null @@ -1,444 +0,0 @@ -var app = require('../../../app'); -var request = require('supertest')(app); -var should = require("should"); -var security = require('../../../core/utils/security'); -var factory = require('../../../core/utils/factory'); -var _ = require('lodash'); - -describe('api/apps/apps.test.js', function() { - var account = '522539441@qq.com'; - var email = 'lisong2010@gmail.com'; - var emailInvalid = 'lisong2010'; - var password = '123456'; - var authToken; - var machineName = `Login-${Math.random()}`; - var friendlyName = `Login-${Math.random()}`; - var appName = 'test'; - var newAppName = 'newtest'; - var bearerToken; - var testDeployment = 'test'; - var newTestDeployment = 'newtest'; - - before(function(done){ - request.post('/auth/login') - .send({ - account: account, - password: password - }) - .end(function(err, res) { - should.not.exist(err); - var rs = JSON.parse(res.text); - rs.should.containEql({status:"OK"}); - authToken = (new Buffer(`auth:${_.get(rs, 'results.tokens')}`)).toString('base64'); - done(); - }); - }); - - describe('create accessKeys', function(done) { - it('should create accessKeys successful', function(done) { - request.post(`/accessKeys`) - .set('Authorization', `Basic ${authToken}`) - .send({createdBy: machineName, friendlyName: friendlyName, ttl: 30*24*60*60}) - .end(function(err, res) { - should.not.exist(err); - res.status.should.equal(200); - var rs = JSON.parse(res.text); - rs.should.have.properties('accessKey'); - rs.accessKey.should.have.properties(['name', 'createdTime', 'createdBy', - 'expires', 'description', 'friendlyName']); - bearerToken = _.get(rs, 'accessKey.name'); - done(); - }); - }); - }); - - describe('add apps', function(done) { - it('should not add apps successful when appName is empty', function(done) { - request.post(`/apps`) - .set('Authorization', `Bearer ${bearerToken}`) - .send({}) - .end(function(err, res) { - should.not.exist(err); - res.status.should.equal(406); - res.text.should.equal(`Please input name!`); - done(); - }); - }); - - it('should add apps successful', function(done) { - request.post(`/apps`) - .set('Authorization', `Bearer ${bearerToken}`) - .send({name: appName, os:'iOS', platform:'React-Native'}) - .end(function(err, res) { - should.not.exist(err); - res.status.should.equal(200); - var rs = JSON.parse(res.text); - rs.should.have.properties('app'); - rs.app.should.have.properties(['name', 'collaborators']); - done(); - }); - }); - - it('should not add apps successful when appName exists', function(done) { - request.post(`/apps`) - .set('Authorization', `Bearer ${bearerToken}`) - .send({name: appName, os:'iOS', platform:'React-Native'}) - .end(function(err, res) { - should.not.exist(err); - res.status.should.equal(406); - res.text.should.equal(`${appName} Exist!`); - done(); - }); - }); - }); - - describe('list apps', function(done) { - it('should list apps successful', function(done) { - request.get(`/apps`) - .set('Authorization', `Bearer ${bearerToken}`) - .send() - .end(function(err, res) { - should.not.exist(err); - res.status.should.equal(200); - var rs = JSON.parse(res.text); - rs.should.have.properties('apps'); - rs.apps.should.be.an.instanceOf(Array); - rs.apps.should.matchEach(function(it) { - return it.should.have.properties(['collaborators', 'deployments', 'name']); - }); - done(); - }); - }); - }); - - describe('list apps all deployments', function(done) { - it('should list apps all deployments successful', function(done) { - request.get(`/apps/${appName}/deployments`) - .set('Authorization', `Bearer ${bearerToken}`) - .send() - .end(function(err, res) { - should.not.exist(err); - res.status.should.equal(200); - var rs = JSON.parse(res.text); - rs.should.have.properties('deployments'); - rs.deployments.should.be.an.instanceOf(Array); - rs.deployments.should.matchEach(function(it) { - return it.should.have.properties(['createdTime', 'id', 'key', 'name', 'package']); - }); - done(); - }); - }); - }); - - describe(`create deployments ${testDeployment}`, function(done) { - it('should create deployments successful', function(done) { - request.post(`/apps/${appName}/deployments`) - .set('Authorization', `Bearer ${bearerToken}`) - .send({name: testDeployment}) - .end(function(err, res) { - should.not.exist(err); - res.status.should.equal(200); - var rs = JSON.parse(res.text); - rs.should.have.properties('deployment'); - rs.deployment.should.have.properties(['key', 'name']); - done(); - }); - }); - - it('should not create deployments successful when deployment exists', function(done) { - request.post(`/apps/${appName}/deployments`) - .set('Authorization', `Bearer ${bearerToken}`) - .send({name: testDeployment}) - .end(function(err, res) { - should.not.exist(err); - res.status.should.equal(406); - res.text.should.equal(`${testDeployment} name does Exist!`); - done(); - }); - }); - }); - - describe(`rename deployments ${testDeployment}`, function(done) { - it('should rename deployments successful', function(done) { - request.patch(`/apps/${appName}/deployments/${testDeployment}`) - .set('Authorization', `Bearer ${bearerToken}`) - .send({name: newTestDeployment}) - .end(function(err, res) { - should.not.exist(err); - res.status.should.equal(200); - var rs = JSON.parse(res.text); - rs.should.have.properties('deployment'); - rs.deployment.should.have.properties(['name']); - done(); - }); - }); - - it('should not rename deployments successful when new deployments name does exists', function(done) { - request.patch(`/apps/${appName}/deployments/${testDeployment}`) - .set('Authorization', `Bearer ${bearerToken}`) - .send({name: newTestDeployment}) - .end(function(err, res) { - should.not.exist(err); - res.status.should.equal(406); - res.text.should.equal(`${newTestDeployment} name does Exist!`); - done(); - }); - }); - - it('should not rename deployments successful when deployments name does not exists', function(done) { - request.patch(`/apps/${appName}/deployments/${testDeployment}`) - .set('Authorization', `Bearer ${bearerToken}`) - .send({name: 'hello'}) - .end(function(err, res) { - should.not.exist(err); - res.status.should.equal(406); - res.text.should.equal(`does not find the deployment "${testDeployment}"`); - done(); - }); - }); - }); - - describe(`delete deployments ${newTestDeployment}`, function(done) { - it('should delete deployments successful', function(done) { - request.delete(`/apps/${appName}/deployments/${newTestDeployment}`) - .set('Authorization', `Bearer ${bearerToken}`) - .send() - .end(function(err, res) { - should.not.exist(err); - res.status.should.equal(200); - var rs = JSON.parse(res.text); - rs.should.have.properties('deployment'); - rs.deployment.should.have.properties(['name']); - done(); - }); - }); - - it(`should not delete deployments successful when ${newTestDeployment} not exists`, function(done) { - request.delete(`/apps/${appName}/deployments/${newTestDeployment}`) - .set('Authorization', `Bearer ${bearerToken}`) - .send() - .end(function(err, res) { - should.not.exist(err); - res.status.should.equal(406); - res.text.should.equal(`does not find the deployment "${newTestDeployment}"`); - done(); - }); - }); - }); - - describe(`add collaborators`, function(done) { - it(`should not add collaborators successful when ${emailInvalid} invalid`, function(done) { - request.post(`/apps/${appName}/collaborators/${emailInvalid}`) - .set('Authorization', `Bearer ${bearerToken}`) - .send() - .end(function(err, res) { - should.not.exist(err); - res.status.should.equal(406); - res.text.should.equal(`Invalid Email!`); - done(); - }); - }); - - it('should add collaborators successful', function(done) { - request.post(`/apps/${appName}/collaborators/${email}`) - .set('Authorization', `Bearer ${bearerToken}`) - .send() - .end(function(err, res) { - should.not.exist(err); - res.status.should.equal(200); - done(); - }); - }); - - it(`should not add collaborators successful when ${email} is already a collaborators`, function(done) { - request.post(`/apps/${appName}/collaborators/${email}`) - .set('Authorization', `Bearer ${bearerToken}`) - .send() - .end(function(err, res) { - should.not.exist(err); - res.status.should.equal(406); - res.text.should.equal(`user already is Collaborator.`); - done(); - }); - }); - }); - - describe(`list collaborators`, function(done) { - it('should list collaborators successful', function(done) { - request.get(`/apps/${appName}/collaborators`) - .set('Authorization', `Bearer ${bearerToken}`) - .send() - .end(function(err, res) { - should.not.exist(err); - res.status.should.equal(200); - var rs = JSON.parse(res.text); - rs.should.have.properties('collaborators'); - done(); - }); - }); - }); - - describe(`delete collaborators`, function(done) { - it(`should not delete collaborators successful when ${emailInvalid} invalid`, function(done) { - request.delete(`/apps/${appName}/collaborators/${emailInvalid}`) - .set('Authorization', `Bearer ${bearerToken}`) - .send() - .end(function(err, res) { - should.not.exist(err); - res.status.should.equal(406); - res.text.should.equal(`Invalid Email!`); - done(); - }); - }); - - it(`should not delete collaborators successful when email is yourself`, function(done) { - request.delete(`/apps/${appName}/collaborators/${account}`) - .set('Authorization', `Bearer ${bearerToken}`) - .send() - .end(function(err, res) { - should.not.exist(err); - res.status.should.equal(406); - res.text.should.equal(`can't delete yourself!`); - done(); - }); - }); - - it('should delete collaborators successful', function(done) { - request.delete(`/apps/${appName}/collaborators/${email}`) - .set('Authorization', `Bearer ${bearerToken}`) - .send() - .end(function(err, res) { - should.not.exist(err); - res.status.should.equal(200); - done(); - }); - }); - - it(`should not delete collaborators successful when ${email} is not a collaborators`, function(done) { - request.delete(`/apps/${appName}/collaborators/${email}`) - .set('Authorization', `Bearer ${bearerToken}`) - .send() - .end(function(err, res) { - should.not.exist(err); - res.status.should.equal(406); - res.text.should.equal(`user is not a Collaborator`); - done(); - }); - }); - }); - - describe(`transfer apps`, function(done) { - var authTokenOther; - before(function(done){ - request.post('/auth/login') - .send({ - account: email, - password: password - }) - .end(function(err, res) { - should.not.exist(err); - var rs = JSON.parse(res.text); - rs.should.containEql({status:"OK"}); - authTokenOther = (new Buffer(`auth:${_.get(rs, 'results.tokens')}`)).toString('base64'); - done(); - }); - }); - - it(`should not transfer apps successful when ${emailInvalid} invalid`, function(done) { - request.post(`/apps/${appName}/transfer/${emailInvalid}`) - .set('Authorization', `Bearer ${bearerToken}`) - .send() - .end(function(err, res) { - should.not.exist(err); - res.status.should.equal(406); - res.text.should.equal(`Invalid Email!`); - done(); - }); - }); - - it(`should not transfer apps successful when email is yourself`, function(done) { - request.post(`/apps/${appName}/transfer/${account}`) - .set('Authorization', `Bearer ${bearerToken}`) - .send() - .end(function(err, res) { - should.not.exist(err); - res.status.should.equal(406); - res.text.should.equal(`You can't transfer to yourself!`); - done(); - }); - }); - - it(`should transfer apps successful`, function(done) { - request.post(`/apps/${appName}/transfer/${email}`) - .set('Authorization', `Bearer ${bearerToken}`) - .send() - .end(function(err, res) { - should.not.exist(err); - res.status.should.equal(200); - done(); - }); - }); - - it(`should transfer apps back successful`, function(done) { - request.post(`/apps/${appName}/transfer/${account}`) - .set('Authorization', `Basic ${authTokenOther}`) - .send() - .end(function(err, res) { - should.not.exist(err); - res.status.should.equal(200); - done(); - }); - }); - }); - - describe(`rename apps`, function(done) { - it(`should not rename apps successful when new name is invalid`, function(done) { - request.patch(`/apps/${appName}`) - .set('Authorization', `Bearer ${bearerToken}`) - .send() - .end(function(err, res) { - should.not.exist(err); - res.status.should.equal(406); - res.text.should.equal(`Please input name!`); - done(); - }); - }); - - it(`should not rename apps successful when new name does exists`, function(done) { - request.patch(`/apps/${appName}`) - .set('Authorization', `Bearer ${bearerToken}`) - .send({name: appName}) - .end(function(err, res) { - should.not.exist(err); - res.status.should.equal(406); - res.text.should.equal(`${appName} Exist!`); - done(); - }); - }); - - it(`should rename apps successful`, function(done) { - request.patch(`/apps/${appName}`) - .set('Authorization', `Bearer ${bearerToken}`) - .send({name: newAppName}) - .end(function(err, res) { - should.not.exist(err); - res.status.should.equal(200); - done(); - }); - }); - }); - - describe(`delete apps`, function(done) { - it(`should delete apps successful`, function(done) { - request.delete(`/apps/${newAppName}`) - .set('Authorization', `Bearer ${bearerToken}`) - .send() - .end(function(err, res) { - should.not.exist(err); - res.status.should.equal(200); - done(); - }); - }); - }); - -}); diff --git a/test/api/apps/release.test.js b/test/api/apps/release.test.js deleted file mode 100644 index 00eb698d..00000000 --- a/test/api/apps/release.test.js +++ /dev/null @@ -1,228 +0,0 @@ -var app = require('../../../app'); -var request = require('supertest')(app); -var should = require("should"); -var path = require("path"); -var security = require('../../../core/utils/security'); -var factory = require('../../../core/utils/factory'); -var _ = require('lodash'); -const SLEEP_TIME = 5000; - -describe('api/apps/release.test.js', function() { - var account = '522539441@qq.com'; - var password = '123456'; - var authToken; - var machineName = `Login-${Math.random()}`; - var friendlyName = `Login-${Math.random()}`; - var appName = 'Demo-ios'; - var bearerToken; - - before(function(done){ - request.post('/auth/login') - .send({ - account: account, - password: password - }) - .end(function(err, res) { - should.not.exist(err); - var rs = JSON.parse(res.text); - rs.should.containEql({status:"OK"}); - authToken = (new Buffer(`auth:${_.get(rs, 'results.tokens')}`)).toString('base64'); - done(); - }); - }); - - describe('create accessKeys', function(done) { - it('should create accessKeys successful', function(done) { - request.post(`/accessKeys`) - .set('Authorization', `Basic ${authToken}`) - .send({createdBy: machineName, friendlyName: friendlyName, ttl: 30*24*60*60}) - .end(function(err, res) { - should.not.exist(err); - res.status.should.equal(200); - var rs = JSON.parse(res.text); - rs.should.have.properties('accessKey'); - rs.accessKey.should.have.properties(['name', 'createdTime', 'createdBy', - 'expires', 'description', 'friendlyName']); - bearerToken = _.get(rs, 'accessKey.name'); - done(); - }); - }); - }); - - describe('add apps', function(done) { - it('should add apps successful', function(done) { - request.post(`/apps`) - .set('Authorization', `Bearer ${bearerToken}`) - .send({name: appName, os:'iOS', platform:'React-Native'}) - .end(function(err, res) { - should.not.exist(err); - res.status.should.equal(200); - var rs = JSON.parse(res.text); - rs.should.have.properties('app'); - rs.app.should.have.properties(['name', 'collaborators']); - done(); - }); - }); - }); - - describe('release apps', function(done) { - it('should release apps successful', function(done) { - request.post(`/apps/${appName}/deployments/Staging/release`) - .set('Authorization', `Bearer ${bearerToken}`) - .attach('package', path.resolve(__dirname, './bundle.zip')) - .field('packageInfo', `{"appVersion": "1.0.0", "description": "test", "isMandatory": false}`) - .end(function(err, res) { - should.not.exist(err); - res.status.should.equal(200); - done(); - }); - }); - - it('should release apps v2 successful', function(done) { - request.post(`/apps/${appName}/deployments/Staging/release`) - .set('Authorization', `Bearer ${bearerToken}`) - .attach('package', path.resolve(__dirname, './bundle_v2.zip')) - .field('packageInfo', `{"appVersion": "1.0.0", "description": "test", "isMandatory": false}`) - .end(function(err, res) { - should.not.exist(err); - res.status.should.equal(200); - setTimeout(function(){ - done(); - }, SLEEP_TIME); - }); - }); - }); - - describe('promote apps', function(done) { - it('should promote apps successful', function(done) { - request.post(`/apps/${appName}/deployments/Staging/promote/Production`) - .set('Authorization', `Bearer ${bearerToken}`) - .send() - .end(function(err, res) { - res.status.should.equal(200); - done(); - }); - }); - }); - - describe('rollback deployments', function(done) { - it('should rollback deployments successful when point labels', function(done) { - request.post(`/apps/${appName}/deployments/Staging/rollback/v1`) - .set('Authorization', `Bearer ${bearerToken}`) - .send() - .end(function(err, res) { - should.not.exist(err); - res.status.should.equal(200); - res.text.should.equal(`ok`); - setTimeout(function(){ - done(); - }, SLEEP_TIME); - }); - }); - - it('should rollback deployments successful', function(done) { - request.post(`/apps/${appName}/deployments/Staging/rollback`) - .set('Authorization', `Bearer ${bearerToken}`) - .send() - .end(function(err, res) { - should.not.exist(err); - res.status.should.equal(200); - res.text.should.equal(`ok`); - setTimeout(function(){ - done(); - }, SLEEP_TIME); - }); - }); - }); - - describe('show deployments history', function(done) { - it('should not show deployments history successful where deployments does not exist', function(done) { - request.get(`/apps/${appName}/deployments/Test/history`) - .set('Authorization', `Bearer ${bearerToken}`) - .send() - .end(function(err, res) { - should.not.exist(err); - res.status.should.equal(406); - res.text.should.equal(`does not find the deployment`); - done(); - }); - }); - - it('should show deployments history successful', function(done) { - request.get(`/apps/${appName}/deployments/Staging/history`) - .set('Authorization', `Bearer ${bearerToken}`) - .send() - .end(function(err, res) { - should.not.exist(err); - res.status.should.equal(200); - var rs = JSON.parse(res.text); - rs.should.have.properties('history'); - rs.history.should.be.an.instanceOf(Array); - rs.history.should.matchEach(function(it) { - return it.should.have.properties([ - 'description','isDisabled','isMandatory','rollout','appVersion','packageHash', - 'blobUrl','size','manifestBlobUrl','diffPackageMap','releaseMethod','uploadTime', - 'originalLabel','originalDeployment','label','releasedBy' - ]); - }); - done(); - }); - }); - }); - - describe('delete deployments history', function(done) { - it('should not delete deployments history successful where deployments does not exist', function(done) { - request.delete(`/apps/${appName}/deployments/Test/history`) - .set('Authorization', `Bearer ${bearerToken}`) - .send() - .end(function(err, res) { - should.not.exist(err); - res.status.should.equal(406); - res.text.should.equal(`does not find the deployment`); - done(); - }); - }); - - it('should delete deployments history successful', function(done) { - request.delete(`/apps/${appName}/deployments/Staging/history`) - .set('Authorization', `Bearer ${bearerToken}`) - .send() - .end(function(err, res) { - should.not.exist(err); - res.status.should.equal(200); - res.text.should.equal(`ok`); - done(); - }); - }); - }); - - describe('show deployments metrics', function(done) { - it('should not show deployments metrics successful where deployments does not exist', function(done) { - request.get(`/apps/${appName}/deployments/Test/metrics`) - .set('Authorization', `Bearer ${bearerToken}`) - .send() - .end(function(err, res) { - should.not.exist(err); - res.status.should.equal(200); - done(); - }); - }); - - it('should show deployments metrics successful', function(done) { - request.get(`/apps/${appName}/deployments/Staging/metrics`) - .set('Authorization', `Bearer ${bearerToken}`) - .send() - .end(function(err, res) { - should.not.exist(err); - res.status.should.equal(200); - var rs = JSON.parse(res.text); - rs.should.have.properties('metrics'); - rs.metrics.should.be.an.instanceOf(Object); - rs.metrics.should.matchEach(function(it) { - return it.should.have.properties(['active','downloaded','failed','installed']); - }); - done(); - }); - }); - }); -}); diff --git a/test/api/auth/auth.test.js b/test/api/auth/auth.test.js deleted file mode 100644 index 0263639a..00000000 --- a/test/api/auth/auth.test.js +++ /dev/null @@ -1,131 +0,0 @@ -var app = require('../../../app'); -var request = require('supertest')(app); -var should = require("should"); -var config = require('../../../core/config'); -var _ = require('lodash'); - -describe('api/auth/test.js', function() { - var account = '522539441@qq.com'; - var password = '123456'; - - describe('sign in view', function(done) { - it('should show sign in redirect view successful', function(done) { - _.set(config, 'common.codePushWebUrl', 'http://127.0.0.1:3001') - request.get('/auth/login') - .send() - .end(function(err, res) { - should.not.exist(err); - res.status.should.equal(302); - done(); - }); - }); - - it('should show sign in view successful', function(done) { - _.set(config, 'common.codePushWebUrl', null) - request.get('/auth/login') - .send() - .end(function(err, res) { - should.not.exist(err); - res.status.should.equal(200); - done(); - }); - }); - }); - - describe('sign up view', function(done) { - it('should show sign up redirect view successful', function(done) { - _.set(config, 'common.codePushWebUrl', 'http://127.0.0.1:3001') - request.get('/auth/register') - .send() - .end(function(err, res) { - should.not.exist(err); - res.status.should.equal(302); - done(); - }); - }); - - it('should show sign up view successful', function(done) { - _.set(config, 'common.codePushWebUrl', null) - request.get('/auth/register') - .send() - .end(function(err, res) { - should.not.exist(err); - res.status.should.equal(200); - done(); - }); - }); - }); - - describe('sign in', function(done) { - it('should not sign in successful when account is empty', function(done) { - request.post('/auth/login') - .send({ - account: '', - password: password - }) - .end(function(err, res) { - should.not.exist(err); - JSON.parse(res.text).should.containEql({status:"ERROR",errorMessage:"请您输入邮箱地址"}); - done(); - }); - }); - it('should not sign in successful when account is not exist', function(done) { - request.post('/auth/login') - .send({ - account: account + '1', - password: password - }) - .end(function(err, res) { - should.not.exist(err); - JSON.parse(res.text).should.containEql({status:"ERROR",errorMessage:"您输入的邮箱或密码有误"}); - done(); - }); - }); - it('should not sign in successful when password is wrong', function(done) { - request.post('/auth/login') - .send({ - account: account, - password: password + '1' - }) - .end(function(err, res) { - should.not.exist(err); - JSON.parse(res.text).should.containEql({status:"ERROR",errorMessage:"您输入的邮箱或密码有误"}); - done(); - }); - }); - it('should sign in successful', function(done) { - request.post('/auth/login') - .send({ - account: account, - password: password - }) - .end(function(err, res) { - should.not.exist(err); - JSON.parse(res.text).should.containEql({status:"OK"}) - done(); - }); - }); - }); - - describe('logout', function(done) { - it('should logout successful', function(done) { - request.post('/auth/logout') - .end(function(err, res) { - should.not.exist(err); - res.text.should.equal('ok'); - done(); - }); - }); - }); - - describe('link', function(done) { - it('should link successful', function(done) { - request.get('/auth/link') - .end(function(err, res) { - should.not.exist(err); - res.headers.location.should.equal('/auth/login'); - done(); - }); - }); - }); -}); diff --git a/test/api/index/index.test.js b/test/api/index/index.test.js deleted file mode 100644 index 51f51289..00000000 --- a/test/api/index/index.test.js +++ /dev/null @@ -1,216 +0,0 @@ -var app = require('../../../app'); -var request = require('supertest')(app); -var should = require("should"); -var _ = require('lodash'); - -describe('api/index/index.test.js', function() { - var account = '522539441@qq.com'; - var password = '123456'; - var authToken; - var appName = 'Demo-ios'; - var deploymentKey; - var packageHash; - var label; - before(function(done){ - request.post('/auth/login') - .send({ - account: account, - password: password - }) - .end(function(err, res) { - should.not.exist(err); - var rs = JSON.parse(res.text); - rs.should.containEql({status:"OK"}); - authToken = (new Buffer(`auth:${_.get(rs, 'results.tokens')}`)).toString('base64'); - done(); - }); - }); - - describe('list apps all deployments', function(done) { - it('should list apps all deployments successful', function(done) { - request.get(`/apps/${appName}/deployments`) - .set('Authorization', `Basic ${authToken}`) - .send() - .end(function(err, res) { - should.not.exist(err); - res.status.should.equal(200); - var rs = JSON.parse(res.text); - rs.should.have.properties('deployments'); - rs.deployments.should.be.an.instanceOf(Array); - rs.deployments.should.matchEach(function(it) { - if (_.get(it, 'name') == 'Production') { - deploymentKey = _.get(it, 'key'); - packageHash = _.get(it, 'package.packageHash'); - label = _.get(it, 'package.label'); - } - return it.should.have.properties(['createdTime', 'id', 'key', 'name', 'package']); - }); - done(); - }); - }); - }); - - describe('render index views', function(done) { - it('should render index views successful', function(done) { - request.get(`/`) - .send() - .end(function(err, res) { - should.not.exist(err); - res.status.should.equal(200); - done(); - }); - }); - }); - - describe('render README.md views', function(done) { - it('should render README.md views successful', function(done) { - request.get(`/README.md`) - .send() - .end(function(err, res) { - should.not.exist(err); - res.status.should.equal(200); - done(); - }); - }); - }); - - describe('render tokens views', function(done) { - it('should render tokens views successful', function(done) { - request.get(`/tokens`) - .send() - .end(function(err, res) { - should.not.exist(err); - res.status.should.equal(200); - done(); - }); - }); - }); - - describe('authenticated', function(done) { - it('should authenticated successful', function(done) { - request.get(`/authenticated`) - .set('Authorization', `Basic ${authToken}`) - .send() - .end(function(err, res) { - should.not.exist(err); - res.status.should.equal(200); - done(); - }); - }); - }); - - describe('updateCheck', function(done) { - it('should not updateCheck successful where deploymentKey is empty', function(done) { - request.get(`/updateCheck?deploymentKey=&appVersion=1.0.0&label=&packageHash=`) - .send() - .end(function(err, res) { - should.not.exist(err); - res.status.should.equal(404); - res.text.should.equal(`please input deploymentKey and appVersion`); - done(); - }); - }); - - it('should not updateCheck successful where deploymentKey does not exist', function(done) { - request.get(`/updateCheck?deploymentKey=123&appVersion=1.0.0&label=&packageHash=`) - .send() - .end(function(err, res) { - should.not.exist(err); - res.status.should.equal(404); - res.text.should.equal(`Not found deployment, check deployment key is right.`); - done(); - }); - }); - - it('should updateCheck successful', function(done) { - request.get(`/updateCheck?deploymentKey=${deploymentKey}&appVersion=1.0.0&label=&packageHash=`) - .send() - .end(function(err, res) { - should.not.exist(err); - res.status.should.equal(200); - var rs = JSON.parse(res.text); - rs.should.have.properties('updateInfo'); - rs.updateInfo.should.have.properties([ - 'downloadURL','description','isAvailable','isMandatory','appVersion', - 'packageHash','label','packageSize','updateAppVersion','shouldRunBinaryVersion' - ]); - rs.updateInfo.isAvailable.should.be.true; - done(); - }); - }); - - it('should updateCheck successful when packageHash is newer', function(done) { - request.get(`/updateCheck?deploymentKey=${deploymentKey}&appVersion=1.0.0&label=&packageHash=${packageHash}`) - .send() - .end(function(err, res) { - should.not.exist(err); - res.status.should.equal(200); - var rs = JSON.parse(res.text); - rs.should.have.properties('updateInfo'); - rs.updateInfo.should.have.properties([ - 'downloadURL','description','isAvailable','isMandatory','appVersion', - 'packageHash','label','packageSize','updateAppVersion','shouldRunBinaryVersion' - ]); - rs.updateInfo.isAvailable.should.be.false; - done(); - }); - }); - }); - - describe('reportStatus download', function(done) { - it('should reportStatus download successful', function(done) { - request.post(`/reportStatus/download`) - .send({ - clientUniqueId: Math.random(), - label: label, - deploymentKey:deploymentKey - }) - .end(function(err, res) { - should.not.exist(err); - res.status.should.equal(200); - res.text.should.equal(`OK`); - setTimeout(function(){ - done(); - }, 1000) - }); - }); - }); - - describe('reportStatus deploy', function(done) { - it('should reportStatus deploy successful', function(done) { - request.post(`/reportStatus/deploy`) - .send({ - clientUniqueId: Math.random(), - label: label, - deploymentKey: deploymentKey, - status: 'DeploymentSucceeded' - }) - .end(function(err, res) { - should.not.exist(err); - res.status.should.equal(200); - res.text.should.equal(`OK`); - setTimeout(function(){ - done(); - }, 1000) - }); - }); - - it('should reportStatus deploy successful', function(done) { - request.post(`/reportStatus/deploy`) - .send({ - clientUniqueId: Math.random(), - label: label, - deploymentKey: deploymentKey, - status: 'DeploymentFailed' - }) - .end(function(err, res) { - should.not.exist(err); - res.status.should.equal(200); - res.text.should.equal(`OK`); - setTimeout(function(){ - done(); - }, 1000) - }); - }); - }); -}); diff --git a/test/api/init/database.js b/test/api/init/database.js deleted file mode 100644 index a32c0aea..00000000 --- a/test/api/init/database.js +++ /dev/null @@ -1,64 +0,0 @@ -var config = require('../../../core/config'); -var mysql = require('mysql2'); -var redis = require('redis'); -var should = require('should'); -var fs = require('fs'); -var path = require('path'); - -describe('api/init/database.js', function() { - - describe('create database', function(done) { - it('should create database successful', function(done) { - var connection = mysql.createConnection({ - host: config.db.host, - user: config.db.username, - password: config.db.password, - multipleStatements: true - }); - connection.connect(); - connection.query(`DROP DATABASE IF EXISTS ${config.db.database};CREATE DATABASE IF NOT EXISTS ${config.db.database}`, function(err, rows, fields) { - should.not.exist(err); - done(); - }); - connection.end(); - }); - }); - - describe('flushall redis', function(done) { - it('should flushall redis successful', function(done) { - var client = redis.createClient(config.redis.default); - client.flushall(function (err, reply) { - should.not.exist(err); - reply.toLowerCase().should.equal('ok'); - done(); - }); - }); - }); - - describe('import data from sql files', function(done) { - var connection; - before(function() { - connection = mysql.createConnection({ - host: config.db.host, - user: config.db.username, - password: config.db.password, - database: config.db.database, - multipleStatements: true - }); - connection.connect(); - }); - - after(function() { - connection.end(); - }); - - it('should import data codepush-all.sql successful', function(done) { - var sql = fs.readFileSync(path.resolve(__dirname, '../../../sql/codepush-all.sql'), 'utf-8'); - connection.query(sql, function(err, results) { - should.not.exist(err); - done(); - }); - }); - }); - -}); diff --git a/test/api/users/users.test.js b/test/api/users/users.test.js deleted file mode 100644 index 2b936dbf..00000000 --- a/test/api/users/users.test.js +++ /dev/null @@ -1,257 +0,0 @@ -var app = require('../../../app'); -var request = require('supertest')(app); -var should = require("should"); -var security = require('../../../core/utils/security'); -var factory = require('../../../core/utils/factory'); -var _ = require('lodash'); - -describe('api/users/users.test.js', function() { - var accountExist = 'lisong2010@gmail.com'; - var account = '522539441@qq.com'; - var registerKey = `REGISTER_CODE_${security.md5(account)}`; - var password = '654321'; - var newPassword = '123456'; - - describe('check email does exists', function(done) { - it('should not check email successful when not input email', function(done) { - request.get(`/users/exists`) - .send() - .end(function(err, res) { - should.not.exist(err); - JSON.parse(res.text).should.containEql({status:"ERROR", message: "请您输入邮箱地址"}); - done(); - }); - }); - - it('should not exists account when sign up', function(done) { - request.get(`/users/exists?email=${account}`) - .send() - .end(function(err, res) { - should.not.exist(err); - JSON.parse(res.text).should.containEql({status:"OK", exists: false}); - done(); - }); - }); - - }); - - describe('send register code to email', function(done) { - it('should not send register code successful when not input email', function(done) { - request.post(`/users/registerCode`) - .send({}) - .end(function(err, res) { - should.not.exist(err); - JSON.parse(res.text).should.containEql({status:"ERROR", message: "请您输入邮箱地址"}); - done(); - }); - }); - - it('should not send register code successful when email already exists', function(done) { - request.post(`/users/registerCode`) - .send({email: accountExist}) - .end(function(err, res) { - should.not.exist(err); - JSON.parse(res.text).should.containEql({status:"ERROR", message: `"${accountExist}" 已经注册过,请更换邮箱注册`}); - done(); - }); - }); - - it('should send register successful', function(done) { - request.post(`/users/registerCode`) - .send({email: account}) - .end(function(err, res) { - should.not.exist(err); - JSON.parse(res.text).should.containEql({status:"OK"}); - done(); - }); - }); - - }); - - describe('check register code', function(done) { - var token = 'invalid token'; - var account2 = '522539441@qq.com2'; - var storageToken; - before(function(done){ - var client = factory.getRedisClient("default"); - client.getAsync(registerKey) - .then(function (t) { - storageToken = t; - done(); - }) - .finally(() => client.quit()); - }); - - it('should not check register code successful when email already exists', function(done) { - request.get(`/users/registerCode/exists?email=${accountExist}`) - .send() - .end(function(err, res) { - should.not.exist(err); - JSON.parse(res.text).should.containEql({status:"ERROR", message: `"${accountExist}" 已经注册过,请更换邮箱注册`}); - done(); - }); - }); - - it('should not check register code successful when token expired', function(done) { - request.get(`/users/registerCode/exists?email=${account2}`) - .send() - .end(function(err, res) { - should.not.exist(err); - JSON.parse(res.text).should.containEql({status:"ERROR", message: `验证码已经失效,请您重新获取`}); - done(); - }); - }); - - it('should not check register code successful when token is invalid', function(done) { - request.get(`/users/registerCode/exists?email=${account}&token=${token}`) - .send() - .end(function(err, res) { - should.not.exist(err); - JSON.parse(res.text).should.containEql({status:"ERROR", message: `您输入的验证码不正确,请重新输入`}); - done(); - }); - }); - - it('should check register code successful', function(done) { - request.get(`/users/registerCode/exists?email=${account}&token=${storageToken}`) - .send() - .end(function(err, res) { - should.not.exist(err); - JSON.parse(res.text).should.containEql({status:"OK"}); - done(); - }); - }); - - }); - - describe('sign up', function(done) { - var storageToken; - before(function(done){ - var client = factory.getRedisClient("default"); - client.getAsync(registerKey) - .then(function (t) { - storageToken = t; - done(); - }) - .finally(() => client.quit()); - }); - - it('should not sign up successful when password length invalid', function(done) { - request.post(`/users`) - .send({email:account, password: '1234', token: storageToken}) - .end(function(err, res) { - should.not.exist(err); - JSON.parse(res.text).should.containEql({status:"ERROR", message: `请您输入6~20位长度的密码`}); - done(); - }); - }); - - it('should sign up successful', function(done) { - request.post(`/users`) - .send({email:account, password: password, token: storageToken}) - .end(function(err, res) { - should.not.exist(err); - JSON.parse(res.text).should.containEql({status:"OK"}); - done(); - }); - }); - }); - - describe('change password', function(done) { - var authToken; - before(function(done){ - request.post('/auth/login') - .send({ - account: account, - password: password - }) - .end(function(err, res) { - should.not.exist(err); - var rs = JSON.parse(res.text); - rs.should.containEql({status:"OK"}); - authToken = (new Buffer(`auth:${_.get(rs, 'results.tokens')}`)).toString('base64'); - done(); - }); - }); - - it('should not change password successful when authToken invalid', function(done) { - request.patch(`/users/password`) - .set('Authorization', `Basic 11345`) - .send({oldPassword: password, newPassword: newPassword}) - .end(function(err, res) { - should.not.exist(err); - var rs = JSON.parse(res.text); - res.status.should.equal(200); - rs.should.containEql({status:401}); - done(); - }); - }); - - it('should not change password successful where password invalid', function(done) { - request.patch(`/users/password`) - .set('Authorization', `Basic ${authToken}`) - .send({oldPassword: '123321', newPassword: newPassword}) - .end(function(err, res) { - should.not.exist(err); - res.status.should.equal(200); - JSON.parse(res.text).should.containEql({status:"ERROR", message: `您输入的旧密码不正确,请重新输入`}); - done(); - }); - }); - - it('should not change password successful where new password invalid', function(done) { - request.patch(`/users/password`) - .set('Authorization', `Basic ${authToken}`) - .send({oldPassword: password, newPassword: '1234'}) - .end(function(err, res) { - should.not.exist(err); - res.status.should.equal(200); - JSON.parse(res.text).should.containEql({status:"ERROR", message: `请您输入6~20位长度的新密码`}); - done(); - }); - }); - - it('should change password successful', function(done) { - request.patch(`/users/password`) - .set('Authorization', `Basic ${authToken}`) - .send({oldPassword:password, newPassword: newPassword}) - .end(function(err, res) { - should.not.exist(err); - res.status.should.equal(200); - JSON.parse(res.text).should.containEql({status:"OK"}); - done(); - }); - }); - }); - - describe('user modules', function(done) { - var authToken; - before(function(done){ - request.post('/auth/login') - .send({ - account: account, - password: newPassword - }) - .end(function(err, res) { - should.not.exist(err); - var rs = JSON.parse(res.text); - rs.should.containEql({status:"OK"}); - authToken = (new Buffer(`auth:${_.get(rs, 'results.tokens')}`)).toString('base64'); - done(); - }); - }); - - it('should get userinfo successful', function(done) { - request.get(`/users`) - .set('Authorization', `Basic ${authToken}`) - .send() - .end(function(err, res) { - should.not.exist(err); - res.status.should.equal(200); - done(); - }); - }); - - }); - -}); diff --git a/tests/api/accessKeys/accessKeys.test.js b/tests/api/accessKeys/accessKeys.test.js new file mode 100644 index 00000000..eb9266ab --- /dev/null +++ b/tests/api/accessKeys/accessKeys.test.js @@ -0,0 +1,115 @@ +const { app } = require('../../../bin/app'); +const request = require('supertest')(app); +const should = require('should'); +const _ = require('lodash'); + +describe('api/accessKeys/accessKeys.test.js', function () { + var account = '522539441@qq.com'; + var password = '123456'; + var authToken; + var friendlyName = 'test'; + var newFriendlyName = 'newtest'; + before(function (done) { + request + .post('/auth/login') + .send({ + account: account, + password: password, + }) + .end(function (err, res) { + should.not.exist(err); + var rs = JSON.parse(res.text); + rs.should.containEql({ status: 'OK' }); + authToken = Buffer.from(`auth:${_.get(rs, 'results.tokens')}`).toString('base64'); + done(); + }); + }); + + describe('create accessKeys', function (done) { + it('should create accessKeys successful', function (done) { + request + .post(`/accessKeys`) + .set('Authorization', `Basic ${authToken}`) + .send({ + createdBy: 'tablee', + friendlyName: friendlyName, + ttl: 30 * 24 * 60 * 60, + }) + .end(function (err, res) { + should.not.exist(err); + res.status.should.equal(200); + var rs = JSON.parse(res.text); + rs.should.have.properties('accessKey'); + rs.accessKey.should.have.properties([ + 'name', + 'createdTime', + 'createdBy', + 'expires', + 'description', + 'friendlyName', + ]); + done(); + }); + }); + + it('should not create accessKeys successful when friendlyName exist', function (done) { + request + .post(`/accessKeys`) + .set('Authorization', `Basic ${authToken}`) + .send({ + createdBy: 'tablee', + friendlyName: friendlyName, + ttl: 30 * 24 * 60 * 60, + }) + .end(function (err, res) { + should.not.exist(err); + res.status.should.equal(406); + res.text.should.equal(`The access key "${friendlyName}" already exists.`); + done(); + }); + }); + }); + + describe('list accessKeys', function (done) { + it('should list accessKeys successful', function (done) { + request + .get(`/accessKeys`) + .set('Authorization', `Basic ${authToken}`) + .send() + .end(function (err, res) { + should.not.exist(err); + res.status.should.equal(200); + var rs = JSON.parse(res.text); + rs.should.have.properties('accessKeys'); + rs.accessKeys.should.be.an.instanceOf(Array); + rs.accessKeys.should.matchEach(function (it) { + return it.should.have.properties([ + 'name', + 'createdTime', + 'createdBy', + 'expires', + 'description', + 'friendlyName', + ]); + }); + done(); + }); + }); + }); + + describe('delete accessKeys', function (done) { + it('should delete accessKeys successful', function (done) { + request + .delete(`/accessKeys/${encodeURI(newFriendlyName)}`) + .set('Authorization', `Basic ${authToken}`) + .send() + .end(function (err, res) { + should.not.exist(err); + res.status.should.equal(200); + var rs = JSON.parse(res.text); + rs.should.have.properties('friendlyName'); + done(); + }); + }); + }); +}); diff --git a/tests/api/account/account.test.js b/tests/api/account/account.test.js new file mode 100644 index 00000000..31bd118c --- /dev/null +++ b/tests/api/account/account.test.js @@ -0,0 +1,45 @@ +const { app } = require('../../../bin/app'); +const request = require('supertest')(app); +const should = require('should'); +const _ = require('lodash'); + +describe('api/account/account.test.js', function () { + var account = '522539441@qq.com'; + var password = '123456'; + + describe('user modules', function (done) { + var authToken; + before(function (done) { + request + .post('/auth/login') + .send({ + account: account, + password: password, + }) + .end(function (err, res) { + should.not.exist(err); + var rs = JSON.parse(res.text); + rs.should.containEql({ status: 'OK' }); + authToken = Buffer.from(`auth:${_.get(rs, 'results.tokens')}`).toString( + 'base64', + ); + done(); + }); + }); + + it('should get account info successful', function (done) { + request + .get(`/account`) + .set('Authorization', `Basic ${authToken}`) + .send() + .end(function (err, res) { + should.not.exist(err); + res.status.should.equal(200); + var rs = JSON.parse(res.text); + rs.should.have.properties('account'); + rs.account.should.have.properties(['email', 'linkedProviders', 'name']); + done(); + }); + }); + }); +}); diff --git a/tests/api/apps/apps.test.js b/tests/api/apps/apps.test.js new file mode 100644 index 00000000..ea7b7fc6 --- /dev/null +++ b/tests/api/apps/apps.test.js @@ -0,0 +1,490 @@ +const { app } = require('../../../bin/app'); +const request = require('supertest')(app); +const should = require('should'); +const _ = require('lodash'); + +describe('api/apps/apps.test.js', function () { + var account = '522539441@qq.com'; + var email = 'lisong2010@gmail.com'; + var emailInvalid = 'lisong2010'; + var password = '123456'; + var authToken; + var machineName = `Login-${Math.random()}`; + var friendlyName = `Login-${Math.random()}`; + var appName = 'test'; + var newAppName = 'newtest'; + var bearerToken; + var testDeployment = 'test'; + var newTestDeployment = 'newtest'; + + before(function (done) { + request + .post('/auth/login') + .send({ + account: account, + password: password, + }) + .end(function (err, res) { + should.not.exist(err); + var rs = JSON.parse(res.text); + rs.should.containEql({ status: 'OK' }); + authToken = Buffer.from(`auth:${_.get(rs, 'results.tokens')}`).toString('base64'); + done(); + }); + }); + + describe('create accessKeys', function (done) { + it('should create accessKeys successful', function (done) { + request + .post(`/accessKeys`) + .set('Authorization', `Basic ${authToken}`) + .send({ + createdBy: machineName, + friendlyName: friendlyName, + ttl: 30 * 24 * 60 * 60, + }) + .end(function (err, res) { + should.not.exist(err); + res.status.should.equal(200); + var rs = JSON.parse(res.text); + rs.should.have.properties('accessKey'); + rs.accessKey.should.have.properties([ + 'name', + 'createdTime', + 'createdBy', + 'expires', + 'description', + 'friendlyName', + ]); + bearerToken = _.get(rs, 'accessKey.name'); + done(); + }); + }); + }); + + describe('add apps', function (done) { + it('should not add apps successful when appName is empty', function (done) { + request + .post(`/apps`) + .set('Authorization', `Bearer ${bearerToken}`) + .send({}) + .end(function (err, res) { + should.not.exist(err); + res.status.should.equal(406); + res.text.should.equal(`Please input name!`); + done(); + }); + }); + + it('should add apps successful', function (done) { + request + .post(`/apps`) + .set('Authorization', `Bearer ${bearerToken}`) + .send({ name: appName, os: 'iOS', platform: 'React-Native' }) + .end(function (err, res) { + should.not.exist(err); + res.status.should.equal(200); + var rs = JSON.parse(res.text); + rs.should.have.properties('app'); + rs.app.should.have.properties(['name', 'collaborators']); + done(); + }); + }); + + it('should not add apps successful when appName exists', function (done) { + request + .post(`/apps`) + .set('Authorization', `Bearer ${bearerToken}`) + .send({ name: appName, os: 'iOS', platform: 'React-Native' }) + .end(function (err, res) { + should.not.exist(err); + res.status.should.equal(406); + res.text.should.equal(`${appName} Exist!`); + done(); + }); + }); + }); + + describe('list apps', function (done) { + it('should list apps successful', function (done) { + request + .get(`/apps`) + .set('Authorization', `Bearer ${bearerToken}`) + .send() + .end(function (err, res) { + should.not.exist(err); + res.status.should.equal(200); + var rs = JSON.parse(res.text); + rs.should.have.properties('apps'); + rs.apps.should.be.an.instanceOf(Array); + rs.apps.should.matchEach(function (it) { + return it.should.have.properties(['collaborators', 'deployments', 'name']); + }); + done(); + }); + }); + }); + + describe('list apps all deployments', function (done) { + it('should list apps all deployments successful', function (done) { + request + .get(`/apps/${appName}/deployments`) + .set('Authorization', `Bearer ${bearerToken}`) + .send() + .end(function (err, res) { + should.not.exist(err); + res.status.should.equal(200); + var rs = JSON.parse(res.text); + rs.should.have.properties('deployments'); + rs.deployments.should.be.an.instanceOf(Array); + rs.deployments.should.matchEach(function (it) { + return it.should.have.properties([ + 'createdTime', + 'id', + 'key', + 'name', + 'package', + ]); + }); + done(); + }); + }); + }); + + describe(`create deployments ${testDeployment}`, function (done) { + it('should create deployments successful', function (done) { + request + .post(`/apps/${appName}/deployments`) + .set('Authorization', `Bearer ${bearerToken}`) + .send({ name: testDeployment }) + .end(function (err, res) { + should.not.exist(err); + res.status.should.equal(200); + var rs = JSON.parse(res.text); + rs.should.have.properties('deployment'); + rs.deployment.should.have.properties(['key', 'name']); + done(); + }); + }); + + it('should not create deployments successful when deployment exists', function (done) { + request + .post(`/apps/${appName}/deployments`) + .set('Authorization', `Bearer ${bearerToken}`) + .send({ name: testDeployment }) + .end(function (err, res) { + should.not.exist(err); + res.status.should.equal(406); + res.text.should.equal(`${testDeployment} name does Exist!`); + done(); + }); + }); + }); + + describe(`rename deployments ${testDeployment}`, function (done) { + it('should rename deployments successful', function (done) { + request + .patch(`/apps/${appName}/deployments/${testDeployment}`) + .set('Authorization', `Bearer ${bearerToken}`) + .send({ name: newTestDeployment }) + .end(function (err, res) { + should.not.exist(err); + res.status.should.equal(200); + var rs = JSON.parse(res.text); + rs.should.have.properties('deployment'); + rs.deployment.should.have.properties(['name']); + done(); + }); + }); + + it('should not rename deployments successful when new deployments name does exists', function (done) { + request + .patch(`/apps/${appName}/deployments/${testDeployment}`) + .set('Authorization', `Bearer ${bearerToken}`) + .send({ name: newTestDeployment }) + .end(function (err, res) { + should.not.exist(err); + res.status.should.equal(406); + res.text.should.equal(`${newTestDeployment} name does Exist!`); + done(); + }); + }); + + it('should not rename deployments successful when deployments name does not exists', function (done) { + request + .patch(`/apps/${appName}/deployments/${testDeployment}`) + .set('Authorization', `Bearer ${bearerToken}`) + .send({ name: 'hello' }) + .end(function (err, res) { + should.not.exist(err); + res.status.should.equal(406); + res.text.should.equal(`does not find the deployment "${testDeployment}"`); + done(); + }); + }); + }); + + describe(`delete deployments ${newTestDeployment}`, function (done) { + it('should delete deployments successful', function (done) { + request + .delete(`/apps/${appName}/deployments/${newTestDeployment}`) + .set('Authorization', `Bearer ${bearerToken}`) + .send() + .end(function (err, res) { + should.not.exist(err); + res.status.should.equal(200); + var rs = JSON.parse(res.text); + rs.should.have.properties('deployment'); + rs.deployment.should.have.properties(['name']); + done(); + }); + }); + + it(`should not delete deployments successful when ${newTestDeployment} not exists`, function (done) { + request + .delete(`/apps/${appName}/deployments/${newTestDeployment}`) + .set('Authorization', `Bearer ${bearerToken}`) + .send() + .end(function (err, res) { + should.not.exist(err); + res.status.should.equal(406); + res.text.should.equal(`does not find the deployment "${newTestDeployment}"`); + done(); + }); + }); + }); + + describe(`add collaborators`, function (done) { + it(`should not add collaborators successful when ${emailInvalid} invalid`, function (done) { + request + .post(`/apps/${appName}/collaborators/${emailInvalid}`) + .set('Authorization', `Bearer ${bearerToken}`) + .send() + .end(function (err, res) { + should.not.exist(err); + res.status.should.equal(406); + res.text.should.equal(`Invalid Email!`); + done(); + }); + }); + + it('should add collaborators successful', function (done) { + request + .post(`/apps/${appName}/collaborators/${email}`) + .set('Authorization', `Bearer ${bearerToken}`) + .send() + .end(function (err, res) { + should.not.exist(err); + res.status.should.equal(200); + done(); + }); + }); + + it(`should not add collaborators successful when ${email} is already a collaborators`, function (done) { + request + .post(`/apps/${appName}/collaborators/${email}`) + .set('Authorization', `Bearer ${bearerToken}`) + .send() + .end(function (err, res) { + should.not.exist(err); + res.status.should.equal(406); + res.text.should.equal(`user already is Collaborator.`); + done(); + }); + }); + }); + + describe(`list collaborators`, function (done) { + it('should list collaborators successful', function (done) { + request + .get(`/apps/${appName}/collaborators`) + .set('Authorization', `Bearer ${bearerToken}`) + .send() + .end(function (err, res) { + should.not.exist(err); + res.status.should.equal(200); + var rs = JSON.parse(res.text); + rs.should.have.properties('collaborators'); + done(); + }); + }); + }); + + describe(`delete collaborators`, function (done) { + it(`should not delete collaborators successful when ${emailInvalid} invalid`, function (done) { + request + .delete(`/apps/${appName}/collaborators/${emailInvalid}`) + .set('Authorization', `Bearer ${bearerToken}`) + .send() + .end(function (err, res) { + should.not.exist(err); + res.status.should.equal(406); + res.text.should.equal(`Invalid Email!`); + done(); + }); + }); + + it(`should not delete collaborators successful when email is yourself`, function (done) { + request + .delete(`/apps/${appName}/collaborators/${account}`) + .set('Authorization', `Bearer ${bearerToken}`) + .send() + .end(function (err, res) { + should.not.exist(err); + res.status.should.equal(406); + res.text.should.equal(`can't delete yourself!`); + done(); + }); + }); + + it('should delete collaborators successful', function (done) { + request + .delete(`/apps/${appName}/collaborators/${email}`) + .set('Authorization', `Bearer ${bearerToken}`) + .send() + .end(function (err, res) { + should.not.exist(err); + res.status.should.equal(200); + done(); + }); + }); + + it(`should not delete collaborators successful when ${email} is not a collaborators`, function (done) { + request + .delete(`/apps/${appName}/collaborators/${email}`) + .set('Authorization', `Bearer ${bearerToken}`) + .send() + .end(function (err, res) { + should.not.exist(err); + res.status.should.equal(406); + res.text.should.equal(`user is not a Collaborator`); + done(); + }); + }); + }); + + describe(`transfer apps`, function (done) { + var authTokenOther; + before(function (done) { + request + .post('/auth/login') + .send({ + account: email, + password: password, + }) + .end(function (err, res) { + should.not.exist(err); + var rs = JSON.parse(res.text); + rs.should.containEql({ status: 'OK' }); + authTokenOther = Buffer.from(`auth:${_.get(rs, 'results.tokens')}`).toString( + 'base64', + ); + done(); + }); + }); + + it(`should not transfer apps successful when ${emailInvalid} invalid`, function (done) { + request + .post(`/apps/${appName}/transfer/${emailInvalid}`) + .set('Authorization', `Bearer ${bearerToken}`) + .send() + .end(function (err, res) { + should.not.exist(err); + res.status.should.equal(406); + res.text.should.equal(`Invalid Email!`); + done(); + }); + }); + + it(`should not transfer apps successful when email is yourself`, function (done) { + request + .post(`/apps/${appName}/transfer/${account}`) + .set('Authorization', `Bearer ${bearerToken}`) + .send() + .end(function (err, res) { + should.not.exist(err); + res.status.should.equal(406); + res.text.should.equal(`You can't transfer to yourself!`); + done(); + }); + }); + + it(`should transfer apps successful`, function (done) { + request + .post(`/apps/${appName}/transfer/${email}`) + .set('Authorization', `Bearer ${bearerToken}`) + .send() + .end(function (err, res) { + should.not.exist(err); + res.status.should.equal(200); + done(); + }); + }); + + it(`should transfer apps back successful`, function (done) { + request + .post(`/apps/${appName}/transfer/${account}`) + .set('Authorization', `Basic ${authTokenOther}`) + .send() + .end(function (err, res) { + should.not.exist(err); + res.status.should.equal(200); + done(); + }); + }); + }); + + describe(`rename apps`, function (done) { + it(`should not rename apps successful when new name is invalid`, function (done) { + request + .patch(`/apps/${appName}`) + .set('Authorization', `Bearer ${bearerToken}`) + .send() + .end(function (err, res) { + should.not.exist(err); + res.status.should.equal(406); + res.text.should.equal(`Please input name!`); + done(); + }); + }); + + it(`should not rename apps successful when new name does exists`, function (done) { + request + .patch(`/apps/${appName}`) + .set('Authorization', `Bearer ${bearerToken}`) + .send({ name: appName }) + .end(function (err, res) { + should.not.exist(err); + res.status.should.equal(406); + res.text.should.equal(`${appName} Exist!`); + done(); + }); + }); + + it(`should rename apps successful`, function (done) { + request + .patch(`/apps/${appName}`) + .set('Authorization', `Bearer ${bearerToken}`) + .send({ name: newAppName }) + .end(function (err, res) { + should.not.exist(err); + res.status.should.equal(200); + done(); + }); + }); + }); + + describe(`delete apps`, function (done) { + it(`should delete apps successful`, function (done) { + request + .delete(`/apps/${newAppName}`) + .set('Authorization', `Bearer ${bearerToken}`) + .send() + .end(function (err, res) { + should.not.exist(err); + res.status.should.equal(200); + done(); + }); + }); + }); +}); diff --git a/test/api/apps/bundle.zip b/tests/api/apps/bundle.zip similarity index 100% rename from test/api/apps/bundle.zip rename to tests/api/apps/bundle.zip diff --git a/test/api/apps/bundle_v2.zip b/tests/api/apps/bundle_v2.zip similarity index 100% rename from test/api/apps/bundle_v2.zip rename to tests/api/apps/bundle_v2.zip diff --git a/tests/api/apps/release.test.js b/tests/api/apps/release.test.js new file mode 100644 index 00000000..66fdc6f1 --- /dev/null +++ b/tests/api/apps/release.test.js @@ -0,0 +1,275 @@ +const { app } = require('../../../bin/app'); +const request = require('supertest')(app); +const should = require('should'); +const path = require('path'); +const _ = require('lodash'); + +const SLEEP_TIME = 5000; + +describe('api/apps/release.test.js', function () { + var account = '522539441@qq.com'; + var password = '123456'; + var authToken; + var machineName = `Login-${Math.random()}`; + var friendlyName = `Login-${Math.random()}`; + var appName = 'Demo-ios'; + var bearerToken; + + before(function (done) { + request + .post('/auth/login') + .send({ + account: account, + password: password, + }) + .end(function (err, res) { + should.not.exist(err); + var rs = JSON.parse(res.text); + rs.should.containEql({ status: 'OK' }); + authToken = Buffer.from(`auth:${_.get(rs, 'results.tokens')}`).toString('base64'); + done(); + }); + }); + + describe('create accessKeys', function (done) { + it('should create accessKeys successful', function (done) { + request + .post(`/accessKeys`) + .set('Authorization', `Basic ${authToken}`) + .send({ + createdBy: machineName, + friendlyName: friendlyName, + ttl: 30 * 24 * 60 * 60, + }) + .end(function (err, res) { + should.not.exist(err); + res.status.should.equal(200); + var rs = JSON.parse(res.text); + rs.should.have.properties('accessKey'); + rs.accessKey.should.have.properties([ + 'name', + 'createdTime', + 'createdBy', + 'expires', + 'description', + 'friendlyName', + ]); + bearerToken = _.get(rs, 'accessKey.name'); + done(); + }); + }); + }); + + describe('add apps', function (done) { + it('should add apps successful', function (done) { + request + .post(`/apps`) + .set('Authorization', `Bearer ${bearerToken}`) + .send({ name: appName, os: 'iOS', platform: 'React-Native' }) + .end(function (err, res) { + should.not.exist(err); + res.status.should.equal(200); + var rs = JSON.parse(res.text); + rs.should.have.properties('app'); + rs.app.should.have.properties(['name', 'collaborators']); + done(); + }); + }); + }); + + describe('release apps', function (done) { + it('should release apps successful', function (done) { + request + .post(`/apps/${appName}/deployments/Staging/release`) + .set('Authorization', `Bearer ${bearerToken}`) + .attach('package', path.resolve(__dirname, './bundle.zip')) + .field( + 'packageInfo', + `{"appVersion": "1.0.0", "description": "test", "isMandatory": false}`, + ) + .end(function (err, res) { + should.not.exist(err); + res.status.should.equal(200); + done(); + }); + }); + + it('should release apps v2 successful', function (done) { + request + .post(`/apps/${appName}/deployments/Staging/release`) + .set('Authorization', `Bearer ${bearerToken}`) + .attach('package', path.resolve(__dirname, './bundle_v2.zip')) + .field( + 'packageInfo', + `{"appVersion": "1.0.0", "description": "test", "isMandatory": false}`, + ) + .end(function (err, res) { + should.not.exist(err); + res.status.should.equal(200); + setTimeout(function () { + done(); + }, SLEEP_TIME); + }); + }); + }); + + describe('promote apps', function (done) { + it('should promote apps successful', function (done) { + request + .post(`/apps/${appName}/deployments/Staging/promote/Production`) + .set('Authorization', `Bearer ${bearerToken}`) + .send() + .end(function (err, res) { + res.status.should.equal(200); + done(); + }); + }); + }); + + describe('rollback deployments', function (done) { + it('should rollback deployments successful when point labels', function (done) { + request + .post(`/apps/${appName}/deployments/Staging/rollback/v1`) + .set('Authorization', `Bearer ${bearerToken}`) + .send() + .end(function (err, res) { + should.not.exist(err); + res.status.should.equal(200); + res.text.should.equal(`ok`); + setTimeout(function () { + done(); + }, SLEEP_TIME); + }); + }); + + it('should rollback deployments successful', function (done) { + request + .post(`/apps/${appName}/deployments/Staging/rollback`) + .set('Authorization', `Bearer ${bearerToken}`) + .send() + .end(function (err, res) { + should.not.exist(err); + res.status.should.equal(200); + res.text.should.equal(`ok`); + setTimeout(function () { + done(); + }, SLEEP_TIME); + }); + }); + }); + + describe('show deployments history', function (done) { + it('should not show deployments history successful where deployments does not exist', function (done) { + request + .get(`/apps/${appName}/deployments/Test/history`) + .set('Authorization', `Bearer ${bearerToken}`) + .send() + .end(function (err, res) { + should.not.exist(err); + res.status.should.equal(406); + res.text.should.equal(`does not find the deployment`); + done(); + }); + }); + + it('should show deployments history successful', function (done) { + request + .get(`/apps/${appName}/deployments/Staging/history`) + .set('Authorization', `Bearer ${bearerToken}`) + .send() + .end(function (err, res) { + should.not.exist(err); + res.status.should.equal(200); + var rs = JSON.parse(res.text); + rs.should.have.properties('history'); + rs.history.should.be.an.instanceOf(Array); + rs.history.should.matchEach(function (it) { + return it.should.have.properties([ + 'description', + 'isDisabled', + 'isMandatory', + 'rollout', + 'appVersion', + 'packageHash', + 'blobUrl', + 'size', + 'manifestBlobUrl', + 'diffPackageMap', + 'releaseMethod', + 'uploadTime', + 'originalLabel', + 'originalDeployment', + 'label', + 'releasedBy', + ]); + }); + done(); + }); + }); + }); + + describe('delete deployments history', function (done) { + it('should not delete deployments history successful where deployments does not exist', function (done) { + request + .delete(`/apps/${appName}/deployments/Test/history`) + .set('Authorization', `Bearer ${bearerToken}`) + .send() + .end(function (err, res) { + should.not.exist(err); + res.status.should.equal(406); + res.text.should.equal(`does not find the deployment`); + done(); + }); + }); + + it('should delete deployments history successful', function (done) { + request + .delete(`/apps/${appName}/deployments/Staging/history`) + .set('Authorization', `Bearer ${bearerToken}`) + .send() + .end(function (err, res) { + should.not.exist(err); + res.status.should.equal(200); + res.text.should.equal(`ok`); + done(); + }); + }); + }); + + describe('show deployments metrics', function (done) { + it('should not show deployments metrics successful where deployments does not exist', function (done) { + request + .get(`/apps/${appName}/deployments/Test/metrics`) + .set('Authorization', `Bearer ${bearerToken}`) + .send() + .end(function (err, res) { + should.not.exist(err); + res.status.should.equal(200); + done(); + }); + }); + + it('should show deployments metrics successful', function (done) { + request + .get(`/apps/${appName}/deployments/Staging/metrics`) + .set('Authorization', `Bearer ${bearerToken}`) + .send() + .end(function (err, res) { + should.not.exist(err); + res.status.should.equal(200); + var rs = JSON.parse(res.text); + rs.should.have.properties('metrics'); + rs.metrics.should.be.an.instanceOf(Object); + rs.metrics.should.matchEach(function (it) { + return it.should.have.properties([ + 'active', + 'downloaded', + 'failed', + 'installed', + ]); + }); + done(); + }); + }); + }); +}); diff --git a/tests/api/auth/auth.test.js b/tests/api/auth/auth.test.js new file mode 100644 index 00000000..37af3eb8 --- /dev/null +++ b/tests/api/auth/auth.test.js @@ -0,0 +1,134 @@ +const { app } = require('../../../bin/app'); +const request = require('supertest')(app); +const should = require('should'); +const _ = require('lodash'); + +const { config } = require('../../../bin/core/config'); + +describe('api/auth/test.js', function () { + var account = '522539441@qq.com'; + var password = '123456'; + + describe('sign in view', function (done) { + it('should show sign in view successful', function (done) { + request + .get('/auth/login') + .send() + .end(function (err, res) { + should.not.exist(err); + res.status.should.equal(200); + done(); + }); + }); + }); + + describe('sign up view', function (done) { + it('should show sign in redirect view if sign up not enabled', function (done) { + _.set(config, 'common.allowRegistration', false); + request + .get('/auth/register') + .send() + .end(function (err, res) { + should.not.exist(err); + res.status.should.equal(302); + done(); + }); + }); + + it('should show sign up view successful', function (done) { + _.set(config, 'common.allowRegistration', true); + request + .get('/auth/register') + .send() + .end(function (err, res) { + should.not.exist(err); + res.status.should.equal(200); + done(); + }); + }); + }); + + describe('sign in', function (done) { + it('should not sign in successful when account is empty', function (done) { + request + .post('/auth/login') + .send({ + account: '', + password: password, + }) + .end(function (err, res) { + should.not.exist(err); + JSON.parse(res.text).should.containEql({ + status: 'ERROR', + message: '请您输入邮箱地址', + }); + done(); + }); + }); + it('should not sign in successful when account is not exist', function (done) { + request + .post('/auth/login') + .send({ + account: account + '1', + password: password, + }) + .end(function (err, res) { + should.not.exist(err); + JSON.parse(res.text).should.containEql({ + status: 'ERROR', + message: '您输入的邮箱或密码有误', + }); + done(); + }); + }); + it('should not sign in successful when password is wrong', function (done) { + request + .post('/auth/login') + .send({ + account: account, + password: password + '1', + }) + .end(function (err, res) { + should.not.exist(err); + JSON.parse(res.text).should.containEql({ + status: 'ERROR', + message: '您输入的邮箱或密码有误', + }); + done(); + }); + }); + it('should sign in successful', function (done) { + request + .post('/auth/login') + .send({ + account: account, + password: password, + }) + .end(function (err, res) { + should.not.exist(err); + JSON.parse(res.text).should.containEql({ status: 'OK' }); + done(); + }); + }); + }); + + describe('logout', function (done) { + it('should logout successful', function (done) { + request.post('/auth/logout').end(function (err, res) { + should.not.exist(err); + res.text.should.equal('ok'); + done(); + }); + }); + }); + + describe('link', function (done) { + it('should link successful', function (done) { + request.get('/auth/link').end(function (err, res) { + should.not.exist(err); + res.headers.location.should.equal('/auth/login'); + done(); + }); + }); + }); +}); diff --git a/tests/api/index/index.test.js b/tests/api/index/index.test.js new file mode 100644 index 00000000..8d055011 --- /dev/null +++ b/tests/api/index/index.test.js @@ -0,0 +1,242 @@ +const { app } = require('../../../bin/app'); +const request = require('supertest')(app); +const should = require('should'); +const _ = require('lodash'); + +describe('api/index/index.test.js', function () { + var account = '522539441@qq.com'; + var password = '123456'; + var authToken; + var appName = 'Demo-ios'; + var deploymentKey; + var packageHash; + var label; + before(function (done) { + request + .post('/auth/login') + .send({ + account: account, + password: password, + }) + .end(function (err, res) { + should.not.exist(err); + var rs = JSON.parse(res.text); + rs.should.containEql({ status: 'OK' }); + authToken = Buffer.from(`auth:${_.get(rs, 'results.tokens')}`).toString('base64'); + done(); + }); + }); + + describe('list apps all deployments', function (done) { + it('should list apps all deployments successful', function (done) { + request + .get(`/apps/${appName}/deployments`) + .set('Authorization', `Basic ${authToken}`) + .send() + .end(function (err, res) { + should.not.exist(err); + res.status.should.equal(200); + var rs = JSON.parse(res.text); + rs.should.have.properties('deployments'); + rs.deployments.should.be.an.instanceOf(Array); + rs.deployments.should.matchEach(function (it) { + if (_.get(it, 'name') == 'Production') { + deploymentKey = _.get(it, 'key'); + packageHash = _.get(it, 'package.packageHash'); + label = _.get(it, 'package.label'); + } + return it.should.have.properties([ + 'createdTime', + 'id', + 'key', + 'name', + 'package', + ]); + }); + done(); + }); + }); + }); + + describe('render index views', function (done) { + it('should render index views successful', function (done) { + request + .get(`/`) + .send() + .end(function (err, res) { + should.not.exist(err); + res.status.should.equal(200); + done(); + }); + }); + }); + + describe('render tokens views', function (done) { + it('should render tokens views successful', function (done) { + request + .get(`/tokens`) + .send() + .end(function (err, res) { + should.not.exist(err); + res.status.should.equal(200); + done(); + }); + }); + }); + + describe('authenticated', function (done) { + it('should authenticated successful', function (done) { + request + .get(`/authenticated`) + .set('Authorization', `Basic ${authToken}`) + .send() + .end(function (err, res) { + should.not.exist(err); + res.status.should.equal(200); + done(); + }); + }); + }); + + describe('updateCheck', function (done) { + it('should not updateCheck successful where deploymentKey is empty', function (done) { + request + .get(`/updateCheck?deploymentKey=&appVersion=1.0.0&label=&packageHash=`) + .send() + .end(function (err, res) { + should.not.exist(err); + res.status.should.equal(404); + res.text.should.equal(`please input deploymentKey and appVersion`); + done(); + }); + }); + + it('should not updateCheck successful where deploymentKey does not exist', function (done) { + request + .get(`/updateCheck?deploymentKey=123&appVersion=1.0.0&label=&packageHash=`) + .send() + .end(function (err, res) { + should.not.exist(err); + res.status.should.equal(404); + res.text.should.equal(`Not found deployment, check deployment key is right.`); + done(); + }); + }); + + it('should updateCheck successful', function (done) { + request + .get( + `/updateCheck?deploymentKey=${deploymentKey}&appVersion=1.0.0&label=&packageHash=`, + ) + .send() + .end(function (err, res) { + should.not.exist(err); + res.status.should.equal(200); + var rs = JSON.parse(res.text); + rs.should.have.properties('updateInfo'); + rs.updateInfo.should.have.properties([ + 'downloadURL', + 'description', + 'isAvailable', + 'isMandatory', + 'appVersion', + 'packageHash', + 'label', + 'packageSize', + 'updateAppVersion', + 'shouldRunBinaryVersion', + ]); + rs.updateInfo.isAvailable.should.be.true; + done(); + }); + }); + + it('should updateCheck successful when packageHash is newer', function (done) { + request + .get( + `/updateCheck?deploymentKey=${deploymentKey}&appVersion=1.0.0&label=&packageHash=${packageHash}`, + ) + .send() + .end(function (err, res) { + should.not.exist(err); + res.status.should.equal(200); + var rs = JSON.parse(res.text); + rs.should.have.properties('updateInfo'); + rs.updateInfo.should.have.properties([ + 'downloadURL', + 'description', + 'isAvailable', + 'isMandatory', + 'appVersion', + 'packageHash', + 'label', + 'packageSize', + 'updateAppVersion', + 'shouldRunBinaryVersion', + ]); + rs.updateInfo.isAvailable.should.be.false; + done(); + }); + }); + }); + + describe('reportStatus download', function (done) { + it('should reportStatus download successful', function (done) { + request + .post(`/reportStatus/download`) + .send({ + clientUniqueId: Math.random(), + label: label, + deploymentKey: deploymentKey, + }) + .end(function (err, res) { + should.not.exist(err); + res.status.should.equal(200); + res.text.should.equal(`OK`); + setTimeout(function () { + done(); + }, 1000); + }); + }); + }); + + describe('reportStatus deploy', function (done) { + it('should reportStatus deploy successful', function (done) { + request + .post(`/reportStatus/deploy`) + .send({ + clientUniqueId: Math.random(), + label: label, + deploymentKey: deploymentKey, + status: 'DeploymentSucceeded', + }) + .end(function (err, res) { + should.not.exist(err); + res.status.should.equal(200); + res.text.should.equal(`OK`); + setTimeout(function () { + done(); + }, 1000); + }); + }); + + it('should reportStatus deploy successful', function (done) { + request + .post(`/reportStatus/deploy`) + .send({ + clientUniqueId: Math.random(), + label: label, + deploymentKey: deploymentKey, + status: 'DeploymentFailed', + }) + .end(function (err, res) { + should.not.exist(err); + res.status.should.equal(200); + res.text.should.equal(`OK`); + setTimeout(function () { + done(); + }, 1000); + }); + }); + }); +}); diff --git a/tests/api/init/database.js b/tests/api/init/database.js new file mode 100644 index 00000000..6f754535 --- /dev/null +++ b/tests/api/init/database.js @@ -0,0 +1,72 @@ +const mysql = require('mysql2'); +const should = require('should'); +const fs = require('fs'); +const path = require('path'); + +const { config } = require('../../../bin/core/config'); +const { redisClient } = require('../../../bin/core/utils/connections'); + +describe('api/init/database.js', function () { + describe('create database', function (done) { + it('should create database successful', function (done) { + var connection = mysql.createConnection({ + host: config.db.host, + user: config.db.username, + password: config.db.password, + multipleStatements: true, + }); + connection.connect(); + connection.query( + `DROP DATABASE IF EXISTS ${config.db.database};CREATE DATABASE IF NOT EXISTS ${config.db.database}`, + function (err, rows, fields) { + should.not.exist(err); + done(); + }, + ); + connection.end(); + }); + }); + + describe('flushall redis', function (done) { + it('should flushall redis successful', function (done) { + redisClient + .flushAll() + .then(function (reply) { + reply.toLowerCase().should.equal('ok'); + done(); + }) + .catch(function (err) { + should.not.exist(err); + }); + }); + }); + + describe('import data from sql files', function (done) { + var connection; + before(function () { + connection = mysql.createConnection({ + host: config.db.host, + user: config.db.username, + password: config.db.password, + database: config.db.database, + multipleStatements: true, + }); + connection.connect(); + }); + + after(function () { + connection.end(); + }); + + it('should import data codepush-all.sql successful', function (done) { + var sql = fs.readFileSync( + path.resolve(__dirname, '../../../sql/codepush-all.sql'), + 'utf-8', + ); + connection.query(sql, function (err, results) { + should.not.exist(err); + done(); + }); + }); + }); +}); diff --git a/tests/api/users/users.test.js b/tests/api/users/users.test.js new file mode 100644 index 00000000..22ce484d --- /dev/null +++ b/tests/api/users/users.test.js @@ -0,0 +1,299 @@ +const { app } = require('../../../bin/app'); +const request = require('supertest')(app); +const should = require('should'); +const _ = require('lodash'); + +const { md5 } = require('../../../bin/core/utils/security'); +const { redisClient } = require('../../../bin/core/utils/connections'); + +describe('api/users/users.test.js', function () { + var accountExist = 'lisong2010@gmail.com'; + var account = '522539441@qq.com'; + var registerKey = `REGISTER_CODE_${md5(account)}`; + var password = '654321'; + var newPassword = '123456'; + + describe('check email does exists', function (done) { + it('should not check email successful when not input email', function (done) { + request + .get(`/users/exists`) + .send() + .end(function (err, res) { + should.not.exist(err); + JSON.parse(res.text).should.containEql({ + status: 'ERROR', + message: '请您输入邮箱地址', + }); + done(); + }); + }); + + it('should not exists account when sign up', function (done) { + request + .get(`/users/exists?email=${account}`) + .send() + .end(function (err, res) { + should.not.exist(err); + JSON.parse(res.text).should.containEql({ + status: 'OK', + exists: false, + }); + done(); + }); + }); + }); + + describe('send register code to email', function (done) { + it('should not send register code successful when not input email', function (done) { + request + .post(`/users/registerCode`) + .send({}) + .end(function (err, res) { + should.not.exist(err); + JSON.parse(res.text).should.containEql({ + status: 'ERROR', + message: '请您输入邮箱地址', + }); + done(); + }); + }); + + it('should not send register code successful when email already exists', function (done) { + request + .post(`/users/registerCode`) + .send({ email: accountExist }) + .end(function (err, res) { + should.not.exist(err); + JSON.parse(res.text).should.containEql({ + status: 'ERROR', + message: `"${accountExist}" 已经注册过,请更换邮箱注册`, + }); + done(); + }); + }); + + it('should send register successful', function (done) { + request + .post(`/users/registerCode`) + .send({ email: account }) + .end(function (err, res) { + should.not.exist(err); + JSON.parse(res.text).should.containEql({ status: 'OK' }); + done(); + }); + }); + }); + + describe('check register code', function (done) { + var token = 'invalid token'; + var account2 = '522539441@qq.com2'; + var storageToken; + before(function (done) { + redisClient.get(registerKey).then(function (t) { + storageToken = t; + done(); + }); + }); + + it('should not check register code successful when email already exists', function (done) { + request + .get(`/users/registerCode/exists?email=${accountExist}`) + .send() + .end(function (err, res) { + should.not.exist(err); + JSON.parse(res.text).should.containEql({ + status: 'ERROR', + message: `"${accountExist}" 已经注册过,请更换邮箱注册`, + }); + done(); + }); + }); + + it('should not check register code successful when token expired', function (done) { + request + .get(`/users/registerCode/exists?email=${account2}`) + .send() + .end(function (err, res) { + should.not.exist(err); + JSON.parse(res.text).should.containEql({ + status: 'ERROR', + message: `验证码已经失效,请您重新获取`, + }); + done(); + }); + }); + + it('should not check register code successful when token is invalid', function (done) { + request + .get(`/users/registerCode/exists?email=${account}&token=${token}`) + .send() + .end(function (err, res) { + should.not.exist(err); + JSON.parse(res.text).should.containEql({ + status: 'ERROR', + message: `您输入的验证码不正确,请重新输入`, + }); + done(); + }); + }); + + it('should check register code successful', function (done) { + request + .get(`/users/registerCode/exists?email=${account}&token=${storageToken}`) + .send() + .end(function (err, res) { + should.not.exist(err); + JSON.parse(res.text).should.containEql({ status: 'OK' }); + done(); + }); + }); + }); + + describe('sign up', function (done) { + var storageToken; + before(function (done) { + redisClient.get(registerKey).then(function (t) { + storageToken = t; + done(); + }); + }); + + it('should not sign up successful when password length invalid', function (done) { + request + .post(`/users`) + .send({ email: account, password: '1234', token: storageToken }) + .end(function (err, res) { + should.not.exist(err); + JSON.parse(res.text).should.containEql({ + status: 'ERROR', + message: `请您输入6~20位长度的密码`, + }); + done(); + }); + }); + + it('should sign up successful', function (done) { + request + .post(`/users`) + .send({ email: account, password: password, token: storageToken }) + .end(function (err, res) { + should.not.exist(err); + JSON.parse(res.text).should.containEql({ status: 'OK' }); + done(); + }); + }); + }); + + describe('change password', function (done) { + var authToken; + before(function (done) { + request + .post('/auth/login') + .send({ + account: account, + password: password, + }) + .end(function (err, res) { + should.not.exist(err); + var rs = JSON.parse(res.text); + rs.should.containEql({ status: 'OK' }); + authToken = Buffer.from(`auth:${_.get(rs, 'results.tokens')}`).toString( + 'base64', + ); + done(); + }); + }); + + it('should not change password successful when authToken invalid', function (done) { + request + .patch(`/users/password`) + .set('Authorization', `Basic 11345`) + .send({ oldPassword: password, newPassword: newPassword }) + .end(function (err, res) { + should.not.exist(err); + var rs = JSON.parse(res.text); + res.status.should.equal(200); + rs.should.containEql({ status: 401 }); + done(); + }); + }); + + it('should not change password successful where password invalid', function (done) { + request + .patch(`/users/password`) + .set('Authorization', `Basic ${authToken}`) + .send({ oldPassword: '123321', newPassword: newPassword }) + .end(function (err, res) { + should.not.exist(err); + res.status.should.equal(200); + JSON.parse(res.text).should.containEql({ + status: 'ERROR', + message: `您输入的旧密码不正确,请重新输入`, + }); + done(); + }); + }); + + it('should not change password successful where new password invalid', function (done) { + request + .patch(`/users/password`) + .set('Authorization', `Basic ${authToken}`) + .send({ oldPassword: password, newPassword: '1234' }) + .end(function (err, res) { + should.not.exist(err); + res.status.should.equal(200); + JSON.parse(res.text).should.containEql({ + status: 'ERROR', + message: `请您输入6~20位长度的新密码`, + }); + done(); + }); + }); + + it('should change password successful', function (done) { + request + .patch(`/users/password`) + .set('Authorization', `Basic ${authToken}`) + .send({ oldPassword: password, newPassword: newPassword }) + .end(function (err, res) { + should.not.exist(err); + res.status.should.equal(200); + JSON.parse(res.text).should.containEql({ status: 'OK' }); + done(); + }); + }); + }); + + describe('user modules', function (done) { + var authToken; + before(function (done) { + request + .post('/auth/login') + .send({ + account: account, + password: newPassword, + }) + .end(function (err, res) { + should.not.exist(err); + var rs = JSON.parse(res.text); + rs.should.containEql({ status: 'OK' }); + authToken = Buffer.from(`auth:${_.get(rs, 'results.tokens')}`).toString( + 'base64', + ); + done(); + }); + }); + + it('should get userinfo successful', function (done) { + request + .get(`/users`) + .set('Authorization', `Basic ${authToken}`) + .send() + .end(function (err, res) { + should.not.exist(err); + res.status.should.equal(200); + done(); + }); + }); + }); +}); diff --git a/test/unit/.gitkeep b/tests/unit/.gitkeep similarity index 100% rename from test/unit/.gitkeep rename to tests/unit/.gitkeep diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 00000000..85bb8508 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,16 @@ +{ + "compilerOptions": { + "moduleResolution": "node", + "module": "commonjs", + "target": "es2020", + "outDir": "bin", + "lib": ["es5", "es2015", "es2016", "es2017", "es2018", "es2019", "es2020"], + "skipLibCheck": true, + "resolveJsonModule": true, + "esModuleInterop": true, + "noEmitOnError": true, + "allowSyntheticDefaultImports": true, + "allowJs": true + }, + "include": ["src/**/*.*"] +} diff --git a/views/auth/confirm.pug b/views/auth/confirm.pug new file mode 100644 index 00000000..42fb040a --- /dev/null +++ b/views/auth/confirm.pug @@ -0,0 +1,61 @@ +extends ../common + +block css + link(rel='stylesheet', href='/stylesheets/signin.css') + +block content + .container + form#form.form-signin(method="post") + h2.form-signin-heading Please confirm your token and create a password + .form-group + label.sr-only(for="inputEmail") Email address + input#inputEmail.form-control(type="text" name="email" placeholder="Email address" value=email required readonly=email ? true : false) + .form-group + label.sr-only(for="inputToken") Token + input#inputToken.form-control(type="text" name="token" placeholder="Token" required autofocus) + .form-group + label.sr-only(for="inputPassword") Create password + input#inputPassword.form-control(type="password" name="password" placeholder="Password" required) + a#submitBtn.btn.btn-lg.btn-primary.btn-block Confirm + + #myModal.modal.fade.bs-example-modal-sm(tabindex="-1" role="dialog" aria-labelledby="mySmallModalLabel") + .modal-dialog.modal-md + .modal-content + .modal-header + button.close(data-dismiss="modal" aria-label="Close") + span(aria-hidden="true") × + h4#mySmallModalLabel.modal-title Registration complete + .modal-body Please proceed to login. + .modal-footer + button.btn.btn-default(type="button" data-dismiss="modal") Close + button#okBtn.btn.btn-primary(type="button" data-dismiss="modal") OK +block js + script(). + $('#okBtn').on('click', function () { + location.href = '/auth/login?email=' + $('#inputEmail').val(); + }); + + var submit = false; + $('#submitBtn').on('click', function () { + if (submit) { + return ; + } + console.log($('#form').serializeArray()); + submit = true; + $.ajax({ + type: 'post', + data: $('#form').serializeArray(), + url: "/users/", + dataType: 'json', + success: function (data) { + if (data.status == "OK") { + myModal = $('#myModal'); + myModal.modal('show'); + submit = false; + } else { + alert(data.message); + submit = false; + } + } + }); + }); diff --git a/views/auth/login.pug b/views/auth/login.pug index c47c8da9..7b17b600 100644 --- a/views/auth/login.pug +++ b/views/auth/login.pug @@ -1,23 +1,36 @@ -extends ../layout +extends ../common + block css link(rel='stylesheet', href='/stylesheets/signin.css') block content .container form#form.form-signin(method="post") - h2.form-signin-heading 请登录 - label.sr-only(for="inputEmail") 邮箱地址/用户名 - input#inputEmail.form-control(type="text" name="account" placeholder="邮箱地址/用户名" required autofocus) - label.sr-only(for="inputPassword") 密码 - input#inputPassword.form-control(type="password" name="password" placeholder="密码" required) - .checkbox - label - input(type="checkbox" value="remember-me") - span 记住我 - a#submitBtn.btn.btn-lg.btn-primary.btn-block 登录 + h2.form-signin-heading #{__('Please sign in')} + label.sr-only(for="inputEmail") #{__('email address')}/#{__('username')} + input#inputEmail.form-control(type="text" name="account" placeholder=`${__('email address')}/${__('username')}` value=email required autofocus) + label.sr-only(for="inputPassword") #{__('password')} + input#inputPassword.form-control(type="password" name="password" placeholder=`${__('password')}` required) + a#submitBtn.btn.btn-lg.btn-primary.btn-block #{__('Log in')} + if showRegister + a#registerBtn.btn.btn-lg.btn-primary.btn-block(href="/auth/register" type="button") #{__('Register')} block js script(). + function onLoggedIn() { + var query = parseQuery() + if (query.hostname) { + // come from code-push-cli login + location.href = '/tokens/' + location.search; + } else { + location.href = '/'; + } + } + + if (getAccessToken()) { + onLoggedIn(); + } + var submit = false; $('#submitBtn').on('click', function () { if (submit) { @@ -31,11 +44,11 @@ block js dataType: 'json', success: function (data) { if (data.status == "OK") { - sessionStorage.setItem('auth', data.results.tokens) + localStorage.setItem('auth', data.results.tokens) submit = false; - location.href = '/tokens/' + location.search; + onLoggedIn(); } else { - alert(data.errorMessage); + alert(data.message); submit = false; } } diff --git a/views/auth/password.pug b/views/auth/password.pug index 47fa302c..5c4a2fd1 100644 --- a/views/auth/password.pug +++ b/views/auth/password.pug @@ -1,52 +1,46 @@ -extends ../layout +extends ../common block content .container(style="margin-top:30px;") form#form.col-md-5.col-md-offset-3(method="post") .form-group - label.sr-only(for="inputEmail") 邮箱地址/用户名 - input#inputEmail.form-control(type="text" name="account" placeholder="邮箱地址/用户名" required autofocus) + label.sr-only(for="inputPassword") #{__('old password')} + input#inputPassword.form-control(type="password" name="oldPassword" placeholder=`${__('old password')}` required) .form-group - .col-md-10(style="margin-left:-15px;") - label.sr-only(for="inputToken") token - input#inputToken.form-control(type="text" name="token" placeholder="token" required) - .col-md-2 - a.form-control.btn.btn-link(style="margin-bottom:15px;" target="_blank" href="/auth/login") 获取token + label.sr-only(for="inputNewPassword") #{__('new password')} + input#inputNewPassword.form-control(type="password" name="newPassword" placeholder=`${__('new password')}` required) .form-group - label.sr-only(for="inputPassword") 原密码 - input#inputPassword.form-control(type="password" name="oldPassword" placeholder="原密码" required) - .form-group - label.sr-only(for="inputNewPassword") 新密码 - input#inputNewPassword.form-control(type="password" name="newPassword" placeholder="新密码" required) - .form-group - a#submitBtn.btn.btn-lg.btn-primary.btn-block 修改密码 + a#submitBtn.btn.btn-lg.btn-primary.btn-block #{__('Change Password')} block js script(). + ensureLogin(); + var submit = false; $('#submitBtn').on('click', function () { if (submit) { return ; } - var token = $('#inputToken').val(); + submit = true; + var accessToken = getAccessToken(); var oldPassword = $('#inputPassword').val(); var newPassword = $('#inputNewPassword').val(); - submit = true; $.ajax({ type: 'patch', - data: JSON.stringify({oldPassword:oldPassword,newPassword:newPassword}), + data: JSON.stringify({ oldPassword: oldPassword, newPassword: newPassword }), contentType: 'application/json;charset=utf-8', headers: { - Authorization : 'Bearer '+token + Authorization : 'Bearer ' + accessToken, }, url: '/users/password', dataType: 'json', success: function (data) { if (data.status == "OK") { - alert("修改成功"); - location.href = '/auth/login'; + alert("#{__('change success')}"); + logout(); } else if (data.status == 401) { alert('token invalid'); + logout(); } else { alert(data.message); } diff --git a/views/auth/register.pug b/views/auth/register.pug index 1b91290e..0d3fd0b5 100644 --- a/views/auth/register.pug +++ b/views/auth/register.pug @@ -1,32 +1,17 @@ -extends ../layout +extends ../common + block css link(rel='stylesheet', href='/stylesheets/signin.css') block content .container form#form.form-signin(method="post") - h2.form-signin-heading Please sign in - label.sr-only(for="inputEmail") Email address - input#inputEmail.form-control(type="text" name="account" placeholder="Email address" required autofocus) - label.sr-only(for="inputPassword") Password - input#inputPassword.form-control(type="password" name="password" placeholder="Password" required) - .checkbox - label - input(type="checkbox" value="remember-me") - span Remember me - a#submitBtn.btn.btn-lg.btn-primary.btn-block Sign in + h2.form-signin-heading Please register + .form-group + label.sr-only(for="inputEmail") Email address + input#inputEmail.form-control(type="text" name="email" placeholder="Email address" value=email required autofocus) + a#submitBtn.btn.btn-lg.btn-primary.btn-block Register - #myModal.modal.fade.bs-example-modal-sm(tabindex="-1" role="dialog" aria-labelledby="mySmallModalLabel") - .modal-dialog.modal-md - .modal-content - .modal-header - button.close(data-dismiss="modal" aria-label="Close") - span(aria-hidden="true") × - h4#mySmallModalLabel.modal-title login token - .modal-body ... - .modal-footer - button.btn.btn-default(type="button" data-dismiss="modal") Close - button.btn.btn-primary(type="button" data-dismiss="modal") OK block js script(). var submit = false; @@ -38,19 +23,17 @@ block js $.ajax({ type: 'post', data: $('#form').serializeArray(), - url: $('#form').attr('action'), + url: "/users/registerCode", dataType: 'json', success: function (data) { if (data.status == "OK") { - myModal = $('#myModal'); - myModal.find(".modal-body").text(data.results.tokens) - myModal.modal('show'); + let email = $('#inputEmail').val(); + location.href = '/auth/confirm?email=' + email; submit = false; } else { - alert(data.errorMessage); + alert(data.message); submit = false; } } }); }); - diff --git a/views/common.pug b/views/common.pug new file mode 100644 index 00000000..61a1da87 --- /dev/null +++ b/views/common.pug @@ -0,0 +1,38 @@ +doctype html +html + head + title= title + meta(name="keywords" content="code-push-server,code-push,react-native,cordova") + meta(name="description" content="CodePush service is hotupdate services which adapter react-native-code-push and cordova-plugin-code-push") + link(rel='stylesheet', href='/js/bootstrap-3.3.7/css/bootstrap.min.css') + link(rel='stylesheet', href='/stylesheets/common.css') + block css + body + block content + + script(src='/js/jquery-3.1.1.min.js') + script(src='/js/bootstrap-3.3.7/js/bootstrap.min.js') + script(). + function getAccessToken() { + return localStorage.getItem('auth'); + } + function ensureLogin() { + if (!getAccessToken()) { + window.location.href = '/auth/login'; + } + } + function logout() { + localStorage.removeItem('auth'); + location.href = '/auth/login'; + } + function parseQuery() { + query = location.search.substring(1); + var vars = query.split('&'); + var rs = {}; + for (var i = 0; i < vars.length; i++) { + var pair = vars[i].split('='); + rs[decodeURIComponent(pair[0])] = decodeURIComponent(pair[1]); + } + return rs; + } + block js diff --git a/views/error.pug b/views/error.pug deleted file mode 100644 index 51ec12c6..00000000 --- a/views/error.pug +++ /dev/null @@ -1,6 +0,0 @@ -extends layout - -block content - h1= message - h2= error.status - pre #{error.stack} diff --git a/views/index.pug b/views/index.pug index 800da9bd..a3972b1d 100644 --- a/views/index.pug +++ b/views/index.pug @@ -1,11 +1,16 @@ -extends layout -block css - link(rel='stylesheet', href='/stylesheets/index.css') +extends common block content - .site-notice react naitve 热更新服务器 + .site-notice react native / cordova #{__('hot update server')} h1(style="text-align: center;")= title p(style="text-align: center;") Welcome to #{title} .site-notice - a.btn.btn-primary(href="/auth/login" type="button") 登录 - a.btn.btn-primary.col-md-offset-1(href="/auth/password" type="button") 修改密码 \ No newline at end of file + a.btn.btn-primary(href="/tokens" type="button") #{__('Obtain')} token + a.btn.btn-primary.col-md-offset-1(href="/auth/password" type="button") #{__('Change Password')} + a#logoutBtn.btn.btn-primary.col-md-offset-1(href="#" type="button") #{__('Logout')} + +block js + script(). + ensureLogin(); + + $('#logoutBtn').on('click', logout); diff --git a/views/layout.pug b/views/layout.pug deleted file mode 100644 index 85d88861..00000000 --- a/views/layout.pug +++ /dev/null @@ -1,14 +0,0 @@ -doctype html -html - head - title= title - meta(name="keywords" content="code-push-server,code-push,react-native,cordova") - meta(name="description" content="CodePush service is hotupdate services which adapter react-native-code-push and cordova-plugin-code-push") - link(rel='stylesheet', href='/js/bootstrap-3.3.7/css/bootstrap.min.css') - block css - body - block content - - script(src='/js/jquery-3.1.1.min.js') - script(src='/js/bootstrap-3.3.7/js/bootstrap.min.js') - block js \ No newline at end of file diff --git a/views/tokens.pug b/views/tokens.pug index ad770b56..0f918501 100644 --- a/views/tokens.pug +++ b/views/tokens.pug @@ -1,11 +1,9 @@ -extends layout -block css - link(rel='stylesheet', href='/stylesheets/tokens.css') +extends common block content h1(style="text-align: center;")= title .site-notice - a#submitBtn.btn.btn-lg.btn-primary 获取token + a#submitBtn.btn.btn-lg.btn-primary #{__('Obtain')} token .form-group #tipsSuccess(style="display:none") h2(style="text-align: center;") Authentication succeeded. @@ -20,28 +18,22 @@ block content block js script(). + ensureLogin(); var submit = false; - function parseQuery(query) { - query = query.substring(1); - var vars = query.split('&'); - var rs = {}; - for (var i = 0; i < vars.length; i++) { - var pair = vars[i].split('='); - rs[decodeURIComponent(pair[0])] = decodeURIComponent(pair[1]); - } - return rs; - } + $('#submitBtn').on('click', function () { if (submit) { return ; } submit = true; - var query = parseQuery(location.search); + var query = parseQuery(); var createdBy = query.hostname; var time = (new Date()).getTime(); if (createdBy == null || createdBy == undefined || createdBy=="") { createdBy = 'Login-' + time; } + + // TODO: make ttl and friendlyName configurable var postParams = { createdBy: createdBy, friendlyName: "Login-" + time, @@ -49,12 +41,12 @@ block js description: "Login-" + time, isSession: true }; - var access_token = sessionStorage.getItem('auth'); + var accessToken = getAccessToken(); $.ajax({ type: 'post', data: postParams, headers: { - Authorization : 'Bearer '+access_token + Authorization : 'Bearer ' + accessToken }, url: '/accessKeys', dataType: 'json', @@ -68,7 +60,7 @@ block js error: function(XMLHttpRequest, textStatus, errorThrown) { submit = false; if (errorThrown == 'Unauthorized') { - alert('请重新登录!'); + alert(`#{__('please login again')}!`); location.href = '/auth/login' }else { alert(errorThrown);