feat: add persistence demo and keyv support

pull/284/head
Travis Fischer 2023-02-01 04:48:36 -06:00
rodzic 21dd9d518f
commit 531e180e3f
7 zmienionych plików z 318 dodań i 658 usunięć

Wyświetl plik

@ -5,7 +5,7 @@ import { ChatGPTAPI } from '../src'
dotenv.config()
/**
* Demo CLI for testing the `onProgress` handler.
* Demo CLI for testing the `onProgress` streaming support.
*
* ```
* npx tsx demos/demo-on-progress.ts

Wyświetl plik

@ -0,0 +1,72 @@
import KeyvRedis from '@keyv/redis'
import dotenv from 'dotenv-safe'
import Keyv from 'keyv'
import { oraPromise } from 'ora'
import { ChatGPTAPI, type ChatMessage } from '../src'
dotenv.config()
/**
* Demo CLI for testing message persistence with redis.
*
* ```
* npx tsx demos/demo-persistence.ts
* ```
*/
async function main() {
const redisUrl = process.env.REDIS_URL || 'redis://localhost:6379'
const store = new KeyvRedis(redisUrl)
const messageStore = new Keyv({ store, namespace: 'chatgpt-demo' })
let res: ChatMessage
{
// create an initial conversation in one client
const api = new ChatGPTAPI({
apiKey: process.env.OPENAI_API_KEY,
messageStore
})
const prompt = 'What are the top 5 anime of all time?'
res = await oraPromise(api.sendMessage(prompt), {
text: prompt
})
console.log('\n' + res.text + '\n')
}
{
// follow up with a second client using the same underlying redis store
const api = new ChatGPTAPI({
apiKey: process.env.OPENAI_API_KEY,
messageStore
})
const prompt = 'Can you give 5 more?'
res = await oraPromise(
api.sendMessage(prompt, {
conversationId: res.conversationId,
parentMessageId: res.id
}),
{
text: prompt
}
)
console.log('\n' + res.text + '\n')
}
// wait for redis to finish and then disconnect
await new Promise<void>((resolve) => {
setTimeout(() => {
messageStore.disconnect()
resolve()
}, 1000)
})
}
main().catch((err) => {
console.error(err)
process.exit(1)
})

Wyświetl plik

@ -37,15 +37,16 @@
"dependencies": {
"eventsource-parser": "^0.0.5",
"gpt-3-encoder": "^1.1.4",
"keyv": "^4.5.2",
"p-timeout": "^6.0.0",
"quick-lru": "^6.1.1",
"uuid": "^9.0.0"
},
"devDependencies": {
"@keyv/redis": "^2.5.4",
"@trivago/prettier-plugin-sort-imports": "^4.0.0",
"@types/node": "^18.11.9",
"@types/uuid": "^9.0.0",
"ava": "^5.1.0",
"del-cli": "^5.0.0",
"dotenv-safe": "^8.2.0",
"husky": "^8.0.2",
@ -64,14 +65,6 @@
"prettier --write"
]
},
"ava": {
"extensions": {
"ts": "module"
},
"nodeArguments": [
"--loader=tsx"
]
},
"keywords": [
"openai",
"chatgpt",

Wyświetl plik

@ -1,15 +1,16 @@
lockfileVersion: 5.4
specifiers:
'@keyv/redis': ^2.5.4
'@trivago/prettier-plugin-sort-imports': ^4.0.0
'@types/node': ^18.11.9
'@types/uuid': ^9.0.0
ava: ^5.1.0
del-cli: ^5.0.0
dotenv-safe: ^8.2.0
eventsource-parser: ^0.0.5
gpt-3-encoder: ^1.1.4
husky: ^8.0.2
keyv: ^4.5.2
lint-staged: ^13.0.3
npm-run-all: ^4.1.5
ora: ^6.1.2
@ -26,15 +27,16 @@ specifiers:
dependencies:
eventsource-parser: 0.0.5
gpt-3-encoder: 1.1.4
keyv: 4.5.2
p-timeout: 6.1.0
quick-lru: 6.1.1
uuid: 9.0.0
devDependencies:
'@keyv/redis': 2.5.4
'@trivago/prettier-plugin-sort-imports': 4.0.0_prettier@2.8.3
'@types/node': 18.11.18
'@types/uuid': 9.0.0
ava: 5.1.1
del-cli: 5.0.0
dotenv-safe: 8.2.0
husky: 8.0.3
@ -334,6 +336,10 @@ packages:
dev: true
optional: true
/@ioredis/commands/1.2.0:
resolution: {integrity: sha512-Sx1pU8EM64o2BrqNpEO1CNLtKQwyhuXuqyfH7oGKCk+1a33d2r5saW8zNwm3j6BTExtjrv2BxTgzzkMwts6vGg==}
dev: true
/@jridgewell/gen-mapping/0.1.1:
resolution: {integrity: sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==}
engines: {node: '>=6.0.0'}
@ -372,6 +378,15 @@ packages:
'@jridgewell/sourcemap-codec': 1.4.14
dev: true
/@keyv/redis/2.5.4:
resolution: {integrity: sha512-27MTiJFME3R13fPiiOV/ww550gU9Zc75eJkzD+EpwRXcgunjcXcYEw1cM9XyaEI5y0aS1PPknRjKGlYRjT8nTQ==}
engines: {node: '>= 12'}
dependencies:
ioredis: 5.3.0
transitivePeerDependencies:
- supports-color
dev: true
/@nodelib/fs.scandir/2.1.5:
resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==}
engines: {node: '>= 8'}
@ -427,17 +442,6 @@ packages:
resolution: {integrity: sha512-kr90f+ERiQtKWMz5rP32ltJ/BtULDI5RVO0uavn1HQUOwjx0R1h0rnDYNL0CepF1zL5bSY6FISAfd9tOdDhU5Q==}
dev: true
/acorn-walk/8.2.0:
resolution: {integrity: sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==}
engines: {node: '>=0.4.0'}
dev: true
/acorn/8.8.2:
resolution: {integrity: sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==}
engines: {node: '>=0.4.0'}
hasBin: true
dev: true
/aggregate-error/3.1.0:
resolution: {integrity: sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==}
engines: {node: '>=8'}
@ -502,101 +506,21 @@ packages:
picomatch: 2.3.1
dev: true
/argparse/1.0.10:
resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==}
dependencies:
sprintf-js: 1.0.3
dev: true
/array-find-index/1.0.2:
resolution: {integrity: sha512-M1HQyIXcBGtVywBt8WVdim+lrNaK7VHp99Qt5pSNziXznKHViIBbXWtfRTpEFpF/c4FdfxNAsCCwPp5phBYJtw==}
engines: {node: '>=0.10.0'}
dev: true
/array-union/2.1.0:
resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==}
engines: {node: '>=8'}
dev: true
/arrgv/1.0.2:
resolution: {integrity: sha512-a4eg4yhp7mmruZDQFqVMlxNRFGi/i1r87pt8SDHy0/I8PqSXoUTlWZRdAZo0VXgvEARcujbtTk8kiZRi1uDGRw==}
engines: {node: '>=8.0.0'}
dev: true
/arrify/1.0.1:
resolution: {integrity: sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==}
engines: {node: '>=0.10.0'}
dev: true
/arrify/3.0.0:
resolution: {integrity: sha512-tLkvA81vQG/XqE2mjDkGQHoOINtMHtysSnemrmoGe6PydDPMRbVugqyk4A6V/WDWEfm3l+0d8anA9r8cv/5Jaw==}
engines: {node: '>=12'}
dev: true
/astral-regex/2.0.0:
resolution: {integrity: sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==}
engines: {node: '>=8'}
dev: true
/ava/5.1.1:
resolution: {integrity: sha512-od1CWgWVIKZSdEc1dhQWhbsd6KBs0EYjek7eqZNGPvy+NyC9Q1bXixcadlgOXwDG9aM0zLMQZwRXfe9gMb1LQQ==}
engines: {node: '>=14.19 <15 || >=16.15 <17 || >=18'}
hasBin: true
peerDependencies:
'@ava/typescript': '*'
peerDependenciesMeta:
'@ava/typescript':
optional: true
dependencies:
acorn: 8.8.2
acorn-walk: 8.2.0
ansi-styles: 6.2.1
arrgv: 1.0.2
arrify: 3.0.0
callsites: 4.0.0
cbor: 8.1.0
chalk: 5.2.0
chokidar: 3.5.3
chunkd: 2.0.1
ci-info: 3.7.1
ci-parallel-vars: 1.0.1
clean-yaml-object: 0.1.0
cli-truncate: 3.1.0
code-excerpt: 4.0.0
common-path-prefix: 3.0.0
concordance: 5.0.4
currently-unhandled: 0.4.1
debug: 4.3.4
del: 7.0.0
emittery: 1.0.1
figures: 5.0.0
globby: 13.1.3
ignore-by-default: 2.1.0
indent-string: 5.0.0
is-error: 2.2.2
is-plain-object: 5.0.0
is-promise: 4.0.0
matcher: 5.0.0
mem: 9.0.2
ms: 2.1.3
p-event: 5.0.1
p-map: 5.5.0
picomatch: 2.3.1
pkg-conf: 4.0.0
plur: 5.1.0
pretty-ms: 8.0.0
resolve-cwd: 3.0.0
slash: 3.0.0
stack-utils: 2.0.6
strip-ansi: 7.0.1
supertap: 3.0.1
temp-dir: 3.0.0
write-file-atomic: 5.0.0
yargs: 17.6.2
transitivePeerDependencies:
- supports-color
dev: true
/available-typed-arrays/1.0.5:
resolution: {integrity: sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==}
engines: {node: '>= 0.4'}
@ -623,10 +547,6 @@ packages:
readable-stream: 3.6.0
dev: true
/blueimp-md5/2.19.0:
resolution: {integrity: sha512-DRQrD6gJyy8FbiE4s+bDoXS9hiW3Vbx5uCdwvcCf3zLHL+Iv7LtGHLpr+GZV8rHG8tK766FGYBwRbu8pELTt+w==}
dev: true
/brace-expansion/1.1.11:
resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==}
dependencies:
@ -691,11 +611,6 @@ packages:
get-intrinsic: 1.2.0
dev: true
/callsites/4.0.0:
resolution: {integrity: sha512-y3jRROutgpKdz5vzEhWM34TidDU8vkJppF8dszITeb1PQmSqV3DTxyV8G/lyO/DNvtE1YTedehmw9MPZsCBHxQ==}
engines: {node: '>=12.20'}
dev: true
/camelcase-keys/7.0.2:
resolution: {integrity: sha512-Rjs1H+A9R+Ig+4E/9oyB66UC5Mj9Xq3N//vcLf2WzgdTi/3gUu3Z9KoqmlrEG4VuuLK8wJHofxzdQXz/knhiYg==}
engines: {node: '>=12'}
@ -715,13 +630,6 @@ packages:
resolution: {integrity: sha512-qMBmvmQmFXaSxexkjjfMvD5rnDL0+m+dUMZKoDYsGG8iZN29RuYh9eRoMvKsT6uMAWlyUUGDEQGJJYjzCIO9ew==}
dev: true
/cbor/8.1.0:
resolution: {integrity: sha512-DwGjNW9omn6EwP70aXsn7FQJx5kO12tX0bZkaTjzdVFM6/7nhA4t0EENocKGx6D2Bch9PE2KzCUf5SceBdeijg==}
engines: {node: '>=12.19'}
dependencies:
nofilter: 3.1.0
dev: true
/chalk/2.4.2:
resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==}
engines: {node: '>=4'}
@ -751,19 +659,6 @@ packages:
fsevents: 2.3.2
dev: true
/chunkd/2.0.1:
resolution: {integrity: sha512-7d58XsFmOq0j6el67Ug9mHf9ELUXsQXYJBkyxhH/k+6Ke0qXRnv0kbemx+Twc6fRJ07C49lcbdgm9FL1Ei/6SQ==}
dev: true
/ci-info/3.7.1:
resolution: {integrity: sha512-4jYS4MOAaCIStSRwiuxc4B8MYhIe676yO1sYGzARnjXkWpmzZMMYxY6zu8WYWDhSuth5zhrQ1rhNSibyyvv4/w==}
engines: {node: '>=8'}
dev: true
/ci-parallel-vars/1.0.1:
resolution: {integrity: sha512-uvzpYrpmidaoxvIQHM+rKSrigjOe9feHYbw4uOI2gdfe1C3xIlxO+kVXq83WQWNniTf8bAxVpy+cQeFQsMERKg==}
dev: true
/clean-stack/2.2.0:
resolution: {integrity: sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==}
engines: {node: '>=6'}
@ -776,11 +671,6 @@ packages:
escape-string-regexp: 5.0.0
dev: true
/clean-yaml-object/0.1.0:
resolution: {integrity: sha512-3yONmlN9CSAkzNwnRCiJQ7Q2xK5mWuEfL3PuTZcAUzhObbXsfsnMptJzXwz93nc5zn9V9TwCVMmV7w4xsm43dw==}
engines: {node: '>=0.10.0'}
dev: true
/cli-cursor/3.1.0:
resolution: {integrity: sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==}
engines: {node: '>=8'}
@ -816,25 +706,14 @@ packages:
string-width: 5.1.2
dev: true
/cliui/8.0.1:
resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==}
engines: {node: '>=12'}
dependencies:
string-width: 4.2.3
strip-ansi: 6.0.1
wrap-ansi: 7.0.0
dev: true
/clone/1.0.4:
resolution: {integrity: sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==}
engines: {node: '>=0.8'}
dev: true
/code-excerpt/4.0.0:
resolution: {integrity: sha512-xxodCmBen3iy2i0WtAK8FlFNrRzjUqjRsMfho58xT/wvZU1YTM3fCnRjcy1gJPMepaRlgm/0e6w8SpWHpn3/cA==}
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
dependencies:
convert-to-spaces: 2.0.1
/cluster-key-slot/1.1.2:
resolution: {integrity: sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==}
engines: {node: '>=0.10.0'}
dev: true
/color-convert/1.9.3:
@ -872,37 +751,14 @@ packages:
engines: {node: ^12.20.0 || >=14}
dev: true
/common-path-prefix/3.0.0:
resolution: {integrity: sha512-QE33hToZseCH3jS0qN96O/bSh3kaw/h+Tq7ngyY9eWDUnTlTNUyqfqvCXioLe5Na5jFsL78ra/wuBU4iuEgd4w==}
dev: true
/concat-map/0.0.1:
resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==}
dev: true
/concordance/5.0.4:
resolution: {integrity: sha512-OAcsnTEYu1ARJqWVGwf4zh4JDfHZEaSNlNccFmt8YjB2l/n19/PF2viLINHc57vO4FKIAFl2FWASIGZZWZ2Kxw==}
engines: {node: '>=10.18.0 <11 || >=12.14.0 <13 || >=14'}
dependencies:
date-time: 3.1.0
esutils: 2.0.3
fast-diff: 1.2.0
js-string-escape: 1.0.1
lodash: 4.17.21
md5-hex: 3.0.1
semver: 7.3.8
well-known-symbols: 2.0.0
dev: true
/convert-source-map/1.9.0:
resolution: {integrity: sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==}
dev: true
/convert-to-spaces/2.0.1:
resolution: {integrity: sha512-rcQ1bsQO9799wq24uE5AM2tAILy4gXGIK/njFWcVQkGNZ96edlpY+A7bjwvzjYvLDyzmG1MmMLZhpcsb+klNMQ==}
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
dev: true
/cross-spawn/6.0.5:
resolution: {integrity: sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==}
engines: {node: '>=4.8'}
@ -923,20 +779,6 @@ packages:
which: 2.0.2
dev: true
/currently-unhandled/0.4.1:
resolution: {integrity: sha512-/fITjgjGU50vjQ4FH6eUoYu+iUoUKIXws2hL15JJpIR+BbTxaXQsMuuyjtNh2WqsSBS5nsaZHFsFecyw5CCAng==}
engines: {node: '>=0.10.0'}
dependencies:
array-find-index: 1.0.2
dev: true
/date-time/3.1.0:
resolution: {integrity: sha512-uqCUKXE5q1PNBXjPqvwhwJf9SwMoAHBgWJ6DcrnS5o+W2JOiIILl0JEdVD8SGujrNS02GGxgwAg2PN2zONgtjg==}
engines: {node: '>=6'}
dependencies:
time-zone: 1.0.0
dev: true
/debug/4.3.4:
resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==}
engines: {node: '>=6.0'}
@ -1004,6 +846,11 @@ packages:
slash: 4.0.0
dev: true
/denque/2.1.0:
resolution: {integrity: sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==}
engines: {node: '>=0.10'}
dev: true
/dir-glob/3.0.1:
resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==}
engines: {node: '>=8'}
@ -1030,11 +877,6 @@ packages:
resolution: {integrity: sha512-M8WEXFuKXMYMVr45fo8mq0wUrrJHheiKZf6BArTKk9ZBYCKJEOU5H8cdWgDT+qCVZf7Na4lVUaZsA+h6uA9+PA==}
dev: true
/emittery/1.0.1:
resolution: {integrity: sha512-2ID6FdrMD9KDLldGesP6317G78K7km/kMcwItRtVFva7I/cSEOIaLpewaUb+YLXVwdAp3Ctfxh/V5zIl1sj7dQ==}
engines: {node: '>=14.16'}
dev: true
/emoji-regex/8.0.0:
resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==}
dev: true
@ -1326,27 +1168,11 @@ packages:
engines: {node: '>=0.8.0'}
dev: true
/escape-string-regexp/2.0.0:
resolution: {integrity: sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==}
engines: {node: '>=8'}
dev: true
/escape-string-regexp/5.0.0:
resolution: {integrity: sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==}
engines: {node: '>=12'}
dev: true
/esprima/4.0.1:
resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==}
engines: {node: '>=4'}
hasBin: true
dev: true
/esutils/2.0.3:
resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==}
engines: {node: '>=0.10.0'}
dev: true
/eventsource-parser/0.0.5:
resolution: {integrity: sha512-BAq82bC3ZW9fPYYZlofXBOAfbpmDzXIOsj+GOehQwgTUYsQZ6HtHs6zuRtge7Ph8OhS6lNH1kJF8q9dj17RcmA==}
engines: {node: '>=12'}
@ -1382,10 +1208,6 @@ packages:
strip-final-newline: 3.0.0
dev: true
/fast-diff/1.2.0:
resolution: {integrity: sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==}
dev: true
/fast-glob/3.2.12:
resolution: {integrity: sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==}
engines: {node: '>=8.6.0'}
@ -1403,14 +1225,6 @@ packages:
reusify: 1.0.4
dev: true
/figures/5.0.0:
resolution: {integrity: sha512-ej8ksPF4x6e5wvK9yevct0UCXh8TTFlWGVLlgjZuoBH1HwjIfKE/IdL5mq89sFA7zELi1VhKpmtDnrs7zWyeyg==}
engines: {node: '>=14'}
dependencies:
escape-string-regexp: 5.0.0
is-unicode-supported: 1.3.0
dev: true
/fill-range/7.0.1:
resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==}
engines: {node: '>=8'}
@ -1426,14 +1240,6 @@ packages:
path-exists: 4.0.0
dev: true
/find-up/6.3.0:
resolution: {integrity: sha512-v2ZsoEuVHYy8ZIlYqwPe/39Cy+cFDzp4dXPaxNvkEuouymu+2Jbz0PxpKarJHYJTmv2HWT3O382qY8l4jMWthw==}
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
dependencies:
locate-path: 7.1.1
path-exists: 5.0.0
dev: true
/for-each/0.3.3:
resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==}
dependencies:
@ -1475,11 +1281,6 @@ packages:
engines: {node: '>=6.9.0'}
dev: true
/get-caller-file/2.0.5:
resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==}
engines: {node: 6.* || 8.* || >= 10.*}
dev: true
/get-intrinsic/1.2.0:
resolution: {integrity: sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q==}
dependencies:
@ -1671,21 +1472,11 @@ packages:
resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==}
dev: true
/ignore-by-default/2.1.0:
resolution: {integrity: sha512-yiWd4GVmJp0Q6ghmM2B/V3oZGRmjrKLXvHR3TE1nfoXsmoggllfZUQe74EN0fJdPFZu2NIvNdrMMLm3OsV7Ohw==}
engines: {node: '>=10 <11 || >=12 <13 || >=14'}
dev: true
/ignore/5.2.4:
resolution: {integrity: sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==}
engines: {node: '>= 4'}
dev: true
/imurmurhash/0.1.4:
resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==}
engines: {node: '>=0.8.19'}
dev: true
/indent-string/4.0.0:
resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==}
engines: {node: '>=8'}
@ -1716,9 +1507,21 @@ packages:
side-channel: 1.0.4
dev: true
/irregular-plurals/3.4.0:
resolution: {integrity: sha512-YXxECO/W6N9aMBVKMKKZ8TXESgq7EFrp3emCGGUcrYY1cgJIeZjoB75MTu8qi+NAKntS9NwPU8VdcQ3r6E6aWQ==}
engines: {node: '>=8'}
/ioredis/5.3.0:
resolution: {integrity: sha512-Id9jKHhsILuIZpHc61QkagfVdUj2Rag5GzG1TGEvRNeM7dtTOjICgjC+tvqYxi//PuX2wjQ+Xjva2ONBuf92Pw==}
engines: {node: '>=12.22.0'}
dependencies:
'@ioredis/commands': 1.2.0
cluster-key-slot: 1.1.2
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
transitivePeerDependencies:
- supports-color
dev: true
/is-array-buffer/3.0.1:
@ -1772,10 +1575,6 @@ packages:
has-tostringtag: 1.0.0
dev: true
/is-error/2.2.2:
resolution: {integrity: sha512-IOQqts/aHWbiisY5DuPJQ0gcbvaLFCa7fBa9xoLfxBZvQ+ZI/Zh9xoI7Gk+G64N0FdK4AbibytHht2tWgpJWLg==}
dev: true
/is-extglob/2.1.1:
resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==}
engines: {node: '>=0.10.0'}
@ -1835,15 +1634,6 @@ packages:
engines: {node: '>=0.10.0'}
dev: true
/is-plain-object/5.0.0:
resolution: {integrity: sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==}
engines: {node: '>=0.10.0'}
dev: true
/is-promise/4.0.0:
resolution: {integrity: sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==}
dev: true
/is-regex/1.1.4:
resolution: {integrity: sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==}
engines: {node: '>= 0.4'}
@ -1917,29 +1707,20 @@ packages:
engines: {node: '>=10'}
dev: true
/js-string-escape/1.0.1:
resolution: {integrity: sha512-Smw4xcfIQ5LVjAOuJCvN/zIodzA/BBSsluuoSykP+lUvScIi4U6RJLfwHet5cxFnCswUjISV8oAXaqaJDY3chg==}
engines: {node: '>= 0.8'}
dev: true
/js-tokens/4.0.0:
resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
dev: true
/js-yaml/3.14.1:
resolution: {integrity: sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==}
hasBin: true
dependencies:
argparse: 1.0.10
esprima: 4.0.1
dev: true
/jsesc/2.5.2:
resolution: {integrity: sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==}
engines: {node: '>=4'}
hasBin: true
dev: true
/json-buffer/3.0.1:
resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==}
dev: false
/json-parse-better-errors/1.0.2:
resolution: {integrity: sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==}
dev: true
@ -1958,6 +1739,12 @@ packages:
resolution: {integrity: sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==}
dev: true
/keyv/4.5.2:
resolution: {integrity: sha512-5MHbFaKn8cNSmVW7BYnijeAVlE4cYA/SVkifVgrh7yotnfhKmjuXpDKjrABLnT0SfHWV21P8ow07OGfRrNDg8g==}
dependencies:
json-buffer: 3.0.1
dev: false
/kind-of/6.0.3:
resolution: {integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==}
engines: {node: '>=0.10.0'}
@ -2024,11 +1811,6 @@ packages:
strip-bom: 3.0.0
dev: true
/load-json-file/7.0.1:
resolution: {integrity: sha512-Gnxj3ev3mB5TkVBGad0JM6dmLiQL+o0t23JPBZ9sd+yvSLk05mFoqKBw5N8gbbkU4TNXyqCgIrl/VM17OgUIgQ==}
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
dev: true
/load-tsconfig/0.2.3:
resolution: {integrity: sha512-iyT2MXws+dc2Wi6o3grCFtGXpeMvHmJqS27sMPGtV2eUu4PeFnG+33I8BlFK1t1NWMjOpcx9bridn5yxLDX2gQ==}
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
@ -2041,11 +1823,12 @@ packages:
p-locate: 5.0.0
dev: true
/locate-path/7.1.1:
resolution: {integrity: sha512-vJXaRMJgRVD3+cUZs3Mncj2mxpt5mP0EmNOsxRSZRMlbqjvxzDEOIUWXGmavo0ZC9+tNZCBLQ66reA11nbpHZg==}
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
dependencies:
p-locate: 6.0.0
/lodash.defaults/4.2.0:
resolution: {integrity: sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==}
dev: true
/lodash.isarguments/3.1.0:
resolution: {integrity: sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg==}
dev: true
/lodash.sortby/4.7.0:
@ -2091,13 +1874,6 @@ packages:
resolution: {integrity: sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow==}
dev: true
/map-age-cleaner/0.1.3:
resolution: {integrity: sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w==}
engines: {node: '>=6'}
dependencies:
p-defer: 1.0.0
dev: true
/map-obj/1.0.1:
resolution: {integrity: sha512-7N/q3lyZ+LVCp7PzuxrJr4KMbBE2hW7BT7YNia330OFxIf4d3r5zVpicP2650l7CPN6RM9zOJRl3NGpqSiw3Eg==}
engines: {node: '>=0.10.0'}
@ -2114,28 +1890,6 @@ packages:
hasBin: true
dev: true
/matcher/5.0.0:
resolution: {integrity: sha512-s2EMBOWtXFc8dgqvoAzKJXxNHibcdJMV0gwqKUaw9E2JBJuGUK7DrNKrA6g/i+v72TT16+6sVm5mS3thaMLQUw==}
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
dependencies:
escape-string-regexp: 5.0.0
dev: true
/md5-hex/3.0.1:
resolution: {integrity: sha512-BUiRtTtV39LIJwinWBjqVsU9xhdnz7/i889V859IBFpuqGAj6LuOvHv5XLbgZ2R7ptJoJaEcxkv88/h25T7Ciw==}
engines: {node: '>=8'}
dependencies:
blueimp-md5: 2.19.0
dev: true
/mem/9.0.2:
resolution: {integrity: sha512-F2t4YIv9XQUBHt6AOJ0y7lSmP1+cY7Fm1DRh9GClTGzKST7UWLMx6ly9WZdLH/G/ppM5RL4MlQfRT71ri9t19A==}
engines: {node: '>=12.20'}
dependencies:
map-age-cleaner: 0.1.3
mimic-fn: 4.0.0
dev: true
/memorystream/0.3.1:
resolution: {integrity: sha512-S3UwM3yj5mtUSEfP41UZmt/0SCoVYUcU1rkXv+BQ5Ig8ndL4sPoJNBUJERafdPb5jjHJGuMgytgKvKIf58XNBw==}
engines: {node: '>= 0.10.0'}
@ -2221,10 +1975,6 @@ packages:
resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==}
dev: true
/ms/2.1.3:
resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
dev: true
/mz/2.7.0:
resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==}
dependencies:
@ -2245,11 +1995,6 @@ packages:
resolution: {integrity: sha512-2xfmOrRkGogbTK9R6Leda0DGiXeY3p2NJpy4+gNCffdUvV6mdEJnaDEic1i3Ec2djAo8jWYoJMR5PB0MSMpxUA==}
dev: true
/nofilter/3.1.0:
resolution: {integrity: sha512-l2NNj07e9afPnhAhvgVrCD/oy2Ai1yfLpuo3EpiO1jFTsB4sFz6oIfAfSZyQzVpkZQ9xS8ZS5g1jCBgq4Hwo0g==}
engines: {node: '>=12.19'}
dev: true
/normalize-package-data/2.5.0:
resolution: {integrity: sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==}
dependencies:
@ -2363,18 +2108,6 @@ packages:
wcwidth: 1.0.1
dev: true
/p-defer/1.0.0:
resolution: {integrity: sha512-wB3wfAxZpk2AzOfUMJNL+d36xothRSyj8EXOa4f6GMqYDN9BJaaSISbsk+wS9abmnebVw95C2Kb5t85UmpCxuw==}
engines: {node: '>=4'}
dev: true
/p-event/5.0.1:
resolution: {integrity: sha512-dd589iCQ7m1L0bmC5NLlVYfy3TbBEsMUfWx9PyAgPeIcFZ/E2yaTZ4Rz4MiBmmJShviiftHVXOqfnfzJ6kyMrQ==}
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
dependencies:
p-timeout: 5.1.0
dev: true
/p-limit/3.1.0:
resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==}
engines: {node: '>=10'}
@ -2382,13 +2115,6 @@ packages:
yocto-queue: 0.1.0
dev: true
/p-limit/4.0.0:
resolution: {integrity: sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==}
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
dependencies:
yocto-queue: 1.0.0
dev: true
/p-locate/5.0.0:
resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==}
engines: {node: '>=10'}
@ -2396,13 +2122,6 @@ packages:
p-limit: 3.1.0
dev: true
/p-locate/6.0.0:
resolution: {integrity: sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw==}
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
dependencies:
p-limit: 4.0.0
dev: true
/p-map/4.0.0:
resolution: {integrity: sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==}
engines: {node: '>=10'}
@ -2417,11 +2136,6 @@ packages:
aggregate-error: 4.0.1
dev: true
/p-timeout/5.1.0:
resolution: {integrity: sha512-auFDyzzzGZZZdHz3BtET9VEz0SE/uMEAx7uWfGPucfzEwwe/xH0iVeZibQmANYE/hp9T2+UUZT5m+BKyrDp3Ew==}
engines: {node: '>=12'}
dev: true
/p-timeout/6.1.0:
resolution: {integrity: sha512-s0y6Le9QYGELLzNpFIt6h8B2DHTVUDLStvxtvRMSKNKeuNVVWby2dZ+pIJpW4/pWr5a3s8W85wBNtc0ZA+lzCg==}
engines: {node: '>=14.16'}
@ -2445,21 +2159,11 @@ packages:
lines-and-columns: 1.2.4
dev: true
/parse-ms/3.0.0:
resolution: {integrity: sha512-Tpb8Z7r7XbbtBTrM9UhpkzzaMrqA2VXMT3YChzYltwV3P3pM6t8wl7TvpMnSTosz1aQAdVib7kdoys7vYOPerw==}
engines: {node: '>=12'}
dev: true
/path-exists/4.0.0:
resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==}
engines: {node: '>=8'}
dev: true
/path-exists/5.0.0:
resolution: {integrity: sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==}
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
dev: true
/path-is-absolute/1.0.1:
resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==}
engines: {node: '>=0.10.0'}
@ -2527,21 +2231,6 @@ packages:
engines: {node: '>= 6'}
dev: true
/pkg-conf/4.0.0:
resolution: {integrity: sha512-7dmgi4UY4qk+4mj5Cd8v/GExPo0K+SlY+hulOSdfZ/T6jVH6//y7NtzZo5WrfhDBxuQ0jCa7fLZmNaNh7EWL/w==}
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
dependencies:
find-up: 6.3.0
load-json-file: 7.0.1
dev: true
/plur/5.1.0:
resolution: {integrity: sha512-VP/72JeXqak2KiOzjgKtQen5y3IZHn+9GOuLDafPv0eXa47xq0At93XahYBs26MsifCQ4enGKwbjBTKgb9QJXg==}
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
dependencies:
irregular-plurals: 3.4.0
dev: true
/postcss-load-config/3.1.4:
resolution: {integrity: sha512-6DiM4E7v4coTE4uzA8U//WhtPwyhiim3eyjEMFCnUpzbrkK9wJHgKDT2mR+HbtSrd/NubVaYTOpSpjUl8NQeRg==}
engines: {node: '>= 10'}
@ -2564,13 +2253,6 @@ packages:
hasBin: true
dev: true
/pretty-ms/8.0.0:
resolution: {integrity: sha512-ASJqOugUF1bbzI35STMBUpZqdfYKlJugy6JBziGi2EE+AL5JPJGSzvpeVXojxrr0ViUYoToUjb5kjSEGf7Y83Q==}
engines: {node: '>=14.16'}
dependencies:
parse-ms: 3.0.0
dev: true
/punycode/2.3.0:
resolution: {integrity: sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==}
engines: {node: '>=6'}
@ -2642,6 +2324,18 @@ packages:
strip-indent: 4.0.0
dev: true
/redis-errors/1.2.0:
resolution: {integrity: sha512-1qny3OExCf0UvUV/5wpYKf2YwPcOqXzkwKKSmKHiE6ZMQs5heeE/c8eXK+PNllPvmjgAbfnsbpkGZWy8cBpn9w==}
engines: {node: '>=4'}
dev: true
/redis-parser/3.0.0:
resolution: {integrity: sha512-DJnGAeenTdpMEH6uAJRK/uiyEIH9WVsUmoLwzudwGJUwZPp80PDBWPHXSAGNPwNvIXAbe7MSUB1zQFugFml66A==}
engines: {node: '>=4'}
dependencies:
redis-errors: 1.2.0
dev: true
/regexp.prototype.flags/1.4.3:
resolution: {integrity: sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA==}
engines: {node: '>= 0.4'}
@ -2651,18 +2345,6 @@ packages:
functions-have-names: 1.2.3
dev: true
/require-directory/2.1.1:
resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==}
engines: {node: '>=0.10.0'}
dev: true
/resolve-cwd/3.0.0:
resolution: {integrity: sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==}
engines: {node: '>=8'}
dependencies:
resolve-from: 5.0.0
dev: true
/resolve-from/5.0.0:
resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==}
engines: {node: '>=8'}
@ -2759,13 +2441,6 @@ packages:
lru-cache: 6.0.0
dev: true
/serialize-error/7.0.1:
resolution: {integrity: sha512-8I8TjW5KMOKsZQTvoxjuSIa7foAwPWGOts+6o7sgjz41/qMD9VQHEDxi6PBvK2l0MXUmqZyNpUK+T2tQaaElvw==}
engines: {node: '>=10'}
dependencies:
type-fest: 0.13.1
dev: true
/shebang-command/1.2.0:
resolution: {integrity: sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==}
engines: {node: '>=0.10.0'}
@ -2896,15 +2571,8 @@ packages:
resolution: {integrity: sha512-rr+VVSXtRhO4OHbXUiAF7xW3Bo9DuuF6C5jH+q/x15j2jniycgKbxU09Hr0WqlSLUs4i4ltHGXqTe7VHclYWyA==}
dev: true
/sprintf-js/1.0.3:
resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==}
dev: true
/stack-utils/2.0.6:
resolution: {integrity: sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==}
engines: {node: '>=10'}
dependencies:
escape-string-regexp: 2.0.0
/standard-as-callback/2.1.0:
resolution: {integrity: sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A==}
dev: true
/string-argv/0.3.1:
@ -3010,16 +2678,6 @@ packages:
ts-interface-checker: 0.1.13
dev: true
/supertap/3.0.1:
resolution: {integrity: sha512-u1ZpIBCawJnO+0QePsEiOknOfCRq0yERxiAchT0i4li0WHNUJbf0evXXSXOcCAR4M8iMDoajXYmstm/qO81Isw==}
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
dependencies:
indent-string: 5.0.0
js-yaml: 3.14.1
serialize-error: 7.0.1
strip-ansi: 7.0.1
dev: true
/supports-color/5.5.0:
resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==}
engines: {node: '>=4'}
@ -3032,11 +2690,6 @@ packages:
engines: {node: '>= 0.4'}
dev: true
/temp-dir/3.0.0:
resolution: {integrity: sha512-nHc6S/bwIilKHNRgK/3jlhDoIHcp45YgyiwcAk46Tr0LfEqGBVpmiAyuiuxeVE44m3mXnEeVhaipLOEWmH+Njw==}
engines: {node: '>=14.16'}
dev: true
/thenify-all/1.6.0:
resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==}
engines: {node: '>=0.8'}
@ -3054,11 +2707,6 @@ packages:
resolution: {integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==}
dev: true
/time-zone/1.0.0:
resolution: {integrity: sha512-TIsDdtKo6+XrPtiTm1ssmMngN1sAhyKnTO2kunQWqNPWIVvCm15Wmw4SWInwTVgJ5u/Tr04+8Ei9TNcw4x4ONA==}
engines: {node: '>=4'}
dev: true
/to-fast-properties/2.0.0:
resolution: {integrity: sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==}
engines: {node: '>=4'}
@ -3142,11 +2790,6 @@ packages:
fsevents: 2.3.2
dev: true
/type-fest/0.13.1:
resolution: {integrity: sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==}
engines: {node: '>=10'}
dev: true
/type-fest/0.21.3:
resolution: {integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==}
engines: {node: '>=10'}
@ -3256,11 +2899,6 @@ packages:
resolution: {integrity: sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==}
dev: true
/well-known-symbols/2.0.0:
resolution: {integrity: sha512-ZMjC3ho+KXo0BfJb7JgtQ5IBuvnShdlACNkKkdsqBmYw3bPAaJfPeYUo6tLUaT5tG/Gkh7xkpBhKRQ9e7pyg9Q==}
engines: {node: '>=6'}
dev: true
/whatwg-url/7.1.0:
resolution: {integrity: sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==}
dependencies:
@ -3332,19 +2970,6 @@ packages:
resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==}
dev: true
/write-file-atomic/5.0.0:
resolution: {integrity: sha512-R7NYMnHSlV42K54lwY9lvW6MnSm1HSJqZL3xiSgi9E7//FYaI74r2G0rd+/X6VAMkHEdzxQaU5HUOXWUz5kA/w==}
engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
dependencies:
imurmurhash: 0.1.4
signal-exit: 3.0.7
dev: true
/y18n/5.0.8:
resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==}
engines: {node: '>=10'}
dev: true
/yallist/3.1.1:
resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==}
dev: true
@ -3368,30 +2993,7 @@ packages:
engines: {node: '>=10'}
dev: true
/yargs-parser/21.1.1:
resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==}
engines: {node: '>=12'}
dev: true
/yargs/17.6.2:
resolution: {integrity: sha512-1/9UrdHjDZc0eOU0HxOHoS78C69UD3JRMvzlJ7S79S2nTaWRA/whGCTV8o9e/N/1Va9YIV7Q4sOxD8VV4pCWOw==}
engines: {node: '>=12'}
dependencies:
cliui: 8.0.1
escalade: 3.1.1
get-caller-file: 2.0.5
require-directory: 2.1.1
string-width: 4.2.3
y18n: 5.0.8
yargs-parser: 21.1.1
dev: true
/yocto-queue/0.1.0:
resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==}
engines: {node: '>=10'}
dev: true
/yocto-queue/1.0.0:
resolution: {integrity: sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==}
engines: {node: '>=12.20'}
dev: true

