diff --git a/.drone copy.yml b/.drone copy.yml deleted file mode 100644 index 12a3102..0000000 --- a/.drone copy.yml +++ /dev/null @@ -1,68 +0,0 @@ -kind: pipeline -type: exec -name: dev-admin-backend - -node: - mode: dev2 - -trigger: - branch: ci - -steps: - - name: inject-file - environment: - ORMCONFIG: - from_secret: ORMCONFIG - ENV: - from_secret: ENV - commands: - - echo -n "$ORMCONFIG" > ormconfig.json - - echo -n "$ENV" > config/.env - - - name: build - commands: - - rm package-lock.json || true - - yarn - - yarn build - - export HOME=/root - - pm2 del dev-admin-backend || true - - mkdir /opt/nodewww/dev-admin-backend || rm -rf /opt/nodewww/dev-admin-backend/* - - mv ./* /opt/nodewww/dev-admin-backend - - - - name: deploy - commands: - - cd /opt/nodewww/express-admin-template - - export OLDHOME=$HOME - - export HOME=/root - - pm2 start -i 0 --name dev-admin-backend ./bin/www - - pm2 startup - - pm2 save - - ---- -kind: pipeline -type: docker -name: dev-admin-backend-builder - -node: - mode: dev - -trigger: - branch: ci - -steps: - - name: build-docker-image - image: plugins/docker - pull: if-not-exists - settings: - username: - from_secret: docker_reg_username - password: - from_secret: docker_reg_password - repo: docker.zcj.plus/zhouchijian/express-admin-template - tags: dev - registry: https://docker.zcj.plus - -depends_on: - - dev-admin-backend diff --git a/.drone.yml b/.drone.yml index b1232b0..d25ab50 100644 --- a/.drone.yml +++ b/.drone.yml @@ -1,17 +1,26 @@ + +# dev环境下的docker镜像构建 kind: pipeline type: docker -name: release +name: dev-build node: mode: dev trigger: event: - - tag - + - push + branch: + - ci steps: + - name: tag + image: alpine + pull: if-not-exists + commands: + - sh ./ci/build_tag.sh + - name: build-image image: plugins/docker pull: if-not-exists @@ -24,21 +33,62 @@ steps: registry: https://docker.zcj.plus --- + +# dev环境下的部署 kind: pipeline -type: docker -name: dev +type: exec +name: dev-deploy node: - mode: dev + mode: ffubuntu trigger: event: - push branch: - ci + + +steps: + + - name: serve + environment: + env: + from_secret: dev_env + commands: + - docker pull docker.zcj.plus/demo/express-template:dev + - echo -n "$env" > .env + - docker rm node-uniqid-dev-server -f || true + - docker create -it --name node-uniqid-dev-server --restart always docker.zcj.plus/demo/express-template:dev + - docker cp .env node-uniqid-dev-server:/src + - docker start node-uniqid-dev-server + - docker logs node-uniqid-dev-server + +depends_on: + - "dev-build" + +--- +# 正式环境下的镜像构建 +kind: pipeline +type: docker +name: release + +node: + mode: dev + +trigger: + event: + - tag + steps: + - name: tag + image: alpine + pull: if-not-exists + commands: + - sh ./ci/build_tag.sh + - name: build-image image: plugins/docker pull: if-not-exists @@ -47,5 +97,5 @@ steps: from_secret: repo_username password: from_secret: repo_password - repo: docker.zcj.plus/zhouchijian/demo/express-template - registry: https://docker.zcj.plus + repo: docker.zcj.plus/demo/express-template + registry: https://docker.zcj.plus \ No newline at end of file diff --git a/.eslintrc.json b/.eslintrc.json new file mode 100644 index 0000000..1c41aae --- /dev/null +++ b/.eslintrc.json @@ -0,0 +1,120 @@ +{ + "env": { + "browser": true, + "commonjs": true, + "es2021": true, + "node": true + }, + "extends": "eslint:recommended", + "parserOptions": { + "ecmaVersion": 12 + }, + "rules": { + "no-multiple-empty-lines": [ + "error", + { + "max": 1, + "maxEOF": 0, + "maxBOF": 0 + } + ], + "object-curly-spacing": [ + "error", + "always" + ], + "space-infix-ops": [ + "error", + { + "int32Hint": false + } + ], + "space-before-blocks": [ + "error", + "always" + ], + "space-before-function-paren": [ + "error", + "always" + ], + "indent": [ + "error", + 2 + ], + "linebreak-style": [ + "error", + "unix" + ], + "quotes": [ + "error", + "single" + ], + "semi": [ + "error", + "never" + ] + }, + "overrides": [ + { + "files": [ + "*.ts" + ], + "extends": [ + "eslint:recommended", + "plugin:@typescript-eslint/recommended" + ], + "parser": "@typescript-eslint/parser", + "parserOptions": { + "ecmaVersion": 12, + "sourceType": "module" + }, + "plugins": [ + "@typescript-eslint" + ], + "rules": { + "no-multiple-empty-lines": [ + "error", + { + "max": 1, + "maxEOF": 0, + "maxBOF": 0 + } + ], + "object-curly-spacing": [ + "error", + "always" + ], + "space-infix-ops": [ + "error", + { + "int32Hint": false + } + ], + "space-before-blocks": [ + "error", + "always" + ], + "space-before-function-paren": [ + "error", + "always" + ], + "indent": [ + "error", + 2 + ], + "linebreak-style": [ + "error", + "unix" + ], + "quotes": [ + "error", + "single" + ], + "semi": [ + "error", + "never" + ], + "@typescript-eslint/no-non-null-assertion": "off" + } + } + ] +} \ No newline at end of file diff --git a/.eslintrc.yml b/.eslintrc.yml deleted file mode 100644 index cef6c08..0000000 --- a/.eslintrc.yml +++ /dev/null @@ -1,80 +0,0 @@ -env: - browser: true - commonjs: true - es2021: true - node: true -extends: 'eslint:recommended' -parserOptions: - ecmaVersion: 12 -rules: - no-multiple-empty-lines: - - error - - max: 1 - maxEOF: 0 - maxBOF: 0 - object-curly-spacing: - - error - - always - space-infix-ops: - - error - - int32Hint: false - space-before-blocks: - - error - - always - space-before-function-paren: - - error - - always - indent: - - error - - 2 - linebreak-style: - - error - - unix - quotes: - - error - - single - semi: - - error - - never -overrides: - - files: - - '*.ts' - extends: - - 'eslint:recommended' - - 'plugin:@typescript-eslint/recommended' - parser: '@typescript-eslint/parser' - parserOptions: - ecmaVersion: 12 - sourceType: module - plugins: - - '@typescript-eslint' - rules: - no-multiple-empty-lines: - - error - - max: 1 - maxEOF: 0 - maxBOF: 0 - object-curly-spacing: - - error - - always - space-infix-ops: - - error - - int32Hint: false - space-before-blocks: - - error - - always - space-before-function-paren: - - error - - always - indent: - - error - - 2 - linebreak-style: - - error - - unix - quotes: - - error - - single - semi: - - error - - never \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index 0cf62fd..8014c04 100644 --- a/Dockerfile +++ b/Dockerfile @@ -4,13 +4,15 @@ WORKDIR /src COPY . . -RUN cp ormconfig.example.json ormconfig.json && \ - cp example.env .env && \ - yarn && \ - npm install pm2 -g +RUN cp example.env .env && \ + rm package-lock.json && \ + rm yarn.lock && \ + npm install && \ + npm install pm2 typescript -g && \ + node ./build + +VOLUME ["/src"] EXPOSE 80-60000 -VOLUME ['/src'] - CMD ["./pm2.sh"] \ No newline at end of file diff --git a/app.js b/app.js index 5431a2a..3155b75 100644 --- a/app.js +++ b/app.js @@ -6,7 +6,10 @@ var cookieParser = require('cookie-parser') var lessMiddleware = require('less-middleware') var logger = require('morgan') const typeorm = require('typeorm') -const event = require('./event') +const { event } = require('./event') +// require('./utils/sys_conf') +// require('./utils/redis/init') +// require('./rpc/server') Object.defineProperty(express.response,'error',{ value:function (error,statusCode = 400,errObj = {}) { @@ -59,8 +62,8 @@ Object.defineProperty(express.response,'success',{ */ typeorm.createConnection().then(()=>{ - // 连接成功,通知bin/www,开始监听http - event.emit('typeorm-connection') + // 连接成功,通知www,开始监听http + event.emit('typeorm-connected') console.log('typeorm启动成功') }) diff --git a/build b/build index cd4ba4b..4db24d9 100755 --- a/build +++ b/build @@ -8,8 +8,12 @@ shell.rm('-rf',dist_dir_path) shell.exec('tsc') -shell.exec('./check-config') - -shell.cp('./.env',dist_dir_path) -shell.cp('./ormconfig.json',dist_dir_path) +shell.cp('./www',dist_dir_path) shell.cp('-r','./views',dist_dir_path) + +shell.chmod('+x',path.join(dist_dir_path,'www')) + +shell.echo('====================================') +shell.echo('构建完成,目录如下:') +shell.ls('-l',dist_dir_path) +shell.echo('====================================') \ No newline at end of file diff --git a/event.js b/event.js index 3adcd78..e94bb9a 100644 --- a/event.js +++ b/event.js @@ -1,3 +1,5 @@ -const {EventEmitter} = require('events') +const { EventEmitter } = require('events') -module.exports = new EventEmitter() \ No newline at end of file +module.exports = { + event:new EventEmitter() +} \ No newline at end of file diff --git a/example.env b/example.env index 2168842..c560904 100644 --- a/example.env +++ b/example.env @@ -1,4 +1,16 @@ PORT=5500 GITHUB_CLIENTID=xxx GITHUB_SECRET=xxx -AES=xxx \ No newline at end of file +AES=xxx + +# Redis相关 +REDIS_HOST=192.168.1.120 +REDIS_PORT=6379 +REDIS_PWD=xxx +REDIS_DB=1 + +# 使用WebSocket作为Json-Rpc的服务端监听地址 +WS_JSON_RPC_SERVER_HOST=0.0.0.0 + +# 使用WebSocket作为Json-Rpc的服务端监听端口 +WS_JSON_RPC_SERVER_PORT=5501 \ No newline at end of file diff --git a/package.json b/package.json index 0ce178a..ad3690f 100644 --- a/package.json +++ b/package.json @@ -4,38 +4,43 @@ "private": true, "repository": "git@git.zcj.plus:zhouchijian/express-template.git", "scripts": { - "build": "rm -rf dist && tsc && cp .env dist/.env && cp ormconfig.json dist/ormconfig.json && cp -r bin dist/bin && cp -r views ./dist/views", - "bu": "./build", - "start:prod": "cd dist && node ./bin/www", + "build": "node ./build", + "start:prod": "cross-env NODE_ENV=production node ./www", "dev": "nodemon" }, "dependencies": { "class-transformer": "^0.4.0", "class-validator": "^0.13.1", "cookie-parser": "~1.4.4", - "debug": "~2.6.9", + "debug": "^4.3.2", "dotenv": "^10.0.0", "es6-shim": "^0.35.6", "express": "~4.16.1", "hjs": "~0.0.6", "http-errors": "~1.6.3", + "ioredis": "^4.27.8", "less-middleware": "~2.2.1", "morgan": "~1.9.1", "mysql": "^2.18.1", "mysql2": "^2.2.5", "reflect-metadata": "^0.1.13", + "rpc-websockets": "^7.4.14", "shelljs": "^0.8.4", "ts-node": "^10.1.0", - "typeorm": "^0.2.34" + "typeorm": "^0.2.34", + "underscore": "^1.13.1" }, "devDependencies": { "@types/cookie-parser": "^1.4.2", + "@types/debug": "^4.1.7", "@types/express": "^4.17.12", "@types/http-errors": "^1.8.0", + "@types/ioredis": "^4.27.1", "@types/less-middleware": "^2.0.31", "@types/md5": "^2.3.1", "@types/morgan": "^1.9.2", "@types/node": "^15.12.3", + "@types/underscore": "^1.11.3", "@types/uuid": "^8.3.1", "@typescript-eslint/eslint-plugin": "^4.27.0", "@typescript-eslint/parser": "^4.27.0", diff --git a/pm2.sh b/pm2.sh index b01310c..166222d 100644 --- a/pm2.sh +++ b/pm2.sh @@ -1,5 +1,7 @@ #!/bin/sh +export NODE_ENV=production + pm2 start --name express-template ./www -i 0 pm2 log \ No newline at end of file diff --git a/rpc/server.ts b/rpc/server.ts new file mode 100644 index 0000000..86367fc --- /dev/null +++ b/rpc/server.ts @@ -0,0 +1,40 @@ +// json-rpc-engine +// rpc-websockets +import { Server as RpcWebsocketServer } from 'rpc-websockets' +import { isFinite } from 'underscore' +import { event } from '../event' +import SysConf from '../utils/sys_conf' + +// const rpc_token = SysConf.get('WS_JSON_RPC_SERVER_TOKEN') + +// if(!rpc_token) { +// throw new Error('缺少参数WS_JSON_RPC_SERVER_TOKEN') +// } + +function register (server:RpcWebsocketServer) { + + server.setAuth(params=>params.token === SysConf.get('WS_JSON_RPC_SERVER_TOKEN')) + + // server.register('snowflake',()=>snowflake.create().toString(10)).protected() + + // server.register('shortid',()=>shortid.create().toString(10)).protected() +} + +const host = process.env.WS_JSON_RPC_SERVER_HOST || '0.0.0.0' + +const port = process.env.WS_JSON_RPC_SERVER_PORT || '' + +if(!isFinite(port)) { + throw new Error('缺少参数:json-rpc服务端口 [WS_JSON_RPC_SERVER_PORT]') +} + +// {"method":"shortid","id":"abcd","jsonrpc":"2.0"} +// {"method":"rpc.login","id":"abcde","jsonrpc":"2.0","params":{"token":"zcj"}} + +event.on('http-server-started',function () { + const server = new RpcWebsocketServer({ port,host }) + + register(server) + + console.log(`启动json-rpc服务,正在监听${host}:${port}`) +}) diff --git a/utils/redis/driver.ts b/utils/redis/driver.ts new file mode 100644 index 0000000..3c797f9 --- /dev/null +++ b/utils/redis/driver.ts @@ -0,0 +1,32 @@ +import Redis from 'ioredis' + +const clients = new Map() + +export class RedisClientDriver extends Redis { + + constructor ( + /** + * redis 客户端名字 + */ + private readonly _name:string, + host:string, + port:number, + password:string, + db:number + ) { + super(port,host,{ + password, + db + }) + clients.set(this.name,this) + } + + static getClient (name:string):RedisClientDriver|null { + return clients.get(name) || null + } + + get name ():string { + return this._name + } + +} diff --git a/utils/redis/init.ts b/utils/redis/init.ts new file mode 100644 index 0000000..4ffb87c --- /dev/null +++ b/utils/redis/init.ts @@ -0,0 +1,53 @@ +import { RedisClientDriver } from './driver' +import { event } from '../../event' + +interface EasyRedisConfig { + host:string, + port:number, + db:number, + password:string +} + +const config_cache = new Map() + +export function getConfig (prefix:string):EasyRedisConfig { + + if(!config_cache.has(prefix)) { + + const host = process.env[prefix + 'REDIS_HOST'] || '' + const port = process.env[prefix + 'REDIS_PORT'] || '6379' + const db = process.env[prefix + 'REDIS_DB'] || '0' + const password = process.env[prefix + 'REDIS_PWD'] || '' + + const cache = { + host, + port:parseInt(port,10), + db:parseInt(db,10), + password + } + + config_cache.set(prefix,cache) + return cache + } + + return config_cache.get(prefix) as unknown as EasyRedisConfig +} + +function init () { + const clients_connect = [{ name:'normal',prefix:'' }] + clients_connect.forEach(item=>{ + let success_count = 0 + const config = getConfig(item.prefix) + const client = new RedisClientDriver(item.name,config.host,config.port,config.password,config.db) + + client.addListener('connect',()=>{ + success_count++ + if(success_count === clients_connect.length) { + event.emit('redis-all-connected') + } + }) + }) + +} + +init() \ No newline at end of file diff --git a/utils/sys_conf.ts b/utils/sys_conf.ts new file mode 100644 index 0000000..6f815fd --- /dev/null +++ b/utils/sys_conf.ts @@ -0,0 +1,59 @@ +import { RedisClientDriver } from './redis/driver' +import DebugFunc from 'debug' +import { event } from '../event' + +const debug = DebugFunc('SystemConfig') + +interface SystemConfig{ + + /**WebSocketJsonRpc的服务端token */ + WS_JSON_RPC_SERVER_TOKEN:string, +} + +const config:SystemConfig = { + WS_JSON_RPC_SERVER_TOKEN:'', +} + +async function sync (client:RedisClientDriver,name:keyof SystemConfig,desc:string) { + const val = await client.hget('config',name) + if(!val) { + const msg = `缺少系统配置项:${desc} [ ${name} ]` + + throw new Error(msg) + } + config[name] = val +} + +function sync_error_handle (error:Error) { + debug(error.message) + return Promise.reject(error) +} + +async function prepare (client:RedisClientDriver):Promise { + await sync(client,'WS_JSON_RPC_SERVER_TOKEN','rpc密钥').catch(sync_error_handle) +} + +event.on('redis-all-connected',async ()=>{ + const client = RedisClientDriver.getClient('normal')! + + await prepare(client) + + event.emit('system-config-sync-complete') + + debug('系统配置完成',config) + +}) + +export default class { + + static all ():SystemConfig { + return Object.freeze( + Object.assign({},config) + ) + } + + static get (name:keyof SystemConfig):string { + return this.all()[name] || '' + } + +} \ No newline at end of file diff --git a/www b/www index d3f9e5f..44a7802 100644 --- a/www +++ b/www @@ -5,70 +5,83 @@ */ const { resolve } = require('path') const package = require('./package.json') -require('dotenv').config({ path:resolve(__dirname,'./.env') }) -var app = require(resolve(__dirname,'./app')) +require('dotenv').config({ path:resolve('./.env') }) + +if(process.env.NODE_ENV === 'production') { + process.chdir(resolve(__dirname,'dist')) +} + +var app = require(resolve('./app')) var debug = require('debug')(package.name + ':server') var http = require('http') -const event = require(resolve(__dirname,'./event')) - +const { event } = require(resolve('./event')) + /** - * Get port from environment and store in Express. - */ - + * Get port from environment and store in Express. + */ + var port = normalizePort(process.env.PORT || '3000') app.set('port', port) - + /** - * Create HTTP server. - */ - + * Create HTTP server. + */ + var server = http.createServer(app) - + /** - * Listen on provided port, on all network interfaces. - */ -event.on('typeorm-connection',()=>{ + * Listen on provided port, on all network interfaces. + */ +// event.on('system-config-sync-complete',()=>{ +// server.listen(port,()=>{ +// console.log(`服务启动成功,监听端口${port}`) +// event.emit('http-server-started') +// }) +// }) + +event.on('typeorm-connected',()=>{ server.listen(port,()=>{ console.log(`服务启动成功,监听端口${port}`) + event.emit('http-server-started') }) }) server.on('error', onError) server.on('listening', onListening) - + /** - * Normalize a port into a number, string, or false. - */ - + * 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. - */ - + * 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': @@ -83,11 +96,11 @@ function onError (error) { throw error } } - + /** - * Event listener for HTTP server "listening" event. - */ - + * Event listener for HTTP server "listening" event. + */ + function onListening () { var addr = server.address() var bind = typeof addr === 'string' diff --git a/yarn.lock b/yarn.lock index 23e3fb5..8968904 100644 --- a/yarn.lock +++ b/yarn.lock @@ -23,6 +23,13 @@ chalk "^2.0.0" js-tokens "^4.0.0" +"@babel/runtime@^7.11.2": + version "7.15.3" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.15.3.tgz#2e1c2880ca118e5b2f9988322bd8a7656a32502b" + integrity sha512-OvwMLqNXkCXSz1kSm58sEsNuhqOx/fKpnUnKnFB5v8uDda5bLNEHNgKPvhDN6IU0LDcnHQ90LlJ0Q6jnyBSIBA== + dependencies: + regenerator-runtime "^0.13.4" + "@eslint/eslintrc@^0.4.3": version "0.4.3" resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-0.4.3.tgz#9e42981ef035beb3dd49add17acb96e8ff6f394c" @@ -132,6 +139,13 @@ dependencies: "@types/express" "*" +"@types/debug@^4.1.7": + version "4.1.7" + resolved "https://registry.yarnpkg.com/@types/debug/-/debug-4.1.7.tgz#7cc0ea761509124709b8b2d1090d8f6c17aadb82" + integrity sha512-9AonUzyTjXXhEOa0DnqpzZi6VHlqKMswga9EXjpXnnqxwLtdvPPtlO8evrI5D9S6asFRCQ6v+wpiUKbw+vKqyg== + dependencies: + "@types/ms" "*" + "@types/express-serve-static-core@^4.17.18": version "4.17.24" resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.17.24.tgz#ea41f93bf7e0d59cd5a76665068ed6aab6815c07" @@ -156,6 +170,13 @@ resolved "https://registry.yarnpkg.com/@types/http-errors/-/http-errors-1.8.1.tgz#e81ad28a60bee0328c6d2384e029aec626f1ae67" integrity sha512-e+2rjEwK6KDaNOm5Aa9wNGgyS9oSZU/4pfSMMPYNOfjvFI0WVXm29+ITRFr6aKDvvKo7uU1jV68MW4ScsfDi7Q== +"@types/ioredis@^4.27.1": + version "4.27.1" + resolved "https://registry.yarnpkg.com/@types/ioredis/-/ioredis-4.27.1.tgz#f1c2d8a4341ed5ff9f4dd7aebfb38e275e3b3197" + integrity sha512-+JichYPCtVapxi5Z+7V/8Uhn+4Piz+rkb03JQTQ0kW0pkV71+bmzSTkpwmIqa7FfWIszp0VbRyN8gfgWDNQMdA== + dependencies: + "@types/node" "*" + "@types/json-schema@^7.0.7": version "7.0.8" resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.8.tgz#edf1bf1dbf4e04413ca8e5b17b3b7d7d54b59818" @@ -187,6 +208,11 @@ dependencies: "@types/node" "*" +"@types/ms@*": + version "0.7.31" + resolved "https://registry.yarnpkg.com/@types/ms/-/ms-0.7.31.tgz#31b7ca6407128a3d2bbc27fe2d21b345397f6197" + integrity sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA== + "@types/node@*": version "16.4.1" resolved "https://registry.yarnpkg.com/@types/node/-/node-16.4.1.tgz#9fad171a5b701613ee8a6f4ece3c88b1034b1b03" @@ -215,6 +241,11 @@ "@types/mime" "^1" "@types/node" "*" +"@types/underscore@^1.11.3": + version "1.11.3" + resolved "https://registry.yarnpkg.com/@types/underscore/-/underscore-1.11.3.tgz#d6734f3741ce41b2630018c6b61c6745f6188c07" + integrity sha512-Fl1TX1dapfXyDqFg2ic9M+vlXRktcPJrc4PR7sRc7sdVrjavg/JHlbUXBt8qWWqhJrmSqg3RNAkAPRiOYw6Ahw== + "@types/uuid@^8.3.1": version "8.3.1" resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-8.3.1.tgz#1a32969cf8f0364b3d8c8af9cc3555b7805df14f" @@ -582,6 +613,13 @@ buffer@^6.0.3: base64-js "^1.3.1" ieee754 "^1.2.1" +bufferutil@^4.0.1: + version "4.0.3" + resolved "https://registry.yarnpkg.com/bufferutil/-/bufferutil-4.0.3.tgz#66724b756bed23cd7c28c4d306d7994f9943cc6b" + integrity sha512-yEYTwGndELGvfXsImMBLop58eaGW+YdONi1fNjTINSY98tmMmFijBG6WXgdkfuLNt4imzQNtIE+eBp1PVpMCSw== + dependencies: + node-gyp-build "^4.2.0" + bytes@3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048" @@ -671,6 +709,11 @@ ci-info@^2.0.0: resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-2.0.0.tgz#67a9e964be31a51e15e5010d58e6f12834002f46" integrity sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ== +circular-json@^0.5.9: + version "0.5.9" + resolved "https://registry.yarnpkg.com/circular-json/-/circular-json-0.5.9.tgz#932763ae88f4f7dead7a0d09c8a51a4743a53b1d" + integrity sha512-4ivwqHpIFJZBuhN3g/pEcdbnGUywkBblloGbkglyloVjjR3uT6tieI89MVOfbP2tHX5sgb01FuLgAOzebNlJNQ== + class-transformer@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/class-transformer/-/class-transformer-0.4.0.tgz#b52144117b423c516afb44cc1c76dbad31c2165b" @@ -718,6 +761,11 @@ clone-response@^1.0.2: dependencies: mimic-response "^1.0.0" +cluster-key-slot@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/cluster-key-slot/-/cluster-key-slot-1.1.0.tgz#30474b2a981fb12172695833052bc0d01336d10d" + integrity sha512-2Nii8p3RwAPiFwsnZvukotvow2rIHM+yQ6ZcBXGHdniadkYGZYiGmkHJIbZPIV9nfv7m/U1IPMVVcAhoWFeklw== + co@^4.6.0: version "4.6.0" resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" @@ -842,7 +890,7 @@ dashdash@^1.12.0: dependencies: assert-plus "^1.0.0" -debug@2.6.9, debug@^2.2.0, debug@~2.6.9: +debug@2.6.9, debug@^2.2.0: version "2.6.9" resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== @@ -856,7 +904,7 @@ debug@^3.2.6: dependencies: ms "^2.1.1" -debug@^4.0.1, debug@^4.1.1, debug@^4.3.1: +debug@^4.0.1, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2: version "4.3.2" resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.2.tgz#f0a49c18ac8779e31d4a0c6029dfb76873c7428b" integrity sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw== @@ -890,6 +938,11 @@ delayed-stream@~1.0.0: resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk= +denque@^1.1.0: + version "1.5.1" + resolved "https://registry.yarnpkg.com/denque/-/denque-1.5.1.tgz#07f670e29c9a78f8faecb2566a1e2c11929c5cbf" + integrity sha512-XwE+iZ4D6ZUB7mfYRMb5wByE8L74HCn30FBN7sWnXksWc1LO1bPDl67pBR9o/kC4z/xSNAwkMYcGgqDV3BE3Hw== + denque@^1.4.1: version "1.5.0" resolved "https://registry.yarnpkg.com/denque/-/denque-1.5.0.tgz#773de0686ff2d8ec2ff92914316a47b73b1c73de" @@ -1151,6 +1204,11 @@ etag@~1.8.1: resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" integrity sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc= +eventemitter3@^4.0.7: + version "4.0.7" + resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f" + integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw== + express@~4.16.1: version "4.16.4" resolved "https://registry.yarnpkg.com/express/-/express-4.16.4.tgz#fddef61926109e24c515ea97fd2f1bdbf62df12e" @@ -1615,6 +1673,23 @@ interpret@^1.0.0: resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.4.0.tgz#665ab8bc4da27a774a40584e812e3e0fa45b1a1e" integrity sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA== +ioredis@^4.27.8: + version "4.27.8" + resolved "https://registry.yarnpkg.com/ioredis/-/ioredis-4.27.8.tgz#822c2d1ac44067a8f7b92fb673070fc9d661c56e" + integrity sha512-AcMEevap2wKxNcYEybZ/Qp+MR2HbNNUwGjG4sVCC3cAJ/zR9HXKAkolXOuR6YcOGPf7DHx9mWb/JKtAGujyPow== + dependencies: + cluster-key-slot "^1.1.0" + debug "^4.3.1" + denque "^1.1.0" + lodash.defaults "^4.2.0" + lodash.flatten "^4.4.0" + lodash.isarguments "^3.1.0" + p-map "^2.1.0" + redis-commands "1.7.0" + redis-errors "^1.2.0" + redis-parser "^3.0.0" + standard-as-callback "^2.1.0" + ipaddr.js@1.9.1: version "1.9.1" resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3" @@ -1858,6 +1933,21 @@ lodash.clonedeep@^4.5.0: resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef" integrity sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8= +lodash.defaults@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/lodash.defaults/-/lodash.defaults-4.2.0.tgz#d09178716ffea4dde9e5fb7b37f6f0802274580c" + integrity sha1-0JF4cW/+pN3p5ft7N/bwgCJ0WAw= + +lodash.flatten@^4.4.0: + version "4.4.0" + resolved "https://registry.yarnpkg.com/lodash.flatten/-/lodash.flatten-4.4.0.tgz#f31c22225a9632d2bbf8e4addbef240aa765a61f" + integrity sha1-8xwiIlqWMtK7+OSt2+8kCqdlph8= + +lodash.isarguments@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz#2f573d85c6a24289ff00663b491c1d338ff3458a" + integrity sha1-L1c9hcaiQon/AGY7SRwdM4/zRYo= + lodash.merge@^4.6.2: version "4.6.2" resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" @@ -2070,6 +2160,11 @@ negotiator@0.6.2: resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb" integrity sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw== +node-gyp-build@^4.2.0: + version "4.2.3" + resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.2.3.tgz#ce6277f853835f718829efb47db20f3e4d9c4739" + integrity sha512-MN6ZpzmfNCRM+3t57PTJHgHyw/h4OWnZ6mR8P5j/uZtqQr46RRuDE/P+g3n0YR/AiYXeWixZZzaip77gdICfRg== + node.extend@~2.0.0: version "2.0.2" resolved "https://registry.yarnpkg.com/node.extend/-/node.extend-2.0.2.tgz#b4404525494acc99740f3703c496b7d5182cc6cc" @@ -2157,6 +2252,11 @@ p-cancelable@^1.0.0: resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-1.1.0.tgz#d078d15a3af409220c886f1d9a0ca2e441ab26cc" integrity sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw== +p-map@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/p-map/-/p-map-2.1.0.tgz#310928feef9c9ecc65b68b17693018a665cea175" + integrity sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw== + package-json@^6.3.0: version "6.5.0" resolved "https://registry.yarnpkg.com/package-json/-/package-json-6.5.0.tgz#6feedaca35e75725876d0b0e64974697fed145b0" @@ -2378,11 +2478,33 @@ rechoir@^0.6.2: dependencies: resolve "^1.1.6" +redis-commands@1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/redis-commands/-/redis-commands-1.7.0.tgz#15a6fea2d58281e27b1cd1acfb4b293e278c3a89" + integrity sha512-nJWqw3bTFy21hX/CPKHth6sfhZbdiHP6bTawSgQBlKOVRG7EZkfHbbHwQJnrE4vsQf0CMNE+3gJ4Fmm16vdVlQ== + +redis-errors@^1.0.0, redis-errors@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/redis-errors/-/redis-errors-1.2.0.tgz#eb62d2adb15e4eaf4610c04afe1529384250abad" + integrity sha1-62LSrbFeTq9GEMBK/hUpOEJQq60= + +redis-parser@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/redis-parser/-/redis-parser-3.0.0.tgz#b66d828cdcafe6b4b8a428a7def4c6bcac31c8b4" + integrity sha1-tm2CjNyv5rS4pCin3vTGvKwxyLQ= + dependencies: + redis-errors "^1.0.0" + reflect-metadata@^0.1.13: version "0.1.13" resolved "https://registry.yarnpkg.com/reflect-metadata/-/reflect-metadata-0.1.13.tgz#67ae3ca57c972a2aa1642b10fe363fe32d49dc08" integrity sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg== +regenerator-runtime@^0.13.4: + version "0.13.9" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz#8925742a98ffd90814988d7566ad30ca3b263b52" + integrity sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA== + regexpp@^3.1.0: version "3.2.0" resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.2.0.tgz#0425a2768d8f23bad70ca4b90461fa2f1213e1b2" @@ -2472,6 +2594,20 @@ rimraf@^3.0.2: dependencies: glob "^7.1.3" +rpc-websockets@^7.4.14: + version "7.4.14" + resolved "https://registry.yarnpkg.com/rpc-websockets/-/rpc-websockets-7.4.14.tgz#d1774ce4d4c231dea6ed448d2bc224587b9561a5" + integrity sha512-x/2Rwzla6bXAyE8A21yx3sHjn49JUlgBUYfnKurNeqrZQgFxfD43Udo5NkTWQp+TASrssTlks8ipcJfvswgv5g== + dependencies: + "@babel/runtime" "^7.11.2" + circular-json "^0.5.9" + eventemitter3 "^4.0.7" + uuid "^8.3.0" + ws "^7.4.5" + optionalDependencies: + bufferutil "^4.0.1" + utf-8-validate "^5.0.2" + run-parallel@^1.1.9: version "1.2.0" resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" @@ -2665,6 +2801,11 @@ sshpk@^1.7.0: safer-buffer "^2.0.2" tweetnacl "~0.14.0" +standard-as-callback@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/standard-as-callback/-/standard-as-callback-2.1.0.tgz#8953fc05359868a77b5b9739a665c5977bb7df45" + integrity sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A== + "statuses@>= 1.4.0 < 2": version "1.5.0" resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" @@ -2929,6 +3070,11 @@ undefsafe@^2.0.3: dependencies: debug "^2.2.0" +underscore@^1.13.1: + version "1.13.1" + resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.13.1.tgz#0c1c6bd2df54b6b69f2314066d65b6cde6fcf9d1" + integrity sha512-hzSoAVtJF+3ZtiFX0VgfFPHEDRm7Y/QPjGyNo4TVdnDTdft3tr8hEkD25a1jC+TjTuE7tkHGKkhwCgs9dgBB2g== + unique-string@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/unique-string/-/unique-string-2.0.0.tgz#39c6451f81afb2749de2b233e3f7c5e8843bd89d" @@ -2974,6 +3120,13 @@ url-parse-lax@^3.0.0: dependencies: prepend-http "^2.0.0" +utf-8-validate@^5.0.2: + version "5.0.5" + resolved "https://registry.yarnpkg.com/utf-8-validate/-/utf-8-validate-5.0.5.tgz#dd32c2e82c72002dc9f02eb67ba6761f43456ca1" + integrity sha512-+pnxRYsS/axEpkrrEpzYfNZGXp0IjC/9RIxwM5gntY4Koi8SHmUGSfxfWqxZdRxrtaoVstuOzUp/rbs3JSPELQ== + dependencies: + node-gyp-build "^4.2.0" + util-deprecate@~1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" @@ -2989,6 +3142,11 @@ uuid@^3.0.0: resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee" integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A== +uuid@^8.3.0: + version "8.3.2" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" + integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== + v8-compile-cache@^2.0.3: version "2.3.0" resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz#2de19618c66dc247dcfb6f99338035d8245a2cee" @@ -3056,6 +3214,11 @@ write-file-atomic@^3.0.0: signal-exit "^3.0.2" typedarray-to-buffer "^3.1.5" +ws@^7.4.5: + version "7.5.4" + resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.4.tgz#56bfa20b167427e138a7795de68d134fe92e21f9" + integrity sha512-zP9z6GXm6zC27YtspwH99T3qTG7bBFv2VIkeHstMLrLlDJuzA7tQ5ls3OJ1hOGGCzTQPniNJoHXIAOS0Jljohg== + xdg-basedir@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-4.0.0.tgz#4bc8d9984403696225ef83a1573cbbcb4e79db13"