diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000..89ec0d8c --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +dist/** linguist-generated=true \ No newline at end of file diff --git a/adapter/docker/README.md b/adapter/docker/README.md index f4f3eafd..0eb5bcda 100644 --- a/adapter/docker/README.md +++ b/adapter/docker/README.md @@ -10,4 +10,15 @@ yarn && yarn run docker ```bash docker run -v $(pwd)/config.json:/app/config.json -p 8787:8787 chatgpt-telegram-bot:latest --name chatgpt-telegram-bot +``` + +### 3. Configure +```json5 +{ + "database": { + "type": "sqlite",// memory, local, sqlite, redis + "path": "/app/data.db" // your database path + }, + "server": "https://example.com" +} ``` \ No newline at end of file diff --git a/adapter/docker/esbuild.config.js b/adapter/docker/esbuild.config.js index 21f03ef8..4d672079 100644 --- a/adapter/docker/esbuild.config.js +++ b/adapter/docker/esbuild.config.js @@ -1,3 +1,5 @@ -import {build} from '../script/esbuild.config.js'; +import { build } from '../script/esbuild.config.js'; -build('../../dist/buildinfo.json', 'build/index.js').catch(() => process.exit(1)); +build('../../dist/buildinfo.json', 'build/index.js') + .then(() => console.log('Build success')) + .catch(() => process.exit(1)); diff --git a/adapter/docker/index.js b/adapter/docker/index.js index 52ef98d0..8d6dda54 100644 --- a/adapter/docker/index.js +++ b/adapter/docker/index.js @@ -1,23 +1,21 @@ -import {default as adapter} from 'cloudflare-worker-adapter'; -import {default as worker} from '../../main.js'; -import fs from 'fs'; -import {createCache} from 'cloudflare-worker-adapter/cache'; - +import fs from 'node:fs'; +import { createCache, startServer } from 'cloudflare-worker-adapter'; +import worker from '../../main.js'; const { - CONFIG_PATH = './config/config.json', - TOML_PATH = './config/config.toml', + CONFIG_PATH = '/app/config.json', + TOML_PATH = '/app/config.toml', } = process.env; const config = JSON.parse(fs.readFileSync(CONFIG_PATH, 'utf-8')); const cache = await createCache(config?.database?.type, config?.database); console.log(`database: ${config?.database?.type} is ready`); -adapter.startServer( +startServer( 8787, '127.0.0.1', TOML_PATH, { DATABASE: cache }, - { server: config.server }, + { baseURL: config.server }, worker.fetch, -); +); \ No newline at end of file diff --git a/adapter/docker/package.json b/adapter/docker/package.json index ffd40de5..cdbac7a8 100644 --- a/adapter/docker/package.json +++ b/adapter/docker/package.json @@ -1,21 +1,20 @@ { - "name": "chatgpt-telegram-bot", - "version": "1.0.0", - "description": "", - "main": "index.js", - "type": "module", - "scripts": { - "start": "node index.js", - "build": "node esbuild.config.js", - "docker": "npm run build && docker build -t chatgpt-telegram-bot:latest .", - "lint": "eslint --fix index.js" - }, - "author": "TBXark", - "license": "MIT", - "dependencies": { - "cloudflare-worker-adapter": "1.0.3" - }, - "devDependencies": { - "@eslint/js": "^9.8.0" - } + "name": "chatgpt-telegram-bot", + "type": "module", + "version": "1.0.0", + "description": "", + "author": "TBXark", + "license": "MIT", + "main": "index.js", + "scripts": { + "start": "node index.js", + "build": "node esbuild.config.js", + "docker": "npm run build && docker build -t chatgpt-telegram-bot:latest ." + }, + "dependencies": { + "cloudflare-worker-adapter": "1.2.2" + }, + "devDependencies": { + "esbuild": "^0.23.1" + } } diff --git a/adapter/docker/yarn.lock b/adapter/docker/yarn.lock index e89d6b07..55343c53 100644 --- a/adapter/docker/yarn.lock +++ b/adapter/docker/yarn.lock @@ -2,10 +2,125 @@ # yarn lockfile v1 -"@eslint/js@^9.8.0": - version "9.9.0" - resolved "https://registry.yarnpkg.com/@eslint/js/-/js-9.9.0.tgz#d8437adda50b3ed4401964517b64b4f59b0e2638" - integrity sha512-hhetes6ZHP3BlXLxmd8K2SNgkhNSi+UcecbnwWKwpP7kyi/uC75DJ1lOOBO3xrC4jyojtGE3YxKZPHfk4yrgug== +"@esbuild/aix-ppc64@0.23.1": + version "0.23.1" + resolved "https://registry.yarnpkg.com/@esbuild/aix-ppc64/-/aix-ppc64-0.23.1.tgz#51299374de171dbd80bb7d838e1cfce9af36f353" + integrity sha512-6VhYk1diRqrhBAqpJEdjASR/+WVRtfjpqKuNw11cLiaWpAT/Uu+nokB+UJnevzy/P9C/ty6AOe0dwueMrGh/iQ== + +"@esbuild/android-arm64@0.23.1": + version "0.23.1" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.23.1.tgz#58565291a1fe548638adb9c584237449e5e14018" + integrity sha512-xw50ipykXcLstLeWH7WRdQuysJqejuAGPd30vd1i5zSyKK3WE+ijzHmLKxdiCMtH1pHz78rOg0BKSYOSB/2Khw== + +"@esbuild/android-arm@0.23.1": + version "0.23.1" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.23.1.tgz#5eb8c652d4c82a2421e3395b808e6d9c42c862ee" + integrity sha512-uz6/tEy2IFm9RYOyvKl88zdzZfwEfKZmnX9Cj1BHjeSGNuGLuMD1kR8y5bteYmwqKm1tj8m4cb/aKEorr6fHWQ== + +"@esbuild/android-x64@0.23.1": + version "0.23.1" + resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.23.1.tgz#ae19d665d2f06f0f48a6ac9a224b3f672e65d517" + integrity sha512-nlN9B69St9BwUoB+jkyU090bru8L0NA3yFvAd7k8dNsVH8bi9a8cUAUSEcEEgTp2z3dbEDGJGfP6VUnkQnlReg== + +"@esbuild/darwin-arm64@0.23.1": + version "0.23.1" + resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.23.1.tgz#05b17f91a87e557b468a9c75e9d85ab10c121b16" + integrity sha512-YsS2e3Wtgnw7Wq53XXBLcV6JhRsEq8hkfg91ESVadIrzr9wO6jJDMZnCQbHm1Guc5t/CdDiFSSfWP58FNuvT3Q== + +"@esbuild/darwin-x64@0.23.1": + version "0.23.1" + resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.23.1.tgz#c58353b982f4e04f0d022284b8ba2733f5ff0931" + integrity sha512-aClqdgTDVPSEGgoCS8QDG37Gu8yc9lTHNAQlsztQ6ENetKEO//b8y31MMu2ZaPbn4kVsIABzVLXYLhCGekGDqw== + +"@esbuild/freebsd-arm64@0.23.1": + version "0.23.1" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.23.1.tgz#f9220dc65f80f03635e1ef96cfad5da1f446f3bc" + integrity sha512-h1k6yS8/pN/NHlMl5+v4XPfikhJulk4G+tKGFIOwURBSFzE8bixw1ebjluLOjfwtLqY0kewfjLSrO6tN2MgIhA== + +"@esbuild/freebsd-x64@0.23.1": + version "0.23.1" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.23.1.tgz#69bd8511fa013b59f0226d1609ac43f7ce489730" + integrity sha512-lK1eJeyk1ZX8UklqFd/3A60UuZ/6UVfGT2LuGo3Wp4/z7eRTRYY+0xOu2kpClP+vMTi9wKOfXi2vjUpO1Ro76g== + +"@esbuild/linux-arm64@0.23.1": + version "0.23.1" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.23.1.tgz#8050af6d51ddb388c75653ef9871f5ccd8f12383" + integrity sha512-/93bf2yxencYDnItMYV/v116zff6UyTjo4EtEQjUBeGiVpMmffDNUyD9UN2zV+V3LRV3/on4xdZ26NKzn6754g== + +"@esbuild/linux-arm@0.23.1": + version "0.23.1" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.23.1.tgz#ecaabd1c23b701070484990db9a82f382f99e771" + integrity sha512-CXXkzgn+dXAPs3WBwE+Kvnrf4WECwBdfjfeYHpMeVxWE0EceB6vhWGShs6wi0IYEqMSIzdOF1XjQ/Mkm5d7ZdQ== + +"@esbuild/linux-ia32@0.23.1": + version "0.23.1" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.23.1.tgz#3ed2273214178109741c09bd0687098a0243b333" + integrity sha512-VTN4EuOHwXEkXzX5nTvVY4s7E/Krz7COC8xkftbbKRYAl96vPiUssGkeMELQMOnLOJ8k3BY1+ZY52tttZnHcXQ== + +"@esbuild/linux-loong64@0.23.1": + version "0.23.1" + resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.23.1.tgz#a0fdf440b5485c81b0fbb316b08933d217f5d3ac" + integrity sha512-Vx09LzEoBa5zDnieH8LSMRToj7ir/Jeq0Gu6qJ/1GcBq9GkfoEAoXvLiW1U9J1qE/Y/Oyaq33w5p2ZWrNNHNEw== + +"@esbuild/linux-mips64el@0.23.1": + version "0.23.1" + resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.23.1.tgz#e11a2806346db8375b18f5e104c5a9d4e81807f6" + integrity sha512-nrFzzMQ7W4WRLNUOU5dlWAqa6yVeI0P78WKGUo7lg2HShq/yx+UYkeNSE0SSfSure0SqgnsxPvmAUu/vu0E+3Q== + +"@esbuild/linux-ppc64@0.23.1": + version "0.23.1" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.23.1.tgz#06a2744c5eaf562b1a90937855b4d6cf7c75ec96" + integrity sha512-dKN8fgVqd0vUIjxuJI6P/9SSSe/mB9rvA98CSH2sJnlZ/OCZWO1DJvxj8jvKTfYUdGfcq2dDxoKaC6bHuTlgcw== + +"@esbuild/linux-riscv64@0.23.1": + version "0.23.1" + resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.23.1.tgz#65b46a2892fc0d1af4ba342af3fe0fa4a8fe08e7" + integrity sha512-5AV4Pzp80fhHL83JM6LoA6pTQVWgB1HovMBsLQ9OZWLDqVY8MVobBXNSmAJi//Csh6tcY7e7Lny2Hg1tElMjIA== + +"@esbuild/linux-s390x@0.23.1": + version "0.23.1" + resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.23.1.tgz#e71ea18c70c3f604e241d16e4e5ab193a9785d6f" + integrity sha512-9ygs73tuFCe6f6m/Tb+9LtYxWR4c9yg7zjt2cYkjDbDpV/xVn+68cQxMXCjUpYwEkze2RcU/rMnfIXNRFmSoDw== + +"@esbuild/linux-x64@0.23.1": + version "0.23.1" + resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.23.1.tgz#d47f97391e80690d4dfe811a2e7d6927ad9eed24" + integrity sha512-EV6+ovTsEXCPAp58g2dD68LxoP/wK5pRvgy0J/HxPGB009omFPv3Yet0HiaqvrIrgPTBuC6wCH1LTOY91EO5hQ== + +"@esbuild/netbsd-x64@0.23.1": + version "0.23.1" + resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.23.1.tgz#44e743c9778d57a8ace4b72f3c6b839a3b74a653" + integrity sha512-aevEkCNu7KlPRpYLjwmdcuNz6bDFiE7Z8XC4CPqExjTvrHugh28QzUXVOZtiYghciKUacNktqxdpymplil1beA== + +"@esbuild/openbsd-arm64@0.23.1": + version "0.23.1" + resolved "https://registry.yarnpkg.com/@esbuild/openbsd-arm64/-/openbsd-arm64-0.23.1.tgz#05c5a1faf67b9881834758c69f3e51b7dee015d7" + integrity sha512-3x37szhLexNA4bXhLrCC/LImN/YtWis6WXr1VESlfVtVeoFJBRINPJ3f0a/6LV8zpikqoUg4hyXw0sFBt5Cr+Q== + +"@esbuild/openbsd-x64@0.23.1": + version "0.23.1" + resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.23.1.tgz#2e58ae511bacf67d19f9f2dcd9e8c5a93f00c273" + integrity sha512-aY2gMmKmPhxfU+0EdnN+XNtGbjfQgwZj43k8G3fyrDM/UdZww6xrWxmDkuz2eCZchqVeABjV5BpildOrUbBTqA== + +"@esbuild/sunos-x64@0.23.1": + version "0.23.1" + resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.23.1.tgz#adb022b959d18d3389ac70769cef5a03d3abd403" + integrity sha512-RBRT2gqEl0IKQABT4XTj78tpk9v7ehp+mazn2HbUeZl1YMdaGAQqhapjGTCe7uw7y0frDi4gS0uHzhvpFuI1sA== + +"@esbuild/win32-arm64@0.23.1": + version "0.23.1" + resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.23.1.tgz#84906f50c212b72ec360f48461d43202f4c8b9a2" + integrity sha512-4O+gPR5rEBe2FpKOVyiJ7wNDPA8nGzDuJ6gN4okSA1gEOYZ67N8JPk58tkWtdtPeLz7lBnY6I5L3jdsr3S+A6A== + +"@esbuild/win32-ia32@0.23.1": + version "0.23.1" + resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.23.1.tgz#5e3eacc515820ff729e90d0cb463183128e82fac" + integrity sha512-BcaL0Vn6QwCwre3Y717nVHZbAa4UBEigzFm6VdsVdT/MbZ38xoj1X9HPkZhbmaBGUD1W8vxAfffbDe8bA6AKnQ== + +"@esbuild/win32-x64@0.23.1": + version "0.23.1" + resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.23.1.tgz#81fd50d11e2c32b2d6241470e3185b70c7b30699" + integrity sha512-BHpFFeslkWrXWyUPnbKm+xYYVYruCinGcftSBaa8zoF9hZO4BcSCFUvHVTtzpIY6YzUnYtuEhZ+C9iEXjxnasg== "@gar/promisify@^1.0.1": version "1.1.3" @@ -50,6 +165,13 @@ agent-base@6, agent-base@^6.0.2: dependencies: debug "4" +agent-base@^7.0.2: + version "7.1.1" + resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-7.1.1.tgz#bdbded7dfb096b751a2a087eeeb9664725b2e317" + integrity sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA== + dependencies: + debug "^4.3.4" + agentkeepalive@^4.1.3: version "4.5.0" resolved "https://registry.yarnpkg.com/agentkeepalive/-/agentkeepalive-4.5.0.tgz#2673ad1389b3c418c5a20c5d7364f93ca04be923" @@ -164,14 +286,15 @@ clean-stack@^2.0.0: resolved "https://registry.yarnpkg.com/clean-stack/-/clean-stack-2.2.0.tgz#ee8472dbb129e727b31e8a10a427dee9dfe4008b" integrity sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A== -cloudflare-worker-adapter@1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/cloudflare-worker-adapter/-/cloudflare-worker-adapter-1.0.3.tgz#c87dda4b9f036c1b6887e36b52dbc4da8de198a0" - integrity sha512-Eyd2JsmGvzSt46fG2spccARgIhlcTXcpPVGIwxpG9ocC229LVYtw+JZ1R6FbMUVplFjrPqNJ2zK+tqX2pkBoKw== +cloudflare-worker-adapter@1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/cloudflare-worker-adapter/-/cloudflare-worker-adapter-1.2.2.tgz#b0139424bee23fd4ceae50e65388da7c4e913401" + integrity sha512-FuqyGK18DTgf0P5/H7lzDwUh2CTxyqItdI0ZZBnvHjYceF1r8nPkV0uN8OG9+18fSdl5Y0s9Ybf4UM/AYH8eng== dependencies: + https-proxy-agent "^7.0.5" ioredis "^5.4.1" node-fetch "^3.3.2" - sqlite3 "^5.1.7" + sqlite3 "^5" toml "^3.0.0" cluster-key-slot@^1.1.0: @@ -262,6 +385,36 @@ err-code@^2.0.2: resolved "https://registry.yarnpkg.com/err-code/-/err-code-2.0.3.tgz#23c2f3b756ffdfc608d30e27c9a941024807e7f9" integrity sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA== +esbuild@^0.23.1: + version "0.23.1" + resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.23.1.tgz#40fdc3f9265ec0beae6f59824ade1bd3d3d2dab8" + integrity sha512-VVNz/9Sa0bs5SELtn3f7qhJCDPCF5oMEl5cO9/SSinpE9hbPVvxbd572HH5AKiP7WD8INO53GgfDDhRjkylHEg== + optionalDependencies: + "@esbuild/aix-ppc64" "0.23.1" + "@esbuild/android-arm" "0.23.1" + "@esbuild/android-arm64" "0.23.1" + "@esbuild/android-x64" "0.23.1" + "@esbuild/darwin-arm64" "0.23.1" + "@esbuild/darwin-x64" "0.23.1" + "@esbuild/freebsd-arm64" "0.23.1" + "@esbuild/freebsd-x64" "0.23.1" + "@esbuild/linux-arm" "0.23.1" + "@esbuild/linux-arm64" "0.23.1" + "@esbuild/linux-ia32" "0.23.1" + "@esbuild/linux-loong64" "0.23.1" + "@esbuild/linux-mips64el" "0.23.1" + "@esbuild/linux-ppc64" "0.23.1" + "@esbuild/linux-riscv64" "0.23.1" + "@esbuild/linux-s390x" "0.23.1" + "@esbuild/linux-x64" "0.23.1" + "@esbuild/netbsd-x64" "0.23.1" + "@esbuild/openbsd-arm64" "0.23.1" + "@esbuild/openbsd-x64" "0.23.1" + "@esbuild/sunos-x64" "0.23.1" + "@esbuild/win32-arm64" "0.23.1" + "@esbuild/win32-ia32" "0.23.1" + "@esbuild/win32-x64" "0.23.1" + expand-template@^2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/expand-template/-/expand-template-2.0.3.tgz#6e14b3fcee0f3a6340ecb57d2e8918692052a47c" @@ -367,6 +520,14 @@ https-proxy-agent@^5.0.0: agent-base "6" debug "4" +https-proxy-agent@^7.0.5: + version "7.0.5" + resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-7.0.5.tgz#9e8b5013873299e11fab6fd548405da2d6c602b2" + integrity sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw== + dependencies: + agent-base "^7.0.2" + debug "4" + humanize-ms@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/humanize-ms/-/humanize-ms-1.2.1.tgz#c46e3159a293f6b896da29316d8b6fe8bb79bbed" @@ -833,7 +994,7 @@ sprintf-js@^1.1.3: resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.1.3.tgz#4914b903a2f8b685d17fdf78a70e917e872e444a" integrity sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA== -sqlite3@^5.1.7: +sqlite3@^5: version "5.1.7" resolved "https://registry.yarnpkg.com/sqlite3/-/sqlite3-5.1.7.tgz#59ca1053c1ab38647396586edad019b1551041b7" integrity sha512-GGIyOiFaG+TUra3JIfkI/zGP8yZYLPQ0pl1bH+ODjiX57sPhrLU5sQJn1y9bDKZUFYkX1crlrPfSYt0BKKdkog== diff --git a/adapter/local/README.md b/adapter/local/README.md index 86310cb8..010c06a1 100644 --- a/adapter/local/README.md +++ b/adapter/local/README.md @@ -8,7 +8,7 @@ #### 1. 创建`config.json` 为了隐私安全,这里把本地的一些配置写在了`config.json`。请自行实现。并放在`index.js`同级目录下。 -```js +```json5 { // 本地端口,默认8787 "port": 8787, diff --git a/adapter/local/index.js b/adapter/local/index.js index a7a4c235..5cab5017 100644 --- a/adapter/local/index.js +++ b/adapter/local/index.js @@ -1,27 +1,18 @@ -import adapter, {bindGlobal} from 'cloudflare-worker-adapter'; -import fs from 'fs'; -import {HttpsProxyAgent} from 'https-proxy-agent'; -import fetch from 'node-fetch'; -import {default as worker} from '../../main.js'; -import {ENV} from '../../src/config/env.js'; -import {createCache} from 'cloudflare-worker-adapter/cache'; - +import fs from 'node:fs'; +import * as process from 'node:process'; +import { createCache, startServer } from 'cloudflare-worker-adapter'; +import { installFetchProxy } from 'cloudflare-worker-adapter/fetchProxy'; +import worker from '../../main.js'; +import { ENV } from '../../src/config/env.js'; const config = JSON.parse(fs.readFileSync('./config.json', 'utf-8')); const cache = await createCache(config?.database?.type, config?.database); console.log(`database: ${config?.database?.type} is ready`); // 配置代理 -const proxy = config?.https_proxy || process.env.https_proxy || process.env.HTTPS_PROXY; +const proxy = config?.https_proxy || process.env.HTTPS_PROXY || process.env.https_proxy || process.env.HTTP_PROXY || process.env.http_proxy; if (proxy) { - console.log(`https proxy: ${proxy}`); - const agent = new HttpsProxyAgent(proxy); - const proxyFetch = async (url, init) => { - return fetch(url, {agent, ...init}); - }; - bindGlobal({ - fetch: proxyFetch, - }); + installFetchProxy(proxy); } // 配置版本信息 @@ -34,12 +25,11 @@ try { console.log(e); } -// 延迟加载 ../main.js, 防止ENV过早初始化 -adapter.startServer( +startServer( config.port || 8787, config.host || '0.0.0.0', '../../wrangler.toml', - {DATABASE: cache}, - {server: config.server}, + { DATABASE: cache }, + { baseURL: config.server }, worker.fetch, ); diff --git a/adapter/local/package.json b/adapter/local/package.json index c82a8408..6b93060d 100644 --- a/adapter/local/package.json +++ b/adapter/local/package.json @@ -1,18 +1,16 @@ { - "name": "local", - "version": "1.0.0", - "description": "", - "type": "module", - "main": "index.js", - "scripts": { - "start": "node index.js", - "debug": "node --watch index.js" - }, - "author": "TBXark", - "license": "ISC", - "dependencies": { - "cloudflare-worker-adapter": "github:TBXark/cloudflare-worker-adapter", - "https-proxy-agent": "^7.0.5", - "node-fetch": "^3.3.2" - } + "name": "local", + "type": "module", + "version": "1.0.0", + "description": "", + "author": "TBXark", + "license": "ISC", + "main": "index.js", + "scripts": { + "start": "node index.js", + "debug": "node --watch index.js" + }, + "dependencies": { + "cloudflare-worker-adapter": "1.2.2" + } } diff --git a/adapter/local/yarn.lock b/adapter/local/yarn.lock index 94f4b793..0a6f8240 100644 --- a/adapter/local/yarn.lock +++ b/adapter/local/yarn.lock @@ -166,13 +166,15 @@ clean-stack@^2.0.0: resolved "https://registry.yarnpkg.com/clean-stack/-/clean-stack-2.2.0.tgz#ee8472dbb129e727b31e8a10a427dee9dfe4008b" integrity sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A== -"cloudflare-worker-adapter@github:TBXark/cloudflare-worker-adapter": - version "1.0.2" - resolved "https://codeload.github.com/TBXark/cloudflare-worker-adapter/tar.gz/0212060e81af289d719a1ecc1ff98732004d9a3c" +cloudflare-worker-adapter@1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/cloudflare-worker-adapter/-/cloudflare-worker-adapter-1.2.2.tgz#b0139424bee23fd4ceae50e65388da7c4e913401" + integrity sha512-FuqyGK18DTgf0P5/H7lzDwUh2CTxyqItdI0ZZBnvHjYceF1r8nPkV0uN8OG9+18fSdl5Y0s9Ybf4UM/AYH8eng== dependencies: + https-proxy-agent "^7.0.5" ioredis "^5.4.1" node-fetch "^3.3.2" - sqlite3 "^5.1.7" + sqlite3 "^5" toml "^3.0.0" cluster-key-slot@^1.1.0: @@ -842,7 +844,7 @@ sprintf-js@^1.1.3: resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.1.3.tgz#4914b903a2f8b685d17fdf78a70e917e872e444a" integrity sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA== -sqlite3@^5.1.7: +sqlite3@^5: version "5.1.7" resolved "https://registry.yarnpkg.com/sqlite3/-/sqlite3-5.1.7.tgz#59ca1053c1ab38647396586edad019b1551041b7" integrity sha512-GGIyOiFaG+TUra3JIfkI/zGP8yZYLPQ0pl1bH+ODjiX57sPhrLU5sQJn1y9bDKZUFYkX1crlrPfSYt0BKKdkog== diff --git a/adapter/local_v2/README.md b/adapter/local_v2/README.md index de90f0fe..782dcb22 100644 --- a/adapter/local_v2/README.md +++ b/adapter/local_v2/README.md @@ -1,7 +1,17 @@ # 本地部署(无需域名版本) ## 使用步骤 +配置为json,结构如下: +```json +{ + "vars": { + "KEY": "VALUE" + } +} +``` 1. 使用 `npm run config` 将toml配置文件转换为json配置文件 +2. 或者修改 `config-example.json` 为 `config.json` 并修改其中的配置 +3. 如果你的网络环境需要代理,请在 `index.js` 中修改相关注释代码 ### 本地运行 1. 使用 `npm run start` 启动服务 diff --git a/adapter/local_v2/config-example.json b/adapter/local_v2/config-example.json new file mode 100644 index 00000000..d646cdcf --- /dev/null +++ b/adapter/local_v2/config-example.json @@ -0,0 +1,12 @@ +{ + "vars": { + "TELEGRAM_AVAILABLE_TOKENS": "TOKEN1,TOKEN2", + "CHAT_WHITE_LIST": "USER_ID1,USER_ID2", + "TELEGRAM_BOT_NAME": "BOT_NAME1,BOT_NAME2", + "CHAT_GROUP_WHITE_LIST": "GROUP_ID1,GROUP_ID2", + "GROUP_CHAT_BOT_ENABLE": "true", + "AI_PROVIDER": "auto", + "AI_IMAGE_PROVIDER": "auto", + "OPENAI_API_KEY": "SK-1,SK-2" + } +} \ No newline at end of file diff --git a/adapter/local_v2/config.js b/adapter/local_v2/config.js index 527bfd46..fa379b4c 100644 --- a/adapter/local_v2/config.js +++ b/adapter/local_v2/config.js @@ -4,4 +4,4 @@ import toml from 'toml'; const TOML_PATH = '../../wrangler.toml'; const raw = fs.readFileSync(TOML_PATH, 'utf-8'); const config = toml.parse(raw); -fs.writeFileSync('./config.json', JSON.stringify(config, null, ' ')); \ No newline at end of file +fs.writeFileSync('./config.json', JSON.stringify(config, null, ' ')); diff --git a/adapter/local_v2/esbuild.config.js b/adapter/local_v2/esbuild.config.js index 21f03ef8..4d672079 100644 --- a/adapter/local_v2/esbuild.config.js +++ b/adapter/local_v2/esbuild.config.js @@ -1,3 +1,5 @@ -import {build} from '../script/esbuild.config.js'; +import { build } from '../script/esbuild.config.js'; -build('../../dist/buildinfo.json', 'build/index.js').catch(() => process.exit(1)); +build('../../dist/buildinfo.json', 'build/index.js') + .then(() => console.log('Build success')) + .catch(() => process.exit(1)); diff --git a/adapter/local_v2/index.js b/adapter/local_v2/index.js index 99a8e611..74c19e94 100644 --- a/adapter/local_v2/index.js +++ b/adapter/local_v2/index.js @@ -1,74 +1,50 @@ -import {ENV, initEnv} from '../../src/config/env.js'; -import {deleteTelegramWebHook, getUpdates} from '../../src/telegram/telegram.js'; -import i18n from '../../src/i18n/index.js'; import fs from 'node:fs'; -import {handleMessage} from '../../src/telegram/message.js'; -import {HttpsProxyAgent} from 'https-proxy-agent'; -import fetch from 'node-fetch'; - -class MemoryCache { - constructor() { - this.cache = {}; - } - - async get(key) { - return this.cache[key]; - } - - async put(key, value) { - this.cache[key] = value; - } +import * as process from 'node:process'; +import { LocalCache } from 'cloudflare-worker-adapter/localCache'; +import { ENV, initEnv } from '../../src/config/env.js'; +import { deleteTelegramWebHook, getBotName, getTelegramUpdates } from '../../src/telegram/telegram.js'; +import i18n from '../../src/i18n/index.js'; +import { handleMessage } from '../../src/telegram/message.js'; - async delete(key) { - delete this.cache[key]; - } +// 如果你的环境需要代理才能访问Telegram API,请取消注释下面的代码,并根据实际情况修改代理地址 +// eslint-disable-next-line import/order +import { installFetchProxy } from 'cloudflare-worker-adapter/fetchProxy'; - syncToDisk(path) { - fs.writeFileSync(path, JSON.stringify(this.cache)); - } -} +const proxy = process.env.HTTPS_PROXY || process.env.https_proxy || process.env.HTTP_PROXY || process.env.http_proxy; +installFetchProxy(proxy); const { CONFIG_PATH = './config.json', CACHE_PATH = './cache.json', } = process.env; +if (!fs.existsSync(CACHE_PATH)) { + fs.writeFileSync(CACHE_PATH, '{}'); +} + // Initialize environment -const cache = new MemoryCache(); +const cache = new LocalCache(CACHE_PATH); initEnv({ - ...(JSON.parse(fs.readFileSync(CONFIG_PATH))).vars, + ...(JSON.parse(fs.readFileSync(CONFIG_PATH, 'utf-8')).vars), DATABASE: cache, }, i18n); -// Configure https proxy -const proxy = process.env.https_proxy || process.env.HTTPS_PROXY; -if (proxy) { - console.log(`https proxy: ${proxy}`); - const agent = new HttpsProxyAgent(proxy); - const proxyFetch = async (url, init) => { - return fetch(url, {agent, ...init}); - }; - global.fetch = proxyFetch; -} - - // Delete all webhooks const offset = {}; for (const token of ENV.TELEGRAM_AVAILABLE_TOKENS) { offset[token] = 0; - const [id] = token.split(':'); + const name = await getBotName(token); await deleteTelegramWebHook(token); - console.log(`Webhook deleted for bot ${id}, If you want to use webhook, please visit /init`); + console.log(`@${name} Webhook deleted, If you want to use webhook, please set it up again.`); } -// Loop to get updates while (true) { for (const token of ENV.TELEGRAM_AVAILABLE_TOKENS) { try { - const {result} = await getUpdates(token, offset[token]); - if (!result) { - continue; - } + /** + * @type {TelegramWebhookRequest[]} + */ + const { result } = await getTelegramUpdates(token, offset[token]); for (const update of result) { if (update.update_id >= offset[token]) { offset[token] = update.update_id + 1; @@ -77,9 +53,8 @@ while (true) { await handleMessage(token, update).catch(console.error); }); } - cache.syncToDisk(CACHE_PATH); } catch (e) { console.error(e); } } -} \ No newline at end of file +} diff --git a/adapter/local_v2/package.json b/adapter/local_v2/package.json index da723a49..5ff66fbc 100644 --- a/adapter/local_v2/package.json +++ b/adapter/local_v2/package.json @@ -1,22 +1,22 @@ { - "name": "local_v2", - "version": "1.0.0", - "main": "index.js", - "license": "MIT", - "type": "module", - "scripts": { - "start": "node index.js", - "build": "node esbuild.config.js", - "config": "node config.js", - "docker": "npm run build && docker build -t chatgpt-telegram-bot:latest ." - }, - "devDependencies": { - "esbuild": "^0.23.0", - "toml": "^3.0.0" - }, - "dependencies": { - "cloudflare-worker-adapter": "1.0.3", - "https-proxy-agent": "^7.0.5", - "node-fetch": "^3.3.2" - } + "name": "local_v2", + "type": "module", + "version": "1.0.0", + "license": "MIT", + "main": "index.js", + "scripts": { + "start": "node index.js", + "build": "node esbuild.config.js", + "config": "node config.js", + "docker": "npm run build && docker build -t chatgpt-telegram-bot:latest ." + }, + "dependencies": { + "https-proxy-agent": "^7.0.5", + "node-fetch": "^3.3.2", + "cloudflare-worker-adapter": "1.2.1" + }, + "devDependencies": { + "esbuild": "^0.23.0", + "toml": "^3.0.0" + } } diff --git a/adapter/local_v2/yarn.lock b/adapter/local_v2/yarn.lock index eb4f2883..0b643658 100644 --- a/adapter/local_v2/yarn.lock +++ b/adapter/local_v2/yarn.lock @@ -286,14 +286,15 @@ clean-stack@^2.0.0: resolved "https://registry.yarnpkg.com/clean-stack/-/clean-stack-2.2.0.tgz#ee8472dbb129e727b31e8a10a427dee9dfe4008b" integrity sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A== -cloudflare-worker-adapter@1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/cloudflare-worker-adapter/-/cloudflare-worker-adapter-1.0.3.tgz#c87dda4b9f036c1b6887e36b52dbc4da8de198a0" - integrity sha512-Eyd2JsmGvzSt46fG2spccARgIhlcTXcpPVGIwxpG9ocC229LVYtw+JZ1R6FbMUVplFjrPqNJ2zK+tqX2pkBoKw== +cloudflare-worker-adapter@1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/cloudflare-worker-adapter/-/cloudflare-worker-adapter-1.2.1.tgz#d96434d2b6e6ebe8ebb935ae010ec3006e5da990" + integrity sha512-XRIJes+dUkM65sTQa4OmdT5QAnmJgIZFdSLBAoc8cezzKZgfsUwldF9RgEDKxLWLyBvgZFugROo7Jgcoaz7NBw== dependencies: + https-proxy-agent "^7.0.5" ioredis "^5.4.1" node-fetch "^3.3.2" - sqlite3 "^5.1.7" + sqlite3 "^5" toml "^3.0.0" cluster-key-slot@^1.1.0: @@ -993,7 +994,7 @@ sprintf-js@^1.1.3: resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.1.3.tgz#4914b903a2f8b685d17fdf78a70e917e872e444a" integrity sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA== -sqlite3@^5.1.7: +sqlite3@^5: version "5.1.7" resolved "https://registry.yarnpkg.com/sqlite3/-/sqlite3-5.1.7.tgz#59ca1053c1ab38647396586edad019b1551041b7" integrity sha512-GGIyOiFaG+TUra3JIfkI/zGP8yZYLPQ0pl1bH+ODjiX57sPhrLU5sQJn1y9bDKZUFYkX1crlrPfSYt0BKKdkog== diff --git a/adapter/render/index.js b/adapter/render/index.js index 603cafab..a64ed99d 100644 --- a/adapter/render/index.js +++ b/adapter/render/index.js @@ -1,11 +1,10 @@ -import fs from 'fs'; +import fs from 'node:fs'; import adapter from 'cloudflare-worker-adapter'; -import {RedisCache} from 'cloudflare-worker-adapter/cache/redis.js'; - +import { RedisCache } from 'cloudflare-worker-adapter/redisCache'; const env = { ...process.env, - DATABASE: new RedisCache(process.env.REDIS_URL || 'redis://localhost:6379'), + DATABASE: RedisCache.createFromUri(process.env.REDIS_URL || 'redis://localhost:6379'), }; try { @@ -25,13 +24,13 @@ const bodyMethods = new Set(['POST', 'PUT', 'PATCH', 'DELETE']); * @returns {Request} */ function requestBuilder(baseURL, req) { - const reqHost = req.headers['x-forwarded-host'] || req.headers['host']; + const reqHost = req.headers['x-forwarded-host'] || req.headers.host; const reqScheme = req.headers['x-forwarded-proto'] || req.headers['x-scheme']; const method = req.method; const headers = req.headers; const body = bodyMethods.has(method) ? req : null; - const reqInit = {method, headers, body}; + const reqInit = { method, headers, body }; if (reqHost) { return new Request(`${reqScheme || 'http'}://${reqHost}${req.url}`, reqInit); @@ -41,5 +40,5 @@ function requestBuilder(baseURL, req) { } // 延迟加载 ../main.js, 防止ENV过早初始化 -const {default: worker} = await import('../../main.js'); -adapter.startServerV2(parseInt(env.PORT), env.HOST, env, {}, requestBuilder, worker.fetch); +const { default: worker } = await import('../../main.js'); +adapter.startServerV2(Number.parseInt(env.PORT), env.HOST, env, {}, requestBuilder, worker.fetch); diff --git a/adapter/render/package.json b/adapter/render/package.json index aff56a35..73d4db88 100644 --- a/adapter/render/package.json +++ b/adapter/render/package.json @@ -1,17 +1,16 @@ { - "name": "chatgpt-telegram-workers-to-render", - "version": "1.0.0", - "description": "render for chatgpt-telegram-workers", - "type": "module", - "main": "index.js", - "scripts": { - "lint": "eslint --fix --ext .js,.jsx,.mjs index.js", - "start": "node index.js", - "debug": "nodemon index.js" - }, - "author": "Cheivin", - "license": "ISC", - "dependencies": { - "cloudflare-worker-adapter": "github:TBXark/cloudflare-worker-adapter" - } + "name": "chatgpt-telegram-workers-to-render", + "type": "module", + "version": "1.0.0", + "description": "render for chatgpt-telegram-workers", + "author": "Cheivin", + "license": "ISC", + "main": "index.js", + "scripts": { + "start": "node index.js", + "debug": "nodemon index.js" + }, + "dependencies": { + "cloudflare-worker-adapter": "^1.2.1" + } } diff --git a/adapter/render/yarn.lock b/adapter/render/yarn.lock index a3a5df4f..b08c7511 100644 --- a/adapter/render/yarn.lock +++ b/adapter/render/yarn.lock @@ -45,6 +45,13 @@ agent-base@6, agent-base@^6.0.2: dependencies: debug "4" +agent-base@^7.0.2: + version "7.1.1" + resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-7.1.1.tgz#bdbded7dfb096b751a2a087eeeb9664725b2e317" + integrity sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA== + dependencies: + debug "^4.3.4" + agentkeepalive@^4.1.3: version "4.5.0" resolved "https://registry.yarnpkg.com/agentkeepalive/-/agentkeepalive-4.5.0.tgz#2673ad1389b3c418c5a20c5d7364f93ca04be923" @@ -159,13 +166,15 @@ clean-stack@^2.0.0: resolved "https://registry.yarnpkg.com/clean-stack/-/clean-stack-2.2.0.tgz#ee8472dbb129e727b31e8a10a427dee9dfe4008b" integrity sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A== -"cloudflare-worker-adapter@github:TBXark/cloudflare-worker-adapter": - version "1.0.1" - resolved "https://codeload.github.com/TBXark/cloudflare-worker-adapter/tar.gz/48062ba3705f5a282e9d45c85e84d8c5017231b5" +cloudflare-worker-adapter@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/cloudflare-worker-adapter/-/cloudflare-worker-adapter-1.2.1.tgz#d96434d2b6e6ebe8ebb935ae010ec3006e5da990" + integrity sha512-XRIJes+dUkM65sTQa4OmdT5QAnmJgIZFdSLBAoc8cezzKZgfsUwldF9RgEDKxLWLyBvgZFugROo7Jgcoaz7NBw== dependencies: + https-proxy-agent "^7.0.5" ioredis "^5.4.1" node-fetch "^3.3.2" - sqlite3 "^5.1.7" + sqlite3 "^5" toml "^3.0.0" cluster-key-slot@^1.1.0: @@ -361,6 +370,14 @@ https-proxy-agent@^5.0.0: agent-base "6" debug "4" +https-proxy-agent@^7.0.5: + version "7.0.5" + resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-7.0.5.tgz#9e8b5013873299e11fab6fd548405da2d6c602b2" + integrity sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw== + dependencies: + agent-base "^7.0.2" + debug "4" + humanize-ms@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/humanize-ms/-/humanize-ms-1.2.1.tgz#c46e3159a293f6b896da29316d8b6fe8bb79bbed" @@ -827,7 +844,7 @@ sprintf-js@^1.1.3: resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.1.3.tgz#4914b903a2f8b685d17fdf78a70e917e872e444a" integrity sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA== -sqlite3@^5.1.7: +sqlite3@^5: version "5.1.7" resolved "https://registry.yarnpkg.com/sqlite3/-/sqlite3-5.1.7.tgz#59ca1053c1ab38647396586edad019b1551041b7" integrity sha512-GGIyOiFaG+TUra3JIfkI/zGP8yZYLPQ0pl1bH+ODjiX57sPhrLU5sQJn1y9bDKZUFYkX1crlrPfSYt0BKKdkog== diff --git a/adapter/script/esbuild.config.js b/adapter/script/esbuild.config.js index 55b0d792..b008474f 100644 --- a/adapter/script/esbuild.config.js +++ b/adapter/script/esbuild.config.js @@ -1,7 +1,6 @@ +import { execSync } from 'node:child_process'; +import * as fs from 'node:fs/promises'; import esbuild from 'esbuild'; -import {execSync} from 'child_process'; -import fs from 'fs/promises'; - /** * Build the project @@ -9,7 +8,6 @@ import fs from 'fs/promises'; * @param {string} output - path to output file */ export async function build(info, output) { - let COMMIT_HASH = execSync('git rev-parse --short HEAD').toString().trim(); let TIMESTAMP = Math.floor(Date.now() / 1000); diff --git a/adapter/vercel/package.json b/adapter/vercel/package.json index 787d8c33..d2504a15 100644 --- a/adapter/vercel/package.json +++ b/adapter/vercel/package.json @@ -1,23 +1,23 @@ { - "name": "vercel", - "version": "1.0.0", - "description": "", - "main": "index.js", - "type": "module", - "scripts": { - "init": "node ./utils/init.js", - "dev": "vercel dev", - "deploy": "node ./utils/env.js && sh deploy.sh" - }, - "author": "TBXark", - "license": "MIT", - "dependencies": { - "chatgpt-telegram-workers": "github:TBXark/ChatGPT-Telegram-Workers", - "cloudflare-worker-adapter": "github:TBXark/cloudflare-worker-adapter" - }, - "devDependencies": { - "dotenv": "^16.0.3", - "toml": "^3.0.0", - "vercel": "^28.16.15" - } + "name": "vercel", + "type": "module", + "version": "1.0.0", + "description": "", + "author": "TBXark", + "license": "MIT", + "main": "index.js", + "scripts": { + "init": "node ./utils/init.js", + "dev": "vercel dev", + "deploy": "node ./utils/env.js && sh deploy.sh" + }, + "dependencies": { + "chatgpt-telegram-workers": "^1.7.0", + "cloudflare-worker-adapter": "^1.2.1" + }, + "devDependencies": { + "dotenv": "^16.0.3", + "toml": "^3.0.0", + "vercel": "^28.16.15" + } } diff --git a/adapter/vercel/src/index.js b/adapter/vercel/src/index.js index 5b61ff6d..8b8233d2 100644 --- a/adapter/vercel/src/index.js +++ b/adapter/vercel/src/index.js @@ -1,10 +1,10 @@ import worker from 'chatgpt-telegram-workers'; -import {RedisCache} from 'cloudflare-worker-adapter/cache/redis.js'; +import { RedisCache } from 'cloudflare-worker-adapter/redisCache'; // cloudflare to vercel adapter export default async (req, res) => { console.log(`${req.method} ${req.url}`); - const redis = new RedisCache(process.env.REDIS_URL); + const redis = RedisCache.createFromUri(process.env.REDIS_URL); const env = { ...Object.assign({}, process.env), DATABASE: redis, @@ -16,7 +16,7 @@ export default async (req, res) => { body: JSON.stringify(req.body), }); const resp = await worker.fetch(cfReq, env); - redis.close(); + await redis.close(); res.status(resp.status); for (const [key, value] of resp.headers) { res.setHeader(key, value); diff --git a/adapter/vercel/utils/env.js b/adapter/vercel/utils/env.js index 4a789e00..f222a7a6 100644 --- a/adapter/vercel/utils/env.js +++ b/adapter/vercel/utils/env.js @@ -1,4 +1,4 @@ -import fs from 'fs'; +import fs from 'node:fs'; import dotenv from 'dotenv'; const env = dotenv.parse(fs.readFileSync('.env', 'utf-8')) || {}; diff --git a/adapter/vercel/utils/init.js b/adapter/vercel/utils/init.js index b53b98f8..bfc640e7 100644 --- a/adapter/vercel/utils/init.js +++ b/adapter/vercel/utils/init.js @@ -1,15 +1,14 @@ -import fs from 'fs'; +import fs from 'node:fs'; import toml from 'toml'; import dotenv from 'dotenv'; -const tryWithDefault = (fn, defaultValue) => { +function tryWithDefault(fn, defaultValue) { try { return fn(); - // eslint-disable-next-line no-unused-vars - } catch (e) { + } catch { return defaultValue; } -}; +} const env = tryWithDefault(() => dotenv.parse(fs.readFileSync('.env', 'utf-8')), {}); const wranglerConfig = toml.parse(fs.readFileSync('../../wrangler.toml', 'utf-8')).vars; diff --git a/adapter/vercel/vercel.json b/adapter/vercel/vercel.json index e6e44a59..bbad6d82 100644 --- a/adapter/vercel/vercel.json +++ b/adapter/vercel/vercel.json @@ -4,6 +4,6 @@ { "src": "src/**", "use": "@vercel/node" } ], "routes": [ - { "src": "/(.*)", "dest": "/src" } + { "src": "/(.*)", "dest": "/src" } ] - } \ No newline at end of file +} diff --git a/adapter/vercel/yarn.lock b/adapter/vercel/yarn.lock index aa369187..fe6a0f29 100644 --- a/adapter/vercel/yarn.lock +++ b/adapter/vercel/yarn.lock @@ -2091,6 +2091,13 @@ agent-base@6, agent-base@^6.0.0, agent-base@^6.0.2: dependencies: debug "4" +agent-base@^7.0.2: + version "7.1.1" + resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-7.1.1.tgz#bdbded7dfb096b751a2a087eeeb9664725b2e317" + integrity sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA== + dependencies: + debug "^4.3.4" + agentkeepalive@^4.1.3: version "4.5.0" resolved "https://registry.yarnpkg.com/agentkeepalive/-/agentkeepalive-4.5.0.tgz#2673ad1389b3c418c5a20c5d7364f93ca04be923" @@ -2478,9 +2485,10 @@ chardet@^0.7.0: resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e" integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA== -"chatgpt-telegram-workers@github:TBXark/ChatGPT-Telegram-Workers": +chatgpt-telegram-workers@^1.7.0: version "1.7.0" - resolved "https://codeload.github.com/TBXark/ChatGPT-Telegram-Workers/tar.gz/bd2c707a6fe83f7a080b9206ed2668e4340ccbd5" + resolved "https://registry.yarnpkg.com/chatgpt-telegram-workers/-/chatgpt-telegram-workers-1.7.0.tgz#c02241280b4761b486f5674154c7d73e602ba3ad" + integrity sha512-yoC7xygwMeoaudhDSHgSs09kWDlp9vKasEnAZx811TRZP/6ssMaoLabvm8MSZJyTwli6NHuAEiXEJl1UAil5hA== chokidar@^3.5.1: version "3.6.0" @@ -2541,13 +2549,15 @@ clone@^1.0.2: resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.4.tgz#da309cc263df15994c688ca902179ca3c7cd7c7e" integrity sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg== -"cloudflare-worker-adapter@github:TBXark/cloudflare-worker-adapter": - version "1.0.1" - resolved "https://codeload.github.com/TBXark/cloudflare-worker-adapter/tar.gz/48062ba3705f5a282e9d45c85e84d8c5017231b5" +cloudflare-worker-adapter@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/cloudflare-worker-adapter/-/cloudflare-worker-adapter-1.2.1.tgz#d96434d2b6e6ebe8ebb935ae010ec3006e5da990" + integrity sha512-XRIJes+dUkM65sTQa4OmdT5QAnmJgIZFdSLBAoc8cezzKZgfsUwldF9RgEDKxLWLyBvgZFugROo7Jgcoaz7NBw== dependencies: + https-proxy-agent "^7.0.5" ioredis "^5.4.1" node-fetch "^3.3.2" - sqlite3 "^5.1.7" + sqlite3 "^5" toml "^3.0.0" cluster-key-slot@^1.1.0: @@ -3812,6 +3822,14 @@ https-proxy-agent@5, https-proxy-agent@^5.0.0: agent-base "6" debug "4" +https-proxy-agent@^7.0.5: + version "7.0.5" + resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-7.0.5.tgz#9e8b5013873299e11fab6fd548405da2d6c602b2" + integrity sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw== + dependencies: + agent-base "^7.0.2" + debug "4" + human-signals@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0" @@ -6055,7 +6073,7 @@ sprintf-js@^1.1.3: resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.1.3.tgz#4914b903a2f8b685d17fdf78a70e917e872e444a" integrity sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA== -sqlite3@^5.1.7: +sqlite3@^5: version "5.1.7" resolved "https://registry.yarnpkg.com/sqlite3/-/sqlite3-5.1.7.tgz#59ca1053c1ab38647396586edad019b1551041b7" integrity sha512-GGIyOiFaG+TUra3JIfkI/zGP8yZYLPQ0pl1bH+ODjiX57sPhrLU5sQJn1y9bDKZUFYkX1crlrPfSYt0BKKdkog== diff --git a/dist/.eslintignore b/dist/.eslintignore deleted file mode 100644 index e69de29b..00000000 diff --git a/dist/buildinfo.json b/dist/buildinfo.json index af7b8bd4..697687f0 100644 --- a/dist/buildinfo.json +++ b/dist/buildinfo.json @@ -1 +1 @@ -{"sha":"bf2448f","timestamp":1723602033} \ No newline at end of file +{"sha":"fe8b5b6","timestamp":1724122033} \ No newline at end of file diff --git a/dist/index.js b/dist/index.js index 5973763d..c7877eed 100644 --- a/dist/index.js +++ b/dist/index.js @@ -1,132 +1,53 @@ -// src/config/env.js -var UserConfig = class { - // -- 非配置属性 -- +class UserConfig { DEFINE_KEYS = []; - // -- 通用配置 -- - // - // AI提供商: auto, openai, azure, workers, gemini, mistral AI_PROVIDER = "auto"; - // AI图片提供商: auto, openai, azure, workers AI_IMAGE_PROVIDER = "auto"; - // 全局默认初始化消息 SYSTEM_INIT_MESSAGE = null; - // 全局默认初始化消息角色 SYSTEM_INIT_MESSAGE_ROLE = "system"; - // -- Open AI 配置 -- - // - // OpenAI API Key OPENAI_API_KEY = []; - // OpenAI的模型名称 OPENAI_CHAT_MODEL = "gpt-4o-mini"; - // OpenAI API BASE `` OPENAI_API_BASE = "https://api.openai.com/v1"; - // OpenAI API Extra Params OPENAI_API_EXTRA_PARAMS = {}; - // -- DALLE 配置 -- - // - // DALL-E的模型名称 DALL_E_MODEL = "dall-e-2"; - // DALL-E图片尺寸 DALL_E_IMAGE_SIZE = "512x512"; - // DALL-E图片质量 DALL_E_IMAGE_QUALITY = "standard"; - // DALL-E图片风格 DALL_E_IMAGE_STYLE = "vivid"; - // -- AZURE 配置 -- - // - // Azure API Key AZURE_API_KEY = null; - // Azure Completions API - // https://RESOURCE_NAME.openai.azure.com/openai/deployments/MODEL_NAME/chat/completions?api-version=VERSION_NAME AZURE_COMPLETIONS_API = null; - // Azure DallE API - // https://RESOURCE_NAME.openai.azure.com/openai/deployments/MODEL_NAME/images/generations?api-version=VERSION_NAME AZURE_DALLE_API = null; - // -- Workers 配置 -- - // - // Cloudflare Account ID CLOUDFLARE_ACCOUNT_ID = null; - // Cloudflare Token CLOUDFLARE_TOKEN = null; - // Text Generation Model WORKERS_CHAT_MODEL = "@cf/mistral/mistral-7b-instruct-v0.1 "; - // Text-to-Image Model WORKERS_IMAGE_MODEL = "@cf/stabilityai/stable-diffusion-xl-base-1.0"; - // -- Gemini 配置 -- - // - // Google Gemini API Key GOOGLE_API_KEY = null; - // Google Gemini API GOOGLE_COMPLETIONS_API = "https://generativelanguage.googleapis.com/v1beta/models/"; - // Google Gemini Model GOOGLE_COMPLETIONS_MODEL = "gemini-pro"; - // -- Mistral 配置 -- - // - // mistral api key MISTRAL_API_KEY = null; - // mistral api base MISTRAL_API_BASE = "https://api.mistral.ai/v1"; - // mistral api model MISTRAL_CHAT_MODEL = "mistral-tiny"; - // -- Cohere 配置 -- - // - // cohere api key COHERE_API_KEY = null; - // cohere api base COHERE_API_BASE = "https://api.cohere.com/v1"; - // cohere api model COHERE_CHAT_MODEL = "command-r-plus"; - // -- Anthropic 配置 -- - // - // Anthropic api key ANTHROPIC_API_KEY = null; - // Anthropic api base ANTHROPIC_API_BASE = "https://api.anthropic.com/v1"; - // Anthropic api model ANTHROPIC_CHAT_MODEL = "claude-3-haiku-20240307"; -}; -var Environment = class { - // -- 版本数据 -- - // - // 当前版本 - BUILD_TIMESTAMP = 1723602033; - // 当前版本 commit id - BUILD_VERSION = "bf2448f"; - // -- 基础配置 -- - /** - * @type {I18n | null} - */ +} +class Environment { + BUILD_TIMESTAMP = 1724122033 ; + BUILD_VERSION = "fe8b5b6" ; I18N = null; - // 多语言支持 LANGUAGE = "zh-cn"; - // 检查更新的分支 UPDATE_BRANCH = "master"; - // Chat Complete API Timeout CHAT_COMPLETE_API_TIMEOUT = 0; - // -- Telegram 相关 -- - // - // Telegram API Domain TELEGRAM_API_DOMAIN = "https://api.telegram.org"; - // 允许访问的Telegram Token, 设置时以逗号分隔 TELEGRAM_AVAILABLE_TOKENS = []; - // 默认消息模式 DEFAULT_PARSE_MODE = "Markdown"; - // 最小stream模式消息间隔,小于等于0则不限制 TELEGRAM_MIN_STREAM_INTERVAL = 0; - // 图片尺寸偏移 0为第一位,-1为最后一位, 越靠后的图片越大。PS: 图片过大可能导致token消耗过多,或者workers超时或内存不足 - // 默认选择次低质量的图片 TELEGRAM_PHOTO_SIZE_OFFSET = 1; - // 向LLM优先传递图片方式:url, base64 TELEGRAM_IMAGE_TRANSFER_MODE = "url"; - // -- 权限相关 -- - // - // 允许所有人使用 I_AM_A_GENEROUS_PERSON = false; - // 白名单 CHAT_WHITE_LIST = []; - // 用户配置 LOCK_USER_CONFIG_KEYS = [ - // 默认为API BASE 防止被替换导致token 泄露 "OPENAI_API_BASE", "GOOGLE_COMPLETIONS_API", "MISTRAL_API_BASE", @@ -135,56 +56,34 @@ var Environment = class { "AZURE_COMPLETIONS_API", "AZURE_DALLE_API" ]; - // -- 群组相关 -- - // - // 允许访问的Telegram Token 对应的Bot Name, 设置时以逗号分隔 TELEGRAM_BOT_NAME = []; - // 群组白名单 CHAT_GROUP_WHITE_LIST = []; - // 群组机器人开关 GROUP_CHAT_BOT_ENABLE = true; - // 群组机器人共享模式,关闭后,一个群组只有一个会话和配置。开启的话群组的每个人都有自己的会话上下文 GROUP_CHAT_BOT_SHARE_MODE = true; - // -- 历史记录相关 -- - // - // 为了避免4096字符限制,将消息删减 AUTO_TRIM_HISTORY = true; - // 最大历史记录长度 MAX_HISTORY_LENGTH = 20; - // 最大消息长度 MAX_TOKEN_LENGTH = -1; - // -- 特性开关 -- - // - // 隐藏部分命令按钮 + HISTORY_IMAGE_PLACEHOLDER = null; HIDE_COMMAND_BUTTONS = []; - // 显示快捷回复按钮 SHOW_REPLY_BUTTON = false; - // 而外引用消息开关 EXTRA_MESSAGE_CONTEXT = false; - // 开启Telegraph图床 TELEGRAPH_ENABLE = false; - // -- 模式开关 -- - // - // 使用流模式 STREAM_MODE = true; - // 安全模式 SAFE_MODE = true; - // 调试模式 DEBUG_MODE = false; - // 开发模式 DEV_MODE = false; USER_CONFIG = new UserConfig(); -}; -var ENV = new Environment(); -var DATABASE = null; -var API_GUARD = null; -var CUSTOM_COMMAND = {}; -var CUSTOM_COMMAND_DESCRIPTION = {}; -var CONST = { +} +const ENV = new Environment(); +let DATABASE = null; +let API_GUARD = null; +const CUSTOM_COMMAND = {}; +const CUSTOM_COMMAND_DESCRIPTION = {}; +const CONST = { PASSWORD_KEY: "chat_history_password", GROUP_TYPES: ["group", "supergroup"] }; -var ENV_TYPES = { +const ENV_TYPES = { SYSTEM_INIT_MESSAGE: "string", AZURE_API_KEY: "string", AZURE_COMPLETIONS_API: "string", @@ -194,14 +93,19 @@ var ENV_TYPES = { GOOGLE_API_KEY: "string", MISTRAL_API_KEY: "string", COHERE_API_KEY: "string", - ANTHROPIC_API_KEY: "string" + ANTHROPIC_API_KEY: "string", + HISTORY_IMAGE_PLACEHOLDER: "string" }; -var ENV_KEY_MAPPER = { +const ENV_KEY_MAPPER = { CHAT_MODEL: "OPENAI_CHAT_MODEL", API_KEY: "OPENAI_API_KEY", WORKERS_AI_MODEL: "WORKERS_CHAT_MODEL" }; function parseArray(raw) { + raw = raw.trim(); + if (raw === "") { + return []; + } if (raw.startsWith("[") && raw.endsWith("]")) { try { return JSON.parse(raw); @@ -224,7 +128,7 @@ function mergeEnvironment(target, source) { } switch (t) { case "number": - target[key] = parseInt(source[key], 10); + target[key] = Number.parseInt(source[key], 10); break; case "boolean": target[key] = (source[key] || "false") === "true"; @@ -252,7 +156,7 @@ function mergeEnvironment(target, source) { } } } -function initEnv(env, i18n2) { +function initEnv(env, i18n) { DATABASE = env.DATABASE; API_GUARD = env.API_GUARD; const customCommandPrefix = "CUSTOM_COMMAND_"; @@ -260,2471 +164,2305 @@ function initEnv(env, i18n2) { for (const key of Object.keys(env)) { if (key.startsWith(customCommandPrefix)) { const cmd = key.substring(customCommandPrefix.length); - CUSTOM_COMMAND["/" + cmd] = env[key]; - CUSTOM_COMMAND_DESCRIPTION["/" + cmd] = env[customCommandDescriptionPrefix + cmd]; + CUSTOM_COMMAND[`/${cmd}`] = env[key]; + CUSTOM_COMMAND_DESCRIPTION[`/${cmd}`] = env[customCommandDescriptionPrefix + cmd]; } } mergeEnvironment(ENV, env); mergeEnvironment(ENV.USER_CONFIG, env); + migrateOldEnv(env, i18n); ENV.USER_CONFIG.DEFINE_KEYS = []; - { - ENV.I18N = i18n2((ENV.LANGUAGE || "cn").toLowerCase()); - if (env.TELEGRAM_TOKEN && !ENV.TELEGRAM_AVAILABLE_TOKENS.includes(env.TELEGRAM_TOKEN)) { - if (env.BOT_NAME && ENV.TELEGRAM_AVAILABLE_TOKENS.length === ENV.TELEGRAM_BOT_NAME.length) { - ENV.TELEGRAM_BOT_NAME.push(env.BOT_NAME); - } - ENV.TELEGRAM_AVAILABLE_TOKENS.push(env.TELEGRAM_TOKEN); +} +function migrateOldEnv(env, i18n) { + ENV.I18N = i18n((ENV.LANGUAGE || "cn").toLowerCase()); + if (env.TELEGRAM_TOKEN && !ENV.TELEGRAM_AVAILABLE_TOKENS.includes(env.TELEGRAM_TOKEN)) { + if (env.BOT_NAME && ENV.TELEGRAM_AVAILABLE_TOKENS.length === ENV.TELEGRAM_BOT_NAME.length) { + ENV.TELEGRAM_BOT_NAME.push(env.BOT_NAME); } - if (env.OPENAI_API_DOMAIN && !ENV.OPENAI_API_BASE) { - ENV.USER_CONFIG.OPENAI_API_BASE = `${env.OPENAI_API_DOMAIN}/v1`; + ENV.TELEGRAM_AVAILABLE_TOKENS.push(env.TELEGRAM_TOKEN); + } + if (env.OPENAI_API_DOMAIN && !ENV.OPENAI_API_BASE) { + ENV.USER_CONFIG.OPENAI_API_BASE = `${env.OPENAI_API_DOMAIN}/v1`; + } + if (env.WORKERS_AI_MODEL && !ENV.USER_CONFIG.WORKERS_CHAT_MODEL) { + ENV.USER_CONFIG.WORKERS_CHAT_MODEL = env.WORKERS_AI_MODEL; + } + if (env.API_KEY && ENV.USER_CONFIG.OPENAI_API_KEY.length === 0) { + ENV.USER_CONFIG.OPENAI_API_KEY = env.API_KEY.split(","); + } + if (env.CHAT_MODEL && !ENV.USER_CONFIG.OPENAI_CHAT_MODEL) { + ENV.USER_CONFIG.OPENAI_CHAT_MODEL = env.CHAT_MODEL; + } + if (!ENV.USER_CONFIG.SYSTEM_INIT_MESSAGE) { + ENV.USER_CONFIG.SYSTEM_INIT_MESSAGE = ENV.I18N?.env?.system_init_message || "You are a helpful assistant"; + } +} + +function trimUserConfig(userConfig) { + const config = { + ...(userConfig || {}), + }; + const keysSet = new Set(userConfig?.DEFINE_KEYS || []); + for (const key of ENV.LOCK_USER_CONFIG_KEYS) { + keysSet.delete(key); + } + keysSet.add('DEFINE_KEYS'); + for (const key of Object.keys(config)) { + if (!keysSet.has(key)) { + delete config[key]; + } } - if (env.WORKERS_AI_MODEL && !ENV.USER_CONFIG.WORKERS_CHAT_MODEL) { - ENV.USER_CONFIG.WORKERS_CHAT_MODEL = env.WORKERS_AI_MODEL; + return config; +} +class ShareContext { + currentBotId = null; + currentBotToken = null; + currentBotName = null; + chatHistoryKey = null; + chatLastMessageIdKey = null; + configStoreKey = null; + groupAdminKey = null; + usageKey = null; + chatType = null; + chatId = null; + speakerId = null; + extraMessageContext = null; + allMemberAreAdmin = false; +} +class CurrentChatContext { + chat_id = null; + reply_to_message_id = null; + parse_mode = ENV.DEFAULT_PARSE_MODE; + message_id = null; + reply_markup = null; + allow_sending_without_reply = null; + disable_web_page_preview = null; +} +class Context { + USER_CONFIG = new UserConfig(); + CURRENT_CHAT_CONTEXT = new CurrentChatContext(); + SHARE_CONTEXT = new ShareContext(); + _initChatContext(chatId, replyToMessageId) { + this.CURRENT_CHAT_CONTEXT.chat_id = chatId; + this.CURRENT_CHAT_CONTEXT.reply_to_message_id = replyToMessageId; + if (replyToMessageId) { + this.CURRENT_CHAT_CONTEXT.allow_sending_without_reply = true; + } } - if (env.API_KEY && ENV.USER_CONFIG.OPENAI_API_KEY.length === 0) { - ENV.USER_CONFIG.OPENAI_API_KEY = env.API_KEY.split(","); + async _initUserConfig(storeKey) { + try { + this.USER_CONFIG = { + ...ENV.USER_CONFIG, + }; + const userConfig = JSON.parse(await DATABASE.get(storeKey)); + mergeEnvironment(this.USER_CONFIG, trimUserConfig(userConfig)); + } catch (e) { + console.error(e); + } } - if (env.CHAT_MODEL && !ENV.USER_CONFIG.OPENAI_CHAT_MODEL) { - ENV.USER_CONFIG.OPENAI_CHAT_MODEL = env.CHAT_MODEL; + initTelegramContext(token) { + const telegramIndex = ENV.TELEGRAM_AVAILABLE_TOKENS.indexOf(token); + if (telegramIndex === -1) { + throw new Error('Token not allowed'); + } + this.SHARE_CONTEXT.currentBotToken = token; + this.SHARE_CONTEXT.currentBotId = token.split(':')[0]; + if (ENV.TELEGRAM_BOT_NAME.length > telegramIndex) { + this.SHARE_CONTEXT.currentBotName = ENV.TELEGRAM_BOT_NAME[telegramIndex]; + } } - if (!ENV.USER_CONFIG.SYSTEM_INIT_MESSAGE) { - ENV.USER_CONFIG.SYSTEM_INIT_MESSAGE = ENV.I18N?.env?.system_init_message || "You are a helpful assistant"; + async _initShareContext(message) { + this.SHARE_CONTEXT.usageKey = `usage:${this.SHARE_CONTEXT.currentBotId}`; + const id = message?.chat?.id; + if (id === undefined || id === null) { + throw new Error('Chat id not found'); + } + const botId = this.SHARE_CONTEXT.currentBotId; + let historyKey = `history:${id}`; + let configStoreKey = `user_config:${id}`; + let groupAdminKey = null; + if (botId) { + historyKey += `:${botId}`; + configStoreKey += `:${botId}`; + } + if (CONST.GROUP_TYPES.includes(message.chat?.type)) { + if (!ENV.GROUP_CHAT_BOT_SHARE_MODE && message.from.id) { + historyKey += `:${message.from.id}`; + configStoreKey += `:${message.from.id}`; + } + groupAdminKey = `group_admin:${id}`; + } + if (message?.chat?.is_forum && message?.is_topic_message) { + if (message?.message_thread_id) { + historyKey += `:${message.message_thread_id}`; + configStoreKey += `:${message.message_thread_id}`; + } + } + this.SHARE_CONTEXT.chatHistoryKey = historyKey; + this.SHARE_CONTEXT.chatLastMessageIdKey = `last_message_id:${historyKey}`; + this.SHARE_CONTEXT.configStoreKey = configStoreKey; + this.SHARE_CONTEXT.groupAdminKey = groupAdminKey; + this.SHARE_CONTEXT.chatType = message.chat?.type; + this.SHARE_CONTEXT.chatId = message.chat.id; + this.SHARE_CONTEXT.speakerId = message.from.id || message.chat.id; + this.SHARE_CONTEXT.allMemberAreAdmin = message?.chat?.all_members_are_administrators; + } + async initContext(message) { + const chatId = message?.chat?.id; + const replyId = CONST.GROUP_TYPES.includes(message.chat?.type) ? message.message_id : null; + this._initChatContext(chatId, replyId); + await this._initShareContext(message); + await this._initUserConfig(this.SHARE_CONTEXT.configStoreKey); } - } } -// src/config/context.js -function trimUserConfig(userConfig) { - const config = { - ...userConfig - }; - const keysSet = new Set(userConfig.DEFINE_KEYS); - for (const key of ENV.LOCK_USER_CONFIG_KEYS) { - keysSet.delete(key); - } - keysSet.add("DEFINE_KEYS"); - for (const key of Object.keys(config)) { - if (!keysSet.has(key)) { - delete config[key]; +class Cache { + constructor() { + this.maxItems = 10; + this.maxAge = 1000 * 60 * 60; + this.cache = {}; + } + set(key, value) { + this.trim(); + this.cache[key] = { + value, + time: Date.now(), + }; } - } - return config; -} -var ShareContext = class { - currentBotId = null; - currentBotToken = null; - currentBotName = null; - chatHistoryKey = null; - chatLastMessageIdKey = null; - configStoreKey = null; - groupAdminKey = null; - usageKey = null; - chatType = null; - chatId = null; - speakerId = null; - extraMessageContext = null; -}; -var CurrentChatContext = class { - chat_id = null; - reply_to_message_id = null; - parse_mode = ENV.DEFAULT_PARSE_MODE; - message_id = null; - reply_markup = null; - allow_sending_without_reply = null; - disable_web_page_preview = null; -}; -var Context = class { - // 用户配置 - USER_CONFIG = new UserConfig(); - CURRENT_CHAT_CONTEXT = new CurrentChatContext(); - SHARE_CONTEXT = new ShareContext(); - /** - * @inner - * @param {string | number} chatId - * @param {string | number} replyToMessageId - */ - _initChatContext(chatId, replyToMessageId) { - this.CURRENT_CHAT_CONTEXT.chat_id = chatId; - this.CURRENT_CHAT_CONTEXT.reply_to_message_id = replyToMessageId; - if (replyToMessageId) { - this.CURRENT_CHAT_CONTEXT.allow_sending_without_reply = true; + get(key) { + this.trim(); + return this.cache[key]?.value; } - } - // - /** - * 初始化用户配置 - * @inner - * @param {string | null} storeKey - */ - async _initUserConfig(storeKey) { + trim() { + let keys = Object.keys(this.cache); + for (const key of keys) { + if (Date.now() - this.cache[key].time > this.maxAge) { + delete this.cache[key]; + } + } + keys = Object.keys(this.cache); + if (keys.length > this.maxItems) { + keys.sort((a, b) => this.cache[a].time - this.cache[b].time); + for (let i = 0; i < keys.length - this.maxItems; i++) { + delete this.cache[keys[i]]; + } + } + } +} + +const IMAGE_CACHE = new Cache(); +async function fetchImage(url) { + if (IMAGE_CACHE[url]) { + return IMAGE_CACHE.get(url); + } + return fetch(url) + .then(resp => resp.blob()) + .then((blob) => { + IMAGE_CACHE.set(url, blob); + return blob; + }); +} +async function uploadImageToTelegraph(url) { + if (url.startsWith('https://telegra.ph')) { + return url; + } + const raw = await fetchImage(url); + const formData = new FormData(); + formData.append('file', raw, 'blob'); + const resp = await fetch('https://telegra.ph/upload', { + method: 'POST', + body: formData, + }); + let [{ src }] = await resp.json(); + src = `https://telegra.ph${src}`; + IMAGE_CACHE.set(src, raw); + return src; +} +async function urlToBase64String(url) { try { - this.USER_CONFIG = { - ...ENV.USER_CONFIG - }; - const userConfig = JSON.parse(await DATABASE.get(storeKey)); - mergeEnvironment(this.USER_CONFIG, trimUserConfig(userConfig)); - } catch (e) { - console.error(e); + const { Buffer } = await import('node:buffer'); + return fetchImage(url) + .then(blob => blob.arrayBuffer()) + .then(buffer => Buffer.from(buffer).toString('base64')); + } catch { + return fetchImage(url) + .then(blob => blob.arrayBuffer()) + .then(buffer => btoa(String.fromCharCode.apply(null, new Uint8Array(buffer)))); } - } - /** - * @param {string} token - */ - initTelegramContext(token) { - const telegramIndex = ENV.TELEGRAM_AVAILABLE_TOKENS.indexOf(token); - if (telegramIndex === -1) { - throw new Error("Token not allowed"); - } - this.SHARE_CONTEXT.currentBotToken = token; - this.SHARE_CONTEXT.currentBotId = token.split(":")[0]; - if (ENV.TELEGRAM_BOT_NAME.length > telegramIndex) { - this.SHARE_CONTEXT.currentBotName = ENV.TELEGRAM_BOT_NAME[telegramIndex]; +} +function getImageFormatFromBase64(base64String) { + const firstChar = base64String.charAt(0); + switch (firstChar) { + case '/': + return 'jpeg'; + case 'i': + return 'png'; + case 'R': + return 'gif'; + case 'U': + return 'webp'; + default: + throw new Error('Unsupported image format'); } - } - /** - * - * @inner - * @param {TelegramMessage} message - */ - async _initShareContext(message) { - this.SHARE_CONTEXT.usageKey = `usage:${this.SHARE_CONTEXT.currentBotId}`; - const id = message?.chat?.id; - if (id === void 0 || id === null) { - throw new Error("Chat id not found"); - } - const botId = this.SHARE_CONTEXT.currentBotId; - let historyKey = `history:${id}`; - let configStoreKey = `user_config:${id}`; - let groupAdminKey = null; - if (botId) { - historyKey += `:${botId}`; - configStoreKey += `:${botId}`; - } - if (CONST.GROUP_TYPES.includes(message.chat?.type)) { - if (!ENV.GROUP_CHAT_BOT_SHARE_MODE && message.from.id) { - historyKey += `:${message.from.id}`; - configStoreKey += `:${message.from.id}`; +} +async function imageToBase64String(url) { + const base64String = await urlToBase64String(url); + const format = getImageFormatFromBase64(base64String); + return { + data: base64String, + format: `image/${format}`, + }; +} +function renderBase64DataURI(params) { + return `data:${params.format};base64,${params.data}`; +} + +function renderHTML(body) { + return ` + + + ChatGPT-Telegram-Workers + + + + + + + + ${body} + + + `; +} +function errorToString(e) { + return JSON.stringify({ + message: e.message, + stack: e.stack, + }); +} +function makeResponse200(resp) { + if (resp === null) { + return new Response('NOT HANDLED', { status: 200 }); } - this.SHARE_CONTEXT.chatHistoryKey = historyKey; - this.SHARE_CONTEXT.chatLastMessageIdKey = `last_message_id:${historyKey}`; - this.SHARE_CONTEXT.configStoreKey = configStoreKey; - this.SHARE_CONTEXT.groupAdminKey = groupAdminKey; - this.SHARE_CONTEXT.chatType = message.chat?.type; - this.SHARE_CONTEXT.chatId = message.chat.id; - this.SHARE_CONTEXT.speakerId = message.from.id || message.chat.id; - } - /** - * @param {TelegramMessage} message - * @returns {Promise} - */ - async initContext(message) { - const chatId = message?.chat?.id; - const replyId = CONST.GROUP_TYPES.includes(message.chat?.type) ? message.message_id : null; - this._initChatContext(chatId, replyId); - await this._initShareContext(message); - await this._initUserConfig(this.SHARE_CONTEXT.configStoreKey); - } -}; + if (resp.status === 200) { + return resp; + } else { + return new Response(resp.body, { + status: 200, + headers: { + 'Original-Status': resp.status, + ...resp.headers, + }, + }); + } +} -// src/utils/md2tgmd.js -var escapeChars = /([\_\*\[\]\(\)\\\~\`\>\#\+\-\=\|\{\}\.\!])/g; +const escapeChars = /([_*[\]()\\~`>#+\-=|{}.!])/g; function escape(text) { - const lines = text.split("\n"); - const stack = []; - const result = []; - let linetrim = ""; - for (const [i, line] of lines.entries()) { - linetrim = line.trim(); - let startIndex; - if (/^```.+/.test(linetrim)) { - stack.push(i); - } else if (linetrim === "```") { - if (stack.length) { - startIndex = stack.pop(); + const lines = text.split('\n'); + const stack = []; + const result = []; + let linetrim = ''; + for (const [i, line] of lines.entries()) { + linetrim = line.trim(); + let startIndex; + if (/^```.+/.test(linetrim)) { + stack.push(i); + } else if (linetrim === '```') { + if (stack.length) { + startIndex = stack.pop(); + if (!stack.length) { + const content = lines.slice(startIndex, i + 1).join('\n'); + result.push(handleEscape(content, 'code')); + continue; + } + } else { + stack.push(i); + } + } if (!stack.length) { - const content = lines.slice(startIndex, i + 1).join("\n"); - result.push(handleEscape(content, "code")); - continue; + result.push(handleEscape(line)); } - } else { - stack.push(i); - } } - if (!stack.length) { - result.push(handleEscape(line)); + if (stack.length) { + const last = `${lines.slice(stack[0]).join('\n')}\n\`\`\``; + result.push(handleEscape(last, 'code')); + } + return result.join('\n'); +} +function handleEscape(text, type = 'text') { + if (!text.trim()) { + return text; + } + if (type === 'text') { + text = text + .replace(escapeChars, '\\$1') + .replace(/\\\*\\\*(.*?[^\\])\\\*\\\*/g, '*$1*') + .replace(/\\_\\_(.*?[^\\])\\_\\_/g, '__$1__') + .replace(/\\_(.*?[^\\])\\_/g, '_$1_') + .replace(/\\~(.*?[^\\])\\~/g, '~$1~') + .replace(/\\\|\\\|(.*?[^\\])\\\|\\\|/g, '||$1||') + .replace(/\\\[([^\]]+?)\\\]\\\((.+?)\\\)/g, '[$1]($2)') + .replace(/\\`(.*?[^\\])\\`/g, '`$1`') + .replace(/\\\\\\([_*[\]()\\~`>#+\-=|{}.!])/g, '\\$1') + .replace(/^(\s*)\\(>.+\s*)$/gm, '$1$2') + .replace(/^(\s*)\\-\s*(.+)$/gm, '$1• $2') + .replace(/^((\\#){1,3}\s)(.+)/gm, '$1*$3*'); + } else { + const codeBlank = text.length - text.trimStart().length; + if (codeBlank > 0) { + const blankReg = new RegExp(`^\\s{${codeBlank}}`, 'gm'); + text = text.replace(blankReg, ''); + } + text = text + .trimEnd() + .replace(/([\\`])/g, '\\$1') + .replace(/^\\`\\`\\`([\s\S]+)\\`\\`\\`$/g, '```$1```'); } - } - if (stack.length) { - const last = lines.slice(stack[0]).join("\n") + "\n```"; - result.push(handleEscape(last, "code")); - } - return result.join("\n"); -} -function handleEscape(text, type = "text") { - if (!text.trim()) { return text; - } - if (type === "text") { - text = text.replace(escapeChars, "\\$1").replace(/\\\*\\\*(.*?[^\\])\\\*\\\*/g, "*$1*").replace(/\\_\\_(.*?[^\\])\\_\\_/g, "__$1__").replace(/\\_(.*?[^\\])\\_/g, "_$1_").replace(/\\~(.*?[^\\])\\~/g, "~$1~").replace(/\\\|\\\|(.*?[^\\])\\\|\\\|/g, "||$1||").replace(/\\\[([^\]]+?)\\\]\\\((.+?)\\\)/g, "[$1]($2)").replace(/\\\`(.*?[^\\])\\\`/g, "`$1`").replace(/\\\\\\([\_\*\[\]\(\)\\\~\`\>\#\+\-\=\|\{\}\.\!])/g, "\\$1").replace(/^(\s*)\\(>.+\s*)$/gm, "$1$2").replace(/^(\s*)\\-\s*(.+)$/gm, "$1\u2022 $2").replace(/^((\\#){1,3}\s)(.+)/gm, "$1*$3*"); - } else { - const codeBlank = text.length - text.trimStart().length; - if (codeBlank > 0) { - const blankReg = new RegExp(`^\\s{${codeBlank}}`, "gm"); - text = text.replace(blankReg, ""); - } - text = text.trimEnd().replace(/([\\\`])/g, "\\$1").replace(/^\\`\\`\\`([\s\S]+)\\`\\`\\`$/g, "```$1```"); - } - return text; } -// src/telegram/telegram.js -async function sendMessage(message, token, context) { - const body = { - text: message - }; - for (const key of Object.keys(context)) { - if (context[key] !== void 0 && context[key] !== null) { - body[key] = context[key]; - } - } - let method = "sendMessage"; - if (context?.message_id) { - method = "editMessageText"; - } - return await fetch( - `${ENV.TELEGRAM_API_DOMAIN}/bot${token}/${method}`, - { - method: "POST", - headers: { - "Content-Type": "application/json" - }, - body: JSON.stringify(body) - } - ); -} -async function sendMessageToTelegram(message, token, context) { - const chatContext = context; - const originMessage = message; - const limit = 4096; - if (chatContext.parse_mode === "MarkdownV2") { - message = escape(message); - } - if (message.length <= limit) { - const resp = await sendMessage(message, token, chatContext); - if (resp.status === 200) { - return resp; - } else { - message = originMessage; - chatContext.parse_mode = null; - return await sendMessage(message, token, chatContext); - } - } - message = originMessage; - chatContext.parse_mode = null; - let lastMessageResponse = null; - for (let i = 0; i < message.length; i += limit) { - const msg = message.slice(i, Math.min(i + limit, message.length)); - if (i > 0) { - chatContext.message_id = null; - } - lastMessageResponse = await sendMessage(msg, token, chatContext); - } - return lastMessageResponse; -} -function sendMessageToTelegramWithContext(context) { - return async (message) => { - return sendMessageToTelegram(message, context.SHARE_CONTEXT.currentBotToken, context.CURRENT_CHAT_CONTEXT); - }; -} -function deleteMessageFromTelegramWithContext(context) { - return async (messageId) => { - return await fetch( - `${ENV.TELEGRAM_API_DOMAIN}/bot${context.SHARE_CONTEXT.currentBotToken}/deleteMessage`, - { - method: "POST", - headers: { - "Content-Type": "application/json" +async function sendTelegramRequest(method, token, body = null) { + const headers = {}; + if (!(body instanceof FormData)) { + headers['Content-Type'] = 'application/json'; + } + return fetch( + `${ENV.TELEGRAM_API_DOMAIN}/bot${token}/${method}`, + { + method: 'POST', + headers, + body: body && ((body instanceof FormData) ? body : JSON.stringify(body)), }, - body: JSON.stringify({ - chat_id: context.CURRENT_CHAT_CONTEXT.chat_id, - message_id: messageId - }) - } ); - }; } -async function sendPhotoToTelegram(photo, token, context) { - const url = `${ENV.TELEGRAM_API_DOMAIN}/bot${token}/sendPhoto`; - let body; - const headers = {}; - if (typeof photo === "string") { - body = { - photo +async function sendMessage(message, token, context) { + const body = { + text: message, }; for (const key of Object.keys(context)) { - if (context[key] !== void 0 && context[key] !== null) { - body[key] = context[key]; - } + if (context[key] !== undefined && context[key] !== null) { + body[key] = context[key]; + } } - body = JSON.stringify(body); - headers["Content-Type"] = "application/json"; - } else { - body = new FormData(); - body.append("photo", photo, "photo.png"); - for (const key of Object.keys(context)) { - if (context[key] !== void 0 && context[key] !== null) { - body.append(key, `${context[key]}`); - } + let method = 'sendMessage'; + if (context?.message_id) { + method = 'editMessageText'; } - } - return await fetch( - url, - { - method: "POST", - headers, - body + return sendTelegramRequest(method, token, body); +} +async function sendMessageToTelegram(message, token, context) { + const chatContext = context; + const originMessage = message; + const limit = 4096; + if (chatContext.parse_mode === 'MarkdownV2') { + message = escape(message); + } + if (message.length <= limit) { + const resp = await sendMessage(message, token, chatContext); + if (resp.status === 200) { + return resp; + } else { + message = originMessage; + chatContext.parse_mode = null; + return await sendMessage(message, token, chatContext); + } + } + message = originMessage; + chatContext.parse_mode = null; + let lastMessageResponse = null; + for (let i = 0; i < message.length; i += limit) { + const msg = message.slice(i, Math.min(i + limit, message.length)); + if (i > 0) { + chatContext.message_id = null; + } + lastMessageResponse = await sendMessage(msg, token, chatContext); + if (lastMessageResponse.status !== 200) { + break; + } } - ); + return lastMessageResponse; } -function sendPhotoToTelegramWithContext(context) { - return (url) => { - return sendPhotoToTelegram(url, context.SHARE_CONTEXT.currentBotToken, context.CURRENT_CHAT_CONTEXT); - }; +async function sendPhotoToTelegram(photo, token, context) { + if (typeof photo === 'string') { + const body = { + photo, + }; + for (const key of Object.keys(context)) { + if (context[key] !== undefined && context[key] !== null) { + body[key] = context[key]; + } + } + return sendTelegramRequest('sendPhoto', token, body); + } else { + const body = new FormData(); + body.append('photo', photo, 'photo.png'); + for (const key of Object.keys(context)) { + if (context[key] !== undefined && context[key] !== null) { + body.append(key, `${context[key]}`); + } + } + return sendTelegramRequest('sendPhoto', token, body); + } } async function sendChatActionToTelegram(action, token, chatId) { - return await fetch( - `${ENV.TELEGRAM_API_DOMAIN}/bot${token}/sendChatAction`, - { - method: "POST", - headers: { - "Content-Type": "application/json" - }, - body: JSON.stringify({ + return sendTelegramRequest('sendChatAction', token, { chat_id: chatId, - action - }) - } - ).then((res) => res.json()); -} -function sendChatActionToTelegramWithContext(context) { - return (action) => { - return sendChatActionToTelegram(action, context.SHARE_CONTEXT.currentBotToken, context.CURRENT_CHAT_CONTEXT.chat_id); - }; + action, + }); } async function bindTelegramWebHook(token, url) { - return await fetch( - `${ENV.TELEGRAM_API_DOMAIN}/bot${token}/setWebhook`, - { - method: "POST", - headers: { - "Content-Type": "application/json" - }, - body: JSON.stringify({ - url - }) - } - ).then((res) => res.json()); -} -async function getChatRole(id, groupAdminKey, chatId, token) { - let groupAdmin; - try { - groupAdmin = JSON.parse(await DATABASE.get(groupAdminKey)); - } catch (e) { - console.error(e); - return e.message; - } - if (!groupAdmin || !Array.isArray(groupAdmin) || groupAdmin.length === 0) { - const administers = await getChatAdminister(chatId, token); - if (administers == null) { - return null; - } - groupAdmin = administers; - await DATABASE.put( - groupAdminKey, - JSON.stringify(groupAdmin), - { expiration: Date.now() / 1e3 + 120 } - ); - } - for (let i = 0; i < groupAdmin.length; i++) { - const user = groupAdmin[i]; - if (user.user.id === id) { - return user.status; - } - } - return "member"; -} -function getChatRoleWithContext(context) { - return (id) => { - return getChatRole(id, context.SHARE_CONTEXT.groupAdminKey, context.CURRENT_CHAT_CONTEXT.chat_id, context.SHARE_CONTEXT.currentBotToken); - }; -} -async function getChatAdminister(chatId, token) { - try { - const resp = await fetch( - `${ENV.TELEGRAM_API_DOMAIN}/bot${token}/getChatAdministrators`, - { - method: "POST", - headers: { - "Content-Type": "application/json" - }, - body: JSON.stringify({ chat_id: chatId }) - } - ).then((res) => res.json()); - if (resp.ok) { - return resp.result; - } - } catch (e) { - console.error(e); - return null; - } + return sendTelegramRequest('setWebhook', token, { url }); } -async function getBot(token) { - const resp = await fetch( - `${ENV.TELEGRAM_API_DOMAIN}/bot${token}/getMe`, - { - method: "POST", - headers: { - "Content-Type": "application/json" - } +async function getChatAdministrators(chatId, token) { + return sendTelegramRequest('getChatAdministrators', token, { chat_id: chatId }) + .then(res => res.json()).catch(() => null); +} +async function getBotName(token) { + const { result: { username } } = await sendTelegramRequest('getMe', token) + .then(res => res.json()); + return username; +} +async function getFileLink(fileId, token) { + try { + const { result: { file_path } } = await sendTelegramRequest('getFile', token, { file_id: fileId }) + .then(res => res.json()); + return `https://api.telegram.org/file/bot${token}/${file_path}`; + } catch (e) { + console.error(e); } - ).then((res) => res.json()); - if (resp.ok) { - return { - ok: true, - info: { - name: resp.result.first_name, - bot_name: resp.result.username, - can_join_groups: resp.result.can_join_groups, - can_read_all_group_messages: resp.result.can_read_all_group_messages - } + return ''; +} +function sendMessageToTelegramWithContext(context) { + return async (message) => { + return sendMessageToTelegram(message, context.SHARE_CONTEXT.currentBotToken, context.CURRENT_CHAT_CONTEXT); }; - } else { - return resp; - } } -async function getFileLink(fileId, token) { - const resp = await fetch( - `${ENV.TELEGRAM_API_DOMAIN}/bot${token}/getFile`, - { - method: "POST", - headers: { - "Content-Type": "application/json" - }, - body: JSON.stringify({ file_id: fileId }) - } - ).then((res) => res.json()); - if (resp.ok && resp.result.file_path) { - return `https://api.telegram.org/file/bot${token}/${resp.result.file_path}`; - } - return ""; +function sendPhotoToTelegramWithContext(context) { + return (url) => { + return sendPhotoToTelegram(url, context.SHARE_CONTEXT.currentBotToken, context.CURRENT_CHAT_CONTEXT); + }; +} +function sendChatActionToTelegramWithContext(context) { + return (action) => { + return sendChatActionToTelegram(action, context.SHARE_CONTEXT.currentBotToken, context.CURRENT_CHAT_CONTEXT.chat_id); + }; } -// src/agent/stream.js -var Stream = class { - constructor(response, controller, decoder = null, parser = null) { - this.response = response; - this.controller = controller; - this.decoder = decoder || new SSEDecoder(); - this.parser = parser || openaiSseJsonParser; - } - async *iterMessages() { - if (!this.response.body) { - this.controller.abort(); - throw new Error("Attempted to iterate over a response with no body"); - } - const lineDecoder = new LineDecoder(); - const iter = this.response.body; - for await (const chunk of iter) { - for (const line of lineDecoder.decode(chunk)) { - const sse = this.decoder.decode(line); - if (sse) { - yield sse; +class Stream { + constructor(response, controller, decoder = null, parser = null) { + this.response = response; + this.controller = controller; + this.decoder = decoder || new SSEDecoder(); + this.parser = parser || openaiSseJsonParser; + } + async* iterMessages() { + if (!this.response.body) { + this.controller.abort(); + throw new Error('Attempted to iterate over a response with no body'); + } + const lineDecoder = new LineDecoder(); + const iter = this.response.body; + for await (const chunk of iter) { + for (const line of lineDecoder.decode(chunk)) { + const sse = this.decoder.decode(line); + if (sse) { + yield sse; + } + } + } + for (const line of lineDecoder.flush()) { + const sse = this.decoder.decode(line); + if (sse) { + yield sse; + } } - } } - for (const line of lineDecoder.flush()) { - const sse = this.decoder.decode(line); - if (sse) { - yield sse; - } + async* [Symbol.asyncIterator]() { + let done = false; + try { + for await (const sse of this.iterMessages()) { + if (done) { + continue; + } + if (!sse) { + continue; + } + const { finish, data } = this.parser(sse); + if (finish) { + done = finish; + continue; + } + if (data) { + yield data; + } + } + done = true; + } catch (e) { + if (e instanceof Error && e.name === 'AbortError') { + return; + } + throw e; + } finally { + if (!done) { + this.controller.abort(); + } + } } - } - async *[Symbol.asyncIterator]() { - let done = false; - try { - for await (const sse of this.iterMessages()) { - if (done) { - continue; +} +class SSEDecoder { + constructor() { + this.event = null; + this.data = []; + this.chunks = []; + } + decode(line) { + if (line.endsWith('\r')) { + line = line.substring(0, line.length - 1); } - if (!sse) { - continue; + if (!line) { + if (!this.event && !this.data.length) { + return null; + } + const sse = { + event: this.event, + data: this.data.join('\n'), + }; + this.event = null; + this.data = []; + this.chunks = []; + return sse; } - const { finish, data } = this.parser(sse); - if (finish) { - done = finish; - continue; + this.chunks.push(line); + if (line.startsWith(':')) { + return null; } - if (data) { - yield data; + let [fieldName, _, value] = this.partition(line, ':'); + if (value.startsWith(' ')) { + value = value.substring(1); + } + if (fieldName === 'event') { + this.event = value; + } else if (fieldName === 'data') { + this.data.push(value); } - } - done = true; - } catch (e) { - if (e instanceof Error && e.name === "AbortError") { - return; - } - throw e; - } finally { - if (!done) { - this.controller.abort(); - } - } - } -}; -var SSEDecoder = class { - constructor() { - this.event = null; - this.data = []; - this.chunks = []; - } - decode(line) { - if (line.endsWith("\r")) { - line = line.substring(0, line.length - 1); - } - if (!line) { - if (!this.event && !this.data.length) { return null; - } - const sse = { - event: this.event, - data: this.data.join("\n") - }; - this.event = null; - this.data = []; - this.chunks = []; - return sse; - } - this.chunks.push(line); - if (line.startsWith(":")) { - return null; - } - let [fieldName, _, value] = this.partition(line, ":"); - if (value.startsWith(" ")) { - value = value.substring(1); - } - if (fieldName === "event") { - this.event = value; - } else if (fieldName === "data") { - this.data.push(value); } - return null; - } - partition(str, delimiter) { - const index = str.indexOf(delimiter); - if (index !== -1) { - return [str.substring(0, index), delimiter, str.substring(index + delimiter.length)]; + partition(str, delimiter) { + const index = str.indexOf(delimiter); + if (index !== -1) { + return [str.substring(0, index), delimiter, str.substring(index + delimiter.length)]; + } + return [str, '', '']; } - return [str, "", ""]; - } -}; +} function openaiSseJsonParser(sse) { - if (sse.data.startsWith("[DONE]")) { - return { finish: true }; - } - if (sse.event === null) { - try { - return { data: JSON.parse(sse.data) }; - } catch (e) { - console.error(e, sse); + if (sse.data.startsWith('[DONE]')) { + return { finish: true }; } - } - return {}; + if (sse.event === null) { + try { + return { data: JSON.parse(sse.data) }; + } catch (e) { + console.error(e, sse); + } + } + return {}; } function cohereSseJsonParser(sse) { - switch (sse.event) { - case "text-generation": - try { - return { data: JSON.parse(sse.data) }; - } catch (e) { - console.error(e, sse.data); - return {}; - } - case "stream-start": - return {}; - case "stream-end": - return { finish: true }; - default: - return {}; - } + switch (sse.event) { + case 'text-generation': + try { + return { data: JSON.parse(sse.data) }; + } catch (e) { + console.error(e, sse.data); + return {}; + } + case 'stream-start': + return {}; + case 'stream-end': + return { finish: true }; + default: + return {}; + } } function anthropicSseJsonParser(sse) { - switch (sse.event) { - case "content_block_delta": - try { - return { data: JSON.parse(sse.data) }; - } catch (e) { - console.error(e, sse.data); - return {}; - } - case "message_start": - case "content_block_start": - case "content_block_stop": - return {}; - case "message_stop": - return { finish: true }; - default: - return {}; - } -} -var LineDecoder = class _LineDecoder { - constructor() { - this.buffer = []; - this.trailingCR = false; - } - decode(chunk) { - let text = this.decodeText(chunk); - if (this.trailingCR) { - text = "\r" + text; - this.trailingCR = false; - } - if (text.endsWith("\r")) { - this.trailingCR = true; - text = text.slice(0, -1); - } - if (!text) { - return []; - } - const trailingNewline = _LineDecoder.NEWLINE_CHARS.has(text[text.length - 1] || ""); - let lines = text.split(_LineDecoder.NEWLINE_REGEXP); - if (lines.length === 1 && !trailingNewline) { - this.buffer.push(lines[0]); - return []; - } - if (this.buffer.length > 0) { - lines = [this.buffer.join("") + lines[0], ...lines.slice(1)]; - this.buffer = []; - } - if (!trailingNewline) { - this.buffer = [lines.pop() || ""]; + switch (sse.event) { + case 'content_block_delta': + try { + return { data: JSON.parse(sse.data) }; + } catch (e) { + console.error(e, sse.data); + return {}; + } + case 'message_start': + case 'content_block_start': + case 'content_block_stop': + return {}; + case 'message_stop': + return { finish: true }; + default: + return {}; } - return lines; - } - decodeText(bytes) { - var _a; - if (bytes == null) { - return ""; +} +class LineDecoder { + constructor() { + this.buffer = []; + this.trailingCR = false; } - if (typeof bytes === "string") { - return bytes; + decode(chunk) { + let text = this.decodeText(chunk); + if (this.trailingCR) { + text = `\r${text}`; + this.trailingCR = false; + } + if (text.endsWith('\r')) { + this.trailingCR = true; + text = text.slice(0, -1); + } + if (!text) { + return []; + } + const trailingNewline = LineDecoder.NEWLINE_CHARS.has(text[text.length - 1] || ''); + let lines = text.split(LineDecoder.NEWLINE_REGEXP); + if (lines.length === 1 && !trailingNewline) { + this.buffer.push(lines[0]); + return []; + } + if (this.buffer.length > 0) { + lines = [this.buffer.join('') + lines[0], ...lines.slice(1)]; + this.buffer = []; + } + if (!trailingNewline) { + this.buffer = [lines.pop() || '']; + } + return lines; } - if (typeof Buffer !== "undefined") { - if (bytes instanceof Buffer) { - return bytes.toString(); - } - if (bytes instanceof Uint8Array) { - return Buffer.from(bytes).toString(); - } - throw new Error(`Unexpected: received non-Uint8Array (${bytes.constructor.name}) stream chunk in an environment with a global "Buffer" defined, which this library assumes to be Node. Please report this error.`); + decodeText(bytes) { + if (bytes == null) { + return ''; + } + if (typeof bytes === 'string') { + return bytes; + } + if (typeof Buffer !== 'undefined') { + if (bytes instanceof Buffer) { + return bytes.toString(); + } + if (bytes instanceof Uint8Array) { + return Buffer.from(bytes).toString(); + } + throw new Error(`Unexpected: received non-Uint8Array (${bytes.constructor.name}) stream chunk in an environment with a global "Buffer" defined, which this library assumes to be Node. Please report this error.`); + } + if (typeof TextDecoder !== 'undefined') { + if (bytes instanceof Uint8Array || bytes instanceof ArrayBuffer) { + if (!this.textDecoder) { + this.textDecoder = new TextDecoder('utf8'); + } + return this.textDecoder.decode(bytes, { stream: true }); + } + throw new Error(`Unexpected: received non-Uint8Array/ArrayBuffer (${bytes.constructor.name}) in a web platform. Please report this error.`); + } + throw new Error('Unexpected: neither Buffer nor TextDecoder are available as globals. Please report this error.'); } - if (typeof TextDecoder !== "undefined") { - if (bytes instanceof Uint8Array || bytes instanceof ArrayBuffer) { - (_a = this.textDecoder) !== null && _a !== void 0 ? _a : this.textDecoder = new TextDecoder("utf8"); - return this.textDecoder.decode(bytes, { stream: true }); - } - throw new Error(`Unexpected: received non-Uint8Array/ArrayBuffer (${bytes.constructor.name}) in a web platform. Please report this error.`); + flush() { + if (!this.buffer.length && !this.trailingCR) { + return []; + } + const lines = [this.buffer.join('')]; + this.buffer = []; + this.trailingCR = false; + return lines; } - throw new Error("Unexpected: neither Buffer nor TextDecoder are available as globals. Please report this error."); - } - flush() { - if (!this.buffer.length && !this.trailingCR) { - return []; - } - const lines = [this.buffer.join("")]; - this.buffer = []; - this.trailingCR = false; - return lines; - } -}; -LineDecoder.NEWLINE_CHARS = /* @__PURE__ */ new Set(["\n", "\r"]); +} +LineDecoder.NEWLINE_CHARS = new Set(['\n', '\r']); LineDecoder.NEWLINE_REGEXP = /\r\n|[\n\r]/g; -// src/agent/request.js function fixOpenAICompatibleOptions(options) { - options = options || {}; - options.streamBuilder = options.streamBuilder || function(r, c) { - return new Stream(r, c); - }; - options.contentExtractor = options.contentExtractor || function(d) { - return d?.choices?.[0]?.delta?.content; - }; - options.fullContentExtractor = options.fullContentExtractor || function(d) { - return d.choices?.[0]?.message.content; - }; - options.errorExtractor = options.errorExtractor || function(d) { - return d.error?.message; - }; - return options; + options = options || {}; + options.streamBuilder = options.streamBuilder || function (r, c) { + return new Stream(r, c); + }; + options.contentExtractor = options.contentExtractor || function (d) { + return d?.choices?.[0]?.delta?.content; + }; + options.fullContentExtractor = options.fullContentExtractor || function (d) { + return d.choices?.[0]?.message.content; + }; + options.errorExtractor = options.errorExtractor || function (d) { + return d.error?.message; + }; + return options; } function isJsonResponse(resp) { - return resp.headers.get("content-type").indexOf("json") !== -1; + return resp.headers.get('content-type').includes('json'); } function isEventStreamResponse(resp) { - const types = ["application/stream+json", "text/event-stream"]; - const content = resp.headers.get("content-type"); - for (const type of types) { - if (content.indexOf(type) !== -1) { - return true; + const types = ['application/stream+json', 'text/event-stream']; + const content = resp.headers.get('content-type'); + for (const type of types) { + if (content.includes(type)) { + return true; + } } - } - return false; + return false; } async function requestChatCompletions(url, header, body, context, onStream, onResult = null, options = null) { - const controller = new AbortController(); - const { signal } = controller; - let timeoutID = null; - let lastUpdateTime = Date.now(); - if (ENV.CHAT_COMPLETE_API_TIMEOUT > 0) { - timeoutID = setTimeout(() => controller.abort(), ENV.CHAT_COMPLETE_API_TIMEOUT); - } - const resp = await fetch(url, { - method: "POST", - headers: header, - body: JSON.stringify(body), - signal - }); - if (timeoutID) { - clearTimeout(timeoutID); - } - options = fixOpenAICompatibleOptions(options); - if (onStream && resp.ok && isEventStreamResponse(resp)) { - const stream = options.streamBuilder(resp, controller); - let contentFull = ""; - let lengthDelta = 0; - let updateStep = 50; - try { - for await (const data of stream) { - const c = options.contentExtractor(data) || ""; - if (c === "") { - continue; - } - lengthDelta += c.length; - contentFull = contentFull + c; - if (lengthDelta > updateStep) { - if (ENV.TELEGRAM_MIN_STREAM_INTERVAL > 0) { - const delta = Date.now() - lastUpdateTime; - if (delta < ENV.TELEGRAM_MIN_STREAM_INTERVAL) { - continue; + const controller = new AbortController(); + const { signal } = controller; + let timeoutID = null; + let lastUpdateTime = Date.now(); + if (ENV.CHAT_COMPLETE_API_TIMEOUT > 0) { + timeoutID = setTimeout(() => controller.abort(), ENV.CHAT_COMPLETE_API_TIMEOUT); + } + const resp = await fetch(url, { + method: 'POST', + headers: header, + body: JSON.stringify(body), + signal, + }); + if (timeoutID) { + clearTimeout(timeoutID); + } + options = fixOpenAICompatibleOptions(options); + if (onStream && resp.ok && isEventStreamResponse(resp)) { + const stream = options.streamBuilder(resp, controller); + let contentFull = ''; + let lengthDelta = 0; + let updateStep = 50; + try { + for await (const data of stream) { + const c = options.contentExtractor(data) || ''; + if (c === '') { + continue; + } + lengthDelta += c.length; + contentFull = contentFull + c; + if (lengthDelta > updateStep) { + if (ENV.TELEGRAM_MIN_STREAM_INTERVAL > 0) { + const delta = Date.now() - lastUpdateTime; + if (delta < ENV.TELEGRAM_MIN_STREAM_INTERVAL) { + continue; + } + lastUpdateTime = Date.now(); + } + lengthDelta = 0; + updateStep += 20; + await onStream(`${contentFull}\n...`); + } } - lastUpdateTime = Date.now(); - } - lengthDelta = 0; - updateStep += 20; - await onStream(`${contentFull} -...`); + } catch (e) { + contentFull += `\nERROR: ${e.message}`; } - } - } catch (e) { - contentFull += ` -ERROR: ${e.message}`; + return contentFull; } - return contentFull; - } - if (!isJsonResponse(resp)) { - throw new Error(resp.statusText); - } - const result = await resp.json(); - if (!result) { - throw new Error("Empty response"); - } - if (options.errorExtractor(result)) { - throw new Error(options.errorExtractor(result)); - } - try { - await onResult?.(result); - return options.fullContentExtractor(result); - } catch (e) { - console.error(e); - throw Error(JSON.stringify(result)); - } -} - -// src/utils/cache.js -var Cache = class { - constructor() { - this.maxItems = 10; - this.maxAge = 1e3 * 60 * 60; - this.cache = {}; - } - /** - * @param {string} key - * @param {any} value - */ - set(key, value) { - this.trim(); - this.cache[key] = { - value, - time: Date.now() - }; - } - /** - * @param {string} key - * @returns {any} - */ - get(key) { - this.trim(); - return this.cache[key]?.value; - } - /** - * @private - */ - trim() { - let keys = Object.keys(this.cache); - for (const key of keys) { - if (Date.now() - this.cache[key].time > this.maxAge) { - delete this.cache[key]; - } + if (!isJsonResponse(resp)) { + throw new Error(resp.statusText); } - keys = Object.keys(this.cache); - if (keys.length > this.maxItems) { - keys.sort((a, b) => this.cache[a].time - this.cache[b].time); - for (let i = 0; i < keys.length - this.maxItems; i++) { - delete this.cache[keys[i]]; - } + const result = await resp.json(); + if (!result) { + throw new Error('Empty response'); + } + if (options.errorExtractor(result)) { + throw new Error(options.errorExtractor(result)); + } + try { + await onResult?.(result); + return options.fullContentExtractor(result); + } catch (e) { + console.error(e); + throw new Error(JSON.stringify(result)); } - } -}; - -// src/utils/image.js -var IMAGE_CACHE = new Cache(); -async function fetchImage(url) { - if (IMAGE_CACHE[url]) { - return IMAGE_CACHE.get(url); - } - return fetch(url).then((resp) => resp.blob()).then((blob) => { - IMAGE_CACHE.set(url, blob); - return blob; - }); -} -async function uploadImageToTelegraph(url) { - if (url.startsWith("https://telegra.ph")) { - return url; - } - const raw = await fetchImage(url); - const formData = new FormData(); - formData.append("file", raw, "blob"); - const resp = await fetch("https://telegra.ph/upload", { - method: "POST", - body: formData - }); - let [{ src }] = await resp.json(); - src = `https://telegra.ph${src}`; - IMAGE_CACHE.set(src, raw); - return src; -} -async function urlToBase64String(url) { - try { - const { Buffer: Buffer2 } = await import("node:buffer"); - return fetchImage(url).then((blob) => blob.arrayBuffer()).then((buffer) => Buffer2.from(buffer).toString("base64")); - } catch { - return fetchImage(url).then((blob) => blob.arrayBuffer()).then((buffer) => btoa(String.fromCharCode.apply(null, new Uint8Array(buffer)))); - } -} -function getImageFormatFromBase64(base64String) { - const firstChar = base64String.charAt(0); - switch (firstChar) { - case "/": - return "jpeg"; - case "i": - return "png"; - case "R": - return "gif"; - case "U": - return "webp"; - default: - throw new Error("Unsupported image format"); - } -} -async function imageToBase64String(url) { - const base64String = await urlToBase64String(url); - const format = getImageFormatFromBase64(base64String); - return { - data: base64String, - format: `image/${format}` - }; -} -function renderBase64DataURI(params) { - return `data:${params.format};base64,${params.data}`; } -// src/agent/openai.js function openAIKeyFromContext(context) { - const length = context.USER_CONFIG.OPENAI_API_KEY.length; - return context.USER_CONFIG.OPENAI_API_KEY[Math.floor(Math.random() * length)]; + const length = context.USER_CONFIG.OPENAI_API_KEY.length; + return context.USER_CONFIG.OPENAI_API_KEY[Math.floor(Math.random() * length)]; } function isOpenAIEnable(context) { - return context.USER_CONFIG.OPENAI_API_KEY.length > 0; + return context.USER_CONFIG.OPENAI_API_KEY.length > 0; } async function renderOpenAIMessage(item) { - const res = { - role: item.role, - content: item.content - }; - if (item.images && item.images.length > 0) { - res.content = []; - if (item.content) { - res.content.push({ type: "text", text: item.content }); - } - for (const image of item.images) { - switch (ENV.TELEGRAM_IMAGE_TRANSFER_MODE) { - case "base64": - res.content.push({ type: "image_url", image_url: { - url: renderBase64DataURI(await imageToBase64String(image)) - } }); - break; - case "url": - default: - res.content.push({ type: "image_url", image_url: { url: image } }); - break; - } + const res = { + role: item.role, + content: item.content, + }; + if (item.images && item.images.length > 0) { + res.content = []; + if (item.content) { + res.content.push({ type: 'text', text: item.content }); + } + for (const image of item.images) { + switch (ENV.TELEGRAM_IMAGE_TRANSFER_MODE) { + case 'base64': + res.content.push({ type: 'image_url', image_url: { + url: renderBase64DataURI(await imageToBase64String(image)), + } }); + break; + case 'url': + default: + res.content.push({ type: 'image_url', image_url: { url: image } }); + break; + } + } } - } - return res; + return res; } async function requestCompletionsFromOpenAI(params, context, onStream) { - const { message, images, prompt, history } = params; - const url = `${context.USER_CONFIG.OPENAI_API_BASE}/chat/completions`; - const header = { - "Content-Type": "application/json", - "Authorization": `Bearer ${openAIKeyFromContext(context)}` - }; - const messages = [...history || [], { role: "user", content: message, images }]; - if (prompt) { - messages.unshift({ role: context.USER_CONFIG.SYSTEM_INIT_MESSAGE_ROLE, content: prompt }); - } - const body = { - model: context.USER_CONFIG.OPENAI_CHAT_MODEL, - ...context.USER_CONFIG.OPENAI_API_EXTRA_PARAMS, - messages: await Promise.all(messages.map(renderOpenAIMessage)), - stream: onStream != null - }; - return requestChatCompletions(url, header, body, context, onStream); + const { message, images, prompt, history } = params; + const url = `${context.USER_CONFIG.OPENAI_API_BASE}/chat/completions`; + const header = { + 'Content-Type': 'application/json', + 'Authorization': `Bearer ${openAIKeyFromContext(context)}`, + }; + const messages = [...(history || []), { role: 'user', content: message, images }]; + if (prompt) { + messages.unshift({ role: context.USER_CONFIG.SYSTEM_INIT_MESSAGE_ROLE, content: prompt }); + } + const body = { + model: context.USER_CONFIG.OPENAI_CHAT_MODEL, + ...context.USER_CONFIG.OPENAI_API_EXTRA_PARAMS, + messages: await Promise.all(messages.map(renderOpenAIMessage)), + stream: onStream != null, + }; + return requestChatCompletions(url, header, body, context, onStream); } async function requestImageFromOpenAI(prompt, context) { - const url = `${context.USER_CONFIG.OPENAI_API_BASE}/images/generations`; - const header = { - "Content-Type": "application/json", - "Authorization": `Bearer ${openAIKeyFromContext(context)}` - }; - const body = { - prompt, - n: 1, - size: context.USER_CONFIG.DALL_E_IMAGE_SIZE, - model: context.USER_CONFIG.DALL_E_MODEL - }; - if (body.model === "dall-e-3") { - body.quality = context.USER_CONFIG.DALL_E_IMAGE_QUALITY; - body.style = context.USER_CONFIG.DALL_E_IMAGE_STYLE; - } - const resp = await fetch(url, { - method: "POST", - headers: header, - body: JSON.stringify(body) - }).then((res) => res.json()); - if (resp.error?.message) { - throw new Error(resp.error.message); - } - return resp?.data?.[0]?.url; + const url = `${context.USER_CONFIG.OPENAI_API_BASE}/images/generations`; + const header = { + 'Content-Type': 'application/json', + 'Authorization': `Bearer ${openAIKeyFromContext(context)}`, + }; + const body = { + prompt, + n: 1, + size: context.USER_CONFIG.DALL_E_IMAGE_SIZE, + model: context.USER_CONFIG.DALL_E_MODEL, + }; + if (body.model === 'dall-e-3') { + body.quality = context.USER_CONFIG.DALL_E_IMAGE_QUALITY; + body.style = context.USER_CONFIG.DALL_E_IMAGE_STYLE; + } + const resp = await fetch(url, { + method: 'POST', + headers: header, + body: JSON.stringify(body), + }).then(res => res.json()); + if (resp.error?.message) { + throw new Error(resp.error.message); + } + return resp?.data?.[0]?.url; } -// src/agent/workersai.js async function run(model, body, id, token) { - return await fetch( - `https://api.cloudflare.com/client/v4/accounts/${id}/ai/run/${model}`, - { - headers: { Authorization: `Bearer ${token}` }, - method: "POST", - body: JSON.stringify(body) - } - ); + return await fetch( + `https://api.cloudflare.com/client/v4/accounts/${id}/ai/run/${model}`, + { + headers: { Authorization: `Bearer ${token}` }, + method: 'POST', + body: JSON.stringify(body), + }, + ); } function isWorkersAIEnable(context) { - return !!(context.USER_CONFIG.CLOUDFLARE_ACCOUNT_ID && context.USER_CONFIG.CLOUDFLARE_TOKEN); + return !!(context.USER_CONFIG.CLOUDFLARE_ACCOUNT_ID && context.USER_CONFIG.CLOUDFLARE_TOKEN); } function renderWorkerAIMessage(item) { - return { - role: item.role, - content: item.content - }; + return { + role: item.role, + content: item.content, + }; } async function requestCompletionsFromWorkersAI(params, context, onStream) { - const { message, prompt, history } = params; - const id = context.USER_CONFIG.CLOUDFLARE_ACCOUNT_ID; - const token = context.USER_CONFIG.CLOUDFLARE_TOKEN; - const model = context.USER_CONFIG.WORKERS_CHAT_MODEL; - const url = `https://api.cloudflare.com/client/v4/accounts/${id}/ai/run/${model}`; - const header = { - Authorization: `Bearer ${token}` - }; - const messages = [...history || [], { role: "user", content: message }]; - if (prompt) { - messages.unshift({ role: context.USER_CONFIG.SYSTEM_INIT_MESSAGE_ROLE, content: prompt }); - } - const body = { - messages: messages.map(renderWorkerAIMessage), - stream: onStream !== null - }; - const options = {}; - options.contentExtractor = function(data) { - return data?.response; - }; - options.fullContentExtractor = function(data) { - return data?.result?.response; - }; - options.errorExtractor = function(data) { - return data?.errors?.[0]?.message; - }; - return requestChatCompletions(url, header, body, context, onStream, null, options); + const { message, prompt, history } = params; + const id = context.USER_CONFIG.CLOUDFLARE_ACCOUNT_ID; + const token = context.USER_CONFIG.CLOUDFLARE_TOKEN; + const model = context.USER_CONFIG.WORKERS_CHAT_MODEL; + const url = `https://api.cloudflare.com/client/v4/accounts/${id}/ai/run/${model}`; + const header = { + Authorization: `Bearer ${token}`, + }; + const messages = [...(history || []), { role: 'user', content: message }]; + if (prompt) { + messages.unshift({ role: context.USER_CONFIG.SYSTEM_INIT_MESSAGE_ROLE, content: prompt }); + } + const body = { + messages: messages.map(renderWorkerAIMessage), + stream: onStream !== null, + }; + const options = {}; + options.contentExtractor = function (data) { + return data?.response; + }; + options.fullContentExtractor = function (data) { + return data?.result?.response; + }; + options.errorExtractor = function (data) { + return data?.errors?.[0]?.message; + }; + return requestChatCompletions(url, header, body, context, onStream, null, options); } async function requestImageFromWorkersAI(prompt, context) { - const id = context.USER_CONFIG.CLOUDFLARE_ACCOUNT_ID; - const token = context.USER_CONFIG.CLOUDFLARE_TOKEN; - const raw = await run(context.USER_CONFIG.WORKERS_IMAGE_MODEL, { prompt }, id, token); - return await raw.blob(); + const id = context.USER_CONFIG.CLOUDFLARE_ACCOUNT_ID; + const token = context.USER_CONFIG.CLOUDFLARE_TOKEN; + const raw = await run(context.USER_CONFIG.WORKERS_IMAGE_MODEL, { prompt }, id, token); + return await raw.blob(); } -// src/agent/gemini.js function isGeminiAIEnable(context) { - return !!context.USER_CONFIG.GOOGLE_API_KEY; + return !!(context.USER_CONFIG.GOOGLE_API_KEY); } -var GEMINI_ROLE_MAP = { - "assistant": "model", - "system": "user", - "user": "user" +const GEMINI_ROLE_MAP = { + assistant: 'model', + system: 'user', + user: 'user', }; function renderGeminiMessage(item) { - return { - role: GEMINI_ROLE_MAP[item.role], - parts: [ - { - "text": item.content || "" - } - ] - }; + return { + role: GEMINI_ROLE_MAP[item.role], + parts: [ + { + text: item.content || '', + }, + ], + }; } async function requestCompletionsFromGeminiAI(params, context, onStream) { - const { message, prompt, history } = params; - onStream = null; - const url = `${context.USER_CONFIG.GOOGLE_COMPLETIONS_API}${context.USER_CONFIG.GOOGLE_COMPLETIONS_MODEL}:${onStream ? "streamGenerateContent" : "generateContent"}?key=${context.USER_CONFIG.GOOGLE_API_KEY}`; - const contentsTemp = [...history || [], { role: "user", content: message }]; - if (prompt) { - contentsTemp.unshift({ role: "assistant", content: prompt }); - } - const contents = []; - for (const msg of contentsTemp) { - msg.role = GEMINI_ROLE_MAP[msg.role]; - if (contents.length === 0 || contents[contents.length - 1].role !== msg.role) { - contents.push(renderGeminiMessage(msg)); - } else { - contents[contents.length - 1].parts[0].text += msg.content; + const { message, prompt, history } = params; + onStream = null; + const url = `${context.USER_CONFIG.GOOGLE_COMPLETIONS_API}${context.USER_CONFIG.GOOGLE_COMPLETIONS_MODEL}:${ + onStream ? 'streamGenerateContent' : 'generateContent' + }?key=${context.USER_CONFIG.GOOGLE_API_KEY}`; + const contentsTemp = [...history || [], { role: 'user', content: message }]; + if (prompt) { + contentsTemp.unshift({ role: 'assistant', content: prompt }); + } + const contents = []; + for (const msg of contentsTemp) { + msg.role = GEMINI_ROLE_MAP[msg.role]; + if (contents.length === 0 || contents[contents.length - 1].role !== msg.role) { + contents.push(renderGeminiMessage(msg)); + } else { + contents[contents.length - 1].parts[0].text += msg.content; + } + } + const resp = await fetch(url, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ contents }), + }); + const data = await resp.json(); + try { + return data.candidates[0].content.parts[0].text; + } catch (e) { + console.error(e); + if (!data) { + throw new Error('Empty response'); + } + throw new Error(data?.error?.message || JSON.stringify(data)); } - } - const resp = await fetch(url, { - method: "POST", - headers: { - "Content-Type": "application/json" - }, - body: JSON.stringify({ contents }) - }); - const data = await resp.json(); - try { - return data.candidates[0].content.parts[0].text; - } catch (e) { - console.error(e); - if (!data) { - throw new Error("Empty response"); - } - throw new Error(data?.error?.message || JSON.stringify(data)); - } } -// src/agent/mistralai.js function isMistralAIEnable(context) { - return !!context.USER_CONFIG.MISTRAL_API_KEY; + return !!(context.USER_CONFIG.MISTRAL_API_KEY); } function renderMistralMessage(item) { - return { - role: item.role, - content: item.content - }; + return { + role: item.role, + content: item.content, + }; } async function requestCompletionsFromMistralAI(params, context, onStream) { - const { message, prompt, history } = params; - const url = `${context.USER_CONFIG.MISTRAL_API_BASE}/chat/completions`; - const header = { - "Content-Type": "application/json", - "Authorization": `Bearer ${context.USER_CONFIG.MISTRAL_API_KEY}` - }; - const messages = [...history || [], { role: "user", content: message }]; - if (prompt) { - messages.unshift({ role: context.USER_CONFIG.SYSTEM_INIT_MESSAGE_ROLE, content: prompt }); - } - const body = { - model: context.USER_CONFIG.MISTRAL_CHAT_MODEL, - messages: messages.map(renderMistralMessage), - stream: onStream != null - }; - return requestChatCompletions(url, header, body, context, onStream); + const { message, prompt, history } = params; + const url = `${context.USER_CONFIG.MISTRAL_API_BASE}/chat/completions`; + const header = { + 'Content-Type': 'application/json', + 'Authorization': `Bearer ${context.USER_CONFIG.MISTRAL_API_KEY}`, + }; + const messages = [...(history || []), { role: 'user', content: message }]; + if (prompt) { + messages.unshift({ role: context.USER_CONFIG.SYSTEM_INIT_MESSAGE_ROLE, content: prompt }); + } + const body = { + model: context.USER_CONFIG.MISTRAL_CHAT_MODEL, + messages: messages.map(renderMistralMessage), + stream: onStream != null, + }; + return requestChatCompletions(url, header, body, context, onStream); } -// src/agent/cohere.js function isCohereAIEnable(context) { - return !!context.USER_CONFIG.COHERE_API_KEY; + return !!(context.USER_CONFIG.COHERE_API_KEY); } -var COHERE_ROLE_MAP = { - "assistant": "CHATBOT", - "user": "USER" +const COHERE_ROLE_MAP = { + assistant: 'CHATBOT', + user: 'USER', }; function renderCohereMessage(item) { - return { - role: COHERE_ROLE_MAP[item.role], - content: item.content - }; + return { + role: COHERE_ROLE_MAP[item.role], + content: item.content, + }; } async function requestCompletionsFromCohereAI(params, context, onStream) { - const { message, prompt, history } = params; - const url = `${context.USER_CONFIG.COHERE_API_BASE}/chat`; - const header = { - "Authorization": `Bearer ${context.USER_CONFIG.COHERE_API_KEY}`, - "Content-Type": "application/json", - "Accept": onStream !== null ? "text/event-stream" : "application/json" - }; - const body = { - message, - model: context.USER_CONFIG.COHERE_CHAT_MODEL, - stream: onStream != null, - preamble: prompt, - chat_history: history.map(renderCohereMessage) - }; - if (!body.preamble) { - delete body.preamble; - } - const options = {}; - options.streamBuilder = function(r, c) { - return new Stream(r, c, null, cohereSseJsonParser); - }; - options.contentExtractor = function(data) { - return data?.text; - }; - options.fullContentExtractor = function(data) { - return data?.text; - }; - options.errorExtractor = function(data) { - return data?.message; - }; - return requestChatCompletions(url, header, body, context, onStream, null, options); + const { message, prompt, history } = params; + const url = `${context.USER_CONFIG.COHERE_API_BASE}/chat`; + const header = { + 'Authorization': `Bearer ${context.USER_CONFIG.COHERE_API_KEY}`, + 'Content-Type': 'application/json', + 'Accept': onStream !== null ? 'text/event-stream' : 'application/json', + }; + const body = { + message, + model: context.USER_CONFIG.COHERE_CHAT_MODEL, + stream: onStream != null, + preamble: prompt, + chat_history: history.map(renderCohereMessage), + }; + if (!body.preamble) { + delete body.preamble; + } + const options = {}; + options.streamBuilder = function (r, c) { + return new Stream(r, c, null, cohereSseJsonParser); + }; + options.contentExtractor = function (data) { + return data?.text; + }; + options.fullContentExtractor = function (data) { + return data?.text; + }; + options.errorExtractor = function (data) { + return data?.message; + }; + return requestChatCompletions(url, header, body, context, onStream, null, options); } -// src/agent/anthropic.js function isAnthropicAIEnable(context) { - return !!context.USER_CONFIG.ANTHROPIC_API_KEY; + return !!(context.USER_CONFIG.ANTHROPIC_API_KEY); } async function renderAnthropicMessage(item) { - const res = { - role: item.role, - content: item.content - }; - if (item.images && item.images.length > 0) { - res.content = []; - if (item.content) { - res.content.push({ type: "text", text: item.content }); - } - for (const image of item.images) { - res.content.push(await imageToBase64String(image).then(({ format, data }) => { - return { type: "image", source: { type: "base64", media_type: format, data } }; - })); + const res = { + role: item.role, + content: item.content, + }; + if (item.images && item.images.length > 0) { + res.content = []; + if (item.content) { + res.content.push({ type: 'text', text: item.content }); + } + for (const image of item.images) { + res.content.push(await imageToBase64String(image).then(({ format, data }) => { + return { type: 'image', source: { type: 'base64', media_type: format, data } }; + })); + } } - } - return res; + return res; } async function requestCompletionsFromAnthropicAI(params, context, onStream) { - const { message, images, prompt, history } = params; - const url = `${context.USER_CONFIG.ANTHROPIC_API_BASE}/messages`; - const header = { - "x-api-key": context.USER_CONFIG.ANTHROPIC_API_KEY, - "anthropic-version": "2023-06-01", - "content-type": "application/json" - }; - const messages = [...history || [], { role: "user", content: message, images }]; - const body = { - system: prompt, - model: context.USER_CONFIG.ANTHROPIC_CHAT_MODEL, - messages: await Promise.all(messages.map(renderAnthropicMessage)), - stream: onStream != null, - max_tokens: ENV.MAX_TOKEN_LENGTH > 0 ? ENV.MAX_TOKEN_LENGTH : 2048 - }; - if (!body.system) { - delete body.system; - } - const options = {}; - options.streamBuilder = function(r, c) { - return new Stream(r, c, null, anthropicSseJsonParser); - }; - options.contentExtractor = function(data) { - return data?.delta?.text; - }; - options.fullContentExtractor = function(data) { - return data?.content?.[0].text; - }; - options.errorExtractor = function(data) { - return data?.error?.message; - }; - return requestChatCompletions(url, header, body, context, onStream, null, options); + const { message, images, prompt, history } = params; + const url = `${context.USER_CONFIG.ANTHROPIC_API_BASE}/messages`; + const header = { + 'x-api-key': context.USER_CONFIG.ANTHROPIC_API_KEY, + 'anthropic-version': '2023-06-01', + 'content-type': 'application/json', + }; + const messages = ([...(history || []), { role: 'user', content: message, images }]); + if (messages.length > 0 && messages[0].role === 'assistant') { + messages.shift(); + } + const body = { + system: prompt, + model: context.USER_CONFIG.ANTHROPIC_CHAT_MODEL, + messages: await Promise.all(messages.map(renderAnthropicMessage)), + stream: onStream != null, + max_tokens: ENV.MAX_TOKEN_LENGTH > 0 ? ENV.MAX_TOKEN_LENGTH : 2048, + }; + if (!body.system) { + delete body.system; + } + const options = {}; + options.streamBuilder = function (r, c) { + return new Stream(r, c, null, anthropicSseJsonParser); + }; + options.contentExtractor = function (data) { + return data?.delta?.text; + }; + options.fullContentExtractor = function (data) { + return data?.content?.[0].text; + }; + options.errorExtractor = function (data) { + return data?.error?.message; + }; + return requestChatCompletions(url, header, body, context, onStream, null, options); } -// src/agent/azure.js function azureKeyFromContext(context) { - return context.USER_CONFIG.AZURE_API_KEY; + return context.USER_CONFIG.AZURE_API_KEY; } function isAzureEnable(context) { - return !!(context.USER_CONFIG.AZURE_API_KEY && context.USER_CONFIG.AZURE_COMPLETIONS_API); + return !!(context.USER_CONFIG.AZURE_API_KEY && context.USER_CONFIG.AZURE_COMPLETIONS_API); } function isAzureImageEnable(context) { - return !!(context.USER_CONFIG.AZURE_API_KEY && context.USER_CONFIG.AZURE_DALLE_API); + return !!(context.USER_CONFIG.AZURE_API_KEY && context.USER_CONFIG.AZURE_DALLE_API); } async function requestCompletionsFromAzureOpenAI(params, context, onStream) { - const { message, images, prompt, history } = params; - const url = context.USER_CONFIG.AZURE_COMPLETIONS_API; - const header = { - "Content-Type": "application/json", - "api-key": azureKeyFromContext(context) - }; - const messages = [...history || [], { role: "user", content: message, images }]; - if (prompt) { - messages.unshift({ role: context.USER_CONFIG.SYSTEM_INIT_MESSAGE_ROLE, content: prompt }); - } - const body = { - ...context.USER_CONFIG.OPENAI_API_EXTRA_PARAMS, - messages: await Promise.all(messages.map(renderOpenAIMessage)), - stream: onStream != null - }; - return requestChatCompletions(url, header, body, context, onStream); + const { message, images, prompt, history } = params; + const url = context.USER_CONFIG.AZURE_COMPLETIONS_API; + const header = { + 'Content-Type': 'application/json', + 'api-key': azureKeyFromContext(context), + }; + const messages = [...(history || []), { role: 'user', content: message, images }]; + if (prompt) { + messages.unshift({ role: context.USER_CONFIG.SYSTEM_INIT_MESSAGE_ROLE, content: prompt }); + } + const body = { + ...context.USER_CONFIG.OPENAI_API_EXTRA_PARAMS, + messages: await Promise.all(messages.map(renderOpenAIMessage)), + stream: onStream != null, + }; + return requestChatCompletions(url, header, body, context, onStream); } async function requestImageFromAzureOpenAI(prompt, context) { - const url = context.USER_CONFIG.AZURE_DALLE_API; - const header = { - "Content-Type": "application/json", - "api-key": azureKeyFromContext(context) - }; - const body = { - prompt, - n: 1, - size: context.USER_CONFIG.DALL_E_IMAGE_SIZE, - style: context.USER_CONFIG.DALL_E_IMAGE_STYLE, - quality: context.USER_CONFIG.DALL_E_IMAGE_QUALITY - }; - const validSize = ["1792x1024", "1024x1024", "1024x1792"]; - if (!validSize.includes(body.size)) { - body.size = "1024x1024"; - } - const resp = await fetch(url, { - method: "POST", - headers: header, - body: JSON.stringify(body) - }).then((res) => res.json()); - if (resp.error?.message) { - throw new Error(resp.error.message); - } - return resp?.data?.[0]?.url; + const url = context.USER_CONFIG.AZURE_DALLE_API; + const header = { + 'Content-Type': 'application/json', + 'api-key': azureKeyFromContext(context), + }; + const body = { + prompt, + n: 1, + size: context.USER_CONFIG.DALL_E_IMAGE_SIZE, + style: context.USER_CONFIG.DALL_E_IMAGE_STYLE, + quality: context.USER_CONFIG.DALL_E_IMAGE_QUALITY, + }; + const validSize = ['1792x1024', '1024x1024', '1024x1792']; + if (!validSize.includes(body.size)) { + body.size = '1024x1024'; + } + const resp = await fetch(url, { + method: 'POST', + headers: header, + body: JSON.stringify(body), + }).then(res => res.json()); + if (resp.error?.message) { + throw new Error(resp.error.message); + } + return resp?.data?.[0]?.url; } -// src/agent/agents.js -var chatLlmAgents = [ - { - name: "azure", - enable: isAzureEnable, - request: requestCompletionsFromAzureOpenAI - }, - { - name: "openai", - enable: isOpenAIEnable, - request: requestCompletionsFromOpenAI - }, - { - name: "workers", - enable: isWorkersAIEnable, - request: requestCompletionsFromWorkersAI - }, - { - name: "gemini", - enable: isGeminiAIEnable, - request: requestCompletionsFromGeminiAI - }, - { - name: "mistral", - enable: isMistralAIEnable, - request: requestCompletionsFromMistralAI - }, - { - name: "cohere", - enable: isCohereAIEnable, - request: requestCompletionsFromCohereAI - }, - { - name: "anthropic", - enable: isAnthropicAIEnable, - request: requestCompletionsFromAnthropicAI - } +const chatLlmAgents = [ + { + name: 'azure', + enable: isAzureEnable, + request: requestCompletionsFromAzureOpenAI, + }, + { + name: 'openai', + enable: isOpenAIEnable, + request: requestCompletionsFromOpenAI, + }, + { + name: 'workers', + enable: isWorkersAIEnable, + request: requestCompletionsFromWorkersAI, + }, + { + name: 'gemini', + enable: isGeminiAIEnable, + request: requestCompletionsFromGeminiAI, + }, + { + name: 'mistral', + enable: isMistralAIEnable, + request: requestCompletionsFromMistralAI, + }, + { + name: 'cohere', + enable: isCohereAIEnable, + request: requestCompletionsFromCohereAI, + }, + { + name: 'anthropic', + enable: isAnthropicAIEnable, + request: requestCompletionsFromAnthropicAI, + }, ]; function currentChatModel(agentName, context) { - switch (agentName) { - case "azure": - try { - const url = new URL(context.USER_CONFIG.AZURE_COMPLETIONS_API); - return url.pathname.split("/")[3]; - } catch { - return context.USER_CONFIG.AZURE_COMPLETIONS_API; - } - case "openai": - return context.USER_CONFIG.OPENAI_CHAT_MODEL; - case "workers": - return context.USER_CONFIG.WORKERS_CHAT_MODEL; - case "gemini": - return context.USER_CONFIG.GOOGLE_COMPLETIONS_MODEL; - case "mistral": - return context.USER_CONFIG.MISTRAL_CHAT_MODEL; - case "cohere": - return context.USER_CONFIG.COHERE_CHAT_MODEL; - case "anthropic": - return context.USER_CONFIG.ANTHROPIC_CHAT_MODEL; - default: - return null; - } + switch (agentName) { + case 'azure': + try { + const url = new URL(context.USER_CONFIG.AZURE_COMPLETIONS_API); + return url.pathname.split('/')[3]; + } catch { + return context.USER_CONFIG.AZURE_COMPLETIONS_API; + } + case 'openai': + return context.USER_CONFIG.OPENAI_CHAT_MODEL; + case 'workers': + return context.USER_CONFIG.WORKERS_CHAT_MODEL; + case 'gemini': + return context.USER_CONFIG.GOOGLE_COMPLETIONS_MODEL; + case 'mistral': + return context.USER_CONFIG.MISTRAL_CHAT_MODEL; + case 'cohere': + return context.USER_CONFIG.COHERE_CHAT_MODEL; + case 'anthropic': + return context.USER_CONFIG.ANTHROPIC_CHAT_MODEL; + default: + return null; + } } function chatModelKey(agentName) { - switch (agentName) { - case "azure": - return "AZURE_COMPLETIONS_API"; - case "openai": - return "OPENAI_CHAT_MODEL"; - case "workers": - return "WORKERS_CHAT_MODEL"; - case "gemini": - return "GOOGLE_COMPLETIONS_MODEL"; - case "mistral": - return "MISTRAL_CHAT_MODEL"; - case "cohere": - return "COHERE_CHAT_MODEL"; - case "anthropic": - return "ANTHROPIC_CHAT_MODEL"; - default: - return null; - } + switch (agentName) { + case 'azure': + return 'AZURE_COMPLETIONS_API'; + case 'openai': + return 'OPENAI_CHAT_MODEL'; + case 'workers': + return 'WORKERS_CHAT_MODEL'; + case 'gemini': + return 'GOOGLE_COMPLETIONS_MODEL'; + case 'mistral': + return 'MISTRAL_CHAT_MODEL'; + case 'cohere': + return 'COHERE_CHAT_MODEL'; + case 'anthropic': + return 'ANTHROPIC_CHAT_MODEL'; + default: + return null; + } } function loadChatLLM(context) { - for (const llm of chatLlmAgents) { - if (llm.name === context.USER_CONFIG.AI_PROVIDER) { - return llm; + for (const llm of chatLlmAgents) { + if (llm.name === context.USER_CONFIG.AI_PROVIDER) { + return llm; + } } - } - for (const llm of chatLlmAgents) { - if (llm.enable(context)) { - return llm; + for (const llm of chatLlmAgents) { + if (llm.enable(context)) { + return llm; + } } - } - return null; -} -var imageGenAgents = [ - { - name: "azure", - enable: isAzureImageEnable, - request: requestImageFromAzureOpenAI - }, - { - name: "openai", - enable: isOpenAIEnable, - request: requestImageFromOpenAI - }, - { - name: "workers", - enable: isWorkersAIEnable, - request: requestImageFromWorkersAI - } + return null; +} +const imageGenAgents = [ + { + name: 'azure', + enable: isAzureImageEnable, + request: requestImageFromAzureOpenAI, + }, + { + name: 'openai', + enable: isOpenAIEnable, + request: requestImageFromOpenAI, + }, + { + name: 'workers', + enable: isWorkersAIEnable, + request: requestImageFromWorkersAI, + }, ]; function loadImageGen(context) { - for (const imgGen of imageGenAgents) { - if (imgGen.name === context.USER_CONFIG.AI_IMAGE_PROVIDER) { - return imgGen; + for (const imgGen of imageGenAgents) { + if (imgGen.name === context.USER_CONFIG.AI_IMAGE_PROVIDER) { + return imgGen; + } } - } - for (const imgGen of imageGenAgents) { - if (imgGen.enable(context)) { - return imgGen; + for (const imgGen of imageGenAgents) { + if (imgGen.enable(context)) { + return imgGen; + } } - } - return null; + return null; } function currentImageModel(agentName, context) { - switch (agentName) { - case "azure": - try { - const url = new URL(context.USER_CONFIG.AZURE_DALLE_API); - return url.pathname.split("/")[3]; - } catch { - return context.USER_CONFIG.AZURE_DALLE_API; - } - case "openai": - return context.USER_CONFIG.DALL_E_MODEL; - case "workers": - return context.USER_CONFIG.WORKERS_IMAGE_MODEL; - default: - return null; - } + switch (agentName) { + case 'azure': + try { + const url = new URL(context.USER_CONFIG.AZURE_DALLE_API); + return url.pathname.split('/')[3]; + } catch { + return context.USER_CONFIG.AZURE_DALLE_API; + } + case 'openai': + return context.USER_CONFIG.DALL_E_MODEL; + case 'workers': + return context.USER_CONFIG.WORKERS_IMAGE_MODEL; + default: + return null; + } } function imageModelKey(agentName) { - switch (agentName) { - case "azure": - return "AZURE_DALLE_API"; - case "openai": - return "DALL_E_MODEL"; - case "workers": - return "WORKERS_IMAGE_MODEL"; - default: - return null; - } + switch (agentName) { + case 'azure': + return 'AZURE_DALLE_API'; + case 'openai': + return 'DALL_E_MODEL'; + case 'workers': + return 'WORKERS_IMAGE_MODEL'; + default: + return null; + } } -// src/agent/llm.js function tokensCounter() { - return (text) => { - return text.length; - }; + return (text) => { + return text.length; + }; } async function loadHistory(key) { - let history = []; - try { - history = JSON.parse(await DATABASE.get(key)); - } catch (e) { - console.error(e); - } - if (!history || !Array.isArray(history)) { - history = []; - } - const counter = tokensCounter(); - const trimHistory = (list, initLength, maxLength, maxToken) => { - if (maxLength >= 0 && list.length > maxLength) { - list = list.splice(list.length - maxLength); - } - if (maxToken > 0) { - let tokenLength = initLength; - for (let i = list.length - 1; i >= 0; i--) { - const historyItem = list[i]; - let length = 0; - if (historyItem.content) { - length = counter(historyItem.content); - } else { - historyItem.content = ""; + let history = []; + try { + history = JSON.parse(await DATABASE.get(key)); + } catch (e) { + console.error(e); + } + if (!history || !Array.isArray(history)) { + history = []; + } + const counter = tokensCounter(); + const trimHistory = (list, initLength, maxLength, maxToken) => { + if (maxLength >= 0 && list.length > maxLength) { + list = list.splice(list.length - maxLength); } - tokenLength += length; - if (tokenLength > maxToken) { - list = list.splice(i + 1); - break; + if (maxToken > 0) { + let tokenLength = initLength; + for (let i = list.length - 1; i >= 0; i--) { + const historyItem = list[i]; + let length = 0; + if (historyItem.content) { + length = counter(historyItem.content); + } else { + historyItem.content = ''; + } + tokenLength += length; + if (tokenLength > maxToken) { + list = list.splice(i + 1); + break; + } + } } - } + return list; + }; + if (ENV.AUTO_TRIM_HISTORY && ENV.MAX_HISTORY_LENGTH > 0) { + history = trimHistory(history, 0, ENV.MAX_HISTORY_LENGTH, ENV.MAX_TOKEN_LENGTH); } - return list; - }; - if (ENV.AUTO_TRIM_HISTORY && ENV.MAX_HISTORY_LENGTH > 0) { - history = trimHistory(history, 0, ENV.MAX_HISTORY_LENGTH, ENV.MAX_TOKEN_LENGTH); - } - return history; + return history; } async function requestCompletionsFromLLM(params, context, llm, modifier, onStream) { - const historyDisable = ENV.AUTO_TRIM_HISTORY && ENV.MAX_HISTORY_LENGTH <= 0; - const historyKey = context.SHARE_CONTEXT.chatHistoryKey; - const { message, images } = params; - let history = await loadHistory(historyKey); - if (modifier) { - const modifierData = modifier(history, message); - history = modifierData.history; - params.message = modifierData.message; - } - const llmParams = { - ...params, - history, - prompt: context.USER_CONFIG.SYSTEM_INIT_MESSAGE - }; - const answer = await llm(llmParams, context, onStream); - if (!historyDisable) { - history.push({ role: "user", content: message || "", images }); - history.push({ role: "assistant", content: answer }); - await DATABASE.put(historyKey, JSON.stringify(history)).catch(console.error); - } - return answer; + const historyDisable = ENV.AUTO_TRIM_HISTORY && ENV.MAX_HISTORY_LENGTH <= 0; + const historyKey = context.SHARE_CONTEXT.chatHistoryKey; + let history = await loadHistory(historyKey); + if (modifier) { + const modifierData = modifier(history, params.message); + history = modifierData.history; + params.message = modifierData.message; + } + const llmParams = { + ...params, + history, + prompt: context.USER_CONFIG.SYSTEM_INIT_MESSAGE, + }; + const answer = await llm(llmParams, context, onStream); + if (!historyDisable) { + const userMessage = { role: 'user', content: params.message || '', images: params.images }; + if (ENV.HISTORY_IMAGE_PLACEHOLDER && userMessage.images && userMessage.images.length > 0) { + delete userMessage.images; + userMessage.content = `${ENV.HISTORY_IMAGE_PLACEHOLDER}\n${userMessage.content}`; + } + history.push(userMessage); + history.push({ role: 'assistant', content: answer }); + await DATABASE.put(historyKey, JSON.stringify(history)).catch(console.error); + } + return answer; } + async function chatWithLLM(params, context, modifier) { - try { try { - const msg = await sendMessageToTelegramWithContext(context)("...").then((r) => r.json()); - context.CURRENT_CHAT_CONTEXT.message_id = msg.result.message_id; - context.CURRENT_CHAT_CONTEXT.reply_markup = null; - } catch (e) { - console.error(e); - } - setTimeout(() => sendChatActionToTelegramWithContext(context)("typing").catch(console.error), 0); - let onStream = null; - const parseMode = context.CURRENT_CHAT_CONTEXT.parse_mode; - let nextEnableTime = null; - if (ENV.STREAM_MODE) { - context.CURRENT_CHAT_CONTEXT.parse_mode = null; - onStream = async (text) => { try { - if (nextEnableTime && nextEnableTime > Date.now()) { - return; - } - const resp = await sendMessageToTelegramWithContext(context)(text); - if (resp.status === 429) { - const retryAfter = parseInt(resp.headers.get("Retry-After")); - if (retryAfter) { - nextEnableTime = Date.now() + retryAfter * 1e3; - return; - } - } - nextEnableTime = null; - if (resp.ok) { - context.CURRENT_CHAT_CONTEXT.message_id = (await resp.json()).result.message_id; - } + const msg = await sendMessageToTelegramWithContext(context)('...').then(r => r.json()); + context.CURRENT_CHAT_CONTEXT.message_id = msg.result.message_id; + context.CURRENT_CHAT_CONTEXT.reply_markup = null; } catch (e) { - console.error(e); - } - }; - } - const llm = loadChatLLM(context)?.request; - if (llm === null) { - return sendMessageToTelegramWithContext(context)("LLM is not enable"); - } - const answer = await requestCompletionsFromLLM(params, context, llm, modifier, onStream); - context.CURRENT_CHAT_CONTEXT.parse_mode = parseMode; - if (ENV.SHOW_REPLY_BUTTON && context.CURRENT_CHAT_CONTEXT.message_id) { - try { - await deleteMessageFromTelegramWithContext(context)(context.CURRENT_CHAT_CONTEXT.message_id); - context.CURRENT_CHAT_CONTEXT.message_id = null; - context.CURRENT_CHAT_CONTEXT.reply_markup = { - keyboard: [[{ text: "/new" }, { text: "/redo" }]], - selective: true, - resize_keyboard: true, - one_time_keyboard: true - }; - } catch (e) { - console.error(e); - } - } - if (nextEnableTime && nextEnableTime > Date.now()) { - await new Promise((resolve) => setTimeout(resolve, nextEnableTime - Date.now())); - } - return sendMessageToTelegramWithContext(context)(answer); - } catch (e) { - let errMsg = `Error: ${e.message}`; - if (errMsg.length > 2048) { - errMsg = errMsg.substring(0, 2048); + console.error(e); + } + setTimeout(() => sendChatActionToTelegramWithContext(context)('typing').catch(console.error), 0); + let onStream = null; + const parseMode = context.CURRENT_CHAT_CONTEXT.parse_mode; + let nextEnableTime = null; + if (ENV.STREAM_MODE) { + context.CURRENT_CHAT_CONTEXT.parse_mode = null; + onStream = async (text) => { + try { + if (nextEnableTime && nextEnableTime > Date.now()) { + return; + } + const resp = await sendMessageToTelegramWithContext(context)(text); + if (resp.status === 429) { + const retryAfter = Number.parseInt(resp.headers.get('Retry-After')); + if (retryAfter) { + nextEnableTime = Date.now() + retryAfter * 1000; + return; + } + } + nextEnableTime = null; + if (resp.ok) { + context.CURRENT_CHAT_CONTEXT.message_id = (await resp.json()).result.message_id; + } + } catch (e) { + console.error(e); + } + }; + } + const llm = loadChatLLM(context)?.request; + if (llm === null) { + return sendMessageToTelegramWithContext(context)('LLM is not enable'); + } + const answer = await requestCompletionsFromLLM(params, context, llm, modifier, onStream); + context.CURRENT_CHAT_CONTEXT.parse_mode = parseMode; + if (nextEnableTime && nextEnableTime > Date.now()) { + await new Promise(resolve => setTimeout(resolve, nextEnableTime - Date.now())); + } + return sendMessageToTelegramWithContext(context)(answer); + } catch (e) { + let errMsg = `Error: ${e.message}`; + if (errMsg.length > 2048) { + errMsg = errMsg.substring(0, 2048); + } + context.CURRENT_CHAT_CONTEXT.disable_web_page_preview = true; + return sendMessageToTelegramWithContext(context)(errMsg); } - context.CURRENT_CHAT_CONTEXT.disable_web_page_preview = true; - return sendMessageToTelegramWithContext(context)(errMsg); - } } -// src/telegram/command.js -var commandAuthCheck = { - default(chatType) { - if (CONST.GROUP_TYPES.includes(chatType)) { - return ["administrator", "creator"]; +function checkMention(content, entities, botName, botId) { + let isMention = false; + for (const entity of entities) { + const entityStr = content.slice(entity.offset, entity.offset + entity.length); + switch (entity.type) { + case 'mention': + if (entityStr === `@${botName}`) { + isMention = true; + content = content.slice(0, entity.offset) + content.slice(entity.offset + entity.length); + } + break; + case 'text_mention': + if (`${entity.user.id}` === `${botId}`) { + isMention = true; + content = content.slice(0, entity.offset) + content.slice(entity.offset + entity.length); + } + break; + case 'bot_command': + if (entityStr.endsWith(`@${botName}`)) { + isMention = true; + const newEntityStr = entityStr.replace(`@${botName}`, ''); + content = content.slice(0, entity.offset) + newEntityStr + content.slice(entity.offset + entity.length); + } + break; + } } - return null; - }, - shareModeGroup(chatType) { - if (CONST.GROUP_TYPES.includes(chatType)) { - if (!ENV.GROUP_CHAT_BOT_SHARE_MODE) { - return false; - } - return ["administrator", "creator"]; + return { + isMention, + content, + }; +} +function findPhotoFileID(photos, offset) { + let sizeIndex = 0; + if (offset >= 0) { + sizeIndex = offset; + } else if (offset < 0) { + sizeIndex = photos.length + offset; + } + sizeIndex = Math.max(0, Math.min(sizeIndex, photos.length - 1)); + return photos[sizeIndex].file_id; +}async function getChatRoleWithContext(context) { + const { + chatId, + speakerId, + groupAdminKey, + currentBotToken: token, + allMemberAreAdmin, + } = context.SHARE_CONTEXT; + if (allMemberAreAdmin) { + return 'administrator'; + } + let groupAdmin; + try { + groupAdmin = JSON.parse(await DATABASE.get(groupAdminKey)); + } catch (e) { + console.error(e); } - return null; - } + if (!groupAdmin || !Array.isArray(groupAdmin) || groupAdmin.length === 0) { + const { result } = await getChatAdministrators(chatId, token); + if (result == null) { + return null; + } + groupAdmin = result; + await DATABASE.put( + groupAdminKey, + JSON.stringify(groupAdmin), + { expiration: (Date.now() / 1000) + 120 }, + ); + } + for (let i = 0; i < groupAdmin.length; i++) { + const user = groupAdmin[i]; + if (`${user.user.id}` === `${speakerId}`) { + return user.status; + } + } + return 'member'; +} + +const commandAuthCheck = { + default(chatType) { + if (CONST.GROUP_TYPES.includes(chatType)) { + return ['administrator', 'creator']; + } + return null; + }, + shareModeGroup(chatType) { + if (CONST.GROUP_TYPES.includes(chatType)) { + if (!ENV.GROUP_CHAT_BOT_SHARE_MODE) { + return false; + } + return ['administrator', 'creator']; + } + return null; + }, }; -var commandSortList = [ - "/new", - "/redo", - "/img", - "/setenv", - "/delenv", - "/version", - "/system", - "/help" +const commandSortList = [ + '/new', + '/redo', + '/img', + '/setenv', + '/delenv', + '/version', + '/system', + '/help', ]; -var commandHandlers = { - "/help": { - scopes: ["all_private_chats", "all_chat_administrators"], - fn: commandGetHelp - }, - "/new": { - scopes: ["all_private_chats", "all_group_chats", "all_chat_administrators"], - fn: commandCreateNewChatContext - }, - "/start": { - scopes: [], - fn: commandCreateNewChatContext - }, - "/img": { - scopes: ["all_private_chats", "all_chat_administrators"], - fn: commandGenerateImg - }, - "/version": { - scopes: ["all_private_chats", "all_chat_administrators"], - fn: commandFetchUpdate - }, - "/setenv": { - scopes: [], - fn: commandUpdateUserConfig, - needAuth: commandAuthCheck.shareModeGroup - }, - "/setenvs": { - scopes: [], - fn: commandUpdateUserConfigs, - needAuth: commandAuthCheck.shareModeGroup - }, - "/delenv": { - scopes: [], - fn: commandDeleteUserConfig, - needAuth: commandAuthCheck.shareModeGroup - }, - "/clearenv": { - scopes: [], - fn: commandClearUserConfig, - needAuth: commandAuthCheck.shareModeGroup - }, - "/system": { - scopes: ["all_private_chats", "all_chat_administrators"], - fn: commandSystem, - needAuth: commandAuthCheck.default - }, - "/redo": { - scopes: ["all_private_chats", "all_group_chats", "all_chat_administrators"], - fn: commandRegenerate - } +const commandHandlers = { + '/help': { + scopes: ['all_private_chats', 'all_chat_administrators'], + fn: commandGetHelp, + }, + '/new': { + scopes: ['all_private_chats', 'all_group_chats', 'all_chat_administrators'], + fn: commandCreateNewChatContext, + }, + '/start': { + scopes: [], + fn: commandCreateNewChatContext, + }, + '/img': { + scopes: ['all_private_chats', 'all_chat_administrators'], + fn: commandGenerateImg, + }, + '/version': { + scopes: ['all_private_chats', 'all_chat_administrators'], + fn: commandFetchUpdate, + }, + '/setenv': { + scopes: [], + fn: commandUpdateUserConfig, + needAuth: commandAuthCheck.shareModeGroup, + }, + '/setenvs': { + scopes: [], + fn: commandUpdateUserConfigs, + needAuth: commandAuthCheck.shareModeGroup, + }, + '/delenv': { + scopes: [], + fn: commandDeleteUserConfig, + needAuth: commandAuthCheck.shareModeGroup, + }, + '/clearenv': { + scopes: [], + fn: commandClearUserConfig, + needAuth: commandAuthCheck.shareModeGroup, + }, + '/system': { + scopes: ['all_private_chats', 'all_chat_administrators'], + fn: commandSystem, + needAuth: commandAuthCheck.default, + }, + '/redo': { + scopes: ['all_private_chats', 'all_group_chats', 'all_chat_administrators'], + fn: commandRegenerate, + }, }; async function commandGenerateImg(message, command, subcommand, context) { - if (subcommand === "") { - return sendMessageToTelegramWithContext(context)(ENV.I18N.command.help.img); - } - try { - const gen = loadImageGen(context)?.request; - if (!gen) { - return sendMessageToTelegramWithContext(context)("ERROR: Image generator not found"); - } - setTimeout(() => sendChatActionToTelegramWithContext(context)("upload_photo").catch(console.error), 0); - const img = await gen(subcommand, context); - return sendPhotoToTelegramWithContext(context)(img); - } catch (e) { - return sendMessageToTelegramWithContext(context)(`ERROR: ${e.message}`); - } + if (subcommand === '') { + return sendMessageToTelegramWithContext(context)(ENV.I18N.command.help.img); + } + try { + const gen = loadImageGen(context)?.request; + if (!gen) { + return sendMessageToTelegramWithContext(context)('ERROR: Image generator not found'); + } + setTimeout(() => sendChatActionToTelegramWithContext(context)('upload_photo').catch(console.error), 0); + const img = await gen(subcommand, context); + const resp = await sendPhotoToTelegramWithContext(context)(img); + if (!resp.ok) { + return sendMessageToTelegramWithContext(context)(`ERROR: ${resp.statusText} ${await resp.text()}`); + } + return resp; + } catch (e) { + return sendMessageToTelegramWithContext(context)(`ERROR: ${e.message}`); + } } async function commandGetHelp(message, command, subcommand, context) { - let helpMsg = ENV.I18N.command.help.summary + "\n"; - helpMsg += Object.keys(commandHandlers).map((key) => `${key}\uFF1A${ENV.I18N.command.help[key.substring(1)]}`).join("\n"); - helpMsg += Object.keys(CUSTOM_COMMAND).filter((key) => !!CUSTOM_COMMAND_DESCRIPTION[key]).map((key) => `${key}\uFF1A${CUSTOM_COMMAND_DESCRIPTION[key]}`).join("\n"); - return sendMessageToTelegramWithContext(context)(helpMsg); + let helpMsg = `${ENV.I18N.command.help.summary}\n`; + helpMsg += Object.keys(commandHandlers) + .map(key => `${key}:${ENV.I18N.command.help[key.substring(1)]}`) + .join('\n'); + helpMsg += Object.keys(CUSTOM_COMMAND) + .filter(key => !!CUSTOM_COMMAND_DESCRIPTION[key]) + .map(key => `${key}:${CUSTOM_COMMAND_DESCRIPTION[key]}`) + .join('\n'); + return sendMessageToTelegramWithContext(context)(helpMsg); } async function commandCreateNewChatContext(message, command, subcommand, context) { - try { - await DATABASE.delete(context.SHARE_CONTEXT.chatHistoryKey); - context.CURRENT_CHAT_CONTEXT.reply_markup = JSON.stringify({ - remove_keyboard: true, - selective: true - }); - if (command === "/new") { - return sendMessageToTelegramWithContext(context)(ENV.I18N.command.new.new_chat_start); - } else { - return sendMessageToTelegramWithContext(context)(`${ENV.I18N.command.new.new_chat_start}(${context.CURRENT_CHAT_CONTEXT.chat_id})`); + try { + await DATABASE.delete(context.SHARE_CONTEXT.chatHistoryKey); + const isNewCommand = command.startsWith('/new'); + const text = ENV.I18N.command.new.new_chat_start + (isNewCommand ? '' : `(${context.CURRENT_CHAT_CONTEXT.chat_id})`); + if (ENV.SHOW_REPLY_BUTTON && !CONST.GROUP_TYPES.includes(context.SHARE_CONTEXT.chatType)) { + context.CURRENT_CHAT_CONTEXT.reply_markup = { + keyboard: [[{ text: '/new' }, { text: '/redo' }]], + selective: true, + resize_keyboard: true, + one_time_keyboard: false, + }; + } else { + context.CURRENT_CHAT_CONTEXT.reply_markup = { + remove_keyboard: true, + selective: true, + }; + } + return sendMessageToTelegramWithContext(context)(text); + } catch (e) { + return sendMessageToTelegramWithContext(context)(`ERROR: ${e.message}`); } - } catch (e) { - return sendMessageToTelegramWithContext(context)(`ERROR: ${e.message}`); - } } async function commandUpdateUserConfig(message, command, subcommand, context) { - const kv = subcommand.indexOf("="); - if (kv === -1) { - return sendMessageToTelegramWithContext(context)(ENV.I18N.command.help.setenv); - } - let key = subcommand.slice(0, kv); - const value = subcommand.slice(kv + 1); - key = ENV_KEY_MAPPER[key] || key; - if (ENV.LOCK_USER_CONFIG_KEYS.includes(key)) { - return sendMessageToTelegramWithContext(context)(`Key ${key} is locked`); - } - if (!Object.keys(context.USER_CONFIG).includes(key)) { - return sendMessageToTelegramWithContext(context)(`Key ${key} not found`); - } - try { - context.USER_CONFIG.DEFINE_KEYS.push(key); - context.USER_CONFIG.DEFINE_KEYS = Array.from(new Set(context.USER_CONFIG.DEFINE_KEYS)); - mergeEnvironment(context.USER_CONFIG, { - [key]: value - }); - console.log("Update user config: ", key, context.USER_CONFIG[key]); - await DATABASE.put( - context.SHARE_CONTEXT.configStoreKey, - JSON.stringify(trimUserConfig(context.USER_CONFIG)) - ); - return sendMessageToTelegramWithContext(context)("Update user config success"); - } catch (e) { - return sendMessageToTelegramWithContext(context)(`ERROR: ${e.message}`); - } -} -async function commandUpdateUserConfigs(message, command, subcommand, context) { - try { - const values = JSON.parse(subcommand); - const configKeys = Object.keys(context.USER_CONFIG); - for (const ent of Object.entries(values)) { - let [key, value] = ent; - key = ENV_KEY_MAPPER[key] || key; - if (ENV.LOCK_USER_CONFIG_KEYS.includes(key)) { + const kv = subcommand.indexOf('='); + if (kv === -1) { + return sendMessageToTelegramWithContext(context)(ENV.I18N.command.help.setenv); + } + let key = subcommand.slice(0, kv); + const value = subcommand.slice(kv + 1); + key = ENV_KEY_MAPPER[key] || key; + if (ENV.LOCK_USER_CONFIG_KEYS.includes(key)) { return sendMessageToTelegramWithContext(context)(`Key ${key} is locked`); - } - if (!configKeys.includes(key)) { + } + if (!Object.keys(context.USER_CONFIG).includes(key)) { return sendMessageToTelegramWithContext(context)(`Key ${key} not found`); - } - context.USER_CONFIG.DEFINE_KEYS.push(key); - mergeEnvironment(context.USER_CONFIG, { - [key]: value - }); - console.log("Update user config: ", key, context.USER_CONFIG[key]); - } - context.USER_CONFIG.DEFINE_KEYS = Array.from(new Set(context.USER_CONFIG.DEFINE_KEYS)); - await DATABASE.put( - context.SHARE_CONTEXT.configStoreKey, - JSON.stringify(trimUserConfig(trimUserConfig(context.USER_CONFIG))) - ); - return sendMessageToTelegramWithContext(context)("Update user config success"); - } catch (e) { - return sendMessageToTelegramWithContext(context)(`ERROR: ${e.message}`); - } + } + try { + context.USER_CONFIG.DEFINE_KEYS.push(key); + context.USER_CONFIG.DEFINE_KEYS = Array.from(new Set(context.USER_CONFIG.DEFINE_KEYS)); + mergeEnvironment(context.USER_CONFIG, { + [key]: value, + }); + console.log('Update user config: ', key, context.USER_CONFIG[key]); + await DATABASE.put( + context.SHARE_CONTEXT.configStoreKey, + JSON.stringify(trimUserConfig(context.USER_CONFIG)), + ); + return sendMessageToTelegramWithContext(context)('Update user config success'); + } catch (e) { + return sendMessageToTelegramWithContext(context)(`ERROR: ${e.message}`); + } +} +async function commandUpdateUserConfigs(message, command, subcommand, context) { + try { + const values = JSON.parse(subcommand); + const configKeys = Object.keys(context.USER_CONFIG); + for (const ent of Object.entries(values)) { + let [key, value] = ent; + key = ENV_KEY_MAPPER[key] || key; + if (ENV.LOCK_USER_CONFIG_KEYS.includes(key)) { + return sendMessageToTelegramWithContext(context)(`Key ${key} is locked`); + } + if (!configKeys.includes(key)) { + return sendMessageToTelegramWithContext(context)(`Key ${key} not found`); + } + context.USER_CONFIG.DEFINE_KEYS.push(key); + mergeEnvironment(context.USER_CONFIG, { + [key]: value, + }); + console.log('Update user config: ', key, context.USER_CONFIG[key]); + } + context.USER_CONFIG.DEFINE_KEYS = Array.from(new Set(context.USER_CONFIG.DEFINE_KEYS)); + await DATABASE.put( + context.SHARE_CONTEXT.configStoreKey, + JSON.stringify(trimUserConfig(trimUserConfig(context.USER_CONFIG))), + ); + return sendMessageToTelegramWithContext(context)('Update user config success'); + } catch (e) { + return sendMessageToTelegramWithContext(context)(`ERROR: ${e.message}`); + } } async function commandDeleteUserConfig(message, command, subcommand, context) { - if (ENV.LOCK_USER_CONFIG_KEYS.includes(subcommand)) { - const msg = `Key ${subcommand} is locked`; - return sendMessageToTelegramWithContext(context)(msg); - } - try { - context.USER_CONFIG[subcommand] = null; - context.USER_CONFIG.DEFINE_KEYS = context.USER_CONFIG.DEFINE_KEYS.filter((key) => key !== subcommand); - await DATABASE.put( - context.SHARE_CONTEXT.configStoreKey, - JSON.stringify(trimUserConfig(context.USER_CONFIG)) - ); - return sendMessageToTelegramWithContext(context)("Delete user config success"); - } catch (e) { - return sendMessageToTelegramWithContext(context)(`ERROR: ${e.message}`); - } + if (ENV.LOCK_USER_CONFIG_KEYS.includes(subcommand)) { + const msg = `Key ${subcommand} is locked`; + return sendMessageToTelegramWithContext(context)(msg); + } + try { + context.USER_CONFIG[subcommand] = null; + context.USER_CONFIG.DEFINE_KEYS = context.USER_CONFIG.DEFINE_KEYS.filter(key => key !== subcommand); + await DATABASE.put( + context.SHARE_CONTEXT.configStoreKey, + JSON.stringify(trimUserConfig(context.USER_CONFIG)), + ); + return sendMessageToTelegramWithContext(context)('Delete user config success'); + } catch (e) { + return sendMessageToTelegramWithContext(context)(`ERROR: ${e.message}`); + } } async function commandClearUserConfig(message, command, subcommand, context) { - try { - await DATABASE.put( - context.SHARE_CONTEXT.configStoreKey, - JSON.stringify({}) - ); - return sendMessageToTelegramWithContext(context)("Clear user config success"); - } catch (e) { - return sendMessageToTelegramWithContext(context)(`ERROR: ${e.message}`); - } + try { + await DATABASE.put( + context.SHARE_CONTEXT.configStoreKey, + JSON.stringify({}), + ); + return sendMessageToTelegramWithContext(context)('Clear user config success'); + } catch (e) { + return sendMessageToTelegramWithContext(context)(`ERROR: ${e.message}`); + } } async function commandFetchUpdate(message, command, subcommand, context) { - const current = { - ts: ENV.BUILD_TIMESTAMP, - sha: ENV.BUILD_VERSION - }; - try { - const info = `https://raw.githubusercontent.com/TBXark/ChatGPT-Telegram-Workers/${ENV.UPDATE_BRANCH}/dist/buildinfo.json`; - const online = await fetch(info).then((r) => r.json()); - const timeFormat = (ts) => { - return new Date(ts * 1e3).toLocaleString("en-US", {}); + const current = { + ts: ENV.BUILD_TIMESTAMP, + sha: ENV.BUILD_VERSION, }; - if (current.ts < online.ts) { - return sendMessageToTelegramWithContext(context)(`New version detected: ${online.sha}(${timeFormat(online.ts)}) -Current version: ${current.sha}(${timeFormat(current.ts)})`); - } else { - return sendMessageToTelegramWithContext(context)(`Current version: ${current.sha}(${timeFormat(current.ts)}) is up to date`); + try { + const info = `https://raw.githubusercontent.com/TBXark/ChatGPT-Telegram-Workers/${ENV.UPDATE_BRANCH}/dist/buildinfo.json`; + const online = await fetch(info).then(r => r.json()); + const timeFormat = (ts) => { + return new Date(ts * 1000).toLocaleString('en-US', {}); + }; + if (current.ts < online.ts) { + return sendMessageToTelegramWithContext(context)(`New version detected: ${online.sha}(${timeFormat(online.ts)})\nCurrent version: ${current.sha}(${timeFormat(current.ts)})`); + } else { + return sendMessageToTelegramWithContext(context)(`Current version: ${current.sha}(${timeFormat(current.ts)}) is up to date`); + } + } catch (e) { + return sendMessageToTelegramWithContext(context)(`ERROR: ${e.message}`); } - } catch (e) { - return sendMessageToTelegramWithContext(context)(`ERROR: ${e.message}`); - } } async function commandSystem(message, command, subcommand, context) { - let chatAgent = loadChatLLM(context)?.name; - let imageAgent = loadImageGen(context)?.name; - const agent = { - AI_PROVIDER: chatAgent, - AI_IMAGE_PROVIDER: imageAgent - }; - if (chatModelKey(chatAgent)) { - agent[chatModelKey(chatAgent)] = currentChatModel(chatAgent, context); - } - if (imageModelKey(imageAgent)) { - agent[imageModelKey(imageAgent)] = currentImageModel(imageAgent, context); - } - let msg = `AGENT: ${JSON.stringify(agent, null, 2)} -`; - if (ENV.DEV_MODE) { - const shareCtx = { ...context.SHARE_CONTEXT }; - shareCtx.currentBotToken = "******"; - context.USER_CONFIG.OPENAI_API_KEY = ["******"]; - context.USER_CONFIG.AZURE_API_KEY = "******"; - context.USER_CONFIG.AZURE_COMPLETIONS_API = "******"; - context.USER_CONFIG.AZURE_DALLE_API = "******"; - context.USER_CONFIG.CLOUDFLARE_ACCOUNT_ID = "******"; - context.USER_CONFIG.CLOUDFLARE_TOKEN = "******"; - context.USER_CONFIG.GOOGLE_API_KEY = "******"; - context.USER_CONFIG.MISTRAL_API_KEY = "******"; - context.USER_CONFIG.COHERE_API_KEY = "******"; - context.USER_CONFIG.ANTHROPIC_API_KEY = "******"; - const config = trimUserConfig(context.USER_CONFIG); - msg = "
\n" + msg;
-    msg += `USER_CONFIG: ${JSON.stringify(config, null, 2)}
-`;
-    msg += `CHAT_CONTEXT: ${JSON.stringify(context.CURRENT_CHAT_CONTEXT, null, 2)}
-`;
-    msg += `SHARE_CONTEXT: ${JSON.stringify(shareCtx, null, 2)}
-`;
-    msg += "
"; - } - context.CURRENT_CHAT_CONTEXT.parse_mode = "HTML"; - return sendMessageToTelegramWithContext(context)(msg); + const chatAgent = loadChatLLM(context)?.name; + const imageAgent = loadImageGen(context)?.name; + const agent = { + AI_PROVIDER: chatAgent, + AI_IMAGE_PROVIDER: imageAgent, + }; + if (chatModelKey(chatAgent)) { + agent[chatModelKey(chatAgent)] = currentChatModel(chatAgent, context); + } + if (imageModelKey(imageAgent)) { + agent[imageModelKey(imageAgent)] = currentImageModel(imageAgent, context); + } + let msg = `AGENT: ${JSON.stringify(agent, null, 2)}\n`; + if (ENV.DEV_MODE) { + const shareCtx = { ...context.SHARE_CONTEXT }; + shareCtx.currentBotToken = '******'; + context.USER_CONFIG.OPENAI_API_KEY = ['******']; + context.USER_CONFIG.AZURE_API_KEY = '******'; + context.USER_CONFIG.AZURE_COMPLETIONS_API = '******'; + context.USER_CONFIG.AZURE_DALLE_API = '******'; + context.USER_CONFIG.CLOUDFLARE_ACCOUNT_ID = '******'; + context.USER_CONFIG.CLOUDFLARE_TOKEN = '******'; + context.USER_CONFIG.GOOGLE_API_KEY = '******'; + context.USER_CONFIG.MISTRAL_API_KEY = '******'; + context.USER_CONFIG.COHERE_API_KEY = '******'; + context.USER_CONFIG.ANTHROPIC_API_KEY = '******'; + const config = trimUserConfig(context.USER_CONFIG); + msg = `
\n${msg}`;
+        msg += `USER_CONFIG: ${JSON.stringify(config, null, 2)}\n`;
+        msg += `CHAT_CONTEXT: ${JSON.stringify(context.CURRENT_CHAT_CONTEXT, null, 2)}\n`;
+        msg += `SHARE_CONTEXT: ${JSON.stringify(shareCtx, null, 2)}\n`;
+        msg += '
'; + } + context.CURRENT_CHAT_CONTEXT.parse_mode = 'HTML'; + return sendMessageToTelegramWithContext(context)(msg); } async function commandRegenerate(message, command, subcommand, context) { - const mf = (history, text) => { - let nextText = text; - if (!(history && Array.isArray(history) && history.length > 0)) { - throw new Error("History not found"); - } - const historyCopy = structuredClone(history); - while (true) { - const data = historyCopy.pop(); - if (data === void 0 || data === null) { - break; - } else if (data.role === "user") { - if (text === "" || text === void 0 || text === null) { - nextText = data.content; + const mf = (history, text) => { + let nextText = text; + if (!(history && Array.isArray(history) && history.length > 0)) { + throw new Error('History not found'); } - break; - } - } - if (subcommand) { - nextText = subcommand; - } - return { history: historyCopy, message: nextText }; - }; - return chatWithLLM({ message: null }, context, mf); + const historyCopy = structuredClone(history); + while (true) { + const data = historyCopy.pop(); + if (data === undefined || data === null) { + break; + } else if (data.role === 'user') { + if (text === '' || text === undefined || text === null) { + nextText = data.content; + } + break; + } + } + if (subcommand) { + nextText = subcommand; + } + return { history: historyCopy, message: nextText }; + }; + return chatWithLLM({ message: null }, context, mf); } async function commandEcho(message, command, subcommand, context) { - let msg = "
";
-  msg += JSON.stringify({ message }, null, 2);
-  msg += "
"; - context.CURRENT_CHAT_CONTEXT.parse_mode = "HTML"; - return sendMessageToTelegramWithContext(context)(msg); + let msg = '
';
+    msg += JSON.stringify({ message }, null, 2);
+    msg += '
'; + context.CURRENT_CHAT_CONTEXT.parse_mode = 'HTML'; + return sendMessageToTelegramWithContext(context)(msg); } async function handleCommandMessage(message, context) { - if (ENV.DEV_MODE) { - commandHandlers["/echo"] = { - help: "[DEBUG ONLY] echo message", - scopes: ["all_private_chats", "all_chat_administrators"], - fn: commandEcho, - needAuth: commandAuthCheck.default - }; - } - if (CUSTOM_COMMAND[message.text]) { - message.text = CUSTOM_COMMAND[message.text]; - } - for (const key in commandHandlers) { - if (message.text === key || message.text.startsWith(key + " ")) { - const command = commandHandlers[key]; - try { - if (command.needAuth) { - const roleList = command.needAuth(context.SHARE_CONTEXT.chatType); - if (roleList) { - const chatRole = await getChatRoleWithContext(context)(context.SHARE_CONTEXT.speakerId); - if (chatRole === null) { - return sendMessageToTelegramWithContext(context)("ERROR: Get chat role failed"); + if (ENV.DEV_MODE) { + commandHandlers['/echo'] = { + help: '[DEBUG ONLY] echo message', + scopes: ['all_private_chats', 'all_chat_administrators'], + fn: commandEcho, + needAuth: commandAuthCheck.default, + }; + } + if (CUSTOM_COMMAND[message.text]) { + message.text = CUSTOM_COMMAND[message.text]; + } + for (const key in commandHandlers) { + if (message.text === key || message.text.startsWith(`${key} `)) { + const command = commandHandlers[key]; + try { + if (command.needAuth) { + const roleList = command.needAuth(context.SHARE_CONTEXT.chatType); + if (roleList) { + const chatRole = await getChatRoleWithContext(context); + if (chatRole === null) { + return sendMessageToTelegramWithContext(context)('ERROR: Get chat role failed'); + } + if (!roleList.includes(chatRole)) { + return sendMessageToTelegramWithContext(context)(`ERROR: Permission denied, need ${roleList.join(' or ')}`); + } + } + } + } catch (e) { + return sendMessageToTelegramWithContext(context)(`ERROR: ${e.message}`); } - if (!roleList.includes(chatRole)) { - return sendMessageToTelegramWithContext(context)(`ERROR: Permission denied, need ${roleList.join(" or ")}`); + const subcommand = message.text.substring(key.length).trim(); + try { + return await command.fn(message, key, subcommand, context); + } catch (e) { + return sendMessageToTelegramWithContext(context)(`ERROR: ${e.message}`); } - } } - } catch (e) { - return sendMessageToTelegramWithContext(context)(`ERROR: ${e.message}`); - } - const subcommand = message.text.substring(key.length).trim(); - try { - return await command.fn(message, key, subcommand, context); - } catch (e) { - return sendMessageToTelegramWithContext(context)(`ERROR: ${e.message}`); - } } - } - return null; + return null; } async function bindCommandForTelegram(token) { - const scopeCommandMap = { - all_private_chats: [], - all_group_chats: [], - all_chat_administrators: [] - }; - for (const key of commandSortList) { - if (ENV.HIDE_COMMAND_BUTTONS.includes(key)) { - continue; - } - if (Object.prototype.hasOwnProperty.call(commandHandlers, key) && commandHandlers[key].scopes) { - for (const scope of commandHandlers[key].scopes) { - if (!scopeCommandMap[scope]) { - scopeCommandMap[scope] = []; + const scopeCommandMap = { + all_private_chats: [], + all_group_chats: [], + all_chat_administrators: [], + }; + for (const key of commandSortList) { + if (ENV.HIDE_COMMAND_BUTTONS.includes(key)) { + continue; + } + if (Object.prototype.hasOwnProperty.call(commandHandlers, key) && commandHandlers[key].scopes) { + for (const scope of commandHandlers[key].scopes) { + if (!scopeCommandMap[scope]) { + scopeCommandMap[scope] = []; + } + scopeCommandMap[scope].push(key); + } } - scopeCommandMap[scope].push(key); - } } - } - const result = {}; - for (const scope in scopeCommandMap) { - result[scope] = await fetch( - `https://api.telegram.org/bot${token}/setMyCommands`, - { - method: "POST", - headers: { - "Content-Type": "application/json" - }, - body: JSON.stringify({ - commands: scopeCommandMap[scope].map((command) => ({ - command, - description: ENV.I18N.command.help[command.substring(1)] || "" - })), - scope: { - type: scope - } - }) - } - ).then((res) => res.json()); - } - return { ok: true, result }; + const result = {}; + for (const scope in scopeCommandMap) { + result[scope] = await fetch( + `https://api.telegram.org/bot${token}/setMyCommands`, + { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + commands: scopeCommandMap[scope].map(command => ({ + command, + description: ENV.I18N.command.help[command.substring(1)] || '', + })), + scope: { + type: scope, + }, + }), + }, + ).then(res => res.json()); + } + return { ok: true, result }; } function commandsDocument() { - return Object.keys(commandHandlers).map((key) => { - return { - command: key, - description: ENV.I18N.command.help[key.substring(1)] - }; - }); -} - -// src/utils/utils.js -function renderHTML(body) { - return ` - - - ChatGPT-Telegram-Workers - - - - - - - - ${body} - - - `; -} -function errorToString(e) { - return JSON.stringify({ - message: e.message, - stack: e.stack - }); -} -function makeResponse200(resp) { - if (resp === null) { - return new Response("NOT HANDLED", { status: 200 }); - } - if (resp.status === 200) { - return resp; - } else { - return new Response(resp.body, { - status: 200, - headers: { - "Original-Status": resp.status, - ...resp.headers - } + return Object.keys(commandHandlers).map((key) => { + return { + command: key, + description: ENV.I18N.command.help[key.substring(1)], + }; }); - } } -// src/telegram/message.js async function msgInitChatContext(message, context) { - await context.initContext(message); - return null; + await context.initContext(message); + return null; } async function msgSaveLastMessage(message, context) { - if (ENV.DEBUG_MODE) { - const lastMessageKey = `last_message:${context.SHARE_CONTEXT.chatHistoryKey}`; - await DATABASE.put(lastMessageKey, JSON.stringify(message), { expirationTtl: 3600 }); - } - return null; + if (ENV.DEBUG_MODE) { + const lastMessageKey = `last_message:${context.SHARE_CONTEXT.chatHistoryKey}`; + await DATABASE.put(lastMessageKey, JSON.stringify(message), { expirationTtl: 3600 }); + } + return null; } async function msgIgnoreOldMessage(message, context) { - if (ENV.SAFE_MODE) { - let idList = []; - try { - idList = JSON.parse(await DATABASE.get(context.SHARE_CONTEXT.chatLastMessageIdKey).catch(() => "[]")) || []; - } catch (e) { - console.error(e); - } - if (idList.includes(message.message_id)) { - throw new Error("Ignore old message"); - } else { - idList.push(message.message_id); - if (idList.length > 100) { - idList.shift(); - } - await DATABASE.put(context.SHARE_CONTEXT.chatLastMessageIdKey, JSON.stringify(idList)); + if (ENV.SAFE_MODE) { + let idList = []; + try { + idList = JSON.parse(await DATABASE.get(context.SHARE_CONTEXT.chatLastMessageIdKey).catch(() => '[]')) || []; + } catch (e) { + console.error(e); + } + if (idList.includes(message.message_id)) { + throw new Error('Ignore old message'); + } else { + idList.push(message.message_id); + if (idList.length > 100) { + idList.shift(); + } + await DATABASE.put(context.SHARE_CONTEXT.chatLastMessageIdKey, JSON.stringify(idList)); + } } - } - return null; + return null; } async function msgCheckEnvIsReady(message, context) { - if (!DATABASE) { - return sendMessageToTelegramWithContext(context)("DATABASE Not Set"); - } - return null; + if (!DATABASE) { + return sendMessageToTelegramWithContext(context)('DATABASE Not Set'); + } + return null; } async function msgFilterWhiteList(message, context) { - if (ENV.I_AM_A_GENEROUS_PERSON) { - return null; - } - if (context.SHARE_CONTEXT.chatType === "private") { - if (!ENV.CHAT_WHITE_LIST.includes(`${context.CURRENT_CHAT_CONTEXT.chat_id}`)) { - return sendMessageToTelegramWithContext(context)( - `You are not in the white list, please contact the administrator to add you to the white list. Your chat_id: ${context.CURRENT_CHAT_CONTEXT.chat_id}` - ); + if (ENV.I_AM_A_GENEROUS_PERSON) { + return null; } - return null; - } - if (CONST.GROUP_TYPES.includes(context.SHARE_CONTEXT.chatType)) { - if (!ENV.GROUP_CHAT_BOT_ENABLE) { - throw new Error("Not support"); + if (context.SHARE_CONTEXT.chatType === 'private') { + if (!ENV.CHAT_WHITE_LIST.includes(`${context.CURRENT_CHAT_CONTEXT.chat_id}`)) { + return sendMessageToTelegramWithContext(context)( + `You are not in the white list, please contact the administrator to add you to the white list. Your chat_id: ${context.CURRENT_CHAT_CONTEXT.chat_id}`, + ); + } + return null; } - if (!ENV.CHAT_GROUP_WHITE_LIST.includes(`${context.CURRENT_CHAT_CONTEXT.chat_id}`)) { - return sendMessageToTelegramWithContext(context)( - `Your group are not in the white list, please contact the administrator to add you to the white list. Your chat_id: ${context.CURRENT_CHAT_CONTEXT.chat_id}` - ); + if (CONST.GROUP_TYPES.includes(context.SHARE_CONTEXT.chatType)) { + if (!ENV.GROUP_CHAT_BOT_ENABLE) { + throw new Error('Not support'); + } + if (!ENV.CHAT_GROUP_WHITE_LIST.includes(`${context.CURRENT_CHAT_CONTEXT.chat_id}`)) { + return sendMessageToTelegramWithContext(context)( + `Your group are not in the white list, please contact the administrator to add you to the white list. Your chat_id: ${context.CURRENT_CHAT_CONTEXT.chat_id}`, + ); + } + return null; } - return null; - } - return sendMessageToTelegramWithContext(context)( - `Not support chat type: ${context.SHARE_CONTEXT.chatType}` - ); + return sendMessageToTelegramWithContext(context)( + `Not support chat type: ${context.SHARE_CONTEXT.chatType}`, + ); } async function msgFilterUnsupportedMessage(message, context) { - if (message.text) { - return null; - } - if (message.caption) { - return null; - } - if (message.photo) { - return null; - } - throw new Error("Not supported message type"); + if (message.text) { + return null; + } + if (message.caption) { + return null; + } + if (message.photo) { + return null; + } + throw new Error('Not supported message type'); } async function msgHandleGroupMessage(message, context) { - if (!CONST.GROUP_TYPES.includes(context.SHARE_CONTEXT.chatType)) { - return null; - } - let botName = context.SHARE_CONTEXT.currentBotName; - if (message.reply_to_message) { - if (`${message.reply_to_message.from.id}` === context.SHARE_CONTEXT.currentBotId) { - return null; - } else if (ENV.EXTRA_MESSAGE_CONTEXT) { - context.SHARE_CONTEXT.extraMessageContext = message.reply_to_message; + if (!CONST.GROUP_TYPES.includes(context.SHARE_CONTEXT.chatType)) { + return null; } - } - if (!botName) { - const res = await getBot(context.SHARE_CONTEXT.currentBotToken); - context.SHARE_CONTEXT.currentBotName = res.info.bot_name; - botName = res.info.bot_name; - } - if (!botName) { - throw new Error("Not set bot name"); - } - if (!message.entities) { - throw new Error("No entities"); - } - const { text, caption } = message; - let originContent = text || caption || ""; - if (!originContent) { - throw new Error("Empty message"); - } - let content = ""; - let offset = 0; - let mentioned = false; - for (const entity of message.entities) { - switch (entity.type) { - case "bot_command": - if (!mentioned) { - const mention = originContent.substring( - entity.offset, - entity.offset + entity.length - ); - if (mention.endsWith(botName)) { - mentioned = true; - } - const cmd = mention.replaceAll("@" + botName, "").replaceAll(botName, "").trim(); - content += cmd; - offset = entity.offset + entity.length; - } - break; - case "mention": - case "text_mention": - if (!mentioned) { - const mention = originContent.substring( - entity.offset, - entity.offset + entity.length - ); - if (mention === botName || mention === "@" + botName) { - mentioned = true; - } + if (message.reply_to_message) { + if (`${message.reply_to_message.from.id}` === context.SHARE_CONTEXT.currentBotId) { + return null; + } else if (ENV.EXTRA_MESSAGE_CONTEXT) { + context.SHARE_CONTEXT.extraMessageContext = message.reply_to_message; } - content += originContent.substring(offset, entity.offset); - offset = entity.offset + entity.length; - break; } - } - content += originContent.substring(offset, originContent.length); - message.text = content.trim(); - if (!mentioned) { - throw new Error("No mentioned"); - } - return null; + let botName = context.SHARE_CONTEXT.currentBotName; + if (!botName) { + botName = await getBotName(context.SHARE_CONTEXT.currentBotToken); + context.SHARE_CONTEXT.currentBotName = botName; + } + if (!botName) { + throw new Error('Not set bot name'); + } + let isMention = false; + if (message.text && message.entities) { + const res = checkMention(message.text, message.entities, botName, context.SHARE_CONTEXT.currentBotId); + isMention = res.isMention; + message.text = res.content.trim(); + } + if (message.caption && message.caption_entities) { + const res = checkMention(message.caption, message.caption_entities, botName, context.SHARE_CONTEXT.currentBotId); + isMention = res.isMention || isMention; + message.caption = res.content.trim(); + } + if (!isMention) { + throw new Error('Not mention'); + } + return null; } async function msgHandleCommand(message, context) { - if (!message.text) { - return null; - } - return await handleCommandMessage(message, context); + if (!message.text) { + return null; + } + return await handleCommandMessage(message, context); } async function msgChatWithLLM(message, context) { - const { text, caption } = message; - let content = text || caption; - if (ENV.EXTRA_MESSAGE_CONTEXT && context.SHARE_CONTEXT.extraMessageContext && context.SHARE_CONTEXT.extraMessageContext.text) { - content = context.SHARE_CONTEXT.extraMessageContext.text + "\n" + text; - } - const params = { message: content }; - if (message.photo && message.photo.length > 0) { - let sizeIndex = 0; - if (ENV.TELEGRAM_PHOTO_SIZE_OFFSET >= 0) { - sizeIndex = ENV.TELEGRAM_PHOTO_SIZE_OFFSET; - } else if (ENV.TELEGRAM_PHOTO_SIZE_OFFSET < 0) { - sizeIndex = message.photo.length + ENV.TELEGRAM_PHOTO_SIZE_OFFSET; - } - sizeIndex = Math.max(0, Math.min(sizeIndex, message.photo.length - 1)); - const fileId = message.photo[sizeIndex].file_id; - let url = await getFileLink(fileId, context.SHARE_CONTEXT.currentBotToken); - if (ENV.TELEGRAPH_ENABLE) { - url = await uploadImageToTelegraph(url); - } - params.images = [url]; - } - return chatWithLLM(params, context, null); + const params = { + message: message.text || message.caption || '', + }; + if (ENV.EXTRA_MESSAGE_CONTEXT && context.SHARE_CONTEXT.extraMessageContext) { + const extra = context.SHARE_CONTEXT.extraMessageContext.text || context.SHARE_CONTEXT.extraMessageContext.caption || ''; + if (extra) { + params.message = `${extra}\n${params.message}`; + } + } + if (message.photo && message.photo.length > 0) { + const id = findPhotoFileID(message.photo, ENV.TELEGRAM_PHOTO_SIZE_OFFSET); + let url = await getFileLink(id, context.SHARE_CONTEXT.currentBotToken); + if (ENV.TELEGRAPH_ENABLE) { + url = await uploadImageToTelegraph(url); + } + params.images = [url]; + } + return chatWithLLM(params, context, null); } function loadMessage(body) { - if (body?.edited_message) { - throw new Error("Ignore edited message"); - } - if (body?.message) { - return body?.message; - } else { - throw new Error("Invalid message"); - } + if (body?.edited_message) { + throw new Error('Ignore edited message'); + } + if (body?.message) { + return body?.message; + } else { + throw new Error('Invalid message'); + } } async function handleMessage(token, body) { - const context = new Context(); - context.initTelegramContext(token); - const message = loadMessage(body); - const handlers = [ - // 初始化聊天上下文: 生成chat_id, reply_to_message_id(群组消息), SHARE_CONTEXT - msgInitChatContext, - // 检查环境是否准备好: DATABASE - msgCheckEnvIsReady, - // 过滤非白名单用户, 提前过滤减少KV消耗 - msgFilterWhiteList, - // 过滤不支持的消息(抛出异常结束消息处理) - msgFilterUnsupportedMessage, - // 处理群消息,判断是否需要响应此条消息 - msgHandleGroupMessage, - // 忽略旧消息 - msgIgnoreOldMessage, - // DEBUG: 保存最后一条消息,按照需求自行调整此中间件位置 - msgSaveLastMessage, - // 处理命令消息 - msgHandleCommand, - // 与llm聊天 - msgChatWithLLM - ]; - for (const handler of handlers) { - try { - const result = await handler(message, context); - if (result) { - return result; - } - } catch (e) { - console.error(e); - return new Response(errorToString(e), { status: 500 }); + const context = new Context(); + context.initTelegramContext(token); + const message = loadMessage(body); + const handlers = [ + msgInitChatContext, + msgCheckEnvIsReady, + msgFilterWhiteList, + msgFilterUnsupportedMessage, + msgHandleGroupMessage, + msgIgnoreOldMessage, + msgSaveLastMessage, + msgHandleCommand, + msgChatWithLLM, + ]; + for (const handler of handlers) { + try { + const result = await handler(message, context); + if (result) { + return result; + } + } catch (e) { + console.error(e); + return new Response(errorToString(e), { status: 500 }); + } } - } - return null; + return null; } -// src/utils/router.js -var Router = class { - constructor({ base = "", routes = [], ...other } = {}) { - this.routes = routes; - this.base = base; - Object.assign(this, other); - } - /** - * @private - * @param {URLSearchParams} searchParams - * @returns {object} - */ - parseQueryParams(searchParams) { - const query = /* @__PURE__ */ Object.create(null); - for (const [k, v] of searchParams) { - query[k] = k in query ? [].concat(query[k], v) : v; - } - return query; - } - /** - * @private - * @param {string} path - * @returns {string} - */ - normalizePath(path) { - return path.replace(/\/+(\/|$)/g, "$1"); - } - /** - * @private - * @param {string} path - * @returns {RegExp} - */ - createRouteRegex(path) { - return RegExp(`^${path.replace(/(\/?\.?):(\w+)\+/g, "($1(?<$2>*))").replace(/(\/?\.?):(\w+)/g, "($1(?<$2>[^$1/]+?))").replace(/\./g, "\\.").replace(/(\/?)\*/g, "($1.*)?")}/*$`); - } - /** - * @param {Request} request - * @param {...any} args - * @returns {Promise} - */ - async fetch(request, ...args) { - const url = new URL(request.url); - const reqMethod = request.method.toUpperCase(); - request.query = this.parseQueryParams(url.searchParams); - for (const [method, regex, handlers, path] of this.routes) { - let match = null; - if ((method === reqMethod || method === "ALL") && (match = url.pathname.match(regex))) { - request.params = match?.groups || {}; - request.route = path; - for (const handler of handlers) { - const response = await handler(request.proxy ?? request, ...args); - if (response != null) return response; +class Router { + constructor({ base = '', routes = [], ...other } = {}) { + this.routes = routes; + this.base = base; + Object.assign(this, other); + } + parseQueryParams(searchParams) { + const query = Object.create(null); + for (const [k, v] of searchParams) { + query[k] = k in query ? [].concat(query[k], v) : v; + } + return query; + } + normalizePath(path) { + return path.replace(/\/+(\/|$)/g, '$1'); + } + createRouteRegex(path) { + return RegExp(`^${path + .replace(/(\/?\.?):(\w+)\+/g, '($1(?<$2>*))') + .replace(/(\/?\.?):(\w+)/g, '($1(?<$2>[^$1/]+?))') + .replace(/\./g, '\\.') + .replace(/(\/?)\*/g, '($1.*)?') + }/*$`); + } + async fetch(request, ...args) { + const url = new URL(request.url); + const reqMethod = request.method.toUpperCase(); + request.query = this.parseQueryParams(url.searchParams); + for (const [method, regex, handlers, path] of this.routes) { + let match = null; + if ((method === reqMethod || method === 'ALL') && (match = url.pathname.match(regex))) { + request.params = match?.groups || {}; + request.route = path; + for (const handler of handlers) { + const response = await handler(request.proxy ?? request, ...args); + if (response != null) + return response; + } + } } - } } - } - /** - * @param {string} method - * @param {string} path - * @param {...any} handlers - * @returns {Router} - */ - route(method, path, ...handlers) { - const route = this.normalizePath(this.base + path); - const regex = this.createRouteRegex(route); - this.routes.push([method.toUpperCase(), regex, handlers, route]); - return this; - } - /** - * @param {string} path - * @param {...any} handlers - * @returns {Router} - */ - get(path, ...handlers) { - return this.route("GET", path, ...handlers); - } - /** - * @param {string} path - * @param {...any} handlers - * @returns {Router} - */ - post(path, ...handlers) { - return this.route("POST", path, ...handlers); - } - /** - * @param {string} path - * @param {...any} handlers - * @returns {Router} - */ - put(path, ...handlers) { - return this.route("PUT", path, ...handlers); - } - /** - * @param {string} path - * @param {...any} handlers - * @returns {Router} - */ - delete(path, ...handlers) { - return this.route("DELETE", path, ...handlers); - } - /** - * @param {string} path - * @param {...any} handlers - * @returns {Router} - */ - patch(path, ...handlers) { - return this.route("PATCH", path, ...handlers); - } - /** - * @param {string} path - * @param {...any} handlers - * @returns {Router} - */ - head(path, ...handlers) { - return this.route("HEAD", path, ...handlers); - } - /** - * @param {string} path - * @param {...any} handlers - * @returns {Router} - */ - options(path, ...handlers) { - return this.route("OPTIONS", path, ...handlers); - } - /** - * @param {string} path - * @param {...any} handlers - * @returns {Router} - */ - all(path, ...handlers) { - return this.route("ALL", path, ...handlers); - } -}; + route(method, path, ...handlers) { + const route = this.normalizePath(this.base + path); + const regex = this.createRouteRegex(route); + this.routes.push([method.toUpperCase(), regex, handlers, route]); + return this; + } + get(path, ...handlers) { + return this.route('GET', path, ...handlers); + } + post(path, ...handlers) { + return this.route('POST', path, ...handlers); + } + put(path, ...handlers) { + return this.route('PUT', path, ...handlers); + } + delete(path, ...handlers) { + return this.route('DELETE', path, ...handlers); + } + patch(path, ...handlers) { + return this.route('PATCH', path, ...handlers); + } + head(path, ...handlers) { + return this.route('HEAD', path, ...handlers); + } + options(path, ...handlers) { + return this.route('OPTIONS', path, ...handlers); + } + all(path, ...handlers) { + return this.route('ALL', path, ...handlers); + } +} -// src/route.js -var helpLink = "https://github.com/TBXark/ChatGPT-Telegram-Workers/blob/master/doc/en/DEPLOY.md"; -var issueLink = "https://github.com/TBXark/ChatGPT-Telegram-Workers/issues"; -var initLink = "./init"; -var footer = ` +const helpLink = 'https://github.com/TBXark/ChatGPT-Telegram-Workers/blob/master/doc/en/DEPLOY.md'; +const issueLink = 'https://github.com/TBXark/ChatGPT-Telegram-Workers/issues'; +const initLink = './init'; +const footer = `

For more information, please visit ${helpLink}

If you have any questions, please visit ${issueLink}

`; function buildKeyNotFoundHTML(key) { - return `

Please set the ${key} environment variable in Cloudflare Workers.

`; + return `

Please set the ${key} environment variable in Cloudflare Workers.

`; } async function bindWebHookAction(request) { - const result = []; - const domain = new URL(request.url).host; - const hookMode = API_GUARD ? "safehook" : "webhook"; - for (const token of ENV.TELEGRAM_AVAILABLE_TOKENS) { - const url = `https://${domain}/telegram/${token.trim()}/${hookMode}`; - const id = token.split(":")[0]; - result[id] = { - webhook: await bindTelegramWebHook(token, url).catch((e) => errorToString(e)), - command: await bindCommandForTelegram(token).catch((e) => errorToString(e)) - }; - } - const HTML = renderHTML(` + const result = []; + const domain = new URL(request.url).host; + const hookMode = API_GUARD ? 'safehook' : 'webhook'; + for (const token of ENV.TELEGRAM_AVAILABLE_TOKENS) { + const url = `https://${domain}/telegram/${token.trim()}/${hookMode}`; + const id = token.split(':')[0]; + result[id] = { + webhook: await bindTelegramWebHook(token, url).then(res => res.json()).catch(e => errorToString(e)), + command: await bindCommandForTelegram(token).catch(e => errorToString(e)), + }; + } + const HTML = renderHTML(`

ChatGPT-Telegram-Workers

${domain}

- ${ENV.TELEGRAM_AVAILABLE_TOKENS.length === 0 ? buildKeyNotFoundHTML("TELEGRAM_AVAILABLE_TOKENS") : ""} - ${Object.keys(result).map((id) => ` + ${ + ENV.TELEGRAM_AVAILABLE_TOKENS.length === 0 ? buildKeyNotFoundHTML('TELEGRAM_AVAILABLE_TOKENS') : '' +} + ${ + Object.keys(result).map(id => `

Bot ID: ${id}

-

Webhook: ${JSON.stringify(result[id].webhook)}

-

Command: ${JSON.stringify(result[id].command)}

- `).join("")} +

Webhook: ${JSON.stringify(result[id].webhook)}

+

Command: ${JSON.stringify(result[id].command)}

+ `).join('') +} ${footer} `); - return new Response(HTML, { status: 200, headers: { "Content-Type": "text/html" } }); + return new Response(HTML, { status: 200, headers: { 'Content-Type': 'text/html' } }); } async function telegramWebhook(request) { - try { - const { token } = request.params; - const body = await request.json(); - return makeResponse200(await handleMessage(token, body)); - } catch (e) { - console.error(e); - return new Response(errorToString(e), { status: 200 }); - } + try { + const { token } = request.params; + const body = await request.json(); + return makeResponse200(await handleMessage(token, body)); + } catch (e) { + console.error(e); + return new Response(errorToString(e), { status: 200 }); + } } async function telegramSafeHook(request) { - try { - if (API_GUARD === void 0 || API_GUARD === null) { - return telegramWebhook(request); - } - console.log("API_GUARD is enabled"); - const url = new URL(request.url); - url.pathname = url.pathname.replace("/safehook", "/webhook"); - request = new Request(url, request); - return makeResponse200(await API_GUARD.fetch(request)); - } catch (e) { - console.error(e); - return new Response(errorToString(e), { status: 200 }); - } + try { + if (API_GUARD === undefined || API_GUARD === null) { + return telegramWebhook(request); + } + console.log('API_GUARD is enabled'); + const url = new URL(request.url); + url.pathname = url.pathname.replace('/safehook', '/webhook'); + request = new Request(url, request); + return makeResponse200(await API_GUARD.fetch(request)); + } catch (e) { + console.error(e); + return new Response(errorToString(e), { status: 200 }); + } } async function defaultIndexAction() { - const HTML = renderHTML(` + const HTML = renderHTML(`

ChatGPT-Telegram-Workers


Deployed Successfully!

@@ -2733,103 +2471,66 @@ async function defaultIndexAction() {

You must >>>>> click here <<<<< to bind the webhook.


After binding the webhook, you can use the following commands to control the bot:

- ${commandsDocument().map((item) => `

${item.command} - ${item.description}

`).join("")} + ${ + commandsDocument().map(item => `

${item.command} - ${item.description}

`).join('') +}

You can get bot information by visiting the following URL:

/telegram/:token/bot - Get bot information

${footer} `); - return new Response(HTML, { status: 200, headers: { "Content-Type": "text/html" } }); -} -async function loadBotInfo() { - const result = []; - for (const token of ENV.TELEGRAM_AVAILABLE_TOKENS) { - const id = token.split(":")[0]; - result[id] = await getBot(token); - } - const HTML = renderHTML(` -

ChatGPT-Telegram-Workers

-
-

Environment About Bot

-

GROUP_CHAT_BOT_ENABLE: ${ENV.GROUP_CHAT_BOT_ENABLE}

-

GROUP_CHAT_BOT_SHARE_MODE: ${ENV.GROUP_CHAT_BOT_SHARE_MODE}

-

TELEGRAM_BOT_NAME: ${ENV.TELEGRAM_BOT_NAME.join(",")}

- ${Object.keys(result).map((id) => ` -
-

Bot ID: ${id}

-

${JSON.stringify(result[id])}

- `).join("")} - ${footer} - `); - return new Response(HTML, { status: 200, headers: { "Content-Type": "text/html" } }); + return new Response(HTML, { status: 200, headers: { 'Content-Type': 'text/html' } }); } async function handleRequest(request) { - const router = new Router(); - router.get("/", defaultIndexAction); - router.get("/init", bindWebHookAction); - router.post("/telegram/:token/webhook", telegramWebhook); - router.post("/telegram/:token/safehook", telegramSafeHook); - if (ENV.DEV_MODE || ENV.DEBUG_MODE) { - router.get("/telegram/:token/bot", loadBotInfo); - } - router.all("*", () => new Response("Not Found", { status: 404 })); - return router.fetch(request); + const router = new Router(); + router.get('/', defaultIndexAction); + router.get('/init', bindWebHookAction); + router.post('/telegram/:token/webhook', telegramWebhook); + router.post('/telegram/:token/safehook', telegramSafeHook); + router.all('*', () => new Response('Not Found', { status: 404 })); + return router.fetch(request); } -// src/i18n/zh-hans.js -var zh_hans_default = { "env": { "system_init_message": "\u4F60\u662F\u4E00\u4E2A\u5F97\u529B\u7684\u52A9\u624B" }, "command": { "help": { "summary": "\u5F53\u524D\u652F\u6301\u4EE5\u4E0B\u547D\u4EE4:\n", "help": "\u83B7\u53D6\u547D\u4EE4\u5E2E\u52A9", "new": "\u53D1\u8D77\u65B0\u7684\u5BF9\u8BDD", "start": "\u83B7\u53D6\u4F60\u7684ID, \u5E76\u53D1\u8D77\u65B0\u7684\u5BF9\u8BDD", "img": "\u751F\u6210\u4E00\u5F20\u56FE\u7247, \u547D\u4EE4\u5B8C\u6574\u683C\u5F0F\u4E3A `/img \u56FE\u7247\u63CF\u8FF0`, \u4F8B\u5982`/img \u6708\u5149\u4E0B\u7684\u6C99\u6EE9`", "version": "\u83B7\u53D6\u5F53\u524D\u7248\u672C\u53F7, \u5224\u65AD\u662F\u5426\u9700\u8981\u66F4\u65B0", "setenv": "\u8BBE\u7F6E\u7528\u6237\u914D\u7F6E\uFF0C\u547D\u4EE4\u5B8C\u6574\u683C\u5F0F\u4E3A /setenv KEY=VALUE", "setenvs": '\u6279\u91CF\u8BBE\u7F6E\u7528\u6237\u914D\u7F6E, \u547D\u4EE4\u5B8C\u6574\u683C\u5F0F\u4E3A /setenvs {"KEY1": "VALUE1", "KEY2": "VALUE2"}', "delenv": "\u5220\u9664\u7528\u6237\u914D\u7F6E\uFF0C\u547D\u4EE4\u5B8C\u6574\u683C\u5F0F\u4E3A /delenv KEY", "clearenv": "\u6E05\u9664\u6240\u6709\u7528\u6237\u914D\u7F6E", "system": "\u67E5\u770B\u5F53\u524D\u4E00\u4E9B\u7CFB\u7EDF\u4FE1\u606F", "redo": "\u91CD\u505A\u4E0A\u4E00\u6B21\u7684\u5BF9\u8BDD, /redo \u52A0\u4FEE\u6539\u8FC7\u7684\u5185\u5BB9 \u6216\u8005 \u76F4\u63A5 /redo", "echo": "\u56DE\u663E\u6D88\u606F" }, "new": { "new_chat_start": "\u65B0\u7684\u5BF9\u8BDD\u5DF2\u7ECF\u5F00\u59CB" } } }; +const zhHans = {"env":{"system_init_message":"你是一个得力的助手"},"command":{"help":{"summary":"当前支持以下命令:\n","help":"获取命令帮助","new":"发起新的对话","start":"获取你的ID, 并发起新的对话","img":"生成一张图片, 命令完整格式为 `/img 图片描述`, 例如`/img 月光下的沙滩`","version":"获取当前版本号, 判断是否需要更新","setenv":"设置用户配置,命令完整格式为 /setenv KEY=VALUE","setenvs":"批量设置用户配置, 命令完整格式为 /setenvs {\"KEY1\": \"VALUE1\", \"KEY2\": \"VALUE2\"}","delenv":"删除用户配置,命令完整格式为 /delenv KEY","clearenv":"清除所有用户配置","system":"查看当前一些系统信息","redo":"重做上一次的对话, /redo 加修改过的内容 或者 直接 /redo","echo":"回显消息"},"new":{"new_chat_start":"新的对话已经开始"}}}; -// src/i18n/zh-hant.js -var zh_hant_default = { "env": { "system_init_message": "\u4F60\u662F\u4E00\u500B\u5F97\u529B\u7684\u52A9\u624B" }, "command": { "help": { "summary": "\u7576\u524D\u652F\u6301\u7684\u547D\u4EE4\u5982\u4E0B\uFF1A\n", "help": "\u7372\u53D6\u547D\u4EE4\u5E6B\u52A9", "new": "\u958B\u59CB\u4E00\u500B\u65B0\u5C0D\u8A71", "start": "\u7372\u53D6\u60A8\u7684ID\u4E26\u958B\u59CB\u4E00\u500B\u65B0\u5C0D\u8A71", "img": "\u751F\u6210\u5716\u7247\uFF0C\u5B8C\u6574\u547D\u4EE4\u683C\u5F0F\u70BA`/img \u5716\u7247\u63CF\u8FF0`\uFF0C\u4F8B\u5982`/img \u6D77\u7058\u6708\u5149`", "version": "\u7372\u53D6\u7576\u524D\u7248\u672C\u865F\u78BA\u8A8D\u662F\u5426\u9700\u8981\u66F4\u65B0", "setenv": "\u8A2D\u7F6E\u7528\u6236\u914D\u7F6E\uFF0C\u5B8C\u6574\u547D\u4EE4\u683C\u5F0F\u70BA/setenv KEY=VALUE", "setenvs": '\u6279\u91CF\u8A2D\u7F6E\u7528\u6237\u914D\u7F6E, \u547D\u4EE4\u5B8C\u6574\u683C\u5F0F\u70BA /setenvs {"KEY1": "VALUE1", "KEY2": "VALUE2"}', "delenv": "\u522A\u9664\u7528\u6236\u914D\u7F6E\uFF0C\u5B8C\u6574\u547D\u4EE4\u683C\u5F0F\u70BA/delenv KEY", "clearenv": "\u6E05\u9664\u6240\u6709\u7528\u6236\u914D\u7F6E", "system": "\u67E5\u770B\u4E00\u4E9B\u7CFB\u7D71\u4FE1\u606F", "redo": "\u91CD\u505A\u4E0A\u4E00\u6B21\u7684\u5C0D\u8A71 /redo \u52A0\u4FEE\u6539\u904E\u7684\u5167\u5BB9 \u6216\u8005 \u76F4\u63A5 /redo", "echo": "\u56DE\u663E\u6D88\u606F" }, "new": { "new_chat_start": "\u958B\u59CB\u4E00\u500B\u65B0\u5C0D\u8A71" } } }; +const zhHant = {"env":{"system_init_message":"你是一個得力的助手"},"command":{"help":{"summary":"當前支持的命令如下:\n","help":"獲取命令幫助","new":"開始一個新對話","start":"獲取您的ID並開始一個新對話","img":"生成圖片,完整命令格式為`/img 圖片描述`,例如`/img 海灘月光`","version":"獲取當前版本號確認是否需要更新","setenv":"設置用戶配置,完整命令格式為/setenv KEY=VALUE","setenvs":"批量設置用户配置, 命令完整格式為 /setenvs {\"KEY1\": \"VALUE1\", \"KEY2\": \"VALUE2\"}","delenv":"刪除用戶配置,完整命令格式為/delenv KEY","clearenv":"清除所有用戶配置","system":"查看一些系統信息","redo":"重做上一次的對話 /redo 加修改過的內容 或者 直接 /redo","echo":"回显消息"},"new":{"new_chat_start":"開始一個新對話"}}}; -// src/i18n/pt.js -var pt_default = { "env": { "system_init_message": "Voc\xEA \xE9 um assistente \xFAtil" }, "command": { "help": { "summary": "Os seguintes comandos s\xE3o suportados atualmente:\n", "help": "Obter ajuda sobre comandos", "new": "Iniciar uma nova conversa", "start": "Obter seu ID e iniciar uma nova conversa", "img": "Gerar uma imagem, o formato completo do comando \xE9 `/img descri\xE7\xE3o da imagem`, por exemplo `/img praia ao luar`", "version": "Obter o n\xFAmero da vers\xE3o atual para determinar se \xE9 necess\xE1rio atualizar", "setenv": "Definir configura\xE7\xE3o do usu\xE1rio, o formato completo do comando \xE9 /setenv CHAVE=VALOR", "setenvs": 'Definir configura\xE7\xF5es do usu\xE1rio em lote, o formato completo do comando \xE9 /setenvs {"CHAVE1": "VALOR1", "CHAVE2": "VALOR2"}', "delenv": "Excluir configura\xE7\xE3o do usu\xE1rio, o formato completo do comando \xE9 /delenv CHAVE", "clearenv": "Limpar todas as configura\xE7\xF5es do usu\xE1rio", "system": "Ver algumas informa\xE7\xF5es do sistema", "redo": "Refazer a \xFAltima conversa, /redo com conte\xFAdo modificado ou diretamente /redo", "echo": "Repetir a mensagem" }, "new": { "new_chat_start": "Uma nova conversa foi iniciada" } } }; +const pt = {"env":{"system_init_message":"Você é um assistente útil"},"command":{"help":{"summary":"Os seguintes comandos são suportados atualmente:\n","help":"Obter ajuda sobre comandos","new":"Iniciar uma nova conversa","start":"Obter seu ID e iniciar uma nova conversa","img":"Gerar uma imagem, o formato completo do comando é `/img descrição da imagem`, por exemplo `/img praia ao luar`","version":"Obter o número da versão atual para determinar se é necessário atualizar","setenv":"Definir configuração do usuário, o formato completo do comando é /setenv CHAVE=VALOR","setenvs":"Definir configurações do usuário em lote, o formato completo do comando é /setenvs {\"CHAVE1\": \"VALOR1\", \"CHAVE2\": \"VALOR2\"}","delenv":"Excluir configuração do usuário, o formato completo do comando é /delenv CHAVE","clearenv":"Limpar todas as configurações do usuário","system":"Ver algumas informações do sistema","redo":"Refazer a última conversa, /redo com conteúdo modificado ou diretamente /redo","echo":"Repetir a mensagem"},"new":{"new_chat_start":"Uma nova conversa foi iniciada"}}}; -// src/i18n/en.js -var en_default = { "env": { "system_init_message": "You are a helpful assistant" }, "command": { "help": { "summary": "The following commands are currently supported:\n", "help": "Get command help", "new": "Start a new conversation", "start": "Get your ID and start a new conversation", "img": "Generate an image, the complete command format is `/img image description`, for example `/img beach at moonlight`", "version": "Get the current version number to determine whether to update", "setenv": "Set user configuration, the complete command format is /setenv KEY=VALUE", "setenvs": 'Batch set user configurations, the full format of the command is /setenvs {"KEY1": "VALUE1", "KEY2": "VALUE2"}', "delenv": "Delete user configuration, the complete command format is /delenv KEY", "clearenv": "Clear all user configuration", "system": "View some system information", "redo": "Redo the last conversation, /redo with modified content or directly /redo", "echo": "Echo the message" }, "new": { "new_chat_start": "A new conversation has started" } } }; +const en = {"env":{"system_init_message":"You are a helpful assistant"},"command":{"help":{"summary":"The following commands are currently supported:\n","help":"Get command help","new":"Start a new conversation","start":"Get your ID and start a new conversation","img":"Generate an image, the complete command format is `/img image description`, for example `/img beach at moonlight`","version":"Get the current version number to determine whether to update","setenv":"Set user configuration, the complete command format is /setenv KEY=VALUE","setenvs":"Batch set user configurations, the full format of the command is /setenvs {\"KEY1\": \"VALUE1\", \"KEY2\": \"VALUE2\"}","delenv":"Delete user configuration, the complete command format is /delenv KEY","clearenv":"Clear all user configuration","system":"View some system information","redo":"Redo the last conversation, /redo with modified content or directly /redo","echo":"Echo the message"},"new":{"new_chat_start":"A new conversation has started"}}}; -// src/i18n/index.js function i18n(lang) { - switch (lang.toLowerCase()) { - case "cn": - case "zh-cn": - case "zh-hans": - return zh_hans_default; - case "zh-tw": - case "zh-hk": - case "zh-mo": - case "zh-hant": - return zh_hant_default; - case "pt": - case "pt-br": - return pt_default; - case "en": - case "en-us": - return en_default; - default: - return en_default; - } + switch (lang.toLowerCase()) { + case 'cn': + case 'zh-cn': + case 'zh-hans': + return zhHans; + case 'zh-tw': + case 'zh-hk': + case 'zh-mo': + case 'zh-hant': + return zhHant; + case 'pt': + case 'pt-br': + return pt; + case 'en': + case 'en-us': + return en; + default: + return en; + } } -// main.js -var main_default = { - /** - * @param {Request} request - * @param {object} env - * @param {object} ctx - * @returns {Promise} - */ - // eslint-disable-next-line no-unused-vars - async fetch(request, env, ctx) { - try { - initEnv(env, i18n); - return await handleRequest(request); - } catch (e) { - console.error(e); - return new Response(errorToString(e), { status: 500 }); - } - } -}; -export { - main_default as default +const main = { + async fetch(request, env, ctx) { + try { + initEnv(env, i18n); + return await handleRequest(request); + } catch (e) { + console.error(e); + return new Response(errorToString(e), { status: 500 }); + } + }, }; + +export { main as default }; diff --git a/dist/timestamp b/dist/timestamp index c7af7ac5..8c38245d 100644 --- a/dist/timestamp +++ b/dist/timestamp @@ -1 +1 @@ -1723602033 \ No newline at end of file +1724122033 \ No newline at end of file diff --git a/doc/cn/CHANGELOG.md b/doc/cn/CHANGELOG.md index 13e1a6c9..66c0601f 100644 --- a/doc/cn/CHANGELOG.md +++ b/doc/cn/CHANGELOG.md @@ -2,8 +2,9 @@ - v1.8.0 - 支持Cohere,Anthropic Ai + - 支持图片输入 - 适配群组话题模式 - - 删除部分废弃功能模块 + - 移除role功能,使用自定义指令代替 - 修复超长文本发送失败BUG - v1.7.0 diff --git a/doc/en/CHANGELOG.md b/doc/en/CHANGELOG.md index df990f3a..2da893a6 100644 --- a/doc/en/CHANGELOG.md +++ b/doc/en/CHANGELOG.md @@ -2,8 +2,9 @@ - v1.8.0 - Support Cohere, Anthropic Ai + - Support image input. - Adapt to group topic mode - - Delete some obsolete functional modules + - Remove the role function and use custom commands instead. - Fix the bug of failure to send super long text. - v1.7.0 diff --git a/esbuild.config.js b/esbuild.config.js deleted file mode 100644 index e8632f87..00000000 --- a/esbuild.config.js +++ /dev/null @@ -1,53 +0,0 @@ -import esbuild from 'esbuild'; -import fs from 'fs/promises'; -import { execSync } from 'child_process'; - -const TIMESTAMP_FILE = './dist/timestamp'; -const BUILD_INFO_JSON = './dist/buildinfo.json'; -const OUTPUT_FILE = './dist/index.js'; -const ENTRY_FILE = 'main.js'; - -async function clean() { - for (const file of [TIMESTAMP_FILE, BUILD_INFO_JSON, OUTPUT_FILE]) { - try { - await fs.unlink(file); - } catch (error) { - if (error.code !== 'ENOENT') { - throw error; - } - } - } -} - -async function build() { - await clean(); - - const COMMIT_HASH = execSync('git rev-parse --short HEAD').toString().trim(); - const TIMESTAMP = Math.floor(Date.now() / 1000); - - await fs.writeFile(TIMESTAMP_FILE, TIMESTAMP.toString()); - await fs.writeFile(BUILD_INFO_JSON, JSON.stringify({ - sha: COMMIT_HASH, - timestamp: TIMESTAMP - })); - - try { - await esbuild.build({ - entryPoints: [ENTRY_FILE], - bundle: true, - outfile: OUTPUT_FILE, - format: 'esm', - platform: 'node', - define: { - 'process.env.BUILD_VERSION': `'${COMMIT_HASH}'`, - 'process.env.BUILD_TIMESTAMP': TIMESTAMP.toString() - } - }); - console.log('Build successfully!'); - } catch (error) { - console.error('Build failed:', error); - process.exit(1); - } -} - -build(); \ No newline at end of file diff --git a/eslint.config.js b/eslint.config.js index 0ffe2d7f..3e1a2246 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -1,31 +1,40 @@ -import globals from "globals"; -import pluginJs from "@eslint/js"; -import jsdoc from "eslint-plugin-jsdoc"; +import antfu, { imports, javascript, jsdoc, node } from '@antfu/eslint-config'; - -export default [ - {languageOptions: { globals: {...globals.browser, ...globals.node} }}, - pluginJs.configs.recommended, - jsdoc.configs['flat/recommended'], - { - rules: { - semi : ["error", "always"], - indent: ["error", 4], - quotes: ["error", "single"], - "comma-dangle": ["error", "always-multiline"], - "no-multi-spaces": "error", - // "space-before-function-paren": ["error", "always"], - "object-shorthand": ["error", "always"], - "operator-linebreak": ["error", "before"], - "arrow-parens": ["error", "always"], - "space-infix-ops": "error", - 'jsdoc/no-undefined-types': 'off', - 'jsdoc/require-returns-description': 'off', - 'jsdoc/require-property-description': 'off', - 'jsdoc/require-param-description': 'off', +export default antfu( + { + type: 'app', + stylistic: { + indent: 4, + quotes: 'single', + semi: true, + braceStyle: '1tbs', + }, + markdown: false, + ignores: [ + '.github/**', + '.idea/**', + '.vscode/**', + '.wrangler/**', + 'dist/**', + 'node_modules/**', + ], + }, + imports, + jsdoc, + javascript, + node, + { + rules: { + 'jsdoc/no-undefined-types': 'off', + 'jsdoc/require-returns-description': 'off', + 'jsdoc/require-property-description': 'off', + 'jsdoc/require-param-description': 'off', + 'node/prefer-global/process': 'off', + 'node/prefer-global/buffer': 'off', + 'eslint-comments/no-unlimited-disable': 'off', + 'padding-line-between-statements': 'off', + 'no-console': 'off', + 'style/brace-style': ['error', '1tbs', { allowSingleLine: true }], + }, }, - plugins: { - jsdoc - } - } -]; +); diff --git a/main.js b/main.js index 030953c8..4e0d99c6 100644 --- a/main.js +++ b/main.js @@ -1,24 +1,23 @@ -import {initEnv} from './src/config/env.js'; -import {handleRequest} from './src/route.js'; -import {errorToString} from './src/utils/utils.js'; +import { initEnv } from './src/config/env.js'; +import { handleRequest } from './src/route.js'; +import { errorToString } from './src/utils/utils.js'; import i18n from './src/i18n/index.js'; - export default { /** - * @param {Request} request - * @param {object} env - * @param {object} ctx + * @param {Request} request + * @param {object} env + * @param {object} ctx * @returns {Promise} */ - // eslint-disable-next-line no-unused-vars + // eslint-disable-next-line unused-imports/no-unused-vars async fetch(request, env, ctx) { try { initEnv(env, i18n); return await handleRequest(request); } catch (e) { console.error(e); - return new Response(errorToString(e), {status: 500}); + return new Response(errorToString(e), { status: 500 }); } }, }; diff --git a/package.json b/package.json index 3a11171a..8e4c75e9 100644 --- a/package.json +++ b/package.json @@ -1,33 +1,36 @@ { - "name": "chatgpt-telegram-workers", - "version": "1.7.0", - "description": "最简单快捷部署属于自己的ChatGPT Telegram机器人的方法,单文件,直接复制粘贴一把梭,无需任何依赖,无需配置本地开发环境,不用域名,免服务器。", - "main": "main.js", - "type": "module", - "scripts": { - "lint": "eslint --fix main.js src adapter", - "build": "node esbuild.config.js", - "debug": "wrangler dev --local", - "wrangler": "wrangler", - "deploy:dist": "wrangler deploy", - "deploy:build": "npm run build && wrangler deploy" - }, - "devDependencies": { - "@eslint/js": "^9.8.0", - "esbuild": "^0.23.0", - "eslint": "^9.8.0", - "eslint-plugin-jsdoc": "^50.0.0", - "globals": "^15.9.0", - "wrangler": "^3.69.1" - }, - "exports": { - "import": "./main.js" - }, - "files": [ - "main.js", - "src/**/*" - ], - "author": "TBXark", - "license": "MIT", - "dependencies": {} + "name": "chatgpt-telegram-workers", + "type": "module", + "version": "1.8.0", + "description": "The easiest and quickest way to deploy your own ChatGPT Telegram bot is to use a single file and simply copy and paste it. There is no need for any dependencies, local development environment configuration, domain names, or servers.", + "author": "TBXark", + "license": "MIT", + "exports": { + ".": { + "import": "./dist/index.js" + } + }, + "module": "dist/index.js", + "files": [ + "dist" + ], + "scripts": { + "lint": "eslint --fix *.js *.json src adapter", + "build": "vite build", + "debug": "wrangler dev --local", + "wrangler": "wrangler", + "deploy:dist": "wrangler deploy", + "deploy:build": "npm run build && wrangler deploy" + }, + "dependencies": {}, + "devDependencies": { + "@antfu/eslint-config": "^2.25.1", + "@rollup/plugin-node-resolve": "^15.2.3", + "eslint": "^9.8.0", + "eslint-plugin-format": "^0.1.2", + "rollup-plugin-cleanup": "^3.2.1", + "typescript": "^5.5.4", + "vite": "^5.2.10", + "wrangler": "^3.69.1" + } } diff --git a/src/agent/agents.js b/src/agent/agents.js index 04ff56fd..d303a4ec 100644 --- a/src/agent/agents.js +++ b/src/agent/agents.js @@ -1,9 +1,9 @@ -import {isOpenAIEnable, requestCompletionsFromOpenAI, requestImageFromOpenAI} from './openai.js'; -import {isWorkersAIEnable, requestCompletionsFromWorkersAI, requestImageFromWorkersAI} from './workersai.js'; -import {isGeminiAIEnable, requestCompletionsFromGeminiAI} from './gemini.js'; -import {isMistralAIEnable, requestCompletionsFromMistralAI} from './mistralai.js'; -import {isCohereAIEnable, requestCompletionsFromCohereAI} from './cohere.js'; -import {isAnthropicAIEnable, requestCompletionsFromAnthropicAI} from './anthropic.js'; +import { isOpenAIEnable, requestCompletionsFromOpenAI, requestImageFromOpenAI } from './openai.js'; +import { isWorkersAIEnable, requestCompletionsFromWorkersAI, requestImageFromWorkersAI } from './workersai.js'; +import { isGeminiAIEnable, requestCompletionsFromGeminiAI } from './gemini.js'; +import { isMistralAIEnable, requestCompletionsFromMistralAI } from './mistralai.js'; +import { isCohereAIEnable, requestCompletionsFromCohereAI } from './cohere.js'; +import { isAnthropicAIEnable, requestCompletionsFromAnthropicAI } from './anthropic.js'; import { isAzureEnable, isAzureImageEnable, @@ -13,7 +13,6 @@ import { import '../types/context.js'; import '../types/agent.js'; - /** * @type {ChatAgent[]} */ @@ -62,27 +61,27 @@ export const chatLlmAgents = [ */ export function currentChatModel(agentName, context) { switch (agentName) { - case 'azure': - try { - const url = new URL(context.USER_CONFIG.AZURE_COMPLETIONS_API); - return url.pathname.split('/')[3]; - } catch { - return context.USER_CONFIG.AZURE_COMPLETIONS_API; - } - case 'openai': - return context.USER_CONFIG.OPENAI_CHAT_MODEL; - case 'workers': - return context.USER_CONFIG.WORKERS_CHAT_MODEL; - case 'gemini': - return context.USER_CONFIG.GOOGLE_COMPLETIONS_MODEL; - case 'mistral': - return context.USER_CONFIG.MISTRAL_CHAT_MODEL; - case 'cohere': - return context.USER_CONFIG.COHERE_CHAT_MODEL; - case 'anthropic': - return context.USER_CONFIG.ANTHROPIC_CHAT_MODEL; - default: - return null; + case 'azure': + try { + const url = new URL(context.USER_CONFIG.AZURE_COMPLETIONS_API); + return url.pathname.split('/')[3]; + } catch { + return context.USER_CONFIG.AZURE_COMPLETIONS_API; + } + case 'openai': + return context.USER_CONFIG.OPENAI_CHAT_MODEL; + case 'workers': + return context.USER_CONFIG.WORKERS_CHAT_MODEL; + case 'gemini': + return context.USER_CONFIG.GOOGLE_COMPLETIONS_MODEL; + case 'mistral': + return context.USER_CONFIG.MISTRAL_CHAT_MODEL; + case 'cohere': + return context.USER_CONFIG.COHERE_CHAT_MODEL; + case 'anthropic': + return context.USER_CONFIG.ANTHROPIC_CHAT_MODEL; + default: + return null; } } @@ -92,26 +91,25 @@ export function currentChatModel(agentName, context) { */ export function chatModelKey(agentName) { switch (agentName) { - case 'azure': - return 'AZURE_COMPLETIONS_API'; - case 'openai': - return 'OPENAI_CHAT_MODEL'; - case 'workers': - return 'WORKERS_CHAT_MODEL'; - case 'gemini': - return 'GOOGLE_COMPLETIONS_MODEL'; - case 'mistral': - return 'MISTRAL_CHAT_MODEL'; - case 'cohere': - return 'COHERE_CHAT_MODEL'; - case 'anthropic': - return 'ANTHROPIC_CHAT_MODEL'; - default: - return null; + case 'azure': + return 'AZURE_COMPLETIONS_API'; + case 'openai': + return 'OPENAI_CHAT_MODEL'; + case 'workers': + return 'WORKERS_CHAT_MODEL'; + case 'gemini': + return 'GOOGLE_COMPLETIONS_MODEL'; + case 'mistral': + return 'MISTRAL_CHAT_MODEL'; + case 'cohere': + return 'COHERE_CHAT_MODEL'; + case 'anthropic': + return 'ANTHROPIC_CHAT_MODEL'; + default: + return null; } } - /** * 加载聊天AI * @param {ContextType} context @@ -153,7 +151,6 @@ export const imageGenAgents = [ }, ]; - /** * 加载图片AI * @param {ContextType} context @@ -181,19 +178,19 @@ export function loadImageGen(context) { */ export function currentImageModel(agentName, context) { switch (agentName) { - case 'azure': - try { - const url = new URL(context.USER_CONFIG.AZURE_DALLE_API); - return url.pathname.split('/')[3]; - } catch { - return context.USER_CONFIG.AZURE_DALLE_API; - } - case 'openai': - return context.USER_CONFIG.DALL_E_MODEL; - case 'workers': - return context.USER_CONFIG.WORKERS_IMAGE_MODEL; - default: - return null; + case 'azure': + try { + const url = new URL(context.USER_CONFIG.AZURE_DALLE_API); + return url.pathname.split('/')[3]; + } catch { + return context.USER_CONFIG.AZURE_DALLE_API; + } + case 'openai': + return context.USER_CONFIG.DALL_E_MODEL; + case 'workers': + return context.USER_CONFIG.WORKERS_IMAGE_MODEL; + default: + return null; } } @@ -203,13 +200,13 @@ export function currentImageModel(agentName, context) { */ export function imageModelKey(agentName) { switch (agentName) { - case 'azure': - return 'AZURE_DALLE_API'; - case 'openai': - return 'DALL_E_MODEL'; - case 'workers': - return 'WORKERS_IMAGE_MODEL'; - default: - return null; + case 'azure': + return 'AZURE_DALLE_API'; + case 'openai': + return 'DALL_E_MODEL'; + case 'workers': + return 'WORKERS_IMAGE_MODEL'; + default: + return null; } } diff --git a/src/agent/anthropic.js b/src/agent/anthropic.js index 5d03212c..b2e723f5 100644 --- a/src/agent/anthropic.js +++ b/src/agent/anthropic.js @@ -1,10 +1,9 @@ import '../types/context.js'; import '../types/agent.js'; -import {anthropicSseJsonParser, Stream} from './stream.js'; -import {requestChatCompletions} from './request.js'; -import {imageToBase64String} from '../utils/image.js'; -import {ENV} from '../config/env.js'; - +import { imageToBase64String } from '../utils/image.js'; +import { ENV } from '../config/env.js'; +import { Stream, anthropicSseJsonParser } from './stream.js'; +import { requestChatCompletions } from './request.js'; /** * @param {ContextType} context @@ -27,18 +26,17 @@ async function renderAnthropicMessage(item) { if (item.images && item.images.length > 0) { res.content = []; if (item.content) { - res.content.push({type: 'text', text: item.content}); + res.content.push({ type: 'text', text: item.content }); } for (const image of item.images) { - res.content.push(await imageToBase64String(image).then(({format, data}) => { - return {type: 'image', source: {type: 'base64', media_type: format, data}}; + res.content.push(await imageToBase64String(image).then(({ format, data }) => { + return { type: 'image', source: { type: 'base64', media_type: format, data } }; })); } } return res; } - /** * 发送消息到Anthropic AI * @param {LlmParams} params @@ -47,7 +45,7 @@ async function renderAnthropicMessage(item) { * @returns {Promise} */ export async function requestCompletionsFromAnthropicAI(params, context, onStream) { - const {message, images, prompt, history} = params; + const { message, images, prompt, history } = params; const url = `${context.USER_CONFIG.ANTHROPIC_API_BASE}/messages`; const header = { 'x-api-key': context.USER_CONFIG.ANTHROPIC_API_KEY, @@ -55,7 +53,11 @@ export async function requestCompletionsFromAnthropicAI(params, context, onStrea 'content-type': 'application/json', }; - const messages = ([...(history || []), {role: 'user', content: message, images}]); + const messages = ([...(history || []), { role: 'user', content: message, images }]); + + if (messages.length > 0 && messages[0].role === 'assistant') { + messages.shift(); + } const body = { system: prompt, @@ -71,18 +73,17 @@ export async function requestCompletionsFromAnthropicAI(params, context, onStrea * @type {SseChatCompatibleOptions} */ const options = {}; - options.streamBuilder = function(r, c) { + options.streamBuilder = function (r, c) { return new Stream(r, c, null, anthropicSseJsonParser); }; - options.contentExtractor = function(data) { + options.contentExtractor = function (data) { return data?.delta?.text; }; - options.fullContentExtractor = function(data) { + options.fullContentExtractor = function (data) { return data?.content?.[0].text; }; - options.errorExtractor = function(data) { + options.errorExtractor = function (data) { return data?.error?.message; }; return requestChatCompletions(url, header, body, context, onStream, null, options); } - diff --git a/src/agent/azure.js b/src/agent/azure.js index c16efae9..edc8b139 100644 --- a/src/agent/azure.js +++ b/src/agent/azure.js @@ -1,7 +1,7 @@ import '../types/context.js'; import '../types/agent.js'; -import {requestChatCompletions} from './request.js'; -import {renderOpenAIMessage} from './openai.js'; +import { requestChatCompletions } from './request.js'; +import { renderOpenAIMessage } from './openai.js'; /** * @param {ContextType} context @@ -11,7 +11,6 @@ function azureKeyFromContext(context) { return context.USER_CONFIG.AZURE_API_KEY; } - /** * @param {ContextType} context * @returns {boolean} @@ -28,7 +27,6 @@ export function isAzureImageEnable(context) { return !!(context.USER_CONFIG.AZURE_API_KEY && context.USER_CONFIG.AZURE_DALLE_API); } - /** * 发送消息到Azure ChatGPT * @param {LlmParams} params @@ -37,16 +35,16 @@ export function isAzureImageEnable(context) { * @returns {Promise} */ export async function requestCompletionsFromAzureOpenAI(params, context, onStream) { - const {message, images, prompt, history} = params; + const { message, images, prompt, history } = params; const url = context.USER_CONFIG.AZURE_COMPLETIONS_API; const header = { 'Content-Type': 'application/json', 'api-key': azureKeyFromContext(context), }; - const messages = [...(history || []), {role: 'user', content: message, images}]; + const messages = [...(history || []), { role: 'user', content: message, images }]; if (prompt) { - messages.unshift({role: context.USER_CONFIG.SYSTEM_INIT_MESSAGE_ROLE, content: prompt}); + messages.unshift({ role: context.USER_CONFIG.SYSTEM_INIT_MESSAGE_ROLE, content: prompt }); } const body = { @@ -85,7 +83,7 @@ export async function requestImageFromAzureOpenAI(prompt, context) { method: 'POST', headers: header, body: JSON.stringify(body), - }).then((res) => res.json()); + }).then(res => res.json()); if (resp.error?.message) { throw new Error(resp.error.message); diff --git a/src/agent/chat.js b/src/agent/chat.js new file mode 100644 index 00000000..4eed619c --- /dev/null +++ b/src/agent/chat.js @@ -0,0 +1,105 @@ +import { DATABASE, ENV } from '../config/env.js'; +import '../types/agent.js'; + +/** + * @returns {(function(string): number)} + */ +function tokensCounter() { + return (text) => { + return text.length; + }; +} + +/** + * 加载历史TG消息 + * @param {string} key + * @returns {Promise} + */ +async function loadHistory(key) { + // 加载历史记录 + let history = []; + try { + history = JSON.parse(await DATABASE.get(key)); + } catch (e) { + console.error(e); + } + if (!history || !Array.isArray(history)) { + history = []; + } + + const counter = tokensCounter(); + + const trimHistory = (list, initLength, maxLength, maxToken) => { + // 历史记录超出长度需要裁剪, 小于0不裁剪 + if (maxLength >= 0 && list.length > maxLength) { + list = list.splice(list.length - maxLength); + } + // 处理token长度问题, 小于0不裁剪 + if (maxToken > 0) { + let tokenLength = initLength; + for (let i = list.length - 1; i >= 0; i--) { + const historyItem = list[i]; + let length = 0; + if (historyItem.content) { + length = counter(historyItem.content); + } else { + historyItem.content = ''; + } + // 如果最大长度超过maxToken,裁剪history + tokenLength += length; + if (tokenLength > maxToken) { + list = list.splice(i + 1); + break; + } + } + } + return list; + }; + + // 裁剪 + if (ENV.AUTO_TRIM_HISTORY && ENV.MAX_HISTORY_LENGTH > 0) { + history = trimHistory(history, 0, ENV.MAX_HISTORY_LENGTH, ENV.MAX_TOKEN_LENGTH); + } + + return history; +} + +/** + * @typedef {function (string): Promise} StreamResultHandler + */ + +/** + * @param {LlmRequestParams} params + * @param {ContextType} context + * @param {ChatAgentRequest} llm + * @param {LlmModifier} modifier + * @param {StreamResultHandler} onStream + * @returns {Promise} + */ +export async function requestCompletionsFromLLM(params, context, llm, modifier, onStream) { + const historyDisable = ENV.AUTO_TRIM_HISTORY && ENV.MAX_HISTORY_LENGTH <= 0; + const historyKey = context.SHARE_CONTEXT.chatHistoryKey; + let history = await loadHistory(historyKey); + if (modifier) { + const modifierData = modifier(history, params.message); + history = modifierData.history; + params.message = modifierData.message; + } + const llmParams = { + ...params, + history, + prompt: context.USER_CONFIG.SYSTEM_INIT_MESSAGE, + }; + const answer = await llm(llmParams, context, onStream); + if (!historyDisable) { + const userMessage = { role: 'user', content: params.message || '', images: params.images }; + if (ENV.HISTORY_IMAGE_PLACEHOLDER && userMessage.images && userMessage.images.length > 0) { + delete userMessage.images; + userMessage.content = `${ENV.HISTORY_IMAGE_PLACEHOLDER}\n${userMessage.content}`; + } + history.push(userMessage); + history.push({ role: 'assistant', content: answer }); + await DATABASE.put(historyKey, JSON.stringify(history)).catch(console.error); + } + return answer; +} diff --git a/src/agent/cohere.js b/src/agent/cohere.js index 592f48b5..aa1972f1 100644 --- a/src/agent/cohere.js +++ b/src/agent/cohere.js @@ -1,7 +1,6 @@ import '../types/context.js'; -import {cohereSseJsonParser, Stream} from './stream.js'; -import {requestChatCompletions} from './request.js'; - +import { Stream, cohereSseJsonParser } from './stream.js'; +import { requestChatCompletions } from './request.js'; /** * @param {ContextType} context @@ -12,8 +11,8 @@ export function isCohereAIEnable(context) { } const COHERE_ROLE_MAP = { - 'assistant': 'CHATBOT', - 'user': 'USER', + assistant: 'CHATBOT', + user: 'USER', }; /** @@ -27,7 +26,6 @@ function renderCohereMessage(item) { }; } - /** * 发送消息到Cohere AI * @param {LlmParams} params @@ -36,7 +34,7 @@ function renderCohereMessage(item) { * @returns {Promise} */ export async function requestCompletionsFromCohereAI(params, context, onStream) { - const {message, prompt, history} = params; + const { message, prompt, history } = params; const url = `${context.USER_CONFIG.COHERE_API_BASE}/chat`; const header = { 'Authorization': `Bearer ${context.USER_CONFIG.COHERE_API_KEY}`, @@ -59,16 +57,16 @@ export async function requestCompletionsFromCohereAI(params, context, onStream) * @type {SseChatCompatibleOptions} */ const options = {}; - options.streamBuilder = function(r, c) { + options.streamBuilder = function (r, c) { return new Stream(r, c, null, cohereSseJsonParser); }; - options.contentExtractor = function(data) { + options.contentExtractor = function (data) { return data?.text; }; - options.fullContentExtractor = function(data) { + options.fullContentExtractor = function (data) { return data?.text; }; - options.errorExtractor = function(data) { + options.errorExtractor = function (data) { return data?.message; }; return requestChatCompletions(url, header, body, context, onStream, null, options); diff --git a/src/agent/gemini.js b/src/agent/gemini.js index 0c8f37ee..d6b88741 100644 --- a/src/agent/gemini.js +++ b/src/agent/gemini.js @@ -8,11 +8,10 @@ export function isGeminiAIEnable(context) { return !!(context.USER_CONFIG.GOOGLE_API_KEY); } - const GEMINI_ROLE_MAP = { - 'assistant': 'model', - 'system': 'user', - 'user': 'user', + assistant: 'model', + system: 'user', + user: 'user', }; /** @@ -24,7 +23,7 @@ function renderGeminiMessage(item) { role: GEMINI_ROLE_MAP[item.role], parts: [ { - 'text': item.content || '', + text: item.content || '', }, ], }; @@ -38,15 +37,15 @@ function renderGeminiMessage(item) { * @returns {Promise} */ export async function requestCompletionsFromGeminiAI(params, context, onStream) { - const {message, prompt, history} = params; + const { message, prompt, history } = params; onStream = null; // 暂时不支持stream模式 const url = `${context.USER_CONFIG.GOOGLE_COMPLETIONS_API}${context.USER_CONFIG.GOOGLE_COMPLETIONS_MODEL}:${ onStream ? 'streamGenerateContent' : 'generateContent' }?key=${context.USER_CONFIG.GOOGLE_API_KEY}`; - const contentsTemp = [...history || [], {role: 'user', content: message}]; + const contentsTemp = [...history || [], { role: 'user', content: message }]; if (prompt) { - contentsTemp.unshift({role: 'assistant', content: prompt}); + contentsTemp.unshift({ role: 'assistant', content: prompt }); } const contents = []; // role必须是 model,user 而且不能连续两个一样 @@ -66,7 +65,7 @@ export async function requestCompletionsFromGeminiAI(params, context, onStream) headers: { 'Content-Type': 'application/json', }, - body: JSON.stringify({contents}), + body: JSON.stringify({ contents }), }); const data = await resp.json(); try { diff --git a/src/agent/llm.js b/src/agent/llm.js deleted file mode 100644 index 6c536f03..00000000 --- a/src/agent/llm.js +++ /dev/null @@ -1,200 +0,0 @@ -import { - deleteMessageFromTelegramWithContext, - sendChatActionToTelegramWithContext, - sendMessageToTelegramWithContext, -} from '../telegram/telegram.js'; -import {DATABASE, ENV} from '../config/env.js'; -import {loadChatLLM} from './agents.js'; -import '../types/agent.js'; - -/** - * @returns {(function(string): number)} - */ -function tokensCounter() { - return (text) => { - return text.length; - }; -} - - -/** - * 加载历史TG消息 - * @param {string} key - * @returns {Promise} - */ -async function loadHistory(key) { - - // 加载历史记录 - let history = []; - try { - history = JSON.parse(await DATABASE.get(key)); - } catch (e) { - console.error(e); - } - if (!history || !Array.isArray(history)) { - history = []; - } - - const counter = tokensCounter(); - - const trimHistory = (list, initLength, maxLength, maxToken) => { - // 历史记录超出长度需要裁剪, 小于0不裁剪 - if (maxLength >= 0 && list.length > maxLength) { - list = list.splice(list.length - maxLength); - } - // 处理token长度问题, 小于0不裁剪 - if (maxToken > 0) { - let tokenLength = initLength; - for (let i = list.length - 1; i >= 0; i--) { - const historyItem = list[i]; - let length = 0; - if (historyItem.content) { - length = counter(historyItem.content); - } else { - historyItem.content = ''; - } - // 如果最大长度超过maxToken,裁剪history - tokenLength += length; - if (tokenLength > maxToken) { - list = list.splice(i + 1); - break; - } - } - } - return list; - }; - - // 裁剪 - if (ENV.AUTO_TRIM_HISTORY && ENV.MAX_HISTORY_LENGTH > 0) { - history = trimHistory(history, 0, ENV.MAX_HISTORY_LENGTH, ENV.MAX_TOKEN_LENGTH); - } - - return history; -} - -/** - * @typedef {object} LlmModifierResult - * @property {HistoryItem[]} history - * @property {string} message - * @typedef {function(HistoryItem[], string): LlmModifierResult} LlmModifier - */ - -/** - * @typedef {function (string): Promise} StreamResultHandler - */ - -/** - * @param {LlmRequestParams} params - * @param {ContextType} context - * @param {ChatAgentRequest} llm - * @param {LlmModifier} modifier - * @param {StreamResultHandler} onStream - * @returns {Promise} - */ -async function requestCompletionsFromLLM(params, context, llm, modifier, onStream) { - const historyDisable = ENV.AUTO_TRIM_HISTORY && ENV.MAX_HISTORY_LENGTH <= 0; - const historyKey = context.SHARE_CONTEXT.chatHistoryKey; - const {message, images} = params; - let history = await loadHistory(historyKey); - if (modifier) { - const modifierData = modifier(history, message); - history = modifierData.history; - params.message = modifierData.message; - } - const llmParams = { - ...params, - history, - prompt: context.USER_CONFIG.SYSTEM_INIT_MESSAGE, - }; - const answer = await llm(llmParams, context, onStream); - if (!historyDisable) { - history.push({role: 'user', content: message || '', images}); - history.push({role: 'assistant', content: answer}); - await DATABASE.put(historyKey, JSON.stringify(history)).catch(console.error); - } - return answer; -} - -/** - * 与LLM聊天 - * @param {LlmRequestParams} params - * @param {ContextType} context - * @param {LlmModifier} modifier - * @returns {Promise} - */ -export async function chatWithLLM(params, context, modifier) { - try { - try { - const msg = await sendMessageToTelegramWithContext(context)('...').then((r) => r.json()); - context.CURRENT_CHAT_CONTEXT.message_id = msg.result.message_id; - context.CURRENT_CHAT_CONTEXT.reply_markup = null; - } catch (e) { - console.error(e); - } - setTimeout(() => sendChatActionToTelegramWithContext(context)('typing').catch(console.error), 0); - let onStream = null; - const parseMode = context.CURRENT_CHAT_CONTEXT.parse_mode; - let nextEnableTime = null; - if (ENV.STREAM_MODE) { - context.CURRENT_CHAT_CONTEXT.parse_mode = null; - onStream = async (text) => { - try { - // 判断是否需要等待 - if (nextEnableTime && nextEnableTime > Date.now()) { - return; - } - const resp = await sendMessageToTelegramWithContext(context)(text); - // 判断429 - if (resp.status === 429) { - // 获取重试时间 - const retryAfter = parseInt(resp.headers.get('Retry-After')); - if (retryAfter) { - nextEnableTime = Date.now() + retryAfter * 1000; - return; - } - } - nextEnableTime = null; - if (resp.ok) { - context.CURRENT_CHAT_CONTEXT.message_id = (await resp.json()).result.message_id; - } - } catch (e) { - console.error(e); - } - }; - } - - const llm = loadChatLLM(context)?.request; - if (llm === null) { - return sendMessageToTelegramWithContext(context)('LLM is not enable'); - } - const answer = await requestCompletionsFromLLM(params, context, llm, modifier, onStream); - context.CURRENT_CHAT_CONTEXT.parse_mode = parseMode; - if (ENV.SHOW_REPLY_BUTTON && context.CURRENT_CHAT_CONTEXT.message_id) { - try { - await deleteMessageFromTelegramWithContext(context)(context.CURRENT_CHAT_CONTEXT.message_id); - context.CURRENT_CHAT_CONTEXT.message_id = null; - context.CURRENT_CHAT_CONTEXT.reply_markup = { - keyboard: [[{text: '/new'}, {text: '/redo'}]], - selective: true, - resize_keyboard: true, - one_time_keyboard: true, - }; - } catch (e) { - console.error(e); - } - } - if (nextEnableTime && nextEnableTime > Date.now()) { - await new Promise((resolve) => setTimeout(resolve, nextEnableTime - Date.now())); - } - return sendMessageToTelegramWithContext(context)(answer); - } catch (e) { - let errMsg = `Error: ${e.message}`; - if (errMsg.length > 2048) { - // 裁剪错误信息 最长2048 - errMsg = errMsg.substring(0, 2048); - } - context.CURRENT_CHAT_CONTEXT.disable_web_page_preview = true; - return sendMessageToTelegramWithContext(context)(errMsg); - } -} - diff --git a/src/agent/mistralai.js b/src/agent/mistralai.js index 179a3498..aed6533a 100644 --- a/src/agent/mistralai.js +++ b/src/agent/mistralai.js @@ -1,5 +1,5 @@ import '../types/context.js'; -import {requestChatCompletions} from './request.js'; +import { requestChatCompletions } from './request.js'; /** * @param {ContextType} context @@ -20,7 +20,6 @@ function renderMistralMessage(item) { }; } - /** * 发送消息到Mistral AI * @param {LlmParams} params @@ -29,16 +28,16 @@ function renderMistralMessage(item) { * @returns {Promise} */ export async function requestCompletionsFromMistralAI(params, context, onStream) { - const {message, prompt, history} = params; + const { message, prompt, history } = params; const url = `${context.USER_CONFIG.MISTRAL_API_BASE}/chat/completions`; const header = { 'Content-Type': 'application/json', 'Authorization': `Bearer ${context.USER_CONFIG.MISTRAL_API_KEY}`, }; - const messages = [...(history || []), {role: 'user', content: message}]; + const messages = [...(history || []), { role: 'user', content: message }]; if (prompt) { - messages.unshift({role: context.USER_CONFIG.SYSTEM_INIT_MESSAGE_ROLE, content: prompt}); + messages.unshift({ role: context.USER_CONFIG.SYSTEM_INIT_MESSAGE_ROLE, content: prompt }); } const body = { diff --git a/src/agent/openai.js b/src/agent/openai.js index f80486f2..d5220529 100644 --- a/src/agent/openai.js +++ b/src/agent/openai.js @@ -1,9 +1,8 @@ import '../types/context.js'; -import {requestChatCompletions} from './request.js'; -import {ENV} from '../config/env.js'; - -import {imageToBase64String, renderBase64DataURI} from '../utils/image.js'; +import { ENV } from '../config/env.js'; +import { imageToBase64String, renderBase64DataURI } from '../utils/image.js'; +import { requestChatCompletions } from './request.js'; /** * @param {ContextType} context @@ -14,7 +13,6 @@ function openAIKeyFromContext(context) { return context.USER_CONFIG.OPENAI_API_KEY[Math.floor(Math.random() * length)]; } - /** * @param {ContextType} context * @returns {boolean} @@ -23,7 +21,6 @@ export function isOpenAIEnable(context) { return context.USER_CONFIG.OPENAI_API_KEY.length > 0; } - /** * @param {HistoryItem} item * @returns {Promise} @@ -36,26 +33,25 @@ export async function renderOpenAIMessage(item) { if (item.images && item.images.length > 0) { res.content = []; if (item.content) { - res.content.push({type: 'text', text: item.content}); + res.content.push({ type: 'text', text: item.content }); } for (const image of item.images) { switch (ENV.TELEGRAM_IMAGE_TRANSFER_MODE) { - case 'base64': - res.content.push({type: 'image_url', image_url: { - url: renderBase64DataURI(await imageToBase64String(image)), - }}); - break; - case 'url': - default: - res.content.push({type: 'image_url', image_url: {url: image}}); - break; + case 'base64': + res.content.push({ type: 'image_url', image_url: { + url: renderBase64DataURI(await imageToBase64String(image)), + } }); + break; + case 'url': + default: + res.content.push({ type: 'image_url', image_url: { url: image } }); + break; } } } return res; } - /** * 发送消息到ChatGPT * @param {LlmParams} params @@ -64,17 +60,16 @@ export async function renderOpenAIMessage(item) { * @returns {Promise} */ export async function requestCompletionsFromOpenAI(params, context, onStream) { - - const {message, images, prompt, history} = params; + const { message, images, prompt, history } = params; const url = `${context.USER_CONFIG.OPENAI_API_BASE}/chat/completions`; const header = { 'Content-Type': 'application/json', 'Authorization': `Bearer ${openAIKeyFromContext(context)}`, }; - const messages = [...(history || []), {role: 'user', content: message, images}]; + const messages = [...(history || []), { role: 'user', content: message, images }]; if (prompt) { - messages.unshift({role: context.USER_CONFIG.SYSTEM_INIT_MESSAGE_ROLE, content: prompt}); + messages.unshift({ role: context.USER_CONFIG.SYSTEM_INIT_MESSAGE_ROLE, content: prompt }); } const body = { @@ -87,7 +82,6 @@ export async function requestCompletionsFromOpenAI(params, context, onStream) { return requestChatCompletions(url, header, body, context, onStream); } - /** * 请求Openai生成图片 * @param {string} prompt @@ -114,13 +108,10 @@ export async function requestImageFromOpenAI(prompt, context) { method: 'POST', headers: header, body: JSON.stringify(body), - }).then((res) => res.json()); + }).then(res => res.json()); if (resp.error?.message) { throw new Error(resp.error.message); } return resp?.data?.[0]?.url; } - - - diff --git a/src/agent/request.js b/src/agent/request.js index c3ea7f77..6580e3fc 100644 --- a/src/agent/request.js +++ b/src/agent/request.js @@ -1,7 +1,6 @@ import '../types/context.js'; -import {ENV} from '../config/env.js'; -import {Stream} from './stream.js'; - +import { ENV } from '../config/env.js'; +import { Stream } from './stream.js'; /** * @callback StreamBuilder @@ -9,7 +8,7 @@ import {Stream} from './stream.js'; * @param {AbortController} controller * @returns {Stream} */ -/** +/** * @callback SSEContentExtractor * @param {object} data * @returns {string|null} @@ -19,7 +18,7 @@ import {Stream} from './stream.js'; * @param {object} data * @returns {string|null} */ -/** +/** * @callback ErrorExtractor * @param {object} data * @returns {string|null} @@ -39,16 +38,16 @@ import {Stream} from './stream.js'; */ function fixOpenAICompatibleOptions(options) { options = options || {}; - options.streamBuilder = options.streamBuilder || function(r, c) { + options.streamBuilder = options.streamBuilder || function (r, c) { return new Stream(r, c); }; - options.contentExtractor = options.contentExtractor || function(d) { + options.contentExtractor = options.contentExtractor || function (d) { return d?.choices?.[0]?.delta?.content; }; - options.fullContentExtractor = options.fullContentExtractor || function(d) { + options.fullContentExtractor = options.fullContentExtractor || function (d) { return d.choices?.[0]?.message.content; }; - options.errorExtractor = options.errorExtractor || function(d) { + options.errorExtractor = options.errorExtractor || function (d) { return d.error?.message; }; return options; @@ -59,7 +58,7 @@ function fixOpenAICompatibleOptions(options) { * @returns {boolean} */ export function isJsonResponse(resp) { - return resp.headers.get('content-type').indexOf('json') !== -1; + return resp.headers.get('content-type').includes('json'); } /** @@ -70,7 +69,7 @@ export function isEventStreamResponse(resp) { const types = ['application/stream+json', 'text/event-stream']; const content = resp.headers.get('content-type'); for (const type of types) { - if (content.indexOf(type) !== -1) { + if (content.includes(type)) { return true; } } @@ -90,7 +89,7 @@ export function isEventStreamResponse(resp) { */ export async function requestChatCompletions(url, header, body, context, onStream, onResult = null, options = null) { const controller = new AbortController(); - const {signal} = controller; + const { signal } = controller; let timeoutID = null; let lastUpdateTime = Date.now(); @@ -162,6 +161,6 @@ export async function requestChatCompletions(url, header, body, context, onStrea return options.fullContentExtractor(result); } catch (e) { console.error(e); - throw Error(JSON.stringify(result)); + throw new Error(JSON.stringify(result)); } } diff --git a/src/agent/stream.js b/src/agent/stream.js index 9a21986d..3cc98f2e 100644 --- a/src/agent/stream.js +++ b/src/agent/stream.js @@ -40,7 +40,7 @@ export class Stream { if (!sse) { continue; } - const {finish, data} = this.parser(sse); + const { finish, data } = this.parser(sse); if (finish) { done = finish; continue; @@ -137,11 +137,11 @@ export function openaiSseJsonParser(sse) { // data: {} // data: [DONE] if (sse.data.startsWith('[DONE]')) { - return {finish: true}; + return { finish: true }; } if (sse.event === null) { try { - return {data: JSON.parse(sse.data)}; + return { data: JSON.parse(sse.data) }; } catch (e) { console.error(e, sse); } @@ -161,19 +161,19 @@ export function cohereSseJsonParser(sse) { // event: stream-end // data: {"is_finished":true,...} switch (sse.event) { - case 'text-generation': - try { - return {data: JSON.parse(sse.data)}; - } catch (e) { - console.error(e, sse.data); + case 'text-generation': + try { + return { data: JSON.parse(sse.data) }; + } catch (e) { + console.error(e, sse.data); + return {}; + } + case 'stream-start': + return {}; + case 'stream-end': + return { finish: true }; + default: return {}; - } - case 'stream-start': - return {}; - case 'stream-end': - return {finish: true}; - default: - return {}; } } @@ -188,21 +188,21 @@ export function anthropicSseJsonParser(sse) { // event: message_stop // data: {"type": "message_stop"} switch (sse.event) { - case 'content_block_delta': - try { - return {data: JSON.parse(sse.data)}; - } catch (e) { - console.error(e, sse.data); + case 'content_block_delta': + try { + return { data: JSON.parse(sse.data) }; + } catch (e) { + console.error(e, sse.data); + return {}; + } + case 'message_start': + case 'content_block_start': + case 'content_block_stop': + return {}; + case 'message_stop': + return { finish: true }; + default: return {}; - } - case 'message_start': - case 'content_block_start': - case 'content_block_stop': - return {}; - case 'message_stop': - return {finish: true}; - default: - return {}; } } @@ -221,7 +221,7 @@ class LineDecoder { decode(chunk) { let text = this.decodeText(chunk); if (this.trailingCR) { - text = '\r' + text; + text = `\r${text}`; this.trailingCR = false; } if (text.endsWith('\r')) { @@ -248,7 +248,6 @@ class LineDecoder { } decodeText(bytes) { - var _a; if (bytes == null) { return ''; } @@ -268,8 +267,10 @@ class LineDecoder { // Browser if (typeof TextDecoder !== 'undefined') { if (bytes instanceof Uint8Array || bytes instanceof ArrayBuffer) { - (_a = this.textDecoder) !== null && _a !== void 0 ? _a : (this.textDecoder = new TextDecoder('utf8')); - return this.textDecoder.decode(bytes, {stream: true}); + if (!this.textDecoder) { + this.textDecoder = new TextDecoder('utf8'); + } + return this.textDecoder.decode(bytes, { stream: true }); } throw new Error(`Unexpected: received non-Uint8Array/ArrayBuffer (${bytes.constructor.name}) in a web platform. Please report this error.`); } diff --git a/src/agent/workersai.js b/src/agent/workersai.js index 540c91f0..1214295b 100644 --- a/src/agent/workersai.js +++ b/src/agent/workersai.js @@ -1,5 +1,5 @@ import '../types/context.js'; -import {requestChatCompletions} from './request.js'; +import { requestChatCompletions } from './request.js'; /** * Run the specified AI model with the provided body data. @@ -13,7 +13,7 @@ async function run(model, body, id, token) { return await fetch( `https://api.cloudflare.com/client/v4/accounts/${id}/ai/run/${model}`, { - headers: {Authorization: `Bearer ${token}`}, + headers: { Authorization: `Bearer ${token}` }, method: 'POST', body: JSON.stringify(body), }, @@ -39,7 +39,6 @@ function renderWorkerAIMessage(item) { }; } - /** * 发送消息到Workers AI * @param {LlmParams} params @@ -48,8 +47,7 @@ function renderWorkerAIMessage(item) { * @returns {Promise} */ export async function requestCompletionsFromWorkersAI(params, context, onStream) { - - const {message, prompt, history} = params; + const { message, prompt, history } = params; const id = context.USER_CONFIG.CLOUDFLARE_ACCOUNT_ID; const token = context.USER_CONFIG.CLOUDFLARE_TOKEN; const model = context.USER_CONFIG.WORKERS_CHAT_MODEL; @@ -58,9 +56,9 @@ export async function requestCompletionsFromWorkersAI(params, context, onStream) Authorization: `Bearer ${token}`, }; - const messages = [...(history || []), {role: 'user', content: message}]; + const messages = [...(history || []), { role: 'user', content: message }]; if (prompt) { - messages.unshift({role: context.USER_CONFIG.SYSTEM_INIT_MESSAGE_ROLE, content: prompt}); + messages.unshift({ role: context.USER_CONFIG.SYSTEM_INIT_MESSAGE_ROLE, content: prompt }); } const body = { @@ -72,13 +70,13 @@ export async function requestCompletionsFromWorkersAI(params, context, onStream) * @type {SseChatCompatibleOptions} */ const options = {}; - options.contentExtractor = function(data) { + options.contentExtractor = function (data) { return data?.response; }; - options.fullContentExtractor = function(data) { + options.fullContentExtractor = function (data) { return data?.result?.response; }; - options.errorExtractor = function(data) { + options.errorExtractor = function (data) { return data?.errors?.[0]?.message; }; return requestChatCompletions(url, header, body, context, onStream, null, options); @@ -92,6 +90,6 @@ export async function requestCompletionsFromWorkersAI(params, context, onStream) export async function requestImageFromWorkersAI(prompt, context) { const id = context.USER_CONFIG.CLOUDFLARE_ACCOUNT_ID; const token = context.USER_CONFIG.CLOUDFLARE_TOKEN; - const raw = await run(context.USER_CONFIG.WORKERS_IMAGE_MODEL, {prompt}, id, token); + const raw = await run(context.USER_CONFIG.WORKERS_IMAGE_MODEL, { prompt }, id, token); return await raw.blob(); } diff --git a/src/config/context.js b/src/config/context.js index e6dfc72e..fd53d4b0 100644 --- a/src/config/context.js +++ b/src/config/context.js @@ -1,4 +1,4 @@ -import {CONST, DATABASE, ENV, mergeEnvironment, UserConfig} from './env.js'; +import { CONST, DATABASE, ENV, UserConfig, mergeEnvironment } from './env.js'; import '../types/telegram.js'; /** @@ -7,9 +7,9 @@ import '../types/telegram.js'; */ export function trimUserConfig(userConfig) { const config = { - ...userConfig, + ...(userConfig || {}), }; - const keysSet = new Set(userConfig.DEFINE_KEYS); + const keysSet = new Set(userConfig?.DEFINE_KEYS || []); for (const key of ENV.LOCK_USER_CONFIG_KEYS) { keysSet.delete(key); } @@ -39,6 +39,7 @@ class ShareContext { chatId = null; speakerId = null; extraMessageContext = null; + allMemberAreAdmin = false; } /** @@ -61,7 +62,6 @@ class CurrentChatContext { * @implements {ContextType} */ export class Context { - // 用户配置 USER_CONFIG = new UserConfig(); CURRENT_CHAT_CONTEXT = new CurrentChatContext(); @@ -103,7 +103,6 @@ export class Context { } } - /** * @param {string} token */ @@ -177,6 +176,7 @@ export class Context { this.SHARE_CONTEXT.chatType = message.chat?.type; this.SHARE_CONTEXT.chatId = message.chat.id; this.SHARE_CONTEXT.speakerId = message.from.id || message.chat.id; + this.SHARE_CONTEXT.allMemberAreAdmin = message?.chat?.all_members_are_administrators; } /** diff --git a/src/config/env.js b/src/config/env.js index 28f2f948..54510c90 100644 --- a/src/config/env.js +++ b/src/config/env.js @@ -101,16 +101,15 @@ export class UserConfig { ANTHROPIC_CHAT_MODEL = 'claude-3-haiku-20240307'; } - export class Environment { - // -- 版本数据 -- // // 当前版本 - BUILD_TIMESTAMP = process?.env?.BUILD_TIMESTAMP || 0; + // eslint-disable-next-line no-undef + BUILD_TIMESTAMP = typeof __BUILD_TIMESTAMP__ === 'number' ? __BUILD_TIMESTAMP__ : 0; // 当前版本 commit id - BUILD_VERSION = process?.env?.BUILD_VERSION || ''; - + // eslint-disable-next-line no-undef + BUILD_VERSION = typeof __BUILD_VERSION__ === 'string' ? __BUILD_VERSION__ : 'unknown'; // -- 基础配置 -- /** @@ -140,7 +139,6 @@ export class Environment { // 向LLM优先传递图片方式:url, base64 TELEGRAM_IMAGE_TRANSFER_MODE = 'url'; - // -- 权限相关 -- // // 允许所有人使用 @@ -178,7 +176,8 @@ export class Environment { MAX_HISTORY_LENGTH = 20; // 最大消息长度 MAX_TOKEN_LENGTH = -1; - + // Image占位符: 当此环境变量存在时,则历史记录中的图片将被替换为此占位符 + HISTORY_IMAGE_PLACEHOLDER = null; // -- 特性开关 -- // @@ -202,16 +201,27 @@ export class Environment { // 开发模式 DEV_MODE = false; - USER_CONFIG = new UserConfig(); } - -// Environment Variables: Separate configuration values from a Worker script with Environment Variables. +/** + * Environment Variables: Separate configuration values from a Worker script with Environment Variables. + * @type {Environment} + */ export const ENV = new Environment(); -// KV Namespace Bindings: Bind an instance of a KV Namespace to access its data in a Worker + +/** + * KV Namespace Bindings: Bind an instance of a KV Namespace to access its data in a Worker + * @type {KVNamespace} + */ +// eslint-disable-next-line import/no-mutable-exports export let DATABASE = null; -// Service Bindings: Bind to another Worker to invoke it directly from your code. + +/** + * Service Bindings: Bind to another Worker to invoke it directly from your code. + * @type {APIGuard|null} + */ +// eslint-disable-next-line import/no-mutable-exports export let API_GUARD = null; export const CUSTOM_COMMAND = {}; @@ -233,6 +243,7 @@ const ENV_TYPES = { MISTRAL_API_KEY: 'string', COHERE_API_KEY: 'string', ANTHROPIC_API_KEY: 'string', + HISTORY_IMAGE_PLACEHOLDER: 'string', }; export const ENV_KEY_MAPPER = { @@ -246,6 +257,10 @@ export const ENV_KEY_MAPPER = { * @returns {string[]} */ function parseArray(raw) { + raw = raw.trim(); + if (raw === '') { + return []; + } if (raw.startsWith('[') && raw.endsWith(']')) { try { return JSON.parse(raw); @@ -257,7 +272,7 @@ function parseArray(raw) { } /** - * @param {object} target + * @param {Environment|UserConfig} target * @param {object} source */ export function mergeEnvironment(target, source) { @@ -274,43 +289,41 @@ export function mergeEnvironment(target, source) { continue; } switch (t) { - case 'number': - target[key] = parseInt(source[key], 10); - break; - case 'boolean': - target[key] = (source[key] || 'false') === 'true'; - break; - case 'string': - target[key] = source[key]; - break; - case 'array': - target[key] = parseArray(source[key]); - break; - case 'object': - if (Array.isArray(target[key])) { + case 'number': + target[key] = Number.parseInt(source[key], 10); + break; + case 'boolean': + target[key] = (source[key] || 'false') === 'true'; + break; + case 'string': + target[key] = source[key]; + break; + case 'array': target[key] = parseArray(source[key]); - } else { - try { - target[key] = JSON.parse(source[key]); - } catch (e) { - console.error(e); + break; + case 'object': + if (Array.isArray(target[key])) { + target[key] = parseArray(source[key]); + } else { + try { + target[key] = JSON.parse(source[key]); + } catch (e) { + console.error(e); + } } - } - break; - default: - target[key] = source[key]; - break; + break; + default: + target[key] = source[key]; + break; } } } - /** * @param {object} env * @param {I18nGenerator} i18n */ export function initEnv(env, i18n) { - // 全局对象 DATABASE = env.DATABASE; API_GUARD = env.API_GUARD; @@ -321,52 +334,55 @@ export function initEnv(env, i18n) { for (const key of Object.keys(env)) { if (key.startsWith(customCommandPrefix)) { const cmd = key.substring(customCommandPrefix.length); - CUSTOM_COMMAND['/' + cmd] = env[key]; - CUSTOM_COMMAND_DESCRIPTION['/' + cmd] = env[customCommandDescriptionPrefix + cmd]; + CUSTOM_COMMAND[`/${cmd}`] = env[key]; + CUSTOM_COMMAND_DESCRIPTION[`/${cmd}`] = env[customCommandDescriptionPrefix + cmd]; } } // 合并环境变量 mergeEnvironment(ENV, env); mergeEnvironment(ENV.USER_CONFIG, env); + migrateOldEnv(env, i18n); ENV.USER_CONFIG.DEFINE_KEYS = []; +} +/** + * @param {object} env + * @param {I18nGenerator} i18n + */ +function migrateOldEnv(env, i18n) { + ENV.I18N = i18n((ENV.LANGUAGE || 'cn').toLowerCase()); - // 兼容旧版配置 - { - ENV.I18N = i18n((ENV.LANGUAGE || 'cn').toLowerCase()); - - // 兼容旧版 TELEGRAM_TOKEN - if (env.TELEGRAM_TOKEN && !ENV.TELEGRAM_AVAILABLE_TOKENS.includes(env.TELEGRAM_TOKEN)) { - if (env.BOT_NAME && ENV.TELEGRAM_AVAILABLE_TOKENS.length === ENV.TELEGRAM_BOT_NAME.length) { - ENV.TELEGRAM_BOT_NAME.push(env.BOT_NAME); - } - ENV.TELEGRAM_AVAILABLE_TOKENS.push(env.TELEGRAM_TOKEN); + // 兼容旧版 TELEGRAM_TOKEN + if (env.TELEGRAM_TOKEN && !ENV.TELEGRAM_AVAILABLE_TOKENS.includes(env.TELEGRAM_TOKEN)) { + if (env.BOT_NAME && ENV.TELEGRAM_AVAILABLE_TOKENS.length === ENV.TELEGRAM_BOT_NAME.length) { + ENV.TELEGRAM_BOT_NAME.push(env.BOT_NAME); } + ENV.TELEGRAM_AVAILABLE_TOKENS.push(env.TELEGRAM_TOKEN); + } - // 兼容旧版 OPENAI_API_DOMAIN - if (env.OPENAI_API_DOMAIN && !ENV.OPENAI_API_BASE) { - ENV.USER_CONFIG.OPENAI_API_BASE = `${env.OPENAI_API_DOMAIN}/v1`; - } + // 兼容旧版 OPENAI_API_DOMAIN + if (env.OPENAI_API_DOMAIN && !ENV.OPENAI_API_BASE) { + ENV.USER_CONFIG.OPENAI_API_BASE = `${env.OPENAI_API_DOMAIN}/v1`; + } - // 兼容旧版 WORKERS_AI_MODEL - if (env.WORKERS_AI_MODEL && !ENV.USER_CONFIG.WORKERS_CHAT_MODEL) { - ENV.USER_CONFIG.WORKERS_CHAT_MODEL = env.WORKERS_AI_MODEL; - } + // 兼容旧版 WORKERS_AI_MODEL + if (env.WORKERS_AI_MODEL && !ENV.USER_CONFIG.WORKERS_CHAT_MODEL) { + ENV.USER_CONFIG.WORKERS_CHAT_MODEL = env.WORKERS_AI_MODEL; + } - // 兼容旧版API_KEY - if (env.API_KEY && ENV.USER_CONFIG.OPENAI_API_KEY.length === 0) { - ENV.USER_CONFIG.OPENAI_API_KEY = env.API_KEY.split(','); - } + // 兼容旧版API_KEY + if (env.API_KEY && ENV.USER_CONFIG.OPENAI_API_KEY.length === 0) { + ENV.USER_CONFIG.OPENAI_API_KEY = env.API_KEY.split(','); + } - // 兼容旧版CHAT_MODEL - if (env.CHAT_MODEL && !ENV.USER_CONFIG.OPENAI_CHAT_MODEL) { - ENV.USER_CONFIG.OPENAI_CHAT_MODEL = env.CHAT_MODEL; - } + // 兼容旧版CHAT_MODEL + if (env.CHAT_MODEL && !ENV.USER_CONFIG.OPENAI_CHAT_MODEL) { + ENV.USER_CONFIG.OPENAI_CHAT_MODEL = env.CHAT_MODEL; + } - // 选择对应语言的SYSTEM_INIT_MESSAGE - if (!ENV.USER_CONFIG.SYSTEM_INIT_MESSAGE) { - ENV.USER_CONFIG.SYSTEM_INIT_MESSAGE = ENV.I18N?.env?.system_init_message || 'You are a helpful assistant'; - } + // 选择对应语言的SYSTEM_INIT_MESSAGE + if (!ENV.USER_CONFIG.SYSTEM_INIT_MESSAGE) { + ENV.USER_CONFIG.SYSTEM_INIT_MESSAGE = ENV.I18N?.env?.system_init_message || 'You are a helpful assistant'; } } diff --git a/src/i18n/index.js b/src/i18n/index.js index dcd4c84e..a6b8e89a 100644 --- a/src/i18n/index.js +++ b/src/i18n/index.js @@ -11,22 +11,22 @@ import '../types/i18n.js'; */ export default function i18n(lang) { switch (lang.toLowerCase()) { - case 'cn': - case 'zh-cn': - case 'zh-hans': - return zhHans; - case 'zh-tw': - case 'zh-hk': - case 'zh-mo': - case 'zh-hant': - return zhHant; - case 'pt': - case 'pt-br': - return pt; - case 'en': - case 'en-us': - return en; - default: - return en; + case 'cn': + case 'zh-cn': + case 'zh-hans': + return zhHans; + case 'zh-tw': + case 'zh-hk': + case 'zh-mo': + case 'zh-hant': + return zhHant; + case 'pt': + case 'pt-br': + return pt; + case 'en': + case 'en-us': + return en; + default: + return en; } } diff --git a/src/route.js b/src/route.js index d2545fb1..38ccd56e 100644 --- a/src/route.js +++ b/src/route.js @@ -1,10 +1,9 @@ -import {handleMessage} from './telegram/message.js'; -import {API_GUARD, ENV} from './config/env.js'; -import {bindCommandForTelegram, commandsDocument} from './telegram/command.js'; -import {bindTelegramWebHook, getBot} from './telegram/telegram.js'; -import {errorToString, makeResponse200, renderHTML} from './utils/utils.js'; -import {Router} from './utils/router.js'; - +import { handleMessage } from './telegram/message.js'; +import { API_GUARD, ENV } from './config/env.js'; +import { bindCommandForTelegram, commandsDocument } from './telegram/command.js'; +import { bindTelegramWebHook } from './telegram/telegram.js'; +import { errorToString, makeResponse200, renderHTML } from './utils/utils.js'; +import { Router } from './utils/router.js'; const helpLink = 'https://github.com/TBXark/ChatGPT-Telegram-Workers/blob/master/doc/en/DEPLOY.md'; const issueLink = 'https://github.com/TBXark/ChatGPT-Telegram-Workers/issues'; @@ -36,8 +35,8 @@ async function bindWebHookAction(request) { const url = `https://${domain}/telegram/${token.trim()}/${hookMode}`; const id = token.split(':')[0]; result[id] = { - webhook: await bindTelegramWebHook(token, url).catch((e) => errorToString(e)), - command: await bindCommandForTelegram(token).catch((e) => errorToString(e)), + webhook: await bindTelegramWebHook(token, url).then(res => res.json()).catch(e => errorToString(e)), + command: await bindCommandForTelegram(token).catch(e => errorToString(e)), }; } @@ -48,7 +47,7 @@ async function bindWebHookAction(request) { ENV.TELEGRAM_AVAILABLE_TOKENS.length === 0 ? buildKeyNotFoundHTML('TELEGRAM_AVAILABLE_TOKENS') : '' } ${ - Object.keys(result).map((id) => ` + Object.keys(result).map(id => `

Bot ID: ${id}

Webhook: ${JSON.stringify(result[id].webhook)}

@@ -58,10 +57,9 @@ async function bindWebHookAction(request) { } ${footer} `); - return new Response(HTML, {status: 200, headers: {'Content-Type': 'text/html'}}); + return new Response(HTML, { status: 200, headers: { 'Content-Type': 'text/html' } }); } - /** * 处理Telegram回调 * @param {Request} request @@ -69,16 +67,15 @@ async function bindWebHookAction(request) { */ async function telegramWebhook(request) { try { - const {token} = request.params; + const { token } = request.params; const body = await request.json(); return makeResponse200(await handleMessage(token, body)); } catch (e) { console.error(e); - return new Response(errorToString(e), {status: 200}); + return new Response(errorToString(e), { status: 200 }); } } - /** *用API_GUARD处理Telegram回调 * @param {Request} request @@ -96,7 +93,7 @@ async function telegramSafeHook(request) { return makeResponse200(await API_GUARD.fetch(request)); } catch (e) { console.error(e); - return new Response(errorToString(e), {status: 200}); + return new Response(errorToString(e), { status: 200 }); } } @@ -114,42 +111,14 @@ async function defaultIndexAction() {

After binding the webhook, you can use the following commands to control the bot:

${ - commandsDocument().map((item) => `

${item.command} - ${item.description}

`).join('') + commandsDocument().map(item => `

${item.command} - ${item.description}

`).join('') }

You can get bot information by visiting the following URL:

/telegram/:token/bot - Get bot information

${footer} `); - return new Response(HTML, {status: 200, headers: {'Content-Type': 'text/html'}}); -} - -/** - * @returns {Promise} - */ -async function loadBotInfo() { - const result = []; - for (const token of ENV.TELEGRAM_AVAILABLE_TOKENS) { - const id = token.split(':')[0]; - result[id] = await getBot(token); - } - const HTML = renderHTML(` -

ChatGPT-Telegram-Workers

-
-

Environment About Bot

-

GROUP_CHAT_BOT_ENABLE: ${ENV.GROUP_CHAT_BOT_ENABLE}

-

GROUP_CHAT_BOT_SHARE_MODE: ${ENV.GROUP_CHAT_BOT_SHARE_MODE}

-

TELEGRAM_BOT_NAME: ${ENV.TELEGRAM_BOT_NAME.join(',')}

- ${ - Object.keys(result).map((id) => ` -
-

Bot ID: ${id}

-

${JSON.stringify(result[id])}

- `).join('') -} - ${footer} - `); - return new Response(HTML, {status: 200, headers: {'Content-Type': 'text/html'}}); + return new Response(HTML, { status: 200, headers: { 'Content-Type': 'text/html' } }); } /** @@ -162,9 +131,6 @@ export async function handleRequest(request) { router.get('/init', bindWebHookAction); router.post('/telegram/:token/webhook', telegramWebhook); router.post('/telegram/:token/safehook', telegramSafeHook); - if (ENV.DEV_MODE || ENV.DEBUG_MODE) { - router.get('/telegram/:token/bot', loadBotInfo); - } - router.all('*', () => new Response('Not Found', {status: 404})); + router.all('*', () => new Response('Not Found', { status: 404 })); return router.fetch(request); } diff --git a/src/telegram/agent.js b/src/telegram/agent.js new file mode 100644 index 00000000..090c2b2f --- /dev/null +++ b/src/telegram/agent.js @@ -0,0 +1,73 @@ +import { ENV } from '../config/env.js'; +import { loadChatLLM } from '../agent/agents.js'; +import { requestCompletionsFromLLM } from '../agent/chat.js'; +import { sendChatActionToTelegramWithContext, sendMessageToTelegramWithContext } from './telegram.js'; + +/** + * 与LLM聊天 + * @param {LlmRequestParams} params + * @param {ContextType} context + * @param {LlmModifier} modifier + * @returns {Promise} + */ +export async function chatWithLLM(params, context, modifier) { + try { + try { + const msg = await sendMessageToTelegramWithContext(context)('...').then(r => r.json()); + context.CURRENT_CHAT_CONTEXT.message_id = msg.result.message_id; + context.CURRENT_CHAT_CONTEXT.reply_markup = null; + } catch (e) { + console.error(e); + } + setTimeout(() => sendChatActionToTelegramWithContext(context)('typing').catch(console.error), 0); + let onStream = null; + const parseMode = context.CURRENT_CHAT_CONTEXT.parse_mode; + let nextEnableTime = null; + if (ENV.STREAM_MODE) { + context.CURRENT_CHAT_CONTEXT.parse_mode = null; + onStream = async (text) => { + try { + // 判断是否需要等待 + if (nextEnableTime && nextEnableTime > Date.now()) { + return; + } + const resp = await sendMessageToTelegramWithContext(context)(text); + // 判断429 + if (resp.status === 429) { + // 获取重试时间 + const retryAfter = Number.parseInt(resp.headers.get('Retry-After')); + if (retryAfter) { + nextEnableTime = Date.now() + retryAfter * 1000; + return; + } + } + nextEnableTime = null; + if (resp.ok) { + context.CURRENT_CHAT_CONTEXT.message_id = (await resp.json()).result.message_id; + } + } catch (e) { + console.error(e); + } + }; + } + + const llm = loadChatLLM(context)?.request; + if (llm === null) { + return sendMessageToTelegramWithContext(context)('LLM is not enable'); + } + const answer = await requestCompletionsFromLLM(params, context, llm, modifier, onStream); + context.CURRENT_CHAT_CONTEXT.parse_mode = parseMode; + if (nextEnableTime && nextEnableTime > Date.now()) { + await new Promise(resolve => setTimeout(resolve, nextEnableTime - Date.now())); + } + return sendMessageToTelegramWithContext(context)(answer); + } catch (e) { + let errMsg = `Error: ${e.message}`; + if (errMsg.length > 2048) { + // 裁剪错误信息 最长2048 + errMsg = errMsg.substring(0, 2048); + } + context.CURRENT_CHAT_CONTEXT.disable_web_page_preview = true; + return sendMessageToTelegramWithContext(context)(errMsg); + } +} diff --git a/src/telegram/command.js b/src/telegram/command.js index 32166bc7..7fd572df 100644 --- a/src/telegram/command.js +++ b/src/telegram/command.js @@ -8,13 +8,6 @@ import { ENV_KEY_MAPPER, mergeEnvironment, } from '../config/env.js'; -import { - getChatRoleWithContext, - sendChatActionToTelegramWithContext, - sendMessageToTelegramWithContext, - sendPhotoToTelegramWithContext, -} from './telegram.js'; -import {chatWithLLM} from '../agent/llm.js'; import { chatModelKey, currentChatModel, @@ -23,8 +16,14 @@ import { loadChatLLM, loadImageGen, } from '../agent/agents.js'; -import {trimUserConfig} from '../config/context.js'; - +import { trimUserConfig } from '../config/context.js'; +import { + sendChatActionToTelegramWithContext, + sendMessageToTelegramWithContext, + sendPhotoToTelegramWithContext, +} from './telegram.js'; +import { chatWithLLM } from './agent.js'; +import { getChatRoleWithContext } from './utils.js'; const commandAuthCheck = { default(chatType) { @@ -45,7 +44,6 @@ const commandAuthCheck = { }, }; - const commandSortList = [ '/new', '/redo', @@ -57,9 +55,8 @@ const commandSortList = [ '/help', ]; - /** - * + * * @callback CommandFunction * @param {TelegramMessage} message * @param {string} command @@ -136,8 +133,6 @@ const commandHandlers = { }, }; - - /** * /img 命令 * @param {TelegramMessage} message @@ -157,7 +152,11 @@ async function commandGenerateImg(message, command, subcommand, context) { } setTimeout(() => sendChatActionToTelegramWithContext(context)('upload_photo').catch(console.error), 0); const img = await gen(subcommand, context); - return sendPhotoToTelegramWithContext(context)(img); + const resp = await sendPhotoToTelegramWithContext(context)(img); + if (!resp.ok) { + return sendMessageToTelegramWithContext(context)(`ERROR: ${resp.statusText} ${await resp.text()}`); + } + return resp; } catch (e) { return sendMessageToTelegramWithContext(context)(`ERROR: ${e.message}`); } @@ -172,13 +171,13 @@ async function commandGenerateImg(message, command, subcommand, context) { * @returns {Promise} */ async function commandGetHelp(message, command, subcommand, context) { - let helpMsg = ENV.I18N.command.help.summary + '\n'; + let helpMsg = `${ENV.I18N.command.help.summary}\n`; helpMsg += Object.keys(commandHandlers) - .map((key) => `${key}:${ENV.I18N.command.help[key.substring(1)]}`) + .map(key => `${key}:${ENV.I18N.command.help[key.substring(1)]}`) .join('\n'); helpMsg += Object.keys(CUSTOM_COMMAND) - .filter((key) => !!CUSTOM_COMMAND_DESCRIPTION[key]) - .map((key) => `${key}:${CUSTOM_COMMAND_DESCRIPTION[key]}`) + .filter(key => !!CUSTOM_COMMAND_DESCRIPTION[key]) + .map(key => `${key}:${CUSTOM_COMMAND_DESCRIPTION[key]}`) .join('\n'); return sendMessageToTelegramWithContext(context)(helpMsg); } @@ -194,21 +193,31 @@ async function commandGetHelp(message, command, subcommand, context) { async function commandCreateNewChatContext(message, command, subcommand, context) { try { await DATABASE.delete(context.SHARE_CONTEXT.chatHistoryKey); - context.CURRENT_CHAT_CONTEXT.reply_markup = JSON.stringify({ - remove_keyboard: true, - selective: true, - }); - if (command === '/new') { - return sendMessageToTelegramWithContext(context)(ENV.I18N.command.new.new_chat_start); + + const isNewCommand = command.startsWith('/new'); + const text = ENV.I18N.command.new.new_chat_start + (isNewCommand ? '' : `(${context.CURRENT_CHAT_CONTEXT.chat_id})`); + + // 非群组消息,显示回复按钮 + if (ENV.SHOW_REPLY_BUTTON && !CONST.GROUP_TYPES.includes(context.SHARE_CONTEXT.chatType)) { + context.CURRENT_CHAT_CONTEXT.reply_markup = { + keyboard: [[{ text: '/new' }, { text: '/redo' }]], + selective: true, + resize_keyboard: true, + one_time_keyboard: false, + }; } else { - return sendMessageToTelegramWithContext(context)(`${ENV.I18N.command.new.new_chat_start}(${context.CURRENT_CHAT_CONTEXT.chat_id})`); + context.CURRENT_CHAT_CONTEXT.reply_markup = { + remove_keyboard: true, + selective: true, + }; } + + return sendMessageToTelegramWithContext(context)(text); } catch (e) { return sendMessageToTelegramWithContext(context)(`ERROR: ${e.message}`); } } - /** * /setenv 用户配置修改 * @param {TelegramMessage} message @@ -301,7 +310,7 @@ async function commandDeleteUserConfig(message, command, subcommand, context) { } try { context.USER_CONFIG[subcommand] = null; - context.USER_CONFIG.DEFINE_KEYS = context.USER_CONFIG.DEFINE_KEYS.filter((key) => key !== subcommand); + context.USER_CONFIG.DEFINE_KEYS = context.USER_CONFIG.DEFINE_KEYS.filter(key => key !== subcommand); await DATABASE.put( context.SHARE_CONTEXT.configStoreKey, JSON.stringify(trimUserConfig(context.USER_CONFIG)), @@ -312,7 +321,6 @@ async function commandDeleteUserConfig(message, command, subcommand, context) { } } - /** * /clearenv 清空用户配置 * @param {TelegramMessage} message @@ -333,7 +341,6 @@ async function commandClearUserConfig(message, command, subcommand, context) { } } - /** * /version 获得更新信息 * @param {TelegramMessage} message @@ -343,7 +350,6 @@ async function commandClearUserConfig(message, command, subcommand, context) { * @returns {Promise} */ async function commandFetchUpdate(message, command, subcommand, context) { - const current = { ts: ENV.BUILD_TIMESTAMP, sha: ENV.BUILD_VERSION, @@ -351,7 +357,7 @@ async function commandFetchUpdate(message, command, subcommand, context) { try { const info = `https://raw.githubusercontent.com/TBXark/ChatGPT-Telegram-Workers/${ENV.UPDATE_BRANCH}/dist/buildinfo.json`; - const online = await fetch(info).then((r) => r.json()); + const online = await fetch(info).then(r => r.json()); const timeFormat = (ts) => { return new Date(ts * 1000).toLocaleString('en-US', {}); }; @@ -365,7 +371,6 @@ async function commandFetchUpdate(message, command, subcommand, context) { } } - /** * /system 获得系统信息 * @param {TelegramMessage} message @@ -375,8 +380,8 @@ async function commandFetchUpdate(message, command, subcommand, context) { * @returns {Promise} */ async function commandSystem(message, command, subcommand, context) { - let chatAgent = loadChatLLM(context)?.name; - let imageAgent = loadImageGen(context)?.name; + const chatAgent = loadChatLLM(context)?.name; + const imageAgent = loadImageGen(context)?.name; const agent = { AI_PROVIDER: chatAgent, AI_IMAGE_PROVIDER: imageAgent, @@ -389,7 +394,7 @@ async function commandSystem(message, command, subcommand, context) { } let msg = `AGENT: ${JSON.stringify(agent, null, 2)}\n`; if (ENV.DEV_MODE) { - const shareCtx = {...context.SHARE_CONTEXT}; + const shareCtx = { ...context.SHARE_CONTEXT }; shareCtx.currentBotToken = '******'; context.USER_CONFIG.OPENAI_API_KEY = ['******']; context.USER_CONFIG.AZURE_API_KEY = '******'; @@ -402,7 +407,7 @@ async function commandSystem(message, command, subcommand, context) { context.USER_CONFIG.COHERE_API_KEY = '******'; context.USER_CONFIG.ANTHROPIC_API_KEY = '******'; const config = trimUserConfig(context.USER_CONFIG); - msg = '
\n' + msg;
+        msg = `
\n${msg}`;
         msg += `USER_CONFIG: ${JSON.stringify(config, null, 2)}\n`;
         msg += `CHAT_CONTEXT: ${JSON.stringify(context.CURRENT_CHAT_CONTEXT, null, 2)}\n`;
         msg += `SHARE_CONTEXT: ${JSON.stringify(shareCtx, null, 2)}\n`;
@@ -441,9 +446,9 @@ async function commandRegenerate(message, command, subcommand, context) {
         if (subcommand) {
             nextText = subcommand;
         }
-        return {history: historyCopy, message: nextText};
+        return { history: historyCopy, message: nextText };
     };
-    return chatWithLLM({message: null}, context, mf);
+    return chatWithLLM({ message: null }, context, mf);
 }
 
 /**
@@ -456,7 +461,7 @@ async function commandRegenerate(message, command, subcommand, context) {
  */
 async function commandEcho(message, command, subcommand, context) {
     let msg = '
';
-    msg += JSON.stringify({message}, null, 2);
+    msg += JSON.stringify({ message }, null, 2);
     msg += '
'; context.CURRENT_CHAT_CONTEXT.parse_mode = 'HTML'; return sendMessageToTelegramWithContext(context)(msg); @@ -482,7 +487,7 @@ export async function handleCommandMessage(message, context) { message.text = CUSTOM_COMMAND[message.text]; } for (const key in commandHandlers) { - if (message.text === key || message.text.startsWith(key + ' ')) { + if (message.text === key || message.text.startsWith(`${key} `)) { const command = commandHandlers[key]; try { // 如果存在权限条件 @@ -490,7 +495,7 @@ export async function handleCommandMessage(message, context) { const roleList = command.needAuth(context.SHARE_CONTEXT.chatType); if (roleList) { // 获取身份并判断 - const chatRole = await getChatRoleWithContext(context)(context.SHARE_CONTEXT.speakerId); + const chatRole = await getChatRoleWithContext(context); if (chatRole === null) { return sendMessageToTelegramWithContext(context)('ERROR: Get chat role failed'); } @@ -548,7 +553,7 @@ export async function bindCommandForTelegram(token) { 'Content-Type': 'application/json', }, body: JSON.stringify({ - commands: scopeCommandMap[scope].map((command) => ({ + commands: scopeCommandMap[scope].map(command => ({ command, description: ENV.I18N.command.help[command.substring(1)] || '', })), @@ -557,9 +562,9 @@ export async function bindCommandForTelegram(token) { }, }), }, - ).then((res) => res.json()); + ).then(res => res.json()); } - return {ok: true, result}; + return { ok: true, result }; } /** diff --git a/src/telegram/message.js b/src/telegram/message.js index 95097d77..ebcca80a 100644 --- a/src/telegram/message.js +++ b/src/telegram/message.js @@ -1,13 +1,13 @@ -import {CONST, DATABASE, ENV} from '../config/env.js'; -import {Context} from '../config/context.js'; -import {getBot, getFileLink, sendMessageToTelegramWithContext} from './telegram.js'; -import {handleCommandMessage} from './command.js'; -import {errorToString} from '../utils/utils.js'; -import {chatWithLLM} from '../agent/llm.js'; +import { CONST, DATABASE, ENV } from '../config/env.js'; +import { Context } from '../config/context.js'; +import { uploadImageToTelegraph } from '../utils/image.js'; +import { errorToString } from '../utils/utils.js'; +import { getBotName, getFileLink, sendMessageToTelegramWithContext } from './telegram.js'; +import { handleCommandMessage } from './command.js'; import '../types/telegram.js'; -import {uploadImageToTelegraph} from '../utils/image.js'; - +import { checkMention, findPhotoFileID } from './utils.js'; +import { chatWithLLM } from './agent.js'; /** * 初始化聊天上下文 @@ -20,7 +20,6 @@ async function msgInitChatContext(message, context) { return null; } - /** * 保存最后一条消息 * @param {TelegramMessage} message @@ -30,7 +29,7 @@ async function msgInitChatContext(message, context) { async function msgSaveLastMessage(message, context) { if (ENV.DEBUG_MODE) { const lastMessageKey = `last_message:${context.SHARE_CONTEXT.chatHistoryKey}`; - await DATABASE.put(lastMessageKey, JSON.stringify(message), {expirationTtl: 3600}); + await DATABASE.put(lastMessageKey, JSON.stringify(message), { expirationTtl: 3600 }); } return null; } @@ -116,14 +115,13 @@ async function msgFilterWhiteList(message, context) { ); } - /** * 过滤不支持的消息 * @param {TelegramMessage} message * @param {ContextType} context * @returns {Promise} */ -// eslint-disable-next-line no-unused-vars +// eslint-disable-next-line unused-imports/no-unused-vars async function msgFilterUnsupportedMessage(message, context) { if (message.text) { return null;// 纯文本消息 @@ -149,8 +147,7 @@ async function msgHandleGroupMessage(message, context) { return null; } - // 处理群组消息,过滤掉AT部分 - let botName = context.SHARE_CONTEXT.currentBotName; + // 处理回复消息, 如果回复的是当前机器人的消息交给下一个中间件处理 if (message.reply_to_message) { if (`${message.reply_to_message.from.id}` === context.SHARE_CONTEXT.currentBotId) { return null; @@ -158,73 +155,35 @@ async function msgHandleGroupMessage(message, context) { context.SHARE_CONTEXT.extraMessageContext = message.reply_to_message; } } + + // 处理群组消息,过滤掉AT部分 + let botName = context.SHARE_CONTEXT.currentBotName; if (!botName) { - const res = await getBot(context.SHARE_CONTEXT.currentBotToken); - context.SHARE_CONTEXT.currentBotName = res.info.bot_name; - botName = res.info.bot_name; + botName = await getBotName(context.SHARE_CONTEXT.currentBotToken); + context.SHARE_CONTEXT.currentBotName = botName; } if (!botName) { throw new Error('Not set bot name'); } - if (!message.entities) { - throw new Error('No entities'); + let isMention = false; + // 检查text中是否有机器人的提及 + if (message.text && message.entities) { + const res = checkMention(message.text, message.entities, botName, context.SHARE_CONTEXT.currentBotId); + isMention = res.isMention; + message.text = res.content.trim(); } - - const {text, caption} = message; - let originContent = text || caption || ''; - if (!originContent) { - throw new Error('Empty message'); - } - - let content = ''; - let offset = 0; - let mentioned = false; - - for (const entity of message.entities) { - switch (entity.type) { - case 'bot_command': - if (!mentioned) { - const mention = originContent.substring( - entity.offset, - entity.offset + entity.length, - ); - if (mention.endsWith(botName)) { - mentioned = true; - } - const cmd = mention - .replaceAll('@' + botName, '') - .replaceAll(botName, '') - .trim(); - content += cmd; - offset = entity.offset + entity.length; - } - break; - case 'mention': - case 'text_mention': - if (!mentioned) { - const mention = originContent.substring( - entity.offset, - entity.offset + entity.length, - ); - if (mention === botName || mention === '@' + botName) { - mentioned = true; - } - } - content += originContent.substring(offset, entity.offset); - offset = entity.offset + entity.length; - break; - } + // 检查caption中是否有机器人的提及 + if (message.caption && message.caption_entities) { + const res = checkMention(message.caption, message.caption_entities, botName, context.SHARE_CONTEXT.currentBotId); + isMention = res.isMention || isMention; + message.caption = res.content.trim(); } - content += originContent.substring(offset, originContent.length); - message.text = content.trim(); - // 未AT机器人的消息不作处理 - if (!mentioned) { - throw new Error('No mentioned'); + if (!isMention) { + throw new Error('Not mention'); } return null; } - /** * 响应命令消息 * @param {TelegramMessage} message @@ -246,25 +205,22 @@ async function msgHandleCommand(message, context) { * @returns {Promise} */ async function msgChatWithLLM(message, context) { - const {text, caption} = message; - let content = text || caption; - if (ENV.EXTRA_MESSAGE_CONTEXT && context.SHARE_CONTEXT.extraMessageContext && context.SHARE_CONTEXT.extraMessageContext.text) { - content = context.SHARE_CONTEXT.extraMessageContext.text + '\n' + text; - } /** * @type {LlmRequestParams} */ - const params = {message: content}; - if (message.photo && message.photo.length > 0) { - let sizeIndex = 0; - if (ENV.TELEGRAM_PHOTO_SIZE_OFFSET >= 0) { - sizeIndex = ENV.TELEGRAM_PHOTO_SIZE_OFFSET; - } else if (ENV.TELEGRAM_PHOTO_SIZE_OFFSET < 0) { - sizeIndex = message.photo.length + ENV.TELEGRAM_PHOTO_SIZE_OFFSET; + const params = { + message: message.text || message.caption || '', + }; + if (ENV.EXTRA_MESSAGE_CONTEXT && context.SHARE_CONTEXT.extraMessageContext) { + const extra = context.SHARE_CONTEXT.extraMessageContext.text || context.SHARE_CONTEXT.extraMessageContext.caption || ''; + if (extra) { + params.message = `${extra}\n${params.message}`; } - sizeIndex = Math.max(0, Math.min(sizeIndex, message.photo.length - 1)); - const fileId = message.photo[sizeIndex].file_id; - let url = await getFileLink(fileId, context.SHARE_CONTEXT.currentBotToken); + } + + if (message.photo && message.photo.length > 0) { + const id = findPhotoFileID(message.photo, ENV.TELEGRAM_PHOTO_SIZE_OFFSET); + let url = await getFileLink(id, context.SHARE_CONTEXT.currentBotToken); if (ENV.TELEGRAPH_ENABLE) { url = await uploadImageToTelegraph(url); } @@ -273,7 +229,6 @@ async function msgChatWithLLM(message, context) { return chatWithLLM(params, context, null); } - /** * 加载真实TG消息 * @param {TelegramWebhookRequest} body @@ -336,7 +291,7 @@ export async function handleMessage(token, body) { } } catch (e) { console.error(e); - return new Response(errorToString(e), {status: 500}); + return new Response(errorToString(e), { status: 500 }); } } return null; diff --git a/src/telegram/telegram.js b/src/telegram/telegram.js index 24c48e7a..a6a868f8 100644 --- a/src/telegram/telegram.js +++ b/src/telegram/telegram.js @@ -1,8 +1,35 @@ -import {DATABASE, ENV} from '../config/env.js'; -import {escape} from '../utils/md2tgmd.js'; +import { ENV } from '../config/env.js'; +import { escape } from '../utils/md2tgmd.js'; import '../types/context.js'; import '../types/telegram.js'; +// Telegram函数 +// 1. 需要判断请求状态的返回Promise +// 2. 无需判断请求结果的返回Promise +// 3. 有具体数据处理需求的返回具体数据类型的Promise +// 4. 默认返回Promise + +/** + * @param {string} method + * @param {string} token + * @param {object} body + * @returns {Promise} + */ +async function sendTelegramRequest(method, token, body = null) { + const headers = {}; + if (!(body instanceof FormData)) { + headers['Content-Type'] = 'application/json'; + } + return fetch( + `${ENV.TELEGRAM_API_DOMAIN}/bot${token}/${method}`, + { + method: 'POST', + headers, + body: body && ((body instanceof FormData) ? body : JSON.stringify(body)), + }, + ); +} + /** * @param {string} message * @param {string} token @@ -22,19 +49,9 @@ async function sendMessage(message, token, context) { if (context?.message_id) { method = 'editMessageText'; } - return await fetch( - `${ENV.TELEGRAM_API_DOMAIN}/bot${token}/${method}`, - { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify(body), - }, - ); + return sendTelegramRequest(method, token, body); } - /** * @param {string} message * @param {string} token @@ -71,43 +88,13 @@ export async function sendMessageToTelegram(message, token, context) { chatContext.message_id = null; } lastMessageResponse = await sendMessage(msg, token, chatContext); + if (lastMessageResponse.status !== 200) { + break; + } } return lastMessageResponse; } -/** - * @param {ContextType} context - * @returns {function(string): Promise} - */ -export function sendMessageToTelegramWithContext(context) { - return async (message) => { - return sendMessageToTelegram(message, context.SHARE_CONTEXT.currentBotToken, context.CURRENT_CHAT_CONTEXT); - }; -} - -/** - * @param {ContextType} context - * @returns {function(string): Promise} - */ -export function deleteMessageFromTelegramWithContext(context) { - return async (messageId) => { - return await fetch( - `${ENV.TELEGRAM_API_DOMAIN}/bot${context.SHARE_CONTEXT.currentBotToken}/deleteMessage`, - { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify({ - chat_id: context.CURRENT_CHAT_CONTEXT.chat_id, - message_id: messageId, - }), - }, - ); - }; -} - - /** * 发送图片消息到Telegram * @param {string | Blob} photo @@ -116,11 +103,8 @@ export function deleteMessageFromTelegramWithContext(context) { * @returns {Promise} */ export async function sendPhotoToTelegram(photo, token, context) { - const url = `${ENV.TELEGRAM_API_DOMAIN}/bot${token}/sendPhoto`; - let body; - const headers = {}; if (typeof photo === 'string') { - body = { + const body = { photo, }; for (const key of Object.keys(context)) { @@ -128,262 +112,128 @@ export async function sendPhotoToTelegram(photo, token, context) { body[key] = context[key]; } } - body = JSON.stringify(body); - headers['Content-Type'] = 'application/json'; + return sendTelegramRequest('sendPhoto', token, body); } else { - body = new FormData(); + const body = new FormData(); body.append('photo', photo, 'photo.png'); for (const key of Object.keys(context)) { if (context[key] !== undefined && context[key] !== null) { body.append(key, `${context[key]}`); } } + return sendTelegramRequest('sendPhoto', token, body); } - return await fetch(url, { - method: 'POST', - headers, - body, - }, - ); -} - - -/** - * @param {ContextType} context - * @returns {function(string): Promise} - */ -export function sendPhotoToTelegramWithContext(context) { - return (url) => { - return sendPhotoToTelegram(url, context.SHARE_CONTEXT.currentBotToken, context.CURRENT_CHAT_CONTEXT); - }; } - /** * 发送聊天动作到TG * @param {string} action * @param {string} token * @param {string | number} chatId - * @returns {Promise} + * @returns {Promise} */ export async function sendChatActionToTelegram(action, token, chatId) { - return await fetch( - `${ENV.TELEGRAM_API_DOMAIN}/bot${token}/sendChatAction`, - { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify({ - chat_id: chatId, - action, - }), - }, - ).then((res) => res.json()); -} - -/** - * @param {ContextType} context - * @returns {function(string): Promise} - */ -export function sendChatActionToTelegramWithContext(context) { - return (action) => { - return sendChatActionToTelegram(action, context.SHARE_CONTEXT.currentBotToken, context.CURRENT_CHAT_CONTEXT.chat_id); - }; + return sendTelegramRequest('sendChatAction', token, { + chat_id: chatId, + action, + }); } /** + * 绑定WebHook * @param {string} token * @param {string} url - * @returns {Promise} + * @returns {Promise} */ export async function bindTelegramWebHook(token, url) { - return await fetch( - `${ENV.TELEGRAM_API_DOMAIN}/bot${token}/setWebhook`, - { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify({ - url, - }), - }, - ).then((res) => res.json()); + return sendTelegramRequest('setWebhook', token, { url }); } /** + * 删除WebHook * @param {string} token - * @returns {Promise} + * @returns {Promise} */ export async function deleteTelegramWebHook(token) { - return await fetch( - `${ENV.TELEGRAM_API_DOMAIN}/bot${token}/deleteWebhook`, - { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - }, - ).then((res) => res.json()); + return sendTelegramRequest('deleteWebhook', token); } /** + * 获取更新 * @param {string} token * @param {number} offset - * @returns {Promise} + * @returns {Promise<{result: TelegramWebhookRequest[]}>} */ -export async function getUpdates(token, offset) { - return await fetch( - `${ENV.TELEGRAM_API_DOMAIN}/bot${token}/getUpdates`, - { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify({offset}), - }, - ).then((res) => res.json()); +export async function getTelegramUpdates(token, offset) { + return sendTelegramRequest('getUpdates', token, { offset }) + .then(res => res.json()); } /** - * 判断是否为群组管理员 - * @param {string | number} id - * @param {string} groupAdminKey + * 获取群组管理员信息 * @param {string | number} chatId * @param {string} token - * @returns {Promise} + * @returns {Promise<{result: object[]}>} */ -export async function getChatRole(id, groupAdminKey, chatId, token) { - let groupAdmin; - try { - groupAdmin = JSON.parse(await DATABASE.get(groupAdminKey)); - } catch (e) { - console.error(e); - return e.message; - } - if (!groupAdmin || !Array.isArray(groupAdmin) || groupAdmin.length === 0) { - const administers = await getChatAdminister(chatId, token); - if (administers == null) { - return null; - } - groupAdmin = administers; - // 缓存120s - await DATABASE.put( - groupAdminKey, - JSON.stringify(groupAdmin), - {expiration: (Date.now() / 1000) + 120}, - ); - } - for (let i = 0; i < groupAdmin.length; i++) { - const user = groupAdmin[i]; - if (user.user.id === id) { - return user.status; - } - } - return 'member'; +export async function getChatAdministrators(chatId, token) { + return sendTelegramRequest('getChatAdministrators', token, { chat_id: chatId }) + .then(res => res.json()).catch(() => null); } /** - * 判断是否为群组管理员 - * @param {ContextType} context - * @returns {function(*): Promise} + * 获取机器人名称 + * @param {string} token + * @returns {Promise} */ -export function getChatRoleWithContext(context) { - return (id) => { - return getChatRole(id, context.SHARE_CONTEXT.groupAdminKey, context.CURRENT_CHAT_CONTEXT.chat_id, context.SHARE_CONTEXT.currentBotToken); - }; +export async function getBotName(token) { + const { result: { username } } = await sendTelegramRequest('getMe', token) + .then(res => res.json()); + return username; } /** - * 获取群组管理员信息 - * @param {string | number} chatId + * 获取文件链接 + * @param {string} fileId * @param {string} token - * @returns {Promise} + * @returns {Promise} */ -export async function getChatAdminister(chatId, token) { +export async function getFileLink(fileId, token) { try { - const resp = await fetch( - `${ENV.TELEGRAM_API_DOMAIN}/bot${ - token - }/getChatAdministrators`, - { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify({chat_id: chatId}), - }, - ).then((res) => res.json()); - if (resp.ok) { - return resp.result; - } + const { result: { file_path } } = await sendTelegramRequest('getFile', token, { file_id: fileId }) + .then(res => res.json()); + return `https://api.telegram.org/file/bot${token}/${file_path}`; } catch (e) { console.error(e); - return null; } + return ''; } -// 获取机器人信息 - /** - * @typedef {object} BotInfo - * @property {boolean} ok - * @property {object} info - * @property {string} info.name - * @property {string} info.bot_name - * @property {boolean} info.can_join_groups - * @property {boolean} info.can_read_all_group_messages + * @param {ContextType} context + * @returns {function(string): Promise} */ +export function sendMessageToTelegramWithContext(context) { + return async (message) => { + return sendMessageToTelegram(message, context.SHARE_CONTEXT.currentBotToken, context.CURRENT_CHAT_CONTEXT); + }; +} /** - * @param {string} token - * @returns {Promise} + * @param {ContextType} context + * @returns {function(string): Promise} */ -export async function getBot(token) { - const resp = await fetch( - `${ENV.TELEGRAM_API_DOMAIN}/bot${token}/getMe`, - { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - }, - ).then((res) => res.json()); - if (resp.ok) { - return { - ok: true, - info: { - name: resp.result.first_name, - bot_name: resp.result.username, - can_join_groups: resp.result.can_join_groups, - can_read_all_group_messages: resp.result.can_read_all_group_messages, - }, - }; - } else { - return resp; - } +export function sendPhotoToTelegramWithContext(context) { + return (url) => { + return sendPhotoToTelegram(url, context.SHARE_CONTEXT.currentBotToken, context.CURRENT_CHAT_CONTEXT); + }; } /** - * 获取文件链接 - * @param {string} fileId - * @param {string} token - * @returns {Promise} + * @param {ContextType} context + * @returns {function(string): Promise} */ -export async function getFileLink(fileId, token) { - const resp = await fetch( - `${ENV.TELEGRAM_API_DOMAIN}/bot${token}/getFile`, - { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify({file_id: fileId}), - }, - ).then((res) => res.json()); - if (resp.ok && resp.result.file_path) { - return `https://api.telegram.org/file/bot${token}/${resp.result.file_path}`; - } - return ''; +export function sendChatActionToTelegramWithContext(context) { + return (action) => { + return sendChatActionToTelegram(action, context.SHARE_CONTEXT.currentBotToken, context.CURRENT_CHAT_CONTEXT.chat_id); + }; } diff --git a/src/telegram/utils.js b/src/telegram/utils.js new file mode 100644 index 00000000..b0d6b3c7 --- /dev/null +++ b/src/telegram/utils.js @@ -0,0 +1,106 @@ +import '../types/context.js'; +import { DATABASE } from '../config/env.js'; +import { getChatAdministrators } from './telegram.js'; + +/** + * @param {string} content + * @param {TelegramMessageEntity[]} entities + * @param {string} botName + * @param {TelegramID} botId + * @returns {{isMention: boolean, content}} + */ +export function checkMention(content, entities, botName, botId) { + let isMention = false; + for (const entity of entities) { + const entityStr = content.slice(entity.offset, entity.offset + entity.length); + switch (entity.type) { + case 'mention': // "mention"适用于有用户名的普通用户 + if (entityStr === `@${botName}`) { + isMention = true; + content = content.slice(0, entity.offset) + content.slice(entity.offset + entity.length); + } + break; + case 'text_mention': // "text_mention"适用于没有用户名的用户或需要通过ID提及用户的情况 + if (`${entity.user.id}` === `${botId}`) { + isMention = true; + content = content.slice(0, entity.offset) + content.slice(entity.offset + entity.length); + } + break; + case 'bot_command': // "bot_command"适用于命令 + if (entityStr.endsWith(`@${botName}`)) { + isMention = true; + const newEntityStr = entityStr.replace(`@${botName}`, ''); + content = content.slice(0, entity.offset) + newEntityStr + content.slice(entity.offset + entity.length); + } + break; + default: + break; + } + } + return { + isMention, + content, + }; +} + +/** + * @param {TelegramPhoto[]} photos + * @param {number} offset + * @returns {string|*} + */ +export function findPhotoFileID(photos, offset) { + let sizeIndex = 0; + if (offset >= 0) { + sizeIndex = offset; + } else if (offset < 0) { + sizeIndex = photos.length + offset; + } + sizeIndex = Math.max(0, Math.min(sizeIndex, photos.length - 1)); + return photos[sizeIndex].file_id; +}; + +/** + * 获取用户在群中的角色 + * @param {ContextType} context + * @returns {Promise} + */ +export async function getChatRoleWithContext(context) { + const { + chatId, + speakerId, + groupAdminKey, + currentBotToken: token, + allMemberAreAdmin, + } = context.SHARE_CONTEXT; + + if (allMemberAreAdmin) { + return 'administrator'; + } + + let groupAdmin; + try { + groupAdmin = JSON.parse(await DATABASE.get(groupAdminKey)); + } catch (e) { + console.error(e); + } + if (!groupAdmin || !Array.isArray(groupAdmin) || groupAdmin.length === 0) { + const { result } = await getChatAdministrators(chatId, token); + if (result == null) { + return null; + } + groupAdmin = result; + // 缓存120s + await DATABASE.put( + groupAdminKey, + JSON.stringify(groupAdmin), + { expiration: (Date.now() / 1000) + 120 }, + ); + } + for (let i = 0; i < groupAdmin.length; i++) { + const user = groupAdmin[i]; + if (`${user.user.id}` === `${speakerId}`) { + return user.status; + } + } + return 'member'; +} diff --git a/src/types/agent.js b/src/types/agent.js index 00aded0b..005875df 100644 --- a/src/types/agent.js +++ b/src/types/agent.js @@ -57,3 +57,10 @@ * @property {string} content * @property {string[]} [images] - 图片 */ + +/** + * @typedef {object} LlmModifierResult + * @property {HistoryItem[]} history + * @property {string} message + * @typedef {function(HistoryItem[], string): LlmModifierResult} LlmModifier + */ diff --git a/src/types/context.js b/src/types/context.js index 311c3a0e..91b0cb4d 100644 --- a/src/types/context.js +++ b/src/types/context.js @@ -49,7 +49,8 @@ * @property {?string} chatType - 会话场景, private/group/supergroup 等, 来源 message.chat.type * @property {?TelegramID} chatId - 会话 id, private 场景为发言人 id, group/supergroup 场景为群组 id * @property {?TelegramID} speakerId - 发言人 id - * @property {?object} extraMessageContext - 额外消息上下文 + * @property {?TelegramMessage} extraMessageContext - 额外消息上下文 + * @property {boolean} allMemberAreAdmin - 是否所有成员都是管理员 */ /** @@ -71,3 +72,15 @@ * @property {ShareContextType} SHARE_CONTEXT - 共享上下文 * @property {function(TelegramMessage): Promise} initContext */ + +/** + * @typedef {object} APIGuard + * @property {(request: Request) => Promise} fetch + */ + +/** + * @typedef {object} KVNamespace + * @property {(key: string) => Promise} get + * @property {(key: string, value: any, options?: {expirationTtl?: number, expiration?: number}) => Promise} put + * @property {(key: string) => Promise} delete + */ diff --git a/src/types/telegram.js b/src/types/telegram.js index f334d964..199b88a8 100644 --- a/src/types/telegram.js +++ b/src/types/telegram.js @@ -2,7 +2,6 @@ * @typedef {(string|number)} TelegramID */ - /** * @typedef {object} TelegramBaseFile * @property {string} file_id - Unique identifier for this file. @@ -16,7 +15,6 @@ * @property {string} mime_type - Optional. MIME type of the file as defined by sender. */ - /** * @typedef {object} TelegramUser * @property {TelegramID} id - The ID of the user. @@ -32,6 +30,7 @@ * @property {TelegramID} id - The ID of the chat. * @property {string} type - The type of the chat. * @property {boolean} is_forum - True, if the chat is a forum. + * @property {boolean} all_members_are_administrators - True, if all members of the chat are administrators. */ /** @@ -54,6 +53,7 @@ * @property {TelegramPhoto[]} [photo] - An array of photos. * @property {TelegramVoice} [voice] - The voice message. * @property {TelegramMessageEntity[]} [entities] - An array of message entities. + * @property {TelegramMessageEntity[]} [caption_entities] - An array of caption entities. * @property {TelegramMessage} [reply_to_message] - The message that this message is a reply to. * @property {boolean} is_topic_message - True, if the message is a topic message. * @property {string|number} message_thread_id - The message thread ID. diff --git a/src/utils/cache.js b/src/utils/cache.js index 666e6dc1..ab3e32c0 100644 --- a/src/utils/cache.js +++ b/src/utils/cache.js @@ -1,6 +1,8 @@ /** * A simple cache implementation. - * 主要作用是防止本地部署使用base64图片时,重复请求相同的图片 + * 主要作用 + * 1. 防止本地部署使用base64图片时,重复请求相同的图片 + * 2. 上传图片telegraph后又使用base64图片时,重复请求相同的图片 */ export class Cache { constructor() { diff --git a/src/utils/image.js b/src/utils/image.js index a5f68298..60dac09a 100644 --- a/src/utils/image.js +++ b/src/utils/image.js @@ -1,4 +1,4 @@ -import {Cache} from './cache.js'; +import { Cache } from './cache.js'; const IMAGE_CACHE = new Cache(); @@ -11,7 +11,7 @@ async function fetchImage(url) { return IMAGE_CACHE.get(url); } return fetch(url) - .then((resp) => resp.blob()) + .then(resp => resp.blob()) .then((blob) => { IMAGE_CACHE.set(url, blob); return blob; @@ -34,10 +34,10 @@ export async function uploadImageToTelegraph(url) { method: 'POST', body: formData, }); - let [{src}] = await resp.json(); + let [{ src }] = await resp.json(); src = `https://telegra.ph${src}`; IMAGE_CACHE.set(src, raw); - + return src; } @@ -47,17 +47,17 @@ export async function uploadImageToTelegraph(url) { */ async function urlToBase64String(url) { try { - const {Buffer} = await import('node:buffer'); + const { Buffer } = await import('node:buffer'); return fetchImage(url) - .then((blob) => blob.arrayBuffer()) - .then((buffer) => Buffer.from(buffer).toString('base64')); + .then(blob => blob.arrayBuffer()) + .then(buffer => Buffer.from(buffer).toString('base64')); } catch { // 非原生base64编码速度太慢不适合在workers中使用 // 在wrangler.toml中添加 Node.js 选项启用nodejs兼容 // compatibility_flags = [ "nodejs_compat" ] return fetchImage(url) - .then((blob) => blob.arrayBuffer()) - .then((buffer) => btoa(String.fromCharCode.apply(null, new Uint8Array(buffer)))); + .then(blob => blob.arrayBuffer()) + .then(buffer => btoa(String.fromCharCode.apply(null, new Uint8Array(buffer)))); } } @@ -68,16 +68,16 @@ async function urlToBase64String(url) { function getImageFormatFromBase64(base64String) { const firstChar = base64String.charAt(0); switch (firstChar) { - case '/': - return 'jpeg'; - case 'i': - return 'png'; - case 'R': - return 'gif'; - case 'U': - return 'webp'; - default: - throw new Error('Unsupported image format'); + case '/': + return 'jpeg'; + case 'i': + return 'png'; + case 'R': + return 'gif'; + case 'U': + return 'webp'; + default: + throw new Error('Unsupported image format'); } } diff --git a/src/utils/md2tgmd.js b/src/utils/md2tgmd.js index 3b766fa3..48c37b4d 100644 --- a/src/utils/md2tgmd.js +++ b/src/utils/md2tgmd.js @@ -1,5 +1,6 @@ -/* eslint-disable no-useless-escape*/ -const escapeChars = /([\_\*\[\]\(\)\\\~\`\>\#\+\-\=\|\{\}\.\!])/g; +/* eslint-disable regexp/no-super-linear-backtracking */ +/* eslint-disable regexp/no-unused-capturing-group */ +const escapeChars = /([_*[\]()\\~`>#+\-=|{}.!])/g; /** * 分割代码块文本 适配嵌套代码块 @@ -34,13 +35,12 @@ export function escape(text) { } } if (stack.length) { - const last = lines.slice(stack[0]).join('\n') + '\n```'; + const last = `${lines.slice(stack[0]).join('\n')}\n\`\`\``; result.push(handleEscape(last, 'code')); } return result.join('\n'); } - /** * 处理转义 * @param {string} text @@ -61,8 +61,8 @@ function handleEscape(text, type = 'text') { .replace(/\\~(.*?[^\\])\\~/g, '~$1~') // strikethrough .replace(/\\\|\\\|(.*?[^\\])\\\|\\\|/g, '||$1||') // spoiler .replace(/\\\[([^\]]+?)\\\]\\\((.+?)\\\)/g, '[$1]($2)') // url - .replace(/\\\`(.*?[^\\])\\\`/g, '`$1`') // inline code - .replace(/\\\\\\([\_\*\[\]\(\)\\\~\`\>\#\+\-\=\|\{\}\.\!])/g, '\\$1') // restore duplicate escapes + .replace(/\\`(.*?[^\\])\\`/g, '`$1`') // inline code + .replace(/\\\\\\([_*[\]()\\~`>#+\-=|{}.!])/g, '\\$1') // restore duplicate escapes .replace(/^(\s*)\\(>.+\s*)$/gm, '$1$2') // > .replace(/^(\s*)\\-\s*(.+)$/gm, '$1• $2') // - .replace(/^((\\#){1,3}\s)(.+)/gm, '$1*$3*'); // number sign @@ -74,7 +74,7 @@ function handleEscape(text, type = 'text') { } text = text .trimEnd() - .replace(/([\\\`])/g, '\\$1') + .replace(/([\\`])/g, '\\$1') .replace(/^\\`\\`\\`([\s\S]+)\\`\\`\\`$/g, '```$1```'); // code block } return text; diff --git a/src/utils/router.js b/src/utils/router.js index e0156799..6d160868 100644 --- a/src/utils/router.js +++ b/src/utils/router.js @@ -3,7 +3,7 @@ * 基于itty-router的路由实现,使用更加可读的方式重写 */ export class Router { - constructor({base = '', routes = [], ...other} = {}) { + constructor({ base = '', routes = [], ...other } = {}) { this.routes = routes; this.base = base; Object.assign(this, other); @@ -56,12 +56,14 @@ export class Router { request.query = this.parseQueryParams(url.searchParams); for (const [method, regex, handlers, path] of this.routes) { let match = null; + // eslint-disable-next-line no-cond-assign if ((method === reqMethod || method === 'ALL') && (match = url.pathname.match(regex))) { request.params = match?.groups || {}; request.route = path; for (const handler of handlers) { const response = await handler(request.proxy ?? request, ...args); - if (response != null) return response; + if (response != null) + return response; } } } @@ -151,4 +153,4 @@ export class Router { all(path, ...handlers) { return this.route('ALL', path, ...handlers); } -} \ No newline at end of file +} diff --git a/src/utils/utils.js b/src/utils/utils.js index 2f20c8d1..8a614b65 100644 --- a/src/utils/utils.js +++ b/src/utils/utils.js @@ -61,14 +61,13 @@ export function errorToString(e) { }); } - /** * @param {Response} resp * @returns {Response} */ export function makeResponse200(resp) { if (resp === null) { - return new Response('NOT HANDLED', {status: 200}); + return new Response('NOT HANDLED', { status: 200 }); } if (resp.status === 200) { return resp; @@ -83,4 +82,3 @@ export function makeResponse200(resp) { }); } } - diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 00000000..fcfacad0 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,10 @@ +{ + "compilerOptions": { + "allowJs": true, + "declaration": true, + "declarationMap": true, + "emitDeclarationOnly": true, + "outDir": "dist" + }, + "include": ["src/**/*", "main.js"] +} diff --git a/vite.config.js b/vite.config.js new file mode 100644 index 00000000..a45e8dac --- /dev/null +++ b/vite.config.js @@ -0,0 +1,48 @@ +import { execSync } from 'node:child_process'; +import * as fs from 'node:fs/promises'; +import { defineConfig } from 'vite'; +import { nodeResolve } from '@rollup/plugin-node-resolve'; +import cleanup from 'rollup-plugin-cleanup'; + +const TIMESTAMP_FILE = './dist/timestamp'; +const BUILD_INFO_JSON = './dist/buildinfo.json'; + +const COMMIT_HASH = execSync('git rev-parse --short HEAD').toString().trim(); +const TIMESTAMP = Math.floor(Date.now() / 1000); + +export default defineConfig({ + plugins: [ + nodeResolve({ + preferBuiltins: true, + }), + cleanup({ + comments: 'none', + }), + { + name: 'buildInfo', + async closeBundle() { + await fs.writeFile(TIMESTAMP_FILE, TIMESTAMP.toString()); + await fs.writeFile(BUILD_INFO_JSON, JSON.stringify({ + sha: COMMIT_HASH, + timestamp: TIMESTAMP, + })); + }, + }, + ], + build: { + target: 'esnext', + lib: { + entry: './main.js', + fileName: 'index', + formats: ['es'], + }, + minify: false, + rollupOptions: { + external: ['node:buffer'], + }, + }, + define: { + __BUILD_VERSION__: JSON.stringify(COMMIT_HASH), + __BUILD_TIMESTAMP__: TIMESTAMP.toString(), + }, +}); diff --git a/wrangler-example.toml b/wrangler-example.toml index 5d79de91..9e4463b6 100644 --- a/wrangler-example.toml +++ b/wrangler-example.toml @@ -105,7 +105,7 @@ AI_IMAGE_PROVIDER = 'auto' # OpenAI API Key OPENAI_API_KEY = 'SK-1,SK-2' ## OpenAI的模型名称 -#OPENAI_CHAT_MODEL = 'gpt-3.5-turbo' +#OPENAI_CHAT_MODEL = 'gpt-4o-mini' ## OpenAI API BASE `` #OPENAI_API_BASE = 'https://api.openai.com/v1' ## OpenAI API Extra Params diff --git a/yarn.lock b/yarn.lock index 61812d0a..4a38e8b9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,6 +2,99 @@ # yarn lockfile v1 +"@antfu/eslint-config@^2.25.1": + version "2.25.1" + resolved "https://registry.yarnpkg.com/@antfu/eslint-config/-/eslint-config-2.25.1.tgz#f0ef773b6ef2f6b11b903173afe4624a93ec17b8" + integrity sha512-aWnq8kNL4MM3RjXJtMvCGhzzXiukbNn4oXT3RFVgQ2KkBmryrlCos8HW7zfF27gggSqrMX8p75wHk8zM/Mo9+Q== + dependencies: + "@antfu/install-pkg" "^0.3.3" + "@clack/prompts" "^0.7.0" + "@stylistic/eslint-plugin" "^2.6.2" + "@typescript-eslint/eslint-plugin" "^8.0.1" + "@typescript-eslint/parser" "^8.0.1" + "@vitest/eslint-plugin" "^1.0.0" + eslint-config-flat-gitignore "^0.1.8" + eslint-flat-config-utils "^0.3.0" + eslint-merge-processors "^0.1.0" + eslint-plugin-antfu "^2.3.4" + eslint-plugin-command "^0.2.3" + eslint-plugin-eslint-comments "^3.2.0" + eslint-plugin-import-x "^3.1.0" + eslint-plugin-jsdoc "^50.0.0" + eslint-plugin-jsonc "^2.16.0" + eslint-plugin-markdown "^5.1.0" + eslint-plugin-n "^17.10.2" + eslint-plugin-no-only-tests "^3.1.0" + eslint-plugin-perfectionist "^3.1.3" + eslint-plugin-regexp "^2.6.0" + eslint-plugin-toml "^0.11.1" + eslint-plugin-unicorn "^55.0.0" + eslint-plugin-unused-imports "^4.1.3" + eslint-plugin-vue "^9.27.0" + eslint-plugin-yml "^1.14.0" + eslint-processor-vue-blocks "^0.1.2" + globals "^15.9.0" + jsonc-eslint-parser "^2.4.0" + local-pkg "^0.5.0" + parse-gitignore "^2.0.0" + picocolors "^1.0.1" + toml-eslint-parser "^0.10.0" + vue-eslint-parser "^9.4.3" + yaml-eslint-parser "^1.2.3" + yargs "^17.7.2" + +"@antfu/install-pkg@^0.3.3": + version "0.3.4" + resolved "https://registry.yarnpkg.com/@antfu/install-pkg/-/install-pkg-0.3.4.tgz#900a57614cb92ad2a1154eccec3891e8ed2b81b9" + integrity sha512-xmYFuDsaS5hlqVSJYVIzBGnUBhZR6NpwelQx/qr9wHTenqMF14YhsexWADcFyMCKwf/vApnvLTfEEnaOBvo5SA== + dependencies: + tinyexec "^0.1.4" + +"@antfu/utils@^0.7.10": + version "0.7.10" + resolved "https://registry.yarnpkg.com/@antfu/utils/-/utils-0.7.10.tgz#ae829f170158e297a9b6a28f161a8e487d00814d" + integrity sha512-+562v9k4aI80m1+VuMHehNJWLOFjBnXn3tdOitzD0il5b7smkSBal4+a3oKiQTbrwMmN/TBUMDvbdoWDehgOww== + +"@babel/code-frame@^7.0.0": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.24.7.tgz#882fd9e09e8ee324e496bd040401c6f046ef4465" + integrity sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA== + dependencies: + "@babel/highlight" "^7.24.7" + picocolors "^1.0.0" + +"@babel/helper-validator-identifier@^7.24.5", "@babel/helper-validator-identifier@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz#75b889cfaf9e35c2aaf42cf0d72c8e91719251db" + integrity sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w== + +"@babel/highlight@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.24.7.tgz#a05ab1df134b286558aae0ed41e6c5f731bf409d" + integrity sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw== + dependencies: + "@babel/helper-validator-identifier" "^7.24.7" + chalk "^2.4.2" + js-tokens "^4.0.0" + picocolors "^1.0.0" + +"@clack/core@^0.3.3": + version "0.3.4" + resolved "https://registry.yarnpkg.com/@clack/core/-/core-0.3.4.tgz#375e82fc8fe46650b37cab2f2ea8752c6b7f0450" + integrity sha512-H4hxZDXgHtWTwV3RAVenqcC4VbJZNegbBjlPvzOzCouXtS2y3sDvlO3IsbrPNWuLWPPlYVYPghQdSF64683Ldw== + dependencies: + picocolors "^1.0.0" + sisteransi "^1.0.5" + +"@clack/prompts@^0.7.0": + version "0.7.0" + resolved "https://registry.yarnpkg.com/@clack/prompts/-/prompts-0.7.0.tgz#6aaef48ea803d91cce12bc80811cfcb8de2e75ea" + integrity sha512-0MhX9/B4iL6Re04jPrttDm+BsP8y6mS7byuv0BvXgdXhbV5PdlsHt55dvNsuBCPZ7xq1oTAOOuotR9NFbQyMSA== + dependencies: + "@clack/core" "^0.3.3" + picocolors "^1.0.0" + sisteransi "^1.0.5" + "@cloudflare/kv-asset-handler@0.3.4": version "0.3.4" resolved "https://registry.yarnpkg.com/@cloudflare/kv-asset-handler/-/kv-asset-handler-0.3.4.tgz#5cc152847c8ae4d280ec5d7f4f6ba8c976b585c3" @@ -46,14 +139,41 @@ dependencies: "@jridgewell/trace-mapping" "0.3.9" -"@es-joy/jsdoccomment@~0.46.0": - version "0.46.0" - resolved "https://registry.yarnpkg.com/@es-joy/jsdoccomment/-/jsdoccomment-0.46.0.tgz#47a2ee4bfc0081f252e058272dfab680aaed464d" - integrity sha512-C3Axuq1xd/9VqFZpW4YAzOx5O9q/LP46uIQy/iNDpHG3fmPa6TBtvfglMCs3RBiBxAIi0Go97r8+jvTt55XMyQ== +"@dprint/formatter@^0.3.0": + version "0.3.0" + resolved "https://registry.yarnpkg.com/@dprint/formatter/-/formatter-0.3.0.tgz#e374398c8e8d7dbf50e8208c87af44a66de0cb2e" + integrity sha512-N9fxCxbaBOrDkteSOzaCqwWjso5iAe+WJPsHC021JfHNj2ThInPNEF13ORDKta3llq5D1TlclODCvOvipH7bWQ== + +"@dprint/markdown@^0.17.1": + version "0.17.2" + resolved "https://registry.yarnpkg.com/@dprint/markdown/-/markdown-0.17.2.tgz#5c867c825d976bf63dbc6fbc57decf04d71c0193" + integrity sha512-isz8iOgA9RezXb0bkHWfJZBp59j1wKUS/lpUTNL8bBelp1Ng1/NPUPG3/WscoSlI5VO+1rSN/itOOjPAfM4Jhg== + +"@dprint/toml@^0.6.2": + version "0.6.2" + resolved "https://registry.yarnpkg.com/@dprint/toml/-/toml-0.6.2.tgz#54c0b8094c6a8639e62314a300e4c88831e6254d" + integrity sha512-Mk5unEANsL/L+WHYU3NpDXt1ARU5bNU5k5OZELxaJodDycKG6RoRnSlZXpW6+7UN2PSnETAFVUdKrh937ZwtHA== + +"@es-joy/jsdoccomment@^0.43.0": + version "0.43.1" + resolved "https://registry.yarnpkg.com/@es-joy/jsdoccomment/-/jsdoccomment-0.43.1.tgz#4b1979b7b4ff8b596fb19a3aa696a438e44608d7" + integrity sha512-I238eDtOolvCuvtxrnqtlBaw0BwdQuYqK7eA6XIonicMdOOOb75mqdIzkGDUbS04+1Di007rgm9snFRNeVrOog== + dependencies: + "@types/eslint" "^8.56.5" + "@types/estree" "^1.0.5" + "@typescript-eslint/types" "^7.2.0" + comment-parser "1.4.1" + esquery "^1.5.0" + jsdoc-type-pratt-parser "~4.0.0" + +"@es-joy/jsdoccomment@~0.48.0": + version "0.48.0" + resolved "https://registry.yarnpkg.com/@es-joy/jsdoccomment/-/jsdoccomment-0.48.0.tgz#5d9dc1a295cf5d1ed224dffafb4800d5c7206c27" + integrity sha512-G6QUWIcC+KvSwXNsJyDTHvqUdNoAVJPPgkc3+Uk4WBKqZvoXhlvazOgm9aL0HwihJLQf0l+tOE2UFzXBqCqgDw== dependencies: comment-parser "1.4.1" esquery "^1.6.0" - jsdoc-type-pratt-parser "~4.0.0" + jsdoc-type-pratt-parser "~4.1.0" "@esbuild-plugins/node-globals-polyfill@^0.2.3": version "0.2.3" @@ -68,244 +188,239 @@ escape-string-regexp "^4.0.0" rollup-plugin-node-polyfills "^0.2.1" -"@esbuild/aix-ppc64@0.23.0": - version "0.23.0" - resolved "https://registry.yarnpkg.com/@esbuild/aix-ppc64/-/aix-ppc64-0.23.0.tgz#145b74d5e4a5223489cabdc238d8dad902df5259" - integrity sha512-3sG8Zwa5fMcA9bgqB8AfWPQ+HFke6uD3h1s3RIwUNK8EG7a4buxvuFTs3j1IMs2NXAk9F30C/FF4vxRgQCcmoQ== +"@esbuild/aix-ppc64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz#c7184a326533fcdf1b8ee0733e21c713b975575f" + integrity sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ== "@esbuild/android-arm64@0.17.19": version "0.17.19" resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.17.19.tgz#bafb75234a5d3d1b690e7c2956a599345e84a2fd" integrity sha512-KBMWvEZooR7+kzY0BtbTQn0OAYY7CsiydT63pVEaPtVYF0hXbUaOyZog37DKxK7NF3XacBJOpYT4adIJh+avxA== -"@esbuild/android-arm64@0.23.0": - version "0.23.0" - resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.23.0.tgz#453bbe079fc8d364d4c5545069e8260228559832" - integrity sha512-EuHFUYkAVfU4qBdyivULuu03FhJO4IJN9PGuABGrFy4vUuzk91P2d+npxHcFdpUnfYKy0PuV+n6bKIpHOB3prQ== +"@esbuild/android-arm64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz#09d9b4357780da9ea3a7dfb833a1f1ff439b4052" + integrity sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A== "@esbuild/android-arm@0.17.19": version "0.17.19" resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.17.19.tgz#5898f7832c2298bc7d0ab53701c57beb74d78b4d" integrity sha512-rIKddzqhmav7MSmoFCmDIb6e2W57geRsM94gV2l38fzhXMwq7hZoClug9USI2pFRGL06f4IOPHHpFNOkWieR8A== -"@esbuild/android-arm@0.23.0": - version "0.23.0" - resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.23.0.tgz#26c806853aa4a4f7e683e519cd9d68e201ebcf99" - integrity sha512-+KuOHTKKyIKgEEqKbGTK8W7mPp+hKinbMBeEnNzjJGyFcWsfrXjSTNluJHCY1RqhxFurdD8uNXQDei7qDlR6+g== +"@esbuild/android-arm@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.21.5.tgz#9b04384fb771926dfa6d7ad04324ecb2ab9b2e28" + integrity sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg== "@esbuild/android-x64@0.17.19": version "0.17.19" resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.17.19.tgz#658368ef92067866d95fb268719f98f363d13ae1" integrity sha512-uUTTc4xGNDT7YSArp/zbtmbhO0uEEK9/ETW29Wk1thYUJBz3IVnvgEiEwEa9IeLyvnpKrWK64Utw2bgUmDveww== -"@esbuild/android-x64@0.23.0": - version "0.23.0" - resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.23.0.tgz#1e51af9a6ac1f7143769f7ee58df5b274ed202e6" - integrity sha512-WRrmKidLoKDl56LsbBMhzTTBxrsVwTKdNbKDalbEZr0tcsBgCLbEtoNthOW6PX942YiYq8HzEnb4yWQMLQuipQ== +"@esbuild/android-x64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.21.5.tgz#29918ec2db754cedcb6c1b04de8cd6547af6461e" + integrity sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA== "@esbuild/darwin-arm64@0.17.19": version "0.17.19" resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.17.19.tgz#584c34c5991b95d4d48d333300b1a4e2ff7be276" integrity sha512-80wEoCfF/hFKM6WE1FyBHc9SfUblloAWx6FJkFWTWiCoht9Mc0ARGEM47e67W9rI09YoUxJL68WHfDRYEAvOhg== -"@esbuild/darwin-arm64@0.23.0": - version "0.23.0" - resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.23.0.tgz#d996187a606c9534173ebd78c58098a44dd7ef9e" - integrity sha512-YLntie/IdS31H54Ogdn+v50NuoWF5BDkEUFpiOChVa9UnKpftgwzZRrI4J132ETIi+D8n6xh9IviFV3eXdxfow== +"@esbuild/darwin-arm64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz#e495b539660e51690f3928af50a76fb0a6ccff2a" + integrity sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ== "@esbuild/darwin-x64@0.17.19": version "0.17.19" resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.17.19.tgz#7751d236dfe6ce136cce343dce69f52d76b7f6cb" integrity sha512-IJM4JJsLhRYr9xdtLytPLSH9k/oxR3boaUIYiHkAawtwNOXKE8KoU8tMvryogdcT8AU+Bflmh81Xn6Q0vTZbQw== -"@esbuild/darwin-x64@0.23.0": - version "0.23.0" - resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.23.0.tgz#30c8f28a7ef4e32fe46501434ebe6b0912e9e86c" - integrity sha512-IMQ6eme4AfznElesHUPDZ+teuGwoRmVuuixu7sv92ZkdQcPbsNHzutd+rAfaBKo8YK3IrBEi9SLLKWJdEvJniQ== +"@esbuild/darwin-x64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz#c13838fa57372839abdddc91d71542ceea2e1e22" + integrity sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw== "@esbuild/freebsd-arm64@0.17.19": version "0.17.19" resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.17.19.tgz#cacd171665dd1d500f45c167d50c6b7e539d5fd2" integrity sha512-pBwbc7DufluUeGdjSU5Si+P3SoMF5DQ/F/UmTSb8HXO80ZEAJmrykPyzo1IfNbAoaqw48YRpv8shwd1NoI0jcQ== -"@esbuild/freebsd-arm64@0.23.0": - version "0.23.0" - resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.23.0.tgz#30f4fcec8167c08a6e8af9fc14b66152232e7fb4" - integrity sha512-0muYWCng5vqaxobq6LB3YNtevDFSAZGlgtLoAc81PjUfiFz36n4KMpwhtAd4he8ToSI3TGyuhyx5xmiWNYZFyw== +"@esbuild/freebsd-arm64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz#646b989aa20bf89fd071dd5dbfad69a3542e550e" + integrity sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g== "@esbuild/freebsd-x64@0.17.19": version "0.17.19" resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.17.19.tgz#0769456eee2a08b8d925d7c00b79e861cb3162e4" integrity sha512-4lu+n8Wk0XlajEhbEffdy2xy53dpR06SlzvhGByyg36qJw6Kpfk7cp45DR/62aPH9mtJRmIyrXAS5UWBrJT6TQ== -"@esbuild/freebsd-x64@0.23.0": - version "0.23.0" - resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.23.0.tgz#1003a6668fe1f5d4439e6813e5b09a92981bc79d" - integrity sha512-XKDVu8IsD0/q3foBzsXGt/KjD/yTKBCIwOHE1XwiXmrRwrX6Hbnd5Eqn/WvDekddK21tfszBSrE/WMaZh+1buQ== +"@esbuild/freebsd-x64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz#aa615cfc80af954d3458906e38ca22c18cf5c261" + integrity sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ== "@esbuild/linux-arm64@0.17.19": version "0.17.19" resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.17.19.tgz#38e162ecb723862c6be1c27d6389f48960b68edb" integrity sha512-ct1Tg3WGwd3P+oZYqic+YZF4snNl2bsnMKRkb3ozHmnM0dGWuxcPTTntAF6bOP0Sp4x0PjSF+4uHQ1xvxfRKqg== -"@esbuild/linux-arm64@0.23.0": - version "0.23.0" - resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.23.0.tgz#3b9a56abfb1410bb6c9138790f062587df3e6e3a" - integrity sha512-j1t5iG8jE7BhonbsEg5d9qOYcVZv/Rv6tghaXM/Ug9xahM0nX/H2gfu6X6z11QRTMT6+aywOMA8TDkhPo8aCGw== +"@esbuild/linux-arm64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz#70ac6fa14f5cb7e1f7f887bcffb680ad09922b5b" + integrity sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q== "@esbuild/linux-arm@0.17.19": version "0.17.19" resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.17.19.tgz#1a2cd399c50040184a805174a6d89097d9d1559a" integrity sha512-cdmT3KxjlOQ/gZ2cjfrQOtmhG4HJs6hhvm3mWSRDPtZ/lP5oe8FWceS10JaSJC13GBd4eH/haHnqf7hhGNLerA== -"@esbuild/linux-arm@0.23.0": - version "0.23.0" - resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.23.0.tgz#237a8548e3da2c48cd79ae339a588f03d1889aad" - integrity sha512-SEELSTEtOFu5LPykzA395Mc+54RMg1EUgXP+iw2SJ72+ooMwVsgfuwXo5Fn0wXNgWZsTVHwY2cg4Vi/bOD88qw== +"@esbuild/linux-arm@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz#fc6fd11a8aca56c1f6f3894f2bea0479f8f626b9" + integrity sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA== "@esbuild/linux-ia32@0.17.19": version "0.17.19" resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.17.19.tgz#e28c25266b036ce1cabca3c30155222841dc035a" integrity sha512-w4IRhSy1VbsNxHRQpeGCHEmibqdTUx61Vc38APcsRbuVgK0OPEnQ0YD39Brymn96mOx48Y2laBQGqgZ0j9w6SQ== -"@esbuild/linux-ia32@0.23.0": - version "0.23.0" - resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.23.0.tgz#4269cd19cb2de5de03a7ccfc8855dde3d284a238" - integrity sha512-P7O5Tkh2NbgIm2R6x1zGJJsnacDzTFcRWZyTTMgFdVit6E98LTxO+v8LCCLWRvPrjdzXHx9FEOA8oAZPyApWUA== +"@esbuild/linux-ia32@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz#3271f53b3f93e3d093d518d1649d6d68d346ede2" + integrity sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg== "@esbuild/linux-loong64@0.17.19": version "0.17.19" resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.17.19.tgz#0f887b8bb3f90658d1a0117283e55dbd4c9dcf72" integrity sha512-2iAngUbBPMq439a+z//gE+9WBldoMp1s5GWsUSgqHLzLJ9WoZLZhpwWuym0u0u/4XmZ3gpHmzV84PonE+9IIdQ== -"@esbuild/linux-loong64@0.23.0": - version "0.23.0" - resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.23.0.tgz#82b568f5658a52580827cc891cb69d2cb4f86280" - integrity sha512-InQwepswq6urikQiIC/kkx412fqUZudBO4SYKu0N+tGhXRWUqAx+Q+341tFV6QdBifpjYgUndV1hhMq3WeJi7A== +"@esbuild/linux-loong64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz#ed62e04238c57026aea831c5a130b73c0f9f26df" + integrity sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg== "@esbuild/linux-mips64el@0.17.19": version "0.17.19" resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.17.19.tgz#f5d2a0b8047ea9a5d9f592a178ea054053a70289" integrity sha512-LKJltc4LVdMKHsrFe4MGNPp0hqDFA1Wpt3jE1gEyM3nKUvOiO//9PheZZHfYRfYl6AwdTH4aTcXSqBerX0ml4A== -"@esbuild/linux-mips64el@0.23.0": - version "0.23.0" - resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.23.0.tgz#9a57386c926262ae9861c929a6023ed9d43f73e5" - integrity sha512-J9rflLtqdYrxHv2FqXE2i1ELgNjT+JFURt/uDMoPQLcjWQA5wDKgQA4t/dTqGa88ZVECKaD0TctwsUfHbVoi4w== +"@esbuild/linux-mips64el@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz#e79b8eb48bf3b106fadec1ac8240fb97b4e64cbe" + integrity sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg== "@esbuild/linux-ppc64@0.17.19": version "0.17.19" resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.17.19.tgz#876590e3acbd9fa7f57a2c7d86f83717dbbac8c7" integrity sha512-/c/DGybs95WXNS8y3Ti/ytqETiW7EU44MEKuCAcpPto3YjQbyK3IQVKfF6nbghD7EcLUGl0NbiL5Rt5DMhn5tg== -"@esbuild/linux-ppc64@0.23.0": - version "0.23.0" - resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.23.0.tgz#f3a79fd636ba0c82285d227eb20ed8e31b4444f6" - integrity sha512-cShCXtEOVc5GxU0fM+dsFD10qZ5UpcQ8AM22bYj0u/yaAykWnqXJDpd77ublcX6vdDsWLuweeuSNZk4yUxZwtw== +"@esbuild/linux-ppc64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz#5f2203860a143b9919d383ef7573521fb154c3e4" + integrity sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w== "@esbuild/linux-riscv64@0.17.19": version "0.17.19" resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.17.19.tgz#7f49373df463cd9f41dc34f9b2262d771688bf09" integrity sha512-FC3nUAWhvFoutlhAkgHf8f5HwFWUL6bYdvLc/TTuxKlvLi3+pPzdZiFKSWz/PF30TB1K19SuCxDTI5KcqASJqA== -"@esbuild/linux-riscv64@0.23.0": - version "0.23.0" - resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.23.0.tgz#f9d2ef8356ce6ce140f76029680558126b74c780" - integrity sha512-HEtaN7Y5UB4tZPeQmgz/UhzoEyYftbMXrBCUjINGjh3uil+rB/QzzpMshz3cNUxqXN7Vr93zzVtpIDL99t9aRw== +"@esbuild/linux-riscv64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz#07bcafd99322d5af62f618cb9e6a9b7f4bb825dc" + integrity sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA== "@esbuild/linux-s390x@0.17.19": version "0.17.19" resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.17.19.tgz#e2afd1afcaf63afe2c7d9ceacd28ec57c77f8829" integrity sha512-IbFsFbxMWLuKEbH+7sTkKzL6NJmG2vRyy6K7JJo55w+8xDk7RElYn6xvXtDW8HCfoKBFK69f3pgBJSUSQPr+4Q== -"@esbuild/linux-s390x@0.23.0": - version "0.23.0" - resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.23.0.tgz#45390f12e802201f38a0229e216a6aed4351dfe8" - integrity sha512-WDi3+NVAuyjg/Wxi+o5KPqRbZY0QhI9TjrEEm+8dmpY9Xir8+HE/HNx2JoLckhKbFopW0RdO2D72w8trZOV+Wg== +"@esbuild/linux-s390x@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz#b7ccf686751d6a3e44b8627ababc8be3ef62d8de" + integrity sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A== "@esbuild/linux-x64@0.17.19": version "0.17.19" resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.17.19.tgz#8a0e9738b1635f0c53389e515ae83826dec22aa4" integrity sha512-68ngA9lg2H6zkZcyp22tsVt38mlhWde8l3eJLWkyLrp4HwMUr3c1s/M2t7+kHIhvMjglIBrFpncX1SzMckomGw== -"@esbuild/linux-x64@0.23.0": - version "0.23.0" - resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.23.0.tgz#c8409761996e3f6db29abcf9b05bee8d7d80e910" - integrity sha512-a3pMQhUEJkITgAw6e0bWA+F+vFtCciMjW/LPtoj99MhVt+Mfb6bbL9hu2wmTZgNd994qTAEw+U/r6k3qHWWaOQ== +"@esbuild/linux-x64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz#6d8f0c768e070e64309af8004bb94e68ab2bb3b0" + integrity sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ== "@esbuild/netbsd-x64@0.17.19": version "0.17.19" resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.17.19.tgz#c29fb2453c6b7ddef9a35e2c18b37bda1ae5c462" integrity sha512-CwFq42rXCR8TYIjIfpXCbRX0rp1jo6cPIUPSaWwzbVI4aOfX96OXY8M6KNmtPcg7QjYeDmN+DD0Wp3LaBOLf4Q== -"@esbuild/netbsd-x64@0.23.0": - version "0.23.0" - resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.23.0.tgz#ba70db0114380d5f6cfb9003f1d378ce989cd65c" - integrity sha512-cRK+YDem7lFTs2Q5nEv/HHc4LnrfBCbH5+JHu6wm2eP+d8OZNoSMYgPZJq78vqQ9g+9+nMuIsAO7skzphRXHyw== - -"@esbuild/openbsd-arm64@0.23.0": - version "0.23.0" - resolved "https://registry.yarnpkg.com/@esbuild/openbsd-arm64/-/openbsd-arm64-0.23.0.tgz#72fc55f0b189f7a882e3cf23f332370d69dfd5db" - integrity sha512-suXjq53gERueVWu0OKxzWqk7NxiUWSUlrxoZK7usiF50C6ipColGR5qie2496iKGYNLhDZkPxBI3erbnYkU0rQ== +"@esbuild/netbsd-x64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz#bbe430f60d378ecb88decb219c602667387a6047" + integrity sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg== "@esbuild/openbsd-x64@0.17.19": version "0.17.19" resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.17.19.tgz#95e75a391403cb10297280d524d66ce04c920691" integrity sha512-cnq5brJYrSZ2CF6c35eCmviIN3k3RczmHz8eYaVlNasVqsNY+JKohZU5MKmaOI+KkllCdzOKKdPs762VCPC20g== -"@esbuild/openbsd-x64@0.23.0": - version "0.23.0" - resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.23.0.tgz#b6ae7a0911c18fe30da3db1d6d17a497a550e5d8" - integrity sha512-6p3nHpby0DM/v15IFKMjAaayFhqnXV52aEmv1whZHX56pdkK+MEaLoQWj+H42ssFarP1PcomVhbsR4pkz09qBg== +"@esbuild/openbsd-x64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz#99d1cf2937279560d2104821f5ccce220cb2af70" + integrity sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow== "@esbuild/sunos-x64@0.17.19": version "0.17.19" resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.17.19.tgz#722eaf057b83c2575937d3ffe5aeb16540da7273" integrity sha512-vCRT7yP3zX+bKWFeP/zdS6SqdWB8OIpaRq/mbXQxTGHnIxspRtigpkUcDMlSCOejlHowLqII7K2JKevwyRP2rg== -"@esbuild/sunos-x64@0.23.0": - version "0.23.0" - resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.23.0.tgz#58f0d5e55b9b21a086bfafaa29f62a3eb3470ad8" - integrity sha512-BFelBGfrBwk6LVrmFzCq1u1dZbG4zy/Kp93w2+y83Q5UGYF1d8sCzeLI9NXjKyujjBBniQa8R8PzLFAUrSM9OA== +"@esbuild/sunos-x64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz#08741512c10d529566baba837b4fe052c8f3487b" + integrity sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg== "@esbuild/win32-arm64@0.17.19": version "0.17.19" resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.17.19.tgz#9aa9dc074399288bdcdd283443e9aeb6b9552b6f" integrity sha512-yYx+8jwowUstVdorcMdNlzklLYhPxjniHWFKgRqH7IFlUEa0Umu3KuYplf1HUZZ422e3NU9F4LGb+4O0Kdcaag== -"@esbuild/win32-arm64@0.23.0": - version "0.23.0" - resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.23.0.tgz#b858b2432edfad62e945d5c7c9e5ddd0f528ca6d" - integrity sha512-lY6AC8p4Cnb7xYHuIxQ6iYPe6MfO2CC43XXKo9nBXDb35krYt7KGhQnOkRGar5psxYkircpCqfbNDB4uJbS2jQ== +"@esbuild/win32-arm64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz#675b7385398411240735016144ab2e99a60fc75d" + integrity sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A== "@esbuild/win32-ia32@0.17.19": version "0.17.19" resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.17.19.tgz#95ad43c62ad62485e210f6299c7b2571e48d2b03" integrity sha512-eggDKanJszUtCdlVs0RB+h35wNlb5v4TWEkq4vZcmVt5u/HiDZrTXe2bWFQUez3RgNHwx/x4sk5++4NSSicKkw== -"@esbuild/win32-ia32@0.23.0": - version "0.23.0" - resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.23.0.tgz#167ef6ca22a476c6c0c014a58b4f43ae4b80dec7" - integrity sha512-7L1bHlOTcO4ByvI7OXVI5pNN6HSu6pUQq9yodga8izeuB1KcT2UkHaH6118QJwopExPn0rMHIseCTx1CRo/uNA== +"@esbuild/win32-ia32@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz#1bfc3ce98aa6ca9a0969e4d2af72144c59c1193b" + integrity sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA== "@esbuild/win32-x64@0.17.19": version "0.17.19" resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.17.19.tgz#8cfaf2ff603e9aabb910e9c0558c26cf32744061" integrity sha512-lAhycmKnVOuRYNtRtatQR1LPQf2oYCkRGkSFnseDAKPl8lu5SOsK/e1sXe5a0Pc5kHIHe6P2I/ilntNv2xf3cA== -"@esbuild/win32-x64@0.23.0": - version "0.23.0" - resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.23.0.tgz#db44a6a08520b5f25bbe409f34a59f2d4bcc7ced" - integrity sha512-Arm+WgUFLUATuoxCJcahGuk6Yj9Pzxd6l11Zb/2aAuv5kWWvvfhLFo2fni4uSK5vzlUdCGZ/BdV5tH8klj8p8g== +"@esbuild/win32-x64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz#acad351d582d157bb145535db2a6ff53dd514b5c" + integrity sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw== -"@eslint-community/eslint-utils@^4.2.0": +"@eslint-community/eslint-utils@^4.1.2", "@eslint-community/eslint-utils@^4.2.0", "@eslint-community/eslint-utils@^4.4.0": version "4.4.0" resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz#a23514e8fb9af1269d5f7788aa556798d61c6b59" integrity sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA== dependencies: eslint-visitor-keys "^3.3.0" -"@eslint-community/regexpp@^4.11.0": +"@eslint-community/regexpp@^4.10.0", "@eslint-community/regexpp@^4.11.0", "@eslint-community/regexpp@^4.8.0", "@eslint-community/regexpp@^4.9.1": version "4.11.0" resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.11.0.tgz#b0ffd0312b4a3fd2d6f77237e7248a5ad3a680ae" integrity sha512-G/M/tIiMrTAxEWRfLfQJMmGNX28IxBg4PBz8XqQhqUHLFI6TL2htpIB1iQCj144V5ee/JaKyT9/WZ0MGZWfA7A== @@ -334,7 +449,7 @@ minimatch "^3.1.2" strip-json-comments "^3.1.1" -"@eslint/js@9.8.0", "@eslint/js@^9.8.0": +"@eslint/js@9.8.0": version "9.8.0" resolved "https://registry.yarnpkg.com/@eslint/js/-/js-9.8.0.tgz#ae9bc14bb839713c5056f5018bcefa955556d3a4" integrity sha512-MfluB7EUfxXtv3i/++oh89uzAr4PDI4nn201hsp+qaXqsjAWzinlZEHEfPgAX4doIlKvPG/i0A9dpKxOLII8yA== @@ -385,12 +500,12 @@ "@nodelib/fs.stat" "2.0.5" run-parallel "^1.1.9" -"@nodelib/fs.stat@2.0.5": +"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2": version "2.0.5" resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b" integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== -"@nodelib/fs.walk@^1.2.8": +"@nodelib/fs.walk@^1.2.3", "@nodelib/fs.walk@^1.2.8": version "1.2.8" resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a" integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg== @@ -403,6 +518,188 @@ resolved "https://registry.yarnpkg.com/@pkgr/core/-/core-0.1.1.tgz#1ec17e2edbec25c8306d424ecfbf13c7de1aaa31" integrity sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA== +"@rollup/plugin-node-resolve@^15.2.3": + version "15.2.3" + resolved "https://registry.yarnpkg.com/@rollup/plugin-node-resolve/-/plugin-node-resolve-15.2.3.tgz#e5e0b059bd85ca57489492f295ce88c2d4b0daf9" + integrity sha512-j/lym8nf5E21LwBT4Df1VD6hRO2L2iwUeUmP7litikRsVp1H6NWx20NEp0Y7su+7XGc476GnXXc4kFeZNGmaSQ== + dependencies: + "@rollup/pluginutils" "^5.0.1" + "@types/resolve" "1.20.2" + deepmerge "^4.2.2" + is-builtin-module "^3.2.1" + is-module "^1.0.0" + resolve "^1.22.1" + +"@rollup/pluginutils@^5.0.1": + version "5.1.0" + resolved "https://registry.yarnpkg.com/@rollup/pluginutils/-/pluginutils-5.1.0.tgz#7e53eddc8c7f483a4ad0b94afb1f7f5fd3c771e0" + integrity sha512-XTIWOPPcpvyKI6L1NHo0lFlCyznUEyPmPY1mc3KpPVDYulHSTvyeLNVW00QTLIAFNhR3kYnJTQHeGqU4M3n09g== + dependencies: + "@types/estree" "^1.0.0" + estree-walker "^2.0.2" + picomatch "^2.3.1" + +"@rollup/rollup-android-arm-eabi@4.21.0": + version "4.21.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.21.0.tgz#d941173f82f9b041c61b0dc1a2a91dcd06e4b31e" + integrity sha512-WTWD8PfoSAJ+qL87lE7votj3syLavxunWhzCnx3XFxFiI/BA/r3X7MUM8dVrH8rb2r4AiO8jJsr3ZjdaftmnfA== + +"@rollup/rollup-android-arm64@4.21.0": + version "4.21.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.21.0.tgz#7e7157c8543215245ceffc445134d9e843ba51c0" + integrity sha512-a1sR2zSK1B4eYkiZu17ZUZhmUQcKjk2/j9Me2IDjk1GHW7LB5Z35LEzj9iJch6gtUfsnvZs1ZNyDW2oZSThrkA== + +"@rollup/rollup-darwin-arm64@4.21.0": + version "4.21.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.21.0.tgz#f0a18a4fc8dc6eb1e94a51fa2adb22876f477947" + integrity sha512-zOnKWLgDld/svhKO5PD9ozmL6roy5OQ5T4ThvdYZLpiOhEGY+dp2NwUmxK0Ld91LrbjrvtNAE0ERBwjqhZTRAA== + +"@rollup/rollup-darwin-x64@4.21.0": + version "4.21.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.21.0.tgz#34b7867613e5cc42d2b85ddc0424228cc33b43f0" + integrity sha512-7doS8br0xAkg48SKE2QNtMSFPFUlRdw9+votl27MvT46vo44ATBmdZdGysOevNELmZlfd+NEa0UYOA8f01WSrg== + +"@rollup/rollup-linux-arm-gnueabihf@4.21.0": + version "4.21.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.21.0.tgz#422b19ff9ae02b05d3395183d1d43b38c7c8be0b" + integrity sha512-pWJsfQjNWNGsoCq53KjMtwdJDmh/6NubwQcz52aEwLEuvx08bzcy6tOUuawAOncPnxz/3siRtd8hiQ32G1y8VA== + +"@rollup/rollup-linux-arm-musleabihf@4.21.0": + version "4.21.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.21.0.tgz#568aa29195ef6fc57ec6ed3f518923764406a8ee" + integrity sha512-efRIANsz3UHZrnZXuEvxS9LoCOWMGD1rweciD6uJQIx2myN3a8Im1FafZBzh7zk1RJ6oKcR16dU3UPldaKd83w== + +"@rollup/rollup-linux-arm64-gnu@4.21.0": + version "4.21.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.21.0.tgz#22309c8bcba9a73114f69165c72bc94b2fbec085" + integrity sha512-ZrPhydkTVhyeGTW94WJ8pnl1uroqVHM3j3hjdquwAcWnmivjAwOYjTEAuEDeJvGX7xv3Z9GAvrBkEzCgHq9U1w== + +"@rollup/rollup-linux-arm64-musl@4.21.0": + version "4.21.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.21.0.tgz#c93c388af6d33f082894b8a60839d7265b2b9bc5" + integrity sha512-cfaupqd+UEFeURmqNP2eEvXqgbSox/LHOyN9/d2pSdV8xTrjdg3NgOFJCtc1vQ/jEke1qD0IejbBfxleBPHnPw== + +"@rollup/rollup-linux-powerpc64le-gnu@4.21.0": + version "4.21.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.21.0.tgz#493c5e19e395cf3c6bd860c7139c8a903dea72b4" + integrity sha512-ZKPan1/RvAhrUylwBXC9t7B2hXdpb/ufeu22pG2psV7RN8roOfGurEghw1ySmX/CmDDHNTDDjY3lo9hRlgtaHg== + +"@rollup/rollup-linux-riscv64-gnu@4.21.0": + version "4.21.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.21.0.tgz#a2eab4346fbe5909165ce99adb935ba30c9fb444" + integrity sha512-H1eRaCwd5E8eS8leiS+o/NqMdljkcb1d6r2h4fKSsCXQilLKArq6WS7XBLDu80Yz+nMqHVFDquwcVrQmGr28rg== + +"@rollup/rollup-linux-s390x-gnu@4.21.0": + version "4.21.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.21.0.tgz#0bc49a79db4345d78d757bb1b05e73a1b42fa5c3" + integrity sha512-zJ4hA+3b5tu8u7L58CCSI0A9N1vkfwPhWd/puGXwtZlsB5bTkwDNW/+JCU84+3QYmKpLi+XvHdmrlwUwDA6kqw== + +"@rollup/rollup-linux-x64-gnu@4.21.0": + version "4.21.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.21.0.tgz#4fd36a6a41f3406d8693321b13d4f9b7658dd4b9" + integrity sha512-e2hrvElFIh6kW/UNBQK/kzqMNY5mO+67YtEh9OA65RM5IJXYTWiXjX6fjIiPaqOkBthYF1EqgiZ6OXKcQsM0hg== + +"@rollup/rollup-linux-x64-musl@4.21.0": + version "4.21.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.21.0.tgz#10ebb13bd4469cbad1a5d9b073bd27ec8a886200" + integrity sha512-1vvmgDdUSebVGXWX2lIcgRebqfQSff0hMEkLJyakQ9JQUbLDkEaMsPTLOmyccyC6IJ/l3FZuJbmrBw/u0A0uCQ== + +"@rollup/rollup-win32-arm64-msvc@4.21.0": + version "4.21.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.21.0.tgz#2fef1a90f1402258ef915ae5a94cc91a5a1d5bfc" + integrity sha512-s5oFkZ/hFcrlAyBTONFY1TWndfyre1wOMwU+6KCpm/iatybvrRgmZVM+vCFwxmC5ZhdlgfE0N4XorsDpi7/4XQ== + +"@rollup/rollup-win32-ia32-msvc@4.21.0": + version "4.21.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.21.0.tgz#a18ad47a95c5f264defb60acdd8c27569f816fc1" + integrity sha512-G9+TEqRnAA6nbpqyUqgTiopmnfgnMkR3kMukFBDsiyy23LZvUCpiUwjTRx6ezYCjJODXrh52rBR9oXvm+Fp5wg== + +"@rollup/rollup-win32-x64-msvc@4.21.0": + version "4.21.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.21.0.tgz#20c09cf44dcb082140cc7f439dd679fe4bba3375" + integrity sha512-2jsCDZwtQvRhejHLfZ1JY6w6kEuEtfF9nzYsZxzSlNVKDX+DpsDJ+Rbjkm74nvg2rdx0gwBS+IMdvwJuq3S9pQ== + +"@stylistic/eslint-plugin-js@2.6.2", "@stylistic/eslint-plugin-js@^2.6.2": + version "2.6.2" + resolved "https://registry.yarnpkg.com/@stylistic/eslint-plugin-js/-/eslint-plugin-js-2.6.2.tgz#ad4c2f35d49927fa81f4667b413a7de9640cb850" + integrity sha512-wCr/kVctAPayMU3pcOI1MKR7MoKIh6VKZU89lPklAqtJoxT+Em6RueiiARbpznUYG5eg3LymiU+aMD+aIZXdqA== + dependencies: + "@types/eslint" "^9.6.0" + acorn "^8.12.1" + eslint-visitor-keys "^4.0.0" + espree "^10.1.0" + +"@stylistic/eslint-plugin-jsx@2.6.2": + version "2.6.2" + resolved "https://registry.yarnpkg.com/@stylistic/eslint-plugin-jsx/-/eslint-plugin-jsx-2.6.2.tgz#308b7db18056ab6d3d49273c86d613062d99616b" + integrity sha512-dSXK/fSPA938J1fBi10QmhzLKtZ/2TuyVNHQMk8jUhWfKJDleAogaSqcWNAbN8fwcoe9UWmt/3StiIf2oYC1aQ== + dependencies: + "@stylistic/eslint-plugin-js" "^2.6.2" + "@types/eslint" "^9.6.0" + estraverse "^5.3.0" + picomatch "^4.0.2" + +"@stylistic/eslint-plugin-plus@2.6.2": + version "2.6.2" + resolved "https://registry.yarnpkg.com/@stylistic/eslint-plugin-plus/-/eslint-plugin-plus-2.6.2.tgz#4a9c5f0f69751dffc74ca5b88ec313d79c8c0465" + integrity sha512-cANcPASfRvq3VTbbQCrSIXq+2AI0IW68PNYaZoXXS0ENlp7HDB8dmrsJnOgWCcoEvdCB8z/eWcG/eq/v5Qcl+Q== + dependencies: + "@types/eslint" "^9.6.0" + "@typescript-eslint/utils" "^8.0.0" + +"@stylistic/eslint-plugin-ts@2.6.2": + version "2.6.2" + resolved "https://registry.yarnpkg.com/@stylistic/eslint-plugin-ts/-/eslint-plugin-ts-2.6.2.tgz#9ede414361f47ad1cca91cb178609d969b0aa5c4" + integrity sha512-6OEN3VtUNxjgOvWPavnC10MByr1H4zsgwNND3rQXr5lDFv93MLUnTsH+/SH15OkuqdyJgrQILI6b9lYecb1vIg== + dependencies: + "@stylistic/eslint-plugin-js" "2.6.2" + "@types/eslint" "^9.6.0" + "@typescript-eslint/utils" "^8.0.0" + +"@stylistic/eslint-plugin@^2.6.2": + version "2.6.2" + resolved "https://registry.yarnpkg.com/@stylistic/eslint-plugin/-/eslint-plugin-2.6.2.tgz#9ca829342e9ab38a2168a830d78c594c65aa3ce6" + integrity sha512-Ic5oFNM/25iuagob6LiIBkSI/A2y45TsyKtDtODXHRZDy52WfPfeexI6r+OH5+aWN9QGob2Bw+4JRM9/4areWw== + dependencies: + "@stylistic/eslint-plugin-js" "2.6.2" + "@stylistic/eslint-plugin-jsx" "2.6.2" + "@stylistic/eslint-plugin-plus" "2.6.2" + "@stylistic/eslint-plugin-ts" "2.6.2" + "@types/eslint" "^9.6.0" + +"@types/eslint@^8.56.5": + version "8.56.11" + resolved "https://registry.yarnpkg.com/@types/eslint/-/eslint-8.56.11.tgz#e2ff61510a3b9454b3329fe7731e3b4c6f780041" + integrity sha512-sVBpJMf7UPo/wGecYOpk2aQya2VUGeHhe38WG7/mN5FufNSubf5VT9Uh9Uyp8/eLJpu1/tuhJ/qTo4mhSB4V4Q== + dependencies: + "@types/estree" "*" + "@types/json-schema" "*" + +"@types/eslint@^9.6.0": + version "9.6.0" + resolved "https://registry.yarnpkg.com/@types/eslint/-/eslint-9.6.0.tgz#51d4fe4d0316da9e9f2c80884f2c20ed5fb022ff" + integrity sha512-gi6WQJ7cHRgZxtkQEoyHMppPjq9Kxo5Tjn2prSKDSmZrCz8TZ3jSRCeTJm+WoM+oB0WG37bRqLzaaU3q7JypGg== + dependencies: + "@types/estree" "*" + "@types/json-schema" "*" + +"@types/estree@*", "@types/estree@1.0.5", "@types/estree@^1.0.0", "@types/estree@^1.0.5": + version "1.0.5" + resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.5.tgz#a6ce3e556e00fd9895dd872dd172ad0d4bd687f4" + integrity sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw== + +"@types/json-schema@*": + version "7.0.15" + resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.15.tgz#596a1747233694d50f6ad8a7869fcb6f56cf5841" + integrity sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA== + +"@types/mdast@^3.0.0": + version "3.0.15" + resolved "https://registry.yarnpkg.com/@types/mdast/-/mdast-3.0.15.tgz#49c524a263f30ffa28b71ae282f813ed000ab9f5" + integrity sha512-LnwD+mUEfxWMa1QpDraczIn6k0Ee3SMicuYSSzS6ZYl2gKS09EClnJYGd8Du6rfc5r/GZEk5o1mRb8TaTj03sQ== + dependencies: + "@types/unist" "^2" + "@types/node-forge@^1.3.0": version "1.3.11" resolved "https://registry.yarnpkg.com/@types/node-forge/-/node-forge-1.3.11.tgz#0972ea538ddb0f4d9c2fa0ec5db5724773a604da" @@ -417,6 +714,152 @@ dependencies: undici-types "~5.26.4" +"@types/normalize-package-data@^2.4.0": + version "2.4.4" + resolved "https://registry.yarnpkg.com/@types/normalize-package-data/-/normalize-package-data-2.4.4.tgz#56e2cc26c397c038fab0e3a917a12d5c5909e901" + integrity sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA== + +"@types/resolve@1.20.2": + version "1.20.2" + resolved "https://registry.yarnpkg.com/@types/resolve/-/resolve-1.20.2.tgz#97d26e00cd4a0423b4af620abecf3e6f442b7975" + integrity sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q== + +"@types/unist@^2", "@types/unist@^2.0.2": + version "2.0.10" + resolved "https://registry.yarnpkg.com/@types/unist/-/unist-2.0.10.tgz#04ffa7f406ab628f7f7e97ca23e290cd8ab15efc" + integrity sha512-IfYcSBWE3hLpBg8+X2SEa8LVkJdJEkT2Ese2aaLs3ptGdVtABxndrMaxuFlQ1qdFf9Q5rDvDpxI3WwgvKFAsQA== + +"@typescript-eslint/eslint-plugin@^8.0.1": + version "8.1.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.1.0.tgz#3c020deeaaba82a6f741d00dacf172c53be4911f" + integrity sha512-LlNBaHFCEBPHyD4pZXb35mzjGkuGKXU5eeCA1SxvHfiRES0E82dOounfVpL4DCqYvJEKab0bZIA0gCRpdLKkCw== + dependencies: + "@eslint-community/regexpp" "^4.10.0" + "@typescript-eslint/scope-manager" "8.1.0" + "@typescript-eslint/type-utils" "8.1.0" + "@typescript-eslint/utils" "8.1.0" + "@typescript-eslint/visitor-keys" "8.1.0" + graphemer "^1.4.0" + ignore "^5.3.1" + natural-compare "^1.4.0" + ts-api-utils "^1.3.0" + +"@typescript-eslint/parser@^8.0.1": + version "8.1.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-8.1.0.tgz#b7e77f5fa212df59eba51ecd4986f194bccc2303" + integrity sha512-U7iTAtGgJk6DPX9wIWPPOlt1gO57097G06gIcl0N0EEnNw8RGD62c+2/DiP/zL7KrkqnnqF7gtFGR7YgzPllTA== + dependencies: + "@typescript-eslint/scope-manager" "8.1.0" + "@typescript-eslint/types" "8.1.0" + "@typescript-eslint/typescript-estree" "8.1.0" + "@typescript-eslint/visitor-keys" "8.1.0" + debug "^4.3.4" + +"@typescript-eslint/scope-manager@7.18.0": + version "7.18.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-7.18.0.tgz#c928e7a9fc2c0b3ed92ab3112c614d6bd9951c83" + integrity sha512-jjhdIE/FPF2B7Z1uzc6i3oWKbGcHb87Qw7AWj6jmEqNOfDFbJWtjt/XfwCpvNkpGWlcJaog5vTR+VV8+w9JflA== + dependencies: + "@typescript-eslint/types" "7.18.0" + "@typescript-eslint/visitor-keys" "7.18.0" + +"@typescript-eslint/scope-manager@8.1.0": + version "8.1.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-8.1.0.tgz#dd8987d2efebb71d230a1c71d82e84a7aead5c3d" + integrity sha512-DsuOZQji687sQUjm4N6c9xABJa7fjvfIdjqpSIIVOgaENf2jFXiM9hIBZOL3hb6DHK9Nvd2d7zZnoMLf9e0OtQ== + dependencies: + "@typescript-eslint/types" "8.1.0" + "@typescript-eslint/visitor-keys" "8.1.0" + +"@typescript-eslint/type-utils@8.1.0": + version "8.1.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-8.1.0.tgz#dbf5a4308166dfc37a36305390dea04a3a3b5048" + integrity sha512-oLYvTxljVvsMnldfl6jIKxTaU7ok7km0KDrwOt1RHYu6nxlhN3TIx8k5Q52L6wR33nOwDgM7VwW1fT1qMNfFIA== + dependencies: + "@typescript-eslint/typescript-estree" "8.1.0" + "@typescript-eslint/utils" "8.1.0" + debug "^4.3.4" + ts-api-utils "^1.3.0" + +"@typescript-eslint/types@7.18.0", "@typescript-eslint/types@^7.2.0": + version "7.18.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-7.18.0.tgz#b90a57ccdea71797ffffa0321e744f379ec838c9" + integrity sha512-iZqi+Ds1y4EDYUtlOOC+aUmxnE9xS/yCigkjA7XpTKV6nCBd3Hp/PRGGmdwnfkV2ThMyYldP1wRpm/id99spTQ== + +"@typescript-eslint/types@8.1.0", "@typescript-eslint/types@^8.0.1": + version "8.1.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-8.1.0.tgz#fbf1eaa668a7e444ac507732ca9d3c3468e5db9c" + integrity sha512-q2/Bxa0gMOu/2/AKALI0tCKbG2zppccnRIRCW6BaaTlRVaPKft4oVYPp7WOPpcnsgbr0qROAVCVKCvIQ0tbWog== + +"@typescript-eslint/typescript-estree@7.18.0": + version "7.18.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-7.18.0.tgz#b5868d486c51ce8f312309ba79bdb9f331b37931" + integrity sha512-aP1v/BSPnnyhMHts8cf1qQ6Q1IFwwRvAQGRvBFkWlo3/lH29OXA3Pts+c10nxRxIBrDnoMqzhgdwVe5f2D6OzA== + dependencies: + "@typescript-eslint/types" "7.18.0" + "@typescript-eslint/visitor-keys" "7.18.0" + debug "^4.3.4" + globby "^11.1.0" + is-glob "^4.0.3" + minimatch "^9.0.4" + semver "^7.6.0" + ts-api-utils "^1.3.0" + +"@typescript-eslint/typescript-estree@8.1.0": + version "8.1.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-8.1.0.tgz#c44e5667683c0bb5caa43192e27de6a994f4e4c4" + integrity sha512-NTHhmufocEkMiAord/g++gWKb0Fr34e9AExBRdqgWdVBaKoei2dIyYKD9Q0jBnvfbEA5zaf8plUFMUH6kQ0vGg== + dependencies: + "@typescript-eslint/types" "8.1.0" + "@typescript-eslint/visitor-keys" "8.1.0" + debug "^4.3.4" + globby "^11.1.0" + is-glob "^4.0.3" + minimatch "^9.0.4" + semver "^7.6.0" + ts-api-utils "^1.3.0" + +"@typescript-eslint/utils@8.1.0", "@typescript-eslint/utils@^8.0.0", "@typescript-eslint/utils@^8.0.1": + version "8.1.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-8.1.0.tgz#a922985a43d2560ce0d293be79148fa80c1325e0" + integrity sha512-ypRueFNKTIFwqPeJBfeIpxZ895PQhNyH4YID6js0UoBImWYoSjBsahUn9KMiJXh94uOjVBgHD9AmkyPsPnFwJA== + dependencies: + "@eslint-community/eslint-utils" "^4.4.0" + "@typescript-eslint/scope-manager" "8.1.0" + "@typescript-eslint/types" "8.1.0" + "@typescript-eslint/typescript-estree" "8.1.0" + +"@typescript-eslint/utils@^7.4.0": + version "7.18.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-7.18.0.tgz#bca01cde77f95fc6a8d5b0dbcbfb3d6ca4be451f" + integrity sha512-kK0/rNa2j74XuHVcoCZxdFBMF+aq/vH83CXAOHieC+2Gis4mF8jJXT5eAfyD3K0sAxtPuwxaIOIOvhwzVDt/kw== + dependencies: + "@eslint-community/eslint-utils" "^4.4.0" + "@typescript-eslint/scope-manager" "7.18.0" + "@typescript-eslint/types" "7.18.0" + "@typescript-eslint/typescript-estree" "7.18.0" + +"@typescript-eslint/visitor-keys@7.18.0": + version "7.18.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-7.18.0.tgz#0564629b6124d67607378d0f0332a0495b25e7d7" + integrity sha512-cDF0/Gf81QpY3xYyJKDV14Zwdmid5+uuENhjH2EqFaF0ni+yAyq/LzMaIJdhNJXZI7uLzwIlA+V7oWoyn6Curg== + dependencies: + "@typescript-eslint/types" "7.18.0" + eslint-visitor-keys "^3.4.3" + +"@typescript-eslint/visitor-keys@8.1.0": + version "8.1.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-8.1.0.tgz#ab2b3a9699a8ddebf0c205e133f114c1fed9daad" + integrity sha512-ba0lNI19awqZ5ZNKh6wCModMwoZs457StTebQ0q1NP58zSi2F6MOZRXwfKZy+jB78JNJ/WH8GSh2IQNzXX8Nag== + dependencies: + "@typescript-eslint/types" "8.1.0" + eslint-visitor-keys "^3.4.3" + +"@vitest/eslint-plugin@^1.0.0": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@vitest/eslint-plugin/-/eslint-plugin-1.0.2.tgz#73e30720bf691811df1e311ae3a24f76fac92085" + integrity sha512-lt7O8NTzDf7H8mbLuvsAdolnpibgv8lo8nRshRr2f2vNFONB3u2MEL9Jt12n9qDpLeT1Ap03Kf7RVH+PF71G1w== + acorn-jsx@^5.3.2: version "5.3.2" resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" @@ -429,7 +872,7 @@ acorn-walk@^8.2.0: dependencies: acorn "^8.11.0" -acorn@^8.11.0, acorn@^8.12.0, acorn@^8.8.0: +acorn@^8.11.0, acorn@^8.11.3, acorn@^8.12.0, acorn@^8.12.1, acorn@^8.5.0, acorn@^8.8.0, acorn@^8.9.0: version "8.12.1" resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.12.1.tgz#71616bdccbe25e27a54439e0046e89ca76df2248" integrity sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg== @@ -449,7 +892,14 @@ ansi-regex@^5.0.1: resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== -ansi-styles@^4.1.0: +ansi-styles@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" + integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== + dependencies: + color-convert "^1.9.0" + +ansi-styles@^4.0.0, ansi-styles@^4.1.0: version "4.3.0" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== @@ -474,6 +924,11 @@ argparse@^2.0.1: resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== +array-union@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" + integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== + as-table@^1.0.36: version "1.0.55" resolved "https://registry.yarnpkg.com/as-table/-/as-table-1.0.55.tgz#dc984da3937745de902cea1d45843c01bdbbec4f" @@ -496,6 +951,11 @@ blake3-wasm@^2.1.5: resolved "https://registry.yarnpkg.com/blake3-wasm/-/blake3-wasm-2.1.5.tgz#b22dbb84bc9419ed0159caa76af4b1b132e6ba52" integrity sha512-F1+K8EbfOZE49dtoPtmxUQrpXaBIl3ICvasLh+nJta0xkz+9kF/7uet9fLnwKqhDrmj6g+6K3Tw9yQPUg2ka5g== +boolbase@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e" + integrity sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww== + brace-expansion@^1.1.7: version "1.1.11" resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" @@ -504,18 +964,45 @@ brace-expansion@^1.1.7: balanced-match "^1.0.0" concat-map "0.0.1" -braces@~3.0.2: +brace-expansion@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.1.tgz#1edc459e0f0c548486ecf9fc99f2221364b9a0ae" + integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA== + dependencies: + balanced-match "^1.0.0" + +braces@^3.0.3, braces@~3.0.2: version "3.0.3" resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789" integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA== dependencies: fill-range "^7.1.1" +browserslist@^4.23.3: + version "4.23.3" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.23.3.tgz#debb029d3c93ebc97ffbc8d9cbb03403e227c800" + integrity sha512-btwCFJVjI4YWDNfau8RhZ+B1Q/VLoUITrm3RlP6y1tYGWIOa+InuYiRGXUBXo8nA1qKmHMyLB/iVQg5TT4eFoA== + dependencies: + caniuse-lite "^1.0.30001646" + electron-to-chromium "^1.5.4" + node-releases "^2.0.18" + update-browserslist-db "^1.1.0" + +builtin-modules@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-3.3.0.tgz#cae62812b89801e9656336e46223e030386be7b6" + integrity sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw== + callsites@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== +caniuse-lite@^1.0.30001646: + version "1.0.30001651" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001651.tgz#52de59529e8b02b1aedcaaf5c05d9e23c0c28138" + integrity sha512-9Cf+Xv1jJNe1xPZLGuUXLNkE1BoDkqRqYyFJ9TDYSqhduqA4hu4oR9HluGoWYQC/aj8WHjsGVV+bwkh0+tegRg== + capnp-ts@^0.7.0: version "0.7.0" resolved "https://registry.yarnpkg.com/capnp-ts/-/capnp-ts-0.7.0.tgz#16fd8e76b667d002af8fcf4bf92bf15d1a7b54a9" @@ -524,6 +1011,15 @@ capnp-ts@^0.7.0: debug "^4.3.1" tslib "^2.2.0" +chalk@^2.4.2: + version "2.4.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" + integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== + dependencies: + ansi-styles "^3.2.1" + escape-string-regexp "^1.0.5" + supports-color "^5.3.0" + chalk@^4.0.0: version "4.1.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" @@ -532,6 +1028,21 @@ chalk@^4.0.0: ansi-styles "^4.1.0" supports-color "^7.1.0" +character-entities-legacy@^1.0.0: + version "1.1.4" + resolved "https://registry.yarnpkg.com/character-entities-legacy/-/character-entities-legacy-1.1.4.tgz#94bc1845dce70a5bb9d2ecc748725661293d8fc1" + integrity sha512-3Xnr+7ZFS1uxeiUDvV02wQ+QDbc55o97tIV5zHScSPJpcLm/r0DFPcoY3tYRp+VZukxuMeKgXYmsXQHO05zQeA== + +character-entities@^1.0.0: + version "1.2.4" + resolved "https://registry.yarnpkg.com/character-entities/-/character-entities-1.2.4.tgz#e12c3939b7eaf4e5b15e7ad4c5e28e1d48c5b16b" + integrity sha512-iBMyeEHxfVnIakwOuDXpVkc54HijNgCyQB2w0VfGQThle6NXn50zU6V/u+LDhxHcDUPojn6Kpga3PTAD8W1bQw== + +character-reference-invalid@^1.0.0: + version "1.1.4" + resolved "https://registry.yarnpkg.com/character-reference-invalid/-/character-reference-invalid-1.1.4.tgz#083329cda0eae272ab3dbbf37e9a382c13af1560" + integrity sha512-mKKUkUbhPpQlCOfIuZkvSEgktjPFIsZKRRbC6KWVEMvlzblj3i3asQv5ODsrwt0N3pHAEvjP8KTQPHkp0+6jOg== + chokidar@^3.5.3: version "3.6.0" resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.6.0.tgz#197c6cc669ef2a8dc5e7b4d97ee4e092c3eb0d5b" @@ -547,6 +1058,34 @@ chokidar@^3.5.3: optionalDependencies: fsevents "~2.3.2" +ci-info@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-4.0.0.tgz#65466f8b280fc019b9f50a5388115d17a63a44f2" + integrity sha512-TdHqgGf9odd8SXNuxtUBVx8Nv+qZOejE6qyqiy5NtbYYQOeFa6zmHkxlPzmaLxWWHsU6nJmB7AETdVPi+2NBUg== + +clean-regexp@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/clean-regexp/-/clean-regexp-1.0.0.tgz#8df7c7aae51fd36874e8f8d05b9180bc11a3fed7" + integrity sha512-GfisEZEJvzKrmGWkvfhgzcz/BllN1USeqD2V6tg14OAOgaCD2Z/PUEuxnAZ/nPvmaHRG7a8y77p1T/IRQ4D1Hw== + dependencies: + escape-string-regexp "^1.0.5" + +cliui@^8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-8.0.1.tgz#0c04b075db02cbfe60dc8e6cf2f5486b1a3608aa" + integrity sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ== + dependencies: + string-width "^4.2.0" + strip-ansi "^6.0.1" + wrap-ansi "^7.0.0" + +color-convert@^1.9.0: + version "1.9.3" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" + integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== + dependencies: + color-name "1.1.3" + color-convert@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" @@ -554,12 +1093,17 @@ color-convert@^2.0.1: dependencies: color-name "~1.1.4" +color-name@1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" + integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== + color-name@~1.1.4: version "1.1.4" resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== -comment-parser@1.4.1: +comment-parser@1.4.1, comment-parser@^1.4.0: version "1.4.1" resolved "https://registry.yarnpkg.com/comment-parser/-/comment-parser-1.4.1.tgz#bdafead37961ac079be11eb7ec65c4d021eaf9cc" integrity sha512-buhp5kePrmda3vhc5B9t7pUQXAb2Tnd0qgpkIhPhkHXxJpiPJ11H0ZEU0oBpJ2QztSbzG/ZxMj/CHsYJqRHmyg== @@ -569,6 +1113,11 @@ concat-map@0.0.1: resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== +confbox@^0.1.7: + version "0.1.7" + resolved "https://registry.yarnpkg.com/confbox/-/confbox-0.1.7.tgz#ccfc0a2bcae36a84838e83a3b7f770fb17d6c579" + integrity sha512-uJcB/FKZtBMCJpK8MQji6bJHgu1tixKPxRLeGkNzBoOZzpnZUJm0jm2/sBDWcuBx1dYgxV4JU+g5hmNxCyAmdA== + consola@^3.2.3: version "3.2.3" resolved "https://registry.yarnpkg.com/consola/-/consola-3.2.3.tgz#0741857aa88cfa0d6fd53f1cff0375136e98502f" @@ -579,6 +1128,13 @@ cookie@^0.5.0: resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.5.0.tgz#d1f5d71adec6558c58f389987c366aa47e994f8b" integrity sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw== +core-js-compat@^3.37.0: + version "3.38.0" + resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.38.0.tgz#d93393b1aa346b6ee683377b0c31172ccfe607aa" + integrity sha512-75LAicdLa4OJVwFxFbQR3NdnZjNgX6ILpVcVzcC4T2smerB5lELMrJQQQoWV6TiuC/vlaFqgU2tKQx9w5s0e0A== + dependencies: + browserslist "^4.23.3" + cross-spawn@^7.0.2: version "7.0.3" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" @@ -588,6 +1144,11 @@ cross-spawn@^7.0.2: shebang-command "^2.0.0" which "^2.0.1" +cssesc@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee" + integrity sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg== + data-uri-to-buffer@^2.0.0: version "2.0.2" resolved "https://registry.yarnpkg.com/data-uri-to-buffer/-/data-uri-to-buffer-2.0.2.tgz#d296973d5a4897a5dbe31716d118211921f04770" @@ -598,30 +1159,81 @@ date-fns@^3.6.0: resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-3.6.0.tgz#f20ca4fe94f8b754951b24240676e8618c0206bf" integrity sha512-fRHTG8g/Gif+kSh50gaGEdToemgfj74aRX3swtiouboip5JDLAyDE9F11nHMIcvOaXeOC6D7SpNhi7uFyB7Uww== -debug@^4.3.1, debug@^4.3.2: - version "4.3.5" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.5.tgz#e83444eceb9fedd4a1da56d671ae2446a01a6e1e" - integrity sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg== +debug@^3.2.7: + version "3.2.7" + resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a" + integrity sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ== dependencies: - ms "2.1.2" + ms "^2.1.1" -debug@^4.3.5: +debug@^4.0.0, debug@^4.1.1, debug@^4.3.4, debug@^4.3.6: version "4.3.6" resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.6.tgz#2ab2c38fbaffebf8aa95fdfe6d88438c7a13c52b" integrity sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg== dependencies: ms "2.1.2" +debug@^4.3.1, debug@^4.3.2: + version "4.3.5" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.5.tgz#e83444eceb9fedd4a1da56d671ae2446a01a6e1e" + integrity sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg== + dependencies: + ms "2.1.2" + deep-is@^0.1.3: version "0.1.4" resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831" integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== +deepmerge@^4.2.2: + version "4.3.1" + resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.3.1.tgz#44b5f2147cd3b00d4b56137685966f26fd25dd4a" + integrity sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A== + defu@^6.1.4: version "6.1.4" resolved "https://registry.yarnpkg.com/defu/-/defu-6.1.4.tgz#4e0c9cf9ff68fe5f3d7f2765cc1a012dfdcb0479" integrity sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg== +dir-glob@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f" + integrity sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA== + dependencies: + path-type "^4.0.0" + +doctrine@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961" + integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w== + dependencies: + esutils "^2.0.2" + +electron-to-chromium@^1.5.4: + version "1.5.7" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.7.tgz#425d2a7f76ecfa564fdca1040d11fb1979851f3c" + integrity sha512-6FTNWIWMxMy/ZY6799nBlPtF1DFDQ6VQJ7yyDP27SJNt5lwtQ5ufqVvHylb3fdQefvRcgA3fKcFMJi9OLwBRNw== + +emoji-regex@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" + integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== + +enhanced-resolve@^5.17.0: + version "5.17.1" + resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.17.1.tgz#67bfbbcc2f81d511be77d686a90267ef7f898a15" + integrity sha512-LMHl3dXhTcfv8gM4kEzIUeTQ+7fpdA0l2tUf34BddXPkz2A5xJ5L/Pchd5BL6rdccM9QGvu0sWZzK1Z1t4wwyg== + dependencies: + graceful-fs "^4.2.4" + tapable "^2.2.0" + +error-ex@^1.3.1: + version "1.3.2" + resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" + integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g== + dependencies: + is-arrayish "^0.2.1" + es-module-lexer@^1.5.3: version "1.5.4" resolved "https://registry.yarnpkg.com/es-module-lexer/-/es-module-lexer-1.5.4.tgz#a8efec3a3da991e60efa6b633a7cad6ab8d26b78" @@ -655,50 +1267,168 @@ esbuild@0.17.19: "@esbuild/win32-ia32" "0.17.19" "@esbuild/win32-x64" "0.17.19" -esbuild@^0.23.0: - version "0.23.0" - resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.23.0.tgz#de06002d48424d9fdb7eb52dbe8e95927f852599" - integrity sha512-1lvV17H2bMYda/WaFb2jLPeHU3zml2k4/yagNMG8Q/YtfMjCwEUZa2eXXMgZTVSL5q1n4H7sQ0X6CdJDqqeCFA== +esbuild@^0.21.3: + version "0.21.5" + resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.21.5.tgz#9ca301b120922959b766360d8ac830da0d02997d" + integrity sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw== optionalDependencies: - "@esbuild/aix-ppc64" "0.23.0" - "@esbuild/android-arm" "0.23.0" - "@esbuild/android-arm64" "0.23.0" - "@esbuild/android-x64" "0.23.0" - "@esbuild/darwin-arm64" "0.23.0" - "@esbuild/darwin-x64" "0.23.0" - "@esbuild/freebsd-arm64" "0.23.0" - "@esbuild/freebsd-x64" "0.23.0" - "@esbuild/linux-arm" "0.23.0" - "@esbuild/linux-arm64" "0.23.0" - "@esbuild/linux-ia32" "0.23.0" - "@esbuild/linux-loong64" "0.23.0" - "@esbuild/linux-mips64el" "0.23.0" - "@esbuild/linux-ppc64" "0.23.0" - "@esbuild/linux-riscv64" "0.23.0" - "@esbuild/linux-s390x" "0.23.0" - "@esbuild/linux-x64" "0.23.0" - "@esbuild/netbsd-x64" "0.23.0" - "@esbuild/openbsd-arm64" "0.23.0" - "@esbuild/openbsd-x64" "0.23.0" - "@esbuild/sunos-x64" "0.23.0" - "@esbuild/win32-arm64" "0.23.0" - "@esbuild/win32-ia32" "0.23.0" - "@esbuild/win32-x64" "0.23.0" + "@esbuild/aix-ppc64" "0.21.5" + "@esbuild/android-arm" "0.21.5" + "@esbuild/android-arm64" "0.21.5" + "@esbuild/android-x64" "0.21.5" + "@esbuild/darwin-arm64" "0.21.5" + "@esbuild/darwin-x64" "0.21.5" + "@esbuild/freebsd-arm64" "0.21.5" + "@esbuild/freebsd-x64" "0.21.5" + "@esbuild/linux-arm" "0.21.5" + "@esbuild/linux-arm64" "0.21.5" + "@esbuild/linux-ia32" "0.21.5" + "@esbuild/linux-loong64" "0.21.5" + "@esbuild/linux-mips64el" "0.21.5" + "@esbuild/linux-ppc64" "0.21.5" + "@esbuild/linux-riscv64" "0.21.5" + "@esbuild/linux-s390x" "0.21.5" + "@esbuild/linux-x64" "0.21.5" + "@esbuild/netbsd-x64" "0.21.5" + "@esbuild/openbsd-x64" "0.21.5" + "@esbuild/sunos-x64" "0.21.5" + "@esbuild/win32-arm64" "0.21.5" + "@esbuild/win32-ia32" "0.21.5" + "@esbuild/win32-x64" "0.21.5" + +escalade@^3.1.1, escalade@^3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.2.tgz#54076e9ab29ea5bf3d8f1ed62acffbb88272df27" + integrity sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA== + +escape-string-regexp@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== escape-string-regexp@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== +eslint-compat-utils@^0.5.0, eslint-compat-utils@^0.5.1: + version "0.5.1" + resolved "https://registry.yarnpkg.com/eslint-compat-utils/-/eslint-compat-utils-0.5.1.tgz#7fc92b776d185a70c4070d03fd26fde3d59652e4" + integrity sha512-3z3vFexKIEnjHE3zCMRo6fn/e44U7T1khUjg+Hp0ZQMCigh28rALD0nPFBcGZuiLC5rLZa2ubQHDRln09JfU2Q== + dependencies: + semver "^7.5.4" + +eslint-config-flat-gitignore@^0.1.8: + version "0.1.8" + resolved "https://registry.yarnpkg.com/eslint-config-flat-gitignore/-/eslint-config-flat-gitignore-0.1.8.tgz#3a5c0ac6ed7a5d925603263b529d217088ebb005" + integrity sha512-OEUbS2wzzYtUfshjOqzFo4Bl4lHykXUdM08TCnYNl7ki+niW4Q1R0j0FDFDr0vjVsI5ZFOz5LvluxOP+Ew+dYw== + dependencies: + find-up-simple "^1.0.0" + parse-gitignore "^2.0.0" + +eslint-flat-config-utils@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/eslint-flat-config-utils/-/eslint-flat-config-utils-0.3.0.tgz#a0a24db924200225235f21e725556d4519bce90d" + integrity sha512-FaFQLUunAl6YK7aU/pT23DXYVWg/cEHbSfxwAxpCGT6Su8H9RfkmzKLh1G2bba46p6dTlQeA4VTiV5//0SeToQ== + dependencies: + "@types/eslint" "^9.6.0" + pathe "^1.1.2" + +eslint-formatting-reporter@^0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/eslint-formatting-reporter/-/eslint-formatting-reporter-0.0.0.tgz#e444c511527900dec3592e9f85876da821ab8ef7" + integrity sha512-k9RdyTqxqN/wNYVaTk/ds5B5rA8lgoAmvceYN7bcZMBwU7TuXx5ntewJv81eF3pIL/CiJE+pJZm36llG8yhyyw== + dependencies: + prettier-linter-helpers "^1.0.0" + +eslint-import-resolver-node@^0.3.9: + version "0.3.9" + resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz#d4eaac52b8a2e7c3cd1903eb00f7e053356118ac" + integrity sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g== + dependencies: + debug "^3.2.7" + is-core-module "^2.13.0" + resolve "^1.22.4" + +eslint-merge-processors@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/eslint-merge-processors/-/eslint-merge-processors-0.1.0.tgz#30ac4c59725a63d12a9677de7d2b2ec2a09fb779" + integrity sha512-IvRXXtEajLeyssvW4wJcZ2etxkR9mUf4zpNwgI+m/Uac9RfXHskuJefkHUcawVzePnd6xp24enp5jfgdHzjRdQ== + +eslint-parser-plain@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/eslint-parser-plain/-/eslint-parser-plain-0.1.0.tgz#8f7f0ac79fe4e4f47b33cf226b837ccff9d71ad6" + integrity sha512-oOeA6FWU0UJT/Rxc3XF5Cq0nbIZbylm7j8+plqq0CZoE6m4u32OXJrR+9iy4srGMmF6v6pmgvP1zPxSRIGh3sg== + +eslint-plugin-antfu@^2.3.4: + version "2.3.5" + resolved "https://registry.yarnpkg.com/eslint-plugin-antfu/-/eslint-plugin-antfu-2.3.5.tgz#99069337a66a3a88f156752d8eba094c64a73d51" + integrity sha512-q3S9q7O176sd5VyPKksN1WGtB0l8W1jeWs61xWAmbM5JdZN8q9e0Vmm+tY/YOygHfn1eK9uE4/MGyZBebdtgLA== + dependencies: + "@antfu/utils" "^0.7.10" + +eslint-plugin-command@^0.2.3: + version "0.2.3" + resolved "https://registry.yarnpkg.com/eslint-plugin-command/-/eslint-plugin-command-0.2.3.tgz#53a28215e66b66fc6e3f4790fb7e7aa0abdd5c09" + integrity sha512-1bBYNfjZg60N2ZpLV5ATYSYyueIJ+zl5yKrTs0UFDdnyu07dNSZ7Xplnc+Wb6SXTdc1sIaoIrnuyhvztcltX6A== + dependencies: + "@es-joy/jsdoccomment" "^0.43.0" + +eslint-plugin-es-x@^7.5.0: + version "7.8.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-es-x/-/eslint-plugin-es-x-7.8.0.tgz#a207aa08da37a7923f2a9599e6d3eb73f3f92b74" + integrity sha512-7Ds8+wAAoV3T+LAKeu39Y5BzXCrGKrcISfgKEqTS4BDN8SFEDQd0S43jiQ8vIa3wUKD07qitZdfzlenSi8/0qQ== + dependencies: + "@eslint-community/eslint-utils" "^4.1.2" + "@eslint-community/regexpp" "^4.11.0" + eslint-compat-utils "^0.5.1" + +eslint-plugin-eslint-comments@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-eslint-comments/-/eslint-plugin-eslint-comments-3.2.0.tgz#9e1cd7b4413526abb313933071d7aba05ca12ffa" + integrity sha512-0jkOl0hfojIHHmEHgmNdqv4fmh7300NdpA9FFpF7zaoLvB/QeXOGNLIo86oAveJFrfB1p05kC8hpEMHM8DwWVQ== + dependencies: + escape-string-regexp "^1.0.5" + ignore "^5.0.5" + +eslint-plugin-format@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/eslint-plugin-format/-/eslint-plugin-format-0.1.2.tgz#ed646b0d29e0ca2d655a1f64e162b89d633912d9" + integrity sha512-ZrcO3aiumgJ6ENAv65IWkPjtW77ML/5mp0YrRK0jdvvaZJb+4kKWbaQTMr/XbJo6CtELRmCApAziEKh7L2NbdQ== + dependencies: + "@dprint/formatter" "^0.3.0" + "@dprint/markdown" "^0.17.1" + "@dprint/toml" "^0.6.2" + eslint-formatting-reporter "^0.0.0" + eslint-parser-plain "^0.1.0" + prettier "^3.3.2" + synckit "^0.9.0" + +eslint-plugin-import-x@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-import-x/-/eslint-plugin-import-x-3.1.0.tgz#e1d132bde47c431b37f3b294d9ff813098375e7d" + integrity sha512-/UbPA+bYY7nIxcjL3kpcDY3UNdoLHFhyBFzHox2M0ypcUoueTn6woZUUmzzi5et/dXChksasYYFeKE2wshOrhg== + dependencies: + "@typescript-eslint/utils" "^7.4.0" + debug "^4.3.4" + doctrine "^3.0.0" + eslint-import-resolver-node "^0.3.9" + get-tsconfig "^4.7.3" + is-glob "^4.0.3" + minimatch "^9.0.3" + semver "^7.6.0" + stable-hash "^0.0.4" + tslib "^2.6.2" + eslint-plugin-jsdoc@^50.0.0: - version "50.0.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-50.0.0.tgz#0d064e14e1a8a3624c0474359fc51325b38b0fc9" - integrity sha512-czyJ5F7/qY2LIhUD5Bl6q1CCZ8mjvfEA9HQN5nvIp/Pb8VLIlUNd+DMZdA2OKN74QQMS3pobC06hFqAOJyOv5Q== + version "50.2.1" + resolved "https://registry.yarnpkg.com/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-50.2.1.tgz#cd1f04087172a98254749108cf4a60524acaa3d6" + integrity sha512-KbGhcct6JxzM0x1gjqH1hf4vvc+YNMag5JXyMuPFIPP9THWctRg3UgBUjNcI6a6Rw+1GdKeJ3vTmSICLVF0mtw== dependencies: - "@es-joy/jsdoccomment" "~0.46.0" + "@es-joy/jsdoccomment" "~0.48.0" are-docs-informative "^0.0.2" comment-parser "1.4.1" - debug "^4.3.5" + debug "^4.3.6" escape-string-regexp "^4.0.0" espree "^10.1.0" esquery "^1.6.0" @@ -707,6 +1437,143 @@ eslint-plugin-jsdoc@^50.0.0: spdx-expression-parse "^4.0.0" synckit "^0.9.1" +eslint-plugin-jsonc@^2.16.0: + version "2.16.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-jsonc/-/eslint-plugin-jsonc-2.16.0.tgz#e90eca15aa2e172f5aca52a77fc8c819f52862d7" + integrity sha512-Af/ZL5mgfb8FFNleH6KlO4/VdmDuTqmM+SPnWcdoWywTetv7kq+vQe99UyQb9XO3b0OWLVuTH7H0d/PXYCMdSg== + dependencies: + "@eslint-community/eslint-utils" "^4.2.0" + eslint-compat-utils "^0.5.0" + espree "^9.6.1" + graphemer "^1.4.0" + jsonc-eslint-parser "^2.0.4" + natural-compare "^1.4.0" + synckit "^0.6.0" + +eslint-plugin-markdown@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-markdown/-/eslint-plugin-markdown-5.1.0.tgz#e87724118e822cdfc89cbf1edb40248a3bc9aece" + integrity sha512-SJeyKko1K6GwI0AN6xeCDToXDkfKZfXcexA6B+O2Wr2btUS9GrC+YgwSyVli5DJnctUHjFXcQ2cqTaAmVoLi2A== + dependencies: + mdast-util-from-markdown "^0.8.5" + +eslint-plugin-n@^17.10.2: + version "17.10.2" + resolved "https://registry.yarnpkg.com/eslint-plugin-n/-/eslint-plugin-n-17.10.2.tgz#16d8d7d0b1dc076c03513bfea096f8ce1b0bcca8" + integrity sha512-e+s4eAf5NtJaxPhTNu3qMO0Iz40WANS93w9LQgYcvuljgvDmWi/a3rh+OrNyMHeng6aOWGJO0rCg5lH4zi8yTw== + dependencies: + "@eslint-community/eslint-utils" "^4.4.0" + enhanced-resolve "^5.17.0" + eslint-plugin-es-x "^7.5.0" + get-tsconfig "^4.7.0" + globals "^15.8.0" + ignore "^5.2.4" + minimatch "^9.0.5" + semver "^7.5.3" + +eslint-plugin-no-only-tests@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-no-only-tests/-/eslint-plugin-no-only-tests-3.1.0.tgz#f38e4935c6c6c4842bf158b64aaa20c366fe171b" + integrity sha512-Lf4YW/bL6Un1R6A76pRZyE1dl1vr31G/ev8UzIc/geCgFWyrKil8hVjYqWVKGB/UIGmb6Slzs9T0wNezdSVegw== + +eslint-plugin-perfectionist@^3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/eslint-plugin-perfectionist/-/eslint-plugin-perfectionist-3.1.3.tgz#61c49620bb91d76dad47735a0a75219943a63558" + integrity sha512-eFRkBvMnnHjle5MuqTzoTIukWIr7Gm2wXvhTj3HyT/ku2J5oj7quBRbvZ8iYkjPyUFBpir3ZBnVQ5vFYswvpQg== + dependencies: + "@typescript-eslint/types" "^8.0.1" + "@typescript-eslint/utils" "^8.0.1" + minimatch "^10.0.1" + natural-compare-lite "^1.4.0" + +eslint-plugin-regexp@^2.6.0: + version "2.6.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-regexp/-/eslint-plugin-regexp-2.6.0.tgz#54b9ca535662ca2c59ca211b7723ef22e2b6681b" + integrity sha512-FCL851+kislsTEQEMioAlpDuK5+E5vs0hi1bF8cFlPlHcEjeRhuAzEsGikXRreE+0j4WhW2uO54MqTjXtYOi3A== + dependencies: + "@eslint-community/eslint-utils" "^4.2.0" + "@eslint-community/regexpp" "^4.9.1" + comment-parser "^1.4.0" + jsdoc-type-pratt-parser "^4.0.0" + refa "^0.12.1" + regexp-ast-analysis "^0.7.1" + scslre "^0.3.0" + +eslint-plugin-toml@^0.11.1: + version "0.11.1" + resolved "https://registry.yarnpkg.com/eslint-plugin-toml/-/eslint-plugin-toml-0.11.1.tgz#b0d34552d417e6243770766e52d412617df45180" + integrity sha512-Y1WuMSzfZpeMIrmlP1nUh3kT8p96mThIq4NnHrYUhg10IKQgGfBZjAWnrg9fBqguiX4iFps/x/3Hb5TxBisfdw== + dependencies: + debug "^4.1.1" + eslint-compat-utils "^0.5.0" + lodash "^4.17.19" + toml-eslint-parser "^0.10.0" + +eslint-plugin-unicorn@^55.0.0: + version "55.0.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-unicorn/-/eslint-plugin-unicorn-55.0.0.tgz#e2aeb397914799895702480970e7d148df5bcc7b" + integrity sha512-n3AKiVpY2/uDcGrS3+QsYDkjPfaOrNrsfQxU9nt5nitd9KuvVXrfAvgCO9DYPSfap+Gqjw9EOrXIsBp5tlHZjA== + dependencies: + "@babel/helper-validator-identifier" "^7.24.5" + "@eslint-community/eslint-utils" "^4.4.0" + ci-info "^4.0.0" + clean-regexp "^1.0.0" + core-js-compat "^3.37.0" + esquery "^1.5.0" + globals "^15.7.0" + indent-string "^4.0.0" + is-builtin-module "^3.2.1" + jsesc "^3.0.2" + pluralize "^8.0.0" + read-pkg-up "^7.0.1" + regexp-tree "^0.1.27" + regjsparser "^0.10.0" + semver "^7.6.1" + strip-indent "^3.0.0" + +eslint-plugin-unused-imports@^4.1.3: + version "4.1.3" + resolved "https://registry.yarnpkg.com/eslint-plugin-unused-imports/-/eslint-plugin-unused-imports-4.1.3.tgz#079ef6f51914a981e657b3834935a6a417bf3f45" + integrity sha512-lqrNZIZjFMUr7P06eoKtQLwyVRibvG7N+LtfKtObYGizAAGrcqLkc3tDx+iAik2z7q0j/XI3ihjupIqxhFabFA== + +eslint-plugin-vue@^9.27.0: + version "9.27.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-vue/-/eslint-plugin-vue-9.27.0.tgz#c22dae704a03d9ecefa81364ff89f60ce0481f94" + integrity sha512-5Dw3yxEyuBSXTzT5/Ge1X5kIkRTQ3nvBn/VwPwInNiZBSJOO/timWMUaflONnFBzU6NhB68lxnCda7ULV5N7LA== + dependencies: + "@eslint-community/eslint-utils" "^4.4.0" + globals "^13.24.0" + natural-compare "^1.4.0" + nth-check "^2.1.1" + postcss-selector-parser "^6.0.15" + semver "^7.6.0" + vue-eslint-parser "^9.4.3" + xml-name-validator "^4.0.0" + +eslint-plugin-yml@^1.14.0: + version "1.14.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-yml/-/eslint-plugin-yml-1.14.0.tgz#98a019dfe4eb6837f881fb80d564df79cb05d8d9" + integrity sha512-ESUpgYPOcAYQO9czugcX5OqRvn/ydDVwGCPXY4YjPqc09rHaUVUA6IE6HLQys4rXk/S+qx3EwTd1wHCwam/OWQ== + dependencies: + debug "^4.3.2" + eslint-compat-utils "^0.5.0" + lodash "^4.17.21" + natural-compare "^1.4.0" + yaml-eslint-parser "^1.2.1" + +eslint-processor-vue-blocks@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/eslint-processor-vue-blocks/-/eslint-processor-vue-blocks-0.1.2.tgz#d472e0a5efe15e9eab5c3f2e2518c9a121097805" + integrity sha512-PfpJ4uKHnqeL/fXUnzYkOax3aIenlwewXRX8jFinA1a2yCFnLgMuiH3xvCgvHHUlV2xJWQHbCTdiJWGwb3NqpQ== + +eslint-scope@^7.1.1: + version "7.2.2" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.2.2.tgz#deb4f92563390f32006894af62a22dba1c46423f" + integrity sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg== + dependencies: + esrecurse "^4.3.0" + estraverse "^5.2.0" + eslint-scope@^8.0.2: version "8.0.2" resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-8.0.2.tgz#5cbb33d4384c9136083a71190d548158fe128f94" @@ -715,7 +1582,7 @@ eslint-scope@^8.0.2: esrecurse "^4.3.0" estraverse "^5.2.0" -eslint-visitor-keys@^3.3.0: +eslint-visitor-keys@^3.0.0, eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.1, eslint-visitor-keys@^3.4.3: version "3.4.3" resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz#0cd72fe8550e3c2eae156a96a4dddcd1c8ac5800" integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag== @@ -774,7 +1641,16 @@ espree@^10.0.1, espree@^10.1.0: acorn-jsx "^5.3.2" eslint-visitor-keys "^4.0.0" -esquery@^1.5.0, esquery@^1.6.0: +espree@^9.0.0, espree@^9.3.1, espree@^9.6.1: + version "9.6.1" + resolved "https://registry.yarnpkg.com/espree/-/espree-9.6.1.tgz#a2a17b8e434690a5432f2f8018ce71d331a48c6f" + integrity sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ== + dependencies: + acorn "^8.9.0" + acorn-jsx "^5.3.2" + eslint-visitor-keys "^3.4.1" + +esquery@^1.4.0, esquery@^1.5.0, esquery@^1.6.0: version "1.6.0" resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.6.0.tgz#91419234f804d852a82dceec3e16cdc22cf9dae7" integrity sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg== @@ -788,7 +1664,7 @@ esrecurse@^4.3.0: dependencies: estraverse "^5.2.0" -estraverse@^5.1.0, estraverse@^5.2.0: +estraverse@^5.1.0, estraverse@^5.2.0, estraverse@^5.3.0: version "5.3.0" resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== @@ -798,6 +1674,11 @@ estree-walker@^0.6.1: resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-0.6.1.tgz#53049143f40c6eb918b23671d1fe3219f3a1b362" integrity sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w== +estree-walker@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-2.0.2.tgz#52f010178c2a4c117a7757cfe942adb7d2da4cac" + integrity sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w== + esutils@^2.0.2: version "2.0.3" resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" @@ -813,6 +1694,22 @@ fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== +fast-diff@^1.1.2: + version "1.3.0" + resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.3.0.tgz#ece407fa550a64d638536cd727e129c61616e0f0" + integrity sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw== + +fast-glob@^3.2.9: + version "3.3.2" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.2.tgz#a904501e57cfdd2ffcded45e99a54fef55e46129" + integrity sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow== + dependencies: + "@nodelib/fs.stat" "^2.0.2" + "@nodelib/fs.walk" "^1.2.3" + glob-parent "^5.1.2" + merge2 "^1.3.0" + micromatch "^4.0.4" + fast-json-stable-stringify@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" @@ -844,6 +1741,19 @@ fill-range@^7.1.1: dependencies: to-regex-range "^5.0.1" +find-up-simple@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/find-up-simple/-/find-up-simple-1.0.0.tgz#21d035fde9fdbd56c8f4d2f63f32fd93a1cfc368" + integrity sha512-q7Us7kcjj2VMePAa02hDAF6d+MzsdsAWEwYyOpwUtlerRBkOEPBCRZrAV4XfcSN8fHAgaD0hP7miwoay6DCprw== + +find-up@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19" + integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw== + dependencies: + locate-path "^5.0.0" + path-exists "^4.0.0" + find-up@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc" @@ -865,7 +1775,7 @@ flatted@^3.2.9: resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.3.1.tgz#21db470729a6734d4997002f439cb308987f567a" integrity sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw== -fsevents@~2.3.2: +fsevents@~2.3.2, fsevents@~2.3.3: version "2.3.3" resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== @@ -875,6 +1785,11 @@ function-bind@^1.1.2: resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c" integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== +get-caller-file@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" + integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== + get-source@^2.0.12: version "2.0.12" resolved "https://registry.yarnpkg.com/get-source/-/get-source-2.0.12.tgz#0b47d57ea1e53ce0d3a69f4f3d277eb8047da944" @@ -883,35 +1798,76 @@ get-source@^2.0.12: data-uri-to-buffer "^2.0.0" source-map "^0.6.1" -glob-parent@^6.0.2: - version "6.0.2" - resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-6.0.2.tgz#6d237d99083950c79290f24c7642a3de9a28f9e3" - integrity sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A== +get-tsconfig@^4.7.0, get-tsconfig@^4.7.3: + version "4.7.6" + resolved "https://registry.yarnpkg.com/get-tsconfig/-/get-tsconfig-4.7.6.tgz#118fd5b7b9bae234cc7705a00cd771d7eb65d62a" + integrity sha512-ZAqrLlu18NbDdRaHq+AKXzAmqIUPswPWKUchfytdAjiRFnCe5ojG2bstg6mRiZabkKfCoL/e98pbBELIV/YCeA== dependencies: - is-glob "^4.0.3" + resolve-pkg-maps "^1.0.0" -glob-parent@~5.1.2: +glob-parent@^5.1.2, glob-parent@~5.1.2: version "5.1.2" resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== dependencies: is-glob "^4.0.1" +glob-parent@^6.0.2: + version "6.0.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-6.0.2.tgz#6d237d99083950c79290f24c7642a3de9a28f9e3" + integrity sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A== + dependencies: + is-glob "^4.0.3" + glob-to-regexp@^0.4.1: version "0.4.1" resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz#c75297087c851b9a578bd217dd59a92f59fe546e" integrity sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw== +globals@^13.24.0: + version "13.24.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-13.24.0.tgz#8432a19d78ce0c1e833949c36adb345400bb1171" + integrity sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ== + dependencies: + type-fest "^0.20.2" + globals@^14.0.0: version "14.0.0" resolved "https://registry.yarnpkg.com/globals/-/globals-14.0.0.tgz#898d7413c29babcf6bafe56fcadded858ada724e" integrity sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ== -globals@^15.9.0: +globals@^15.7.0, globals@^15.8.0, globals@^15.9.0: version "15.9.0" resolved "https://registry.yarnpkg.com/globals/-/globals-15.9.0.tgz#e9de01771091ffbc37db5714dab484f9f69ff399" integrity sha512-SmSKyLLKFbSr6rptvP8izbyxJL4ILwqO9Jg23UA0sDlGlu58V59D1//I3vlc0KJphVdUR7vMjHIplYnzBxorQA== +globby@^11.1.0: + version "11.1.0" + resolved "https://registry.yarnpkg.com/globby/-/globby-11.1.0.tgz#bd4be98bb042f83d796f7e3811991fbe82a0d34b" + integrity sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g== + dependencies: + array-union "^2.1.0" + dir-glob "^3.0.1" + fast-glob "^3.2.9" + ignore "^5.2.0" + merge2 "^1.4.1" + slash "^3.0.0" + +graceful-fs@^4.2.4: + version "4.2.11" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" + integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== + +graphemer@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/graphemer/-/graphemer-1.4.0.tgz#fb2f1d55e0e3a1849aeffc90c4fa0dd53a0e66c6" + integrity sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag== + +has-flag@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" + integrity sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw== + has-flag@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" @@ -924,6 +1880,16 @@ hasown@^2.0.2: dependencies: function-bind "^1.1.2" +hosted-git-info@^2.1.4: + version "2.8.9" + resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.9.tgz#dffc0bf9a21c02209090f2aa69429e1414daf3f9" + integrity sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw== + +ignore@^5.0.5, ignore@^5.2.4, ignore@^5.3.1: + version "5.3.2" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.2.tgz#3cd40e729f3643fd87cb04e50bf0eb722bc596f5" + integrity sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g== + ignore@^5.2.0: version "5.3.1" resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.1.tgz#5073e554cd42c5b33b394375f538b8593e34d4ef" @@ -942,6 +1908,29 @@ imurmurhash@^0.1.4: resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" integrity sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA== +indent-string@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-4.0.0.tgz#624f8f4497d619b2d9768531d58f4122854d7251" + integrity sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg== + +is-alphabetical@^1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-alphabetical/-/is-alphabetical-1.0.4.tgz#9e7d6b94916be22153745d184c298cbf986a686d" + integrity sha512-DwzsA04LQ10FHTZuL0/grVDk4rFoVH1pjAToYwBrHSxcrBIGQuXrQMtD5U1b0U2XVgKZCTLLP8u2Qxqhy3l2Vg== + +is-alphanumerical@^1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-alphanumerical/-/is-alphanumerical-1.0.4.tgz#7eb9a2431f855f6b1ef1a78e326df515696c4dbf" + integrity sha512-UzoZUr+XfVz3t3v4KyGEniVL9BDRoQtY7tOyrRybkVNjDFWyo1yhXNGrrBTQxp3ib9BLAWs7k2YKBQsFRkZG9A== + dependencies: + is-alphabetical "^1.0.0" + is-decimal "^1.0.0" + +is-arrayish@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" + integrity sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg== + is-binary-path@~2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" @@ -949,6 +1938,13 @@ is-binary-path@~2.1.0: dependencies: binary-extensions "^2.0.0" +is-builtin-module@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/is-builtin-module/-/is-builtin-module-3.2.1.tgz#f03271717d8654cfcaf07ab0463faa3571581169" + integrity sha512-BSLE3HnV2syZ0FK0iMA/yUGplUeMmNz4AW5fnTunbCIqZi4vG3WjJT9FHMy5D69xmAYBHXQhJdALdpwVxV501A== + dependencies: + builtin-modules "^3.3.0" + is-core-module@^2.13.0: version "2.15.0" resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.15.0.tgz#71c72ec5442ace7e76b306e9d48db361f22699ea" @@ -956,11 +1952,21 @@ is-core-module@^2.13.0: dependencies: hasown "^2.0.2" +is-decimal@^1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-decimal/-/is-decimal-1.0.4.tgz#65a3a5958a1c5b63a706e1b333d7cd9f630d3fa5" + integrity sha512-RGdriMmQQvZ2aqaQq3awNA6dCGtKpiDFcOzrTWrDAT2MiWrKQVPmxLGHl7Y2nNu6led0kEyoX0enY0qXYsv9zw== + is-extglob@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== +is-fullwidth-code-point@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" + integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== + is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3, is-glob@~4.0.1: version "4.0.3" resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" @@ -968,6 +1974,16 @@ is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3, is-glob@~4.0.1: dependencies: is-extglob "^2.1.1" +is-hexadecimal@^1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-hexadecimal/-/is-hexadecimal-1.0.4.tgz#cc35c97588da4bd49a8eedd6bc4082d44dcb23a7" + integrity sha512-gyPJuv83bHMpocVYoqof5VDiZveEoGoFL8m3BXNb2VW8Xs+rz9kqO8LOQ5DH6EsuvilT1ApazU0pyl+ytbPtlw== + +is-module@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-module/-/is-module-1.0.0.tgz#3258fb69f78c14d5b815d664336b4cffb6441591" + integrity sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g== + is-number@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" @@ -983,6 +1999,20 @@ isexe@^2.0.0: resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== +js-cleanup@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/js-cleanup/-/js-cleanup-1.2.0.tgz#8dbc65954b1d38b255f1e8cf02cd17b3f7a053f9" + integrity sha512-JeDD0yiiSt80fXzAVa/crrS0JDPQljyBG/RpOtaSbyDq03VHa9szJWMaWOYU/bcTn412uMN2MxApXq8v79cUiQ== + dependencies: + magic-string "^0.25.7" + perf-regexes "^1.0.1" + skip-regex "^1.0.2" + +js-tokens@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" + integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== + js-yaml@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" @@ -990,16 +2020,36 @@ js-yaml@^4.1.0: dependencies: argparse "^2.0.1" +jsdoc-type-pratt-parser@^4.0.0, jsdoc-type-pratt-parser@~4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-4.1.0.tgz#ff6b4a3f339c34a6c188cbf50a16087858d22113" + integrity sha512-Hicd6JK5Njt2QB6XYFS7ok9e37O8AYk3jTcppG4YVQnYjOemymvTcmc7OWsmq/Qqj5TdRFO5/x/tIPmBeRtGHg== + jsdoc-type-pratt-parser@~4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-4.0.0.tgz#136f0571a99c184d84ec84662c45c29ceff71114" integrity sha512-YtOli5Cmzy3q4dP26GraSOeAhqecewG04hoO8DY56CH4KJ9Fvv5qKWUCCo3HZob7esJQHCv6/+bnTy72xZZaVQ== +jsesc@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-3.0.2.tgz#bb8b09a6597ba426425f2e4a07245c3d00b9343e" + integrity sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g== + +jsesc@~0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" + integrity sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA== + json-buffer@3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.1.tgz#9338802a30d3b6605fbe0613e094008ca8c05a13" integrity sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ== +json-parse-even-better-errors@^2.3.0: + version "2.3.1" + resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d" + integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w== + json-schema-traverse@^0.4.1: version "0.4.1" resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" @@ -1010,6 +2060,16 @@ json-stable-stringify-without-jsonify@^1.0.1: resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" integrity sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw== +jsonc-eslint-parser@^2.0.4, jsonc-eslint-parser@^2.4.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/jsonc-eslint-parser/-/jsonc-eslint-parser-2.4.0.tgz#74ded53f9d716e8d0671bd167bf5391f452d5461" + integrity sha512-WYDyuc/uFcGp6YtM2H0uKmUwieOuzeE/5YocFJLnLfclZ4inf3mRn8ZVy1s7Hxji7Jxm6Ss8gqpexD/GlKoGgg== + dependencies: + acorn "^8.5.0" + eslint-visitor-keys "^3.0.0" + espree "^9.0.0" + semver "^7.3.5" + keyv@^4.5.4: version "4.5.4" resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.5.4.tgz#a879a99e29452f942439f2a405e3af8b31d4de93" @@ -1025,6 +2085,26 @@ levn@^0.4.1: prelude-ls "^1.2.1" type-check "~0.4.0" +lines-and-columns@^1.1.6: + version "1.2.4" + resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632" + integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg== + +local-pkg@^0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/local-pkg/-/local-pkg-0.5.0.tgz#093d25a346bae59a99f80e75f6e9d36d7e8c925c" + integrity sha512-ok6z3qlYyCDS4ZEU27HaU6x/xZa9Whf8jD4ptH5UZTQYZVYeb9bnZ3ojVhiJNLiXK1Hfc0GNbLXcmZ5plLDDBg== + dependencies: + mlly "^1.4.2" + pkg-types "^1.0.3" + +locate-path@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0" + integrity sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g== + dependencies: + p-locate "^4.1.0" + locate-path@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286" @@ -1037,18 +2117,65 @@ lodash.merge@^4.6.2: resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== -magic-string@^0.25.3: +lodash@^4.17.19, lodash@^4.17.21: + version "4.17.21" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" + integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== + +magic-string@^0.25.3, magic-string@^0.25.7: version "0.25.9" resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.25.9.tgz#de7f9faf91ef8a1c91d02c2e5314c8277dbcdd1c" integrity sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ== dependencies: sourcemap-codec "^1.4.8" +mdast-util-from-markdown@^0.8.5: + version "0.8.5" + resolved "https://registry.yarnpkg.com/mdast-util-from-markdown/-/mdast-util-from-markdown-0.8.5.tgz#d1ef2ca42bc377ecb0463a987910dae89bd9a28c" + integrity sha512-2hkTXtYYnr+NubD/g6KGBS/0mFmBcifAsI0yIWRiRo0PjVs6SSOSOdtzbp6kSGnShDN6G5aWZpKQ2lWRy27mWQ== + dependencies: + "@types/mdast" "^3.0.0" + mdast-util-to-string "^2.0.0" + micromark "~2.11.0" + parse-entities "^2.0.0" + unist-util-stringify-position "^2.0.0" + +mdast-util-to-string@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/mdast-util-to-string/-/mdast-util-to-string-2.0.0.tgz#b8cfe6a713e1091cb5b728fc48885a4767f8b97b" + integrity sha512-AW4DRS3QbBayY/jJmD8437V1Gombjf8RSOUCMFBuo5iHi58AGEgVCKQ+ezHkZZDpAQS75hcBMpLqjpJTjtUL7w== + +merge2@^1.3.0, merge2@^1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" + integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== + +micromark@~2.11.0: + version "2.11.4" + resolved "https://registry.yarnpkg.com/micromark/-/micromark-2.11.4.tgz#d13436138eea826383e822449c9a5c50ee44665a" + integrity sha512-+WoovN/ppKolQOFIAajxi7Lu9kInbPxFuTBVEavFcL8eAfVstoc5MocPmqBeAdBOJV00uaVjegzH4+MA0DN/uA== + dependencies: + debug "^4.0.0" + parse-entities "^2.0.0" + +micromatch@^4.0.4: + version "4.0.7" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.7.tgz#33e8190d9fe474a9895525f5618eee136d46c2e5" + integrity sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q== + dependencies: + braces "^3.0.3" + picomatch "^2.3.1" + mime@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/mime/-/mime-3.0.0.tgz#b374550dca3a0c18443b0c950a6a58f1931cf7a7" integrity sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A== +min-indent@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/min-indent/-/min-indent-1.0.1.tgz#a63f681673b30571fbe8bc25686ae746eefa9869" + integrity sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg== + miniflare@3.20240725.0: version "3.20240725.0" resolved "https://registry.yarnpkg.com/miniflare/-/miniflare-3.20240725.0.tgz#8d4683a4d0f8de260514a0df8d83da558eebec5c" @@ -1067,6 +2194,13 @@ miniflare@3.20240725.0: youch "^3.2.2" zod "^3.22.3" +minimatch@^10.0.1: + version "10.0.1" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-10.0.1.tgz#ce0521856b453c86e25f2c4c0d03e6ff7ddc440b" + integrity sha512-ethXTt3SGGR+95gudmqJ1eNhRO7eGEGIgYA9vnPatK4/etz2MEVDno5GMCibdMTuBMyElzIlgxMna3K94XDIDQ== + dependencies: + brace-expansion "^2.0.1" + minimatch@^3.1.2: version "3.1.2" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" @@ -1074,21 +2208,48 @@ minimatch@^3.1.2: dependencies: brace-expansion "^1.1.7" +minimatch@^9.0.3, minimatch@^9.0.4, minimatch@^9.0.5: + version "9.0.5" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.5.tgz#d74f9dd6b57d83d8e98cfb82133b03978bc929e5" + integrity sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow== + dependencies: + brace-expansion "^2.0.1" + +mlly@^1.4.2, mlly@^1.7.1: + version "1.7.1" + resolved "https://registry.yarnpkg.com/mlly/-/mlly-1.7.1.tgz#e0336429bb0731b6a8e887b438cbdae522c8f32f" + integrity sha512-rrVRZRELyQzrIUAVMHxP97kv+G786pHmOKzuFII8zDYahFBS7qnHh2AlYSl1GAHhaMPCz6/oHjVMcfFYgFYHgA== + dependencies: + acorn "^8.11.3" + pathe "^1.1.2" + pkg-types "^1.1.1" + ufo "^1.5.3" + ms@2.1.2: version "2.1.2" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== +ms@^2.1.1: + version "2.1.3" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" + integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== + mustache@^4.2.0: version "4.2.0" resolved "https://registry.yarnpkg.com/mustache/-/mustache-4.2.0.tgz#e5892324d60a12ec9c2a73359edca52972bf6f64" integrity sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ== -nanoid@^3.3.3: +nanoid@^3.3.3, nanoid@^3.3.7: version "3.3.7" resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.7.tgz#d0c301a691bc8d54efa0a2226ccf3fe2fd656bd8" integrity sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g== +natural-compare-lite@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz#17b09581988979fddafe0201e931ba933c96cbb4" + integrity sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g== + natural-compare@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" @@ -1104,11 +2265,33 @@ node-forge@^1: resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-1.3.1.tgz#be8da2af243b2417d5f646a770663a92b7e9ded3" integrity sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA== +node-releases@^2.0.18: + version "2.0.18" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.18.tgz#f010e8d35e2fe8d6b2944f03f70213ecedc4ca3f" + integrity sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g== + +normalize-package-data@^2.5.0: + version "2.5.0" + resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8" + integrity sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA== + dependencies: + hosted-git-info "^2.1.4" + resolve "^1.10.0" + semver "2 || 3 || 4 || 5" + validate-npm-package-license "^3.0.1" + normalize-path@^3.0.0, normalize-path@~3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== +nth-check@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/nth-check/-/nth-check-2.1.1.tgz#c9eab428effce36cd6b92c924bdb000ef1f1ed1d" + integrity sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w== + dependencies: + boolbase "^1.0.0" + optionator@^0.9.3: version "0.9.4" resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.4.tgz#7ea1c1a5d91d764fb282139c88fe11e182a3a734" @@ -1121,6 +2304,13 @@ optionator@^0.9.3: type-check "^0.4.0" word-wrap "^1.2.5" +p-limit@^2.2.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" + integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w== + dependencies: + p-try "^2.0.0" + p-limit@^3.0.2: version "3.1.0" resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" @@ -1128,6 +2318,13 @@ p-limit@^3.0.2: dependencies: yocto-queue "^0.1.0" +p-locate@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07" + integrity sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A== + dependencies: + p-limit "^2.2.0" + p-locate@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834" @@ -1135,6 +2332,11 @@ p-locate@^5.0.0: dependencies: p-limit "^3.0.2" +p-try@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" + integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== + parent-module@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" @@ -1142,6 +2344,23 @@ parent-module@^1.0.0: dependencies: callsites "^3.0.0" +parse-entities@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/parse-entities/-/parse-entities-2.0.0.tgz#53c6eb5b9314a1f4ec99fa0fdf7ce01ecda0cbe8" + integrity sha512-kkywGpCcRYhqQIchaWqZ875wzpS/bMKhz5HnN3p7wveJTkTtyAB/AlnS0f8DFSqYW1T82t6yEAkEcB+A1I3MbQ== + dependencies: + character-entities "^1.0.0" + character-entities-legacy "^1.0.0" + character-reference-invalid "^1.0.0" + is-alphanumerical "^1.0.0" + is-decimal "^1.0.0" + is-hexadecimal "^1.0.0" + +parse-gitignore@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/parse-gitignore/-/parse-gitignore-2.0.0.tgz#81156b265115c507129f3faea067b8476da3b642" + integrity sha512-RmVuCHWsfu0QPNW+mraxh/xjQVw/lhUCUru8Zni3Ctq3AoMhpDTq0OVdKS6iesd6Kqb7viCV3isAL43dciOSog== + parse-imports@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/parse-imports/-/parse-imports-2.1.1.tgz#ce52141df24990065d72a446a364bffd595577f4" @@ -1150,6 +2369,16 @@ parse-imports@^2.1.1: es-module-lexer "^1.5.3" slashes "^3.0.12" +parse-json@^5.0.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd" + integrity sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg== + dependencies: + "@babel/code-frame" "^7.0.0" + error-ex "^1.3.1" + json-parse-even-better-errors "^2.3.0" + lines-and-columns "^1.1.6" + path-exists@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" @@ -1170,21 +2399,84 @@ path-to-regexp@^6.2.0: resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-6.2.2.tgz#324377a83e5049cbecadc5554d6a63a9a4866b36" integrity sha512-GQX3SSMokngb36+whdpRXE+3f9V8UzyAorlYvOGx87ufGHehNTn5lCxrKtLyZ4Yl/wEKnNnr98ZzOwwDZV5ogw== +path-type@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" + integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== + pathe@^1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/pathe/-/pathe-1.1.2.tgz#6c4cb47a945692e48a1ddd6e4094d170516437ec" integrity sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ== -picomatch@^2.0.4, picomatch@^2.2.1: +perf-regexes@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/perf-regexes/-/perf-regexes-1.0.1.tgz#6da1d62f5a94bf9353a0451bccacf69068b75d0b" + integrity sha512-L7MXxUDtqr4PUaLFCDCXBfGV/6KLIuSEccizDI7JxT+c9x1G1v04BQ4+4oag84SHaCdrBgQAIs/Cqn+flwFPng== + +picocolors@^1.0.0, picocolors@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.1.tgz#a8ad579b571952f0e5d25892de5445bcfe25aaa1" + integrity sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew== + +picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.3.1: version "2.3.1" resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== +picomatch@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-4.0.2.tgz#77c742931e8f3b8820946c76cd0c1f13730d1dab" + integrity sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg== + +pkg-types@^1.0.3, pkg-types@^1.1.1: + version "1.1.3" + resolved "https://registry.yarnpkg.com/pkg-types/-/pkg-types-1.1.3.tgz#161bb1242b21daf7795036803f28e30222e476e3" + integrity sha512-+JrgthZG6m3ckicaOB74TwQ+tBWsFl3qVQg7mN8ulwSOElJ7gBhKzj2VkCPnZ4NlF6kEquYU+RIYNVAvzd54UA== + dependencies: + confbox "^0.1.7" + mlly "^1.7.1" + pathe "^1.1.2" + +pluralize@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-8.0.0.tgz#1a6fa16a38d12a1901e0320fa017051c539ce3b1" + integrity sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA== + +postcss-selector-parser@^6.0.15: + version "6.1.2" + resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz#27ecb41fb0e3b6ba7a1ec84fff347f734c7929de" + integrity sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg== + dependencies: + cssesc "^3.0.0" + util-deprecate "^1.0.2" + +postcss@^8.4.41: + version "8.4.41" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.41.tgz#d6104d3ba272d882fe18fc07d15dc2da62fa2681" + integrity sha512-TesUflQ0WKZqAvg52PWL6kHgLKP6xB6heTOdoYM0Wt2UHyxNa4K25EZZMgKns3BH1RLVbZCREPpLY0rhnNoHVQ== + dependencies: + nanoid "^3.3.7" + picocolors "^1.0.1" + source-map-js "^1.2.0" + prelude-ls@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== +prettier-linter-helpers@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz#d23d41fe1375646de2d0104d3454a3008802cf7b" + integrity sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w== + dependencies: + fast-diff "^1.1.2" + +prettier@^3.3.2: + version "3.3.3" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.3.3.tgz#30c54fe0be0d8d12e6ae61dbb10109ea00d53105" + integrity sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew== + printable-characters@^1.0.42: version "1.0.42" resolved "https://registry.yarnpkg.com/printable-characters/-/printable-characters-1.0.42.tgz#3f18e977a9bd8eb37fcc4ff5659d7be90868b3d8" @@ -1200,6 +2492,25 @@ queue-microtask@^1.2.2: resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== +read-pkg-up@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-7.0.1.tgz#f3a6135758459733ae2b95638056e1854e7ef507" + integrity sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg== + dependencies: + find-up "^4.1.0" + read-pkg "^5.2.0" + type-fest "^0.8.1" + +read-pkg@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-5.2.0.tgz#7bf295438ca5a33e56cd30e053b34ee7250c93cc" + integrity sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg== + dependencies: + "@types/normalize-package-data" "^2.4.0" + normalize-package-data "^2.5.0" + parse-json "^5.0.0" + type-fest "^0.6.0" + readdirp@~3.6.0: version "3.6.0" resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" @@ -1207,17 +2518,54 @@ readdirp@~3.6.0: dependencies: picomatch "^2.2.1" +refa@^0.12.0, refa@^0.12.1: + version "0.12.1" + resolved "https://registry.yarnpkg.com/refa/-/refa-0.12.1.tgz#dac13c4782dc22b6bae6cce81a2b863888ea39c6" + integrity sha512-J8rn6v4DBb2nnFqkqwy6/NnTYMcgLA+sLr0iIO41qpv0n+ngb7ksag2tMRl0inb1bbO/esUwzW1vbJi7K0sI0g== + dependencies: + "@eslint-community/regexpp" "^4.8.0" + +regexp-ast-analysis@^0.7.0, regexp-ast-analysis@^0.7.1: + version "0.7.1" + resolved "https://registry.yarnpkg.com/regexp-ast-analysis/-/regexp-ast-analysis-0.7.1.tgz#c0e24cb2a90f6eadd4cbaaba129317e29d29c482" + integrity sha512-sZuz1dYW/ZsfG17WSAG7eS85r5a0dDsvg+7BiiYR5o6lKCAtUrEwdmRmaGF6rwVj3LcmAeYkOWKEPlbPzN3Y3A== + dependencies: + "@eslint-community/regexpp" "^4.8.0" + refa "^0.12.1" + +regexp-tree@^0.1.27: + version "0.1.27" + resolved "https://registry.yarnpkg.com/regexp-tree/-/regexp-tree-0.1.27.tgz#2198f0ef54518ffa743fe74d983b56ffd631b6cd" + integrity sha512-iETxpjK6YoRWJG5o6hXLwvjYAoW+FEZn9os0PD/b6AP6xQwsa/Y7lCVgIixBbUPMfhu+i2LtdeAqVTgGlQarfA== + +regjsparser@^0.10.0: + version "0.10.0" + resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.10.0.tgz#b1ed26051736b436f22fdec1c8f72635f9f44892" + integrity sha512-qx+xQGZVsy55CH0a1hiVwHmqjLryfh7wQyF5HO07XJ9f7dQMY/gPQHhlyDkIzJKC+x2fUCpCcUODUUUFrm7SHA== + dependencies: + jsesc "~0.5.0" + +require-directory@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" + integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q== + resolve-from@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== +resolve-pkg-maps@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz#616b3dc2c57056b5588c31cdf4b3d64db133720f" + integrity sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw== + resolve.exports@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/resolve.exports/-/resolve.exports-2.0.2.tgz#f8c934b8e6a13f539e38b7098e2e36134f01e800" integrity sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg== -resolve@^1.22.8: +resolve@^1.10.0, resolve@^1.22.1, resolve@^1.22.4, resolve@^1.22.8: version "1.22.8" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.8.tgz#b6c87a9f2aa06dfab52e3d70ac8cde321fa5a48d" integrity sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw== @@ -1231,6 +2579,14 @@ reusify@^1.0.4: resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== +rollup-plugin-cleanup@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/rollup-plugin-cleanup/-/rollup-plugin-cleanup-3.2.1.tgz#8cbc92ecf58babd7c210051929797f137bbf777c" + integrity sha512-zuv8EhoO3TpnrU8MX8W7YxSbO4gmOR0ny06Lm3nkFfq0IVKdBUtHwhVzY1OAJyNCIAdLiyPnOrU0KnO0Fri1GQ== + dependencies: + js-cleanup "^1.2.0" + rollup-pluginutils "^2.8.2" + rollup-plugin-inject@^3.0.0: version "3.0.2" resolved "https://registry.yarnpkg.com/rollup-plugin-inject/-/rollup-plugin-inject-3.0.2.tgz#e4233855bfba6c0c12a312fd6649dff9a13ee9f4" @@ -1247,13 +2603,38 @@ rollup-plugin-node-polyfills@^0.2.1: dependencies: rollup-plugin-inject "^3.0.0" -rollup-pluginutils@^2.8.1: +rollup-pluginutils@^2.8.1, rollup-pluginutils@^2.8.2: version "2.8.2" resolved "https://registry.yarnpkg.com/rollup-pluginutils/-/rollup-pluginutils-2.8.2.tgz#72f2af0748b592364dbd3389e600e5a9444a351e" integrity sha512-EEp9NhnUkwY8aif6bxgovPHMoMoNr2FulJziTndpt5H9RdwC47GSGuII9XxpSdzVGM0GWrNPHV6ie1LTNJPaLQ== dependencies: estree-walker "^0.6.1" +rollup@^4.13.0: + version "4.21.0" + resolved "https://registry.yarnpkg.com/rollup/-/rollup-4.21.0.tgz#28db5f5c556a5180361d35009979ccc749560b9d" + integrity sha512-vo+S/lfA2lMS7rZ2Qoubi6I5hwZwzXeUIctILZLbHI+laNtvhhOIon2S1JksA5UEDQ7l3vberd0fxK44lTYjbQ== + dependencies: + "@types/estree" "1.0.5" + optionalDependencies: + "@rollup/rollup-android-arm-eabi" "4.21.0" + "@rollup/rollup-android-arm64" "4.21.0" + "@rollup/rollup-darwin-arm64" "4.21.0" + "@rollup/rollup-darwin-x64" "4.21.0" + "@rollup/rollup-linux-arm-gnueabihf" "4.21.0" + "@rollup/rollup-linux-arm-musleabihf" "4.21.0" + "@rollup/rollup-linux-arm64-gnu" "4.21.0" + "@rollup/rollup-linux-arm64-musl" "4.21.0" + "@rollup/rollup-linux-powerpc64le-gnu" "4.21.0" + "@rollup/rollup-linux-riscv64-gnu" "4.21.0" + "@rollup/rollup-linux-s390x-gnu" "4.21.0" + "@rollup/rollup-linux-x64-gnu" "4.21.0" + "@rollup/rollup-linux-x64-musl" "4.21.0" + "@rollup/rollup-win32-arm64-msvc" "4.21.0" + "@rollup/rollup-win32-ia32-msvc" "4.21.0" + "@rollup/rollup-win32-x64-msvc" "4.21.0" + fsevents "~2.3.2" + run-parallel@^1.1.9: version "1.2.0" resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" @@ -1261,6 +2642,15 @@ run-parallel@^1.1.9: dependencies: queue-microtask "^1.2.2" +scslre@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/scslre/-/scslre-0.3.0.tgz#c3211e9bfc5547fc86b1eabaa34ed1a657060155" + integrity sha512-3A6sD0WYP7+QrjbfNA2FN3FsOaGGFoekCVgTyypy53gPxhbkCIjtO6YWgdrfM+n/8sI8JeXZOIxsHjMTNxQ4nQ== + dependencies: + "@eslint-community/regexpp" "^4.8.0" + refa "^0.12.0" + regexp-ast-analysis "^0.7.0" + selfsigned@^2.0.1: version "2.4.1" resolved "https://registry.yarnpkg.com/selfsigned/-/selfsigned-2.4.1.tgz#560d90565442a3ed35b674034cec4e95dceb4ae0" @@ -1269,7 +2659,12 @@ selfsigned@^2.0.1: "@types/node-forge" "^1.3.0" node-forge "^1" -semver@^7.6.3: +"semver@2 || 3 || 4 || 5": + version "5.7.2" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.2.tgz#48d55db737c3287cd4835e17fa13feace1c41ef8" + integrity sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g== + +semver@^7.3.5, semver@^7.3.6, semver@^7.5.3, semver@^7.5.4, semver@^7.6.0, semver@^7.6.1, semver@^7.6.3: version "7.6.3" resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.3.tgz#980f7b5550bc175fb4dc09403085627f9eb33143" integrity sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A== @@ -1286,11 +2681,31 @@ shebang-regex@^3.0.0: resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== +sisteransi@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/sisteransi/-/sisteransi-1.0.5.tgz#134d681297756437cc05ca01370d3a7a571075ed" + integrity sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg== + +skip-regex@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/skip-regex/-/skip-regex-1.0.2.tgz#ac655d77e7c771ac2b9f37585fea37bff56ad65b" + integrity sha512-pEjMUbwJ5Pl/6Vn6FsamXHXItJXSRftcibixDmNCWbWhic0hzHrwkMZo0IZ7fMRH9KxcWDFSkzhccB4285PutA== + +slash@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" + integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== + slashes@^3.0.12: version "3.0.12" resolved "https://registry.yarnpkg.com/slashes/-/slashes-3.0.12.tgz#3d664c877ad542dc1509eaf2c50f38d483a6435a" integrity sha512-Q9VME8WyGkc7pJf6QEkj3wE+2CnvZMI+XJhwdTPR8Z/kWQRXi7boAWLDibRPyHRTUTPx5FaU7MsyrjI3yLB4HA== +source-map-js@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.2.0.tgz#16b809c162517b5b8c3e7dcd315a2a5c2612b2af" + integrity sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg== + source-map@^0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" @@ -1301,11 +2716,27 @@ sourcemap-codec@^1.4.8: resolved "https://registry.yarnpkg.com/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz#ea804bd94857402e6992d05a38ef1ae35a9ab4c4" integrity sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA== +spdx-correct@^3.0.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.2.0.tgz#4f5ab0668f0059e34f9c00dce331784a12de4e9c" + integrity sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA== + dependencies: + spdx-expression-parse "^3.0.0" + spdx-license-ids "^3.0.0" + spdx-exceptions@^2.1.0: version "2.5.0" resolved "https://registry.yarnpkg.com/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz#5d607d27fc806f66d7b64a766650fa890f04ed66" integrity sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w== +spdx-expression-parse@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz#cf70f50482eefdc98e3ce0a6833e4a53ceeba679" + integrity sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q== + dependencies: + spdx-exceptions "^2.1.0" + spdx-license-ids "^3.0.0" + spdx-expression-parse@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-4.0.0.tgz#a23af9f3132115465dac215c099303e4ceac5794" @@ -1319,6 +2750,11 @@ spdx-license-ids@^3.0.0: resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.18.tgz#22aa922dcf2f2885a6494a261f2d8b75345d0326" integrity sha512-xxRs31BqRYHwiMzudOrpSiHtZ8i/GeionCBDSilhYRj+9gIcI8wCZTlXZKu9vZIVqViP3dcp9qE5G6AlIaD+TQ== +stable-hash@^0.0.4: + version "0.0.4" + resolved "https://registry.yarnpkg.com/stable-hash/-/stable-hash-0.0.4.tgz#55ae7dadc13e4b3faed13601587cec41859b42f7" + integrity sha512-LjdcbuBeLcdETCrPn9i8AYAZ1eCtu4ECAWtP7UleOiZ9LzVxRzzUZEoZ8zB24nhkQnDWyET0I+3sWokSDS3E7g== + stacktracey@^2.1.8: version "2.1.8" resolved "https://registry.yarnpkg.com/stacktracey/-/stacktracey-2.1.8.tgz#bf9916020738ce3700d1323b32bd2c91ea71199d" @@ -1332,18 +2768,41 @@ stoppable@^1.1.0: resolved "https://registry.yarnpkg.com/stoppable/-/stoppable-1.1.0.tgz#32da568e83ea488b08e4d7ea2c3bcc9d75015d5b" integrity sha512-KXDYZ9dszj6bzvnEMRYvxgeTHU74QBFL54XKtP3nyMuJ81CFYtABZ3bAzL2EdFUaEwJOBOgENyFj3R7oTzDyyw== -strip-ansi@^6.0.1: +string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: + version "4.2.3" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + +strip-ansi@^6.0.0, strip-ansi@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== dependencies: ansi-regex "^5.0.1" +strip-indent@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-3.0.0.tgz#c32e1cee940b6b3432c771bc2c54bcce73cd3001" + integrity sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ== + dependencies: + min-indent "^1.0.0" + strip-json-comments@^3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== +supports-color@^5.3.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" + integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== + dependencies: + has-flag "^3.0.0" + supports-color@^7.1.0: version "7.2.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" @@ -1356,7 +2815,14 @@ supports-preserve-symlinks-flag@^1.0.0: resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== -synckit@^0.9.1: +synckit@^0.6.0: + version "0.6.2" + resolved "https://registry.yarnpkg.com/synckit/-/synckit-0.6.2.tgz#e1540b97825f2855f7170b98276e8463167f33eb" + integrity sha512-Vhf+bUa//YSTYKseDiiEuQmhGCoIF3CVBhunm3r/DQnYiGT4JssmnKQc44BIyOZRK2pKjXXAgbhfmbeoC9CJpA== + dependencies: + tslib "^2.3.1" + +synckit@^0.9.0, synckit@^0.9.1: version "0.9.1" resolved "https://registry.yarnpkg.com/synckit/-/synckit-0.9.1.tgz#febbfbb6649979450131f64735aa3f6c14575c88" integrity sha512-7gr8p9TQP6RAHusBOSLs46F4564ZrjV8xFmw5zCmgmhGUcw2hxsShhJ6CEiHQMgPDwAQ1fWHPM0ypc4RMAig4A== @@ -1364,11 +2830,21 @@ synckit@^0.9.1: "@pkgr/core" "^0.1.0" tslib "^2.6.2" +tapable@^2.2.0: + version "2.2.1" + resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.2.1.tgz#1967a73ef4060a82f12ab96af86d52fdb76eeca0" + integrity sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ== + text-table@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw== +tinyexec@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/tinyexec/-/tinyexec-0.1.4.tgz#29d24b14294bddcd35d78cab9730e05b725a9fd8" + integrity sha512-Ba2ELcNnnWkgqnAJBouhcsDsYitbD9LIAVNSz3746u50f+tlF3wO0uB3uqyz8NHFSTpv23qtT47XGDw8pXW5DA== + to-regex-range@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" @@ -1376,7 +2852,19 @@ to-regex-range@^5.0.1: dependencies: is-number "^7.0.0" -tslib@^2.2.0, tslib@^2.6.2: +toml-eslint-parser@^0.10.0: + version "0.10.0" + resolved "https://registry.yarnpkg.com/toml-eslint-parser/-/toml-eslint-parser-0.10.0.tgz#52000b150a8b298feefeea701c29cca8b4730a38" + integrity sha512-khrZo4buq4qVmsGzS5yQjKe/WsFvV8fGfOjDQN0q4iy9FjRfPWRgTFrU8u1R2iu/SfWLhY9WnCi4Jhdrcbtg+g== + dependencies: + eslint-visitor-keys "^3.0.0" + +ts-api-utils@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-1.3.0.tgz#4b490e27129f1e8e686b45cc4ab63714dc60eea1" + integrity sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ== + +tslib@^2.2.0, tslib@^2.3.1, tslib@^2.6.2: version "2.6.3" resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.3.tgz#0438f810ad7a9edcde7a241c3d80db693c8cbfe0" integrity sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ== @@ -1388,6 +2876,26 @@ type-check@^0.4.0, type-check@~0.4.0: dependencies: prelude-ls "^1.2.1" +type-fest@^0.20.2: + version "0.20.2" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4" + integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== + +type-fest@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.6.0.tgz#8d2a2370d3df886eb5c90ada1c5bf6188acf838b" + integrity sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg== + +type-fest@^0.8.1: + version "0.8.1" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d" + integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA== + +typescript@^5.5.4: + version "5.5.4" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.5.4.tgz#d9852d6c82bad2d2eda4fd74a5762a8f5909e9ba" + integrity sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q== + ufo@^1.5.3: version "1.5.4" resolved "https://registry.yarnpkg.com/ufo/-/ufo-1.5.4.tgz#16d6949674ca0c9e0fbbae1fa20a71d7b1ded754" @@ -1417,6 +2925,21 @@ undici@^5.28.4: pathe "^1.1.2" ufo "^1.5.3" +unist-util-stringify-position@^2.0.0: + version "2.0.3" + resolved "https://registry.yarnpkg.com/unist-util-stringify-position/-/unist-util-stringify-position-2.0.3.tgz#cce3bfa1cdf85ba7375d1d5b17bdc4cada9bd9da" + integrity sha512-3faScn5I+hy9VleOq/qNbAd6pAx7iH5jYBMS9I1HgQVijz/4mv5Bvw5iw1sC/90CODiKo81G/ps8AJrISn687g== + dependencies: + "@types/unist" "^2.0.2" + +update-browserslist-db@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.1.0.tgz#7ca61c0d8650766090728046e416a8cde682859e" + integrity sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ== + dependencies: + escalade "^3.1.2" + picocolors "^1.0.1" + uri-js@^4.2.2: version "4.4.1" resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" @@ -1424,6 +2947,43 @@ uri-js@^4.2.2: dependencies: punycode "^2.1.0" +util-deprecate@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== + +validate-npm-package-license@^3.0.1: + version "3.0.4" + resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a" + integrity sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew== + dependencies: + spdx-correct "^3.0.0" + spdx-expression-parse "^3.0.0" + +vite@^5.2.10: + version "5.4.1" + resolved "https://registry.yarnpkg.com/vite/-/vite-5.4.1.tgz#2aa72370de824d23f53658affd807e4c9905b058" + integrity sha512-1oE6yuNXssjrZdblI9AfBbHCC41nnyoVoEZxQnID6yvQZAFBzxxkqoFLtHUMkYunL8hwOLEjgTuxpkRxvba3kA== + dependencies: + esbuild "^0.21.3" + postcss "^8.4.41" + rollup "^4.13.0" + optionalDependencies: + fsevents "~2.3.3" + +vue-eslint-parser@^9.4.3: + version "9.4.3" + resolved "https://registry.yarnpkg.com/vue-eslint-parser/-/vue-eslint-parser-9.4.3.tgz#9b04b22c71401f1e8bca9be7c3e3416a4bde76a8" + integrity sha512-2rYRLWlIpaiN8xbPiDyXZXRgLGOtWxERV7ND5fFAv5qo1D2N9Fu9MNajBNc6o13lZ+24DAWCkQCvj4klgmcITg== + dependencies: + debug "^4.3.4" + eslint-scope "^7.1.1" + eslint-visitor-keys "^3.3.0" + espree "^9.3.1" + esquery "^1.4.0" + lodash "^4.17.21" + semver "^7.3.6" + which@^2.0.1: version "2.0.2" resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" @@ -1473,16 +3033,67 @@ wrangler@^3.69.1: optionalDependencies: fsevents "~2.3.2" +wrap-ansi@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + ws@^8.17.1: version "8.18.0" resolved "https://registry.yarnpkg.com/ws/-/ws-8.18.0.tgz#0d7505a6eafe2b0e712d232b42279f53bc289bbc" integrity sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw== +xml-name-validator@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-4.0.0.tgz#79a006e2e63149a8600f15430f0a4725d1524835" + integrity sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw== + xxhash-wasm@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/xxhash-wasm/-/xxhash-wasm-1.0.2.tgz#ecc0f813219b727af4d5f3958ca6becee2f2f1ff" integrity sha512-ibF0Or+FivM9lNrg+HGJfVX8WJqgo+kCLDc4vx6xMeTce7Aj+DLttKbxxRR/gNLSAelRc1omAPlJ77N/Jem07A== +y18n@^5.0.5: + version "5.0.8" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" + integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== + +yaml-eslint-parser@^1.2.1, yaml-eslint-parser@^1.2.3: + version "1.2.3" + resolved "https://registry.yarnpkg.com/yaml-eslint-parser/-/yaml-eslint-parser-1.2.3.tgz#3a8ae839fc8df376ef8497add7f40942b493389c" + integrity sha512-4wZWvE398hCP7O8n3nXKu/vdq1HcH01ixYlCREaJL5NUMwQ0g3MaGFUBNSlmBtKmhbtVG/Cm6lyYmSVTEVil8A== + dependencies: + eslint-visitor-keys "^3.0.0" + lodash "^4.17.21" + yaml "^2.0.0" + +yaml@^2.0.0: + version "2.5.0" + resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.5.0.tgz#c6165a721cf8000e91c36490a41d7be25176cf5d" + integrity sha512-2wWLbGbYDiSqqIKoPjar3MPgB94ErzCtrNE1FdqGuaO0pi2JGjmE8aW8TDZwzU7vuxcGRdL/4gPQwQ7hD5AMSw== + +yargs-parser@^21.1.1: + version "21.1.1" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.1.1.tgz#9096bceebf990d21bb31fa9516e0ede294a77d35" + integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw== + +yargs@^17.7.2: + version "17.7.2" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.7.2.tgz#991df39aca675a192b816e1e0363f9d75d2aa269" + integrity sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w== + 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.5" + yargs-parser "^21.1.1" + yocto-queue@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b"