Wyświetl plik

@ -1,131 +0,0 @@
import test from 'ava'
import dotenv from 'dotenv-safe'
import * as types from './types'
import { ChatGPTAPI } from './chatgpt-api'
dotenv.config()
const isCI = !!process.env.CI
test('ChatGPTAPI invalid session token', async (t) => {
t.timeout(30 * 1000) // 30 seconds
t.throws(() => new ChatGPTAPI({ sessionToken: null, clearanceToken: null }), {
message: 'ChatGPT invalid session token'
})
await t.throwsAsync(
async () => {
const chatgpt = new ChatGPTAPI({
sessionToken: 'invalid',
clearanceToken: 'invalid'
})
await chatgpt.initSession()
},
{
instanceOf: types.ChatGPTError,
message: 'ChatGPT failed to refresh auth token. Error: Unauthorized'
}
)
})
test('ChatGPTAPI valid session token', async (t) => {
if (!isCI) {
t.timeout(2 * 60 * 1000) // 2 minutes
}
t.notThrows(
() =>
new ChatGPTAPI({
sessionToken: 'fake valid session token',
clearanceToken: 'invalid'
})
)
await t.notThrowsAsync(
(async () => {
const chatgpt = new ChatGPTAPI({
sessionToken: process.env.SESSION_TOKEN,
clearanceToken: process.env.CLEARANCE_TOKEN
})
// Don't make any real API calls using our session token if we're running on CI
if (!isCI) {
await chatgpt.initSession()
const response = await chatgpt.sendMessage('test')
console.log('chatgpt response', response)
t.truthy(response)
t.is(typeof response, 'string')
}
})()
)
})
if (!isCI) {
test('ChatGPTAPI expired session token', async (t) => {
t.timeout(30 * 1000) // 30 seconds
const expiredSessionToken = process.env.TEST_EXPIRED_SESSION_TOKEN
await t.throwsAsync(
async () => {
const chatgpt = new ChatGPTAPI({
sessionToken: expiredSessionToken,
clearanceToken: 'invalid'
})
await chatgpt.initSession()
},
{
instanceOf: types.ChatGPTError,
message:
'ChatGPT failed to refresh auth token. Error: session token may have expired'
}
)
})
}
if (!isCI) {
test('ChatGPTAPI timeout', async (t) => {
t.timeout(30 * 1000) // 30 seconds
await t.throwsAsync(
async () => {
const chatgpt = new ChatGPTAPI({
sessionToken: process.env.SESSION_TOKEN,
clearanceToken: process.env.CLEARANCE_TOKEN
})
await chatgpt.sendMessage('test', {
timeoutMs: 1
})
},
{
message: 'ChatGPT timed out waiting for response'
}
)
})
test('ChatGPTAPI abort', async (t) => {
t.timeout(30 * 1000) // 30 seconds
await t.throwsAsync(
async () => {
const chatgpt = new ChatGPTAPI({
sessionToken: process.env.SESSION_TOKEN,
clearanceToken: process.env.CLEARANCE_TOKEN
})
const abortController = new AbortController()
setTimeout(() => abortController.abort(new Error('testing abort')), 10)
await chatgpt.sendMessage('test', {
abortSignal: abortController.signal
})
},
{
message: 'testing abort'
}
)
})
}

Wyświetl plik

@ -1,4 +1,5 @@
import { encode as gptEncode } from 'gpt-3-encoder'
import Keyv from 'keyv'
import pTimeout from 'p-timeout'
import QuickLRU from 'quick-lru'
import { v4 as uuidv4 } from 'uuid'
@ -7,26 +8,30 @@ import * as types from './types'
import { fetch } from './fetch'
import { fetchSSE } from './fetch-sse'
// NOTE: this is not a public model, but it was leaked by the ChatGPT webapp.
const CHATGPT_MODEL = 'text-chat-davinci-002-20230126'
const USER_LABEL = 'User'
const ASSISTANT_LABEL = 'ChatGPT'
export class ChatGPTAPI {
protected _apiKey: string
protected _apiBaseUrl: string
protected _model: string
protected _temperature: number
protected _presencePenalty: number
protected _stop: string[]
protected _completionParams: types.openai.CompletionParams
protected _debug: boolean
protected _getMessageById: types.GetMessageByIdFunction
protected _messageCache: QuickLRU<string, types.ChatMessage>
protected _upsertMessage: types.UpsertMessageFunction
protected _messageStore: Keyv<types.ChatMessage>
/**
* Creates a new client wrapper around OpenAI's completion API using the
* unofficial ChatGPT model.
*
* @param debug - Optional enables logging debugging into to stdout
* @param apiKey - OpenAI API key (required).
* @param debug - Optional enables logging debugging info to stdout.
* @param stop - Up to 4 sequences where the API will stop generating further tokens. The returned text will not contain the stop sequence.
*/
constructor(opts: {
apiKey: string
@ -34,44 +39,48 @@ export class ChatGPTAPI {
/** @defaultValue `'https://api.openai.com'` **/
apiBaseUrl?: string
/** @defaultValue `'text-chat-davinci-002-20230126'` **/
model?: string
/** @defaultValue 0.7 **/
temperature?: number
/** @defaultValue 0.6 **/
presencePenalty?: number
stop?: string[]
completionParams?: types.openai.CompletionParams
/** @defaultValue `false` **/
debug?: boolean
messageStore?: Keyv
getMessageById?: types.GetMessageByIdFunction
upsertMessage?: types.UpsertMessageFunction
}) {
const {
apiKey,
apiBaseUrl = 'https://api.openai.com',
model = CHATGPT_MODEL,
temperature = 0.7,
presencePenalty = 0.6,
stop = ['<|im_end|>'],
debug = false,
getMessageById = this._defaultGetMessageById
messageStore,
getMessageById = this._defaultGetMessageById,
upsertMessage = this._defaultUpsertMessage,
completionParams
} = opts
this._apiKey = apiKey
this._apiBaseUrl = apiBaseUrl
this._model = model
this._temperature = temperature
this._presencePenalty = presencePenalty
this._stop = stop
this._debug = !!debug
this._getMessageById = getMessageById
// override `getMessageById` if you want persistence
this._messageCache = new QuickLRU({ maxSize: 10000 })
this._completionParams = {
model: CHATGPT_MODEL,
temperature: 0.7,
presence_penalty: 0.6,
stop: ['<|im_end|>'],
...completionParams
}
this._getMessageById = getMessageById
this._upsertMessage = upsertMessage
if (messageStore) {
this._messageStore = messageStore
} else {
this._messageStore = new Keyv<types.ChatMessage, any>({
store: new QuickLRU<string, types.ChatMessage>({ maxSize: 10000 })
})
}
if (!this._apiKey) {
throw new Error('ChatGPT invalid apiKey')
@ -91,7 +100,6 @@ export class ChatGPTAPI {
* @param opts.conversationId - Optional ID of a conversation to continue
* @param opts.parentMessageId - Optional ID of the previous message in the conversation
* @param opts.messageId - Optional ID of the message to send (defaults to a random UUID)
* @param opts.action - Optional ChatGPT `action` (either `next` or `variant`)
* @param opts.timeoutMs - Optional timeout in milliseconds (defaults to no timeout)
* @param opts.onProgress - Optional callback which will be invoked every time the partial response is updated
* @param opts.abortSignal - Optional callback used to abort the underlying `fetch` call using an [AbortController](https://developer.mozilla.org/en-US/docs/Web/API/AbortController)
@ -119,15 +127,15 @@ export class ChatGPTAPI {
abortSignal = abortController.signal
}
const input: types.ChatMessage = {
const message: types.ChatMessage = {
role: 'user',
id: messageId,
parentMessageId,
conversationId,
text
}
await this._upsertMessage(message)
this._messageCache.set(input.id, input)
const { prompt, maxTokens } = await this._buildPrompt(text, opts)
const result: types.ChatMessage = {
@ -146,13 +154,10 @@ export class ChatGPTAPI {
Authorization: `Bearer ${this._apiKey}`
}
const body = {
max_tokens: maxTokens,
...this._completionParams,
prompt,
stream,
model: this._model,
temperature: this._temperature,
presence_penalty: this._presencePenalty,
stop: this._stop,
max_tokens: maxTokens
stream
}
if (this._debug) {
@ -173,7 +178,8 @@ export class ChatGPTAPI {
}
try {
const response = JSON.parse(data)
const response: types.openai.CompletionResponse =
JSON.parse(data)
if (response?.id && response?.choices?.length) {
result.id = response.id
@ -207,7 +213,7 @@ export class ChatGPTAPI {
return reject(error)
}
const response = await res.json()
const response: types.openai.CompletionResponse = await res.json()
if (this._debug) {
console.log(response)
}
@ -221,10 +227,8 @@ export class ChatGPTAPI {
}
}
}
)
responseP.then((message) => {
this._messageCache.set(message.id, message)
).then((message) => {
return this._upsertMessage(message).then(() => message)
})
if (timeoutMs) {
@ -266,7 +270,7 @@ Current date: ${currentDate}\n\n`
const maxNumTokens = 3097
let { parentMessageId } = opts
let nextPromptBody = `${USER_LABEL}:\n\n${message}`
let nextPromptBody = `${USER_LABEL}:\n\n${message}<|im_end|>`
let promptBody = ''
let prompt: string
let numTokens: number
@ -315,7 +319,7 @@ Current date: ${currentDate}\n\n`
}
protected async _getTokenCount(text: string) {
if (this._model === CHATGPT_MODEL) {
if (this._completionParams.model === CHATGPT_MODEL) {
// With this model, "<|im_end|>" is 1 token, but tokenizers aren't aware of it yet.
// Replace it with "<|endoftext|>" (which it does know about) so that the tokenizer can count it as 1 token.
text = text.replace(/<\|im_end\|>/g, '<|endoftext|>')
@ -327,6 +331,12 @@ Current date: ${currentDate}\n\n`
protected async _defaultGetMessageById(
id: string
): Promise<types.ChatMessage> {
return this._messageCache.get(id)
return this._messageStore.get(id)
}
protected async _defaultUpsertMessage(
message: types.ChatMessage
): Promise<void> {
this._messageStore.set(message.id, message)
}
}

Wyświetl plik

@ -16,14 +16,128 @@ export interface ChatMessage {
id: string
text: string
role: Role
parentMessageId?: string
conversationId?: string
}
export type GetMessageByIdFunction = (id: string) => Promise<ChatMessage>
export class ChatGPTError extends Error {
statusCode?: number
statusText?: string
}
/** Returns a chat message from a store by it's ID (or null if not found). */
export type GetMessageByIdFunction = (id: string) => Promise<ChatMessage>
/** Upserts a chat message to a store. */
export type UpsertMessageFunction = (message: ChatMessage) => Promise<void>
export namespace openai {
export type CompletionParams = {
/** ID of the model to use. */
model: string
/** The string prompt to generate a completion for. */
prompt: string
/**
* The suffix that comes after a completion of inserted text.
*/
suffix?: string
/**
* The maximum number of tokens to generate in the completion. The token count of your prompt plus `max_tokens` cannot exceed the model\'s context length. Most models have a context length of 2048 tokens (except for the newest models, which support 4096).
*/
max_tokens?: number
/**
* What [sampling temperature](https://towardsdatascience.com/how-to-sample-from-language-models-682bceb97277) to use. Higher values means the model will take more risks. Try 0.9 for more creative applications, and 0 (argmax sampling) for ones with a well-defined answer. We generally recommend altering this or `top_p` but not both.
*/
temperature?: number
/**
* An alternative to sampling with temperature, called nucleus sampling, where the model considers the results of the tokens with top_p probability mass. So 0.1 means only the tokens comprising the top 10% probability mass are considered. We generally recommend altering this or `temperature` but not both.
*/
top_p?: number
/**
* Include the log probabilities on the `logprobs` most likely tokens, as well the chosen tokens. For example, if `logprobs` is 5, the API will return a list of the 5 most likely tokens. The API will always return the `logprob` of the sampled token, so there may be up to `logprobs+1` elements in the response. The maximum value for `logprobs` is 5. If you need more than this, please contact us through our [Help center](https://help.openai.com) and describe your use case.
*/
logprobs?: number
/**
* Echo back the prompt in addition to the completion
*/
echo?: boolean
/**
* Up to 4 sequences where the API will stop generating further tokens. The returned text will not contain the stop sequence.
*/
stop?: string[]
/**
* Number between -2.0 and 2.0. Positive values penalize new tokens based on whether they appear in the text so far, increasing the model\'s likelihood to talk about new topics. [See more information about frequency and presence penalties.](/docs/api-reference/parameter-details)
*/
presence_penalty?: number
/**
* Number between -2.0 and 2.0. Positive values penalize new tokens based on their existing frequency in the text so far, decreasing the model\'s likelihood to repeat the same line verbatim. [See more information about frequency and presence penalties.](/docs/api-reference/parameter-details)
*/
frequency_penalty?: number
/**
* Generates `best_of` completions server-side and returns the \"best\" (the one with the highest log probability per token). Results cannot be streamed. When used with `n`, `best_of` controls the number of candidate completions and `n` specifies how many to return `best_of` must be greater than `n`. **Note:** Because this parameter generates many completions, it can quickly consume your token quota. Use carefully and ensure that you have reasonable settings for `max_tokens` and `stop`.
*/
best_of?: number
/**
* Modify the likelihood of specified tokens appearing in the completion. Accepts a json object that maps tokens (specified by their token ID in the GPT tokenizer) to an associated bias value from -100 to 100. You can use this [tokenizer tool](/tokenizer?view=bpe) (which works for both GPT-2 and GPT-3) to convert text to token IDs. Mathematically, the bias is added to the logits generated by the model prior to sampling. The exact effect will vary per model, but values between -1 and 1 should decrease or increase likelihood of selection; values like -100 or 100 should result in a ban or exclusive selection of the relevant token. As an example, you can pass `{\"50256\": -100}` to prevent the <|endoftext|> token from being generated.
*/
logit_bias?: Record<string, number>
/**
* A unique identifier representing your end-user, which will help OpenAI to monitor and detect abuse. [Learn more](/docs/usage-policies/end-user-ids).
*/
user?: string
/* NOTE: this is handled by the `sendMessage` function.
*
* Whether to stream back partial progress. If set, tokens will be sent as data-only [server-sent events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#Event_stream_format) as they become available, with the stream terminated by a `data: [DONE]` message.
*/
// stream?: boolean | null
/**
* NOT SUPPORTED
*/
/**
* How many completions to generate for each prompt. **Note:** Because this parameter generates many completions, it can quickly consume your token quota. Use carefully and ensure that you have reasonable settings for `max_tokens` and `stop`.
*/
// 'n'?: number | null;
}
export type CompletionResponse = {
id: string
object: string
created: number
model: string
choices: CompletionResponseChoices
usage?: CompletionResponseUsage
}
export type CompletionResponseChoices = {
text?: string
index?: number
logprobs?: {
tokens?: Array<string>
token_logprobs?: Array<number>
top_logprobs?: Array<object>
text_offset?: Array<number>
} | null
finish_reason?: string
}[]
export type CompletionResponseUsage = {
prompt_tokens: number
completion_tokens: number
total_tokens: number
}
}