diff --git a/.gitignore b/.gitignore index 802b7a0..fb8c17d 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ subscribe.yml node_modules/ dist/ *.zip +configs/ \ No newline at end of file diff --git a/index.js b/index.js index 82544c8..1ad65df 100644 --- a/index.js +++ b/index.js @@ -1,7 +1,4 @@ -const Promise = require('bluebird'); -Promise.config({ - cancellation: true, -}); +import 'node-telegram-bot-api'; +import App from './dist/App'; -var App = require('./dist/App').default; -new App(__dirname + "/config.yml"); \ No newline at end of file +new App("./config.yml"); \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 7acd7e6..0288656 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,8 +10,13 @@ "license": "MIT", "dependencies": { "@types/node-telegram-bot-api": "^0.57.1", + "@waylaidwanderer/chatgpt-api": "file:../node-chatgpt-api", + "cache-manager": "^5.1.7", + "cache-manager-ioredis-yet": "^1.1.0", + "cache-manager-redis-yet": "^4.1.1", "chokidar": "^3.5.1", "decoders": "^1.25.3", + "got": "^11.8.3", "handlebars": "^4.7.7", "koa": "^2.13.4", "koa-body": "^6.0.1", @@ -22,24 +27,49 @@ "node-telegram-bot-api": "^0.58.0", "pusher": "^3.0.1", "pusher-js": "^5.1.1", - "request": "^2.88.2", - "request-promise": "^4.2.5", "throttle-debounce": "^3.0.1", + "winston": "^3.8.2", "yaml": "^1.8.3" }, "devDependencies": { - "@types/bluebird-global": "^3.5.13", "@types/koa": "^2.13.4", "@types/koa-router": "^7.4.4", "@types/micromatch": "^4.0.2", "@types/node": "^17.0.8", - "@types/request-promise": "^4.1.48", "@types/throttle-debounce": "^2.1.0", "@types/yaml": "^1.9.7", "ts-node": "^10.4.0", "typescript": "^4.5.4" } }, + "../node-chatgpt-api": { + "name": "@waylaidwanderer/chatgpt-api", + "version": "1.22.5", + "license": "MIT", + "dependencies": { + "@fastify/cors": "^8.2.0", + "@waylaidwanderer/fastify-sse-v2": "^3.1.0", + "@waylaidwanderer/fetch-event-source": "^3.0.1", + "boxen": "^7.0.1", + "clipboardy": "^3.0.0", + "dotenv": "^16.0.3", + "fastify": "^4.11.0", + "fetch-undici": "^3.0.1", + "gpt-3-encoder": "^1.1.4", + "http-proxy-agent": "^5.0.0", + "https-proxy-agent": "^5.0.1", + "inquirer": "^9.1.4", + "inquirer-autocomplete-prompt": "^3.0.0", + "keyv": "^4.5.2", + "keyv-file": "^0.2.0", + "ora": "^6.1.2", + "ws": "^8.12.0" + }, + "bin": { + "chatgpt-api": "bin/server.js", + "chatgpt-cli": "bin/cli.js" + } + }, "node_modules/@babel/runtime": { "version": "7.9.2", "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.9.2.tgz", @@ -48,6 +78,14 @@ "regenerator-runtime": "^0.13.4" } }, + "node_modules/@colors/colors": { + "version": "1.5.0", + "resolved": "https://registry.npmmirror.com/@colors/colors/-/colors-1.5.0.tgz", + "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==", + "engines": { + "node": ">=0.1.90" + } + }, "node_modules/@cspotcode/source-map-consumer": { "version": "0.8.0", "resolved": "https://registry.npmjs.org/@cspotcode/source-map-consumer/-/source-map-consumer-0.8.0.tgz", @@ -69,6 +107,93 @@ "node": ">=12" } }, + "node_modules/@dabh/diagnostics": { + "version": "2.0.3", + "resolved": "https://registry.npmmirror.com/@dabh/diagnostics/-/diagnostics-2.0.3.tgz", + "integrity": "sha512-hrlQOIi7hAfzsMqlGSFyVucrx38O+j6wiGOf//H2ecvIEqYN4ADBSS2iLMh5UFyDunCNniUIPk/q3riFv45xRA==", + "dependencies": { + "colorspace": "1.1.x", + "enabled": "2.0.x", + "kuler": "^2.0.0" + } + }, + "node_modules/@ioredis/commands": { + "version": "1.2.0", + "resolved": "https://registry.npmmirror.com/@ioredis/commands/-/commands-1.2.0.tgz", + "integrity": "sha512-Sx1pU8EM64o2BrqNpEO1CNLtKQwyhuXuqyfH7oGKCk+1a33d2r5saW8zNwm3j6BTExtjrv2BxTgzzkMwts6vGg==" + }, + "node_modules/@redis/bloom": { + "version": "1.2.0", + "resolved": "https://registry.npmmirror.com/@redis/bloom/-/bloom-1.2.0.tgz", + "integrity": "sha512-HG2DFjYKbpNmVXsa0keLHp/3leGJz1mjh09f2RLGGLQZzSHpkmZWuwJbAvo3QcRY8p80m5+ZdXZdYOSBLlp7Cg==", + "peerDependencies": { + "@redis/client": "^1.0.0" + } + }, + "node_modules/@redis/client": { + "version": "1.5.6", + "resolved": "https://registry.npmmirror.com/@redis/client/-/client-1.5.6.tgz", + "integrity": "sha512-dFD1S6je+A47Lj22jN/upVU2fj4huR7S9APd7/ziUXsIXDL+11GPYti4Suv5y8FuXaN+0ZG4JF+y1houEJ7ToA==", + "dependencies": { + "cluster-key-slot": "1.1.2", + "generic-pool": "3.9.0", + "yallist": "4.0.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@redis/graph": { + "version": "1.1.0", + "resolved": "https://registry.npmmirror.com/@redis/graph/-/graph-1.1.0.tgz", + "integrity": "sha512-16yZWngxyXPd+MJxeSr0dqh2AIOi8j9yXKcKCwVaKDbH3HTuETpDVPcLujhFYVPtYrngSco31BUcSa9TH31Gqg==", + "peerDependencies": { + "@redis/client": "^1.0.0" + } + }, + "node_modules/@redis/json": { + "version": "1.0.4", + "resolved": "https://registry.npmmirror.com/@redis/json/-/json-1.0.4.tgz", + "integrity": "sha512-LUZE2Gdrhg0Rx7AN+cZkb1e6HjoSKaeeW8rYnt89Tly13GBI5eP4CwDVr+MY8BAYfCg4/N15OUrtLoona9uSgw==", + "peerDependencies": { + "@redis/client": "^1.0.0" + } + }, + "node_modules/@redis/search": { + "version": "1.1.2", + "resolved": "https://registry.npmmirror.com/@redis/search/-/search-1.1.2.tgz", + "integrity": "sha512-/cMfstG/fOh/SsE+4/BQGeuH/JJloeWuH+qJzM8dbxuWvdWibWAOAHHCZTMPhV3xIlH4/cUEIA8OV5QnYpaVoA==", + "peerDependencies": { + "@redis/client": "^1.0.0" + } + }, + "node_modules/@redis/time-series": { + "version": "1.0.4", + "resolved": "https://registry.npmmirror.com/@redis/time-series/-/time-series-1.0.4.tgz", + "integrity": "sha512-ThUIgo2U/g7cCuZavucQTQzA9g9JbDDY2f64u3AbAoz/8vE2lt2U37LamDUVChhaDA3IRT9R6VvJwqnUfTJzng==", + "peerDependencies": { + "@redis/client": "^1.0.0" + } + }, + "node_modules/@sindresorhus/is": { + "version": "4.6.0", + "resolved": "https://registry.npmmirror.com/@sindresorhus/is/-/is-4.6.0.tgz", + "integrity": "sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==", + "engines": { + "node": ">=10" + } + }, + "node_modules/@szmarczak/http-timer": { + "version": "4.0.6", + "resolved": "https://registry.npmmirror.com/@szmarczak/http-timer/-/http-timer-4.0.6.tgz", + "integrity": "sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==", + "dependencies": { + "defer-to-connect": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/@tsconfig/node10": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.8.tgz", @@ -101,21 +226,6 @@ "@types/node": "*" } }, - "node_modules/@types/bluebird": { - "version": "3.5.36", - "resolved": "https://registry.npmjs.org/@types/bluebird/-/bluebird-3.5.36.tgz", - "integrity": "sha512-HBNx4lhkxN7bx6P0++W8E289foSu8kO8GCk2unhuVggO+cE7rh9DhZUyPhUxNRG9m+5B5BTKxZQ5ZP92x/mx9Q==", - "dev": true - }, - "node_modules/@types/bluebird-global": { - "version": "3.5.13", - "resolved": "https://registry.npmmirror.com/@types/bluebird-global/-/bluebird-global-3.5.13.tgz", - "integrity": "sha512-jmq47VdRYy8KPjXDlJ6zO5Ie+l5j0X2fGdSbfCS3mGdM93MTy50dh/EfltIv/QD15hCYTY+0lm/C0Bou1tPYnQ==", - "dev": true, - "dependencies": { - "@types/bluebird": "*" - } - }, "node_modules/@types/body-parser": { "version": "1.19.2", "resolved": "https://registry.npmmirror.com/@types/body-parser/-/body-parser-1.19.2.tgz", @@ -131,6 +241,17 @@ "integrity": "sha512-+euflG6ygo4bn0JHtn4pYqcXwRtLvElQ7/nnjDu7iYG56H0+OhCd7d6Ug0IE3WcFpZozBKW2+80FUbv5QGk5AQ==", "dev": true }, + "node_modules/@types/cacheable-request": { + "version": "6.0.3", + "resolved": "https://registry.npmmirror.com/@types/cacheable-request/-/cacheable-request-6.0.3.tgz", + "integrity": "sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw==", + "dependencies": { + "@types/http-cache-semantics": "*", + "@types/keyv": "^3.1.4", + "@types/node": "*", + "@types/responselike": "^1.0.0" + } + }, "node_modules/@types/caseless": { "version": "0.12.2", "resolved": "https://registry.npmjs.org/@types/caseless/-/caseless-0.12.2.tgz", @@ -203,6 +324,11 @@ "resolved": "https://registry.npmmirror.com/@types/http-assert/-/http-assert-1.5.3.tgz", "integrity": "sha512-FyAOrDuQmBi8/or3ns4rwPno7/9tJTijVW6aQQjK02+kOQ8zmoNg2XJtAuQhvQcy1ASJq38wirX5//9J1EqoUA==" }, + "node_modules/@types/http-cache-semantics": { + "version": "4.0.1", + "resolved": "https://registry.npmmirror.com/@types/http-cache-semantics/-/http-cache-semantics-4.0.1.tgz", + "integrity": "sha512-SZs7ekbP8CN0txVG2xVRH6EgKmEm31BOxA07vkFaETzZz1xh+cbt8BcI0slpymvwhx5dlFnQG2rTlPVQn+iRPQ==" + }, "node_modules/@types/http-errors": { "version": "1.8.2", "resolved": "https://registry.npmmirror.com/@types/http-errors/-/http-errors-1.8.2.tgz", @@ -213,6 +339,14 @@ "resolved": "https://registry.npmmirror.com/@types/keygrip/-/keygrip-1.0.2.tgz", "integrity": "sha512-GJhpTepz2udxGexqos8wgaBx4I/zWIDPh/KOGEwAqtuGDkOUJu5eFvwmdBX4AmB8Odsr+9pHCQqiAqDL/yKMKw==" }, + "node_modules/@types/keyv": { + "version": "3.1.4", + "resolved": "https://registry.npmmirror.com/@types/keyv/-/keyv-3.1.4.tgz", + "integrity": "sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/koa": { "version": "2.13.5", "resolved": "https://registry.npmmirror.com/@types/koa/-/koa-2.13.5.tgz", @@ -294,16 +428,6 @@ "form-data": "^2.5.0" } }, - "node_modules/@types/request-promise": { - "version": "4.1.48", - "resolved": "https://registry.npmjs.org/@types/request-promise/-/request-promise-4.1.48.tgz", - "integrity": "sha512-sLsfxfwP5G3E3U64QXxKwA6ctsxZ7uKyl4I28pMj3JvV+ztWECRns73GL71KMOOJME5u1A5Vs5dkBqyiR1Zcnw==", - "dev": true, - "dependencies": { - "@types/bluebird": "*", - "@types/request": "*" - } - }, "node_modules/@types/request/node_modules/form-data": { "version": "2.5.1", "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.5.1.tgz", @@ -317,6 +441,14 @@ "node": ">= 0.12" } }, + "node_modules/@types/responselike": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/@types/responselike/-/responselike-1.0.0.tgz", + "integrity": "sha512-85Y2BjiufFzaMIlvJDvTTB8Fxl2xfLo4HgmHzVBz08w4wDePCTjYw66PdrolO0kzli3yam/YCgRufyo1DdQVTA==", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/serve-static": { "version": "1.13.10", "resolved": "https://registry.npmmirror.com/@types/serve-static/-/serve-static-1.13.10.tgz", @@ -337,6 +469,11 @@ "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.0.tgz", "integrity": "sha512-I99sngh224D0M7XgW1s120zxCt3VYQ3IQsuw3P3jbq5GG4yc79+ZjyKznyOGIQrflfylLgcfekeZW/vk0yng6A==" }, + "node_modules/@types/triple-beam": { + "version": "1.3.2", + "resolved": "https://registry.npmmirror.com/@types/triple-beam/-/triple-beam-1.3.2.tgz", + "integrity": "sha512-txGIh+0eDFzKGC25zORnswy+br1Ha7hj5cMVwKIU7+s0U2AxxJru/jZSMU6OC9MJWP6+pc/hc6ZjyZShpsyY2g==" + }, "node_modules/@types/yaml": { "version": "1.9.7", "resolved": "https://registry.npmjs.org/@types/yaml/-/yaml-1.9.7.tgz", @@ -347,6 +484,10 @@ "yaml": "*" } }, + "node_modules/@waylaidwanderer/chatgpt-api": { + "resolved": "../node-chatgpt-api", + "link": true + }, "node_modules/accepts": { "version": "1.3.8", "resolved": "https://registry.npmmirror.com/accepts/-/accepts-1.3.8.tgz", @@ -460,6 +601,11 @@ "node": ">=0.8" } }, + "node_modules/async": { + "version": "3.2.4", + "resolved": "https://registry.npmmirror.com/async/-/async-3.2.4.tgz", + "integrity": "sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==" + }, "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", @@ -539,6 +685,70 @@ "node": ">= 6.0.0" } }, + "node_modules/cache-manager": { + "version": "5.1.7", + "resolved": "https://registry.npmmirror.com/cache-manager/-/cache-manager-5.1.7.tgz", + "integrity": "sha512-2W43F4ruaYb7dSiCOqkKtpnmn51/3DqxbKMMTxHfLa6qtj1letd8rr17/P/c7D7wYViqQLa+LetLCoKSVwBN1w==", + "dependencies": { + "lodash.clonedeep": "^4.5.0", + "lru-cache": "^7.17.0" + } + }, + "node_modules/cache-manager-ioredis-yet": { + "version": "1.1.0", + "resolved": "https://registry.npmmirror.com/cache-manager-ioredis-yet/-/cache-manager-ioredis-yet-1.1.0.tgz", + "integrity": "sha512-bGBAq8oNzzNkO2dwlYGWBxNXrz4w8FUTpe3nfUydJ6bm1ixKEcSUKYksGokQMaRgqkQjMbIHWFkvb8p+V9ZKqw==", + "dependencies": { + "cache-manager": "^5.1.0", + "ioredis": "^5.2.3" + }, + "engines": { + "node": ">= 16.17.0" + } + }, + "node_modules/cache-manager-redis-yet": { + "version": "4.1.1", + "resolved": "https://registry.npmmirror.com/cache-manager-redis-yet/-/cache-manager-redis-yet-4.1.1.tgz", + "integrity": "sha512-3Mzug/4z57YXoFf8yF3U1B7Ga3ezeQR+xc1hgNVmoDk7mStdbSlnwoNSI8FoF7SBRy4MfBQXdg2zkWY7guqQzw==", + "dependencies": { + "@redis/bloom": "^1.0.2", + "@redis/client": "^1.3.0", + "@redis/graph": "^1.0.1", + "@redis/json": "^1.0.4", + "@redis/search": "^1.1.0", + "@redis/time-series": "^1.0.3", + "cache-manager": "^5.1.0", + "redis": "^4.3.1" + }, + "engines": { + "node": ">= 16.17.0" + } + }, + "node_modules/cacheable-lookup": { + "version": "5.0.4", + "resolved": "https://registry.npmmirror.com/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz", + "integrity": "sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA==", + "engines": { + "node": ">=10.6.0" + } + }, + "node_modules/cacheable-request": { + "version": "7.0.2", + "resolved": "https://registry.npmmirror.com/cacheable-request/-/cacheable-request-7.0.2.tgz", + "integrity": "sha512-pouW8/FmiPQbuGpkXQ9BAPv/Mo5xDGANgSNXzTzJ8DrKGuXOssM4wIQRjfanNRh3Yu5cfYPvcorqbhg2KIJtew==", + "dependencies": { + "clone-response": "^1.0.2", + "get-stream": "^5.1.0", + "http-cache-semantics": "^4.0.0", + "keyv": "^4.0.0", + "lowercase-keys": "^2.0.0", + "normalize-url": "^6.0.1", + "responselike": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/call-bind": { "version": "1.0.2", "resolved": "https://registry.nlark.com/call-bind/download/call-bind-1.0.2.tgz", @@ -573,6 +783,22 @@ "fsevents": "~2.3.1" } }, + "node_modules/clone-response": { + "version": "1.0.3", + "resolved": "https://registry.npmmirror.com/clone-response/-/clone-response-1.0.3.tgz", + "integrity": "sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==", + "dependencies": { + "mimic-response": "^1.0.0" + } + }, + "node_modules/cluster-key-slot": { + "version": "1.1.2", + "resolved": "https://registry.npmmirror.com/cluster-key-slot/-/cluster-key-slot-1.1.2.tgz", + "integrity": "sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/co": { "version": "4.6.0", "resolved": "https://registry.npmmirror.com/co/-/co-4.6.0.tgz", @@ -593,6 +819,46 @@ "type-is": "^1.6.16" } }, + "node_modules/color": { + "version": "3.2.1", + "resolved": "https://registry.npmmirror.com/color/-/color-3.2.1.tgz", + "integrity": "sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==", + "dependencies": { + "color-convert": "^1.9.3", + "color-string": "^1.6.0" + } + }, + "node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmmirror.com/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmmirror.com/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + }, + "node_modules/color-string": { + "version": "1.9.1", + "resolved": "https://registry.npmmirror.com/color-string/-/color-string-1.9.1.tgz", + "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", + "dependencies": { + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" + } + }, + "node_modules/colorspace": { + "version": "1.1.4", + "resolved": "https://registry.npmmirror.com/colorspace/-/colorspace-1.1.4.tgz", + "integrity": "sha512-BgvKJiuVu1igBUF2kEjRCZXol6wiiGbY5ipL/oVPwm0BL9sIpMIzM8IK7vwuxIIzOXMV3Ey5w+vxhm0rR/TN8w==", + "dependencies": { + "color": "^3.1.3", + "text-hex": "1.0.x" + } + }, "node_modules/combined-stream": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", @@ -704,11 +970,38 @@ "lemons": "^1.4.0" } }, + "node_modules/decompress-response": { + "version": "6.0.0", + "resolved": "https://registry.npmmirror.com/decompress-response/-/decompress-response-6.0.0.tgz", + "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", + "dependencies": { + "mimic-response": "^3.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/decompress-response/node_modules/mimic-response": { + "version": "3.1.0", + "resolved": "https://registry.npmmirror.com/mimic-response/-/mimic-response-3.1.0.tgz", + "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", + "engines": { + "node": ">=10" + } + }, "node_modules/deep-equal": { "version": "1.0.1", "resolved": "https://registry.npmmirror.com/deep-equal/-/deep-equal-1.0.1.tgz", "integrity": "sha512-bHtC0iYvWhyaTzvV3CZgPeZQqCOBGyGsVV7v4eevpdkLHfiSrXUdBG+qAuSz4RI70sszvjQ1QSZ98An1yNwpSw==" }, + "node_modules/defer-to-connect": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/defer-to-connect/-/defer-to-connect-2.0.1.tgz", + "integrity": "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==", + "engines": { + "node": ">=10" + } + }, "node_modules/define-properties": { "version": "1.1.4", "resolved": "https://registry.npmmirror.com/define-properties/-/define-properties-1.1.4.tgz", @@ -734,6 +1027,14 @@ "resolved": "https://registry.npmmirror.com/delegates/-/delegates-1.0.0.tgz", "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==" }, + "node_modules/denque": { + "version": "2.1.0", + "resolved": "https://registry.npmmirror.com/denque/-/denque-2.1.0.tgz", + "integrity": "sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==", + "engines": { + "node": ">=0.10" + } + }, "node_modules/depd": { "version": "2.0.0", "resolved": "https://registry.npmmirror.com/depd/-/depd-2.0.0.tgz", @@ -783,6 +1084,11 @@ "resolved": "https://registry.npmmirror.com/ee-first/-/ee-first-1.1.1.tgz", "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" }, + "node_modules/enabled": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/enabled/-/enabled-2.0.0.tgz", + "integrity": "sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==" + }, "node_modules/encodeurl": { "version": "1.0.2", "resolved": "https://registry.npmmirror.com/encodeurl/-/encodeurl-1.0.2.tgz", @@ -877,15 +1183,20 @@ ] }, "node_modules/fast-deep-equal": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.1.tgz", - "integrity": "sha512-8UEa58QDLauDNfpbrX55Q9jrGHThw2ZMdOky5Gl1CDtVeJDPVrG4Jxx1N8jw2gkWaff5UUuX1KJd+9zGe2B+ZA==" + "version": "3.1.3", + "resolved": "https://registry.npmmirror.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" }, "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/fecha": { + "version": "4.2.3", + "resolved": "https://registry.npmmirror.com/fecha/-/fecha-4.2.3.tgz", + "integrity": "sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==" + }, "node_modules/file-type": { "version": "3.9.0", "resolved": "https://registry.npmmirror.com/file-type/-/file-type-3.9.0.tgz", @@ -905,6 +1216,11 @@ "node": ">=8" } }, + "node_modules/fn.name": { + "version": "1.1.0", + "resolved": "https://registry.npmmirror.com/fn.name/-/fn.name-1.1.0.tgz", + "integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==" + }, "node_modules/forever-agent": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", @@ -992,6 +1308,14 @@ "resolved": "https://registry.npmmirror.com/functions-have-names/-/functions-have-names-1.2.3.tgz", "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==" }, + "node_modules/generic-pool": { + "version": "3.9.0", + "resolved": "https://registry.npmmirror.com/generic-pool/-/generic-pool-3.9.0.tgz", + "integrity": "sha512-hymDOu5B53XvN4QT9dBmZxPX4CWhBPPLguTZ9MMFeFa/Kg0xWVfylOVNlJji/E7yTZWFd/q9GO5TxDLq156D7g==", + "engines": { + "node": ">= 4" + } + }, "node_modules/get-intrinsic": { "version": "1.1.1", "resolved": "https://registry.nlark.com/get-intrinsic/download/get-intrinsic-1.1.1.tgz", @@ -1002,6 +1326,26 @@ "has-symbols": "^1.0.1" } }, + "node_modules/get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmmirror.com/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "dependencies": { + "pump": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/get-stream/node_modules/pump": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, "node_modules/get-symbol-description": { "version": "1.0.0", "resolved": "https://registry.npmmirror.com/get-symbol-description/-/get-symbol-description-1.0.0.tgz", @@ -1033,6 +1377,27 @@ "node": ">= 6" } }, + "node_modules/got": { + "version": "11.8.6", + "resolved": "https://registry.npmmirror.com/got/-/got-11.8.6.tgz", + "integrity": "sha512-6tfZ91bOr7bOXnK7PRDCGBLa1H4U080YHNaAQ2KsMGlLEzRbk44nsZF2E1IeRc3vtJHPVbKCYgdFbaGO2ljd8g==", + "dependencies": { + "@sindresorhus/is": "^4.0.0", + "@szmarczak/http-timer": "^4.0.5", + "@types/cacheable-request": "^6.0.1", + "@types/responselike": "^1.0.0", + "cacheable-lookup": "^5.0.3", + "cacheable-request": "^7.0.2", + "decompress-response": "^6.0.0", + "http2-wrapper": "^1.0.0-beta.5.2", + "lowercase-keys": "^2.0.0", + "p-cancelable": "^2.0.0", + "responselike": "^2.0.0" + }, + "engines": { + "node": ">=10.19.0" + } + }, "node_modules/handlebars": { "version": "4.7.7", "resolved": "https://registry.npmmirror.com/handlebars/-/handlebars-4.7.7.tgz", @@ -1137,6 +1502,11 @@ "node": ">= 0.8" } }, + "node_modules/http-cache-semantics": { + "version": "4.1.1", + "resolved": "https://registry.npmmirror.com/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", + "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==" + }, "node_modules/http-errors": { "version": "1.8.1", "resolved": "https://registry.npmmirror.com/http-errors/-/http-errors-1.8.1.tgz", @@ -1174,6 +1544,18 @@ "npm": ">=1.3.7" } }, + "node_modules/http2-wrapper": { + "version": "1.0.3", + "resolved": "https://registry.npmmirror.com/http2-wrapper/-/http2-wrapper-1.0.3.tgz", + "integrity": "sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==", + "dependencies": { + "quick-lru": "^5.1.1", + "resolve-alpn": "^1.0.0" + }, + "engines": { + "node": ">=10.19.0" + } + }, "node_modules/iconv-lite": { "version": "0.4.24", "resolved": "https://registry.npmmirror.com/iconv-lite/-/iconv-lite-0.4.24.tgz", @@ -1211,6 +1593,30 @@ "node": ">= 0.4" } }, + "node_modules/ioredis": { + "version": "5.3.1", + "resolved": "https://registry.npmmirror.com/ioredis/-/ioredis-5.3.1.tgz", + "integrity": "sha512-C+IBcMysM6v52pTLItYMeV4Hz7uriGtoJdz7SSBDX6u+zwSYGirLdQh3L7t/OItWITcw3gTFMjJReYUwS4zihg==", + "dependencies": { + "@ioredis/commands": "^1.1.1", + "cluster-key-slot": "^1.1.0", + "debug": "^4.3.4", + "denque": "^2.1.0", + "lodash.defaults": "^4.2.0", + "lodash.isarguments": "^3.1.0", + "redis-errors": "^1.2.0", + "redis-parser": "^3.0.0", + "standard-as-callback": "^2.1.0" + }, + "engines": { + "node": ">=12.22.0" + } + }, + "node_modules/is-arrayish": { + "version": "0.3.2", + "resolved": "https://registry.npmmirror.com/is-arrayish/-/is-arrayish-0.3.2.tgz", + "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==" + }, "node_modules/is-base64": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-base64/-/is-base64-1.1.0.tgz", @@ -1359,6 +1765,14 @@ "call-bind": "^1.0.2" } }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "engines": { + "node": ">=8" + } + }, "node_modules/is-string": { "version": "1.0.7", "resolved": "https://registry.npmmirror.com/is-string/-/is-string-1.0.7.tgz", @@ -1409,6 +1823,11 @@ "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=" }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmmirror.com/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==" + }, "node_modules/json-schema": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", @@ -1449,6 +1868,14 @@ "node": ">= 0.6" } }, + "node_modules/keyv": { + "version": "4.5.2", + "resolved": "https://registry.npmmirror.com/keyv/-/keyv-4.5.2.tgz", + "integrity": "sha512-5MHbFaKn8cNSmVW7BYnijeAVlE4cYA/SVkifVgrh7yotnfhKmjuXpDKjrABLnT0SfHWV21P8ow07OGfRrNDg8g==", + "dependencies": { + "json-buffer": "3.0.1" + } + }, "node_modules/koa": { "version": "2.13.4", "resolved": "https://registry.npmmirror.com/koa/-/koa-2.13.4.tgz", @@ -1527,6 +1954,11 @@ "node": ">= 8.0.0" } }, + "node_modules/kuler": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/kuler/-/kuler-2.0.0.tgz", + "integrity": "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==" + }, "node_modules/lemons": { "version": "1.6.0", "resolved": "https://registry.nlark.com/lemons/download/lemons-1.6.0.tgz", @@ -1537,11 +1969,55 @@ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" }, + "node_modules/lodash.clonedeep": { + "version": "4.5.0", + "resolved": "https://registry.npmmirror.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", + "integrity": "sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==" + }, + "node_modules/lodash.defaults": { + "version": "4.2.0", + "resolved": "https://registry.npmmirror.com/lodash.defaults/-/lodash.defaults-4.2.0.tgz", + "integrity": "sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==" + }, + "node_modules/lodash.isarguments": { + "version": "3.1.0", + "resolved": "https://registry.npmmirror.com/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz", + "integrity": "sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg==" + }, + "node_modules/logform": { + "version": "2.5.1", + "resolved": "https://registry.npmmirror.com/logform/-/logform-2.5.1.tgz", + "integrity": "sha512-9FyqAm9o9NKKfiAKfZoYo9bGXXuwMkxQiQttkT4YjjVtQVIQtK6LmVtlxmCaFswo6N4AfEkHqZTV0taDtPotNg==", + "dependencies": { + "@colors/colors": "1.5.0", + "@types/triple-beam": "^1.3.2", + "fecha": "^4.2.0", + "ms": "^2.1.1", + "safe-stable-stringify": "^2.3.1", + "triple-beam": "^1.3.0" + } + }, "node_modules/long-timeout": { "version": "0.1.1", "resolved": "https://registry.npm.taobao.org/long-timeout/download/long-timeout-0.1.1.tgz", "integrity": "sha1-lyHXiLR+C8taJMLivuGg2lXatRQ=" }, + "node_modules/lowercase-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/lowercase-keys/-/lowercase-keys-2.0.0.tgz", + "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", + "engines": { + "node": ">=8" + } + }, + "node_modules/lru-cache": { + "version": "7.17.0", + "resolved": "https://registry.npmmirror.com/lru-cache/-/lru-cache-7.17.0.tgz", + "integrity": "sha512-zSxlVVwOabhVyTi6E8gYv2cr6bXK+8ifYz5/uyJb9feXX6NACVDwY4p5Ut3WC3Ivo/QhpARHU3iujx2xGAYHbQ==", + "engines": { + "node": ">=12" + } + }, "node_modules/lua-runner": { "version": "2.0.3", "resolved": "https://registry.npmmirror.com/lua-runner/download/lua-runner-2.0.3.tgz", @@ -1627,6 +2103,14 @@ "node": ">= 0.6" } }, + "node_modules/mimic-response": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/mimic-response/-/mimic-response-1.0.1.tgz", + "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", + "engines": { + "node": ">=4" + } + }, "node_modules/minimist": { "version": "1.2.6", "resolved": "https://registry.npmmirror.com/minimist/-/minimist-1.2.6.tgz", @@ -1708,6 +2192,14 @@ "node": ">=0.10.0" } }, + "node_modules/normalize-url": { + "version": "6.1.0", + "resolved": "https://registry.npmmirror.com/normalize-url/-/normalize-url-6.1.0.tgz", + "integrity": "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==", + "engines": { + "node": ">=10" + } + }, "node_modules/oauth-sign": { "version": "0.9.0", "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", @@ -1762,11 +2254,27 @@ "wrappy": "1" } }, + "node_modules/one-time": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/one-time/-/one-time-1.0.0.tgz", + "integrity": "sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g==", + "dependencies": { + "fn.name": "1.x.x" + } + }, "node_modules/only": { "version": "0.0.2", "resolved": "https://registry.npmmirror.com/only/-/only-0.0.2.tgz", "integrity": "sha512-Fvw+Jemq5fjjyWz6CpKx6w9s7xxqo3+JCyM0WXWeCSOboZ8ABkyvP8ID4CZuChA/wxSx+XSJmdOm8rGVyJ1hdQ==" }, + "node_modules/p-cancelable": { + "version": "2.1.1", + "resolved": "https://registry.npmmirror.com/p-cancelable/-/p-cancelable-2.1.1.tgz", + "integrity": "sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==", + "engines": { + "node": ">=8" + } + }, "node_modules/parseurl": { "version": "1.3.3", "resolved": "https://registry.npmmirror.com/parseurl/-/parseurl-1.3.3.tgz", @@ -1901,6 +2409,14 @@ "node": ">=0.6" } }, + "node_modules/quick-lru": { + "version": "5.1.1", + "resolved": "https://registry.npmmirror.com/quick-lru/-/quick-lru-5.1.1.tgz", + "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==", + "engines": { + "node": ">=10" + } + }, "node_modules/raw-body": { "version": "2.5.1", "resolved": "https://registry.npmmirror.com/raw-body/-/raw-body-2.5.1.tgz", @@ -1968,6 +2484,41 @@ "node": ">=8.10.0" } }, + "node_modules/redis": { + "version": "4.6.5", + "resolved": "https://registry.npmmirror.com/redis/-/redis-4.6.5.tgz", + "integrity": "sha512-O0OWA36gDQbswOdUuAhRL6mTZpHFN525HlgZgDaVNgCJIAZR3ya06NTESb0R+TUZ+BFaDpz6NnnVvoMx9meUFg==", + "workspaces": [ + "./packages/*" + ], + "dependencies": { + "@redis/bloom": "1.2.0", + "@redis/client": "1.5.6", + "@redis/graph": "1.1.0", + "@redis/json": "1.0.4", + "@redis/search": "1.1.2", + "@redis/time-series": "1.0.4" + } + }, + "node_modules/redis-errors": { + "version": "1.2.0", + "resolved": "https://registry.npmmirror.com/redis-errors/-/redis-errors-1.2.0.tgz", + "integrity": "sha512-1qny3OExCf0UvUV/5wpYKf2YwPcOqXzkwKKSmKHiE6ZMQs5heeE/c8eXK+PNllPvmjgAbfnsbpkGZWy8cBpn9w==", + "engines": { + "node": ">=4" + } + }, + "node_modules/redis-parser": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/redis-parser/-/redis-parser-3.0.0.tgz", + "integrity": "sha512-DJnGAeenTdpMEH6uAJRK/uiyEIH9WVsUmoLwzudwGJUwZPp80PDBWPHXSAGNPwNvIXAbe7MSUB1zQFugFml66A==", + "dependencies": { + "redis-errors": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/regenerator-runtime": { "version": "0.13.5", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.5.tgz", @@ -2049,11 +2600,32 @@ "request": "^2.34" } }, + "node_modules/resolve-alpn": { + "version": "1.2.1", + "resolved": "https://registry.npmmirror.com/resolve-alpn/-/resolve-alpn-1.2.1.tgz", + "integrity": "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==" + }, + "node_modules/responselike": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/responselike/-/responselike-2.0.1.tgz", + "integrity": "sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw==", + "dependencies": { + "lowercase-keys": "^2.0.0" + } + }, "node_modules/safe-buffer": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz", "integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==" }, + "node_modules/safe-stable-stringify": { + "version": "2.4.2", + "resolved": "https://registry.npmmirror.com/safe-stable-stringify/-/safe-stable-stringify-2.4.2.tgz", + "integrity": "sha512-gMxvPJYhP0O9n2pvcfYfIuYgbledAOJFcqRThtPRmjscaipiwcwPPKLytpVzMkG2HAN87Qmo2d4PtGiri1dSLA==", + "engines": { + "node": ">=10" + } + }, "node_modules/safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", @@ -2074,6 +2646,14 @@ "object-inspect": "^1.9.0" } }, + "node_modules/simple-swizzle": { + "version": "0.2.2", + "resolved": "https://registry.npmmirror.com/simple-swizzle/-/simple-swizzle-0.2.2.tgz", + "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==", + "dependencies": { + "is-arrayish": "^0.3.1" + } + }, "node_modules/sorted-array-functions": { "version": "1.3.0", "resolved": "https://registry.npm.taobao.org/sorted-array-functions/download/sorted-array-functions-1.3.0.tgz", @@ -2111,6 +2691,19 @@ "node": ">=0.10.0" } }, + "node_modules/stack-trace": { + "version": "0.0.10", + "resolved": "https://registry.npmmirror.com/stack-trace/-/stack-trace-0.0.10.tgz", + "integrity": "sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==", + "engines": { + "node": "*" + } + }, + "node_modules/standard-as-callback": { + "version": "2.1.0", + "resolved": "https://registry.npmmirror.com/standard-as-callback/-/standard-as-callback-2.1.0.tgz", + "integrity": "sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A==" + }, "node_modules/statuses": { "version": "1.5.0", "resolved": "https://registry.npmmirror.com/statuses/-/statuses-1.5.0.tgz", @@ -2160,6 +2753,11 @@ "es-abstract": "^1.19.5" } }, + "node_modules/text-hex": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/text-hex/-/text-hex-1.0.0.tgz", + "integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==" + }, "node_modules/throttle-debounce": { "version": "3.0.1", "resolved": "https://registry.nlark.com/throttle-debounce/download/throttle-debounce-3.0.1.tgz", @@ -2199,6 +2797,11 @@ "node": ">=0.8" } }, + "node_modules/triple-beam": { + "version": "1.3.0", + "resolved": "https://registry.npmmirror.com/triple-beam/-/triple-beam-1.3.0.tgz", + "integrity": "sha512-XrHUvV5HpdLmIj4uVMxHggLbFSZYIn7HEWsqePZcI50pco+MPqJ50wMGY794X7AOOhxOBAjbkqfAbEe/QMp2Lw==" + }, "node_modules/ts-node": { "version": "10.4.0", "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.4.0.tgz", @@ -2380,6 +2983,66 @@ "is-symbol": "^1.0.3" } }, + "node_modules/winston": { + "version": "3.8.2", + "resolved": "https://registry.npmmirror.com/winston/-/winston-3.8.2.tgz", + "integrity": "sha512-MsE1gRx1m5jdTTO9Ld/vND4krP2To+lgDoMEHGGa4HIlAUyXJtfc7CxQcGXVyz2IBpw5hbFkj2b/AtUdQwyRew==", + "dependencies": { + "@colors/colors": "1.5.0", + "@dabh/diagnostics": "^2.0.2", + "async": "^3.2.3", + "is-stream": "^2.0.0", + "logform": "^2.4.0", + "one-time": "^1.0.0", + "readable-stream": "^3.4.0", + "safe-stable-stringify": "^2.3.1", + "stack-trace": "0.0.x", + "triple-beam": "^1.3.0", + "winston-transport": "^4.5.0" + }, + "engines": { + "node": ">= 12.0.0" + } + }, + "node_modules/winston-transport": { + "version": "4.5.0", + "resolved": "https://registry.npmmirror.com/winston-transport/-/winston-transport-4.5.0.tgz", + "integrity": "sha512-YpZzcUzBedhlTAfJg6vJDlyEai/IFMIVcaEZZyl3UXIl4gmqRpU7AE89AHLkbzLUsv0NVmw7ts+iztqKxxPW1Q==", + "dependencies": { + "logform": "^2.3.2", + "readable-stream": "^3.6.0", + "triple-beam": "^1.3.0" + }, + "engines": { + "node": ">= 6.4.0" + } + }, + "node_modules/winston-transport/node_modules/readable-stream": { + "version": "3.6.1", + "resolved": "https://registry.npmmirror.com/readable-stream/-/readable-stream-3.6.1.tgz", + "integrity": "sha512-+rQmrWMYGA90yenhTYsLWAsLsqVC8osOw6PKE1HDYiO0gdPeKe/xDHNzIAIn4C91YQ6oenEhfYqqc1883qHbjQ==", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/winston/node_modules/readable-stream": { + "version": "3.6.1", + "resolved": "https://registry.npmmirror.com/readable-stream/-/readable-stream-3.6.1.tgz", + "integrity": "sha512-+rQmrWMYGA90yenhTYsLWAsLsqVC8osOw6PKE1HDYiO0gdPeKe/xDHNzIAIn4C91YQ6oenEhfYqqc1883qHbjQ==", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/wordwrap": { "version": "1.0.0", "resolved": "https://registry.npmmirror.com/wordwrap/-/wordwrap-1.0.0.tgz", @@ -2390,6 +3053,11 @@ "resolved": "https://registry.npmmirror.com/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmmirror.com/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, "node_modules/yaml": { "version": "1.8.3", "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.8.3.tgz", @@ -2433,6 +3101,11 @@ "regenerator-runtime": "^0.13.4" } }, + "@colors/colors": { + "version": "1.5.0", + "resolved": "https://registry.npmmirror.com/@colors/colors/-/colors-1.5.0.tgz", + "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==" + }, "@cspotcode/source-map-consumer": { "version": "0.8.0", "resolved": "https://registry.npmjs.org/@cspotcode/source-map-consumer/-/source-map-consumer-0.8.0.tgz", @@ -2448,6 +3121,74 @@ "@cspotcode/source-map-consumer": "0.8.0" } }, + "@dabh/diagnostics": { + "version": "2.0.3", + "resolved": "https://registry.npmmirror.com/@dabh/diagnostics/-/diagnostics-2.0.3.tgz", + "integrity": "sha512-hrlQOIi7hAfzsMqlGSFyVucrx38O+j6wiGOf//H2ecvIEqYN4ADBSS2iLMh5UFyDunCNniUIPk/q3riFv45xRA==", + "requires": { + "colorspace": "1.1.x", + "enabled": "2.0.x", + "kuler": "^2.0.0" + } + }, + "@ioredis/commands": { + "version": "1.2.0", + "resolved": "https://registry.npmmirror.com/@ioredis/commands/-/commands-1.2.0.tgz", + "integrity": "sha512-Sx1pU8EM64o2BrqNpEO1CNLtKQwyhuXuqyfH7oGKCk+1a33d2r5saW8zNwm3j6BTExtjrv2BxTgzzkMwts6vGg==" + }, + "@redis/bloom": { + "version": "1.2.0", + "resolved": "https://registry.npmmirror.com/@redis/bloom/-/bloom-1.2.0.tgz", + "integrity": "sha512-HG2DFjYKbpNmVXsa0keLHp/3leGJz1mjh09f2RLGGLQZzSHpkmZWuwJbAvo3QcRY8p80m5+ZdXZdYOSBLlp7Cg==", + "requires": {} + }, + "@redis/client": { + "version": "1.5.6", + "resolved": "https://registry.npmmirror.com/@redis/client/-/client-1.5.6.tgz", + "integrity": "sha512-dFD1S6je+A47Lj22jN/upVU2fj4huR7S9APd7/ziUXsIXDL+11GPYti4Suv5y8FuXaN+0ZG4JF+y1houEJ7ToA==", + "requires": { + "cluster-key-slot": "1.1.2", + "generic-pool": "3.9.0", + "yallist": "4.0.0" + } + }, + "@redis/graph": { + "version": "1.1.0", + "resolved": "https://registry.npmmirror.com/@redis/graph/-/graph-1.1.0.tgz", + "integrity": "sha512-16yZWngxyXPd+MJxeSr0dqh2AIOi8j9yXKcKCwVaKDbH3HTuETpDVPcLujhFYVPtYrngSco31BUcSa9TH31Gqg==", + "requires": {} + }, + "@redis/json": { + "version": "1.0.4", + "resolved": "https://registry.npmmirror.com/@redis/json/-/json-1.0.4.tgz", + "integrity": "sha512-LUZE2Gdrhg0Rx7AN+cZkb1e6HjoSKaeeW8rYnt89Tly13GBI5eP4CwDVr+MY8BAYfCg4/N15OUrtLoona9uSgw==", + "requires": {} + }, + "@redis/search": { + "version": "1.1.2", + "resolved": "https://registry.npmmirror.com/@redis/search/-/search-1.1.2.tgz", + "integrity": "sha512-/cMfstG/fOh/SsE+4/BQGeuH/JJloeWuH+qJzM8dbxuWvdWibWAOAHHCZTMPhV3xIlH4/cUEIA8OV5QnYpaVoA==", + "requires": {} + }, + "@redis/time-series": { + "version": "1.0.4", + "resolved": "https://registry.npmmirror.com/@redis/time-series/-/time-series-1.0.4.tgz", + "integrity": "sha512-ThUIgo2U/g7cCuZavucQTQzA9g9JbDDY2f64u3AbAoz/8vE2lt2U37LamDUVChhaDA3IRT9R6VvJwqnUfTJzng==", + "requires": {} + }, + "@sindresorhus/is": { + "version": "4.6.0", + "resolved": "https://registry.npmmirror.com/@sindresorhus/is/-/is-4.6.0.tgz", + "integrity": "sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==" + }, + "@szmarczak/http-timer": { + "version": "4.0.6", + "resolved": "https://registry.npmmirror.com/@szmarczak/http-timer/-/http-timer-4.0.6.tgz", + "integrity": "sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==", + "requires": { + "defer-to-connect": "^2.0.0" + } + }, "@tsconfig/node10": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.8.tgz", @@ -2480,21 +3221,6 @@ "@types/node": "*" } }, - "@types/bluebird": { - "version": "3.5.36", - "resolved": "https://registry.npmjs.org/@types/bluebird/-/bluebird-3.5.36.tgz", - "integrity": "sha512-HBNx4lhkxN7bx6P0++W8E289foSu8kO8GCk2unhuVggO+cE7rh9DhZUyPhUxNRG9m+5B5BTKxZQ5ZP92x/mx9Q==", - "dev": true - }, - "@types/bluebird-global": { - "version": "3.5.13", - "resolved": "https://registry.npmmirror.com/@types/bluebird-global/-/bluebird-global-3.5.13.tgz", - "integrity": "sha512-jmq47VdRYy8KPjXDlJ6zO5Ie+l5j0X2fGdSbfCS3mGdM93MTy50dh/EfltIv/QD15hCYTY+0lm/C0Bou1tPYnQ==", - "dev": true, - "requires": { - "@types/bluebird": "*" - } - }, "@types/body-parser": { "version": "1.19.2", "resolved": "https://registry.npmmirror.com/@types/body-parser/-/body-parser-1.19.2.tgz", @@ -2510,6 +3236,17 @@ "integrity": "sha512-+euflG6ygo4bn0JHtn4pYqcXwRtLvElQ7/nnjDu7iYG56H0+OhCd7d6Ug0IE3WcFpZozBKW2+80FUbv5QGk5AQ==", "dev": true }, + "@types/cacheable-request": { + "version": "6.0.3", + "resolved": "https://registry.npmmirror.com/@types/cacheable-request/-/cacheable-request-6.0.3.tgz", + "integrity": "sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw==", + "requires": { + "@types/http-cache-semantics": "*", + "@types/keyv": "^3.1.4", + "@types/node": "*", + "@types/responselike": "^1.0.0" + } + }, "@types/caseless": { "version": "0.12.2", "resolved": "https://registry.npmjs.org/@types/caseless/-/caseless-0.12.2.tgz", @@ -2582,6 +3319,11 @@ "resolved": "https://registry.npmmirror.com/@types/http-assert/-/http-assert-1.5.3.tgz", "integrity": "sha512-FyAOrDuQmBi8/or3ns4rwPno7/9tJTijVW6aQQjK02+kOQ8zmoNg2XJtAuQhvQcy1ASJq38wirX5//9J1EqoUA==" }, + "@types/http-cache-semantics": { + "version": "4.0.1", + "resolved": "https://registry.npmmirror.com/@types/http-cache-semantics/-/http-cache-semantics-4.0.1.tgz", + "integrity": "sha512-SZs7ekbP8CN0txVG2xVRH6EgKmEm31BOxA07vkFaETzZz1xh+cbt8BcI0slpymvwhx5dlFnQG2rTlPVQn+iRPQ==" + }, "@types/http-errors": { "version": "1.8.2", "resolved": "https://registry.npmmirror.com/@types/http-errors/-/http-errors-1.8.2.tgz", @@ -2592,6 +3334,14 @@ "resolved": "https://registry.npmmirror.com/@types/keygrip/-/keygrip-1.0.2.tgz", "integrity": "sha512-GJhpTepz2udxGexqos8wgaBx4I/zWIDPh/KOGEwAqtuGDkOUJu5eFvwmdBX4AmB8Odsr+9pHCQqiAqDL/yKMKw==" }, + "@types/keyv": { + "version": "3.1.4", + "resolved": "https://registry.npmmirror.com/@types/keyv/-/keyv-3.1.4.tgz", + "integrity": "sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==", + "requires": { + "@types/node": "*" + } + }, "@types/koa": { "version": "2.13.5", "resolved": "https://registry.npmmirror.com/@types/koa/-/koa-2.13.5.tgz", @@ -2685,14 +3435,12 @@ } } }, - "@types/request-promise": { - "version": "4.1.48", - "resolved": "https://registry.npmjs.org/@types/request-promise/-/request-promise-4.1.48.tgz", - "integrity": "sha512-sLsfxfwP5G3E3U64QXxKwA6ctsxZ7uKyl4I28pMj3JvV+ztWECRns73GL71KMOOJME5u1A5Vs5dkBqyiR1Zcnw==", - "dev": true, + "@types/responselike": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/@types/responselike/-/responselike-1.0.0.tgz", + "integrity": "sha512-85Y2BjiufFzaMIlvJDvTTB8Fxl2xfLo4HgmHzVBz08w4wDePCTjYw66PdrolO0kzli3yam/YCgRufyo1DdQVTA==", "requires": { - "@types/bluebird": "*", - "@types/request": "*" + "@types/node": "*" } }, "@types/serve-static": { @@ -2715,6 +3463,11 @@ "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.0.tgz", "integrity": "sha512-I99sngh224D0M7XgW1s120zxCt3VYQ3IQsuw3P3jbq5GG4yc79+ZjyKznyOGIQrflfylLgcfekeZW/vk0yng6A==" }, + "@types/triple-beam": { + "version": "1.3.2", + "resolved": "https://registry.npmmirror.com/@types/triple-beam/-/triple-beam-1.3.2.tgz", + "integrity": "sha512-txGIh+0eDFzKGC25zORnswy+br1Ha7hj5cMVwKIU7+s0U2AxxJru/jZSMU6OC9MJWP6+pc/hc6ZjyZShpsyY2g==" + }, "@types/yaml": { "version": "1.9.7", "resolved": "https://registry.npmjs.org/@types/yaml/-/yaml-1.9.7.tgz", @@ -2724,6 +3477,28 @@ "yaml": "*" } }, + "@waylaidwanderer/chatgpt-api": { + "version": "file:../node-chatgpt-api", + "requires": { + "@fastify/cors": "^8.2.0", + "@waylaidwanderer/fastify-sse-v2": "^3.1.0", + "@waylaidwanderer/fetch-event-source": "^3.0.1", + "boxen": "^7.0.1", + "clipboardy": "^3.0.0", + "dotenv": "^16.0.3", + "fastify": "^4.11.0", + "fetch-undici": "^3.0.1", + "gpt-3-encoder": "^1.1.4", + "http-proxy-agent": "^5.0.0", + "https-proxy-agent": "^5.0.1", + "inquirer": "^9.1.4", + "inquirer-autocomplete-prompt": "^3.0.0", + "keyv": "^4.5.2", + "keyv-file": "^0.2.0", + "ora": "^6.1.2", + "ws": "^8.12.0" + } + }, "accepts": { "version": "1.3.8", "resolved": "https://registry.npmmirror.com/accepts/-/accepts-1.3.8.tgz", @@ -2815,6 +3590,11 @@ "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" }, + "async": { + "version": "3.2.4", + "resolved": "https://registry.npmmirror.com/async/-/async-3.2.4.tgz", + "integrity": "sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==" + }, "asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", @@ -2879,6 +3659,58 @@ "ylru": "^1.2.0" } }, + "cache-manager": { + "version": "5.1.7", + "resolved": "https://registry.npmmirror.com/cache-manager/-/cache-manager-5.1.7.tgz", + "integrity": "sha512-2W43F4ruaYb7dSiCOqkKtpnmn51/3DqxbKMMTxHfLa6qtj1letd8rr17/P/c7D7wYViqQLa+LetLCoKSVwBN1w==", + "requires": { + "lodash.clonedeep": "^4.5.0", + "lru-cache": "^7.17.0" + } + }, + "cache-manager-ioredis-yet": { + "version": "1.1.0", + "resolved": "https://registry.npmmirror.com/cache-manager-ioredis-yet/-/cache-manager-ioredis-yet-1.1.0.tgz", + "integrity": "sha512-bGBAq8oNzzNkO2dwlYGWBxNXrz4w8FUTpe3nfUydJ6bm1ixKEcSUKYksGokQMaRgqkQjMbIHWFkvb8p+V9ZKqw==", + "requires": { + "cache-manager": "^5.1.0", + "ioredis": "^5.2.3" + } + }, + "cache-manager-redis-yet": { + "version": "4.1.1", + "resolved": "https://registry.npmmirror.com/cache-manager-redis-yet/-/cache-manager-redis-yet-4.1.1.tgz", + "integrity": "sha512-3Mzug/4z57YXoFf8yF3U1B7Ga3ezeQR+xc1hgNVmoDk7mStdbSlnwoNSI8FoF7SBRy4MfBQXdg2zkWY7guqQzw==", + "requires": { + "@redis/bloom": "^1.0.2", + "@redis/client": "^1.3.0", + "@redis/graph": "^1.0.1", + "@redis/json": "^1.0.4", + "@redis/search": "^1.1.0", + "@redis/time-series": "^1.0.3", + "cache-manager": "^5.1.0", + "redis": "^4.3.1" + } + }, + "cacheable-lookup": { + "version": "5.0.4", + "resolved": "https://registry.npmmirror.com/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz", + "integrity": "sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA==" + }, + "cacheable-request": { + "version": "7.0.2", + "resolved": "https://registry.npmmirror.com/cacheable-request/-/cacheable-request-7.0.2.tgz", + "integrity": "sha512-pouW8/FmiPQbuGpkXQ9BAPv/Mo5xDGANgSNXzTzJ8DrKGuXOssM4wIQRjfanNRh3Yu5cfYPvcorqbhg2KIJtew==", + "requires": { + "clone-response": "^1.0.2", + "get-stream": "^5.1.0", + "http-cache-semantics": "^4.0.0", + "keyv": "^4.0.0", + "lowercase-keys": "^2.0.0", + "normalize-url": "^6.0.1", + "responselike": "^2.0.0" + } + }, "call-bind": { "version": "1.0.2", "resolved": "https://registry.nlark.com/call-bind/download/call-bind-1.0.2.tgz", @@ -2908,6 +3740,19 @@ "readdirp": "~3.5.0" } }, + "clone-response": { + "version": "1.0.3", + "resolved": "https://registry.npmmirror.com/clone-response/-/clone-response-1.0.3.tgz", + "integrity": "sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==", + "requires": { + "mimic-response": "^1.0.0" + } + }, + "cluster-key-slot": { + "version": "1.1.2", + "resolved": "https://registry.npmmirror.com/cluster-key-slot/-/cluster-key-slot-1.1.2.tgz", + "integrity": "sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==" + }, "co": { "version": "4.6.0", "resolved": "https://registry.npmmirror.com/co/-/co-4.6.0.tgz", @@ -2924,6 +3769,46 @@ "type-is": "^1.6.16" } }, + "color": { + "version": "3.2.1", + "resolved": "https://registry.npmmirror.com/color/-/color-3.2.1.tgz", + "integrity": "sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==", + "requires": { + "color-convert": "^1.9.3", + "color-string": "^1.6.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmmirror.com/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmmirror.com/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + }, + "color-string": { + "version": "1.9.1", + "resolved": "https://registry.npmmirror.com/color-string/-/color-string-1.9.1.tgz", + "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", + "requires": { + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" + } + }, + "colorspace": { + "version": "1.1.4", + "resolved": "https://registry.npmmirror.com/colorspace/-/colorspace-1.1.4.tgz", + "integrity": "sha512-BgvKJiuVu1igBUF2kEjRCZXol6wiiGbY5ipL/oVPwm0BL9sIpMIzM8IK7vwuxIIzOXMV3Ey5w+vxhm0rR/TN8w==", + "requires": { + "color": "^3.1.3", + "text-hex": "1.0.x" + } + }, "combined-stream": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", @@ -3011,11 +3896,31 @@ "lemons": "^1.4.0" } }, + "decompress-response": { + "version": "6.0.0", + "resolved": "https://registry.npmmirror.com/decompress-response/-/decompress-response-6.0.0.tgz", + "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", + "requires": { + "mimic-response": "^3.1.0" + }, + "dependencies": { + "mimic-response": { + "version": "3.1.0", + "resolved": "https://registry.npmmirror.com/mimic-response/-/mimic-response-3.1.0.tgz", + "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==" + } + } + }, "deep-equal": { "version": "1.0.1", "resolved": "https://registry.npmmirror.com/deep-equal/-/deep-equal-1.0.1.tgz", "integrity": "sha512-bHtC0iYvWhyaTzvV3CZgPeZQqCOBGyGsVV7v4eevpdkLHfiSrXUdBG+qAuSz4RI70sszvjQ1QSZ98An1yNwpSw==" }, + "defer-to-connect": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/defer-to-connect/-/defer-to-connect-2.0.1.tgz", + "integrity": "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==" + }, "define-properties": { "version": "1.1.4", "resolved": "https://registry.npmmirror.com/define-properties/-/define-properties-1.1.4.tgz", @@ -3035,6 +3940,11 @@ "resolved": "https://registry.npmmirror.com/delegates/-/delegates-1.0.0.tgz", "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==" }, + "denque": { + "version": "2.1.0", + "resolved": "https://registry.npmmirror.com/denque/-/denque-2.1.0.tgz", + "integrity": "sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==" + }, "depd": { "version": "2.0.0", "resolved": "https://registry.npmmirror.com/depd/-/depd-2.0.0.tgz", @@ -3074,6 +3984,11 @@ "resolved": "https://registry.npmmirror.com/ee-first/-/ee-first-1.1.1.tgz", "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" }, + "enabled": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/enabled/-/enabled-2.0.0.tgz", + "integrity": "sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==" + }, "encodeurl": { "version": "1.0.2", "resolved": "https://registry.npmmirror.com/encodeurl/-/encodeurl-1.0.2.tgz", @@ -3156,15 +4071,20 @@ "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=" }, "fast-deep-equal": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.1.tgz", - "integrity": "sha512-8UEa58QDLauDNfpbrX55Q9jrGHThw2ZMdOky5Gl1CDtVeJDPVrG4Jxx1N8jw2gkWaff5UUuX1KJd+9zGe2B+ZA==" + "version": "3.1.3", + "resolved": "https://registry.npmmirror.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" }, "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==" }, + "fecha": { + "version": "4.2.3", + "resolved": "https://registry.npmmirror.com/fecha/-/fecha-4.2.3.tgz", + "integrity": "sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==" + }, "file-type": { "version": "3.9.0", "resolved": "https://registry.npmmirror.com/file-type/-/file-type-3.9.0.tgz", @@ -3178,6 +4098,11 @@ "to-regex-range": "^5.0.1" } }, + "fn.name": { + "version": "1.1.0", + "resolved": "https://registry.npmmirror.com/fn.name/-/fn.name-1.1.0.tgz", + "integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==" + }, "forever-agent": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", @@ -3246,6 +4171,11 @@ "resolved": "https://registry.npmmirror.com/functions-have-names/-/functions-have-names-1.2.3.tgz", "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==" }, + "generic-pool": { + "version": "3.9.0", + "resolved": "https://registry.npmmirror.com/generic-pool/-/generic-pool-3.9.0.tgz", + "integrity": "sha512-hymDOu5B53XvN4QT9dBmZxPX4CWhBPPLguTZ9MMFeFa/Kg0xWVfylOVNlJji/E7yTZWFd/q9GO5TxDLq156D7g==" + }, "get-intrinsic": { "version": "1.1.1", "resolved": "https://registry.nlark.com/get-intrinsic/download/get-intrinsic-1.1.1.tgz", @@ -3256,6 +4186,25 @@ "has-symbols": "^1.0.1" } }, + "get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmmirror.com/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "requires": { + "pump": "^3.0.0" + }, + "dependencies": { + "pump": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + } + } + }, "get-symbol-description": { "version": "1.0.0", "resolved": "https://registry.npmmirror.com/get-symbol-description/-/get-symbol-description-1.0.0.tgz", @@ -3281,6 +4230,24 @@ "is-glob": "^4.0.1" } }, + "got": { + "version": "11.8.6", + "resolved": "https://registry.npmmirror.com/got/-/got-11.8.6.tgz", + "integrity": "sha512-6tfZ91bOr7bOXnK7PRDCGBLa1H4U080YHNaAQ2KsMGlLEzRbk44nsZF2E1IeRc3vtJHPVbKCYgdFbaGO2ljd8g==", + "requires": { + "@sindresorhus/is": "^4.0.0", + "@szmarczak/http-timer": "^4.0.5", + "@types/cacheable-request": "^6.0.1", + "@types/responselike": "^1.0.0", + "cacheable-lookup": "^5.0.3", + "cacheable-request": "^7.0.2", + "decompress-response": "^6.0.0", + "http2-wrapper": "^1.0.0-beta.5.2", + "lowercase-keys": "^2.0.0", + "p-cancelable": "^2.0.0", + "responselike": "^2.0.0" + } + }, "handlebars": { "version": "4.7.7", "resolved": "https://registry.npmmirror.com/handlebars/-/handlebars-4.7.7.tgz", @@ -3355,6 +4322,11 @@ "http-errors": "~1.8.0" } }, + "http-cache-semantics": { + "version": "4.1.1", + "resolved": "https://registry.npmmirror.com/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", + "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==" + }, "http-errors": { "version": "1.8.1", "resolved": "https://registry.npmmirror.com/http-errors/-/http-errors-1.8.1.tgz", @@ -3384,6 +4356,15 @@ "sshpk": "^1.7.0" } }, + "http2-wrapper": { + "version": "1.0.3", + "resolved": "https://registry.npmmirror.com/http2-wrapper/-/http2-wrapper-1.0.3.tgz", + "integrity": "sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==", + "requires": { + "quick-lru": "^5.1.1", + "resolve-alpn": "^1.0.0" + } + }, "iconv-lite": { "version": "0.4.24", "resolved": "https://registry.npmmirror.com/iconv-lite/-/iconv-lite-0.4.24.tgz", @@ -3412,6 +4393,27 @@ "side-channel": "^1.0.4" } }, + "ioredis": { + "version": "5.3.1", + "resolved": "https://registry.npmmirror.com/ioredis/-/ioredis-5.3.1.tgz", + "integrity": "sha512-C+IBcMysM6v52pTLItYMeV4Hz7uriGtoJdz7SSBDX6u+zwSYGirLdQh3L7t/OItWITcw3gTFMjJReYUwS4zihg==", + "requires": { + "@ioredis/commands": "^1.1.1", + "cluster-key-slot": "^1.1.0", + "debug": "^4.3.4", + "denque": "^2.1.0", + "lodash.defaults": "^4.2.0", + "lodash.isarguments": "^3.1.0", + "redis-errors": "^1.2.0", + "redis-parser": "^3.0.0", + "standard-as-callback": "^2.1.0" + } + }, + "is-arrayish": { + "version": "0.3.2", + "resolved": "https://registry.npmmirror.com/is-arrayish/-/is-arrayish-0.3.2.tgz", + "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==" + }, "is-base64": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-base64/-/is-base64-1.1.0.tgz", @@ -3520,6 +4522,11 @@ "call-bind": "^1.0.2" } }, + "is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==" + }, "is-string": { "version": "1.0.7", "resolved": "https://registry.npmmirror.com/is-string/-/is-string-1.0.7.tgz", @@ -3564,6 +4571,11 @@ "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=" }, + "json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmmirror.com/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==" + }, "json-schema": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", @@ -3598,6 +4610,14 @@ "tsscmp": "1.0.6" } }, + "keyv": { + "version": "4.5.2", + "resolved": "https://registry.npmmirror.com/keyv/-/keyv-4.5.2.tgz", + "integrity": "sha512-5MHbFaKn8cNSmVW7BYnijeAVlE4cYA/SVkifVgrh7yotnfhKmjuXpDKjrABLnT0SfHWV21P8ow07OGfRrNDg8g==", + "requires": { + "json-buffer": "3.0.1" + } + }, "koa": { "version": "2.13.4", "resolved": "https://registry.npmmirror.com/koa/-/koa-2.13.4.tgz", @@ -3667,6 +4687,11 @@ "path-to-regexp": "^6.1.0" } }, + "kuler": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/kuler/-/kuler-2.0.0.tgz", + "integrity": "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==" + }, "lemons": { "version": "1.6.0", "resolved": "https://registry.nlark.com/lemons/download/lemons-1.6.0.tgz", @@ -3677,11 +4702,49 @@ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" }, + "lodash.clonedeep": { + "version": "4.5.0", + "resolved": "https://registry.npmmirror.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", + "integrity": "sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==" + }, + "lodash.defaults": { + "version": "4.2.0", + "resolved": "https://registry.npmmirror.com/lodash.defaults/-/lodash.defaults-4.2.0.tgz", + "integrity": "sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==" + }, + "lodash.isarguments": { + "version": "3.1.0", + "resolved": "https://registry.npmmirror.com/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz", + "integrity": "sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg==" + }, + "logform": { + "version": "2.5.1", + "resolved": "https://registry.npmmirror.com/logform/-/logform-2.5.1.tgz", + "integrity": "sha512-9FyqAm9o9NKKfiAKfZoYo9bGXXuwMkxQiQttkT4YjjVtQVIQtK6LmVtlxmCaFswo6N4AfEkHqZTV0taDtPotNg==", + "requires": { + "@colors/colors": "1.5.0", + "@types/triple-beam": "^1.3.2", + "fecha": "^4.2.0", + "ms": "^2.1.1", + "safe-stable-stringify": "^2.3.1", + "triple-beam": "^1.3.0" + } + }, "long-timeout": { "version": "0.1.1", "resolved": "https://registry.npm.taobao.org/long-timeout/download/long-timeout-0.1.1.tgz", "integrity": "sha1-lyHXiLR+C8taJMLivuGg2lXatRQ=" }, + "lowercase-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/lowercase-keys/-/lowercase-keys-2.0.0.tgz", + "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==" + }, + "lru-cache": { + "version": "7.17.0", + "resolved": "https://registry.npmmirror.com/lru-cache/-/lru-cache-7.17.0.tgz", + "integrity": "sha512-zSxlVVwOabhVyTi6E8gYv2cr6bXK+8ifYz5/uyJb9feXX6NACVDwY4p5Ut3WC3Ivo/QhpARHU3iujx2xGAYHbQ==" + }, "lua-runner": { "version": "2.0.3", "resolved": "https://registry.npmmirror.com/lua-runner/download/lua-runner-2.0.3.tgz", @@ -3742,6 +4805,11 @@ "mime-db": "1.43.0" } }, + "mimic-response": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/mimic-response/-/mimic-response-1.0.1.tgz", + "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==" + }, "minimist": { "version": "1.2.6", "resolved": "https://registry.npmmirror.com/minimist/-/minimist-1.2.6.tgz", @@ -3810,6 +4878,11 @@ "resolved": "https://registry.npm.taobao.org/normalize-path/download/normalize-path-3.0.0.tgz", "integrity": "sha1-Dc1p/yOhybEf0JeDFmRKA4ghamU=" }, + "normalize-url": { + "version": "6.1.0", + "resolved": "https://registry.npmmirror.com/normalize-url/-/normalize-url-6.1.0.tgz", + "integrity": "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==" + }, "oauth-sign": { "version": "0.9.0", "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", @@ -3852,11 +4925,24 @@ "wrappy": "1" } }, + "one-time": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/one-time/-/one-time-1.0.0.tgz", + "integrity": "sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g==", + "requires": { + "fn.name": "1.x.x" + } + }, "only": { "version": "0.0.2", "resolved": "https://registry.npmmirror.com/only/-/only-0.0.2.tgz", "integrity": "sha512-Fvw+Jemq5fjjyWz6CpKx6w9s7xxqo3+JCyM0WXWeCSOboZ8ABkyvP8ID4CZuChA/wxSx+XSJmdOm8rGVyJ1hdQ==" }, + "p-cancelable": { + "version": "2.1.1", + "resolved": "https://registry.npmmirror.com/p-cancelable/-/p-cancelable-2.1.1.tgz", + "integrity": "sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==" + }, "parseurl": { "version": "1.3.3", "resolved": "https://registry.npmmirror.com/parseurl/-/parseurl-1.3.3.tgz", @@ -3971,6 +5057,11 @@ "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==" }, + "quick-lru": { + "version": "5.1.1", + "resolved": "https://registry.npmmirror.com/quick-lru/-/quick-lru-5.1.1.tgz", + "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==" + }, "raw-body": { "version": "2.5.1", "resolved": "https://registry.npmmirror.com/raw-body/-/raw-body-2.5.1.tgz", @@ -4030,6 +5121,32 @@ "picomatch": "^2.2.1" } }, + "redis": { + "version": "4.6.5", + "resolved": "https://registry.npmmirror.com/redis/-/redis-4.6.5.tgz", + "integrity": "sha512-O0OWA36gDQbswOdUuAhRL6mTZpHFN525HlgZgDaVNgCJIAZR3ya06NTESb0R+TUZ+BFaDpz6NnnVvoMx9meUFg==", + "requires": { + "@redis/bloom": "1.2.0", + "@redis/client": "1.5.6", + "@redis/graph": "1.1.0", + "@redis/json": "1.0.4", + "@redis/search": "1.1.2", + "@redis/time-series": "1.0.4" + } + }, + "redis-errors": { + "version": "1.2.0", + "resolved": "https://registry.npmmirror.com/redis-errors/-/redis-errors-1.2.0.tgz", + "integrity": "sha512-1qny3OExCf0UvUV/5wpYKf2YwPcOqXzkwKKSmKHiE6ZMQs5heeE/c8eXK+PNllPvmjgAbfnsbpkGZWy8cBpn9w==" + }, + "redis-parser": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/redis-parser/-/redis-parser-3.0.0.tgz", + "integrity": "sha512-DJnGAeenTdpMEH6uAJRK/uiyEIH9WVsUmoLwzudwGJUwZPp80PDBWPHXSAGNPwNvIXAbe7MSUB1zQFugFml66A==", + "requires": { + "redis-errors": "^1.0.0" + } + }, "regenerator-runtime": { "version": "0.13.5", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.5.tgz", @@ -4091,11 +5208,29 @@ "lodash": "^4.17.15" } }, + "resolve-alpn": { + "version": "1.2.1", + "resolved": "https://registry.npmmirror.com/resolve-alpn/-/resolve-alpn-1.2.1.tgz", + "integrity": "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==" + }, + "responselike": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/responselike/-/responselike-2.0.1.tgz", + "integrity": "sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw==", + "requires": { + "lowercase-keys": "^2.0.0" + } + }, "safe-buffer": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz", "integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==" }, + "safe-stable-stringify": { + "version": "2.4.2", + "resolved": "https://registry.npmmirror.com/safe-stable-stringify/-/safe-stable-stringify-2.4.2.tgz", + "integrity": "sha512-gMxvPJYhP0O9n2pvcfYfIuYgbledAOJFcqRThtPRmjscaipiwcwPPKLytpVzMkG2HAN87Qmo2d4PtGiri1dSLA==" + }, "safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", @@ -4116,6 +5251,14 @@ "object-inspect": "^1.9.0" } }, + "simple-swizzle": { + "version": "0.2.2", + "resolved": "https://registry.npmmirror.com/simple-swizzle/-/simple-swizzle-0.2.2.tgz", + "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==", + "requires": { + "is-arrayish": "^0.3.1" + } + }, "sorted-array-functions": { "version": "1.3.0", "resolved": "https://registry.npm.taobao.org/sorted-array-functions/download/sorted-array-functions-1.3.0.tgz", @@ -4142,6 +5285,16 @@ "tweetnacl": "~0.14.0" } }, + "stack-trace": { + "version": "0.0.10", + "resolved": "https://registry.npmmirror.com/stack-trace/-/stack-trace-0.0.10.tgz", + "integrity": "sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==" + }, + "standard-as-callback": { + "version": "2.1.0", + "resolved": "https://registry.npmmirror.com/standard-as-callback/-/standard-as-callback-2.1.0.tgz", + "integrity": "sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A==" + }, "statuses": { "version": "1.5.0", "resolved": "https://registry.npmmirror.com/statuses/-/statuses-1.5.0.tgz", @@ -4187,6 +5340,11 @@ "es-abstract": "^1.19.5" } }, + "text-hex": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/text-hex/-/text-hex-1.0.0.tgz", + "integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==" + }, "throttle-debounce": { "version": "3.0.1", "resolved": "https://registry.nlark.com/throttle-debounce/download/throttle-debounce-3.0.1.tgz", @@ -4214,6 +5372,11 @@ "punycode": "^2.1.1" } }, + "triple-beam": { + "version": "1.3.0", + "resolved": "https://registry.npmmirror.com/triple-beam/-/triple-beam-1.3.0.tgz", + "integrity": "sha512-XrHUvV5HpdLmIj4uVMxHggLbFSZYIn7HEWsqePZcI50pco+MPqJ50wMGY794X7AOOhxOBAjbkqfAbEe/QMp2Lw==" + }, "ts-node": { "version": "10.4.0", "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.4.0.tgz", @@ -4339,6 +5502,58 @@ "is-symbol": "^1.0.3" } }, + "winston": { + "version": "3.8.2", + "resolved": "https://registry.npmmirror.com/winston/-/winston-3.8.2.tgz", + "integrity": "sha512-MsE1gRx1m5jdTTO9Ld/vND4krP2To+lgDoMEHGGa4HIlAUyXJtfc7CxQcGXVyz2IBpw5hbFkj2b/AtUdQwyRew==", + "requires": { + "@colors/colors": "1.5.0", + "@dabh/diagnostics": "^2.0.2", + "async": "^3.2.3", + "is-stream": "^2.0.0", + "logform": "^2.4.0", + "one-time": "^1.0.0", + "readable-stream": "^3.4.0", + "safe-stable-stringify": "^2.3.1", + "stack-trace": "0.0.x", + "triple-beam": "^1.3.0", + "winston-transport": "^4.5.0" + }, + "dependencies": { + "readable-stream": { + "version": "3.6.1", + "resolved": "https://registry.npmmirror.com/readable-stream/-/readable-stream-3.6.1.tgz", + "integrity": "sha512-+rQmrWMYGA90yenhTYsLWAsLsqVC8osOw6PKE1HDYiO0gdPeKe/xDHNzIAIn4C91YQ6oenEhfYqqc1883qHbjQ==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + } + } + }, + "winston-transport": { + "version": "4.5.0", + "resolved": "https://registry.npmmirror.com/winston-transport/-/winston-transport-4.5.0.tgz", + "integrity": "sha512-YpZzcUzBedhlTAfJg6vJDlyEai/IFMIVcaEZZyl3UXIl4gmqRpU7AE89AHLkbzLUsv0NVmw7ts+iztqKxxPW1Q==", + "requires": { + "logform": "^2.3.2", + "readable-stream": "^3.6.0", + "triple-beam": "^1.3.0" + }, + "dependencies": { + "readable-stream": { + "version": "3.6.1", + "resolved": "https://registry.npmmirror.com/readable-stream/-/readable-stream-3.6.1.tgz", + "integrity": "sha512-+rQmrWMYGA90yenhTYsLWAsLsqVC8osOw6PKE1HDYiO0gdPeKe/xDHNzIAIn4C91YQ6oenEhfYqqc1883qHbjQ==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + } + } + }, "wordwrap": { "version": "1.0.0", "resolved": "https://registry.npmmirror.com/wordwrap/-/wordwrap-1.0.0.tgz", @@ -4349,6 +5564,11 @@ "resolved": "https://registry.npmmirror.com/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmmirror.com/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, "yaml": { "version": "1.8.3", "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.8.3.tgz", diff --git a/package.json b/package.json index ad37d14..f7fbfbe 100644 --- a/package.json +++ b/package.json @@ -3,9 +3,10 @@ "version": "1.0.0", "description": "", "main": "index.js", + "type": "module", "scripts": { - "start": "node index.js", - "dev": "tsc && node index.js", + "start": "node --es-module-specifier-resolution=node index.js", + "dev": "tsc && node --es-module-specifier-resolution=node index.js", "build": "tsc" }, "author": { @@ -16,8 +17,13 @@ "license": "MIT", "dependencies": { "@types/node-telegram-bot-api": "^0.57.1", + "@waylaidwanderer/chatgpt-api": "file:../node-chatgpt-api", + "cache-manager": "^5.1.7", + "cache-manager-ioredis-yet": "^1.1.0", + "cache-manager-redis-yet": "^4.1.1", "chokidar": "^3.5.1", "decoders": "^1.25.3", + "got": "^11.8.3", "handlebars": "^4.7.7", "koa": "^2.13.4", "koa-body": "^6.0.1", @@ -28,18 +34,15 @@ "node-telegram-bot-api": "^0.58.0", "pusher": "^3.0.1", "pusher-js": "^5.1.1", - "request": "^2.88.2", - "request-promise": "^4.2.5", "throttle-debounce": "^3.0.1", + "winston": "^3.8.2", "yaml": "^1.8.3" }, "devDependencies": { - "@types/bluebird-global": "^3.5.13", "@types/koa": "^2.13.4", "@types/koa-router": "^7.4.4", "@types/micromatch": "^4.0.2", "@types/node": "^17.0.8", - "@types/request-promise": "^4.1.48", "@types/throttle-debounce": "^2.1.0", "@types/yaml": "^1.9.7", "ts-node": "^10.4.0", diff --git a/src/App.ts b/src/App.ts index f65b143..0f41093 100644 --- a/src/App.ts +++ b/src/App.ts @@ -1,27 +1,33 @@ import fs from 'fs'; -import path from 'path'; +import winston from 'winston'; import Yaml from 'yaml'; -import { BaseProvider, MultipleMessage } from './base/provider/BaseProvider'; +import { fileURLToPath } from 'url'; +import path from 'path'; +import { BaseProvider, MultipleMessage } from './base/provider/BaseProvider'; +import { Setup } from './Setup'; import { ChannelManager } from './ChannelManager'; import { ChannelConfig, Config } from './Config'; import { EventManager } from './EventManager'; -import { CommonSendMessage } from './message/Message'; import { PluginManager } from './PluginManager'; import { ProviderManager } from './ProviderManager'; import { RestfulApiManager } from './RestfulApiManager'; import { RobotManager } from './RobotManager'; import { Service, ServiceManager } from './ServiceManager'; -import { Setup } from './Setup'; import { SubscribeManager, Target } from './SubscribeManager'; +import { SessionManager } from './SessionManager'; export default class App { public config: Config; - public srcPath: string = __dirname; + + public srcPath: string = path.dirname(fileURLToPath(import.meta.url)); + public basePath: string = path.dirname(this.srcPath); public debug: boolean = false; + public logger!: winston.Logger; public event!: EventManager; + public session!: SessionManager; public robot!: RobotManager; public provider!: ProviderManager; public service!: ServiceManager; @@ -33,7 +39,7 @@ export default class App { constructor(configFile: string) { this.config = Yaml.parse(fs.readFileSync(configFile, { encoding: 'utf-8' })); this.debug = this.config.debug; - + this.initialize(); } @@ -41,17 +47,56 @@ export default class App { await this.initModules(); await this.initRestfulApiManager(); await this.initEventManager(); + await this.initSessionManager(); await this.initRobot(); await this.initProviderManager(); await this.initServiceManager(); await this.initSubscribeManager(); await this.initChannelManager(); await this.initPluginManager(); - console.log('初始化完成,正在接收消息'); + + this.logger.info('初始化完成,正在接收消息'); } async initModules() { await Setup.initHandlebars(); + + // 创建Logger + const loggerFormat = winston.format.printf(({ level, message, timestamp }) => { + return `${timestamp} [${level}]: ${message}`; + }); + + this.logger = winston.createLogger({ + level: 'info', + format: winston.format.json(), + }); + + if (this.debug) { + this.logger.add( + new winston.transports.Console({ + format: winston.format.combine( + winston.format.timestamp(), + winston.format.colorize(), + winston.format.simple(), + loggerFormat, + winston.format.metadata() + ), + level: 'debug' + }) + ); + } else { + this.logger.add( + new winston.transports.Console({ + format: winston.format.combine( + winston.format.timestamp(), + winston.format.colorize(), + winston.format.simple(), + loggerFormat + ), + level: 'info', + }) + ); + } } async initRestfulApiManager() { @@ -64,6 +109,11 @@ export default class App { await this.event.initialize(); } + async initSessionManager() { + this.session = new SessionManager(this, this.config.session); + await this.session.initialize(); + } + async initRobot() { this.robot = new RobotManager(this, this.config.robot); await this.robot.initialize(); @@ -91,7 +141,7 @@ export default class App { } async initPluginManager() { - this.plugin = new PluginManager(this, this.config.plugin_path); + this.plugin = new PluginManager(this, this.config.plugin_path, this.config.plugin_config_path); await this.plugin.initialize(); } @@ -119,11 +169,7 @@ export default class App { * @returns */ async sendPushMessage(channelId: string, messages: MultipleMessage): Promise { - console.log(`[${channelId}] 消息: `, messages); + this.logger.info(`[${channelId}] 消息: `, messages); this.robot.sendPushMessage(channelId, messages); } - - require(file: string): any { - return require(path.join(this.srcPath, file)); - } } diff --git a/src/ChannelManager.ts b/src/ChannelManager.ts index 2501c7a..558ed59 100644 --- a/src/ChannelManager.ts +++ b/src/ChannelManager.ts @@ -96,7 +96,6 @@ export class ChannelManager extends EventEmitter { this.channelName[channelId] = config?.name; } else { if (BaseProvider.checkConfig(config)) { - // console.log(`正在加载Channel: ${channelId}`); // 处理channel let providerName = this.getProviderName(config); let isReload = false; @@ -114,10 +113,10 @@ export class ChannelManager extends EventEmitter { this.channelName[channelId] = config?.name; if (isReload) { this.emit('reload', channelId); - console.log(`已重载Channel: ${channelId}`); + this.app.logger.info(`已重载Channel: ${channelId}`); } else { this.emit('add', channelId); - console.log(`已加载Channel: ${channelId}`); + this.app.logger.info(`已加载Channel: ${channelId}`); } } } else { @@ -148,7 +147,7 @@ export class ChannelManager extends EventEmitter { delete this.channels[channelId]; delete this.channelName[channelId]; this.emit('remove', channelId); - console.log("已移除Channel: ", this.getChannelFullName(channelId)); + this.app.logger.info("已移除Channel: ", this.getChannelFullName(channelId)); } } } diff --git a/src/Config.ts b/src/Config.ts index 666572a..01f3ad8 100644 --- a/src/Config.ts +++ b/src/Config.ts @@ -3,19 +3,25 @@ import { RegexFilterConfig } from "./generator/RegexFilter"; export type Config = { channel_config_path: string; + plugin_config_path: string; plugin_path: string; subscribe_config: string; debug: boolean; robot: Record; service: Record; + session: SessionConfig; http_api: RestfulApiConfig; - command_override: CommandOverrideConfig; - focused_as_command: true; + command_override?: CommandOverrideConfig; + focused_as_command?: true; + + robot_description?: string; }; export type RobotConfig = { type: string; baseId: string; + + description?: string; }; export type RestfulApiConfig = { @@ -26,6 +32,17 @@ export type RestfulApiConfig = { export type ServiceConfig = { [name: string]: any }; +export type SessionConfig = { + type?: 'memory' | 'redis', + redis?: { + host?: string, + port?: number, + password?: string, + db?: number, + } + ttl?: number +}; + export type ChannelConfig = any; export type GeneratorConfig = { diff --git a/src/EventManager.ts b/src/EventManager.ts index d903a69..616d391 100644 --- a/src/EventManager.ts +++ b/src/EventManager.ts @@ -1,34 +1,57 @@ import App from "./App"; +import { CommandOverrideConfig } from "./Config"; import { CommonReceivedMessage, CommonSendMessage } from "./message/Message"; -import { CommandInfo, ControllerSubscribeSource, MessageEventOptions, MessagePriority, PluginController, PluginEvent } from "./PluginManager"; +import { SenderIdentity } from "./message/Sender"; +import { CommandInfo, EventScope, MessageEventOptions, MessagePriority, PluginEvent } from "./PluginManager"; import { Robot } from "./RobotManager"; -export type PluginControllerListenerInfo = { +export type ControllerEventInfo = { priority: number; callback: CallableFunction; - controllerEvent: PluginEvent; + eventScope: PluginEvent; } -export type PluginControllerCommandInfo = { +export type SessionEventInfo = { + activeTime: Date; + eventScope: EventScope; +} + +export type ControllerCommandInfo = { commandInfo: CommandInfo; - controllerEvent: PluginEvent; + eventScope: PluginEvent; } export class EventManager { private app: App; + + /** 事件排序的debounce */ private eventSortDebounce: Record = {}; - private eventList: Record = {}; - private commandList: Record = {}; + + /** 全局事件列表 */ + private eventList: Record = {}; + + /** 会话事件列表 */ + private sessionEventList: Record = {}; + + /** 全局指令列表 */ + private commandList: Record = {}; + + /** 指令信息 */ + private commandInfoList: ControllerCommandInfo[] = []; + + /** 指令信息覆盖配置 */ + private commandOverride: CommandOverrideConfig; constructor(app: App) { this.app = app; + this.commandOverride = app.config.command_override ?? {}; } public async initialize() { } - public on(event: string, controllerEvent: PluginEvent, callback: CallableFunction, options?: MessageEventOptions) { + public on(event: string, eventScope: PluginEvent, callback: CallableFunction, options?: MessageEventOptions) { if (!(event in this.eventList)) { this.eventList[event] = []; } @@ -48,7 +71,7 @@ export class EventManager { const eventInfo = { callback: callback, priority: options.priority!, - controllerEvent + eventScope }; this.eventList[event].push(eventInfo); @@ -56,62 +79,73 @@ export class EventManager { this.sortEvent(event); } - public off(event: string, controllerEvent: PluginEvent, callback: CallableFunction): void - public off(controllerEvent: PluginEvent): void + public off(event: string, eventScope: PluginEvent, callback: CallableFunction): void + public off(eventScope: PluginEvent): void public off(...args: any): void { if (typeof args[0] === 'string') { let [event, controller, callback] = args; if (Array.isArray(this.eventList[event])) { - this.eventList[event] = this.eventList[event].filter((eventInfo) => eventInfo.callback !== callback || eventInfo.controllerEvent !== controller); + this.eventList[event] = this.eventList[event].filter((eventInfo) => eventInfo.callback !== callback || eventInfo.eventScope !== controller); } } else if (typeof args[0] !== 'undefined') { let controller = args[0]; for (let event in this.eventList) { - this.eventList[event] = this.eventList[event].filter((eventInfo) => eventInfo.controllerEvent !== controller); + this.eventList[event] = this.eventList[event].filter((eventInfo) => eventInfo.eventScope !== controller); } } } - public addCommand(commandInfo: CommandInfo, controllerEvent: PluginEvent) { + public addCommand(commandInfo: CommandInfo, eventScope: PluginEvent) { + // 如果配置了Command覆盖,则覆盖原本的指令设置 + if (commandInfo.command in this.commandOverride) { + commandInfo = { + ...commandInfo, + ...this.commandOverride[commandInfo.command] + }; + } + let data = { commandInfo, - controllerEvent: controllerEvent + eventScope: eventScope }; - this.commandList[commandInfo.command] = data; + this.commandInfoList.push(data); + this.commandList[commandInfo.command.toLocaleLowerCase()] = data; if (Array.isArray(commandInfo.alias)) { commandInfo.alias.forEach((alias) => { - this.commandList[alias] = data; + this.commandList[alias.toLocaleLowerCase()] = data; }); } } public removeCommand(commandInfo: CommandInfo): void - public removeCommand(controllerEvent: PluginEvent): void + public removeCommand(eventScope: PluginEvent): void public removeCommand(...args: any): void { if ('command' in args[0]) { let commandInfo: CommandInfo = args[0]; - delete this.commandList[commandInfo.command]; + this.commandInfoList = this.commandInfoList.filter((commandInfoItem) => commandInfoItem.commandInfo !== commandInfo); + delete this.commandList[commandInfo.command.toLocaleLowerCase()]; if (Array.isArray(commandInfo.alias)) { commandInfo.alias.forEach((alias) => { - delete this.commandList[alias]; + delete this.commandList[alias.toLocaleLowerCase()]; }); } } else if (typeof args[0] !== 'undefined') { - let controllerEvent = args[0]; + let eventScope = args[0]; + this.commandInfoList = this.commandInfoList.filter((commandInfoItem) => commandInfoItem.eventScope !== eventScope); for (let command in this.commandList) { - if (this.commandList[command].controllerEvent.controller?.id === controllerEvent.controller?.id) { + if (this.commandList[command].eventScope.controller?.id === eventScope.controller?.id) { delete this.commandList[command]; } } } } - public async emit(eventName: string, senderInfo?: ControllerSubscribeSource | null, ...args: any[]) { + public async emit(eventName: string, senderInfo?: SenderIdentity | null, ...args: any[]) { if (this.app.debug) { if (args[0] instanceof CommonReceivedMessage) { - console.log(`[DEBUG] 触发事件 ${eventName} ${args[0].contentText}`); + this.app.logger.debug(`触发事件 ${eventName} ${args[0].contentText}`); } else { - console.log(`[DEBUG] 触发事件 ${eventName}`); + this.app.logger.debug(`触发事件 ${eventName}`); } } @@ -126,40 +160,46 @@ export class EventManager { isResolved = true; }; - let subscribeList: string[] = []; - - if (senderInfo) { - // 获取订阅列表 - let targetType = ''; - let targetId = ''; - switch (senderInfo.type) { - case 'private': - targetType = 'user'; - targetId = senderInfo.userId!; - break; - case 'group': - targetType = 'group'; - targetId = senderInfo.groupId!; - break; - case 'channel': - targetType = 'channel'; - targetId = senderInfo.channelId!; - break; - } - subscribeList = this.app.subscribe.getSubscribedList(senderInfo.robot.robotId!, targetType, targetId, 'controller'); - } + let [subscribedControllers, disabledControllers] = this.getControllerSubscribe(senderInfo); for (let eventInfo of eventList) { if (!isFilter && senderInfo) { - if (eventInfo.controllerEvent.autoSubscribe) { - if (!eventInfo.controllerEvent.isAllowSubscribe(senderInfo)) { - continue; + switch (senderInfo.type) { + case 'private': + if (!eventInfo.eventScope.allowPrivate) { + continue; + } + if (!eventInfo.eventScope.isAllowSubscribe(senderInfo)) { + continue; + } + break; + case 'group': + if (!eventInfo.eventScope.allowGroup) { + continue; + } + break; + case 'channel': + if (!eventInfo.eventScope.allowChannel) { + continue; + } + break; + } + + if (senderInfo.type !== 'private') { // 私聊消息不存在订阅,只判断群消息和频道消息 + if (eventInfo.eventScope.autoSubscribe) { + if (!eventInfo.eventScope.isAllowSubscribe(senderInfo)) { + continue; + } else { + // 检测控制器是否已禁用 + if (!eventInfo.eventScope.controller || disabledControllers.includes(eventInfo.eventScope.controller.id)) { + continue; + } + } } else { - // 需要添加订阅检测 - } - } else if (senderInfo.type !== 'private') { - if (!eventInfo.controllerEvent.controller || !subscribeList.includes(eventInfo.controllerEvent.controller.id)) { - continue; + // 检测控制器是否已启用 + if (!eventInfo.eventScope.controller || !subscribedControllers.includes(eventInfo.eventScope.controller.id)) { + continue; + } } } } @@ -170,7 +210,7 @@ export class EventManager { break; } } catch(err: any) { - console.error(`事件 ${eventName} 处理失败`); + this.app.logger.error(`事件 ${eventName} 处理失败: `, err); console.error(err); } } @@ -206,7 +246,7 @@ export class EventManager { // 尝试识别空格分隔的指令 if (contentText.includes(' ')) { - command = contentText.split(' ')[0]; + command = contentText.split(' ')[0].toLocaleLowerCase(); args = contentText.substring(command.length + 1); if (!(command in this.commandList)) { @@ -232,7 +272,7 @@ export class EventManager { } if (this.app.debug) { - console.log('[DEBUG] 指令识别结果', command, args); + this.app.logger.debug('指令识别结果', command, args); } return await this.emit(`command/${command}`, this.getSenderInfo(message), args, message); @@ -257,7 +297,7 @@ export class EventManager { } - public getSenderInfo(message: CommonReceivedMessage): ControllerSubscribeSource { + public getSenderInfo(message: CommonReceivedMessage): SenderIdentity { if (message.origin === 'private') { return { type: 'private', @@ -279,6 +319,37 @@ export class EventManager { } } + public getControllerSubscribe(senderInfo?: SenderIdentity | null): [string[], string[]] { + let subscribedCommands: string[] = []; + let disabledCommands: string[] = []; + + if (senderInfo) { + let targetType = ''; + let targetId = ''; + switch (senderInfo.type) { + case 'private': + targetType = 'user'; + targetId = senderInfo.userId!; + break; + case 'group': + targetType = 'group'; + targetId = senderInfo.groupId!; + break; + case 'channel': + targetType = 'channel'; + targetId = senderInfo.channelId!; + break; + } + subscribedCommands = this.app.subscribe.getSubscribedList(senderInfo.robot.robotId!, targetType, targetId, 'controller'); + disabledCommands = this.app.subscribe.getSubscribedList(senderInfo.robot.robotId!, targetType, targetId, 'disable_controller'); + } + + return [ + subscribedCommands, + disabledCommands + ]; + } + private sortEvent(eventName: string) { if (this.eventSortDebounce[eventName]) { return; diff --git a/src/PluginManager.ts b/src/PluginManager.ts index 9559cce..51ade86 100644 --- a/src/PluginManager.ts +++ b/src/PluginManager.ts @@ -1,21 +1,27 @@ import { EventManager } from "./EventManager"; import { CommonReceivedMessage } from "./message/Message"; import { Robot } from "./RobotManager"; +import fs from 'fs'; +import fsAsync from 'fs/promises'; import chokidar from 'chokidar'; +import Yaml from 'yaml'; import App from "./App"; import EventEmitter from "events"; import path from "path"; +import { SenderIdentity } from "./message/Sender"; +import { Utils } from "./utils/Utils"; export const MessagePriority = { LOWEST: 0, LOW: 20, DEFAULT: 40, + HIGH: 50, /** - * 在控制器中添加的临时会话处理器。 - * 用于处理深层会话,会比一般指令优先级高。 + * 在控制器中添加的会话处理器。 + * 用于处理独占模式会话,会比一般指令优先级高,且会阻止所有后续事件。 */ - TEMP_HANDLER: 60, - HIGH: 80, + SESSION_HANDLER: 60, + HIGHER: 70, /** * 一些系统自带的事件处理,如:记录消息 */ @@ -48,29 +54,26 @@ export type RawEventCallback = (robot: Robot, event: any, resolved: VoidFunction export type AllowedList = string[] | '*'; -export type ControllerSubscribeSource = { - type: 'private' | 'group' | 'channel' | 'raw' | string, - robot: Robot, - groupId?: string, - userId?: string, - channelId?: string, -} - export class PluginManager extends EventEmitter { private app: App; private pluginPath: string; + private configPath: string; private watcher!: chokidar.FSWatcher; + private configWatcher!: chokidar.FSWatcher; public controllers: Record; public fileControllers: Record; + public configControllers: Record; - constructor(app: App, pluginPath: string) { + constructor(app: App, pluginPath: string, configPath: string) { super(); this.app = app; - this.pluginPath = pluginPath; + this.pluginPath = path.resolve(pluginPath); + this.configPath = path.resolve(configPath); this.controllers = {}; this.fileControllers = {}; + this.configControllers = {}; } /** @@ -82,10 +85,15 @@ export class PluginManager extends EventEmitter { ignorePermissionErrors: true, persistent: true }); - this.watcher.on('add', this.loadController.bind(this)); this.watcher.on('change', this.loadController.bind(this)); this.watcher.on('unlink', this.removeController.bind(this)); + + this.configWatcher = chokidar.watch(this.configPath + '/**/*.yml', { + ignorePermissionErrors: true, + persistent: true + }); + this.configWatcher.on('change', this.reloadConfig.bind(this)); } async loadController(file: string) { @@ -111,16 +119,19 @@ export class PluginManager extends EventEmitter { this.fileControllers[file] = controllerInstance; if (isReload) { - console.log(`已重新加载Controller: ${file}`); + this.app.logger.info(`已重新加载Controller: ${file}`); this.emit('controllerReloaded', controllerInstance); } else { - console.log(`已加载Controller: ${file}`); + this.app.logger.info(`已加载Controller: ${file}`); this.emit('controllerLoaded', controllerInstance); } - const pluginMisc = new PluginEvent(this.app.event); - controllerInstance.event = pluginMisc; - await controllerInstance.initialize(); + const pluginEvent = new PluginEvent(this.app); + controllerInstance.event = pluginEvent; + + const controllerConfig = await this.loadControllerConfig('standalone', controllerInstance); + + await controllerInstance.initialize(controllerConfig); } else { throw new Error('PluginController ID is not defined.'); } @@ -136,18 +147,147 @@ export class PluginManager extends EventEmitter { async removeController(file: string, isReload = false) { const controller = this.fileControllers[file]; if (controller) { + const configFile = this.getConfigFile('standalone', controller); + await controller.event.destroy(); await controller.destroy?.(); delete this.controllers[file]; delete this.fileControllers[file]; + if (configFile in this.configControllers) { + delete this.configControllers[configFile]; + } this.emit('controllerRemoved', controller); if (!isReload) { - console.log(`已移除Controller: ${controller.id}`); + this.app.logger.info(`已移除Controller: ${controller.id}`); } } } + + getConfigFile(pluginId: string, controller: PluginController) { + return path.resolve(this.configPath, pluginId, controller.id + '.yml'); + } + + async loadControllerConfig(pluginId: string, controller: PluginController) { + const configFile = this.getConfigFile(pluginId, controller); + try { + if (configFile in this.configControllers) { // 防止保存时触发重载 + delete this.configControllers[configFile]; + } + + const defaultConfig = await controller.getDefaultConfig?.() ?? {}; + let config: any = defaultConfig; + let shouldFill: boolean = false; + + if (fs.existsSync(configFile)) { + let localConfig = Yaml.parse(await fsAsync.readFile(configFile, 'utf-8')); + config = {...defaultConfig, ...localConfig}; + if (!Utils.compare(config, localConfig)) { + shouldFill = true; + this.app.logger.info(`配置文件已生成: ${configFile}`); + } + } else { + shouldFill = true; + } + + if (shouldFill) { + Utils.prepareDir(path.dirname(configFile)); + await fsAsync.writeFile(configFile, Yaml.stringify(config)); + } + + setTimeout(() => { + this.configControllers[configFile] = controller; + }, 1000); + + return config; + } catch(err: any) { + this.app.logger.error(`加载Controller配置失败: ${configFile}`, err); + console.error(err); + } + } + + async reloadConfig(file: string) { + this.app.logger.info(`配置文件已更新: ${file}`); + if (file in this.configControllers) { + try { + const controller = this.configControllers[file]; + if (controller.updateConfig) { // 如果控制器支持重载配置,则直接调用 + const localConfig = Yaml.parse(await fsAsync.readFile(file, 'utf-8')); + await controller.updateConfig(localConfig); + this.app.logger.info(`已重载Controller配置: ${controller.id}`); + } else { // 重载整个控制器 + let controllerFile: string = ''; + for (let [file, c] of Object.entries(this.fileControllers)) { + if (c === controller) { + controllerFile = file; + break; + } + } + if (controllerFile) { + await this.loadController(controllerFile); + } + } + } catch(err: any) { + this.app.logger.error(`重载Controller配置失败: ${file}`, err); + console.error(err); + } + } + } + + /** + * 获取订阅的控制器 + * @param senderInfo + * @returns + */ + public getSubscribedControllers(senderInfo: SenderIdentity): PluginController[] { + let [subscribedControllers, disabledControllers] = this.app.event.getControllerSubscribe(senderInfo); + + return Object.values(this.controllers).filter((controller) => { + if (controller.event.commandList.length === 0) return false; + + switch (senderInfo.type) { + case 'private': + if (!controller.event.allowPrivate) { + return false; + } + if (!controller.event.isAllowSubscribe(senderInfo)) { + return false; + } + break; + case 'group': + if (!controller.event.allowGroup) { + return false; + } + break; + case 'channel': + if (!controller.event.allowChannel) { + return false; + } + break; + } + + if (senderInfo.type !== 'private') { // 私聊消息不存在订阅,只判断群消息和频道消息 + if (controller.event.autoSubscribe) { + if (!controller.event.isAllowSubscribe(senderInfo)) { + return false; + } else { + // 检测控制器是否已禁用 + if (disabledControllers.includes(controller.id)) { + return false; + } + } + } else { + // 检测控制器是否已启用 + if (!subscribedControllers.includes(controller.id)) { + return false; + } + } + } + + return true; + }); + } } export interface PluginController { @@ -157,55 +297,24 @@ export interface PluginController { event: PluginEvent; - initialize: () => Promise; + initialize: (config: any) => Promise; destroy?: () => Promise; -} - -export class PluginEvent { - private eventManager: EventManager; - - public controller?: PluginController; - - public autoSubscribe = false; - public forceSubscribe = false; - public showInSubscribeList = true; - public allowPrivate = true; - public allowGroup = true; - public allowChannel = true; - - public allowedRobotTypeList: AllowedList = '*'; - - private commandList: CommandInfo[] = []; - private eventList: Record = {}; + getDefaultConfig?: () => Promise; + updateConfig?: (config: any) => Promise; +} - constructor(eventManager: EventManager) { - this.eventManager = eventManager; - } +export class EventScope { + protected app: App; + protected eventManager: EventManager; - public isAllowSubscribe: (source: ControllerSubscribeSource) => boolean = (source) => { - if (this.allowedRobotTypeList !== '*' && !this.allowedRobotTypeList.includes(source.robot.type)) { - return false; - } + public commandList: CommandInfo[] = []; + public eventList: Record = {}; + public eventSorted: Record = {}; - switch (source.type) { - case 'private': - if (!this.allowPrivate) { - return false; - } - break; - case 'group': - if (!this.allowGroup) { - return false; - } - break; - case 'channel': - if (!this.allowChannel) { - return false; - } - break; - } - return true; + constructor(app: App) { + this.app = app; + this.eventManager = app.event; } /** @@ -295,8 +404,9 @@ export class PluginEvent { priority: options.priority! }; this.eventList[event].push(eventInfo); - - this.eventManager.on(event, this, callback, options); + this.eventSorted[event] = false; + + this.afterAddEventListener(event, callback, options); } public off(event: string, callback: CallableFunction): void { @@ -306,17 +416,58 @@ export class PluginEvent { }); } - this.eventManager.off(event, this, callback); + this.afterRemoveEventListener(event, callback); + } + + /** + * Trigger event. + * @param event Event name + * @param args Arguments + * @returns + */ + public async emit(event: string, ...args: any[]) { + let isResolved = false; + + const resolved = () => { + isResolved = true; + }; + + if (event in this.eventList) { + if (!this.eventSorted[event]) { // 如果事件未排序,触发排序 + this.eventList[event].sort((a, b) => { + return a.priority - b.priority; + }); + } + + for (const eventInfo of this.eventList[event]) { + try { + await eventInfo.callback(...args, resolved); + if (isResolved) { + break; + } + } catch (err) { + this.app.logger.error(err); + } + } + } + + return isResolved; } /** * Register command. - * @param command - * @param name - * @param callback - * @param options + * @param command Command + * @param name Command name + * @param callback Callback function + * @param options Command options */ public registerCommand(command: string, name: string, callback: CommandCallback, options?: MessageEventOptions): void + /** + * Register command. + * @param commandInfo Command info + * @param callback Callback function + * @param options Command options + */ public registerCommand(commandInfo: CommandInfo, callback: CommandCallback, options?: MessageEventOptions): void public registerCommand(...args: any[]): void { // 处理传入参数 @@ -341,18 +492,62 @@ export class PluginEvent { this.on(`command/${commandInfo.command}`, callback, options); if (Array.isArray(commandInfo.alias)) { // Add event for alias commandInfo.alias.forEach((cmd) => { - this.on(`command/${cmd}`, callback, options); + this.on(`command/${cmd.toLocaleLowerCase()}`, callback, options); }); } + + this.afterAddCommand(commandInfo as any); + } + + protected afterAddEventListener(event: string, callback: CallableFunction, options?: MessageEventOptions): void { - this.eventManager.addCommand(commandInfo as any, this); } - /** - * Initialize plugin controller. - */ - public async initialize() { + protected afterRemoveEventListener(event: string, callback: CallableFunction): void { } + + protected afterAddCommand(commandInfo: CommandInfo): void { } +} + +export class PluginEvent extends EventScope { + public controller?: PluginController; + public autoSubscribe = false; + public forceSubscribe = false; + public showInSubscribeList = true; + + public allowPrivate = true; + public allowGroup = true; + public allowChannel = true; + + public allowedRobotTypeList: AllowedList = '*'; + + public isAllowSubscribe: (source: SenderIdentity) => boolean = (source) => { + if (this.allowedRobotTypeList !== '*' && !this.allowedRobotTypeList.includes(source.robot.type)) { + return false; + } + + switch (source.type) { + case 'private': + if (!this.allowPrivate) { + return false; + } + break; + case 'group': + if (!this.allowGroup) { + return false; + } + break; + case 'channel': + if (!this.allowChannel) { + return false; + } + break; + } + return true; + } + + public init(controller: PluginController) { + this.controller = controller; } /** @@ -365,4 +560,16 @@ export class PluginEvent { this.eventList = {}; } + + protected override afterAddEventListener(event: string, callback: CallableFunction, options?: MessageEventOptions): void { + this.eventManager.on(event, this, callback, options); + } + + protected override afterRemoveEventListener(event: string, callback: CallableFunction): void { + this.eventManager.off(event, this, callback); + } + + protected override afterAddCommand(commandInfo: CommandInfo): void { + this.eventManager.addCommand(commandInfo as any, this); + } } \ No newline at end of file diff --git a/src/ProviderManager.ts b/src/ProviderManager.ts index b1c173b..f909752 100644 --- a/src/ProviderManager.ts +++ b/src/ProviderManager.ts @@ -4,8 +4,6 @@ import App from './App'; import { BaseProvider } from './base/provider/BaseProvider'; import { ChannelConfig } from './Config'; -const PROVIDER_PATH = __dirname + "/provider"; - export class ProviderManager { private app: App; private providerClasses: { [key: string]: any } @@ -16,20 +14,22 @@ export class ProviderManager { } async initialize() { + const PROVIDER_PATH = path.join(this.app.srcPath, "provider"); + for (let file of fs.readdirSync(PROVIDER_PATH)) { let providerFile = `${PROVIDER_PATH}/${file}`; if (providerFile.match(/\.(js|mjs)$/)) { // 加载js文件 let providerName = path.basename(providerFile).replace(/Provider\.(js|mjs)$/gi, "").toLocaleLowerCase(); try { - let provider = require(providerFile)?.default; - if (!provider) { + let provider = await import(providerFile); + if (!provider || !provider.default) { throw new Error("provider is empty"); } - this.providerClasses[providerName] = provider; - console.log(`已加载Provider: ${providerName}`); + this.providerClasses[providerName] = provider.default; + this.app.logger.info(`已加载Provider: ${providerName}`); } catch(err) { - console.log(`无法加载Provider: ${providerName}`, err); + this.app.logger.info(`无法加载Provider: ${providerName}`, err); } } } diff --git a/src/RestfulApiManager.ts b/src/RestfulApiManager.ts index 7754e22..01132d8 100644 --- a/src/RestfulApiManager.ts +++ b/src/RestfulApiManager.ts @@ -3,7 +3,7 @@ import Koa from 'koa'; import { RestfulApiConfig } from "./Config"; import Router from "koa-router"; import { makeRoutes } from "./restful/routes"; -import koaBody from "koa-body"; +import { koaBody } from "koa-body"; export interface RestfulContext { feedbot: App, @@ -46,7 +46,7 @@ export class RestfulApiManager { return new Promise((resolve) => { this.koa.use(this.router.routes()); this.koa.listen(this.config.port, () => { - console.log(`Restful API 启动于:http://${this.config.host}:${this.config.port}`); + this.app.logger.info(`Restful API 启动于:http://${this.config.host}:${this.config.port}`); resolve(); }); }); diff --git a/src/RobotManager.ts b/src/RobotManager.ts index 2236ff6..294f9f6 100644 --- a/src/RobotManager.ts +++ b/src/RobotManager.ts @@ -4,22 +4,24 @@ import path from "path"; import App from "./App"; import { MultipleMessage } from "./base/provider/BaseProvider"; import { RobotConfig } from "./Config"; -import { CommonSendMessage } from "./message/Message"; +import { CommonGroupMessage, CommonPrivateMessage, CommonReceivedMessage, CommonSendMessage } from "./message/Message"; +import { GroupSender, SenderIdentity, UserSender } from "./message/Sender"; import { CommandInfo } from "./PluginManager"; import { RestfulApiManager, RestfulContext, RestfulRouter } from "./RestfulApiManager"; +import { SessionStore } from "./SessionManager"; import { Target } from "./SubscribeManager"; -const ROBOT_PATH = __dirname + "/robot"; - export interface Robot { type: string; robotId?: string; uid?: string; + description?: string; initialize?: () => Promise; initRestfulApi?: (router: RestfulRouter, api: RestfulApiManager) => Promise; setCommands?(commands: CommandInfo[]): Promise; sendMessage(message: CommonSendMessage): Promise; sendPushMessage(targets: Target[], message: string): Promise; + getSession(senderIdentity: SenderIdentity, type: string): SessionStore; } export class RobotManager { @@ -37,20 +39,22 @@ export class RobotManager { this.robots = {}; } - async initialize() { + public async initialize() { + const ROBOT_PATH = path.join(this.app.srcPath, "robot"); + for (let file of fs.readdirSync(ROBOT_PATH)) { let robotFile = `${ROBOT_PATH}/${file}`; if (robotFile.match(/\.m?js$/)) { // 加载js文件 let robotName = path.basename(robotFile).replace(/Robot\.m?js$/gi, "").toLocaleLowerCase(); try { - let robotClass = require(robotFile)?.default; - if (!robotClass) { + let robotClass = await import(robotFile); + if (!robotClass || !robotClass.default) { throw new Error("robot api is empty"); } - this.robotClasses[robotName] = robotClass; + this.robotClasses[robotName] = robotClass.default; } catch(err) { - console.log(`无法加载Robot API: ${robotName}`, err); + this.app.logger.error(`无法加载Robot API: ${robotName}`, err); } } } @@ -59,7 +63,7 @@ export class RobotManager { let robotConfig = this.config[robotId]; let robotType: string = robotConfig.type; if (!robotType) { - console.error("无法加载 " + robotId + " Robot: 配置文件中未定义 'type'"); + this.app.logger.error("无法加载 " + robotId + " Robot: 配置文件中未定义 'type'"); continue; } robotType = robotType.toLocaleLowerCase(); @@ -72,7 +76,7 @@ export class RobotManager { await robotObject.initRestfulApi?.(this.app.restfulApi.getRobotRouter(robotId), this.app.restfulApi); this.robots[robotId] = robotObject; - console.log(`已加载Robot: ${robotId}`); + this.app.logger.info(`已加载Robot: ${robotId}`); } catch(err) { console.error(`无法加载 ${robotId} Robot: `, err); } @@ -110,4 +114,66 @@ export class RobotManager { } } } + + public getSenderIdentity(robot: Robot, message: CommonReceivedMessage) { + let sender: SenderIdentity = { + robot: robot, + type: 'raw', + }; + if (message instanceof CommonPrivateMessage) { + const messageSender = message.sender as UserSender; + sender.type = 'private'; + sender.userId = messageSender.uid; + } else if (message instanceof CommonGroupMessage) { + const messageSender = message.sender as GroupSender; + sender.type = 'group'; + sender.userId = messageSender.uid; + sender.groupId = messageSender.groupId; + sender.rootGroupId = messageSender.rootGroupId; + } + + return sender; + } + + public getSessionPath(sender: SenderIdentity, type: string = 'chat'): string[] { + if (type === 'global') { // 全局Session + return ['global']; + } + + let ret: string[] = ['robot', sender.robot.robotId!]; + + if (type === 'robot') { // 机器人Session + return ret; + } + + if (!sender.userId) { + throw new Error("Unknown sender"); + } + + if (type === 'user' || sender.type === 'private') { // 用户Session + ret.push('user', sender.userId!); + return ret; + } + + if (sender.type === 'group') { + if (sender.rootGroupId && sender.groupId) { + ret.push('group', sender.rootGroupId); + if (type === 'rootGroup') return ret; + + ret.push(sender.groupId); + if (type === 'group') return ret; + + ret.push(sender.userId!); + if (type === 'chat') return ret; + } else if (sender.rootGroupId || sender.groupId) { + ret.push('group', sender.rootGroupId || sender.groupId!); + if (type === 'rootGroup' || type === 'group') return ret; + + ret.push(sender.userId!); + if (type === 'chat') return ret; + } + } + + throw new Error(`Unknown session type: ${type}`); + } } diff --git a/src/ServiceManager.ts b/src/ServiceManager.ts index 0dbadb3..15fad06 100644 --- a/src/ServiceManager.ts +++ b/src/ServiceManager.ts @@ -4,8 +4,6 @@ import path from 'path'; import App from './App'; import { ServiceConfig } from './Config'; -const SERVICE_PATH = __dirname + "/service"; - export interface Service { initialize(): Promise; destory(): Promise; @@ -35,20 +33,22 @@ export class ServiceManager { this.services = {}; } - async initialize() { + public async initialize() { + const SERVICE_PATH = path.join(this.app.srcPath, "service"); + for (let file of fs.readdirSync(SERVICE_PATH)) { let serviceFile = `${SERVICE_PATH}/${file}`; if (serviceFile.match(/\.(js|mjs)$/)) { // 加载js文件 let serviceName = path.basename(serviceFile).replace(/Service\.(js|mjs)$/gi, "").toLocaleLowerCase(); try { - let serviceClass = require(serviceFile)?.default; - if (!serviceClass) { + let serviceClass = await import(serviceFile); + if (!serviceClass || !serviceClass.default) { throw new Error("service is empty"); } - this.serviceClasses[serviceName] = serviceClass; + this.serviceClasses[serviceName] = serviceClass.default; } catch(err) { - console.log(`无法加载Service: ${serviceName}`, err); + this.app.logger.error(`无法加载Service: ${serviceName}`, err); } } } @@ -67,7 +67,7 @@ export class ServiceManager { let serviceObject: Service = new serviceClass(this.app, serviceConfig); await serviceObject.initialize(); this.services[serviceName] = serviceObject; - console.log(`已加载Service: ${serviceName}`); + this.app.logger.info(`已加载Service: ${serviceName}`); } catch(err) { console.error(`无法加载 ${serviceName} Service: `, err); } diff --git a/src/SessionManager.ts b/src/SessionManager.ts new file mode 100644 index 0000000..8ce0946 --- /dev/null +++ b/src/SessionManager.ts @@ -0,0 +1,95 @@ +import { caching, Cache } from "cache-manager"; +import { redisStore } from "cache-manager-redis-yet"; + +import App from "./App"; +import { SessionConfig } from "./Config"; + +export class SessionManager { + private app: App; + private config: SessionConfig; + + private store!: Cache; + + constructor(app: App, config: SessionConfig) { + this.app = app; + this.config = config; + } + + public async initialize() { + if (this.config.type === 'redis') { + let cacheOption = { + socket: { + host: this.config.redis?.host ?? 'localhost', + port: this.config.redis?.port ?? 6379, + }, + password: this.config.redis?.password, + db: this.config.redis?.db ?? 0, + ttl: (this.config.ttl ?? 600) * 1000 + }; + this.app.logger.debug('Redis Store 配置: ' + JSON.stringify(cacheOption)); + this.store = await caching(await redisStore(cacheOption)); + this.app.logger.info(`使用Redis作为SessionStore`); + } else { + let cacheOption = { + ttl: (this.config.ttl ?? 600) * 1000 + }; + this.store = await caching('memory', cacheOption); + this.app.logger.info(`使用内存数据库作为SessionStore`); + } + } + + /** + * 获取命名的SessionStore + * @param path + * @returns + */ + public getStore(path: string[]): SessionStore { + return new SessionStore(this.store, path); + } +} + +export class SessionStore implements Cache { + rootStore: Cache; + prefix: string; + + constructor(rootStore: Cache, path: string[]) { + this.rootStore = rootStore; + if (path.length > 0) { + this.prefix = path.join(':') + ':'; + } else { + this.prefix = ''; + } + } + + public set(key: string, value: unknown, ttl?: number | undefined) { + if (typeof ttl === 'undefined') { + return this.rootStore.set(this.prefix + key, value); + } else { + return this.rootStore.set(this.prefix + key, value, ttl * 1000); + } + } + + public get(key: string) { + return this.rootStore.get(this.prefix + key); + } + + public del(key: string) { + return this.rootStore.del(this.prefix + key); + } + + public reset() { + return this.rootStore.store.del(this.prefix + '*'); + } + + wrap(key: string, fn: () => Promise, ttl?: number | undefined) { + if (typeof ttl === 'undefined') { + return this.rootStore.wrap(this.prefix + key, fn); + } else { + return this.rootStore.wrap(this.prefix + key, fn, ttl * 1000); + } + } + + get store() { + return this.rootStore.store; + } +} \ No newline at end of file diff --git a/src/SubscribeManager.ts b/src/SubscribeManager.ts index 3b4c704..ad60c90 100644 --- a/src/SubscribeManager.ts +++ b/src/SubscribeManager.ts @@ -67,7 +67,7 @@ export class SubscribeManager { this.loadSubscribeFile(); this.subscribeList = {}; this.rebuildTree(); - console.log('已重载Subscribe'); + this.app.logger.info('已重载Subscribe'); } /** @@ -80,14 +80,10 @@ export class SubscribeManager { let targetTypeConf = targetConf[targetType]; for (let targetId in targetTypeConf) { let subscribeList = targetTypeConf[targetId]; - if (subscribeList.channel) { - for (let sourceId in subscribeList.channel) { - this.addSubscribe(robotId, targetType, targetId, 'channel:' + sourceId); - } - } - if (subscribeList.controller) { - for (let controllerId in subscribeList.controller) { - this.addSubscribe(robotId, targetType, targetId, 'controller:' + controllerId); + for (let sourceType in subscribeList) { + let sourceList = subscribeList[sourceType]; + for (let sourceId of sourceList) { + this.addSubscribe(robotId, targetType, targetId, sourceType + ':' + sourceId); } } } diff --git a/src/channel/BroadcastChannel.js b/src/channel/BroadcastChannel.js index 6b01f0e..8acc44a 100644 --- a/src/channel/BroadcastChannel.js +++ b/src/channel/BroadcastChannel.js @@ -1,6 +1,6 @@ var Channel = require('./Channel'); -class BroadcastChannel extends Channel { +export default class BroadcastChannel extends Channel { constructor(app){ super(app, {}); } @@ -27,5 +27,3 @@ class BroadcastChannel extends Channel { } } } - -module.exports = BroadcastChannel; \ No newline at end of file diff --git a/src/channel/Channel.js b/src/channel/Channel.js index 5059b30..0929ab1 100644 --- a/src/channel/Channel.js +++ b/src/channel/Channel.js @@ -1,6 +1,6 @@ -var utils = require('../Utils'); +import { Utils as utils } from '../utils/Utils'; -class Channel { +export default class Channel { constructor(app, config){ this.app = app; this.config = config; @@ -172,5 +172,3 @@ class Channel { } } } - -module.exports = Channel; \ No newline at end of file diff --git a/src/controller/ChatGPTController.ts b/src/controller/ChatGPTController.ts new file mode 100644 index 0000000..da346da --- /dev/null +++ b/src/controller/ChatGPTController.ts @@ -0,0 +1,241 @@ +import App from "../App"; +import { CommonReceivedMessage } from "../message/Message"; +import { MessagePriority, PluginController, PluginEvent } from "../PluginManager"; +import { ChatGPTBrowserClient, ChatGPTClient } from '@waylaidwanderer/chatgpt-api'; + +export default class ChatGPTController implements PluginController { + private SESSION_KEY_CHAT_SESSION = 'openai_chatSession'; + private SESSION_KEY_API_CHAT_SESSION = 'openai_apiChatSession'; + + private DEFAULT_PROMPT = ''; + + private config: any = {}; + + public event!: PluginEvent; + public app: App; + public chatGPTClient: any; + public chatGPTApiClient: any; + + public id = 'openai'; + public name = 'OpenAI'; + public description = '对话AI的功能'; + + private chatGenerating = false; + + constructor(app: App) { + this.app = app; + } + + async getDefaultConfig() { + return { + proxy: '', + browser_api: { + token: '', + cookies: '', + }, + openai_api: { + token: '', + bot_name: '', + model_options: { + model: 'gpt-3.5-turbo', + max_tokens: 1000, + } + }, + } + } + + async initialize(config: any) { + await this.updateConfig(config); + + this.event.init(this); + + this.event.registerCommand({ + command: 'ai', + name: '开始对话', + }, (args, message, resolve) => { + resolve(); + + this.handleChatGPTChat(args, message).catch(console.error); + }); + + this.event.registerCommand({ + command: '重置对话', + name: '重置对话', + }, (args, message, resolve) => { + resolve(); + + message.session.chat.del(this.SESSION_KEY_CHAT_SESSION); + message.session.chat.del(this.SESSION_KEY_API_CHAT_SESSION); + message.sendReply('对话已重置', true); + }); + + /* + this.event.on('message/focused', async (message, resolved) => { + let chatSession = await message.session.chat.get(this.SESSION_KEY_CHAT_SESSION); + if (chatSession) { + resolved(); + + this.handleChatGPTChat(message.contentText, message).catch(console.error); + } + }); + */ + + this.event.on('message/focused', async (message, resolved) => { + resolved(); + + this.handleChatGPTAPIChat(message.contentText, message).catch(console.error); + }, { priority: MessagePriority.LOWEST }); + } + + async updateConfig(config: any) { + this.config = config; + + const clientOptions = { + accessToken: config.browser_api.token, + cookies: config.browser_api.cookies, + proxy: config.proxy, + }; + this.chatGPTClient = new ChatGPTBrowserClient(clientOptions); + + const apiClientOptions = { + promptPrefix: config.openai_api.system_prompt, + chatGptLabel: config.openai_api.bot_name, + proxy: config.proxy, + modelOptions: config.openai_api.model_options ? { + model: config.openai_api.model_options.model, + max_tokens: config.openai_api.model_options.max_tokens, + } : undefined, + } + this.chatGPTApiClient = new ChatGPTClient(config.openai_api.token, apiClientOptions); + + this.DEFAULT_PROMPT = config.browser_api.prefix_prompt; + } + + private async handleChatGPTChat(content: string, message: CommonReceivedMessage) { + if (this.chatGenerating) { + message.sendReply('正在生成另一段对话,请稍后', true); + return; + } + if (content.trim() === '') { + message.sendReply('说点什么啊', true); + return; + } + + let response: any; + + let isFirstMessage = false; + let chatSession = await message.session.chat.get(this.SESSION_KEY_CHAT_SESSION); + if (!chatSession) { + isFirstMessage = true; + chatSession = {}; + } + + this.app.logger.debug('ChatGPT chatSession', chatSession); + + const lowSpeedTimer = setTimeout(() => { + message.sendReply('生成对话速度较慢,请耐心等待', true); + }, 10 * 1000); + + this.chatGenerating = true; + try { + if (!chatSession.conversationId) { + response = await this.chatGPTClient.sendMessage(this.DEFAULT_PROMPT + content); + } else { + response = await this.chatGPTClient.sendMessage(content, chatSession); + } + } catch (err: any) { + this.app.logger.error('ChatGPT error', err); + console.error(err); + if (err?.json?.detail) { + if (err.json.detail === 'Conversation not found') { + message.sendReply('对话已失效,请重新开始', true); + await message.session.chat.del(this.SESSION_KEY_CHAT_SESSION); + return; + } + } + + message.sendReply('生成对话失败: ' + err.toString(), true); + return; + } finally { + clearTimeout(lowSpeedTimer); + this.chatGenerating = false; + } + + if (this.app.debug) { + this.app.logger.debug('ChatGPT response', JSON.stringify(response)); + console.log(response); + } + + if (response.response) { + let reply: string = response.response ?? ''; + reply = reply.replace(/\n\n/g, '\n'); + /* + if (isFirstMessage) { + reply += '\n\n接下来的对话可以直接回复我。'; + } + */ + + chatSession.conversationId = response.conversationId; + chatSession.parentMessageId = response.messageId; + + await message.session.chat.set(this.SESSION_KEY_CHAT_SESSION, chatSession, 600); + + message.sendReply(reply, true); + } + } + + private async handleChatGPTAPIChat(content: string, message: CommonReceivedMessage) { + if (content.trim() === '') { + message.sendReply('说点什么啊', true); + return; + } + + let response: any; + + let isFirstMessage = false; + let chatSession = await message.session.chat.get(this.SESSION_KEY_API_CHAT_SESSION); + if (!chatSession) { + isFirstMessage = true; + chatSession = {}; + } + + this.app.logger.debug('ChatGPT chatSession', chatSession); + + try { + if (!chatSession.conversationId) { + response = await this.chatGPTApiClient.sendMessage(content); + } else { + response = await this.chatGPTApiClient.sendMessage(content, chatSession); + } + } catch (err: any) { + this.app.logger.error('ChatGPT error', err); + console.error(err); + if (err?.json?.detail) { + if (err.json.detail === 'Conversation not found') { + message.sendReply('对话已失效,请重新开始', true); + await message.session.chat.del(this.SESSION_KEY_CHAT_SESSION); + return; + } + } + + message.sendReply('生成对话失败: ' + err.toString(), true); + return; + } + + if (this.app.debug) { + this.app.logger.debug('ChatGPT response', JSON.stringify(response)); + console.log(response); + } + + if (response.response) { + let reply: string = response.response ?? ''; + + chatSession.conversationId = response.conversationId; + chatSession.parentMessageId = response.messageId; + + await message.session.chat.set(this.SESSION_KEY_API_CHAT_SESSION, chatSession, 3600); + + message.sendReply(reply, true); + } + } +} \ No newline at end of file diff --git a/src/controller/IsekaiWikiController.ts b/src/controller/IsekaiWikiController.ts index c1e8849..258fb73 100644 --- a/src/controller/IsekaiWikiController.ts +++ b/src/controller/IsekaiWikiController.ts @@ -19,7 +19,7 @@ export default class IsekaiWikiController implements PluginController { } public async initialize(): Promise { - this.event.controller = this; + this.event.init(this); const wikiMisc = new WikiMisc(this.app, 'https://www.isekai.cn/api.php'); diff --git a/src/controller/SfsettingsController.ts b/src/controller/SfsettingsController.ts index ed0b8fb..40a4f59 100644 --- a/src/controller/SfsettingsController.ts +++ b/src/controller/SfsettingsController.ts @@ -15,7 +15,7 @@ export default class SfsettingsController implements PluginController { } public async initialize(): Promise { - this.event.controller = this; + this.event.init(this); const wikiMisc = new WikiMisc(this.app, 'https://www.sfsettings.com/w/api.php'); diff --git a/src/controller/SystemController.ts b/src/controller/SystemController.ts new file mode 100644 index 0000000..34dacd5 --- /dev/null +++ b/src/controller/SystemController.ts @@ -0,0 +1,84 @@ +import App from "../App"; +import { CommonReceivedMessage, CommonSendMessage } from "../message/Message"; +import { PluginController, PluginEvent } from "../PluginManager"; + +export default class SystemController implements PluginController { + public event!: PluginEvent; + public app: App; + + public id = 'system'; + public name = '系统功能'; + public description = '系统功能控制器'; + + constructor(app: App) { + this.app = app; + } + + async initialize() { + this.event.init(this); + + this.event.autoSubscribe = true; + this.event.forceSubscribe = true; + + this.event.registerCommand({ + command: '帮助', + name: '获取帮助', + alias: ['help', '?', '?'], + }, (args, message, resolved) => { + resolved(); + + this.handleHelp(args, message); + }); + } + + async handleHelp(args: string, message: CommonReceivedMessage) { + const senderInfo = this.app.event.getSenderInfo(message); + const subscribedControllers = this.app.plugin.getSubscribedControllers(senderInfo); + + let replyMsg = message.createReplyMessage(); + replyMsg.type = 'help'; + replyMsg.extra.controllers = subscribedControllers; + + let helpBuilder: string[] = []; + + let robotDescription = message.receiver.description; + if (robotDescription) { + helpBuilder.push(robotDescription); + helpBuilder.push(''); + } + + helpBuilder.push('功能列表:'); + + for (let controller of subscribedControllers) { + helpBuilder.push(`【${controller.name}】`); + if (controller.event.commandList.length > 0) { + controller.event.commandList.forEach(commandInfo => { + helpBuilder.push(`/${commandInfo.command} - ${commandInfo.name}`); + }); + } else { + helpBuilder.push('此功能没有指令'); + } + helpBuilder.push(''); + } + + if (helpBuilder[helpBuilder.length - 1] === '') { + helpBuilder.pop(); + } + + if (this.app.debug) { + this.app.logger.debug(`收到帮助指令,已找到 ${subscribedControllers.length} 个控制器`); + } + + replyMsg.content = [{ + type: 'text', + data: { + text: helpBuilder.join('\n') + } + }]; + + if (this.app.debug) { + this.app.logger.debug('发送帮助信息'); + } + await replyMsg.send(); + } +} \ No newline at end of file diff --git a/src/controller/TestController.ts b/src/controller/TestController.ts new file mode 100644 index 0000000..e6f8101 --- /dev/null +++ b/src/controller/TestController.ts @@ -0,0 +1,59 @@ +import App from "../App"; +import { PluginController, PluginEvent } from "../PluginManager"; + +export default class TestController implements PluginController { + public event!: PluginEvent; + public app: App; + + public id = 'test'; + public name = '测试功能'; + public description = '测试功能控制器'; + + constructor(app: App) { + this.app = app; + } + + async initialize() { + this.event.init(this); + + this.event.registerCommand({ + command: '写入全局', + name: '写入全局Session', + }, (args, message, resolve) => { + resolve(); + + message.session.global.set('_test', args); + }); + + this.event.registerCommand({ + command: '写入群组', + name: '写入群组Session', + }, (args, message, resolve) => { + resolve(); + + message.session.group.set('_test', args); + }); + + this.event.registerCommand({ + command: '写入对话', + name: '写入对话Session', + }, (args, message, resolve) => { + resolve(); + + message.session.chat.set('_test', args); + }); + + this.event.registerCommand({ + command: '读取', + name: '读取Session', + }, async (args, message, resolve) => { + resolve(); + + let globalSession = await message.session.global.get('_test'); + let groupSession = await message.session.group.get('_test'); + let chatSession = await message.session.chat.get('_test'); + + message.sendReply(`全局Session: ${globalSession}\n群组Session: ${groupSession}\n对话Session: ${chatSession}`); + }); + } +} \ No newline at end of file diff --git a/src/controller/wiki/WikiMisc.ts b/src/controller/wiki/WikiMisc.ts index d1cfd53..c1982fe 100644 --- a/src/controller/wiki/WikiMisc.ts +++ b/src/controller/wiki/WikiMisc.ts @@ -1,4 +1,4 @@ -import request from "request-promise"; +import got from "got"; import App from "../../App"; import { CommonReceivedMessage } from "../../message/Message"; import { PluginEvent } from "../../PluginManager"; @@ -9,10 +9,6 @@ export class WikiMisc { private apiEndpoint: string; - public id = 'sfsettings'; - public name = '科幻设定百科'; - public description = '科幻设定百科的相关功能'; - constructor(app: App, apiEndpoint: string) { this.app = app; this.apiEndpoint = apiEndpoint; @@ -20,19 +16,16 @@ export class WikiMisc { public async handleSearch(args: string, message: CommonReceivedMessage) { try { - let res = await request({ - uri: this.apiEndpoint, - method: 'GET', - qs: { + let res = await got.post(this.apiEndpoint, { + form: { action: 'opensearch', search: args, limit: 10, namespace: 0, format: 'json', formatversion: 2, - }, - json: true, - }); + } + }).json(); if (res.error) { message.sendReply('获取词条列表失败: ' + res.error.info, true); @@ -45,10 +38,8 @@ export class WikiMisc { } // Get page info - res = await request({ - uri: this.apiEndpoint, - method: 'GET', - qs: { + res = await got.post(this.apiEndpoint, { + form: { action: 'query', prop: 'info|extracts', inprop: 'url', @@ -61,8 +52,7 @@ export class WikiMisc { formatversion: 2, titles: titles[0], }, - json: true, - }); + }).json(); if (res.error) { message.sendReply('获取词条详情失败: ' + res.error.info, true); @@ -89,10 +79,8 @@ export class WikiMisc { public async handleRandomPage(args: string, message: CommonReceivedMessage) { try { - let res = await request({ - uri: this.apiEndpoint, - method: 'GET', - qs: { + let res = await got.post(this.apiEndpoint, { + form: { action: 'query', prop: 'info|extracts', inprop: 'url', @@ -106,8 +94,7 @@ export class WikiMisc { format: 'json', formatversion: 2, }, - json: true, - }); + }).json(); if (res.error) { message.sendReply('获取随机页面失败: ' + res.error.info, true); @@ -115,7 +102,7 @@ export class WikiMisc { } if (this.app.debug) { - console.log(res); + this.app.logger.debug('随机页面信息', res); } let pageTitle = res.query.random?.[0]?.title; @@ -124,10 +111,8 @@ export class WikiMisc { return; } // Get page info - res = await request({ - uri: this.apiEndpoint, - method: 'GET', - qs: { + res = await got.post(this.apiEndpoint, { + form: { action: 'query', prop: 'info|extracts', inprop: 'url', @@ -140,8 +125,7 @@ export class WikiMisc { formatversion: 2, titles: pageTitle, }, - json: true, - }); + }).json(); if (res.error) { message.sendReply('获取随机页面失败: ' + res.error.info, true); diff --git a/src/message/Message.ts b/src/message/Message.ts index 3fbb1cb..fab473f 100644 --- a/src/message/Message.ts +++ b/src/message/Message.ts @@ -1,4 +1,5 @@ import { Robot } from "../RobotManager"; +import { SessionStore } from "../SessionManager"; import { BaseSender, GroupSender, UserSender } from "./Sender"; export interface MessageChunk { @@ -215,8 +216,21 @@ export class CommonSendMessage extends CommonMessage { this.targetId = targetId; if (Array.isArray(content)) this.content = content; } + + async send(): Promise { + await this.sender.sendMessage(this); + } } +export type SessionStoreGroup = { + global: SessionStore; + robot: SessionStore; + user: SessionStore; + rootGroup: SessionStore; + group: SessionStore; + chat: SessionStore; +}; + export class CommonReceivedMessage extends CommonMessage { /** 接收时间 */ time: Date = new Date(); @@ -226,6 +240,15 @@ export class CommonReceivedMessage extends CommonMessage { sender: any; /** 接收者是否被提到 */ mentionedReceiver: boolean = false; + /** Session存储 */ + session: SessionStoreGroup = new Proxy({} as any, { + get: (target, p) => { + if (!target[p]) { + target[p] = this.getSession(p as string); + } + return target[p]; + }, + }) as any; constructor(receiver: Robot, messageId?: string) { super(); @@ -234,7 +257,7 @@ export class CommonReceivedMessage extends CommonMessage { this.id = messageId; } - public async sendReply(message: string | MessageChunk[], addReply: boolean = false): Promise { + public createReplyMessage(message?: string | MessageChunk[], addReply: boolean = false) { const sender = this.sender as BaseSender; let newMessage = new CommonSendMessage(this.receiver!, this.origin, sender.targetId); if (typeof message === 'string') { @@ -245,8 +268,6 @@ export class CommonReceivedMessage extends CommonMessage { newMessage.content = msgContent; } else if (Array.isArray(message)) { newMessage.content = message; - } else { - return null; } if (addReply) { @@ -254,10 +275,21 @@ export class CommonReceivedMessage extends CommonMessage { newMessage.repliedMessage = this; } + return newMessage; + } + + public async sendReply(message: string | MessageChunk[], addReply: boolean = false): Promise { + let newMessage = this.createReplyMessage(message, addReply); + if (newMessage.content.length === 0) return null; + newMessage = await this.receiver.sendMessage(newMessage); return newMessage; } + + public getSession(type: string) { + return this.receiver.getSession(this.sender.identity, type); + } } export class CommonPrivateMessage extends CommonReceivedMessage { diff --git a/src/message/Sender.ts b/src/message/Sender.ts index 6b6a526..f2c3048 100644 --- a/src/message/Sender.ts +++ b/src/message/Sender.ts @@ -1,3 +1,5 @@ +import { Robot } from "../RobotManager"; + export type BaseSenderType = "user" | "group" | "channel"; export interface BaseSender { @@ -6,17 +8,31 @@ export interface BaseSender { } export class UserSender implements BaseSender { + public robot: Robot; + public readonly type = "user"; public uid: string; public userName?: string; public nickName?: string; - constructor(uid: string) { + constructor(robot: Robot, uid: string) { + this.robot = robot; this.uid = uid; } - static newAnonymous() { - return new UserSender(''); + static newAnonymous(robot: Robot) { + return new UserSender(robot, ''); + } + + + get identity(): SenderIdentity { + let senderIdentity: SenderIdentity = { + type: 'private', + robot: this.robot, + userId: this.uid, + }; + + return senderIdentity; } get targetId() { @@ -31,19 +47,40 @@ export class UserSender implements BaseSender { export class GroupSender { public readonly type = "group"; + public robot: Robot; + public groupId: string; public groupName?: string; + public rootGroupId?: string; + public rootGroupName?: string; + public uid: string; public userName?: string; public globalNickName?: string; public nickName?: string; - constructor(groupId: string, uid: string) { + constructor(robot: Robot, groupId: string, uid: string) { + this.robot = robot; this.groupId = groupId; this.uid = uid; } + get identity(): SenderIdentity { + let senderIdentity: SenderIdentity = { + type: 'group', + robot: this.robot, + groupId: this.groupId, + userId: this.uid, + }; + + if (this.rootGroupId) { + senderIdentity.rootGroupId = this.rootGroupId; + } + + return senderIdentity; + } + get targetId() { return this.groupId; } @@ -57,10 +94,19 @@ export class GroupSender { } get userSender() { - let sender = new UserSender(this.uid); + let sender = new UserSender(this.robot, this.uid); sender.userName = this.userName; sender.nickName = this.globalNickName; return sender; } +} + +export type SenderIdentity = { + type: 'private' | 'group' | 'channel' | 'raw' | string, + robot: Robot, + rootGroupId?: string, + groupId?: string, + userId?: string, + channelId?: string, } \ No newline at end of file diff --git a/src/module.d.ts b/src/module.d.ts index bc131a2..d320a2f 100644 --- a/src/module.d.ts +++ b/src/module.d.ts @@ -1 +1,2 @@ -declare module 'yaml'; \ No newline at end of file +declare module 'yaml'; +declare module '@waylaidwanderer/chatgpt-api'; \ No newline at end of file diff --git a/src/provider/PusherProvider.ts b/src/provider/PusherProvider.ts index fc1aef8..b56bb17 100644 --- a/src/provider/PusherProvider.ts +++ b/src/provider/PusherProvider.ts @@ -3,8 +3,7 @@ import { BaseProvider, MultipleMessage } from "../base/provider/BaseProvider"; import { ChannelConfig } from "../Config"; import { ConfigCheckError } from "../error/ConfigCheckError"; import PusherService from "../service/PusherService"; - -const { string, optional, object, guard } = require("decoders"); +import { string, optional, object, guard } from "decoders"; export type PusherProviderConfig = { source: { diff --git a/src/robot/QQRobot.ts b/src/robot/QQRobot.ts index 39e6c2d..3b1cbe7 100644 --- a/src/robot/QQRobot.ts +++ b/src/robot/QQRobot.ts @@ -1,15 +1,19 @@ +import koa from "koa"; +import got from "got/dist/source"; + import App from "../App"; import { Robot } from "../RobotManager"; import { Target } from "../SubscribeManager"; -import request from "request-promise"; import { Utils } from "../utils/Utils"; import { FullRestfulContext, RestfulApiManager, RestfulRouter } from "../RestfulApiManager"; -import koa from "koa"; -import { convertMessageToQQChunk, parseQQMessageChunk, QQFaceMessage, QQGroupMessage, QQGroupSender, QQImageMessage, QQPrivateMessage, QQUserSender, QQVoiceMessage } from "./qq/Message"; -import { CommonReceivedMessage, CommonSendMessage, MentionMessage, TextMessage } from "../message/Message"; - -export type QQRobotConfig = { - user: string; +import { convertMessageToQQChunk, parseQQMessageChunk, QQGroupMessage, QQGroupSender, QQPrivateMessage, QQUserSender } from "./qq/Message"; +import { CommonReceivedMessage, CommonSendMessage } from "../message/Message"; +import { PluginController } from "../PluginManager"; +import { RobotConfig } from "../Config"; +import { SenderIdentity } from "../message/Sender"; + +export type QQRobotConfig = RobotConfig & { + uid: string; host: string; command_prefix?: string; } @@ -26,6 +30,7 @@ export default class QQRobot implements Robot { public uid: string; public robotId: string; + public description: string; public commandPrefix: string[] = ['/', '!', '!', '/']; @@ -36,11 +41,15 @@ export default class QQRobot implements Robot { private groupList: QQGroupInfo[] = []; + private messageTypeHandler: Record Promise> = {}; + constructor(app: App, robotId: string, config: QQRobotConfig) { this.app = app; this.robotId = robotId; this.endpoint = 'http://' + config.host; - this.uid = config.user; + this.uid = config.uid.toString(); + + this.description = config.description ?? this.app.config.robot_description ?? 'Isekai Feedbot for QQ'; if (config.command_prefix) { if (Array.isArray(config.command_prefix)) { @@ -49,6 +58,8 @@ export default class QQRobot implements Robot { this.commandPrefix = [config.command_prefix]; } } + + this.messageTypeHandler.help = this.parseHelpMessage.bind(this); } async initialize() { @@ -93,6 +104,44 @@ export default class QQRobot implements Robot { await next(); } + async parseHelpMessage(message: CommonSendMessage) { + const controllers = message.extra.controllers as PluginController[]; + + let helpBuilder: string[] = []; + if (this.description) { + helpBuilder.push(this.description, ''); + } + + helpBuilder.push( + '可用的指令前缀:"' + this.commandPrefix.join('"、"') + '"', + '功能列表:' + ); + const mainCommandPrefix = this.commandPrefix[0]; + + for (let controller of controllers) { + helpBuilder.push(`【${controller.name}】`); + if (controller.event.commandList.length > 0) { + controller.event.commandList.forEach(commandInfo => { + helpBuilder.push(`${mainCommandPrefix}${commandInfo.command} - ${commandInfo.name}`); + }); + } else { + helpBuilder.push('此功能没有指令'); + } + helpBuilder.push(''); + } + + if (helpBuilder[helpBuilder.length - 1] === '') { + helpBuilder.pop(); + } + + message.content = [{ + type: 'text', + data: { + text: helpBuilder.join('\n') + } + }]; + } + /** * 处理消息事件 * @param postData @@ -110,7 +159,7 @@ export default class QQRobot implements Robot { // 处理群消息 let groupInfo = this.groupList.find((info) => info.groupId === postData.group_id); - let groupSender = new QQGroupSender(postData.group_id.toString(), postData.user_id.toString()); + let groupSender = new QQGroupSender(this, postData.group_id.toString(), postData.user_id.toString()); groupSender.groupInfo = groupInfo; groupSender.groupName = groupInfo?.groupName; groupSender.globalNickName = postData.sender?.nickname; @@ -125,7 +174,7 @@ export default class QQRobot implements Robot { message = await parseQQMessageChunk(this, postData.message ?? [], message); } else if (postData.message_type === 'private') { // 处理私聊消息 - let userSender = new QQUserSender(postData.user_id.toString()); + let userSender = new QQUserSender(this, postData.user_id.toString()); userSender.nickName = postData.sender?.nickname; message = new QQPrivateMessage(userSender, this, postData.message_id.toString()); @@ -162,6 +211,11 @@ export default class QQRobot implements Robot { return null; } + getSession(senderIdentity: SenderIdentity, type: string) { + const sessionPath = this.app.robot.getSessionPath(senderIdentity, type); + return this.app.session.getStore(sessionPath); + } + /** * 发送私聊消息 * @param user - QQ号 @@ -206,15 +260,19 @@ export default class QQRobot implements Robot { * @param message */ async sendMessage(message: CommonSendMessage): Promise { + if (message.type in this.messageTypeHandler) { + this.app.logger.debug('[DEBUG] 运行消息类型处理器', message.type); + let newMessage = await this.messageTypeHandler[message.type](message); + if (newMessage) message = newMessage; + } + let msgData = await convertMessageToQQChunk(message); if (message.origin === 'private') { - if (this.app.debug) console.log('[DEBUG] 发送私聊消息', message.targetId, msgData); - + this.app.logger.debug('[DEBUG] 发送私聊消息', message.targetId, msgData); await this.sendToUser(message.targetId, msgData); } else if (message.origin === 'group') { - if (this.app.debug) console.log('[DEBUG] 发送群消息', message.targetId, msgData); - + this.app.logger.debug('[DEBUG] 发送群消息', message.targetId, msgData); await this.sendToGroup(message.targetId, msgData); } @@ -256,12 +314,9 @@ export default class QQRobot implements Robot { * 执行API调用 */ async doApiRequest(method: string, data: any): Promise { - return await request({ - method: 'POST', - uri: this.endpoint + '/' + method, - body: data, - json: true, + return await got.post(this.endpoint + '/' + method, { + json: data, timeout: 10000 - }); + }).json(); } } diff --git a/src/robot/TelegramRobot.ts b/src/robot/TelegramRobot.ts index cd6183b..6f4fa42 100644 --- a/src/robot/TelegramRobot.ts +++ b/src/robot/TelegramRobot.ts @@ -1,26 +1,33 @@ import TelegramBot from "node-telegram-bot-api"; import App from "../App"; +import { RobotConfig } from "../Config"; import { CommonSendMessage } from "../message/Message"; +import { SenderIdentity } from "../message/Sender"; import { CommandInfo } from "../PluginManager"; import { Robot } from "../RobotManager"; import { Target } from "../SubscribeManager"; import { Utils } from "../utils/Utils"; -export type TelegramRobotConfig = { +export type TelegramRobotConfig = RobotConfig & { token: string; - baseId?: string; proxy?: string; } export default class TelegramRobot implements Robot { + private app: App; + public type = 'telegram'; public robotId: string; public uid?: string; + public description: string; private bot: TelegramBot; constructor(app: App, robotId: string, config: TelegramRobotConfig) { + this.app = app; + this.robotId = robotId; + this.description = config.description ?? app.config.robot_description ?? 'Isekai Feedbot for Telegram'; let botOptions: any = { polling: true @@ -70,6 +77,11 @@ export default class TelegramRobot implements Robot { */ } + getSession(senderIdentity: SenderIdentity, type: string) { + const sessionPath = this.app.robot.getSessionPath(senderIdentity, type); + return this.app.session.getStore(sessionPath); + } + /** * 发送群消息 */ diff --git a/src/robot/qq/Message.ts b/src/robot/qq/Message.ts index 1842d46..d17b032 100644 --- a/src/robot/qq/Message.ts +++ b/src/robot/qq/Message.ts @@ -34,8 +34,8 @@ export interface QQUrlMessage extends MessageChunk { } export class QQUserSender extends UserSender { - constructor(uid: string) { - super(uid); + constructor(robot: QQRobot, uid: string) { + super(robot, uid); this.userName = uid; } } @@ -46,13 +46,13 @@ export class QQGroupSender extends GroupSender { public title?: string; public groupInfo?: QQGroupInfo; - constructor(groupId: string, uid: string) { - super(groupId, uid); + constructor(robot: QQRobot, groupId: string, uid: string) { + super(robot, groupId, uid); this.userName = uid; } get userSender() { - let sender = new QQUserSender(this.uid); + let sender = new QQUserSender(this.robot as any, this.uid); sender.userName = this.userName; sender.nickName = this.globalNickName; diff --git a/src/service/HttpQueue.js b/src/service/HttpQueue.js index f06f847..217986d 100644 --- a/src/service/HttpQueue.js +++ b/src/service/HttpQueue.js @@ -1,5 +1,3 @@ -class HttpQueue { +export default class HttpQueue { } - -module.exports = HttpQueue; \ No newline at end of file diff --git a/src/utils/Utils.ts b/src/utils/Utils.ts index 29e60b4..4c34a61 100644 --- a/src/utils/Utils.ts +++ b/src/utils/Utils.ts @@ -1,3 +1,5 @@ +import fs from 'fs'; + export class Utils { static dictJoin(dict: { [key: string]: any }, d1: string = ": ", d2: string = "\n"): string { let lines: string[] = []; @@ -37,4 +39,36 @@ export class Utils { return text; } } + + static compare(a: any, b: any, depth: number = 5): boolean { + if (depth <= 0) return true; + + if (a === b) return true; + if (a === null || b === null) return false; + if (typeof a !== typeof b) return false; + if (typeof a === 'object') { + if (Array.isArray(a) && Array.isArray(b)) { + if (a.length !== b.length) return false; + for (let i = 0; i < a.length; i++) { + if (!this.compare(a[i], b[i], depth - 1)) return false; + } + return true; + } else { + let keys = Object.keys(a); + if (keys.length !== Object.keys(b).length) return false; + for (let i = 0; i < keys.length; i++) { + if (!this.compare(a[keys[i]], b[keys[i]], depth - 1)) return false; + } + return true; + } + } else { + return false; + } + } + + static prepareDir(path: string): void { + if (!fs.existsSync(path)) { + fs.mkdirSync(path, { recursive: true }); + } + } } diff --git a/tsconfig.json b/tsconfig.json index de02cb4..ef5bc90 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -24,9 +24,9 @@ // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */ /* Modules */ - "module": "commonjs", /* Specify what module code is generated. */ + "module": "ES2022", /* Specify what module code is generated. */ "rootDir": "./src", /* Specify the root folder within your source files. */ - // "moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */ + "moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */ // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */