57 Commits

Author SHA1 Message Date
dependabot[bot] 103f4519fd Bump @mistralai/mistralai from 1.15.1 to 2.2.1
Bumps [@mistralai/mistralai](https://github.com/mistralai/client-ts) from 1.15.1 to 2.2.1.
- [Release notes](https://github.com/mistralai/client-ts/releases)
- [Changelog](https://github.com/mistralai/client-ts/blob/main/RELEASES.md)
- [Commits](https://github.com/mistralai/client-ts/compare/v1.15.1...v2.2.1)

---
updated-dependencies:
- dependency-name: "@mistralai/mistralai"
  dependency-version: 2.2.1
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-05-19 19:18:49 +00:00
melod1n d95c37a322 improvements 2026-04-29 19:54:55 +03:00
melod1n a7fcb8074c improvements, fixes 2026-04-29 19:48:38 +03:00
melod1n c003d443e3 temp disable prefix requirement for AI reply 2026-04-29 19:24:31 +03:00
melod1n 874f312465 temp disable prefix requirement for AI reply 2026-04-29 19:19:50 +03:00
melod1n d41a4ed3ea improve replies, formatting and system prompt handling 2026-04-29 19:13:28 +03:00
melod1n 27ca75ed7c update export db command 2026-04-29 06:49:56 +03:00
melod1n cbf5392ffa fix bump libs 2026-04-29 06:46:43 +03:00
melod1n 8822e8f46a export db command 2026-04-29 06:45:00 +03:00
melod1n 8a3c6d40a9 bump libs 2026-04-29 06:44:44 +03:00
melod1n 860182d409 add policies for future 2026-03-18 13:44:19 +03:00
melod1n e21c786e71 add todo 2026-03-18 13:44:03 +03:00
melod1n 126bebb40b add "imgen" option to OpenAiGenImage command 2026-03-18 13:43:56 +03:00
melod1n d77b33514c bump libs 2026-03-18 13:43:35 +03:00
melod1n 3700f61393 add /admins command 2026-03-18 13:43:28 +03:00
melod1n bfb6fe33db error handling 2026-03-03 00:34:07 +03:00
melod1n 18b7a2082b updates 2026-03-03 00:29:03 +03:00
melod1n 6a8dbed691 update text 2026-03-03 00:22:20 +03:00
melod1n 07a6dde0b8 fix typo 2026-03-03 00:05:43 +03:00
melod1n 1f96e3553e * environment variable to enable/disable processing links in messages (for downloading videos)
* bot will not automatically download video from youtube or load it from cache. It will fetch video info first, then suggest to download or get video from cache (with retry options)
* some rewriting in sending/editing/replying to messages
2026-03-03 00:01:44 +03:00
melod1n 3f34a48d41 bump libs 2026-03-02 23:58:57 +03:00
melod1n 6dce990c4c update ytdl 2026-02-25 17:02:46 +03:00
melod1n 0c5d17663c update Dockerfiles to include downloading ffmpeg 2026-02-25 16:53:26 +03:00
melod1n 8bbf97e4c0 bump libs
rewrite ytdl command - now streaming both audio and video, separated, then merging using ffmpeg
2026-02-25 16:22:01 +03:00
melod1n 51db4ba9b5 fix using wrong dirs 2026-02-16 20:05:21 +03:00
melod1n c98528a54f fix 2026-02-16 20:00:25 +03:00
melod1n 2f0f10eed9 fix mkdir dirs 2026-02-16 19:57:35 +03:00
melod1n 8bec34413f some code cleanup 2026-02-16 19:52:28 +03:00
melod1n b8b3895310 update openAiGenImage params 2026-02-16 19:52:08 +03:00
melod1n 5b84376dc7 improve cache storage and cleanup (+ recursively) 2026-02-16 19:51:43 +03:00
melod1n 69ae37e05e /ae command now available if specifically set to 2026-02-16 19:50:07 +03:00
melod1n edcc0ddc91 Revert "move to debian-based runtime"
This reverts commit 751a0a1e15.
2026-02-16 16:40:28 +03:00
melod1n 751a0a1e15 move to debian-based runtime 2026-02-16 16:29:38 +03:00
melod1n c491996a5d (feat): graceful shutdown 2026-02-12 18:33:56 +03:00
melod1n 6ea9905c25 (feat): clearing up both photo and video after 1 day and on process' start 2026-02-12 18:22:37 +03:00
melod1n 4ce3229b5c (chore): change Info command base command from ChatCommand to Command 2026-02-12 18:22:01 +03:00
melod1n 2c7824ebc8 (feat): add image generation from openai 2026-02-12 18:21:29 +03:00
melod1n 8dbd9a456a (chore): add zod and bump deps 2026-02-12 14:56:58 +03:00
melod1n 82468cf61b chat with gemini now will use any first images 2026-02-12 14:48:13 +03:00
melod1n 2026c673f5 checking models capabilities 2026-02-12 14:22:43 +03:00
melod1n 77d0ca2f38 add info command 2026-02-12 13:14:10 +03:00
melod1n b9fa2538db add support for youtube music videos 2026-02-12 11:55:14 +03:00
melod1n 21ab362776 fix 2026-02-06 21:22:20 +03:00
melod1n ae431f6258 use apple emoji by default in quote command 2026-02-06 12:33:36 +03:00
melod1n fbbbebaf2e fix emoji naming 2026-02-06 12:20:00 +03:00
melod1n b1dfe93e22 fix regex 2026-02-06 12:05:20 +03:00
melod1n ae428d8415 fix usage of wrong entities if a quote is present 2026-02-06 12:05:11 +03:00
melod1n 9ba3d81a21 feat(ai): add configurable default provider + refactor telegram handlers
- add AiProvider enum and DEFAULT_AI_PROVIDER env var (fallback: OLLAMA)
- route chat execution based on selected provider (Ollama/Gemini/Mistral/OpenAI)
- move inline query / callback / edited message / my_chat_member handlers into utils
- minor cleanup (command requirements placement, whitespace)
2026-02-04 12:55:04 +03:00
melod1n 3c7d56b213 support for custom baseURL for OpenAI
fix messages' type in context chain
2026-02-04 12:16:31 +03:00
melod1n fc5478b5ec update bun.lock 2026-02-04 11:30:09 +03:00
dependabot[bot] 285067e640 Bump drizzle-kit from 1.0.0-beta.9-e89174b to 1.0.0-beta.13-5204f18 (#20)
Bumps [drizzle-kit](https://github.com/drizzle-team/drizzle-orm) from 1.0.0-beta.9-e89174b to 1.0.0-beta.13-5204f18.
- [Release notes](https://github.com/drizzle-team/drizzle-orm/releases)
- [Commits](https://github.com/drizzle-team/drizzle-orm/commits)

---
updated-dependencies:
- dependency-name: drizzle-kit
  dependency-version: 1.0.0-beta.13-5204f18
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-04 11:26:23 +03:00
dependabot[bot] f15e189019 Bump drizzle-orm from 1.0.0-beta.9-e89174b to 1.0.0-beta.13-5204f18 (#21)
Bumps [drizzle-orm](https://github.com/drizzle-team/drizzle-orm) from 1.0.0-beta.9-e89174b to 1.0.0-beta.13-5204f18.
- [Release notes](https://github.com/drizzle-team/drizzle-orm/releases)
- [Commits](https://github.com/drizzle-team/drizzle-orm/commits)

---
updated-dependencies:
- dependency-name: drizzle-orm
  dependency-version: 1.0.0-beta.13-5204f18
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-04 11:24:54 +03:00
melod1n 639c8ed9d0 update default OpenAI model 2026-02-03 13:55:50 +03:00
melod1n a28ac7f3a6 change ChatGPT -> OpenAI in OpenAIChat chat command 2026-02-03 13:44:28 +03:00
melod1n cf91f26ac9 add title and description to OpenAIChat chat command 2026-02-03 13:43:39 +03:00
melod1n a736f786c2 feat(openai): add chat streaming and model commands
- add /openai (/chatgpt) chat command using OpenAI Responses API (streaming + incremental edits)
- add /openAIListModels, /openAIGetModel, /openAISetModel
- introduce base Command class and migrate non-chat commands to it
- wire OpenAI client + env vars (OPENAI_API_KEY, OPENAI_MODEL)
- bump deps (@google/genai, systeminformation, @types/node) and add openai
2026-02-03 13:39:01 +03:00
melod1n 810151263d feat: separate Ollama text/image/think models + add YouTube downloader
Support OLLAMA_IMAGE_MODEL and new OLLAMA_THINK_MODEL (both default to OLLAMA_MODEL)

Add /ollamathink command; validate thinking capability; disable image-analysis flow in think mode

Make /ollama-get-model show Text/Image/Think blocks only when models differ

Add /ytdl (/youtube) command + auto-detect YouTube URLs in messages

Cache downloaded videos to data/video and schedule daily cleanup

Move photo storage from data/temp to data/photo; improve env boolean parsing via ifTrue

Update deps (youtubei.js, puppeteer*) and TS config (allowJs, allowSyntheticDefaultImports)
2026-01-31 19:37:25 +03:00
78 changed files with 2893 additions and 998 deletions
+1
View File
@@ -12,6 +12,7 @@ RUN npx tsc -p tsconfig.build.json
# ---- runtime ----
FROM node:lts-alpine AS runner
RUN apk add --no-cache ffmpeg
WORKDIR /app
ENV NODE_ENV=production
+1
View File
@@ -12,6 +12,7 @@ RUN bunx tsc -p tsconfig.build.json
# ---- runtime ----
FROM oven/bun:alpine AS runner
RUN apk add --no-cache ffmpeg
WORKDIR /app
ENV NODE_ENV=production
+336 -84
View File
@@ -5,29 +5,37 @@
"": {
"name": "tg-chat-bot",
"dependencies": {
"@google/genai": "^1.38.0",
"@libsql/client": "^0.17.0",
"@mistralai/mistralai": "^1.13.0",
"@napi-rs/canvas": "^0.1.89",
"axios": "^1.13.4",
"dotenv": "^17.2.3",
"drizzle-orm": "^1.0.0-beta.12-5845444",
"@google/genai": "^1.50.1",
"@libsql/client": "^0.17.3",
"@mistralai/mistralai": "^1.15.1",
"@napi-rs/canvas": "^0.1.100",
"axios": "^1.15.2",
"dotenv": "^17.4.2",
"drizzle-orm": "1.0.0-beta.21",
"emoji-regex": "^10.6.0",
"fluent-ffmpeg": "^2.1.3",
"ollama": "^0.6.3",
"openai": "^6.35.0",
"puppeteer": "^24.42.0",
"puppeteer-extra": "^3.3.6",
"puppeteer-extra-plugin-stealth": "^2.11.2",
"qrcode": "^1.5.4",
"sharp": "^0.34.5",
"systeminformation": "^5.30.6",
"systeminformation": "^5.31.5",
"twemoji": "^14.0.2",
"typescript-telegram-bot-api": "^0.11.0",
"youtubei.js": "^16.0.1",
"zod": "^4.3.6",
},
"devDependencies": {
"@types/bun": "^1.3.7",
"@types/node": "^25.1.0",
"@types/bun": "^1.3.13",
"@types/fluent-ffmpeg": "^2.1.28",
"@types/node": "^25.6.0",
"@types/qrcode": "^1.5.6",
"@typescript-eslint/eslint-plugin": "^8.54.0",
"@typescript-eslint/parser": "^8.54.0",
"drizzle-kit": "^1.0.0-beta.12-5845444",
"eslint": "^9.39.2",
"@typescript-eslint/eslint-plugin": "^8.59.1",
"@typescript-eslint/parser": "^8.59.1",
"drizzle-kit": "^1.0.0-beta.9-e89174b",
"eslint": "^9.39.4",
"tsx": "^4.21.0",
"typescript": "^5.9.3",
},
@@ -68,6 +76,12 @@
"@azure/msal-node": ["@azure/msal-node@3.8.4", "", { "dependencies": { "@azure/msal-common": "15.13.3", "jsonwebtoken": "^9.0.0", "uuid": "^8.3.0" } }, "sha512-lvuAwsDpPDE/jSuVQOBMpLbXuVuLsPNRwWCyK3/6bPlBk0fGWegqoZ0qjZclMWyQ2JNvIY3vHY7hoFmFmFQcOw=="],
"@babel/code-frame": ["@babel/code-frame@7.28.6", "", { "dependencies": { "@babel/helper-validator-identifier": "^7.28.5", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" } }, "sha512-JYgintcMjRiCvS8mMECzaEn+m3PfoQiyqukOMCCVQtoJGYJw8j/8LBJEiqkHLkfwCcs74E3pbAUFNg7d9VNJ+Q=="],
"@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.28.5", "", {}, "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q=="],
"@bufbuild/protobuf": ["@bufbuild/protobuf@2.11.0", "", {}, "sha512-sBXGT13cpmPR5BMgHE6UEEfEaShh5Ror6rfN3yEK5si7QVrtZg8LEPQb0VVhiLRUslD2yLnXtnRzG035J/mZXQ=="],
"@drizzle-team/brocli": ["@drizzle-team/brocli@0.11.0", "", {}, "sha512-hD3pekGiPg0WPCCGAZmusBBJsDqGUR66Y452YgQsZOnkdQ7ViEPKuyP4huUGEZQefp8g34RRodXYmJ2TbCH+tg=="],
"@emnapi/runtime": ["@emnapi/runtime@1.7.1", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-PVtJr5CmLwYAU9PZDMITZoR5iAOShYREoR45EyyLrbntV50mdePTgUn4AmOw90Ifcj+x2kRjdzr1HP3RrNiHGA=="],
@@ -124,25 +138,25 @@
"@esbuild/win32-x64": ["@esbuild/win32-x64@0.25.12", "", { "os": "win32", "cpu": "x64" }, "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA=="],
"@eslint-community/eslint-utils": ["@eslint-community/eslint-utils@4.9.0", "", { "dependencies": { "eslint-visitor-keys": "^3.4.3" }, "peerDependencies": { "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } }, "sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g=="],
"@eslint-community/eslint-utils": ["@eslint-community/eslint-utils@4.9.1", "", { "dependencies": { "eslint-visitor-keys": "^3.4.3" }, "peerDependencies": { "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } }, "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ=="],
"@eslint-community/regexpp": ["@eslint-community/regexpp@4.12.2", "", {}, "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew=="],
"@eslint/config-array": ["@eslint/config-array@0.21.1", "", { "dependencies": { "@eslint/object-schema": "^2.1.7", "debug": "^4.3.1", "minimatch": "^3.1.2" } }, "sha512-aw1gNayWpdI/jSYVgzN5pL0cfzU02GT3NBpeT/DXbx1/1x7ZKxFPd9bwrzygx/qiwIQiJ1sw/zD8qY/kRvlGHA=="],
"@eslint/config-array": ["@eslint/config-array@0.21.2", "", { "dependencies": { "@eslint/object-schema": "^2.1.7", "debug": "^4.3.1", "minimatch": "^3.1.5" } }, "sha512-nJl2KGTlrf9GjLimgIru+V/mzgSK0ABCDQRvxw5BjURL7WfH5uoWmizbH7QB6MmnMBd8cIC9uceWnezL1VZWWw=="],
"@eslint/config-helpers": ["@eslint/config-helpers@0.4.2", "", { "dependencies": { "@eslint/core": "^0.17.0" } }, "sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw=="],
"@eslint/core": ["@eslint/core@0.17.0", "", { "dependencies": { "@types/json-schema": "^7.0.15" } }, "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ=="],
"@eslint/eslintrc": ["@eslint/eslintrc@3.3.3", "", { "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", "espree": "^10.0.1", "globals": "^14.0.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", "js-yaml": "^4.1.1", "minimatch": "^3.1.2", "strip-json-comments": "^3.1.1" } }, "sha512-Kr+LPIUVKz2qkx1HAMH8q1q6azbqBAsXJUxBl/ODDuVPX45Z9DfwB8tPjTi6nNZ8BuM3nbJxC5zCAg5elnBUTQ=="],
"@eslint/eslintrc": ["@eslint/eslintrc@3.3.5", "", { "dependencies": { "ajv": "^6.14.0", "debug": "^4.3.2", "espree": "^10.0.1", "globals": "^14.0.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", "js-yaml": "^4.1.1", "minimatch": "^3.1.5", "strip-json-comments": "^3.1.1" } }, "sha512-4IlJx0X0qftVsN5E+/vGujTRIFtwuLbNsVUe7TO6zYPDR1O6nFwvwhIKEKSrl6dZchmYBITazxKoUYOjdtjlRg=="],
"@eslint/js": ["@eslint/js@9.39.2", "", {}, "sha512-q1mjIoW1VX4IvSocvM/vbTiveKC4k9eLrajNEuSsmjymSDEbpGddtpfOoN7YGAqBK3NG+uqo8ia4PDTt8buCYA=="],
"@eslint/js": ["@eslint/js@9.39.4", "", {}, "sha512-nE7DEIchvtiFTwBw4Lfbu59PG+kCofhjsKaCWzxTpt4lfRjRMqG6uMBzKXuEcyXhOHoUp9riAm7/aWYGhXZ9cw=="],
"@eslint/object-schema": ["@eslint/object-schema@2.1.7", "", {}, "sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA=="],
"@eslint/plugin-kit": ["@eslint/plugin-kit@0.4.1", "", { "dependencies": { "@eslint/core": "^0.17.0", "levn": "^0.4.1" } }, "sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA=="],
"@google/genai": ["@google/genai@1.38.0", "", { "dependencies": { "google-auth-library": "^10.3.0", "protobufjs": "^7.5.4", "ws": "^8.18.0" }, "peerDependencies": { "@modelcontextprotocol/sdk": "^1.25.2" }, "optionalPeers": ["@modelcontextprotocol/sdk"] }, "sha512-V/4CQVQGovvGHuS73lwJwHKR9x33kCij3zz/ReEQ4A7RJaV0U7m4k1mvYhFk55cGZdF5JLKu2S9BTaFuEs5xTA=="],
"@google/genai": ["@google/genai@1.50.1", "", { "dependencies": { "google-auth-library": "^10.3.0", "p-retry": "^4.6.2", "protobufjs": "^7.5.4", "ws": "^8.18.0" }, "peerDependencies": { "@modelcontextprotocol/sdk": "^1.25.2" }, "optionalPeers": ["@modelcontextprotocol/sdk"] }, "sha512-YbkX7H9+1Pt8wOt7DDREy8XSoiL6fRDzZQRyaVBarFf8MR3zHGqVdvM4cLbDXqPhxqvegZShgfxb8kw9C7YhAQ=="],
"@humanfs/core": ["@humanfs/core@0.19.1", "", {}, "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA=="],
@@ -208,57 +222,57 @@
"@js-temporal/polyfill": ["@js-temporal/polyfill@0.5.1", "", { "dependencies": { "jsbi": "^4.3.0" } }, "sha512-hloP58zRVCRSpgDxmqCWJNlizAlUgJFqG2ypq79DCvyv9tHjRYMDOcPFjzfl/A1/YxDvRCZz8wvZvmapQnKwFQ=="],
"@libsql/client": ["@libsql/client@0.17.0", "", { "dependencies": { "@libsql/core": "^0.17.0", "@libsql/hrana-client": "^0.9.0", "js-base64": "^3.7.5", "libsql": "^0.5.22", "promise-limit": "^2.7.0" } }, "sha512-TLjSU9Otdpq0SpKHl1tD1Nc9MKhrsZbCFGot3EbCxRa8m1E5R1mMwoOjKMMM31IyF7fr+hPNHLpYfwbMKNusmg=="],
"@libsql/client": ["@libsql/client@0.17.3", "", { "dependencies": { "@libsql/core": "^0.17.3", "@libsql/hrana-client": "^0.10.0", "js-base64": "^3.7.5", "libsql": "^0.5.28", "promise-limit": "^2.7.0" } }, "sha512-HXk9wiAoJbKFbyBH4O+aEhN6ir5ERXuXvwE5OD2eR4/5RUa3Pw/8L9zrnVdU+iNJitRvisPWaIwmhkO3bH7giA=="],
"@libsql/core": ["@libsql/core@0.17.0", "", { "dependencies": { "js-base64": "^3.7.5" } }, "sha512-hnZRnJHiS+nrhHKLGYPoJbc78FE903MSDrFJTbftxo+e52X+E0Y0fHOCVYsKWcg6XgB7BbJYUrz/xEkVTSaipw=="],
"@libsql/core": ["@libsql/core@0.17.3", "", { "dependencies": { "js-base64": "^3.7.5" } }, "sha512-2UjK1i7JBkMduJo4WdvvBxMMvVJ31pArBZNONyz/GCJJAH+1UHat2X6vn10S/WpY5fKzIT98WqYFl2vzWRLOfg=="],
"@libsql/darwin-arm64": ["@libsql/darwin-arm64@0.5.22", "", { "os": "darwin", "cpu": "arm64" }, "sha512-4B8ZlX3nIDPndfct7GNe0nI3Yw6ibocEicWdC4fvQbSs/jdq/RC2oCsoJxJ4NzXkvktX70C1J4FcmmoBy069UA=="],
"@libsql/darwin-arm64": ["@libsql/darwin-arm64@0.5.29", "", { "os": "darwin", "cpu": "arm64" }, "sha512-K+2RIB1OGFPYQbfay48GakLhqf3ArcbHqPFu7EZiaUcRgFcdw8RoltsMyvbj5ix2fY0HV3Q3Ioa/ByvQdaSM0A=="],
"@libsql/darwin-x64": ["@libsql/darwin-x64@0.5.22", "", { "os": "darwin", "cpu": "x64" }, "sha512-ny2HYWt6lFSIdNFzUFIJ04uiW6finXfMNJ7wypkAD8Pqdm6nAByO+Fdqu8t7sD0sqJGeUCiOg480icjyQ2/8VA=="],
"@libsql/darwin-x64": ["@libsql/darwin-x64@0.5.29", "", { "os": "darwin", "cpu": "x64" }, "sha512-OtT+KFHsKFy1R5FVadr8FJ2Bb1mghtXTyJkxv0trocq7NuHntSki1eUbxpO5ezJesDvBlqFjnWaYYY516QNLhQ=="],
"@libsql/hrana-client": ["@libsql/hrana-client@0.9.0", "", { "dependencies": { "@libsql/isomorphic-ws": "^0.1.5", "cross-fetch": "^4.0.0", "js-base64": "^3.7.5", "node-fetch": "^3.3.2" } }, "sha512-pxQ1986AuWfPX4oXzBvLwBnfgKDE5OMhAdR/5cZmRaB4Ygz5MecQybvwZupnRz341r2CtFmbk/BhSu7k2Lm+Jw=="],
"@libsql/hrana-client": ["@libsql/hrana-client@0.10.0", "", { "dependencies": { "@libsql/isomorphic-ws": "^0.1.5", "js-base64": "^3.7.5" } }, "sha512-OoA4EMqRAC7kn7V2P6EQqRcpZf2W+AjsNIyCizBg339Tq/aMC7sRnzs3SklderhmQWAqEzvv8A2vhxVmWpkVvw=="],
"@libsql/isomorphic-ws": ["@libsql/isomorphic-ws@0.1.5", "", { "dependencies": { "@types/ws": "^8.5.4", "ws": "^8.13.0" } }, "sha512-DtLWIH29onUYR00i0GlQ3UdcTRC6EP4u9w/h9LxpUZJWRMARk6dQwZ6Jkd+QdwVpuAOrdxt18v0K2uIYR3fwFg=="],
"@libsql/linux-arm-gnueabihf": ["@libsql/linux-arm-gnueabihf@0.5.22", "", { "os": "linux", "cpu": "arm" }, "sha512-3Uo3SoDPJe/zBnyZKosziRGtszXaEtv57raWrZIahtQDsjxBVjuzYQinCm9LRCJCUT5t2r5Z5nLDPJi2CwZVoA=="],
"@libsql/linux-arm-gnueabihf": ["@libsql/linux-arm-gnueabihf@0.5.29", "", { "os": "linux", "cpu": "arm" }, "sha512-CD4n4zj7SJTHso4nf5cuMoWoMSS7asn5hHygsDuhRl8jjjCTT3yE+xdUvI4J7zsyb53VO5ISh4cwwOtf6k2UhQ=="],
"@libsql/linux-arm-musleabihf": ["@libsql/linux-arm-musleabihf@0.5.22", "", { "os": "linux", "cpu": "arm" }, "sha512-LCsXh07jvSojTNJptT9CowOzwITznD+YFGGW+1XxUr7fS+7/ydUrpDfsMX7UqTqjm7xG17eq86VkWJgHJfvpNg=="],
"@libsql/linux-arm-musleabihf": ["@libsql/linux-arm-musleabihf@0.5.29", "", { "os": "linux", "cpu": "arm" }, "sha512-2Z9qBVpEJV7OeflzIR3+l5yAd4uTOLxklScYTwpZnkm2vDSGlC1PRlueLaufc4EFITkLKXK2MWBpexuNJfMVcg=="],
"@libsql/linux-arm64-gnu": ["@libsql/linux-arm64-gnu@0.5.22", "", { "os": "linux", "cpu": "arm64" }, "sha512-KSdnOMy88c9mpOFKUEzPskSaF3VLflfSUCBwas/pn1/sV3pEhtMF6H8VUCd2rsedwoukeeCSEONqX7LLnQwRMA=="],
"@libsql/linux-arm64-gnu": ["@libsql/linux-arm64-gnu@0.5.29", "", { "os": "linux", "cpu": "arm64" }, "sha512-gURBqaiXIGGwFNEaUj8Ldk7Hps4STtG+31aEidCk5evMMdtsdfL3HPCpvys+ZF/tkOs2MWlRWoSq7SOuCE9k3w=="],
"@libsql/linux-arm64-musl": ["@libsql/linux-arm64-musl@0.5.22", "", { "os": "linux", "cpu": "arm64" }, "sha512-mCHSMAsDTLK5YH//lcV3eFEgiR23Ym0U9oEvgZA0667gqRZg/2px+7LshDvErEKv2XZ8ixzw3p1IrBzLQHGSsw=="],
"@libsql/linux-arm64-musl": ["@libsql/linux-arm64-musl@0.5.29", "", { "os": "linux", "cpu": "arm64" }, "sha512-fwgYZ0H8mUkyVqXZHF3mT/92iIh1N94Owi/f66cPVNsk9BdGKq5gVpoKO+7UxaNzuEH1roJp2QEwsCZMvBLpqg=="],
"@libsql/linux-x64-gnu": ["@libsql/linux-x64-gnu@0.5.22", "", { "os": "linux", "cpu": "x64" }, "sha512-kNBHaIkSg78Y4BqAdgjcR2mBilZXs4HYkAmi58J+4GRwDQZh5fIUWbnQvB9f95DkWUIGVeenqLRFY2pcTmlsew=="],
"@libsql/linux-x64-gnu": ["@libsql/linux-x64-gnu@0.5.29", "", { "os": "linux", "cpu": "x64" }, "sha512-y14V0vY0nmMC6G0pHeJcEarcnGU2H6cm21ZceRkacWHvQAEhAG0latQkCtoS2njFOXiYIg+JYPfAoWKbi82rkg=="],
"@libsql/linux-x64-musl": ["@libsql/linux-x64-musl@0.5.22", "", { "os": "linux", "cpu": "x64" }, "sha512-UZ4Xdxm4pu3pQXjvfJiyCzZop/9j/eA2JjmhMaAhe3EVLH2g11Fy4fwyUp9sT1QJYR1kpc2JLuybPM0kuXv/Tg=="],
"@libsql/linux-x64-musl": ["@libsql/linux-x64-musl@0.5.29", "", { "os": "linux", "cpu": "x64" }, "sha512-gquqwA/39tH4pFl+J9n3SOMSymjX+6kZ3kWgY3b94nXFTwac9bnFNMffIomgvlFaC4ArVqMnOZD3nuJ3H3VO1w=="],
"@libsql/win32-x64-msvc": ["@libsql/win32-x64-msvc@0.5.22", "", { "os": "win32", "cpu": "x64" }, "sha512-Fj0j8RnBpo43tVZUVoNK6BV/9AtDUM5S7DF3LB4qTYg1LMSZqi3yeCneUTLJD6XomQJlZzbI4mst89yspVSAnA=="],
"@libsql/win32-x64-msvc": ["@libsql/win32-x64-msvc@0.5.29", "", { "os": "win32", "cpu": "x64" }, "sha512-4/0CvEdhi6+KjMxMaVbFM2n2Z44escBRoEYpR+gZg64DdetzGnYm8mcNLcoySaDJZNaBd6wz5DNdgRmcI4hXcg=="],
"@mistralai/mistralai": ["@mistralai/mistralai@1.13.0", "", { "dependencies": { "zod": "^3.25.0 || ^4.0.0", "zod-to-json-schema": "^3.24.1" } }, "sha512-eg7/8hQp91SshYDJ5XdWDsJENdIaSu52npJfKLCPuhla8Vm6GlESv2RROQyxESglCl7b1OULWiAv1ERbsrZO7w=="],
"@mistralai/mistralai": ["@mistralai/mistralai@1.15.1", "", { "dependencies": { "ws": "^8.18.0", "zod": "^3.25.0 || ^4.0.0", "zod-to-json-schema": "^3.24.1" } }, "sha512-fb995eiz3r0KsBGtRjFV+/iLbX+UpfalxpF+YitT3R6ukrPD4PN+FGwwmYcRFhNAzVzDUtTVxQYnjQWEnwV5nw=="],
"@napi-rs/canvas": ["@napi-rs/canvas@0.1.89", "", { "optionalDependencies": { "@napi-rs/canvas-android-arm64": "0.1.89", "@napi-rs/canvas-darwin-arm64": "0.1.89", "@napi-rs/canvas-darwin-x64": "0.1.89", "@napi-rs/canvas-linux-arm-gnueabihf": "0.1.89", "@napi-rs/canvas-linux-arm64-gnu": "0.1.89", "@napi-rs/canvas-linux-arm64-musl": "0.1.89", "@napi-rs/canvas-linux-riscv64-gnu": "0.1.89", "@napi-rs/canvas-linux-x64-gnu": "0.1.89", "@napi-rs/canvas-linux-x64-musl": "0.1.89", "@napi-rs/canvas-win32-arm64-msvc": "0.1.89", "@napi-rs/canvas-win32-x64-msvc": "0.1.89" } }, "sha512-7GjmkMirJHejeALCqUnZY3QwID7bbumOiLrqq2LKgxrdjdmxWQBTc6rcASa2u8wuWrH7qo4/4n/VNrOwCoKlKg=="],
"@napi-rs/canvas": ["@napi-rs/canvas@0.1.100", "", { "optionalDependencies": { "@napi-rs/canvas-android-arm64": "0.1.100", "@napi-rs/canvas-darwin-arm64": "0.1.100", "@napi-rs/canvas-darwin-x64": "0.1.100", "@napi-rs/canvas-linux-arm-gnueabihf": "0.1.100", "@napi-rs/canvas-linux-arm64-gnu": "0.1.100", "@napi-rs/canvas-linux-arm64-musl": "0.1.100", "@napi-rs/canvas-linux-riscv64-gnu": "0.1.100", "@napi-rs/canvas-linux-x64-gnu": "0.1.100", "@napi-rs/canvas-linux-x64-musl": "0.1.100", "@napi-rs/canvas-win32-arm64-msvc": "0.1.100", "@napi-rs/canvas-win32-x64-msvc": "0.1.100" } }, "sha512-xglYA6q3XO5P3BNJYxVZ1IV7DLVjp1Py6nwag88YntrS+3vKHyYcMqXVS4ZztJmwz2uGvz1FWhI/4LgbR5uQDA=="],
"@napi-rs/canvas-android-arm64": ["@napi-rs/canvas-android-arm64@0.1.89", "", { "os": "android", "cpu": "arm64" }, "sha512-CXxQTXsjtQqKGENS8Ejv9pZOFJhOPIl2goenS+aU8dY4DygvkyagDhy/I07D1YLqrDtPvLEX5zZHt8qUdnuIpQ=="],
"@napi-rs/canvas-android-arm64": ["@napi-rs/canvas-android-arm64@0.1.100", "", { "os": "android", "cpu": "arm64" }, "sha512-hjhCKhntPv9+t4ckHymdx0phYNcVW+GKQR6Lzw2zE+pOVjOplSmtx9nNNknTjbEDLcuLZqA1y8ufKg1XfgftzQ=="],
"@napi-rs/canvas-darwin-arm64": ["@napi-rs/canvas-darwin-arm64@0.1.89", "", { "os": "darwin", "cpu": "arm64" }, "sha512-k29cR/Zl20WLYM7M8YePevRu2VQRaKcRedYr1V/8FFHkyIQ8kShEV+MPoPGi+znvmd17Eqjy2Pk2F2kpM2umVg=="],
"@napi-rs/canvas-darwin-arm64": ["@napi-rs/canvas-darwin-arm64@0.1.100", "", { "os": "darwin", "cpu": "arm64" }, "sha512-2PcswRaC7Ly645DGt88///zuFDhJxJYdKAs1uU3mfk1atYkXufgcgLfBpk6Tm12nCQBaNt1wpybuPZ4qOhTo8A=="],
"@napi-rs/canvas-darwin-x64": ["@napi-rs/canvas-darwin-x64@0.1.89", "", { "os": "darwin", "cpu": "x64" }, "sha512-iUragqhBrA5FqU13pkhYBDbUD1WEAIlT8R2+fj6xHICY2nemzwMUI8OENDhRh7zuL06YDcRwENbjAVxOmaX9jg=="],
"@napi-rs/canvas-darwin-x64": ["@napi-rs/canvas-darwin-x64@0.1.100", "", { "os": "darwin", "cpu": "x64" }, "sha512-ePNZtj7pNIva/siZMg+HmbeozkIjqUIYdoymH8HaA3qK7LfzFN4WMBM8G6HQ9ZC+H3+Dnn5pqtiXpgLykaPOhw=="],
"@napi-rs/canvas-linux-arm-gnueabihf": ["@napi-rs/canvas-linux-arm-gnueabihf@0.1.89", "", { "os": "linux", "cpu": "arm" }, "sha512-y3SM9sfDWasY58ftoaI09YBFm35Ig8tosZqgahLJ2WGqawCusGNPV9P0/4PsrLOCZqGg629WxexQMY25n7zcvA=="],
"@napi-rs/canvas-linux-arm-gnueabihf": ["@napi-rs/canvas-linux-arm-gnueabihf@0.1.100", "", { "os": "linux", "cpu": "arm" }, "sha512-d5cDB48oWFGU8/XPhUOFAlySgb/VAu7D+s8fi55K1Pcfg8aPplHWqMgibhVLU8ky7Pyg/fuiVLz4Nf3JrSTuUA=="],
"@napi-rs/canvas-linux-arm64-gnu": ["@napi-rs/canvas-linux-arm64-gnu@0.1.89", "", { "os": "linux", "cpu": "arm64" }, "sha512-NEoF9y8xq5fX8HG8aZunBom1ILdTwt7ayBzSBIwrmitk7snj4W6Fz/yN/ZOmlM1iyzHDNX5Xn0n+VgWCF8BEdA=="],
"@napi-rs/canvas-linux-arm64-gnu": ["@napi-rs/canvas-linux-arm64-gnu@0.1.100", "", { "os": "linux", "cpu": "arm64" }, "sha512-rDxgxRu69RvDlX/bh9o22DxLsGr8EqsNgotL9+RwQE1S0b0cqeatqsw6aW45mukm0B42DIAaAacKaYQ8cqS1nw=="],
"@napi-rs/canvas-linux-arm64-musl": ["@napi-rs/canvas-linux-arm64-musl@0.1.89", "", { "os": "linux", "cpu": "arm64" }, "sha512-UQQkIEzV12/l60j1ziMjZ+mtodICNUbrd205uAhbyTw0t60CrC/EsKb5/aJWGq1wM0agvcgZV72JJCKfLS6+4w=="],
"@napi-rs/canvas-linux-arm64-musl": ["@napi-rs/canvas-linux-arm64-musl@0.1.100", "", { "os": "linux", "cpu": "arm64" }, "sha512-K3mDW66N+xT2/V439u1alFANiBUjdEx2gLiNYnCmUsva5jZMxWTjafBYwTzYK+EMFMHrUoabuU+T1BIP5CgbYQ=="],
"@napi-rs/canvas-linux-riscv64-gnu": ["@napi-rs/canvas-linux-riscv64-gnu@0.1.89", "", { "os": "linux", "cpu": "none" }, "sha512-1/VmEoFaIO6ONeeEMGoWF17wOYZOl5hxDC1ios2Bkz/oQjbJJ8DY/X22vWTmvuUKWWhBVlo63pxLGZbjJU/heA=="],
"@napi-rs/canvas-linux-riscv64-gnu": ["@napi-rs/canvas-linux-riscv64-gnu@0.1.100", "", { "os": "linux", "cpu": "none" }, "sha512-mooqUBTIsccZpnoQC4NgrC1v6C1vof39etLNMnBwCY+p0gajWJvAHLGQ6g/gGyS5YrpDW+GefSN4+Cvcr08UWw=="],
"@napi-rs/canvas-linux-x64-gnu": ["@napi-rs/canvas-linux-x64-gnu@0.1.89", "", { "os": "linux", "cpu": "x64" }, "sha512-ebLuqkCuaPIkKgKH9q4+pqWi1tkPOfiTk5PM1LKR1tB9iO9sFNVSIgwEp+SJreTSbA2DK5rW8lQXiN78SjtcvA=="],
"@napi-rs/canvas-linux-x64-gnu": ["@napi-rs/canvas-linux-x64-gnu@0.1.100", "", { "os": "linux", "cpu": "x64" }, "sha512-1eCvkDCazm7FFhsT7DfGOdSaHgZVK3bt/dSBl5EWHOWmnz+I7j8tPseJqqD81NF+MH21jKUK4wQSDjN0mdhnTg=="],
"@napi-rs/canvas-linux-x64-musl": ["@napi-rs/canvas-linux-x64-musl@0.1.89", "", { "os": "linux", "cpu": "x64" }, "sha512-w+5qxHzplvA4BkHhCaizNMLLXiI+CfP84YhpHm/PqMub4u8J0uOAv+aaGv40rYEYra5hHRWr9LUd6cfW32o9/A=="],
"@napi-rs/canvas-linux-x64-musl": ["@napi-rs/canvas-linux-x64-musl@0.1.100", "", { "os": "linux", "cpu": "x64" }, "sha512-20arT6lnI19S68qNlii73TSEDbECNgzMz2EpldC1V3mZFuRkeujXkcebRk0LRJe9SEUAooYiLokfMViY8IX7yA=="],
"@napi-rs/canvas-win32-arm64-msvc": ["@napi-rs/canvas-win32-arm64-msvc@0.1.89", "", { "os": "win32", "cpu": "arm64" }, "sha512-DmyXa5lJHcjOsDC78BM3bnEECqbK3xASVMrKfvtT/7S7Z8NGQOugvu+L7b41V6cexCd34mBWgMOsjoEBceeB1Q=="],
"@napi-rs/canvas-win32-arm64-msvc": ["@napi-rs/canvas-win32-arm64-msvc@0.1.100", "", { "os": "win32", "cpu": "arm64" }, "sha512-DZFFT1wIAg37LJw37yhMRFfjATd3vTQzjZ1Yki8u2vhO6Hi5VE6BVaGQ1aaDu7xb4iMErz+9EOwjpS7xcxFeBw=="],
"@napi-rs/canvas-win32-x64-msvc": ["@napi-rs/canvas-win32-x64-msvc@0.1.89", "", { "os": "win32", "cpu": "x64" }, "sha512-WMej0LZrIqIncQcx0JHaMXlnAG7sncwJh7obs/GBgp0xF9qABjwoRwIooMWCZkSansapKGNUHhamY6qEnFN7gA=="],
"@napi-rs/canvas-win32-x64-msvc": ["@napi-rs/canvas-win32-x64-msvc@0.1.100", "", { "os": "win32", "cpu": "x64" }, "sha512-MyT1j3mHC2+Lu4pBi9mKyMJhtP6U7k7EldY7sj/uS5gJA65gTXt8MefJQXLJo5d/vZbuWmfxzkEUNc/urV3pHA=="],
"@neon-rs/load": ["@neon-rs/load@0.0.4", "", {}, "sha512-kTPhdZyTQxB+2wpiRcFWrDcejc4JI6tkPuS7UZCG4l6Zvc5kU/gGQ/ozvHTh1XR5tS+UlfAfGuPajjzQjCiHCw=="],
@@ -284,43 +298,57 @@
"@protobufjs/utf8": ["@protobufjs/utf8@1.1.0", "", {}, "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw=="],
"@puppeteer/browsers": ["@puppeteer/browsers@2.13.0", "", { "dependencies": { "debug": "^4.4.3", "extract-zip": "^2.0.1", "progress": "^2.0.3", "proxy-agent": "^6.5.0", "semver": "^7.7.4", "tar-fs": "^3.1.1", "yargs": "^17.7.2" }, "bin": { "browsers": "lib/cjs/main-cli.js" } }, "sha512-46BZJYJjc/WwmKjsvDFykHtXrtomsCIrwYQPOP7VfMJoZY2bsDF9oROBABR3paDjDcmkUye1Pb1BqdcdiipaWA=="],
"@tediousjs/connection-string": ["@tediousjs/connection-string@0.5.0", "", {}, "sha512-7qSgZbincDDDFyRweCIEvZULFAw5iz/DeunhvuxpL31nfntX3P4Yd4HkHBRg9H8CdqY1e5WFN1PZIz/REL9MVQ=="],
"@types/bun": ["@types/bun@1.3.7", "", { "dependencies": { "bun-types": "1.3.7" } }, "sha512-lmNuMda+Z9b7tmhA0tohwy8ZWFSnmQm1UDWXtH5r9F7wZCfkeO3Jx7wKQ1EOiKq43yHts7ky6r8SDJQWRNupkA=="],
"@tootallnate/quickjs-emscripten": ["@tootallnate/quickjs-emscripten@0.23.0", "", {}, "sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA=="],
"@types/bun": ["@types/bun@1.3.13", "", { "dependencies": { "bun-types": "1.3.13" } }, "sha512-9fqXWk5YIHGGnUau9TEi+qdlTYDAnOj+xLCmSTwXfAIqXr2x4tytJb43E9uCvt09zJURKXwAtkoH4nLQfzeTXw=="],
"@types/debug": ["@types/debug@4.1.12", "", { "dependencies": { "@types/ms": "*" } }, "sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ=="],
"@types/estree": ["@types/estree@1.0.8", "", {}, "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w=="],
"@types/fluent-ffmpeg": ["@types/fluent-ffmpeg@2.1.28", "", { "dependencies": { "@types/node": "*" } }, "sha512-5ovxsDwBcPfJ+eYs1I/ZpcYCnkce7pvH9AHSvrZllAp1ZPpTRDZAFjF3TRFbukxSgIYTTNYePbS0rKUmaxVbXw=="],
"@types/json-schema": ["@types/json-schema@7.0.15", "", {}, "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA=="],
"@types/ms": ["@types/ms@2.1.0", "", {}, "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA=="],
"@types/mssql": ["@types/mssql@9.1.8", "", { "dependencies": { "@types/node": "*", "tarn": "^3.0.1", "tedious": "*" } }, "sha512-mt9h5jWj+DYE5jxnKaWSV/GqDf9FV52XYVk6T3XZF69noEe+JJV6MKirii48l81+cjmAkSq+qeKX+k61fHkYrQ=="],
"@types/node": ["@types/node@25.1.0", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-t7frlewr6+cbx+9Ohpl0NOTKXZNV9xHRmNOvql47BFJKcEG1CxtxlPEEe+gR9uhVWM4DwhnvTF110mIL4yP9RA=="],
"@types/node": ["@types/node@25.6.0", "", { "dependencies": { "undici-types": "~7.19.0" } }, "sha512-+qIYRKdNYJwY3vRCZMdJbPLJAtGjQBudzZzdzwQYkEPQd+PJGixUL5QfvCLDaULoLv+RhT3LDkwEfKaAkgSmNQ=="],
"@types/qrcode": ["@types/qrcode@1.5.6", "", { "dependencies": { "@types/node": "*" } }, "sha512-te7NQcV2BOvdj2b1hCAHzAoMNuj65kNBMz0KBaxM6c3VGBOhU0dURQKOtH8CFNI/dsKkwlv32p26qYQTWoB5bw=="],
"@types/readable-stream": ["@types/readable-stream@4.0.23", "", { "dependencies": { "@types/node": "*" } }, "sha512-wwXrtQvbMHxCbBgjHaMGEmImFTQxxpfMOR/ZoQnXxB1woqkUbdLGFDgauo00Py9IudiaqSeiBiulSV9i6XIPig=="],
"@types/retry": ["@types/retry@0.12.0", "", {}, "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA=="],
"@types/ws": ["@types/ws@8.18.1", "", { "dependencies": { "@types/node": "*" } }, "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg=="],
"@typescript-eslint/eslint-plugin": ["@typescript-eslint/eslint-plugin@8.54.0", "", { "dependencies": { "@eslint-community/regexpp": "^4.12.2", "@typescript-eslint/scope-manager": "8.54.0", "@typescript-eslint/type-utils": "8.54.0", "@typescript-eslint/utils": "8.54.0", "@typescript-eslint/visitor-keys": "8.54.0", "ignore": "^7.0.5", "natural-compare": "^1.4.0", "ts-api-utils": "^2.4.0" }, "peerDependencies": { "@typescript-eslint/parser": "^8.54.0", "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-hAAP5io/7csFStuOmR782YmTthKBJ9ND3WVL60hcOjvtGFb+HJxH4O5huAcmcZ9v9G8P+JETiZ/G1B8MALnWZQ=="],
"@types/yauzl": ["@types/yauzl@2.10.3", "", { "dependencies": { "@types/node": "*" } }, "sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q=="],
"@typescript-eslint/parser": ["@typescript-eslint/parser@8.54.0", "", { "dependencies": { "@typescript-eslint/scope-manager": "8.54.0", "@typescript-eslint/types": "8.54.0", "@typescript-eslint/typescript-estree": "8.54.0", "@typescript-eslint/visitor-keys": "8.54.0", "debug": "^4.4.3" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-BtE0k6cjwjLZoZixN0t5AKP0kSzlGu7FctRXYuPAm//aaiZhmfq1JwdYpYr1brzEspYyFeF+8XF5j2VK6oalrA=="],
"@typescript-eslint/eslint-plugin": ["@typescript-eslint/eslint-plugin@8.59.1", "", { "dependencies": { "@eslint-community/regexpp": "^4.12.2", "@typescript-eslint/scope-manager": "8.59.1", "@typescript-eslint/type-utils": "8.59.1", "@typescript-eslint/utils": "8.59.1", "@typescript-eslint/visitor-keys": "8.59.1", "ignore": "^7.0.5", "natural-compare": "^1.4.0", "ts-api-utils": "^2.5.0" }, "peerDependencies": { "@typescript-eslint/parser": "^8.59.1", "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } }, "sha512-BOziFIfE+6osHO9FoJG4zjoHUcvI7fTNBSpdAwrNH0/TLvzjsk2oo8XSSOT2HhqUyhZPfHv4UOffoJ9oEEQ7Ag=="],
"@typescript-eslint/project-service": ["@typescript-eslint/project-service@8.54.0", "", { "dependencies": { "@typescript-eslint/tsconfig-utils": "^8.54.0", "@typescript-eslint/types": "^8.54.0", "debug": "^4.4.3" }, "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-YPf+rvJ1s7MyiWM4uTRhE4DvBXrEV+d8oC3P9Y2eT7S+HBS0clybdMIPnhiATi9vZOYDc7OQ1L/i6ga6NFYK/g=="],
"@typescript-eslint/parser": ["@typescript-eslint/parser@8.59.1", "", { "dependencies": { "@typescript-eslint/scope-manager": "8.59.1", "@typescript-eslint/types": "8.59.1", "@typescript-eslint/typescript-estree": "8.59.1", "@typescript-eslint/visitor-keys": "8.59.1", "debug": "^4.4.3" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } }, "sha512-HDQH9O/47Dxi1ceDhBXdaldtf/WV9yRYMjbjCuNk3qnaTD564qwv61Y7+gTxwxRKzSrgO5uhtw584igXVuuZkA=="],
"@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@8.54.0", "", { "dependencies": { "@typescript-eslint/types": "8.54.0", "@typescript-eslint/visitor-keys": "8.54.0" } }, "sha512-27rYVQku26j/PbHYcVfRPonmOlVI6gihHtXFbTdB5sb6qA0wdAQAbyXFVarQ5t4HRojIz64IV90YtsjQSSGlQg=="],
"@typescript-eslint/project-service": ["@typescript-eslint/project-service@8.59.1", "", { "dependencies": { "@typescript-eslint/tsconfig-utils": "^8.59.1", "@typescript-eslint/types": "^8.59.1", "debug": "^4.4.3" }, "peerDependencies": { "typescript": ">=4.8.4 <6.1.0" } }, "sha512-+MuHQlHiEr00Of/IQbE/MmEoi44znZHbR/Pz7Opq4HryUOlRi+/44dro9Ycy8Fyo+/024IWtw8m4JUMCGTYxDg=="],
"@typescript-eslint/tsconfig-utils": ["@typescript-eslint/tsconfig-utils@8.54.0", "", { "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-dRgOyT2hPk/JwxNMZDsIXDgyl9axdJI3ogZ2XWhBPsnZUv+hPesa5iuhdYt2gzwA9t8RE5ytOJ6xB0moV0Ujvw=="],
"@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@8.59.1", "", { "dependencies": { "@typescript-eslint/types": "8.59.1", "@typescript-eslint/visitor-keys": "8.59.1" } }, "sha512-LwuHQI4pDOYVKvmH2dkaJo6YZCSgouVgnS/z7yBPKBMvgtBvyLqiLy9Z6b7+m/TRcX1NFYUqZetI5Y+aT4GEfg=="],
"@typescript-eslint/type-utils": ["@typescript-eslint/type-utils@8.54.0", "", { "dependencies": { "@typescript-eslint/types": "8.54.0", "@typescript-eslint/typescript-estree": "8.54.0", "@typescript-eslint/utils": "8.54.0", "debug": "^4.4.3", "ts-api-utils": "^2.4.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-hiLguxJWHjjwL6xMBwD903ciAwd7DmK30Y9Axs/etOkftC3ZNN9K44IuRD/EB08amu+Zw6W37x9RecLkOo3pMA=="],
"@typescript-eslint/tsconfig-utils": ["@typescript-eslint/tsconfig-utils@8.59.1", "", { "peerDependencies": { "typescript": ">=4.8.4 <6.1.0" } }, "sha512-/0nEyPbX7gRsk0Uwfe4ALwwgxuA66d/l2mhRDNlAvaj4U3juhUtJNq0DsY8M2AYwwb9rEq2hrC3IcIcEt++iJA=="],
"@typescript-eslint/types": ["@typescript-eslint/types@8.54.0", "", {}, "sha512-PDUI9R1BVjqu7AUDsRBbKMtwmjWcn4J3le+5LpcFgWULN3LvHC5rkc9gCVxbrsrGmO1jfPybN5s6h4Jy+OnkAA=="],
"@typescript-eslint/type-utils": ["@typescript-eslint/type-utils@8.59.1", "", { "dependencies": { "@typescript-eslint/types": "8.59.1", "@typescript-eslint/typescript-estree": "8.59.1", "@typescript-eslint/utils": "8.59.1", "debug": "^4.4.3", "ts-api-utils": "^2.5.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } }, "sha512-klWPBR2ciQHS3f++ug/mVnWKPjBUo7icEL3FAO1lhAR1Z1i5NQYZ1EannMSRYcq5qCv5wNALlXr6fksRHyYl7w=="],
"@typescript-eslint/typescript-estree": ["@typescript-eslint/typescript-estree@8.54.0", "", { "dependencies": { "@typescript-eslint/project-service": "8.54.0", "@typescript-eslint/tsconfig-utils": "8.54.0", "@typescript-eslint/types": "8.54.0", "@typescript-eslint/visitor-keys": "8.54.0", "debug": "^4.4.3", "minimatch": "^9.0.5", "semver": "^7.7.3", "tinyglobby": "^0.2.15", "ts-api-utils": "^2.4.0" }, "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-BUwcskRaPvTk6fzVWgDPdUndLjB87KYDrN5EYGetnktoeAvPtO4ONHlAZDnj5VFnUANg0Sjm7j4usBlnoVMHwA=="],
"@typescript-eslint/types": ["@typescript-eslint/types@8.59.1", "", {}, "sha512-ZDCjgccSdYPw5Bxh+my4Z0lJU96ZDN7jbBzvmEn0FZx3RtU1C7VWl6NbDx94bwY3V5YsgwRzJPOgeY2Q/nLG8A=="],
"@typescript-eslint/utils": ["@typescript-eslint/utils@8.54.0", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.9.1", "@typescript-eslint/scope-manager": "8.54.0", "@typescript-eslint/types": "8.54.0", "@typescript-eslint/typescript-estree": "8.54.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-9Cnda8GS57AQakvRyG0PTejJNlA2xhvyNtEVIMlDWOOeEyBkYWhGPnfrIAnqxLMTSTo6q8g12XVjjev5l1NvMA=="],
"@typescript-eslint/typescript-estree": ["@typescript-eslint/typescript-estree@8.59.1", "", { "dependencies": { "@typescript-eslint/project-service": "8.59.1", "@typescript-eslint/tsconfig-utils": "8.59.1", "@typescript-eslint/types": "8.59.1", "@typescript-eslint/visitor-keys": "8.59.1", "debug": "^4.4.3", "minimatch": "^10.2.2", "semver": "^7.7.3", "tinyglobby": "^0.2.15", "ts-api-utils": "^2.5.0" }, "peerDependencies": { "typescript": ">=4.8.4 <6.1.0" } }, "sha512-OUd+vJS05sSkOip+BkZ/2NS8RMxrAAJemsC6vU3kmfLyeaJT0TftHkV9mcx2107MmsBVXXexhVu4F0TZXyMl4g=="],
"@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.54.0", "", { "dependencies": { "@typescript-eslint/types": "8.54.0", "eslint-visitor-keys": "^4.2.1" } }, "sha512-VFlhGSl4opC0bprJiItPQ1RfUhGDIBokcPwaFH4yiBCaNPeld/9VeXbiPO1cLyorQi1G1vL+ecBk1x8o1axORA=="],
"@typescript-eslint/utils": ["@typescript-eslint/utils@8.59.1", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.9.1", "@typescript-eslint/scope-manager": "8.59.1", "@typescript-eslint/types": "8.59.1", "@typescript-eslint/typescript-estree": "8.59.1" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } }, "sha512-3pIeoXhCeYH9FSCBI8P3iNwJlGuzPlYKkTlen2O9T1DSeeg8UG8jstq6BLk+Mda0qup7mgk4z4XL4OzRaxZ8LA=="],
"@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.59.1", "", { "dependencies": { "@typescript-eslint/types": "8.59.1", "eslint-visitor-keys": "^5.0.0" } }, "sha512-LdDNl6C5iJExcM0Yh0PwAIBb9PrSiCsWamF/JyEZawm3kFDnRoaq3LGE4bpyRao/fWeGKKyw7icx0YxrLFC5Cg=="],
"@typespec/ts-http-runtime": ["@typespec/ts-http-runtime@0.3.2", "", { "dependencies": { "http-proxy-agent": "^7.0.0", "https-proxy-agent": "^7.0.0", "tslib": "^2.6.2" } }, "sha512-IlqQ/Gv22xUC1r/WQm4StLkYQmaaTsXAhUVsNE0+xiyf0yRFiH5++q78U3bw6bLKDCTmh0uqKB9eG9+Bt75Dkg=="],
@@ -332,7 +360,7 @@
"agent-base": ["agent-base@7.1.4", "", {}, "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ=="],
"ajv": ["ajv@6.12.6", "", { "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", "json-schema-traverse": "^0.4.1", "uri-js": "^4.2.2" } }, "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g=="],
"ajv": ["ajv@6.14.0", "", { "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", "json-schema-traverse": "^0.4.1", "uri-js": "^4.2.2" } }, "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw=="],
"ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="],
@@ -340,14 +368,36 @@
"argparse": ["argparse@2.0.1", "", {}, "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="],
"arr-union": ["arr-union@3.1.0", "", {}, "sha512-sKpyeERZ02v1FeCZT8lrfJq5u6goHCtpTAzPwJYe7c8SPFOboNjNg1vz2L4VTn9T4PQxEx13TbXLmYUcS6Ug7Q=="],
"ast-types": ["ast-types@0.13.4", "", { "dependencies": { "tslib": "^2.0.1" } }, "sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w=="],
"async": ["async@0.2.10", "", {}, "sha512-eAkdoKxU6/LkKDBzLpT+t6Ff5EtfSF4wx1WfJiPEEV7WNLnDaRXk0oVysiEPm262roaachGexwUv94WhSgN5TQ=="],
"asynckit": ["asynckit@0.4.0", "", {}, "sha1-x57Zf380y48robyXkLzDZkdLS3k="],
"axios": ["axios@1.13.4", "", { "dependencies": { "follow-redirects": "^1.15.6", "form-data": "^4.0.4", "proxy-from-env": "^1.1.0" } }, "sha512-1wVkUaAO6WyaYtCkcYCOx12ZgpGf9Zif+qXa4n+oYzK558YryKqiL6UWwd5DqiH3VRW0GYhTZQ/vlgJrCoNQlg=="],
"axios": ["axios@1.15.2", "", { "dependencies": { "follow-redirects": "^1.15.11", "form-data": "^4.0.5", "proxy-from-env": "^2.1.0" } }, "sha512-wLrXxPtcrPTsNlJmKjkPnNPK2Ihe0hn0wGSaTEiHRPxwjvJwT3hKmXF4dpqxmPO9SoNb2FsYXj/xEo0gHN+D5A=="],
"b4a": ["b4a@1.7.3", "", { "peerDependencies": { "react-native-b4a": "*" }, "optionalPeers": ["react-native-b4a"] }, "sha512-5Q2mfq2WfGuFp3uS//0s6baOJLMoVduPYVeNmDYxu5OUA1/cBfvr2RIS7vi62LdNj/urk1hfmj867I3qt6uZ7Q=="],
"balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="],
"bare-events": ["bare-events@2.8.2", "", { "peerDependencies": { "bare-abort-controller": "*" }, "optionalPeers": ["bare-abort-controller"] }, "sha512-riJjyv1/mHLIPX4RwiK+oW9/4c3TEUeORHKefKAKnZ5kyslbN+HXowtbaVEqt4IMUB7OXlfixcs6gsFeo/jhiQ=="],
"bare-fs": ["bare-fs@4.5.3", "", { "dependencies": { "bare-events": "^2.5.4", "bare-path": "^3.0.0", "bare-stream": "^2.6.4", "bare-url": "^2.2.2", "fast-fifo": "^1.3.2" }, "peerDependencies": { "bare-buffer": "*" }, "optionalPeers": ["bare-buffer"] }, "sha512-9+kwVx8QYvt3hPWnmb19tPnh38c6Nihz8Lx3t0g9+4GoIf3/fTgYwM4Z6NxgI+B9elLQA7mLE9PpqcWtOMRDiQ=="],
"bare-os": ["bare-os@3.6.2", "", {}, "sha512-T+V1+1srU2qYNBmJCXZkUY5vQ0B4FSlL3QDROnKQYOqeiQR8UbjNHlPa+TIbM4cuidiN9GaTaOZgSEgsvPbh5A=="],
"bare-path": ["bare-path@3.0.0", "", { "dependencies": { "bare-os": "^3.0.1" } }, "sha512-tyfW2cQcB5NN8Saijrhqn0Zh7AnFNsnczRcuWODH0eYAXBsJ5gVxAUuNr7tsHSC6IZ77cA0SitzT+s47kot8Mw=="],
"bare-stream": ["bare-stream@2.7.0", "", { "dependencies": { "streamx": "^2.21.0" }, "peerDependencies": { "bare-buffer": "*", "bare-events": "*" }, "optionalPeers": ["bare-buffer", "bare-events"] }, "sha512-oyXQNicV1y8nc2aKffH+BUHFRXmx6VrPzlnaEvMhram0nPBrKcEdcyBg5r08D0i8VxngHFAiVyn1QKXpSG0B8A=="],
"bare-url": ["bare-url@2.3.2", "", { "dependencies": { "bare-path": "^3.0.0" } }, "sha512-ZMq4gd9ngV5aTMa5p9+UfY0b3skwhHELaDkhEHetMdX0LRkW9kzaym4oo/Eh+Ghm0CCDuMTsRIGM/ytUc1ZYmw=="],
"base64-js": ["base64-js@1.5.1", "", {}, "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="],
"basic-ftp": ["basic-ftp@5.1.0", "", {}, "sha512-RkaJzeJKDbaDWTIPiJwubyljaEPwpVWkm9Rt5h9Nd6h7tEXTJ3VB4qxdZBioV7JO5yLUaOKwz7vDOzlncUsegw=="],
"bignumber.js": ["bignumber.js@9.3.1", "", {}, "sha512-Ko0uX15oIUS7wJ3Rb30Fs6SkVbLmPBAKdlm7q9+ak9bbIeFf0MwuBsQV6z7+X768/cHsfg+WlysDWJcmthjsjQ=="],
"bl": ["bl@6.1.6", "", { "dependencies": { "@types/readable-stream": "^4.0.0", "buffer": "^6.0.3", "inherits": "^2.0.4", "readable-stream": "^4.2.0" } }, "sha512-jLsPgN/YSvPUg9UX0Kd73CXpm2Psg9FxMeCSXnk3WBO3CMT10JMwijubhGfHCnFu6TPn1ei3b975dxv7K2pWVg=="],
@@ -356,9 +406,11 @@
"buffer": ["buffer@6.0.3", "", { "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.2.1" } }, "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA=="],
"buffer-crc32": ["buffer-crc32@0.2.13", "", {}, "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ=="],
"buffer-equal-constant-time": ["buffer-equal-constant-time@1.0.1", "", {}, "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA=="],
"bun-types": ["bun-types@1.3.7", "", { "dependencies": { "@types/node": "*" } }, "sha512-qyschsA03Qz+gou+apt6HNl6HnI+sJJLL4wLDke4iugsE6584CMupOtTY1n+2YC9nGVrEKUlTs99jjRLKgWnjQ=="],
"bun-types": ["bun-types@1.3.13", "", { "dependencies": { "@types/node": "*" } }, "sha512-QXKeHLlOLqQX9LgYaHJfzdBaV21T63HhFJnvuRCcjZiaUDpbs5ED1MgxbMra71CsryN/1dAoXuJJJwIv/2drVA=="],
"bundle-name": ["bundle-name@4.1.0", "", { "dependencies": { "run-applescript": "^7.0.0" } }, "sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q=="],
@@ -370,8 +422,12 @@
"chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="],
"chromium-bidi": ["chromium-bidi@14.0.0", "", { "dependencies": { "mitt": "^3.0.1", "zod": "^3.24.1" }, "peerDependencies": { "devtools-protocol": "*" } }, "sha512-9gYlLtS6tStdRWzrtXaTMnqcM4dudNegMXJxkR0I/CXObHalYeYcAMPrL19eroNZHtJ8DQmu1E+ZNOYu/IXMXw=="],
"cliui": ["cliui@6.0.0", "", { "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.0", "wrap-ansi": "^6.2.0" } }, "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ=="],
"clone-deep": ["clone-deep@0.2.4", "", { "dependencies": { "for-own": "^0.1.3", "is-plain-object": "^2.0.1", "kind-of": "^3.0.2", "lazy-cache": "^1.0.3", "shallow-clone": "^0.1.2" } }, "sha512-we+NuQo2DHhSl+DP6jlUiAhyAjBQrYnpOk15rN6c6JSPScjiCLh8IbSU+VTcph6YS3o7mASE8a0+gbZ7ChLpgg=="],
"color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="],
"color-name": ["color-name@1.1.4", "", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="],
@@ -382,7 +438,7 @@
"concat-map": ["concat-map@0.0.1", "", {}, "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="],
"cross-fetch": ["cross-fetch@4.1.0", "", { "dependencies": { "node-fetch": "^2.7.0" } }, "sha512-uKm5PU+MHTootlWEY+mZ4vvXoCn4fLQxT9dSc1sXVMSFkINTJVN8cAQROpwcKm8bJ/c7rgZVIBWzH5T78sNZZw=="],
"cosmiconfig": ["cosmiconfig@9.0.0", "", { "dependencies": { "env-paths": "^2.2.1", "import-fresh": "^3.3.0", "js-yaml": "^4.1.0", "parse-json": "^5.2.0" }, "peerDependencies": { "typescript": ">=4.9.5" }, "optionalPeers": ["typescript"] }, "sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg=="],
"cross-spawn": ["cross-spawn@7.0.6", "", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA=="],
@@ -394,23 +450,29 @@
"deep-is": ["deep-is@0.1.4", "", {}, "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ=="],
"deepmerge": ["deepmerge@4.3.1", "", {}, "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A=="],
"default-browser": ["default-browser@5.4.0", "", { "dependencies": { "bundle-name": "^4.1.0", "default-browser-id": "^5.0.0" } }, "sha512-XDuvSq38Hr1MdN47EDvYtx3U0MTqpCEn+F6ft8z2vYDzMrvQhVp0ui9oQdqW3MvK3vqUETglt1tVGgjLuJ5izg=="],
"default-browser-id": ["default-browser-id@5.0.1", "", {}, "sha512-x1VCxdX4t+8wVfd1so/9w+vQ4vx7lKd2Qp5tDRutErwmR85OgmfX7RlLRMWafRMY7hbEiXIbudNrjOAPa/hL8Q=="],
"define-lazy-prop": ["define-lazy-prop@3.0.0", "", {}, "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg=="],
"degenerator": ["degenerator@5.0.1", "", { "dependencies": { "ast-types": "^0.13.4", "escodegen": "^2.1.0", "esprima": "^4.0.1" } }, "sha512-TllpMR/t0M5sqCXfj85i4XaAzxmS5tVA16dqvdkMwGmzI+dXLXnw3J+3Vdv7VKw+ThlTMboK6i9rnZ6Nntj5CQ=="],
"delayed-stream": ["delayed-stream@1.0.0", "", {}, "sha1-3zrhmayt+31ECqrgsp4icrJOxhk="],
"detect-libc": ["detect-libc@2.1.2", "", {}, "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ=="],
"devtools-protocol": ["devtools-protocol@0.0.1595872", "", {}, "sha512-kRfgp8vWVjBu/fbYCiVFiOqsCk3CrMKEo3WbgGT2NXK2dG7vawWPBljixajVgGK9II8rDO9G0oD0zLt3I1daRg=="],
"dijkstrajs": ["dijkstrajs@1.0.3", "", {}, "sha512-qiSlmBq9+BCdCA/L46dw8Uy93mloxsPSbwnm5yrKn2vMPiy8KyAskTF6zuV/j5BMsmOGZDPs7KjU+mjb670kfA=="],
"dotenv": ["dotenv@17.2.3", "", {}, "sha512-JVUnt+DUIzu87TABbhPmNfVdBDt18BLOWjMUFJMSi/Qqg7NTYtabbvSNJGOJ7afbRuv9D/lngizHtP7QyLQ+9w=="],
"dotenv": ["dotenv@17.4.2", "", {}, "sha512-nI4U3TottKAcAD9LLud4Cb7b2QztQMUEfHbvhTH09bqXTxnSie8WnjPALV/WMCrJZ6UV/qHJ6L03OqO3LcdYZw=="],
"drizzle-kit": ["drizzle-kit@1.0.0-beta.9-e89174b", "", { "dependencies": { "@drizzle-team/brocli": "^0.11.0", "@js-temporal/polyfill": "^0.5.1", "esbuild": "^0.25.10", "tsx": "^4.20.6" }, "bin": { "drizzle-kit": "bin.cjs" } }, "sha512-Xrw3k8E2CbSZr+kqe3k5W4oxd2fbEyczjKtyGIkAq0x9Wqpa/VtAT6Mkh83sIzqG4OSN7lOoUafsDxSE/AR7RA=="],
"drizzle-orm": ["drizzle-orm@1.0.0-beta.9-e89174b", "", { "peerDependencies": { "@aws-sdk/client-rds-data": ">=3", "@cloudflare/workers-types": ">=4", "@effect/sql": "^0.48.5", "@effect/sql-pg": "^0.49.7", "@electric-sql/pglite": ">=0.2.0", "@libsql/client": ">=0.10.0", "@libsql/client-wasm": ">=0.10.0", "@neondatabase/serverless": ">=0.10.0", "@op-engineering/op-sqlite": ">=2", "@opentelemetry/api": "^1.4.1", "@planetscale/database": ">=1.13", "@prisma/client": "*", "@sqlitecloud/drivers": ">=1.0.653", "@tidbcloud/serverless": "*", "@tursodatabase/database": ">=0.2.1", "@tursodatabase/database-common": ">=0.2.1", "@tursodatabase/database-wasm": ">=0.2.1", "@types/better-sqlite3": "*", "@types/mssql": "^9.1.4", "@types/pg": "*", "@types/sql.js": "*", "@upstash/redis": ">=1.34.7", "@vercel/postgres": ">=0.8.0", "@xata.io/client": "*", "better-sqlite3": ">=9.3.0", "bun-types": "*", "expo-sqlite": ">=14.0.0", "gel": ">=2", "mssql": "^11.0.1", "mysql2": ">=2", "pg": ">=8", "postgres": ">=3", "sql.js": ">=1", "sqlite3": ">=5" }, "optionalPeers": ["@aws-sdk/client-rds-data", "@cloudflare/workers-types", "@effect/sql", "@effect/sql-pg", "@electric-sql/pglite", "@libsql/client", "@libsql/client-wasm", "@neondatabase/serverless", "@op-engineering/op-sqlite", "@opentelemetry/api", "@planetscale/database", "@prisma/client", "@sqlitecloud/drivers", "@tidbcloud/serverless", "@tursodatabase/database", "@tursodatabase/database-common", "@tursodatabase/database-wasm", "@types/better-sqlite3", "@types/pg", "@types/sql.js", "@upstash/redis", "@vercel/postgres", "@xata.io/client", "better-sqlite3", "bun-types", "expo-sqlite", "gel", "mysql2", "pg", "postgres", "sql.js", "sqlite3"] }, "sha512-B5KR/qYMZ0JMOurK+0xi1ObpOQcgrjaC9wHUiU2eTJjLemuh2CoQIw6yur68NxZG6Xcd0b9qghUNC/78/bEfbg=="],
"drizzle-orm": ["drizzle-orm@1.0.0-beta.21", "", { "peerDependencies": { "@aws-sdk/client-rds-data": ">=3", "@cloudflare/workers-types": ">=4", "@effect/sql": "^0.48.5", "@effect/sql-pg": "^0.49.7", "@electric-sql/pglite": ">=0.2.0", "@libsql/client": ">=0.10.0", "@libsql/client-wasm": ">=0.10.0", "@neondatabase/serverless": ">=0.10.0", "@op-engineering/op-sqlite": ">=2", "@opentelemetry/api": "^1.4.1", "@planetscale/database": ">=1.13", "@sinclair/typebox": ">=0.34.8", "@sqlitecloud/drivers": ">=1.0.653", "@tidbcloud/serverless": "*", "@tursodatabase/database": ">=0.2.1", "@tursodatabase/database-common": ">=0.2.1", "@tursodatabase/database-wasm": ">=0.2.1", "@types/better-sqlite3": "*", "@types/mssql": "^9.1.4", "@types/pg": "*", "@types/sql.js": "*", "@upstash/redis": ">=1.34.7", "@vercel/postgres": ">=0.8.0", "@xata.io/client": "*", "arktype": ">=2.0.0", "better-sqlite3": ">=9.3.0", "bun-types": "*", "expo-sqlite": ">=14.0.0", "gel": ">=2", "mssql": "^11.0.1", "mysql2": ">=2", "pg": ">=8", "postgres": ">=3", "sql.js": ">=1", "sqlite3": ">=5", "typebox": ">=1.0.0", "valibot": ">=1.0.0-beta.7", "zod": "^3.25.0 || ^4.0.0" }, "optionalPeers": ["@aws-sdk/client-rds-data", "@cloudflare/workers-types", "@effect/sql", "@effect/sql-pg", "@electric-sql/pglite", "@libsql/client", "@libsql/client-wasm", "@neondatabase/serverless", "@op-engineering/op-sqlite", "@opentelemetry/api", "@planetscale/database", "@sinclair/typebox", "@sqlitecloud/drivers", "@tidbcloud/serverless", "@tursodatabase/database", "@tursodatabase/database-common", "@tursodatabase/database-wasm", "@types/better-sqlite3", "@types/pg", "@types/sql.js", "@upstash/redis", "@vercel/postgres", "@xata.io/client", "arktype", "better-sqlite3", "bun-types", "expo-sqlite", "gel", "mysql2", "pg", "postgres", "sql.js", "sqlite3", "typebox", "valibot", "zod"] }, "sha512-HZcIbVn5J9T/Z91Wj12Pn7Pi8/1aykS/GPJf2lXeZnEuPjxaBfQ+YAt0Sl+XI+9R/D1BpK+2fdIqbpuaTbcvqA=="],
"dunder-proto": ["dunder-proto@1.0.1", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.1", "es-errors": "^1.3.0", "gopd": "^1.2.0" } }, "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A=="],
@@ -420,6 +482,12 @@
"emoji-regex": ["emoji-regex@10.6.0", "", {}, "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A=="],
"end-of-stream": ["end-of-stream@1.4.5", "", { "dependencies": { "once": "^1.4.0" } }, "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg=="],
"env-paths": ["env-paths@2.2.1", "", {}, "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A=="],
"error-ex": ["error-ex@1.3.4", "", { "dependencies": { "is-arrayish": "^0.2.1" } }, "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ=="],
"es-define-property": ["es-define-property@1.0.1", "", {}, "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g=="],
"es-errors": ["es-errors@1.3.0", "", {}, "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw=="],
@@ -430,9 +498,13 @@
"esbuild": ["esbuild@0.25.12", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.25.12", "@esbuild/android-arm": "0.25.12", "@esbuild/android-arm64": "0.25.12", "@esbuild/android-x64": "0.25.12", "@esbuild/darwin-arm64": "0.25.12", "@esbuild/darwin-x64": "0.25.12", "@esbuild/freebsd-arm64": "0.25.12", "@esbuild/freebsd-x64": "0.25.12", "@esbuild/linux-arm": "0.25.12", "@esbuild/linux-arm64": "0.25.12", "@esbuild/linux-ia32": "0.25.12", "@esbuild/linux-loong64": "0.25.12", "@esbuild/linux-mips64el": "0.25.12", "@esbuild/linux-ppc64": "0.25.12", "@esbuild/linux-riscv64": "0.25.12", "@esbuild/linux-s390x": "0.25.12", "@esbuild/linux-x64": "0.25.12", "@esbuild/netbsd-arm64": "0.25.12", "@esbuild/netbsd-x64": "0.25.12", "@esbuild/openbsd-arm64": "0.25.12", "@esbuild/openbsd-x64": "0.25.12", "@esbuild/openharmony-arm64": "0.25.12", "@esbuild/sunos-x64": "0.25.12", "@esbuild/win32-arm64": "0.25.12", "@esbuild/win32-ia32": "0.25.12", "@esbuild/win32-x64": "0.25.12" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg=="],
"escalade": ["escalade@3.2.0", "", {}, "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA=="],
"escape-string-regexp": ["escape-string-regexp@4.0.0", "", {}, "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA=="],
"eslint": ["eslint@9.39.2", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", "@eslint/config-array": "^0.21.1", "@eslint/config-helpers": "^0.4.2", "@eslint/core": "^0.17.0", "@eslint/eslintrc": "^3.3.1", "@eslint/js": "9.39.2", "@eslint/plugin-kit": "^0.4.1", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/retry": "^0.4.2", "@types/estree": "^1.0.6", "ajv": "^6.12.4", "chalk": "^4.0.0", "cross-spawn": "^7.0.6", "debug": "^4.3.2", "escape-string-regexp": "^4.0.0", "eslint-scope": "^8.4.0", "eslint-visitor-keys": "^4.2.1", "espree": "^10.4.0", "esquery": "^1.5.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", "file-entry-cache": "^8.0.0", "find-up": "^5.0.0", "glob-parent": "^6.0.2", "ignore": "^5.2.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", "json-stable-stringify-without-jsonify": "^1.0.1", "lodash.merge": "^4.6.2", "minimatch": "^3.1.2", "natural-compare": "^1.4.0", "optionator": "^0.9.3" }, "peerDependencies": { "jiti": "*" }, "optionalPeers": ["jiti"], "bin": { "eslint": "bin/eslint.js" } }, "sha512-LEyamqS7W5HB3ujJyvi0HQK/dtVINZvd5mAAp9eT5S/ujByGjiZLCzPcHVzuXbpJDJF/cxwHlfceVUDZ2lnSTw=="],
"escodegen": ["escodegen@2.1.0", "", { "dependencies": { "esprima": "^4.0.1", "estraverse": "^5.2.0", "esutils": "^2.0.2" }, "optionalDependencies": { "source-map": "~0.6.1" }, "bin": { "esgenerate": "bin/esgenerate.js", "escodegen": "bin/escodegen.js" } }, "sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w=="],
"eslint": ["eslint@9.39.4", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", "@eslint/config-array": "^0.21.2", "@eslint/config-helpers": "^0.4.2", "@eslint/core": "^0.17.0", "@eslint/eslintrc": "^3.3.5", "@eslint/js": "9.39.4", "@eslint/plugin-kit": "^0.4.1", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/retry": "^0.4.2", "@types/estree": "^1.0.6", "ajv": "^6.14.0", "chalk": "^4.0.0", "cross-spawn": "^7.0.6", "debug": "^4.3.2", "escape-string-regexp": "^4.0.0", "eslint-scope": "^8.4.0", "eslint-visitor-keys": "^4.2.1", "espree": "^10.4.0", "esquery": "^1.5.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", "file-entry-cache": "^8.0.0", "find-up": "^5.0.0", "glob-parent": "^6.0.2", "ignore": "^5.2.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", "json-stable-stringify-without-jsonify": "^1.0.1", "lodash.merge": "^4.6.2", "minimatch": "^3.1.5", "natural-compare": "^1.4.0", "optionator": "^0.9.3" }, "peerDependencies": { "jiti": "*" }, "optionalPeers": ["jiti"], "bin": { "eslint": "bin/eslint.js" } }, "sha512-XoMjdBOwe/esVgEvLmNsD3IRHkm7fbKIUGvrleloJXUZgDHig2IPWNniv+GwjyJXzuNqVjlr5+4yVUZjycJwfQ=="],
"eslint-scope": ["eslint-scope@8.4.0", "", { "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^5.2.0" } }, "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg=="],
@@ -440,6 +512,8 @@
"espree": ["espree@10.4.0", "", { "dependencies": { "acorn": "^8.15.0", "acorn-jsx": "^5.3.2", "eslint-visitor-keys": "^4.2.1" } }, "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ=="],
"esprima": ["esprima@4.0.1", "", { "bin": { "esparse": "./bin/esparse.js", "esvalidate": "./bin/esvalidate.js" } }, "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A=="],
"esquery": ["esquery@1.6.0", "", { "dependencies": { "estraverse": "^5.1.0" } }, "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg=="],
"esrecurse": ["esrecurse@4.3.0", "", { "dependencies": { "estraverse": "^5.2.0" } }, "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag=="],
@@ -452,14 +526,22 @@
"events": ["events@3.3.0", "", {}, "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q=="],
"events-universal": ["events-universal@1.0.1", "", { "dependencies": { "bare-events": "^2.7.0" } }, "sha512-LUd5euvbMLpwOF8m6ivPCbhQeSiYVNb8Vs0fQ8QjXo0JTkEHpz8pxdQf0gStltaPpw0Cca8b39KxvK9cfKRiAw=="],
"extend": ["extend@3.0.2", "", {}, "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g=="],
"extract-zip": ["extract-zip@2.0.1", "", { "dependencies": { "debug": "^4.1.1", "get-stream": "^5.1.0", "yauzl": "^2.10.0" }, "optionalDependencies": { "@types/yauzl": "^2.9.1" }, "bin": { "extract-zip": "cli.js" } }, "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg=="],
"fast-deep-equal": ["fast-deep-equal@3.1.3", "", {}, "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="],
"fast-fifo": ["fast-fifo@1.3.2", "", {}, "sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ=="],
"fast-json-stable-stringify": ["fast-json-stable-stringify@2.1.0", "", {}, "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw=="],
"fast-levenshtein": ["fast-levenshtein@2.0.6", "", {}, "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw=="],
"fd-slicer": ["fd-slicer@1.1.0", "", { "dependencies": { "pend": "~1.2.0" } }, "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g=="],
"fdir": ["fdir@6.5.0", "", { "peerDependencies": { "picomatch": "^3 || ^4" }, "optionalPeers": ["picomatch"] }, "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg=="],
"fetch-blob": ["fetch-blob@3.2.0", "", { "dependencies": { "node-domexception": "^1.0.0", "web-streams-polyfill": "^3.0.3" } }, "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ=="],
@@ -472,8 +554,14 @@
"flatted": ["flatted@3.3.3", "", {}, "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg=="],
"fluent-ffmpeg": ["fluent-ffmpeg@2.1.3", "", { "dependencies": { "async": "^0.2.9", "which": "^1.1.1" } }, "sha512-Be3narBNt2s6bsaqP6Jzq91heDgOEaDCJAXcE3qcma/EJBSy5FB4cvO31XBInuAuKBx8Kptf8dkhjK0IOru39Q=="],
"follow-redirects": ["follow-redirects@1.15.11", "", {}, "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ=="],
"for-in": ["for-in@1.0.2", "", {}, "sha512-7EwmXrOjyL+ChxMhmG5lnW9MPt1aIeZEwKhQzoBUdTV0N3zuwWDZYVJatDvZ2OyzPUvdIAZDsCetk3coyMfcnQ=="],
"for-own": ["for-own@0.1.5", "", { "dependencies": { "for-in": "^1.0.1" } }, "sha512-SKmowqGTJoPzLO1T0BBJpkfp3EMacCMOuH40hOUbrbzElVktk4DioXVM99QkLCyKoiuOmyjgcWMpVz2xjE7LZw=="],
"foreground-child": ["foreground-child@3.3.1", "", { "dependencies": { "cross-spawn": "^7.0.6", "signal-exit": "^4.0.1" } }, "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw=="],
"form-data": ["form-data@4.0.5", "", { "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", "es-set-tostringtag": "^2.1.0", "hasown": "^2.0.2", "mime-types": "^2.1.12" } }, "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w=="],
@@ -482,6 +570,8 @@
"fs-extra": ["fs-extra@8.1.0", "", { "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^4.0.0", "universalify": "^0.1.0" } }, "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g=="],
"fs.realpath": ["fs.realpath@1.0.0", "", {}, "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw=="],
"fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="],
"function-bind": ["function-bind@1.1.2", "", {}, "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA=="],
@@ -496,8 +586,12 @@
"get-proto": ["get-proto@1.0.1", "", { "dependencies": { "dunder-proto": "^1.0.1", "es-object-atoms": "^1.0.0" } }, "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g=="],
"get-stream": ["get-stream@5.2.0", "", { "dependencies": { "pump": "^3.0.0" } }, "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA=="],
"get-tsconfig": ["get-tsconfig@4.13.0", "", { "dependencies": { "resolve-pkg-maps": "^1.0.0" } }, "sha512-1VKTZJCwBrvbd+Wn3AOgQP/2Av+TfTCOlE4AcRJE72W1ksZXbAx8PPBR9RzgTeSPzlPMHrbANMH3LbltH73wxQ=="],
"get-uri": ["get-uri@6.0.5", "", { "dependencies": { "basic-ftp": "^5.0.2", "data-uri-to-buffer": "^6.0.2", "debug": "^4.3.4" } }, "sha512-b1O07XYq8eRuVzBNgJLstU6FYc1tS6wnMtF1I1D9lE8LxZSOGZ7LhxN54yPP6mGw5f2CkXY2BQUL9Fx41qvcIg=="],
"glob": ["glob@10.5.0", "", { "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^3.1.2", "minimatch": "^9.0.4", "minipass": "^7.1.2", "package-json-from-dist": "^1.0.0", "path-scurry": "^1.11.1" }, "bin": { "glob": "dist/esm/bin.mjs" } }, "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg=="],
"glob-parent": ["glob-parent@6.0.2", "", { "dependencies": { "is-glob": "^4.0.3" } }, "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A=="],
@@ -536,10 +630,20 @@
"imurmurhash": ["imurmurhash@0.1.4", "", {}, "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA=="],
"inflight": ["inflight@1.0.6", "", { "dependencies": { "once": "^1.3.0", "wrappy": "1" } }, "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA=="],
"inherits": ["inherits@2.0.4", "", {}, "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="],
"ip-address": ["ip-address@10.1.0", "", {}, "sha512-XXADHxXmvT9+CRxhXg56LJovE+bmWnEWB78LB83VZTprKTmaC5QfruXocxzTZ2Kl0DNwKuBdlIhjL8LeY8Sf8Q=="],
"is-arrayish": ["is-arrayish@0.2.1", "", {}, "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg=="],
"is-buffer": ["is-buffer@1.1.6", "", {}, "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w=="],
"is-docker": ["is-docker@3.0.0", "", { "bin": { "is-docker": "cli.js" } }, "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ=="],
"is-extendable": ["is-extendable@0.1.1", "", {}, "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw=="],
"is-extglob": ["is-extglob@2.1.1", "", {}, "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ=="],
"is-fullwidth-code-point": ["is-fullwidth-code-point@3.0.0", "", {}, "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="],
@@ -548,16 +652,22 @@
"is-inside-container": ["is-inside-container@1.0.0", "", { "dependencies": { "is-docker": "^3.0.0" }, "bin": { "is-inside-container": "cli.js" } }, "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA=="],
"is-plain-object": ["is-plain-object@2.0.4", "", { "dependencies": { "isobject": "^3.0.1" } }, "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og=="],
"is-wsl": ["is-wsl@3.1.0", "", { "dependencies": { "is-inside-container": "^1.0.0" } }, "sha512-UcVfVfaK4Sc4m7X3dUSoHoozQGBEFeDC+zVo06t98xe8CzHSZZBekNXH+tu0NalHolcJ/QAGqS46Hef7QXBIMw=="],
"isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="],
"isobject": ["isobject@3.0.1", "", {}, "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg=="],
"jackspeak": ["jackspeak@3.4.3", "", { "dependencies": { "@isaacs/cliui": "^8.0.2" }, "optionalDependencies": { "@pkgjs/parseargs": "^0.11.0" } }, "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw=="],
"js-base64": ["js-base64@3.7.8", "", {}, "sha512-hNngCeKxIUQiEUN3GPJOkz4wF/YvdUdbNL9hsBcMQTkKzboD7T/q3OYOuuPZLUE6dBxSGpwhk5mwuDud7JVAow=="],
"js-md4": ["js-md4@0.3.2", "", {}, "sha512-/GDnfQYsltsjRswQhN9fhv3EMw2sCpUdrdxyWDOUK7eyD++r3gRhzgiQgc/x4MAv2i1iuQ4lxO5mvqM3vj4bwA=="],
"js-tokens": ["js-tokens@4.0.0", "", {}, "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="],
"js-yaml": ["js-yaml@4.1.1", "", { "dependencies": { "argparse": "^2.0.1" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA=="],
"jsbi": ["jsbi@4.3.2", "", {}, "sha512-9fqMSQbhJykSeii05nxKl4m6Eqn2P6rOlYiS+C5Dr/HPIU/7yZxu5qzbs40tgaFORiw2Amd0mirjxatXYMkIew=="],
@@ -566,6 +676,8 @@
"json-buffer": ["json-buffer@3.0.1", "", {}, "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ=="],
"json-parse-even-better-errors": ["json-parse-even-better-errors@2.3.1", "", {}, "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w=="],
"json-schema-traverse": ["json-schema-traverse@0.4.1", "", {}, "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="],
"json-stable-stringify-without-jsonify": ["json-stable-stringify-without-jsonify@1.0.1", "", {}, "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw=="],
@@ -580,9 +692,15 @@
"keyv": ["keyv@4.5.4", "", { "dependencies": { "json-buffer": "3.0.1" } }, "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw=="],
"kind-of": ["kind-of@3.2.2", "", { "dependencies": { "is-buffer": "^1.1.5" } }, "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ=="],
"lazy-cache": ["lazy-cache@1.0.4", "", {}, "sha512-RE2g0b5VGZsOCFOCgP7omTRYFqydmZkBwl5oNnQ1lDYC57uyO9KqNnNVxT7COSHTxrRCWVcAVOcbjk+tvh/rgQ=="],
"levn": ["levn@0.4.1", "", { "dependencies": { "prelude-ls": "^1.2.1", "type-check": "~0.4.0" } }, "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ=="],
"libsql": ["libsql@0.5.22", "", { "dependencies": { "@neon-rs/load": "^0.0.4", "detect-libc": "2.0.2" }, "optionalDependencies": { "@libsql/darwin-arm64": "0.5.22", "@libsql/darwin-x64": "0.5.22", "@libsql/linux-arm-gnueabihf": "0.5.22", "@libsql/linux-arm-musleabihf": "0.5.22", "@libsql/linux-arm64-gnu": "0.5.22", "@libsql/linux-arm64-musl": "0.5.22", "@libsql/linux-x64-gnu": "0.5.22", "@libsql/linux-x64-musl": "0.5.22", "@libsql/win32-x64-msvc": "0.5.22" }, "os": [ "linux", "win32", "darwin", ], "cpu": [ "arm", "x64", "arm64", ] }, "sha512-NscWthMQt7fpU8lqd7LXMvT9pi+KhhmTHAJWUB/Lj6MWa0MKFv0F2V4C6WKKpjCVZl0VwcDz4nOI3CyaT1DDiA=="],
"libsql": ["libsql@0.5.29", "", { "dependencies": { "@neon-rs/load": "^0.0.4", "detect-libc": "2.0.2" }, "optionalDependencies": { "@libsql/darwin-arm64": "0.5.29", "@libsql/darwin-x64": "0.5.29", "@libsql/linux-arm-gnueabihf": "0.5.29", "@libsql/linux-arm-musleabihf": "0.5.29", "@libsql/linux-arm64-gnu": "0.5.29", "@libsql/linux-arm64-musl": "0.5.29", "@libsql/linux-x64-gnu": "0.5.29", "@libsql/linux-x64-musl": "0.5.29", "@libsql/win32-x64-msvc": "0.5.29" }, "os": [ "linux", "win32", "darwin", ], "cpu": [ "arm", "x64", "arm64", ] }, "sha512-8lMP8iMgiBzzoNbAPQ59qdVcj6UaE/Vnm+fiwX4doX4Narook0a4GPKWBEv+CR8a1OwbfkgL18uBfBjWdF0Fzg=="],
"lines-and-columns": ["lines-and-columns@1.2.4", "", {}, "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg=="],
"locate-path": ["locate-path@6.0.0", "", { "dependencies": { "p-locate": "^5.0.0" } }, "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw=="],
@@ -604,18 +722,26 @@
"long": ["long@5.3.2", "", {}, "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA=="],
"lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="],
"lru-cache": ["lru-cache@7.18.3", "", {}, "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA=="],
"math-intrinsics": ["math-intrinsics@1.1.0", "", {}, "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g=="],
"merge-deep": ["merge-deep@3.0.3", "", { "dependencies": { "arr-union": "^3.1.0", "clone-deep": "^0.2.4", "kind-of": "^3.0.2" } }, "sha512-qtmzAS6t6grwEkNrunqTBdn0qKwFgNWvlxUbAV8es9M7Ot1EbyApytCnvE0jALPa46ZpKDUo527kKiaWplmlFA=="],
"meriyah": ["meriyah@6.1.4", "", {}, "sha512-Sz8FzjzI0kN13GK/6MVEsVzMZEPvOhnmmI1lU5+/1cGOiK3QUahntrNNtdVeihrO7t9JpoH75iMNXg6R6uWflQ=="],
"mime-db": ["mime-db@1.46.0", "", {}, "sha512-svXaP8UQRZ5K7or+ZmfNhg2xX3yKDMUzqadsSqi4NCH/KomcH75MAMYAGVlvXn4+b/xOPhS3I2uHKRUzvjY7BQ=="],
"mime-types": ["mime-types@2.1.29", "", { "dependencies": { "mime-db": "1.46.0" } }, "sha512-Y/jMt/S5sR9OaqteJtslsFZKWOIIqMACsJSiHghlCAyhf7jfVYjKBmLiX8OgpWeW+fjJ2b+Az69aPFPkUOY6xQ=="],
"minimatch": ["minimatch@3.1.2", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw=="],
"minimatch": ["minimatch@3.1.5", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w=="],
"minipass": ["minipass@7.1.2", "", {}, "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw=="],
"mitt": ["mitt@3.0.1", "", {}, "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw=="],
"mixin-object": ["mixin-object@2.0.1", "", { "dependencies": { "for-in": "^0.1.3", "is-extendable": "^0.1.1" } }, "sha512-ALGF1Jt9ouehcaXaHhn6t1yGWRqGaHkPFndtFVHfZXOvkIZ/yoGaSi0AHVTafb3ZBGg4dr/bDwnaEKqCXzchMA=="],
"ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="],
"mssql": ["mssql@11.0.1", "", { "dependencies": { "@tediousjs/connection-string": "^0.5.0", "commander": "^11.0.0", "debug": "^4.3.3", "rfdc": "^1.3.0", "tarn": "^3.0.2", "tedious": "^18.2.1" }, "bin": { "mssql": "bin/mssql" } }, "sha512-KlGNsugoT90enKlR8/G36H0kTxPthDhmtNUCwEHvgRza5Cjpjoj+P2X6eMpFUDN7pFrJZsKadL4x990G8RBE1w=="],
@@ -624,32 +750,52 @@
"natural-compare": ["natural-compare@1.4.0", "", {}, "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw=="],
"netmask": ["netmask@2.0.2", "", {}, "sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg=="],
"node-domexception": ["node-domexception@1.0.0", "", {}, "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ=="],
"node-fetch": ["node-fetch@3.3.2", "", { "dependencies": { "data-uri-to-buffer": "^4.0.0", "fetch-blob": "^3.1.4", "formdata-polyfill": "^4.0.10" } }, "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA=="],
"ollama": ["ollama@0.6.3", "", { "dependencies": { "whatwg-fetch": "^3.6.20" } }, "sha512-KEWEhIqE5wtfzEIZbDCLH51VFZ6Z3ZSa6sIOg/E/tBV8S51flyqBOXi+bRxlOYKDf8i327zG9eSTb8IJxvm3Zg=="],
"once": ["once@1.4.0", "", { "dependencies": { "wrappy": "1" } }, "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w=="],
"open": ["open@10.2.0", "", { "dependencies": { "default-browser": "^5.2.1", "define-lazy-prop": "^3.0.0", "is-inside-container": "^1.0.0", "wsl-utils": "^0.1.0" } }, "sha512-YgBpdJHPyQ2UE5x+hlSXcnejzAvD0b22U2OuAP+8OnlJT+PjWPxtgmGqKKc+RgTM63U9gN0YzrYc71R2WT/hTA=="],
"openai": ["openai@6.35.0", "", { "peerDependencies": { "ws": "^8.18.0", "zod": "^3.25 || ^4.0" }, "optionalPeers": ["ws", "zod"], "bin": { "openai": "bin/cli" } }, "sha512-L/skwIGnt5xQZHb0UfTu9uAUKbis3ehKypOuJKi20QvG7UStV6C8IC3myGYHcdiF4kms/bAvOJ9UqqNWqi8x/Q=="],
"optionator": ["optionator@0.9.4", "", { "dependencies": { "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", "levn": "^0.4.1", "prelude-ls": "^1.2.1", "type-check": "^0.4.0", "word-wrap": "^1.2.5" } }, "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g=="],
"p-limit": ["p-limit@3.1.0", "", { "dependencies": { "yocto-queue": "^0.1.0" } }, "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ=="],
"p-locate": ["p-locate@5.0.0", "", { "dependencies": { "p-limit": "^3.0.2" } }, "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw=="],
"p-retry": ["p-retry@4.6.2", "", { "dependencies": { "@types/retry": "0.12.0", "retry": "^0.13.1" } }, "sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ=="],
"p-try": ["p-try@2.2.0", "", {}, "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ=="],
"pac-proxy-agent": ["pac-proxy-agent@7.2.0", "", { "dependencies": { "@tootallnate/quickjs-emscripten": "^0.23.0", "agent-base": "^7.1.2", "debug": "^4.3.4", "get-uri": "^6.0.1", "http-proxy-agent": "^7.0.0", "https-proxy-agent": "^7.0.6", "pac-resolver": "^7.0.1", "socks-proxy-agent": "^8.0.5" } }, "sha512-TEB8ESquiLMc0lV8vcd5Ql/JAKAoyzHFXaStwjkzpOpC5Yv+pIzLfHvjTSdf3vpa2bMiUQrg9i6276yn8666aA=="],
"pac-resolver": ["pac-resolver@7.0.1", "", { "dependencies": { "degenerator": "^5.0.0", "netmask": "^2.0.2" } }, "sha512-5NPgf87AT2STgwa2ntRMr45jTKrYBGkVU36yT0ig/n/GMAa3oPqhZfIQ2kMEimReg0+t9kZViDVZ83qfVUlckg=="],
"package-json-from-dist": ["package-json-from-dist@1.0.1", "", {}, "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw=="],
"parent-module": ["parent-module@1.0.1", "", { "dependencies": { "callsites": "^3.0.0" } }, "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g=="],
"parse-json": ["parse-json@5.2.0", "", { "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" } }, "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg=="],
"path-exists": ["path-exists@4.0.0", "", {}, "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w=="],
"path-is-absolute": ["path-is-absolute@1.0.1", "", {}, "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg=="],
"path-key": ["path-key@3.1.1", "", {}, "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="],
"path-scurry": ["path-scurry@1.11.1", "", { "dependencies": { "lru-cache": "^10.2.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" } }, "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA=="],
"pend": ["pend@1.2.0", "", {}, "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg=="],
"picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="],
"picomatch": ["picomatch@4.0.3", "", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="],
"pngjs": ["pngjs@5.0.0", "", {}, "sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw=="],
@@ -658,14 +804,34 @@
"process": ["process@0.11.10", "", {}, "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A=="],
"progress": ["progress@2.0.3", "", {}, "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA=="],
"promise-limit": ["promise-limit@2.7.0", "", {}, "sha512-7nJ6v5lnJsXwGprnGXga4wx6d1POjvi5Qmf1ivTRxTjH4Z/9Czja/UCMLVmB9N93GeWOU93XaFaEt6jbuoagNw=="],
"protobufjs": ["protobufjs@7.5.4", "", { "dependencies": { "@protobufjs/aspromise": "^1.1.2", "@protobufjs/base64": "^1.1.2", "@protobufjs/codegen": "^2.0.4", "@protobufjs/eventemitter": "^1.1.0", "@protobufjs/fetch": "^1.1.0", "@protobufjs/float": "^1.0.2", "@protobufjs/inquire": "^1.1.0", "@protobufjs/path": "^1.1.2", "@protobufjs/pool": "^1.1.0", "@protobufjs/utf8": "^1.1.0", "@types/node": ">=13.7.0", "long": "^5.0.0" } }, "sha512-CvexbZtbov6jW2eXAvLukXjXUW1TzFaivC46BpWc/3BpcCysb5Vffu+B3XHMm8lVEuy2Mm4XGex8hBSg1yapPg=="],
"proxy-from-env": ["proxy-from-env@1.1.0", "", {}, "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg=="],
"proxy-agent": ["proxy-agent@6.5.0", "", { "dependencies": { "agent-base": "^7.1.2", "debug": "^4.3.4", "http-proxy-agent": "^7.0.1", "https-proxy-agent": "^7.0.6", "lru-cache": "^7.14.1", "pac-proxy-agent": "^7.1.0", "proxy-from-env": "^1.1.0", "socks-proxy-agent": "^8.0.5" } }, "sha512-TmatMXdr2KlRiA2CyDu8GqR8EjahTG3aY3nXjdzFyoZbmB8hrBsTyMezhULIXKnC0jpfjlmiZ3+EaCzoInSu/A=="],
"proxy-from-env": ["proxy-from-env@2.1.0", "", {}, "sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA=="],
"pump": ["pump@3.0.3", "", { "dependencies": { "end-of-stream": "^1.1.0", "once": "^1.3.1" } }, "sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA=="],
"punycode": ["punycode@2.3.1", "", {}, "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg=="],
"puppeteer": ["puppeteer@24.42.0", "", { "dependencies": { "@puppeteer/browsers": "2.13.0", "chromium-bidi": "14.0.0", "cosmiconfig": "^9.0.0", "devtools-protocol": "0.0.1595872", "puppeteer-core": "24.42.0", "typed-query-selector": "^2.12.1" }, "bin": { "puppeteer": "lib/cjs/puppeteer/node/cli.js" } }, "sha512-94MoPfFp2eY3eYIMdINkez4IOP5TMHntlZbVx06fHlQTtiQiYgaY0L2Zzfod8PVUkPqP7m3Qlre2v8YS8cudPA=="],
"puppeteer-core": ["puppeteer-core@24.42.0", "", { "dependencies": { "@puppeteer/browsers": "2.13.0", "chromium-bidi": "14.0.0", "debug": "^4.4.3", "devtools-protocol": "0.0.1595872", "typed-query-selector": "^2.12.1", "webdriver-bidi-protocol": "0.4.1", "ws": "^8.19.0" } }, "sha512-T4zXokk/izH01fYPhyyev1A4piWiOKrYq7CUFpdoYQxmOnXoV6YjUabmfIjCYkNspSoAXIxRid3Tw+Vg0fthYg=="],
"puppeteer-extra": ["puppeteer-extra@3.3.6", "", { "dependencies": { "@types/debug": "^4.1.0", "debug": "^4.1.1", "deepmerge": "^4.2.2" }, "peerDependencies": { "@types/puppeteer": "*", "puppeteer": "*", "puppeteer-core": "*" }, "optionalPeers": ["@types/puppeteer", "puppeteer", "puppeteer-core"] }, "sha512-rsLBE/6mMxAjlLd06LuGacrukP2bqbzKCLzV1vrhHFavqQE/taQ2UXv3H5P0Ls7nsrASa+6x3bDbXHpqMwq+7A=="],
"puppeteer-extra-plugin": ["puppeteer-extra-plugin@3.2.3", "", { "dependencies": { "@types/debug": "^4.1.0", "debug": "^4.1.1", "merge-deep": "^3.0.1" }, "peerDependencies": { "playwright-extra": "*", "puppeteer-extra": "*" }, "optionalPeers": ["playwright-extra", "puppeteer-extra"] }, "sha512-6RNy0e6pH8vaS3akPIKGg28xcryKscczt4wIl0ePciZENGE2yoaQJNd17UiEbdmh5/6WW6dPcfRWT9lxBwCi2Q=="],
"puppeteer-extra-plugin-stealth": ["puppeteer-extra-plugin-stealth@2.11.2", "", { "dependencies": { "debug": "^4.1.1", "puppeteer-extra-plugin": "^3.2.3", "puppeteer-extra-plugin-user-preferences": "^2.4.1" }, "peerDependencies": { "playwright-extra": "*", "puppeteer-extra": "*" }, "optionalPeers": ["playwright-extra", "puppeteer-extra"] }, "sha512-bUemM5XmTj9i2ZerBzsk2AN5is0wHMNE6K0hXBzBXOzP5m5G3Wl0RHhiqKeHToe/uIH8AoZiGhc1tCkLZQPKTQ=="],
"puppeteer-extra-plugin-user-data-dir": ["puppeteer-extra-plugin-user-data-dir@2.4.1", "", { "dependencies": { "debug": "^4.1.1", "fs-extra": "^10.0.0", "puppeteer-extra-plugin": "^3.2.3", "rimraf": "^3.0.2" }, "peerDependencies": { "playwright-extra": "*", "puppeteer-extra": "*" }, "optionalPeers": ["playwright-extra", "puppeteer-extra"] }, "sha512-kH1GnCcqEDoBXO7epAse4TBPJh9tEpVEK/vkedKfjOVOhZAvLkHGc9swMs5ChrJbRnf8Hdpug6TJlEuimXNQ+g=="],
"puppeteer-extra-plugin-user-preferences": ["puppeteer-extra-plugin-user-preferences@2.4.1", "", { "dependencies": { "debug": "^4.1.1", "deepmerge": "^4.2.2", "puppeteer-extra-plugin": "^3.2.3", "puppeteer-extra-plugin-user-data-dir": "^2.4.1" }, "peerDependencies": { "playwright-extra": "*", "puppeteer-extra": "*" }, "optionalPeers": ["playwright-extra", "puppeteer-extra"] }, "sha512-i1oAZxRbc1bk8MZufKCruCEC3CCafO9RKMkkodZltI4OqibLFXF3tj6HZ4LZ9C5vCXZjYcDWazgtY69mnmrQ9A=="],
"qrcode": ["qrcode@1.5.4", "", { "dependencies": { "dijkstrajs": "^1.0.1", "pngjs": "^5.0.0", "yargs": "^15.3.1" }, "bin": { "qrcode": "bin/qrcode" } }, "sha512-1ca71Zgiu6ORjHqFBDpnSMTR2ReToX4l1Au1VFLyVeBTFavzQnv5JxMFr3ukHVKpSrSA2MCk0lNJSykjUfz7Zg=="],
"readable-stream": ["readable-stream@4.7.0", "", { "dependencies": { "abort-controller": "^3.0.0", "buffer": "^6.0.3", "events": "^3.3.0", "process": "^0.11.10", "string_decoder": "^1.3.0" } }, "sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg=="],
@@ -678,6 +844,8 @@
"resolve-pkg-maps": ["resolve-pkg-maps@1.0.0", "", {}, "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw=="],
"retry": ["retry@0.13.1", "", {}, "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg=="],
"rfdc": ["rfdc@1.4.1", "", {}, "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA=="],
"rimraf": ["rimraf@5.0.10", "", { "dependencies": { "glob": "^10.3.7" }, "bin": { "rimraf": "dist/esm/bin.mjs" } }, "sha512-l0OE8wL34P4nJH/H2ffoaniAokM2qSmrtXHmlpvYr5AVVX8msAyW0l8NVJFDxlSK4u3Uh/f41cQheDVdnYijwQ=="],
@@ -692,6 +860,8 @@
"set-blocking": ["set-blocking@2.0.0", "", {}, "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw=="],
"shallow-clone": ["shallow-clone@0.1.2", "", { "dependencies": { "is-extendable": "^0.1.1", "kind-of": "^2.0.1", "lazy-cache": "^0.2.3", "mixin-object": "^2.0.1" } }, "sha512-J1zdXCky5GmNnuauESROVu31MQSnLoYvlyEn6j2Ztk6Q5EHFIhxkMhYcv6vuDzl2XEzoRr856QwzMgWM/TmZgw=="],
"sharp": ["sharp@0.34.5", "", { "dependencies": { "@img/colour": "^1.0.0", "detect-libc": "^2.1.2", "semver": "^7.7.3" }, "optionalDependencies": { "@img/sharp-darwin-arm64": "0.34.5", "@img/sharp-darwin-x64": "0.34.5", "@img/sharp-libvips-darwin-arm64": "1.2.4", "@img/sharp-libvips-darwin-x64": "1.2.4", "@img/sharp-libvips-linux-arm": "1.2.4", "@img/sharp-libvips-linux-arm64": "1.2.4", "@img/sharp-libvips-linux-ppc64": "1.2.4", "@img/sharp-libvips-linux-riscv64": "1.2.4", "@img/sharp-libvips-linux-s390x": "1.2.4", "@img/sharp-libvips-linux-x64": "1.2.4", "@img/sharp-libvips-linuxmusl-arm64": "1.2.4", "@img/sharp-libvips-linuxmusl-x64": "1.2.4", "@img/sharp-linux-arm": "0.34.5", "@img/sharp-linux-arm64": "0.34.5", "@img/sharp-linux-ppc64": "0.34.5", "@img/sharp-linux-riscv64": "0.34.5", "@img/sharp-linux-s390x": "0.34.5", "@img/sharp-linux-x64": "0.34.5", "@img/sharp-linuxmusl-arm64": "0.34.5", "@img/sharp-linuxmusl-x64": "0.34.5", "@img/sharp-wasm32": "0.34.5", "@img/sharp-win32-arm64": "0.34.5", "@img/sharp-win32-ia32": "0.34.5", "@img/sharp-win32-x64": "0.34.5" } }, "sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg=="],
"shebang-command": ["shebang-command@2.0.0", "", { "dependencies": { "shebang-regex": "^3.0.0" } }, "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA=="],
@@ -700,8 +870,18 @@
"signal-exit": ["signal-exit@4.1.0", "", {}, "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw=="],
"smart-buffer": ["smart-buffer@4.2.0", "", {}, "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg=="],
"socks": ["socks@2.8.7", "", { "dependencies": { "ip-address": "^10.0.1", "smart-buffer": "^4.2.0" } }, "sha512-HLpt+uLy/pxB+bum/9DzAgiKS8CX1EvbWxI4zlmgGCExImLdiad2iCwXT5Z4c9c3Eq8rP2318mPW2c+QbtjK8A=="],
"socks-proxy-agent": ["socks-proxy-agent@8.0.5", "", { "dependencies": { "agent-base": "^7.1.2", "debug": "^4.3.4", "socks": "^2.8.3" } }, "sha512-HehCEsotFqbPW9sJ8WVYB6UbmIMv7kUUORIF2Nncq4VQvBfNBLibW9YZR5dlYCSUhwcD628pRllm7n+E+YTzJw=="],
"source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="],
"sprintf-js": ["sprintf-js@1.1.3", "", {}, "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA=="],
"streamx": ["streamx@2.23.0", "", { "dependencies": { "events-universal": "^1.0.0", "fast-fifo": "^1.3.2", "text-decoder": "^1.1.0" } }, "sha512-kn+e44esVfn2Fa/O0CPFcex27fjIL6MkVae0Mm6q+E6f0hWv578YCERbv+4m02cjxvDsPKLnmxral/rR6lBMAg=="],
"string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="],
"string-width-cjs": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="],
@@ -716,17 +896,21 @@
"supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="],
"systeminformation": ["systeminformation@5.30.6", "", { "os": "!aix", "bin": { "systeminformation": "lib/cli.js" } }, "sha512-LEIyK1aEv5P3BhAPW3swdlIyCihxwEq/Gki+kcONieU4PIeRCSLDuGkk0Va/56PSBgjVgEksOM88dmY6YqOyfQ=="],
"systeminformation": ["systeminformation@5.31.5", "", { "os": "!aix", "bin": { "systeminformation": "lib/cli.js" } }, "sha512-5SyLdip4/3alxD4Kh+63bUQTJmu7YMfYQTC+koZy7X73HgNqZSD2P4wOZQWtUncvPvcEmnfIjCoygN4MRoEejQ=="],
"tar-fs": ["tar-fs@3.1.1", "", { "dependencies": { "pump": "^3.0.0", "tar-stream": "^3.1.5" }, "optionalDependencies": { "bare-fs": "^4.0.1", "bare-path": "^3.0.0" } }, "sha512-LZA0oaPOc2fVo82Txf3gw+AkEd38szODlptMYejQUhndHMLQ9M059uXR+AfS7DNo0NpINvSqDsvyaCrBVkptWg=="],
"tar-stream": ["tar-stream@3.1.7", "", { "dependencies": { "b4a": "^1.6.4", "fast-fifo": "^1.2.0", "streamx": "^2.15.0" } }, "sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ=="],
"tarn": ["tarn@3.0.2", "", {}, "sha512-51LAVKUSZSVfI05vjPESNc5vwqqZpbXCsU+/+wxlOrUjk2SnFTt97v9ZgQrD4YmxYW1Px6w2KjaDitCfkvgxMQ=="],
"tedious": ["tedious@18.6.2", "", { "dependencies": { "@azure/core-auth": "^1.7.2", "@azure/identity": "^4.2.1", "@azure/keyvault-keys": "^4.4.0", "@js-joda/core": "^5.6.1", "@types/node": ">=18", "bl": "^6.0.11", "iconv-lite": "^0.6.3", "js-md4": "^0.3.2", "native-duplexpair": "^1.0.0", "sprintf-js": "^1.1.3" } }, "sha512-g7jC56o3MzLkE3lHkaFe2ZdOVFBahq5bsB60/M4NYUbocw/MCrS89IOEQUFr+ba6pb8ZHczZ/VqCyYeYq0xBAg=="],
"text-decoder": ["text-decoder@1.2.3", "", { "dependencies": { "b4a": "^1.6.4" } }, "sha512-3/o9z3X0X0fTupwsYvR03pJ/DjWuqqrfwBgTQzdWDiQSm9KitAyz/9WqsT2JQW7KV2m+bC2ol/zqpW37NHxLaA=="],
"tinyglobby": ["tinyglobby@0.2.15", "", { "dependencies": { "fdir": "^6.5.0", "picomatch": "^4.0.3" } }, "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ=="],
"tr46": ["tr46@0.0.3", "", {}, "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="],
"ts-api-utils": ["ts-api-utils@2.4.0", "", { "peerDependencies": { "typescript": ">=4.8.4" } }, "sha512-3TaVTaAv2gTiMB35i3FiGJaRfwb3Pyn/j3m/bfAvGe8FB7CF6u+LMYqYlDh7reQf7UNvoTvdfAqHGmPGOSsPmA=="],
"ts-api-utils": ["ts-api-utils@2.5.0", "", { "peerDependencies": { "typescript": ">=4.8.4" } }, "sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA=="],
"tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],
@@ -738,11 +922,13 @@
"type-check": ["type-check@0.4.0", "", { "dependencies": { "prelude-ls": "^1.2.1" } }, "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew=="],
"typed-query-selector": ["typed-query-selector@2.12.1", "", {}, "sha512-uzR+FzI8qrUEIu96oaeBJmd9E7CFEiQ3goA5qCVgc4s5llSubcfGHq9yUstZx/k4s9dXHVKsE35YWoFyvEqEHA=="],
"typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="],
"typescript-telegram-bot-api": ["typescript-telegram-bot-api@0.11.0", "", { "dependencies": { "axios": "^1.7.7", "form-data": "^4.0.1" } }, "sha512-pWSv0fglpnETAGtptNaqHjqreUTunRstfxeI9opdhq7P8T8T/tbBH8nLzP7WVAoFW55F4I6biKa9NOx1bs5O3Q=="],
"undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="],
"undici-types": ["undici-types@7.19.2", "", {}, "sha512-qYVnV5OEm2AW8cJMCpdV20CDyaN3g0AjDlOGf1OW4iaDEx8MwdtChUp4zu4H0VP3nDRF/8RKWH+IPp9uW0YGZg=="],
"universalify": ["universalify@0.1.2", "", {}, "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg=="],
@@ -752,13 +938,11 @@
"web-streams-polyfill": ["web-streams-polyfill@3.3.3", "", {}, "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw=="],
"webidl-conversions": ["webidl-conversions@3.0.1", "", {}, "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="],
"webdriver-bidi-protocol": ["webdriver-bidi-protocol@0.4.1", "", {}, "sha512-ARrjNjtWRRs2w4Tk7nqrf2gBI0QXWuOmMCx2hU+1jUt6d00MjMxURrhxhGbrsoiZKJrhTSTzbIrc554iKI10qw=="],
"whatwg-fetch": ["whatwg-fetch@3.6.20", "", {}, "sha512-EqhiFU6daOA8kpjOWTL0olhVOF3i7OrFzSYiGsEMB8GcXS+RrzauAERX65xMeNWVqxA6HXH2m69Z9LaKKdisfg=="],
"whatwg-url": ["whatwg-url@5.0.0", "", { "dependencies": { "tr46": "~0.0.3", "webidl-conversions": "^3.0.0" } }, "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw=="],
"which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="],
"which": ["which@1.3.1", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "which": "./bin/which" } }, "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ=="],
"which-module": ["which-module@2.0.1", "", {}, "sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ=="],
@@ -768,7 +952,9 @@
"wrap-ansi-cjs": ["wrap-ansi@7.0.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q=="],
"ws": ["ws@8.18.3", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg=="],
"wrappy": ["wrappy@1.0.2", "", {}, "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="],
"ws": ["ws@8.19.0", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg=="],
"wsl-utils": ["wsl-utils@0.1.0", "", { "dependencies": { "is-wsl": "^3.1.0" } }, "sha512-h3Fbisa2nKGPxCpm89Hk33lBLsnaGBvctQopaBSOW/uIs6FTe1ATyAnKFJrzVs9vpGdsTe73WF3V4lIsk4Gacw=="],
@@ -778,9 +964,13 @@
"yargs-parser": ["yargs-parser@18.1.3", "", { "dependencies": { "camelcase": "^5.0.0", "decamelize": "^1.2.0" } }, "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ=="],
"yauzl": ["yauzl@2.10.0", "", { "dependencies": { "buffer-crc32": "~0.2.3", "fd-slicer": "~1.1.0" } }, "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g=="],
"yocto-queue": ["yocto-queue@0.1.0", "", {}, "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q=="],
"zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="],
"youtubei.js": ["youtubei.js@16.0.1", "", { "dependencies": { "@bufbuild/protobuf": "^2.0.0", "meriyah": "^6.1.4" } }, "sha512-3802bCAGkBc2/G5WUTc0l/bO5mPYJbQAHL04d9hE9PnrDHoBUT8MN721Yqt4RCNncAXdHcfee9VdJy3Fhq1r5g=="],
"zod": ["zod@4.3.6", "", {}, "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg=="],
"zod-to-json-schema": ["zod-to-json-schema@3.25.1", "", { "peerDependencies": { "zod": "^3.25 || ^4" } }, "sha512-pM/SU9d3YAggzi6MtR4h7ruuQlqKtad8e9S0fmxcMi+ueAK5Korys/aWcV9LIIHTVbj01NdzxcnXSN+O74ZIVA=="],
@@ -794,6 +984,14 @@
"@isaacs/cliui/wrap-ansi": ["wrap-ansi@8.1.0", "", { "dependencies": { "ansi-styles": "^6.1.0", "string-width": "^5.0.1", "strip-ansi": "^7.0.1" } }, "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ=="],
"@libsql/isomorphic-ws/ws": ["ws@8.18.3", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg=="],
"@puppeteer/browsers/semver": ["semver@7.7.4", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA=="],
"@puppeteer/browsers/yargs": ["yargs@17.7.2", "", { "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" } }, "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w=="],
"@types/fluent-ffmpeg/@types/node": ["@types/node@25.2.3", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-m0jEgYlYz+mDJZ2+F4v8D1AyQb+QzsNqRuI7xg1VQX/KlKS0qT9r1Mo16yo5F/MtifXFgaofIFsdFMox2SxIbQ=="],
"@types/mssql/@types/node": ["@types/node@25.0.3", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-W609buLVRVmeW693xKfzHeIV6nJGGz98uCPfeXI1ELMLXVeKYZ9m15fAMSaUPBHYLGFsVRcMmSCksQOrZV9BYA=="],
"@types/qrcode/@types/node": ["@types/node@25.0.3", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-W609buLVRVmeW693xKfzHeIV6nJGGz98uCPfeXI1ELMLXVeKYZ9m15fAMSaUPBHYLGFsVRcMmSCksQOrZV9BYA=="],
@@ -802,24 +1000,44 @@
"@types/ws/@types/node": ["@types/node@25.0.3", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-W609buLVRVmeW693xKfzHeIV6nJGGz98uCPfeXI1ELMLXVeKYZ9m15fAMSaUPBHYLGFsVRcMmSCksQOrZV9BYA=="],
"@typescript-eslint/typescript-estree/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="],
"@types/yauzl/@types/node": ["@types/node@25.1.0", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-t7frlewr6+cbx+9Ohpl0NOTKXZNV9xHRmNOvql47BFJKcEG1CxtxlPEEe+gR9uhVWM4DwhnvTF110mIL4yP9RA=="],
"@typescript-eslint/utils/@eslint-community/eslint-utils": ["@eslint-community/eslint-utils@4.9.1", "", { "dependencies": { "eslint-visitor-keys": "^3.4.3" }, "peerDependencies": { "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } }, "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ=="],
"@typescript-eslint/typescript-estree/minimatch": ["minimatch@10.2.3", "", { "dependencies": { "brace-expansion": "^5.0.2" } }, "sha512-Rwi3pnapEqirPSbWbrZaa6N3nmqq4Xer/2XooiOKyV3q12ML06f7MOuc5DVH8ONZIFhwIYQ3yzPH4nt7iWHaTg=="],
"bun-types/@types/node": ["@types/node@25.0.10", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-zWW5KPngR/yvakJgGOmZ5vTBemDoSqF3AcV/LrO5u5wTWyEAVVh+IT39G4gtyAkh3CtTZs8aX/yRM82OfzHJRg=="],
"@typescript-eslint/typescript-estree/semver": ["semver@7.7.4", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA=="],
"cross-fetch/node-fetch": ["node-fetch@2.7.0", "", { "dependencies": { "whatwg-url": "^5.0.0" }, "peerDependencies": { "encoding": "^0.1.0" }, "optionalPeers": ["encoding"] }, "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A=="],
"@typescript-eslint/visitor-keys/eslint-visitor-keys": ["eslint-visitor-keys@5.0.1", "", {}, "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA=="],
"chromium-bidi/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="],
"cross-spawn/which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="],
"eslint/ignore": ["ignore@5.3.2", "", {}, "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g=="],
"fs-extra/jsonfile": ["jsonfile@4.0.0", "", { "optionalDependencies": { "graceful-fs": "^4.1.6" } }, "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg=="],
"get-uri/data-uri-to-buffer": ["data-uri-to-buffer@6.0.2", "", {}, "sha512-7hvf7/GW8e86rW0ptuwS3OcBGDjIi6SZva7hCyWC0yYry2cOPmLIjXAUHI6DK2HsnwJd9ifmt57i8eV2n4YNpw=="],
"glob/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="],
"libsql/detect-libc": ["detect-libc@2.0.2", "", {}, "sha512-UX6sGumvvqSaXgdKGUsgZWqcUyIXZ/vZTrlRT/iobiKhGL0zL4d3osHj3uqllWJK+i+sixDS/3COVEOFbupFyw=="],
"mixin-object/for-in": ["for-in@0.1.8", "", {}, "sha512-F0to7vbBSHP8E3l6dCjxNOLuSFAACIxFy3UehTUlG7svlXi37HHsDkyVcHo0Pq8QwrE+pXvWSVX3ZT1T9wAZ9g=="],
"path-scurry/lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="],
"protobufjs/@types/node": ["@types/node@25.0.10", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-zWW5KPngR/yvakJgGOmZ5vTBemDoSqF3AcV/LrO5u5wTWyEAVVh+IT39G4gtyAkh3CtTZs8aX/yRM82OfzHJRg=="],
"proxy-agent/proxy-from-env": ["proxy-from-env@1.1.0", "", {}, "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg=="],
"puppeteer-extra-plugin-user-data-dir/fs-extra": ["fs-extra@10.1.0", "", { "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" } }, "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ=="],
"puppeteer-extra-plugin-user-data-dir/rimraf": ["rimraf@3.0.2", "", { "dependencies": { "glob": "^7.1.3" }, "bin": { "rimraf": "bin.js" } }, "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA=="],
"shallow-clone/kind-of": ["kind-of@2.0.1", "", { "dependencies": { "is-buffer": "^1.0.2" } }, "sha512-0u8i1NZ/mg0b+W3MGGw5I7+6Eib2nx72S/QvXa0hYjEkjTknYmEYQJwGu3mLC0BrhtJjtQafTkyRUQ75Kx0LVg=="],
"shallow-clone/lazy-cache": ["lazy-cache@0.2.7", "", {}, "sha512-gkX52wvU/R8DVMMt78ATVPFMJqfW8FPz1GZ1sVHBVQHmu/WvhIWE4cE1GBzhJNFicDeYhnwp6Rl35BcAIM3YOQ=="],
"string-width/emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="],
"string-width-cjs/emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="],
@@ -838,12 +1056,38 @@
"@isaacs/cliui/wrap-ansi/ansi-styles": ["ansi-styles@6.2.3", "", {}, "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg=="],
"@typescript-eslint/typescript-estree/minimatch/brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="],
"@puppeteer/browsers/yargs/cliui": ["cliui@8.0.1", "", { "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.1", "wrap-ansi": "^7.0.0" } }, "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ=="],
"@typescript-eslint/utils/@eslint-community/eslint-utils/eslint-visitor-keys": ["eslint-visitor-keys@3.4.3", "", {}, "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag=="],
"@puppeteer/browsers/yargs/y18n": ["y18n@5.0.8", "", {}, "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA=="],
"@puppeteer/browsers/yargs/yargs-parser": ["yargs-parser@21.1.1", "", {}, "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw=="],
"@types/fluent-ffmpeg/@types/node/undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="],
"@types/mssql/@types/node/undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="],
"@types/qrcode/@types/node/undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="],
"@types/readable-stream/@types/node/undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="],
"@types/ws/@types/node/undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="],
"@types/yauzl/@types/node/undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="],
"@typescript-eslint/typescript-estree/minimatch/brace-expansion": ["brace-expansion@5.0.3", "", { "dependencies": { "balanced-match": "^4.0.2" } }, "sha512-fy6KJm2RawA5RcHkLa1z/ScpBeA762UF9KmZQxwIbDtRJrgLzM10depAiEQ+CXYcoiqW1/m96OAAoke2nE9EeA=="],
"glob/minimatch/brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="],
"protobufjs/@types/node/undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="],
"puppeteer-extra-plugin-user-data-dir/fs-extra/jsonfile": ["jsonfile@6.2.0", "", { "dependencies": { "universalify": "^2.0.0" }, "optionalDependencies": { "graceful-fs": "^4.1.6" } }, "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg=="],
"puppeteer-extra-plugin-user-data-dir/fs-extra/universalify": ["universalify@2.0.1", "", {}, "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw=="],
"puppeteer-extra-plugin-user-data-dir/rimraf/glob": ["glob@7.2.3", "", { "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", "minimatch": "^3.1.1", "once": "^1.3.0", "path-is-absolute": "^1.0.0" } }, "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q=="],
"tedious/@types/node/undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="],
"tsx/esbuild/@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.27.2", "", { "os": "aix", "cpu": "ppc64" }, "sha512-GZMB+a0mOMZs4MpDbj8RJp4cw+w1WV5NYD6xzgvzUJ5Ek2jerwfO2eADyI6ExDSUED+1X8aMbegahsJi+8mgpw=="],
"tsx/esbuild/@esbuild/android-arm": ["@esbuild/android-arm@0.27.2", "", { "os": "android", "cpu": "arm" }, "sha512-DVNI8jlPa7Ujbr1yjU2PfUSRtAUZPG9I1RwW4F4xFB1Imiu2on0ADiI/c3td+KmDtVKNbi+nffGDQMfcIMkwIA=="],
@@ -896,8 +1140,16 @@
"tsx/esbuild/@esbuild/win32-x64": ["@esbuild/win32-x64@0.27.2", "", { "os": "win32", "cpu": "x64" }, "sha512-sRdU18mcKf7F+YgheI/zGf5alZatMUTKj/jNS6l744f9u3WFu4v7twcUI9vu4mknF4Y9aDlblIie0IM+5xxaqQ=="],
"typescript-telegram-bot-api/axios/proxy-from-env": ["proxy-from-env@1.1.0", "", {}, "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg=="],
"yargs/find-up/locate-path": ["locate-path@5.0.0", "", { "dependencies": { "p-locate": "^4.1.0" } }, "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g=="],
"@puppeteer/browsers/yargs/cliui/wrap-ansi": ["wrap-ansi@7.0.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q=="],
"@typescript-eslint/typescript-estree/minimatch/brace-expansion/balanced-match": ["balanced-match@4.0.4", "", {}, "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA=="],
"puppeteer-extra-plugin-user-data-dir/rimraf/glob/minimatch": ["minimatch@3.1.2", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw=="],
"yargs/find-up/locate-path/p-locate": ["p-locate@4.1.0", "", { "dependencies": { "p-limit": "^2.2.0" } }, "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A=="],
"yargs/find-up/locate-path/p-locate/p-limit": ["p-limit@2.3.0", "", { "dependencies": { "p-try": "^2.0.0" } }, "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w=="],
+484 -370
View File
File diff suppressed because it is too large Load Diff
+20 -16
View File
@@ -8,33 +8,37 @@
"bun:start": "bun run dist/index.js"
},
"dependencies": {
"@google/genai": "^1.38.0",
"@libsql/client": "^0.17.0",
"@mistralai/mistralai": "^1.13.0",
"@napi-rs/canvas": "^0.1.89",
"axios": "^1.13.4",
"dotenv": "^17.2.3",
"drizzle-orm": "^1.0.0-beta.12-5845444",
"@google/genai": "^1.50.1",
"@libsql/client": "^0.17.3",
"@mistralai/mistralai": "^2.2.1",
"@napi-rs/canvas": "^0.1.100",
"axios": "^1.15.2",
"dotenv": "^17.4.2",
"drizzle-orm": "1.0.0-beta.21",
"emoji-regex": "^10.6.0",
"fluent-ffmpeg": "^2.1.3",
"ollama": "^0.6.3",
"puppeteer": "^24.36.1",
"openai": "^6.35.0",
"puppeteer": "^24.42.0",
"puppeteer-extra": "^3.3.6",
"puppeteer-extra-plugin-stealth": "^2.11.2",
"qrcode": "^1.5.4",
"sharp": "^0.34.5",
"systeminformation": "^5.30.6",
"systeminformation": "^5.31.5",
"twemoji": "^14.0.2",
"typescript-telegram-bot-api": "^0.11.0",
"youtubei.js": "^16.0.1"
"youtubei.js": "^16.0.1",
"zod": "^4.3.6"
},
"devDependencies": {
"@types/bun": "^1.3.8",
"@types/node": "^25.1.0",
"@types/bun": "^1.3.13",
"@types/node": "^25.6.0",
"@types/qrcode": "^1.5.6",
"@typescript-eslint/eslint-plugin": "^8.54.0",
"@typescript-eslint/parser": "^8.54.0",
"drizzle-kit": "^1.0.0-beta.12-5845444",
"eslint": "^9.39.2",
"@types/fluent-ffmpeg": "^2.1.28",
"@typescript-eslint/eslint-plugin": "^8.59.1",
"@typescript-eslint/parser": "^8.59.1",
"drizzle-kit": "^1.0.0-beta.9-e89174b",
"eslint": "^9.39.4",
"tsx": "^4.21.0",
"typescript": "^5.9.3"
}
+2 -56
View File
@@ -1,58 +1,4 @@
import {Message} from "typescript-telegram-bot-api";
import {Requirements} from "./requirements";
import {Command} from "./command";
export type ArgsMode = "none" | "optional" | "required";
export abstract class ChatCommand {
regexp?: RegExp | null;
command?: string | string[];
argsMode: ArgsMode = "none";
requirements?: Requirements = null;
title?: string;
description?: string;
get finalRegexp(): RegExp {
if (!this.regexp) {
const inferred = name(this.constructor.name);
const names = this.command ?? inferred;
this.regexp = createCommandRegExp(names, this.argsMode);
}
return this.regexp;
}
abstract execute(
msg: Message,
match?: RegExpExecArray
): Promise<void>;
}
export function name(s: string) {
return s
.replace(/Command$/, "")
.replace(/([a-z0-9])([A-Z])/g, "$1$2")
.toLowerCase();
}
function escapeRe(s: string) {
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
}
export function createCommandRegExp(
names: string | string[],
argsMode: ArgsMode = "optional",
) {
const list = Array.isArray(names) ? names : [names];
const group = list.map(escapeRe).join("|");
const base = `^\\/(${group})(?:@([\\w_]+))?`; // (1)=cmd, (2)=bot
const tail =
argsMode === "none"
? "\\s*$"
: argsMode === "required"
? "\\s+([\\s\\S]+)\\s*$" // (3)=args обязателен
: "(?:\\s+([\\s\\S]+))?\\s*$"; // (3)=args опционален
return new RegExp(base + tail, "i");
export abstract class ChatCommand extends Command {
}
+58
View File
@@ -0,0 +1,58 @@
import {Message} from "typescript-telegram-bot-api";
import {Requirements} from "./requirements";
export type ArgsMode = "none" | "optional" | "required";
export abstract class Command {
regexp?: RegExp | null;
command?: string | string[];
argsMode: ArgsMode = "none";
requirements?: Requirements = null;
title?: string;
description?: string;
get finalRegexp(): RegExp {
if (!this.regexp) {
const inferred = name(this.constructor.name);
const names = this.command ?? inferred;
this.regexp = createCommandRegExp(names, this.argsMode);
}
return this.regexp;
}
abstract execute(
msg: Message,
match?: RegExpExecArray
): Promise<void>;
}
export function name(s: string) {
return s
.replace(/Command$/, "")
.replace(/([a-z0-9])([A-Z])/g, "$1$2")
.toLowerCase();
}
function escapeRe(s: string) {
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
}
export function createCommandRegExp(
names: string | string[],
argsMode: ArgsMode = "optional",
) {
const list = Array.isArray(names) ? names : [names];
const group = list.map(escapeRe).join("|");
const base = `^\\/(${group})(?:@([\\w_]+))?`; // (1)=cmd, (2)=bot
const tail =
argsMode === "none"
? "\\s*$"
: argsMode === "required"
? "\\s+([\\s\\S]+)\\s*$" // (3)=args обязателен
: "(?:\\s+([\\s\\S]+))?\\s*$"; // (3)=args опционален
return new RegExp(base + tail, "i");
}
+4
View File
@@ -38,4 +38,8 @@ export class Requirements {
isRequiresSameUser(): boolean {
return this.requirements.includes(Requirement.SAME_USER);
}
isPublic(): boolean {
return !this.isRequiresBotCreator();
}
}
@@ -0,0 +1,36 @@
import {CallbackCommand} from "../base/callback-command";
import {CallbackQuery} from "typescript-telegram-bot-api";
import {Requirements} from "../base/requirements";
import {Requirement} from "../base/requirement";
import {commands} from "../index";
import {YouTubeDownload} from "../commands/youtube-download";
const downloadText = " 📥 Скачать";
const getFromCacheText = "📥 Загрузить из кэша";
export class DownloadYtVideo extends CallbackCommand {
data = "/ytdl";
text = " 📥 Скачать";
requirements = Requirements.Build(Requirement.SAME_USER);
constructor(text?: string, data?: string) {
super();
this.text = text || this.text;
this.data = data || this.data;
}
static withData(inCache?: boolean, data?: string): DownloadYtVideo {
return new DownloadYtVideo(inCache ? getFromCacheText : downloadText, data);
}
async execute(query: CallbackQuery): Promise<void> {
const videoId = query.data.split(" ")[1];
if (!videoId) return;
const yt = commands.find(c => c instanceof YouTubeDownload);
if (!yt) return;
await yt.downloadYouTubeVideo(query.message, {videoId: videoId});
}
}
+21
View File
@@ -0,0 +1,21 @@
import {CallbackCommand} from "../base/callback-command";
export class TryAgain extends CallbackCommand {
data = "";
text = "🔁 Повторить";
constructor(text?: string, data?: string) {
super();
this.text = text ?? this.text;
this.data = data ?? this.data;
}
static withData(data?: string): TryAgain {
return new TryAgain(null, data);
}
async execute(): Promise<void> {
return Promise.resolve();
}
}
+15
View File
@@ -0,0 +1,15 @@
import {CallbackCommand} from "../base/callback-command";
import {CallbackQuery} from "typescript-telegram-bot-api";
import {processYouTubeLink} from "../util/utils";
export class YtInfo extends CallbackCommand {
data = "/ytinfo";
text: string;
async execute(query: CallbackQuery): Promise<void> {
const videoId = query.data.split(" ")[1];
if (!videoId) return;
await processYouTubeLink(query.message, null, videoId);
}
}
+2 -2
View File
@@ -1,4 +1,4 @@
import {ChatCommand} from "../base/chat-command";
import {Command} from "../base/command";
import {Message} from "typescript-telegram-bot-api";
import {Requirements} from "../base/requirements";
import {Requirement} from "../base/requirement";
@@ -6,7 +6,7 @@ import {fullName, logError, oldSendMessage} from "../util/utils";
import {Environment} from "../common/environment";
import {botUser} from "../index";
export class AdminsAdd extends ChatCommand {
export class AdminsAdd extends Command {
command = "addAdmin";
title = "/addAdmin";
description = "Add user to admins";
+55
View File
@@ -0,0 +1,55 @@
import {Command} from "../base/command";
import {Message} from "typescript-telegram-bot-api";
import {Requirements} from "../base/requirements";
import {Requirement} from "../base/requirement";
import {Environment} from "../common/environment";
import {fullName, logError, replyToMessage, sendErrorPlaceholder} from "../util/utils";
import {StoredUser} from "../model/stored-user";
import {UserStore} from "../common/user-store";
export class AdminsList extends Command {
command = ["adminslist", "admins"];
argsMode = "none" as const;
requirements = Requirements.Build(Requirement.BOT_ADMIN);
async execute(msg: Message): Promise<void> {
try {
const adminIds: number[] = [...Environment.ADMIN_IDS];
const users: (StoredUser | null)[] = [];
for (let i = 0; i < adminIds.length; i++) {
const id = adminIds[i];
const user = await UserStore.get(id);
if (user) {
users.push(user);
} else {
users.push(null);
}
}
let text = "*Администраторы*:\n\n";
users.forEach(user => {
text += "\\* ";
if (user) {
text += `[${fullName(user)}](tg://user?id=${user.id})`;
} else {
text += "Нет информации о пользователе";
}
text += "\n";
});
await replyToMessage({
message: msg,
text: text,
parse_mode: "MarkdownV2"
});
} catch (e) {
logError(e);
await sendErrorPlaceholder(msg).catch(logError);
}
}
}
+2 -2
View File
@@ -1,4 +1,4 @@
import {ChatCommand} from "../base/chat-command";
import {Command} from "../base/command";
import {Message} from "typescript-telegram-bot-api";
import {Requirements} from "../base/requirements";
import {Requirement} from "../base/requirement";
@@ -6,7 +6,7 @@ import {fullName, logError, oldSendMessage} from "../util/utils";
import {Environment} from "../common/environment";
import {botUser} from "../index";
export class AdminsRemove extends ChatCommand {
export class AdminsRemove extends Command {
command = "removeAdmin";
title = "/removeAdmin";
description = "Remove user from admins";
+2 -2
View File
@@ -1,10 +1,10 @@
import {ChatCommand} from "../base/chat-command";
import {Command} from "../base/command";
import {Message} from "typescript-telegram-bot-api";
import {errorPlaceholder, logError, oldSendMessage} from "../util/utils";
import {Requirements} from "../base/requirements";
import {Requirement} from "../base/requirement";
export class Ae extends ChatCommand {
export class Ae extends Command {
argsMode = "required" as const;
title = "/ae";
+2 -2
View File
@@ -1,4 +1,4 @@
import {ChatCommand} from "../base/chat-command";
import {Command} from "../base/command";
import {Requirements} from "../base/requirements";
import {Requirement} from "../base/requirement";
import {Message} from "typescript-telegram-bot-api";
@@ -6,7 +6,7 @@ import {bot, botUser} from "../index";
import {fullName, logError, oldSendMessage, oldReplyToMessage} from "../util/utils";
import {Environment} from "../common/environment";
export class Ban extends ChatCommand {
export class Ban extends Command {
title = "/ban [reply]";
description = "ban user from chat";
+2 -2
View File
@@ -1,8 +1,8 @@
import {ChatCommand} from "../base/chat-command";
import {Command} from "../base/command";
import {Message} from "typescript-telegram-bot-api";
import {logError, oldReplyToMessage, randomValue} from "../util/utils";
export class Choice extends ChatCommand {
export class Choice extends Command {
command = "choice";
argsMode = "required" as const;
+2 -2
View File
@@ -1,8 +1,8 @@
import {ChatCommand} from "../base/chat-command";
import {Command} from "../base/command";
import {Message} from "typescript-telegram-bot-api";
import {getRangedRandomInt, logError, oldReplyToMessage} from "../util/utils";
export class Coin extends ChatCommand {
export class Coin extends Command {
title = "/coin";
description = "Heads or tails";
+2 -2
View File
@@ -1,10 +1,10 @@
import {ChatCommand} from "../base/chat-command";
import {Command} from "../base/command";
import {Message} from "typescript-telegram-bot-api";
import {Requirements} from "../base/requirements";
import {Requirement} from "../base/requirement";
import {logError, replyToMessage} from "../util/utils";
export class Debug extends ChatCommand {
export class Debug extends Command {
title = "/debug";
description = "Returns msg (or reply) as json";
+2 -2
View File
@@ -1,4 +1,4 @@
import {ChatCommand} from "../base/chat-command";
import {Command} from "../base/command";
import {Message} from "typescript-telegram-bot-api";
import {logError, randomValue} from "../util/utils";
import {bot} from "../index";
@@ -6,7 +6,7 @@ import {bot} from "../index";
type DiceEmoji = "🎲" | "🎯" | "🏀" | "⚽" | "🎳" | "🎰";
const emojis = ["🎲", "🎯", "🏀", "⚽", "🎳", "🎰"];
export class Dice extends ChatCommand {
export class Dice extends Command {
title = "/dice";
description = "Sends random or specific dice";
+6 -3
View File
@@ -1,9 +1,9 @@
import {ChatCommand} from "../base/chat-command";
import {Command} from "../base/command";
import {Message} from "typescript-telegram-bot-api";
import {downloadTelegramFile, extractImageFileId, logError, oldReplyToMessage, waveDistortSharp} from "../util/utils";
import {bot} from "../index";
export class Distort extends ChatCommand {
export class Distort extends Command {
command = "distort";
argsMode = "optional" as const;
@@ -40,7 +40,10 @@ export class Distort extends ChatCommand {
await bot.sendChatAction({chat_id: chatId, action: "upload_photo"});
const file = await bot.getFile({file_id: fileId});
if (!file.file_path) throw new Error("No file_path in Telegram getFile response");
if (!file.file_path) {
// noinspection ExceptionCaughtLocallyJS
throw new Error("No file_path in Telegram getFile response");
}
const inputBuf = await downloadTelegramFile(file.file_path);
+42
View File
@@ -0,0 +1,42 @@
import {Command} from "../base/command";
import {FileOptions, Message} from "typescript-telegram-bot-api";
import {Requirements} from "../base/requirements";
import {Requirement} from "../base/requirement";
import {Environment} from "../common/environment";
import fs from "node:fs";
import {logError, replyToMessage, sendErrorPlaceholder} from "../util/utils";
import {bot} from "../index";
export class ExportDb extends Command {
command = ["exportdb"];
argsMode = "none" as const;
requirements = Requirements.Build(Requirement.BOT_CREATOR);
async execute(msg: Message): Promise<void> {
const fullPath = Environment.DB_PATH.substring(5);
if (!fs.existsSync(fullPath)) {
await sendErrorPlaceholder(msg);
return;
}
try {
const buffer = fs.readFileSync(fullPath);
await bot.sendDocument({
chat_id: Environment.CREATOR_ID,
document: new FileOptions(buffer, {filename: "database.db", contentType: "application/sql"}),
caption: "Бэкап базы данных",
});
if (msg.chat.id !== Environment.CREATOR_ID) {
await replyToMessage({message: msg, text: "Успешно отправлено в ЛС создателю!"});
}
} catch (e) {
logError(e);
await sendErrorPlaceholder(msg);
}
}
}
+18 -12
View File
@@ -1,4 +1,3 @@
import {ChatCommand} from "../base/chat-command";
import {Message} from "typescript-telegram-bot-api";
import {Environment} from "../common/environment";
import {bot, googleAi} from "../index";
@@ -10,19 +9,20 @@ import {
collectReplyChainText,
escapeMarkdownV2Text,
logError,
oldReplyToMessage,
oldReplyToMessage, replyToMessage,
startIntervalEditor
} from "../util/utils";
import {ChatCommand} from "../base/chat-command";
export class GeminiChat extends ChatCommand {
command = "gemini";
argsMode = "required" as const;
requirements = Requirements.Build(Requirement.BOT_CREATOR);
title = "/gemini";
description = "Chat with AI (Gemini)";
requirements = Requirements.Build(Requirement.BOT_CREATOR);
async execute(msg: Message, match?: RegExpExecArray): Promise<void> {
console.log("match", match);
return this.executeGemini(msg, match?.[3]);
@@ -44,7 +44,10 @@ export class GeminiChat extends ChatCommand {
};
});
chatMessages.reverse();
chatMessages.unshift({role: "system", content: Environment.SYSTEM_PROMPT});
if (Environment.SYSTEM_PROMPT) {
chatMessages.unshift({role: "system", content: Environment.SYSTEM_PROMPT});
}
let chatContent = "";
for (const part of chatMessages) {
@@ -61,10 +64,10 @@ export class GeminiChat extends ChatCommand {
}
);
if (messageParts[0].images?.length) {
const images = messageParts[0].images;
images.forEach(image => {
// TODO: 12/02/2026, Danil Nikolaev: support for multiple images
if (messageParts.some(p => p.images?.length)) {
const firstImages = messageParts.find(p => p.images?.length)?.images ?? [];
firstImages.forEach(image => {
input.push({
type: "image",
data: image,
@@ -80,7 +83,7 @@ export class GeminiChat extends ChatCommand {
try {
waitMessage = await bot.sendMessage({
chat_id: chatId,
text: Environment.waitText,
text: Environment.waitThinkText,
reply_parameters: {
chat_id: chatId,
message_id: msg.message_id
@@ -105,7 +108,7 @@ export class GeminiChat extends ChatCommand {
chat_id: chatId,
message_id: waitMessage.message_id,
text: escapeMarkdownV2Text(text),
parse_mode: "Markdown"
parse_mode: "MarkdownV2"
}
).catch(logError);
@@ -164,7 +167,10 @@ export class GeminiChat extends ChatCommand {
waitMessage.reply_to_message = msg;
waitMessage.text = currentText;
await MessageStore.put(waitMessage);
await oldReplyToMessage(waitMessage, `⏱️ ${diff}s`);
if (Environment.SEND_TIME_TOOK) {
await replyToMessage({message: waitMessage, text: `⏱️ ${diff}s`});
}
}
} catch (error) {
logError(error);
+3 -3
View File
@@ -1,4 +1,4 @@
import {ChatCommand} from "../base/chat-command";
import {Command} from "../base/command";
import {Requirements} from "../base/requirements";
import {Requirement} from "../base/requirement";
import {Message} from "typescript-telegram-bot-api";
@@ -6,7 +6,7 @@ import {googleAi} from "../index";
import {logError, replyToMessage} from "../util/utils";
import {Environment} from "../common/environment";
export class GeminiGenerateImage extends ChatCommand {
export class GeminiGenerateImage extends Command {
command = "geminiGenImage";
argsMode = "required" as const;
@@ -53,7 +53,7 @@ export class GeminiGenerateImage extends ChatCommand {
await replyToMessage({
message: waitMessage,
text: `Произошла ошибка!\n${e.toString()}`,
disableLinkPreview: true
link_preview_options: {is_disabled: true}
}).catch(logError);
}
}
+21 -2
View File
@@ -1,13 +1,32 @@
import {ChatCommand} from "../base/chat-command";
import {Command} from "../base/command";
import {Message} from "typescript-telegram-bot-api";
import {logError, replyToMessage} from "../util/utils";
import {Environment} from "../common/environment";
import {googleAi} from "../index";
import {AiModelCapabilities} from "../model/ai-model-capabilities";
export class GeminiGetModel extends ChatCommand {
export class GeminiGetModel extends Command {
title = "/geminiGetModel";
description = "Get current Gemini model";
async execute(msg: Message): Promise<void> {
await replyToMessage({message: msg, text: `Текущая модель: "${Environment.GEMINI_MODEL}"`}).catch(logError);
}
async getModelCapabilities(): Promise<AiModelCapabilities | null> {
try {
const info = await googleAi.models.get({model: Environment.GEMINI_MODEL});
console.log(info);
return {
vision: {supported: true},
ocr: null,
thinking: {supported: info.thinking},
tools: null
};
} catch (e) {
logError(e);
return null;
}
}
}
+2 -2
View File
@@ -1,11 +1,11 @@
import {ChatCommand} from "../base/chat-command";
import {Command} from "../base/command";
import {Requirements} from "../base/requirements";
import {Requirement} from "../base/requirement";
import {Message} from "typescript-telegram-bot-api";
import {googleAi} from "../index";
import {logError, replyToMessage} from "../util/utils";
export class GeminiListModels extends ChatCommand {
export class GeminiListModels extends Command {
title = "/geminiListModels";
description = "List all Gemini models";
+2 -2
View File
@@ -1,11 +1,11 @@
import {ChatCommand} from "../base/chat-command";
import {Command} from "../base/command";
import {Requirements} from "../base/requirements";
import {Requirement} from "../base/requirement";
import {Message} from "typescript-telegram-bot-api";
import {Environment} from "../common/environment";
import {logError, replyToMessage} from "../util/utils";
export class GeminiSetModel extends ChatCommand {
export class GeminiSetModel extends Command {
argsMode = "required" as const;
title = "/geminiSetModel";
+4 -4
View File
@@ -1,10 +1,10 @@
import {Message} from "typescript-telegram-bot-api";
import {chatCommandToString, delay, logError, sendMessage} from "../util/utils";
import {ChatCommand} from "../base/chat-command";
import {chatCommands} from "../index";
import {Command} from "../base/command";
import {commands} from "../index";
import {TelegramError} from "typescript-telegram-bot-api/dist/errors";
export class Help extends ChatCommand {
export class Help extends Command {
command = ["h", "help"];
title = "/help";
@@ -13,7 +13,7 @@ export class Help extends ChatCommand {
async execute(msg: Message) {
let text = "Commands:\n\n";
chatCommands.forEach(c => {
commands.forEach(c => {
text += `${chatCommandToString(c)}\n`;
});
+2 -2
View File
@@ -1,8 +1,8 @@
import {ChatCommand} from "../base/chat-command";
import {Command} from "../base/command";
import {Message} from "typescript-telegram-bot-api";
import {logError, oldReplyToMessage} from "../util/utils";
export class Id extends ChatCommand {
export class Id extends Command {
title = "/id";
description = "ID of chat, user and reply (if replied to any message)";
+2 -2
View File
@@ -1,4 +1,4 @@
import {ChatCommand} from "../base/chat-command";
import {Command} from "../base/command";
import {Requirements} from "../base/requirements";
import {Requirement} from "../base/requirement";
import {Message} from "typescript-telegram-bot-api";
@@ -6,7 +6,7 @@ import {fullName, logError, oldSendMessage} from "../util/utils";
import {botUser} from "../index";
import {Environment} from "../common/environment";
export class Ignore extends ChatCommand {
export class Ignore extends Command {
title = "/ignore";
description = "Bot will ignore user";
+67
View File
@@ -0,0 +1,67 @@
import {ChatCommand} from "../base/chat-command";
import {Message} from "typescript-telegram-bot-api";
import {callbackCommands, commands} from "../index";
import {Environment} from "../common/environment";
import {boolToEmoji, getCurrentModel, getCurrentModelCapabilities, logError, replyToMessage} from "../util/utils";
import {AiModelCapabilities} from "../model/ai-model-capabilities";
import {AiProvider} from "../model/ai-provider";
import {Command} from "../base/command";
export class Info extends Command {
command = ["info", "v"];
title = "/info";
description = "Info about bot";
async execute(msg: Message): Promise<void> {
const aiProvider = Environment.DEFAULT_AI_PROVIDER;
const aiModel = getCurrentModel();
let aiModelCapabilities: AiModelCapabilities = {};
try {
aiModelCapabilities = await getCurrentModelCapabilities();
} catch (e) {
logError(e);
await replyToMessage({message: msg, text: `Произошла ошибка: ${e}`}).catch(logError);
return;
}
const aiInfo = "```" +
"AI\n" +
`supported providers: ${Object.keys(AiProvider).filter(key => isNaN(Number(key))).length}\n\n` +
`provider: ${aiProvider.toLowerCase()}\n` +
`model: ${aiModel}\n\n` +
`vision${aiModelCapabilities.vision?.external ? "(ext)" : ""}: ${boolToEmoji(aiModelCapabilities.vision?.supported)}\n` +
`ocr${aiModelCapabilities.ocr?.external ? "(ext)" : ""}: ${boolToEmoji(aiModelCapabilities.ocr?.supported)}\n` +
`thinking${aiModelCapabilities.thinking?.external ? "(ext)" : ""}: ${boolToEmoji(aiModelCapabilities.thinking?.supported)}\n` +
`tools${aiModelCapabilities.tools?.external ? "(ext)" : ""}: ${boolToEmoji(aiModelCapabilities.tools?.supported)}` +
"```";
const cmds = commands.filter(c => !(c instanceof ChatCommand));
const chatCmds = commands.filter(c => c instanceof ChatCommand);
const callbackCmds = callbackCommands;
const publicCmdsLength = cmds.filter(c => c.requirements?.isPublic()).length;
const privateCmdsLength = cmds.length - publicCmdsLength;
const chatCmdsLength = chatCmds.length;
const callbackCmdsLength = callbackCmds.length;
const text =
aiInfo + "\n\n" +
"```" +
"Commands\n" +
`Public: ${publicCmdsLength}\n` +
`Private: ${privateCmdsLength}\n` +
`Chat: ${chatCmdsLength}\n` +
`Callback: ${callbackCmdsLength}\n` +
"```"
;
await replyToMessage({message: msg, text: text, parse_mode: "Markdown"}).catch(logError);
}
}
+2 -2
View File
@@ -1,10 +1,10 @@
import {ChatCommand} from "../base/chat-command";
import {Command} from "../base/command";
import {Message} from "typescript-telegram-bot-api";
import {Requirements} from "../base/requirements";
import {Requirement} from "../base/requirement";
import {bot} from "../index";
export class Leave extends ChatCommand {
export class Leave extends Command {
title = "/leave";
description = "Bot will leave current chat";
+32 -8
View File
@@ -1,4 +1,3 @@
import {ChatCommand} from "../base/chat-command";
import {Requirements} from "../base/requirements";
import {Requirement} from "../base/requirement";
import {Message} from "typescript-telegram-bot-api";
@@ -7,21 +6,24 @@ import {
escapeMarkdownV2Text,
logError,
oldReplyToMessage,
replyToMessage,
startIntervalEditor
} from "../util/utils";
import {Environment} from "../common/environment";
import {bot, mistralAi} from "../index";
import {bot, commands, mistralAi} from "../index";
import {MessageStore} from "../common/message-store";
import {ChatCommand} from "../base/chat-command";
import {MistralGetModel} from "./mistral-get-model";
export class MistralChat extends ChatCommand {
command = "mistral";
argsMode = "required" as const;
requirements = Requirements.Build(Requirement.BOT_CREATOR);
title = "/mistral";
description = "Chat with AI (Mistral)";
requirements = Requirements.Build(Requirement.BOT_CREATOR);
async execute(msg: Message, match?: RegExpExecArray): Promise<void> {
console.log("match", match);
return this.executeMistral(msg, match?.[3]);
@@ -56,7 +58,10 @@ export class MistralChat extends ChatCommand {
};
});
chatMessages.reverse();
chatMessages.unshift({role: "system", content: [{type: "text", text: Environment.SYSTEM_PROMPT}]});
if (Environment.SYSTEM_PROMPT) {
chatMessages.unshift({role: "system", content: [{type: "text", text: Environment.SYSTEM_PROMPT}]});
}
let waitMessage: Message;
@@ -67,11 +72,28 @@ export class MistralChat extends ChatCommand {
return total + (curr.content.filter(c => c.type === "image_url")?.length ?? 0);
}, 0);
if (imagesCount) {
try {
const modelInfo = await commands.find(c => c instanceof MistralGetModel).getModelCapabilities();
if (modelInfo) {
if (!modelInfo.vision?.supported) {
await replyToMessage({
message: msg,
text: "Моя текущая модель не умеет анализировать изображения 🥹"
});
return;
}
}
} catch (e) {
logError(e);
}
}
waitMessage = await bot.sendMessage({
chat_id: chatId,
text: imagesCount ?
imagesCount > 1 ? Environment.analyzingPicturesText : Environment.analyzingPictureText
: Environment.waitText,
: Environment.waitThinkText,
reply_parameters: {
chat_id: chatId,
@@ -97,7 +119,7 @@ export class MistralChat extends ChatCommand {
chat_id: chatId,
message_id: waitMessage.message_id,
text: escapeMarkdownV2Text(text),
parse_mode: "Markdown"
parse_mode: "MarkdownV2"
}
).catch(logError);
@@ -146,7 +168,9 @@ export class MistralChat extends ChatCommand {
waitMessage.reply_to_message = msg;
waitMessage.text = currentText;
await MessageStore.put(waitMessage);
await oldReplyToMessage(waitMessage, `⏱️ ${diff}s`);
if (Environment.SEND_TIME_TOOK) {
await replyToMessage({message: waitMessage, text: `⏱️ ${diff}s`});
}
}
} catch (error) {
logError(error);
+21 -2
View File
@@ -1,11 +1,13 @@
import {ChatCommand} from "../base/chat-command";
import {Command} from "../base/command";
import {Message} from "typescript-telegram-bot-api";
import {logError, replyToMessage} from "../util/utils";
import {Environment} from "../common/environment";
import {Requirements} from "../base/requirements";
import {Requirement} from "../base/requirement";
import {mistralAi} from "../index";
import {AiModelCapabilities} from "../model/ai-model-capabilities";
export class MistralGetModel extends ChatCommand {
export class MistralGetModel extends Command {
title = "/mistralGetModel";
description = "Get current Mistral model";
@@ -14,4 +16,21 @@ export class MistralGetModel extends ChatCommand {
async execute(msg: Message): Promise<void> {
await replyToMessage({message: msg, text: `Текущая модель: "${Environment.MISTRAL_MODEL}"`}).catch(logError);
}
async getModelCapabilities(): Promise<AiModelCapabilities | null> {
try {
const info = await mistralAi.models.retrieve({modelId: Environment.MISTRAL_MODEL});
console.log(info);
return {
vision: {supported: info.capabilities.vision},
ocr: {supported: info.capabilities.ocr},
thinking: null,
tools: {supported: info.capabilities.functionCalling}
};
} catch (e) {
logError(e);
return null;
}
}
}
+2 -2
View File
@@ -1,11 +1,11 @@
import {ChatCommand} from "../base/chat-command";
import {Command} from "../base/command";
import {Requirements} from "../base/requirements";
import {Requirement} from "../base/requirement";
import {Message} from "typescript-telegram-bot-api";
import {mistralAi} from "../index";
import {logError, oldReplyToMessage, replyToMessage} from "../util/utils";
export class MistralListModels extends ChatCommand {
export class MistralListModels extends Command {
title = "/mistralListModels";
description = "List all Mistral models";
+2 -2
View File
@@ -1,11 +1,11 @@
import {ChatCommand} from "../base/chat-command";
import {Command} from "../base/command";
import {Requirements} from "../base/requirements";
import {Requirement} from "../base/requirement";
import {Message} from "typescript-telegram-bot-api";
import {Environment} from "../common/environment";
import {logError, replyToMessage} from "../util/utils";
export class MistralSetModel extends ChatCommand {
export class MistralSetModel extends Command {
argsMode = "required" as const;
title = "/mistralSetModel";
+17 -13
View File
@@ -1,6 +1,5 @@
import {ChatCommand} from "../base/chat-command";
import {Message} from "typescript-telegram-bot-api";
import {abortOllamaRequest, bot, chatCommands, getOllamaRequest, ollama, ollamaRequests} from "../index";
import {abortOllamaRequest, bot, commands, getOllamaRequest, ollama, ollamaRequests} from "../index";
import {
collectReplyChainText,
escapeMarkdownV2Text,
@@ -14,9 +13,10 @@ import {MessageStore} from "../common/message-store";
import {Cancel} from "../callback_commands/cancel";
import {OllamaCancel} from "../callback_commands/ollama-cancel";
import {OllamaGetModel} from "./ollama-get-model";
import {ChatCommand} from "../base/chat-command";
export class OllamaChat extends ChatCommand {
command = ["ollama", "ollamathink"];
command = ["ollamaThink", "ollama"];
argsMode = "required" as const;
title = "/ollama";
@@ -44,7 +44,10 @@ export class OllamaChat extends ChatCommand {
};
});
chatMessages.reverse();
chatMessages.unshift({role: "system", content: Environment.SYSTEM_PROMPT, images: []});
if (Environment.SYSTEM_PROMPT) {
chatMessages.unshift({role: "system", content: Environment.SYSTEM_PROMPT, images: []});
}
let waitMessage: Message;
@@ -57,10 +60,9 @@ export class OllamaChat extends ChatCommand {
if (!think && imagesCount) {
try {
const modelInfo = await chatCommands.find(c => c instanceof OllamaGetModel).loadImageModelInfo();
const modelInfo = await commands.find(c => c instanceof OllamaGetModel).loadImageModelInfo();
if (modelInfo) {
const caps = modelInfo.capabilities || [];
if (!caps.includes("vision")) {
if (!modelInfo.vision?.supported) {
await replyToMessage({
message: msg,
text: "Моя текущая модель не умеет анализировать изображения 🥹"
@@ -75,10 +77,9 @@ export class OllamaChat extends ChatCommand {
if (think) {
try {
const modelInfo = await chatCommands.find(c => c instanceof OllamaGetModel).loadThinkModelInfo();
const modelInfo = await commands.find(c => c instanceof OllamaGetModel).loadThinkModelInfo();
if (modelInfo) {
const caps = modelInfo.capabilities || [];
if (!caps.includes("thinking")) {
if (!modelInfo.thinking?.supported) {
await replyToMessage({
message: msg,
text: "Моя текущая модель не умеет размышлять 🥹"
@@ -98,7 +99,7 @@ export class OllamaChat extends ChatCommand {
message: msg,
text: (!think && imagesCount) ?
imagesCount > 1 ? Environment.analyzingPicturesText : Environment.analyzingPictureText
: Environment.waitText
: Environment.waitThinkText
});
const stream = await ollama.chat({
@@ -142,7 +143,7 @@ export class OllamaChat extends ChatCommand {
chat_id: chatId,
message_id: waitMessage.message_id,
text: escapeMarkdownV2Text(text),
parse_mode: "Markdown",
parse_mode: "MarkdownV2",
reply_markup: cancelMarkup
}).catch(logError);
@@ -219,7 +220,10 @@ export class OllamaChat extends ChatCommand {
waitMessage.reply_to_message = msg;
waitMessage.text = currentText;
await MessageStore.put(waitMessage);
await oldReplyToMessage(waitMessage, `⏱️ ${diff}s`);
if (Environment.SEND_TIME_TOOK) {
await replyToMessage({message: waitMessage, text: `⏱️ ${diff}s`});
}
break;
}
}
+43 -16
View File
@@ -1,11 +1,11 @@
import {ChatCommand} from "../base/chat-command";
import {Command} from "../base/command";
import {Message} from "typescript-telegram-bot-api";
import {boolToEmoji, logError, replyToMessage} from "../util/utils";
import {Environment} from "../common/environment";
import {ollama} from "../index";
import {ShowResponse} from "ollama";
import {AiModelCapabilities} from "../model/ai-model-capabilities";
export class OllamaGetModel extends ChatCommand {
export class OllamaGetModel extends Command {
title = "/ollamaGetModel";
description = "Ollama model info";
@@ -15,7 +15,7 @@ export class OllamaGetModel extends ChatCommand {
const imageModel = Environment.OLLAMA_IMAGE_MODEL;
const thinkModel = Environment.OLLAMA_THINK_MODEL;
const promises: (Promise<ShowResponse | null> | null)[] = [this.loadModelInfo()];
const promises: (Promise<AiModelCapabilities | null> | null)[] = [this.getModelCapabilities()];
if (imageModel && imageModel !== model) {
promises.push(this.loadImageModelInfo());
@@ -62,24 +62,51 @@ export class OllamaGetModel extends ChatCommand {
}
}
private getModelText(model: string, info: ShowResponse): string {
const caps = info.capabilities;
private getModelText(model: string, info: AiModelCapabilities): string {
return `model: ${model}\n\n` +
`vision: ${boolToEmoji(caps.includes("vision"))}\n` +
`thinking: ${boolToEmoji(caps.includes("thinking"))}\n` +
`tools: ${boolToEmoji(caps.includes("tools"))}`;
`vision: ${boolToEmoji(info.vision?.supported)}\n` +
`thinking: ${boolToEmoji(info.thinking?.supported)}\n` +
`tools: ${boolToEmoji(info.tools?.supported)}`;
}
async loadModelInfo(): Promise<ShowResponse | null> {
return ollama.show({model: Environment.OLLAMA_MODEL});
async getModelCapabilities(model: string = Environment.OLLAMA_MODEL): Promise<AiModelCapabilities | null> {
try {
const info = await ollama.show({model: model});
console.log(info);
return {
vision: {
supported: info.capabilities.includes("vision"),
external: model !== Environment.OLLAMA_MODEL,
model: model
},
ocr: {
supported: info.capabilities.includes("ocr"),
external: model !== Environment.OLLAMA_MODEL,
model: model
},
thinking: {
supported: info.capabilities.includes("thinking"),
external: model !== Environment.OLLAMA_MODEL,
model: model
},
tools: {
supported: info.capabilities.includes("tools"),
external: model !== Environment.OLLAMA_MODEL,
model: model
},
};
} catch (e) {
logError(e);
return null;
}
}
async loadImageModelInfo(): Promise<ShowResponse | null> {
return ollama.show({model: Environment.OLLAMA_IMAGE_MODEL});
async loadImageModelInfo(): Promise<AiModelCapabilities | null> {
return this.getModelCapabilities(Environment.OLLAMA_IMAGE_MODEL);
}
async loadThinkModelInfo(): Promise<ShowResponse | null> {
return ollama.show({model: Environment.OLLAMA_THINK_MODEL});
async loadThinkModelInfo(): Promise<AiModelCapabilities | null> {
return this.getModelCapabilities(Environment.OLLAMA_THINK_MODEL);
}
}
+2 -2
View File
@@ -1,11 +1,11 @@
import {ChatCommand} from "../base/chat-command";
import {Command} from "../base/command";
import {Message} from "typescript-telegram-bot-api";
import {ollama} from "../index";
import {logError, oldReplyToMessage, replyToMessage} from "../util/utils";
import {Requirements} from "../base/requirements";
import {Requirement} from "../base/requirement";
export class OllamaListModels extends ChatCommand {
export class OllamaListModels extends Command {
title = "/ollamaListModels";
description = "List all Ollama models";
+3 -3
View File
@@ -1,4 +1,4 @@
import {ChatCommand} from "../base/chat-command";
import {Command} from "../base/command";
import {Message} from "typescript-telegram-bot-api";
import {abortOllamaRequest, bot, getOllamaRequest, ollama, ollamaRequests} from "../index";
import {escapeMarkdownV2Text, logError, oldReplyToMessage, startIntervalEditor} from "../util/utils";
@@ -9,7 +9,7 @@ import {Cancel} from "../callback_commands/cancel";
import {OllamaCancel} from "../callback_commands/ollama-cancel";
import {MessageStore} from "../common/message-store";
export class OllamaPrompt extends ChatCommand {
export class OllamaPrompt extends Command {
command = "ollamaPrompt";
argsMode = "required" as const;
@@ -37,7 +37,7 @@ export class OllamaPrompt extends ChatCommand {
waitMessage = await bot.sendMessage({
chat_id: chatId,
text: Environment.waitText,
text: Environment.waitThinkText,
reply_parameters: {
chat_id: chatId,
message_id: msg.message_id
+5 -5
View File
@@ -1,13 +1,13 @@
import {ChatCommand} from "../base/chat-command";
import {Command} from "../base/command";
import {Requirements} from "../base/requirements";
import {Requirement} from "../base/requirement";
import {Message} from "typescript-telegram-bot-api";
import {bot, ollama} from "../index";
import {WebSearchResponse} from "../model/web-search-response";
import {editMessageText, logError} from "../util/utils";
import {oldEditMessageText, logError} from "../util/utils";
import {Environment} from "../common/environment";
export class OllamaSearch extends ChatCommand {
export class OllamaSearch extends Command {
command = ["s", "search"];
argsMode = "required" as const;
@@ -23,7 +23,7 @@ export class OllamaSearch extends ChatCommand {
try {
const wait = await bot.sendMessage({
chat_id: chatId,
text: Environment.waitText,
text: Environment.waitThinkText,
reply_parameters: {
chat_id: chatId,
message_id: msg.message_id
@@ -40,7 +40,7 @@ export class OllamaSearch extends ChatCommand {
message += `${index + 1}. ${r.url}\n`;
});
await editMessageText(chatId, wait.message_id, message);
await oldEditMessageText(chatId, wait.message_id, message);
} catch (error) {
logError(error);
}
+2 -2
View File
@@ -1,12 +1,12 @@
import {Message} from "typescript-telegram-bot-api";
import {ChatCommand} from "../base/chat-command";
import {Command} from "../base/command";
import {Environment} from "../common/environment";
import {logError, replyToMessage} from "../util/utils";
import {Requirements} from "../base/requirements";
import {Requirement} from "../base/requirement";
import {ollama} from "../index";
export class OllamaSetModel extends ChatCommand {
export class OllamaSetModel extends Command {
argsMode = "required" as const;
title = "/ollamaSetModel";
+167
View File
@@ -0,0 +1,167 @@
import {Message} from "typescript-telegram-bot-api";
import {MessageStore} from "../common/message-store";
import {
collectReplyChainText,
escapeMarkdownV2Text,
logError,
replyToMessage,
startIntervalEditor
} from "../util/utils";
import {Environment} from "../common/environment";
import {bot, openAi} from "../index";
import {Requirements} from "../base/requirements";
import {Requirement} from "../base/requirement";
import {ChatCommand} from "../base/chat-command";
export class OpenAIChat extends ChatCommand {
command = ["openai", "chatgpt"];
argsMode = "required" as const;
requirements = Requirements.Build(Requirement.BOT_CREATOR);
title = "/openAI";
description = "Chat with AI (OpenAI)";
async execute(msg: Message, match?: RegExpExecArray): Promise<void> {
console.log("OpenAI Chat: ", match);
return this.executeOpenAI(msg, match?.[3]);
}
async executeOpenAI(msg: Message, text: string): Promise<void> {
if (!text || text.trim().length === 0) return;
const chatId = msg.chat.id;
const storedMsg = await MessageStore.get(chatId, msg.message_id);
const messageParts = await collectReplyChainText(storedMsg);
console.log("MESSAGE PARTS", messageParts);
const chatMessages = messageParts.map(part => {
const content = [];
content.push({
type: part.bot ? "output_text" : "input_text",
text: (Environment.USE_NAMES_IN_PROMPT && !part.bot ? `MESSAGE FROM USER "${part.name}":\n` : "") + part.content,
});
// TODO: 03/02/2026, Danil Nikolaev: upload file then add here
// for (const image of part.images) {
// content.push({
// type: "image_url",
// imageUrl: "data:image/jpeg;base64," + image
// });
// }
return {
role: part.bot ? "assistant" : "user",
content: content,
type: "message",
};
});
chatMessages.reverse();
if (Environment.SYSTEM_PROMPT) {
chatMessages.unshift({
role: "system",
content: [{type: "input_text", text: Environment.SYSTEM_PROMPT}],
type: "message"
});
}
let waitMessage: Message;
const startTime = Date.now();
try {
waitMessage = await bot.sendMessage({
chat_id: chatId,
text: Environment.waitThinkText,
reply_parameters: {
chat_id: chatId,
message_id: msg.message_id
}
});
const stream = await openAi.responses.create({
model: Environment.OPENAI_MODEL,
// eslint-disable-next-line @typescript-eslint/no-explicit-any
input: chatMessages as any,
stream: true
});
let currentText = "";
let shouldBreak = false;
const editor = startIntervalEditor({
intervalMs: 4500,
getText: () => currentText,
editFn: async (text) => {
await bot.editMessageText(
{
chat_id: chatId,
message_id: waitMessage.message_id,
text: escapeMarkdownV2Text(text),
parse_mode: "MarkdownV2"
}
).catch(logError);
console.log("editMessageText", text);
waitMessage.reply_to_message = msg;
waitMessage.text = text;
await MessageStore.put(waitMessage);
},
onStop: async () => {
}
});
await editor.tick();
try {
for await (const chunk of stream) {
console.log("chunk", chunk);
if (chunk.type === "response.output_text.delta") {
const text = chunk.delta;
currentText += text;
if (currentText.length > 4096) {
currentText = currentText.slice(0, 4093) + "...";
shouldBreak = true;
}
console.log("messageText", currentText);
console.log("length", currentText.length);
if (shouldBreak) {
console.log("break", true);
break;
}
}
}
} finally {
await editor.tick();
await editor.stop();
if (!shouldBreak) {
console.log("ended", true);
}
const diff = Math.abs(Date.now() - startTime) / 1000.0;
console.log("time", diff);
waitMessage.reply_to_message = msg;
waitMessage.text = currentText;
await MessageStore.put(waitMessage);
if (Environment.SEND_TIME_TOOK) {
await replyToMessage({message: waitMessage, text: `⏱️ ${diff}s`});
}
}
} catch (error) {
logError(error);
await replyToMessage({
message: waitMessage,
text: `Произошла ошибка!\n${error.toString()}`
}).catch(logError);
}
}
}
+117
View File
@@ -0,0 +1,117 @@
import {ChatCommand} from "../base/chat-command";
import {Message} from "typescript-telegram-bot-api";
import {Requirements} from "../base/requirements";
import {Requirement} from "../base/requirement";
import {bot, openAi, photoGenDir} from "../index";
import fs from "node:fs";
import path from "node:path";
import {oldEditMessageText, logError, replyToMessage} from "../util/utils";
import {Environment} from "../common/environment";
import {APIError} from "openai";
export class OpenAIGenImage extends ChatCommand {
command = ["openAiGenImage", "chatGPTGenImage", "imgen"];
title = "/openAIGenImage";
description = "Generate image from OpenAI";
argsMode = "required" as const;
requirements = Requirements.Build(Requirement.BOT_CREATOR);
async execute(msg: Message, match?: RegExpExecArray): Promise<void> {
const prompt = match?.[3]?.trim();
if (!prompt?.length) return;
let waitMessage: Message | null = null;
try {
const totalParts = 3;
const model = Environment.OPENAI_IMAGE_MODEL;
const fileFullName = `${msg.chat.id}_${msg.message_id}.png`;
const getFileLocation = (fn: string) => {
return path.join(photoGenDir, fn);
};
waitMessage = await replyToMessage({message: msg, text: "🌈 Генерирую изображение..."});
const stream = await openAi.images.generate({
model: model,
prompt: prompt,
n: 1,
size: "auto",
stream: true,
partial_images: totalParts,
moderation: "low",
output_format: "png",
});
const then = Date.now();
for await (const event of stream) {
switch (event.type) {
case "image_generation.partial_image": {
console.log(` Partial image ${event.partial_image_index + 1}/3 received`);
console.log(` Size: ${event.b64_json.length} characters (base64)`);
const fileName = `partial_${event.partial_image_index + 1}_${fileFullName}`;
const imageBuffer = Buffer.from(event.b64_json, "base64");
const fileLocation = getFileLocation(fileName);
fs.writeFileSync(fileLocation, imageBuffer);
console.log(` 💾 Saved to: ${path.resolve(fileLocation)}`);
await bot.editMessageMedia({
chat_id: msg.chat.id,
message_id: waitMessage.message_id,
media: {
type: "photo",
media: imageBuffer,
caption: `🌈 Генерирую изображение (${(event.partial_image_index + 1)}/${totalParts})...`
}
});
break;
}
case "image_generation.completed": {
console.log("\n✅ Final image completed!");
console.log(` Size: ${event.b64_json.length} characters (base64)`);
const imageBuffer = Buffer.from(event.b64_json, "base64");
const fileLocation = getFileLocation(fileFullName);
fs.writeFileSync(fileLocation, imageBuffer);
console.log(` Saved to: ${path.resolve(fileLocation)}`);
const diff = Date.now() - then;
await bot.editMessageMedia({
chat_id: msg.chat.id,
message_id: waitMessage.message_id,
media: {
type: "photo",
media: imageBuffer,
caption: `🌈 Изображение по запросу "${prompt}" сгенерировано моделью "${model}" размеров ${event.size} за ${diff}ms`
}
});
break;
}
default:
console.log(`❓ Unknown event: ${event}`);
}
}
} catch (e) {
logError(e);
if (e instanceof APIError && e.error.code === "moderation_blocked") {
const text = "❌ Мне запрещено такое генерировать 😠";
if (waitMessage) {
await oldEditMessageText(msg.chat.id, waitMessage.message_id, text).catch(logError);
} else {
await replyToMessage({message: msg, text: text}).catch(logError);
}
} else {
await replyToMessage({
message: waitMessage ? waitMessage : msg,
text: `Произошла ошибка: ${e}`
}).catch(logError);
}
}
}
}
+29
View File
@@ -0,0 +1,29 @@
import {Command} from "../base/command";
import {Message} from "typescript-telegram-bot-api";
import {logError, replyToMessage} from "../util/utils";
import {Environment} from "../common/environment";
import {AiModelCapabilities} from "../model/ai-model-capabilities";
export class OpenAIGetModel extends Command {
title = "/openAIGetModel";
description = "Get current OpenAI model";
async execute(msg: Message): Promise<void> {
await replyToMessage({message: msg, text: `Текущая модель: "${Environment.OPENAI_MODEL}"`}).catch(logError);
}
async getModelCapabilities(): Promise<AiModelCapabilities | null> {
// TODO: 12/02/2026, Danil Nikolaev: find solution
try {
return {
vision: {supported: true},
ocr: null,
thinking: {supported: true},
tools: {supported: true},
};
} catch (e) {
logError(e);
return null;
}
}
}
+37
View File
@@ -0,0 +1,37 @@
import {Command} from "../base/command";
import {Requirements} from "../base/requirements";
import {Requirement} from "../base/requirement";
import {Message} from "typescript-telegram-bot-api";
import {openAi} from "../index";
import {logError, replyToMessage} from "../util/utils";
export class OpenAIListModels extends Command {
title = "/openAIListModels";
description = "List all OpenAI models";
requirements = Requirements.Build(Requirement.BOT_CREATOR);
async execute(msg: Message): Promise<void> {
try {
const listResponse = await openAi.models.list();
console.log(listResponse);
const modelsString = listResponse.data
.map(e => `${e.id}`)
.sort((a, b) => a.localeCompare(b))
.join("\n")
.substring(0, 4000);
const text = "Доступные модели:\n\n" + "<blockquote expandable>" + modelsString + "</blockquote>";
await replyToMessage({
message: msg,
text: text,
parse_mode: "HTML"
});
} catch (e) {
logError(e);
await replyToMessage({message: msg, text: "Не получилось загрузить список моделей"}).catch(logError);
}
}
}
+25
View File
@@ -0,0 +1,25 @@
import {Command} from "../base/command";
import {Requirements} from "../base/requirements";
import {Requirement} from "../base/requirement";
import {Message} from "typescript-telegram-bot-api";
import {Environment} from "../common/environment";
import {logError, replyToMessage} from "../util/utils";
export class OpenAISetModel extends Command {
argsMode = "required" as const;
title = "/openAISetModel";
description = "Set OpenAI model";
requirements = Requirements.Build(Requirement.BOT_CREATOR);
async execute(msg: Message, match?: RegExpExecArray | null): Promise<void> {
const newModel = match?.[3];
Environment.setOpenAIModel(newModel || Environment.OPENAI_MODEL);
const text = newModel ? `Выбрана модель "${newModel}"`
: `Модель не задана. Будет использоваться стандартная модель "${Environment.OPENAI_MODEL}".`;
await replyToMessage({message: msg, text: text}).catch(logError);
}
}
+2 -2
View File
@@ -1,8 +1,8 @@
import {logError, sendMessage} from "../util/utils";
import {Message} from "typescript-telegram-bot-api";
import {ChatCommand} from "../base/chat-command";
import {Command} from "../base/command";
export class Ping extends ChatCommand {
export class Ping extends Command {
title = "/ping";
description = "Ping between received and sent message";
+2 -2
View File
@@ -1,9 +1,9 @@
import {ChatCommand} from "../base/chat-command";
import {Command} from "../base/command";
import {Message} from "typescript-telegram-bot-api";
import {logError, randomValue, replyToMessage} from "../util/utils";
import {Environment} from "../common/environment";
export class PrefixResponse extends ChatCommand {
export class PrefixResponse extends Command {
async execute(msg: Message): Promise<void> {
await replyToMessage({message: msg, text: randomValue(Environment.ANSWERS.prefix)}).catch(logError);
}
+4 -2
View File
@@ -1,10 +1,10 @@
import {ChatCommand} from "../base/chat-command";
import {Command} from "../base/command";
import {Message} from "typescript-telegram-bot-api";
import {extractMessagePayload, logError, replyToMessage} from "../util/utils";
import {bot, botUser} from "../index";
import QRCode from "qrcode";
export class Qr extends ChatCommand {
export class Qr extends Command {
argsMode = "optional" as const;
@@ -25,6 +25,8 @@ export class Qr extends ChatCommand {
return;
}
// TODO: 16/02/2026, Danil Nikolaev: escape html symbols in payload
if (payload.length > 1500) {
payload = payload.slice(0, 1500);
+24 -26
View File
@@ -2,9 +2,9 @@ import axios from "axios";
import sharp from "sharp";
import emojiRegex from "emoji-regex";
import {createCanvas, GlobalFonts, type Image as CanvasImage, loadImage, SKRSContext2D} from "@napi-rs/canvas";
import {createCanvas, GlobalFonts, Image, type Image as CanvasImage, loadImage, SKRSContext2D} from "@napi-rs/canvas";
import {Message, MessageEntity, PhotoSize} from "typescript-telegram-bot-api";
import {ChatCommand} from "../base/chat-command";
import {Command} from "../base/command";
import {bot, botUser} from "../index";
import {
getChatAvatar,
@@ -12,8 +12,7 @@ import {
getUserAvatar,
logError,
makeDarkGradientBgFancy,
oldReplyToMessage,
oldSendMessage
replyToMessage
} from "../util/utils";
import {Requirements} from "../base/requirements";
import {Requirement} from "../base/requirement";
@@ -37,7 +36,7 @@ try {
logError(e);
}
export class Quote extends ChatCommand {
export class Quote extends Command {
command = ["cit", "citation", "q", "quote"];
argsMode = "none" as const;
@@ -50,21 +49,16 @@ export class Quote extends ChatCommand {
const chatId = msg.chat.id;
const reply = msg.reply_to_message;
if (!reply) {
await oldReplyToMessage(msg, "Сделай /quote реплаем на сообщение 🙂").catch(logError);
return;
}
try {
const quoteRaw = (msg.quote?.text ?? reply.text ?? reply.caption ?? "").trim();
if (quoteRaw.length === 0) {
await oldReplyToMessage(msg, "Не нашёл в сообщении текста 😢").catch(logError);
await replyToMessage({message: msg, text: "Не нашёл в сообщении текста 😢"}).catch(logError);
return;
}
const quote = quoteRaw.length ? quoteRaw : "…";
const entities = reply.entities ?? reply.caption_entities ?? [];
const entities = msg.quote ? msg.quote.entities : reply.entities ?? reply.caption_entities ?? [];
const png = await renderQuoteCard(msg, quote, reply, entities);
await bot.sendPhoto({
@@ -76,7 +70,7 @@ export class Quote extends ChatCommand {
}).catch(logError);
} catch (e) {
logError(e);
await oldSendMessage(msg, "Не смог собрать цитату 😢").catch(logError);
await replyToMessage({message: msg, text: "Не смог собрать цитату 😢"}).catch(logError);
}
}
}
@@ -85,6 +79,13 @@ const emojiCache = new Map<string, CanvasImage>();
const customEmojiCache = new Map<string, CanvasImage>();
function appleEmojiUrl(emoji: string): string {
const codePoints = [...emoji]
.map(char => char.codePointAt(0)!.toString(16))
.join("-");
return `https://cdn.jsdelivr.net/npm/emoji-datasource-apple@15.0.0/img/apple/64/${codePoints}.png`;
}
function githubEmojiUrl(emoji: string): string {
const codePoints = [...emoji]
.map(char => char.codePointAt(0)!.toString(16))
.join("-");
@@ -97,27 +98,24 @@ function twemojiUrl(emoji: string) {
}
async function loadEmoji(emoji: string): Promise<CanvasImage> {
let url = appleEmojiUrl(emoji);
let cached = emojiCache.get(url);
if (cached) return cached;
try {
const downloadAndCache = async (url: string): Promise<Image> => {
const res = await axios.get<ArrayBuffer>(url, {responseType: "arraybuffer"});
const img = await loadImage(Buffer.from(res.data));
emojiCache.set(url, img);
return img;
} catch (e) {
logError(e);
};
url = twemojiUrl(emoji);
cached = emojiCache.get(url);
const checkIfCached = async (emoji: string, emojiToUrl: (emoji: string) => string): Promise<CanvasImage> => {
const url = emojiToUrl(emoji);
const cached = emojiCache.get(url);
if (cached) return cached;
return await downloadAndCache(emojiToUrl(emoji));
};
const sources = [appleEmojiUrl, githubEmojiUrl, twemojiUrl];
for (const source of sources) {
try {
const res = await axios.get<ArrayBuffer>(url, {responseType: "arraybuffer"});
const img = await loadImage(Buffer.from(res.data));
emojiCache.set(url, img);
return img;
return await checkIfCached(emoji, source);
} catch (e) {
logError(e);
}
+2 -2
View File
@@ -1,8 +1,8 @@
import {ChatCommand} from "../base/chat-command";
import {Command} from "../base/command";
import {getRandomInt, getRangedRandomInt, logError, oldSendMessage} from "../util/utils";
import {Message} from "typescript-telegram-bot-api";
export class RandomInt extends ChatCommand {
export class RandomInt extends Command {
argsMode = "optional" as const;
title = "/randomInt";
+2 -2
View File
@@ -1,8 +1,8 @@
import {ChatCommand} from "../base/chat-command";
import {Command} from "../base/command";
import {getRandomInt, logError, replyToMessage} from "../util/utils";
import {Message} from "typescript-telegram-bot-api";
export class RandomString extends ChatCommand {
export class RandomString extends Command {
argsMode = "optional" as const;
title = "/randomString";
+2 -2
View File
@@ -1,4 +1,4 @@
import {ChatCommand} from "../base/chat-command";
import {Command} from "../base/command";
import {Message} from "typescript-telegram-bot-api";
import {Requirements} from "../base/requirements";
import {Requirement} from "../base/requirement";
@@ -15,7 +15,7 @@ const texts = [
const timings = [1500, 2500];
const timer = [3, 2, 1];
export class Shutdown extends ChatCommand {
export class Shutdown extends Command {
title = "/shutdown";
description = "Self-destruction sequence for bot (shutdown)";
+4 -4
View File
@@ -1,13 +1,13 @@
import {ChatCommand} from "../base/chat-command";
import {Command} from "../base/command";
import {Message} from "typescript-telegram-bot-api";
import {chatCommands} from "../index";
import {commands} from "../index";
import {Help} from "./help";
export class Start extends ChatCommand {
export class Start extends Command {
title = "/start";
description = "Start the bot";
async execute(msg: Message): Promise<void> {
await chatCommands.find(e => e instanceof Help).execute(msg);
await commands.find(e => e instanceof Help).execute(msg);
}
}
+2 -2
View File
@@ -1,8 +1,8 @@
import {ChatCommand} from "../base/chat-command";
import {Command} from "../base/command";
import {logError, replyToMessage} from "../util/utils";
import {Message} from "typescript-telegram-bot-api";
export class SystemInfo extends ChatCommand {
export class SystemInfo extends Command {
title = "/systemInfo";
description = "System information";
+3 -3
View File
@@ -1,10 +1,10 @@
import {ChatCommand} from "../base/chat-command";
import {Command} from "../base/command";
import {Message} from "typescript-telegram-bot-api";
import {logError, oldReplyToMessage, randomValue} from "../util/utils";
import {Environment} from "../common/environment";
export class Test extends ChatCommand {
regexp = /^(test|тест|еуые|ntcn|инноке(нтий|ш|нтич))/i;
export class Test extends Command {
regexp = /^(test|тест|еуые|ntcn|инноке(нтий|ш|нтич))$/i;
title = "тест";
description = "System functionality check";
+2 -2
View File
@@ -1,11 +1,11 @@
import {ChatCommand} from "../base/chat-command";
import {Command} from "../base/command";
import {Message} from "typescript-telegram-bot-api";
import {Requirements} from "../base/requirements";
import {Requirement} from "../base/requirement";
import {logError, oldReplyToMessage} from "../util/utils";
import {bot} from "../index";
export class Title extends ChatCommand {
export class Title extends Command {
command = "title";
argsMode = "required" as const;
+2 -2
View File
@@ -1,4 +1,4 @@
import {ChatCommand} from "../base/chat-command";
import {Command} from "../base/command";
import {Message} from "typescript-telegram-bot-api";
import {logError, oldReplyToMessage, randomValue} from "../util/utils";
@@ -74,7 +74,7 @@ export function fixLayoutAuto(
return text;
}
export class Transliteration extends ChatCommand {
export class Transliteration extends Command {
command = ["transliteration", "tr"];
title = "/tr [text or reply]";
+2 -2
View File
@@ -1,4 +1,4 @@
import {ChatCommand} from "../base/chat-command";
import {Command} from "../base/command";
import {Requirements} from "../base/requirements";
import {Requirement} from "../base/requirement";
import {Message} from "typescript-telegram-bot-api";
@@ -6,7 +6,7 @@ import {bot, botUser} from "../index";
import {fullName, logError, oldReplyToMessage, oldSendMessage} from "../util/utils";
import {Environment} from "../common/environment";
export class Unban extends ChatCommand {
export class Unban extends Command {
title = "/unban [reply]";
description = "unban user from chat";
+2 -2
View File
@@ -1,4 +1,4 @@
import {ChatCommand} from "../base/chat-command";
import {Command} from "../base/command";
import {Requirements} from "../base/requirements";
import {Requirement} from "../base/requirement";
import {fullName, logError, oldSendMessage} from "../util/utils";
@@ -6,7 +6,7 @@ import {Message} from "typescript-telegram-bot-api";
import {botUser} from "../index";
import {Environment} from "../common/environment";
export class Unignore extends ChatCommand {
export class Unignore extends Command {
title = "/unignore";
description = "Bot will start responding to the user";
requirements = Requirements.Build(
+2 -2
View File
@@ -1,8 +1,8 @@
import {ChatCommand} from "../base/chat-command";
import {Command} from "../base/command";
import {Message} from "typescript-telegram-bot-api";
import {getUptime, logError, oldSendMessage} from "../util/utils";
export class Uptime extends ChatCommand {
export class Uptime extends Command {
title = "/uptime";
description = "Bot's uptime";
+2 -2
View File
@@ -1,9 +1,9 @@
import {ChatCommand} from "../base/chat-command";
import {Command} from "../base/command";
import {logError, oldSendMessage, randomValue} from "../util/utils";
import {Message} from "typescript-telegram-bot-api";
import {Environment} from "../common/environment";
export class WhatBetter extends ChatCommand {
export class WhatBetter extends Command {
command = ["what", "что"];
argsMode = "required" as const;
+2 -2
View File
@@ -1,8 +1,8 @@
import {ChatCommand} from "../base/chat-command";
import {Command} from "../base/command";
import {getRandomInt, getRangedRandomInt, logError, oldReplyToMessage} from "../util/utils";
import {Message} from "typescript-telegram-bot-api";
export class When extends ChatCommand {
export class When extends Command {
command = ["when", "когда"];
argsMode = "required" as const;
+25 -13
View File
@@ -1,25 +1,33 @@
import {ChatCommand} from "../base/chat-command";
import {Command} from "../base/command";
import {Message} from "typescript-telegram-bot-api";
import {logError, replyToMessage} from "../util/utils";
import {bot} from "../index";
import {downloadVideoFromYouTube} from "../util/ytdl";
import {editMessageText, logError, replyToMessage} from "../util/utils";
import {bot, botUser} from "../index";
import {DownloadOptions, downloadVideoFromYouTube, getYouTubeVideoId} from "../util/ytdl";
import {Environment} from "../common/environment";
import {TryAgain} from "../callback_commands/try-again";
export class YouTubeDownload extends ChatCommand {
export class YouTubeDownload extends Command {
command = ["ytdl", "youtube"];
argsMode = "required" as const;
async execute(msg: Message, match?: RegExpExecArray): Promise<void> {
const url = match?.[3];
return this.downloadYouTubeVideo(msg, url);
return this.downloadYouTubeVideo(msg, {url: url});
}
async downloadYouTubeVideo(msg: Message, url: string): Promise<void> {
let waitMessage: Message | null = null;
async downloadYouTubeVideo(msg: Message, options: DownloadOptions): Promise<void> {
// TODO: 02.03.2026, Danil Nikolaev: add check for date
let waitMessage: Message | null = (msg.from.id === botUser.id) ? msg : null;
const videoId = "videoId" in options ? options.videoId : getYouTubeVideoId(options.url);
try {
waitMessage = await replyToMessage({message: msg, text: "⏳ Секунду..."});
if (!waitMessage) {
waitMessage = await replyToMessage({message: msg, text: "⏳ Скачиваю видео..."});
} else {
await editMessageText({message: msg, text: "⏳ Скачиваю видео..."});
}
const {time, exists, buffer} = await downloadVideoFromYouTube(url);
const {time, exists, buffer} = await downloadVideoFromYouTube({videoId: videoId});
if (buffer) {
const start = Date.now();
waitMessage = await bot.editMessageMedia({
@@ -35,8 +43,7 @@ export class YouTubeDownload extends ChatCommand {
waitMessage = await bot.editMessageCaption({
chat_id: msg.chat.id,
message_id: waitMessage.message_id,
caption: `[Видео](${url})` + (exists ? " загружено из кэша" : " успешно скачано") + " за " + (time + diff) + "мс",
parse_mode: "MarkdownV2"
caption: "✅ Видео" + (exists ? " загружено из кэша" : " успешно скачано") + " за " + (time + diff) + "мс",
}) as Message;
}
} catch (e) {
@@ -46,7 +53,12 @@ export class YouTubeDownload extends ChatCommand {
await bot.editMessageText({
chat_id: msg.chat.id,
message_id: waitMessage.message_id,
text: `⚠️ Произошла ошибка.\n${e}`,
text: Environment.errorText,
reply_markup: {
inline_keyboard: [[
TryAgain.withData("/ytdl " + videoId).asButton()
]]
}
});
}
}
+68 -3
View File
@@ -2,6 +2,8 @@ import path from "node:path";
import {saveData} from "../db/database";
import {Answers} from "../model/answers";
import {ifTrue} from "../util/utils";
import {AiProvider} from "../model/ai-provider";
import {ImageHandleFallbackPolicy, ImageHandlePolicy, RateLimitFallbackPolicy} from "./policies";
export class Environment {
static BOT_TOKEN: string;
@@ -18,13 +20,24 @@ export class Environment {
static ONLY_FOR_CREATOR_MODE: boolean;
static ENABLE_UNSAFE_EVAL: boolean;
static ANSWERS: Answers;
static USE_NAMES_IN_PROMPT: boolean;
static MAX_PHOTO_SIZE: number;
static PROCESS_LINKS: boolean;
static DEFAULT_AI_PROVIDER: AiProvider;
static RATE_LIMIT_FALLBACK_POLICY: RateLimitFallbackPolicy;
static IMAGE_HANDLE_POLICY: ImageHandlePolicy;
static IMAGE_HANDLE_FALLBACK_POLICY: ImageHandleFallbackPolicy;
static SYSTEM_PROMPT?: string;
static SEND_TIME_TOOK: boolean;
static OLLAMA_ADDRESS?: string;
static OLLAMA_MODEL?: string;
@@ -39,7 +52,14 @@ export class Environment {
static MISTRAL_API_KEY?: string;
static MISTRAL_MODEL: string;
static waitText = "⏳ Дайте-ка подумать...";
static OPENAI_BASE_URL?: string;
static OPENAI_API_KEY?: string;
static OPENAI_MODEL: string;
static OPENAI_IMAGE_MODEL: string;
static errorText = "⚠️ Произошла ошибка.";
static waitText = "⏳ Секунду...";
static waitThinkText = "⏳ Дайте-ка подумать...";
static analyzingPictureText = "🔍 Внимательно изучаю изображение...";
static analyzingPicturesText = "🔍 Внимательно изучаю изображения...";
static genImageText = "👨‍🎨 Генерирую изображение...";
@@ -57,11 +77,43 @@ export class Environment {
Environment.ONLY_FOR_CREATOR_MODE = ifTrue(process.env.ONLY_FOR_CREATOR_MODE);
Environment.ENABLE_UNSAFE_EVAL = ifTrue(process.env.ENABLE_UNSAFE_EVAL);
Environment.USE_NAMES_IN_PROMPT = ifTrue(process.env.USE_NAMES_IN_PROMPT);
Environment.MAX_PHOTO_SIZE = Number(process.env.MAX_PHOTO_SIZE || "1280");
Environment.SYSTEM_PROMPT = process.env.SYSTEM_PROMPT?.trim();
Environment.PROCESS_LINKS = ifTrue(process.env.PROCESS_LINKS);
const aiProvider = process.env.DEFAULT_AI_PROVIDER || "OLLAMA";
if (Object.values(AiProvider).includes(aiProvider as AiProvider)) {
Environment.DEFAULT_AI_PROVIDER = aiProvider as AiProvider;
} else {
Environment.DEFAULT_AI_PROVIDER = AiProvider.OLLAMA;
}
const rateLimitFallbackPolicy = process.env.RATE_LIMIT_FALLBACK_POLICY || "NOTIFY_USER";
if (Object.values(RateLimitFallbackPolicy).includes(rateLimitFallbackPolicy as RateLimitFallbackPolicy)) {
Environment.RATE_LIMIT_FALLBACK_POLICY = rateLimitFallbackPolicy as RateLimitFallbackPolicy;
} else {
Environment.RATE_LIMIT_FALLBACK_POLICY = RateLimitFallbackPolicy.NOTIFY_USER;
}
const imageHandlePolicy = process.env.IMAGE_HANDLE_POLICY || "HANDLE_IF_CAPABLE";
if (Object.values(ImageHandlePolicy).includes(imageHandlePolicy as ImageHandlePolicy)) {
Environment.IMAGE_HANDLE_POLICY = imageHandlePolicy as ImageHandlePolicy;
} else {
Environment.IMAGE_HANDLE_POLICY = ImageHandlePolicy.HANDLE_IF_CAPABLE;
}
const imageHandleFallbackPolicy = process.env.IMAGE_HANDLE_FALLBACK_POLICY || "NOTIFY_USER";
if (Object.values(ImageHandleFallbackPolicy).includes(imageHandleFallbackPolicy as ImageHandleFallbackPolicy)) {
Environment.IMAGE_HANDLE_FALLBACK_POLICY = imageHandleFallbackPolicy as ImageHandleFallbackPolicy;
} else {
Environment.IMAGE_HANDLE_FALLBACK_POLICY = ImageHandleFallbackPolicy.NOTIFY_USER;
}
Environment.SEND_TIME_TOOK = ifTrue(process.env.SEND_TOOK_TIME || false);
Environment.OLLAMA_ADDRESS = process.env.OLLAMA_ADDRESS;
Environment.OLLAMA_MODEL = process.env.OLLAMA_MODEL || "gemma3:4b";
@@ -74,7 +126,16 @@ export class Environment {
Environment.GEMINI_IMAGE_MODEL = process.env.GEMINI_IMAGE_MODEL || "gemini-2.5-flash-image";
Environment.MISTRAL_API_KEY = process.env.MISTRAL_API_KEY;
Environment.MISTRAL_MODEL = process.env.MISTRAL_MODEL || "mistral-small-latest";
Environment.MISTRAL_MODEL = process.env.MISTRAL_MODEL || "mistral-tiny-latest";
Environment.OPENAI_BASE_URL = process.env.OPENAI_BASE_URL;
Environment.OPENAI_API_KEY = process.env.OPENAI_API_KEY;
Environment.OPENAI_MODEL = process.env.OPENAI_MODEL || "gpt-4.1-nano";
Environment.OPENAI_IMAGE_MODEL = process.env.OPENAI_IMAGE_MODEL || "gpt-image-1-mini";
}
static setSystemPrompt(prompt: string) {
this.SYSTEM_PROMPT = prompt;
}
static setAdmins(admins: Set<number>) {
@@ -135,4 +196,8 @@ export class Environment {
static setMistralModel(newModel: string) {
Environment.MISTRAL_MODEL = newModel;
}
static setOpenAIModel(newModel: string) {
Environment.OPENAI_MODEL = newModel;
}
}
+17
View File
@@ -0,0 +1,17 @@
export enum RateLimitFallbackPolicy {
NOTIFY_USER = "NOTIFY_USER",
IGNORE_USER = "IGNORE_USER",
USE_OLLAMA = "USE_OLLAMA",
}
export enum ImageHandlePolicy {
IGNORE = "IGNORE",
FORCE_HANDLE = "FORCE_HANDLE",
HANDLE_IF_CAPABLE = "HANDLE_IF_CAPABLE",
}
export enum ImageHandleFallbackPolicy {
NOTIFY_USER = "NOTIFY_USER",
IGNORE_USER = "IGNORE_USER",
USE_OLLAMA = "USE_OLLAMA",
}
+14
View File
@@ -2,6 +2,7 @@ import * as fs from "fs";
import {Environment} from "../common/environment";
import {logError} from "../util/utils";
import {Answers} from "../model/answers";
import path from "node:path";
type DataJsonFile = {
admins: number[]
@@ -27,6 +28,19 @@ export async function readData(): Promise<void> {
}
}
export async function readPrompts(): Promise<void> {
try {
const prompt = fs.readFileSync(path.join(Environment.DATA_PATH, "system_prompt.txt")).toString().trim();
if (prompt.length) {
Environment.setSystemPrompt(prompt);
}
} catch (e) {
logError(e);
}
return Promise.resolve();
}
export async function saveData(): Promise<void> {
const adminIds: number[] = [];
Environment.ADMIN_IDS.forEach(id => adminIds.push(id));
+94 -90
View File
@@ -1,14 +1,15 @@
import "dotenv/config";
import {Environment} from "./common/environment";
import {InlineQueryResult, TelegramBot, User} from "typescript-telegram-bot-api";
import {ChatCommand} from "./base/chat-command";
import {TelegramBot, User} from "typescript-telegram-bot-api";
import {Command} from "./base/command";
import {
delay,
extractTextMessage,
findAndExecuteCallbackCommand,
ignore,
initSystemSpecs,
logError,
processCallbackQuery,
processEditedMessage,
processInlineQuery,
processMyChatMember,
processNewMessage
} from "./util/utils";
import {Ae} from "./commands/ae";
@@ -19,7 +20,7 @@ import {Ping} from "./commands/ping";
import {RandomString} from "./commands/random-string";
import {SystemInfo} from "./commands/system-info";
import {Test} from "./commands/test";
import {readData, retrieveAnswers} from "./db/database";
import {readData, readPrompts, retrieveAnswers} from "./db/database";
import {Uptime} from "./commands/uptime";
import {WhatBetter} from "./commands/what-better";
import {When} from "./commands/when";
@@ -27,7 +28,6 @@ import {RandomInt} from "./commands/random-int";
import {Ban} from "./commands/ban";
import {Quote} from "./commands/quote";
import {Ollama} from "ollama";
import {WebSearchResponse} from "./model/web-search-response";
import {OllamaSearch} from "./commands/ollama-search";
import {Id} from "./commands/id";
import {OllamaPrompt} from "./commands/ollama-prompt";
@@ -37,7 +37,6 @@ import {Shutdown} from "./commands/shutdown";
import {Leave} from "./commands/leave";
import {OllamaChat} from "./commands/ollama-chat";
import {Start} from "./commands/start";
import {MessageStore} from "./common/message-store";
import {GeminiChat} from "./commands/gemini-chat";
import {Choice} from "./commands/choice";
import {Coin} from "./commands/coin";
@@ -72,7 +71,18 @@ import {YouTubeDownload} from "./commands/youtube-download";
import fs from "node:fs";
import path from "node:path";
import {setInterval} from "node:timers";
import {clearUpVideoFolder} from "./util/files";
import {OpenAI} from "openai";
import {OpenAIChat} from "./commands/openai-chat";
import {OpenAIListModels} from "./commands/openai-list-models";
import {OpenAIGetModel} from "./commands/openai-get-model";
import {OpenAISetModel} from "./commands/openai-set-model";
import {Info} from "./commands/info";
import {OpenAIGenImage} from "./commands/openai-gen-image";
import {clearUpFolderFromOldFiles} from "./util/files";
import {DownloadYtVideo} from "./callback_commands/download-yt-video";
import {YtInfo} from "./callback_commands/yt-info";
import {AdminsList} from "./commands/admins-list";
import {ExportDb} from "./commands/export-db";
process.setUncaughtExceptionCaptureCallback(logError);
@@ -87,6 +97,7 @@ export let botUser: User;
export const googleAi = new GoogleGenAI({apiKey: Environment.GEMINI_API_KEY});
export const mistralAi = new Mistral({apiKey: Environment.MISTRAL_API_KEY});
export const openAi = new OpenAI({apiKey: Environment.OPENAI_API_KEY, baseURL: Environment.OPENAI_BASE_URL, dangerouslyAllowBrowser: true});
export const ollama = new Ollama({
host: Environment.OLLAMA_ADDRESS,
@@ -120,11 +131,10 @@ export function abortOllamaRequest(uuid: string): boolean {
}
}
export const chatCommands: ChatCommand[] = [
export const commands: Command[] = [
new Start(),
new Help(),
new Test(),
new Ae(),
new Ignore(),
new Unignore(),
new Ping(),
@@ -149,9 +159,13 @@ export const chatCommands: ChatCommand[] = [
new Title(),
new Transliteration(),
new Debug(),
new Info(),
new AdminsAdd(),
new AdminsRemove(),
new AdminsList(),
new ExportDb(),
new Shutdown(),
new Leave(),
@@ -159,12 +173,18 @@ export const chatCommands: ChatCommand[] = [
new YouTubeDownload()
];
if (Environment.ENABLE_UNSAFE_EVAL) {
commands.push(new Ae());
}
export const callbackCommands: CallbackCommand[] = [
new OllamaCancel()
new OllamaCancel(),
new DownloadYtVideo(),
new YtInfo()
];
if (Environment.OLLAMA_ADDRESS && Environment.OLLAMA_MODEL && Environment.SYSTEM_PROMPT) {
chatCommands.push(
commands.push(
new OllamaChat(),
new OllamaPrompt(),
new OllamaListModels(),
@@ -174,11 +194,11 @@ if (Environment.OLLAMA_ADDRESS && Environment.OLLAMA_MODEL && Environment.SYSTEM
}
if (Environment.OLLAMA_API_KEY) {
chatCommands.push(new OllamaSearch());
commands.push(new OllamaSearch());
}
if (Environment.GEMINI_API_KEY) {
chatCommands.push(
commands.push(
new GeminiChat(),
new GeminiListModels(),
new GeminiGetModel(),
@@ -188,7 +208,7 @@ if (Environment.GEMINI_API_KEY) {
}
if (Environment.MISTRAL_API_KEY) {
chatCommands.push(
commands.push(
new MistralChat(),
new MistralListModels(),
new MistralGetModel(),
@@ -196,21 +216,60 @@ if (Environment.MISTRAL_API_KEY) {
);
}
export const photoDir = path.join(Environment.DATA_PATH, "photo");
export const videoDir = path.join(Environment.DATA_PATH, "video");
if (Environment.OPENAI_API_KEY) {
commands.push(
new OpenAIChat(),
new OpenAIListModels(),
new OpenAIGetModel(),
new OpenAISetModel(),
new OpenAIGenImage()
);
}
export const cacheDir = path.join(Environment.DATA_PATH, "cache");
export const photoDir = path.join(cacheDir, "photo");
export const photoGenDir = path.join(photoDir, "gen");
export const videoDir = path.join(cacheDir, "video");
export const videoTempDir = path.join(videoDir, "temp");
let isShuttingDown = false;
async function shutdown(signal: NodeJS.Signals) {
if (isShuttingDown) return;
isShuttingDown = true;
console.log(`Received ${signal}. Stopping bot polling...`);
try {
await bot.stopPolling();
} catch (error) {
logError(error);
} finally {
process.exit(0);
}
}
async function main() {
const start = Date.now();
await readPrompts();
console.log(Environment.SYSTEM_PROMPT);
console.log(
`TEST_ENVIRONMENT: ${Environment.TEST_ENVIRONMENT}\n` +
`DATA_PATH: ${Environment.DATA_PATH}\n` +
`MAX_PHOTO_SIZE: ${Environment.MAX_PHOTO_SIZE}\n` +
`ONLY_FOR_CREATOR: ${Environment.ONLY_FOR_CREATOR_MODE}`
`ONLY_FOR_CREATOR: ${Environment.ONLY_FOR_CREATOR_MODE}\n` +
`DEFAULT_AI_PROVIDER: ${Environment.DEFAULT_AI_PROVIDER}`
);
fs.mkdir(photoDir, ignore);
fs.mkdir(videoDir, ignore);
const dirsToCheck = [cacheDir, photoDir, photoGenDir, videoDir, videoTempDir];
dirsToCheck.forEach(dir => {
if (!fs.existsSync(dir)) {
fs.mkdirSync(dir);
}
});
const now = new Date();
@@ -219,16 +278,17 @@ async function main() {
midnight.setDate(now.getDate() + 1);
const diff = midnight.getTime() - now.getTime();
console.log("Clearing up videos will be started in " + diff + "ms");
console.log("Clearing up cache will be started in " + diff + "ms");
clearUpFolderFromOldFiles(cacheDir);
delay(diff).then(() => {
setInterval(() => {
console.log("Started clearing up videos");
clearUpVideoFolder();
console.log("Started clearing up cache");
clearUpFolderFromOldFiles(cacheDir);
}, 1000 * 60 * 60 * 24);
});
const commands = chatCommands.filter(cmd => {
const cmds = commands.filter(cmd => {
return cmd.title && cmd.title.startsWith("/") && cmd.title.split(" ").length === 1 && cmd.description;
}).map(cmd => {
return {
@@ -242,7 +302,7 @@ async function main() {
[
initSystemSpecs(), readData(), retrieveAnswers(),
bot.getMe(),
bot.setMyCommands({commands: commands, scope: {type: "default"}})
bot.setMyCommands({commands: cmds, scope: {type: "default"}})
]
);
botUser = results[3];
@@ -257,74 +317,18 @@ async function main() {
}
}
bot.on("my_chat_member", async (u) => {
console.log("my_chat_member", u);
});
bot.on("edited_message", async (msg) => {
console.log("edited_message", msg);
await UserStore.put(msg.from);
if (!extractTextMessage(msg) || msg.from.id === botUser.id) return;
await MessageStore.put(msg);
});
bot.on("my_chat_member", processMyChatMember);
bot.on("edited_message", processEditedMessage);
bot.on("message", processNewMessage);
bot.on("inline_query", processInlineQuery);
bot.on("callback_query", processCallbackQuery);
bot.on("inline_query", async (query) => {
console.log("query", query);
if (Environment.CREATOR_ID !== query.from.id) {
await bot.answerInlineQuery({
inline_query_id: query.id,
results: [],
button: {
text: "No access",
start_parameter: "nope"
}
}).catch(logError);
return;
}
if (query.query.trim().length !== 0) {
try {
const queryResults: InlineQueryResult[] = [];
const results = await ollama.webSearch({query: query.query});
console.log("results", results);
results.results.forEach((result, i) => {
const r = result as WebSearchResponse;
queryResults.push({
type: "article",
id: `${i}`,
title: `${r.title}`,
input_message_content: {
message_text: `${r.title}\n\n${r.url}`
}
});
});
await bot.answerInlineQuery({
inline_query_id: query.id,
results: queryResults,
});
} catch (e) {
logError(e);
}
} else {
await bot.answerInlineQuery({
inline_query_id: query.id,
results: [],
}).catch(logError);
}
process.on("SIGTERM", () => {
shutdown("SIGTERM").catch(logError);
});
bot.on("callback_query", async (query) => {
console.log(query);
await findAndExecuteCallbackCommand(callbackCommands, query);
process.on("SIGINT", () => {
shutdown("SIGINT").catch(logError);
});
main().catch(logError);
+5
View File
@@ -0,0 +1,5 @@
export type AiCapabilityInfo = {
supported?: boolean,
external?: boolean,
model?: string
};
+8
View File
@@ -0,0 +1,8 @@
import {AiCapabilityInfo} from "./ai-capability-info";
export class AiModelCapabilities {
vision?: AiCapabilityInfo;
ocr?: AiCapabilityInfo;
thinking?: AiCapabilityInfo;
tools?: AiCapabilityInfo;
}
+6
View File
@@ -0,0 +1,6 @@
export enum AiProvider {
OLLAMA = "OLLAMA",
GEMINI = "GEMINI",
MISTRAL = "MISTRAL",
OPENAI = "OPENAI",
}
+15
View File
@@ -0,0 +1,15 @@
import {InlineKeyboardMarkup, Message, ParseMode} from "typescript-telegram-bot-api";
import {LinkPreviewOptions, MessageEntity} from "typescript-telegram-bot-api/dist/types";
export type EditOptions = ({
message: Message
} | {
chat_id: number;
message_id: number;
}) & {
text: string;
parse_mode?: ParseMode;
entities?: MessageEntity[];
link_preview_options?: LinkPreviewOptions;
reply_markup?: InlineKeyboardMarkup;
}
+77
View File
@@ -0,0 +1,77 @@
import {InlineKeyboardMarkup, Message, ParseMode} from "typescript-telegram-bot-api";
import {
ForceReply,
LinkPreviewOptions,
MessageEntity, ReplyKeyboardMarkup, ReplyKeyboardRemove,
ReplyParameters,
SuggestedPostParameters
} from "typescript-telegram-bot-api/dist/types";
export type SendOptions = ({
message: Message
} | {
/**
* Unique identifier for the target chat or username of the target channel (in the format `@channelusername`)
*/
chat_id: number | string;
message_id?: number;
}) & {
/**
* Unique identifier for the target message thread (topic) of the forum; for forum supergroups only
*/
message_thread_id?: number;
/**
* Identifier of the direct messages topic to which the message will be sent; required if the message is sent to a
* direct messages chat
*/
direct_messages_topic_id?: number;
/**
* Text of the message to be sent, 1-4096 characters after entities parsing
*/
text: string;
/**
* Mode for parsing entities in the message text. See formatting options for more details.
*/
parse_mode?: ParseMode;
/**
* A JSON-serialized list of special entities that appear in message text, which can be specified instead of
* parse_mode
*/
entities?: MessageEntity[];
/**
* Link preview generation options for the message
*/
link_preview_options?: LinkPreviewOptions;
/**
* Sends the message silently. Users will receive a notification with no sound.
*/
disable_notification?: boolean;
/**
* Protects the contents of the sent message from forwarding and saving
*/
protect_content?: boolean;
/**
* Pass True to allow up to 1000 messages per second, ignoring
* [broadcasting limits](https://core.telegram.org/bots/faq#how-can-i-message-all-of-my-bot-39s-subscribers-at-once)
* for a fee of 0.1 Telegram Stars per message. The relevant Stars will be withdrawn from the bot's balance
*/
allow_paid_broadcast?: boolean;
/**
* Unique identifier of the message effect to be added to the message; for private chats only
*/
message_effect_id?: string;
/**
* A JSON-serialized object containing the parameters of the suggested post to send; for direct messages chats only.
* If the message is sent as a reply to another suggested post, then that suggested post is automatically declined.
*/
suggested_post_parameters?: SuggestedPostParameters;
/**
* Description of the message to reply to
*/
reply_parameters?: ReplyParameters;
/**
* Additional interface options. A JSON-serialized object for an inline keyboard, custom reply keyboard,
* instructions to remove a reply keyboard or to force a reply from the user
*/
reply_markup?: InlineKeyboardMarkup | ReplyKeyboardMarkup | ReplyKeyboardRemove | ForceReply;
};
+11
View File
@@ -0,0 +1,11 @@
import {FfmpegCommand} from "fluent-ffmpeg";
export async function performFFmpeg(buildFFmpeg: () => FfmpegCommand): Promise<void> {
return new Promise((resolve, reject) => {
buildFFmpeg()
.on("end", () => {
resolve();
})
.on("error", reject);
});
}
+23 -19
View File
@@ -1,10 +1,9 @@
import {logError} from "./utils";
import fs from "node:fs";
import {videoDir} from "../index";
import path from "node:path";
export function clearUpVideoFolder() {
fs.readdir(videoDir, (err, files) => {
export function clearUpFolderFromOldFiles(folder: string, recursive = true) {
fs.readdir(folder, (err, files) => {
if (err) {
logError(err);
return;
@@ -12,30 +11,35 @@ export function clearUpVideoFolder() {
const filenamesToDelete: string[] = [];
files.forEach((filename, index) => {
fs.stat(path.join(videoDir, filename), (err, stats) => {
if (err) {
logError(err);
files.forEach(filename => {
const fullPath = path.join(folder, filename);
try {
const stats = fs.statSync(fullPath);
if (stats.isDirectory() && recursive) {
clearUpFolderFromOldFiles(fullPath, recursive);
} else {
const then = stats.mtime.getTime() / 1000;
const now = Date.now() / 1000;
const diff = Math.abs(now - then);
const moreThanOneDay = diff >= 60 * 60 * 24;
if (moreThanOneDay) {
filenamesToDelete.push(filename);
}
if (index === files.length - 1) {
console.log("filenamesToDelete", filenamesToDelete);
if (filenamesToDelete.length) {
filenamesToDelete.forEach((filename) => {
const fullPath = path.join(videoDir, filename);
fs.rm(fullPath, logError);
});
}
if (stats.isFile() && moreThanOneDay) {
filenamesToDelete.push(fullPath);
}
}
});
} catch (e) {
logError(e);
}
});
console.log("filenamesToDelete", filenamesToDelete);
if (filenamesToDelete.length) {
filenamesToDelete.forEach((filename) => {
fs.rm(filename, (e) => {
if (e) logError(e);
});
});
}
});
}
+637 -149
View File
@@ -1,18 +1,22 @@
import * as si from "systeminformation";
import {ChatCommand} from "../base/chat-command";
import {Command} from "../base/command";
import {CallbackCommand} from "../base/callback-command";
import {
CallbackQuery,
ChatMember,
ChatMemberUpdated,
InlineKeyboardMarkup,
InlineQuery,
InlineQueryResult,
Message,
ParseMode,
PhotoSize,
TelegramBot,
User
} from "typescript-telegram-bot-api";
import {Environment} from "../common/environment";
import {TelegramError} from "typescript-telegram-bot-api/dist/errors";
import {bot, botUser, chatCommands, messageDao} from "../index";
import {bot, botUser, callbackCommands, commands, messageDao, ollama, photoDir} from "../index";
import os from "os";
import axios from "axios";
import {MessagePart} from "../common/message-part";
@@ -27,8 +31,25 @@ import {MessageStore} from "../common/message-store";
import {SystemInfo} from "../commands/system-info";
import {PrefixResponse} from "../commands/prefix-response";
import {OllamaChat} from "../commands/ollama-chat";
import {getYouTubeVideoId} from "./ytdl";
import {getYouTubeVideoId, getYouTubeVideoInfo, isVideoExists} from "./ytdl";
import {YouTubeDownload} from "../commands/youtube-download";
import {ChatCommand} from "../base/chat-command";
import {WebSearchResponse} from "../model/web-search-response";
import {GeminiChat} from "../commands/gemini-chat";
import {MistralChat} from "../commands/mistral-chat";
import {OpenAIChat} from "../commands/openai-chat";
import {AiProvider} from "../model/ai-provider";
import {AiModelCapabilities} from "../model/ai-model-capabilities";
import {OllamaGetModel} from "../commands/ollama-get-model";
import {GeminiGetModel} from "../commands/gemini-get-model";
import {MistralGetModel} from "../commands/mistral-get-model";
import {OpenAIGetModel} from "../commands/openai-get-model";
import {SendOptions} from "../model/send-options";
import {EditOptions} from "../model/edit-options";
import VideoInfo from "youtubei.js/dist/src/parser/youtube/VideoInfo";
import {DownloadYtVideo} from "../callback_commands/download-yt-video";
import {TryAgain} from "../callback_commands/try-again";
import {StoredUser} from "../model/stored-user";
export const ignore = () => {
};
@@ -40,7 +61,7 @@ export const ignoreIfNotChanged = (e: Error | TelegramError) => {
};
export const ignoreIfMarkupFailed = (e: Error | TelegramError) => {
if (!(e instanceof TelegramError && e?.response?.description?.startsWith("Bad Request: can't parse entities"))) {
if (!isMarkupFailed(e)) {
throw e;
}
};
@@ -53,11 +74,23 @@ export const errorPlaceholder = async (msg: Message) => {
await sendErrorPlaceholder(msg).catch(logError);
};
export const isMarkupFailed = (e: Error | TelegramError) => {
return TelegramBot.isTelegramError(e) && e?.response?.description?.startsWith("Bad Request: can't parse entities");
};
export const isTooManyRequests = (e: Error | TelegramError) => {
return TelegramBot.isTelegramError(e) && e.response.description.includes("Too Many Requests");
};
export const isMessageTooLong = (e: Error | TelegramError) => {
return TelegramBot.isTelegramError(e) && e.response.description.includes("MESSAGE_TOO_LONG");
};
export function searchChatCommand(
commands: ChatCommand[],
commands: Command[],
text: string,
botUsername: string = botUser.username
): ChatCommand | null {
): Command | null {
for (const command of commands) {
const match = command.finalRegexp.exec(text);
if (!match) continue;
@@ -85,7 +118,7 @@ export function searchCallbackCommand(commands: CallbackCommand[], data: string)
return null;
}
export async function checkRequirements(cmd: ChatCommand | CallbackCommand | null, msg?: Message, cb?: CallbackQuery): Promise<boolean> {
export async function checkRequirements(cmd: Command | CallbackCommand | null, msg?: Message, cb?: CallbackQuery): Promise<boolean> {
if (!cmd) return false;
if (!msg && !cb) return false;
@@ -103,7 +136,7 @@ export async function checkRequirements(cmd: ChatCommand | CallbackCommand | nul
const cbId = cb?.id;
const chatId = msg?.chat?.id || cb?.message?.chat?.id || -1;
const messageId = msg?.message_id || cb?.message?.message_id || -1;
const messageId = msg?.message_id || (cb && cb.message && "reply_to_message" in cb.message ? cb.message.reply_to_message.message_id : null) || -1;
const fromId = msg?.from?.id || cb?.from?.id || -1;
const chatType = msg?.chat?.type || cb?.message?.chat?.type || null;
@@ -182,11 +215,8 @@ export async function checkRequirements(cmd: ChatCommand | CallbackCommand | nul
if (reqs.isRequiresSameUser()) {
let originalFromId: number | null;
try {
const queryMessage = await MessageStore.get(chatId, messageId);
if (queryMessage && queryMessage.replyToMessageId) {
const originalMessage = await MessageStore.get(chatId, queryMessage.replyToMessageId);
originalFromId = originalMessage?.fromId;
}
const originalMessage = await MessageStore.get(chatId, messageId);
originalFromId = originalMessage?.fromId;
} catch (e) {
logError(e);
originalFromId = null;
@@ -202,7 +232,7 @@ export async function checkRequirements(cmd: ChatCommand | CallbackCommand | nul
return true;
}
export async function executeChatCommand(cmd: ChatCommand | null, msg: Message, text: string): Promise<boolean> {
export async function executeChatCommand(cmd: Command | null, msg: Message, text: string): Promise<boolean> {
if (!cmd) return false;
if (!await checkRequirements(cmd, msg)) return false;
@@ -225,93 +255,92 @@ export async function findAndExecuteCallbackCommand(commands: CallbackCommand[],
return true;
}
export async function editMessageText(chatId: number, messageId: number, messageText: string, parseMode?: ParseMode, replyMarkup?: InlineKeyboardMarkup): Promise<void> {
if (messageText.trim().length === 0) return Promise.resolve();
export async function oldEditMessageText(chatId: number, messageId: number, messageText: string, parseMode?: ParseMode, replyMarkup?: InlineKeyboardMarkup): Promise<boolean | Message> {
return editMessageText({
chat_id: chatId,
message_id: messageId,
text: messageText,
parse_mode: parseMode,
reply_markup: replyMarkup,
link_preview_options: {is_disabled: true}
});
}
export async function editMessageText(options: EditOptions) {
if (options.text.trim().length === 0) return Promise.resolve(false);
try {
await bot.editMessageText({
chat_id: chatId,
message_id: messageId,
text: messageText,
parse_mode: parseMode,
link_preview_options: {
is_disabled: true
},
reply_markup: replyMarkup
}).catch(ignoreIfMarkupFailed);
return Promise.resolve();
const message = await bot.editMessageText({
chat_id: "message" in options ? options.message.chat.id : options.chat_id,
message_id: "message" in options ? options.message.message_id : options.message_id,
text: options.text,
parse_mode: options.parse_mode,
reply_markup: options.reply_markup,
link_preview_options: options.link_preview_options,
});
return Promise.resolve(message);
} catch (e) {
logError(e);
if (e instanceof TelegramError && e.response.description.includes("Too Many Requests")) {
if (isMarkupFailed(e)) {
return Promise.resolve(true);
} else if (isTooManyRequests(e)) {
const delay = Number(e.message.split("retry after ")[1]) || 30;
setTimeout(() => {
return Promise.resolve();
}, delay * 1000);
} else if (e instanceof TelegramError && e.response.description.includes("MESSAGE_TOO_LONG")) {
return Promise.reject(e);
} else {
return Promise.resolve();
return Promise.reject(e);
}
}
}
export type SendOptions = {
chat_id?: number;
message?: Message,
message_id?: number;
text: string,
parse_mode?: ParseMode,
disableLinkPreview?: boolean
};
export async function oldSendMessage(message: Message, text: string, parseMode?: ParseMode): Promise<Message> {
const response = await bot.sendMessage({
chat_id: message.chat.id,
return sendMessage({
message: message,
text: text,
parse_mode: parseMode
});
return Promise.resolve(response);
}
export async function sendMessage(options: SendOptions): Promise<Message> {
const response = await bot.sendMessage({
chat_id: options.chat_id ?? options.message?.chat?.id,
chat_id: "message" in options ? options.message.chat.id : options.chat_id,
text: options.text,
parse_mode: options.parse_mode,
link_preview_options: {
is_disabled: options.disableLinkPreview
}
link_preview_options: options.link_preview_options,
reply_markup: options.reply_markup,
});
return Promise.resolve(response);
}
export async function replyToMessage(options: SendOptions): Promise<Message> {
const response = await bot.sendMessage({
chat_id: options.chat_id ?? options.message?.chat?.id,
text: options.text,
parse_mode: options.parse_mode,
reply_parameters: {
message_id: options.message_id || options.message?.message_id
},
link_preview_options: {
is_disabled: options.disableLinkPreview
}
});
await MessageStore.put(response);
return Promise.resolve(response);
}
export async function oldReplyToMessage(message: Message, text: string, parseMode?: ParseMode): Promise<Message> {
const response = await bot.sendMessage({
chat_id: message.chat.id,
return replyToMessage({
message: message,
text: text,
reply_parameters: {
message_id: message.message_id
},
parse_mode: parseMode,
parse_mode: parseMode
});
}
export async function replyToMessage(options: SendOptions): Promise<Message> {
if (!("message" in options) && !options.message_id) {
return Promise.reject("for reply there must be message or message_id");
}
const response = await bot.sendMessage({
chat_id: "message" in options ? options.message.chat.id : options.chat_id,
text: options.text,
parse_mode: options.parse_mode,
reply_parameters: {
message_id: "message" in options ? options.message.message_id : options.message_id
},
link_preview_options: options.link_preview_options
});
await MessageStore.put(response);
return Promise.resolve(response);
}
@@ -353,7 +382,7 @@ export function randomValue<T>(list: T[]): T {
return list[Math.floor(Math.random() * list.length)];
}
export function chatCommandToString(cmd: ChatCommand): string {
export function chatCommandToString(cmd: Command): string {
if (!cmd.title && !cmd.description) {
return "";
}
@@ -365,11 +394,13 @@ export function chatCommandToString(cmd: ChatCommand): string {
return `${cmd.title ? `${cmd.title}: ` : ""}${cmd.description ? `${cmd.description}` : ""}`;
}
export function fullName(from: User): string {
let fullName = from.first_name;
export function fullName(from: User | StoredUser): string {
const isStored = "isBot" in from;
if (from.last_name) {
fullName += " " + from.last_name;
let fullName = isStored ? from.firstName : from.first_name;
if (isStored ? from.lastName : from.last_name) {
fullName += " " + (isStored ? from.lastName : from.last_name);
}
return fullName;
@@ -425,14 +456,230 @@ export const delay = (ms: number, signal?: AbortSignal): Promise<void> =>
}
});
export function escapeMarkdownV2Text(s: string) {
s = s.replace(/^\*{3,}\s*$/gm, "— — —");
s = s.replace(/^\*\s+(?=\S)/gm, "• ");
s = s.replace(/\*\*(.+?)\*\*/g, "*$1*");
const MARKDOWN_V2_RESERVED_RE = /([\\_*\[\]()~`>#+\-=|{}.!])/g;
function escapePlainMarkdownV2(s: string): string {
return s.replace(MARKDOWN_V2_RESERVED_RE, "\\$1");
}
function escapeCodeMarkdownV2(s: string): string {
return s.replace(/[\\`]/g, "\\$&");
}
function escapeLinkUrlMarkdownV2(s: string): string {
return s.replace(/[\\)]/g, "\\$&");
}
function escapeMarkdownV2PreservingAllowedFormatting(s: string): string {
let result = "";
let i = 0;
while (i < s.length) {
// links: [text](url)
if (s[i] === "[") {
const linkMatch = s.slice(i).match(/^\[([^\]\n]+)]\(([^)\n]+)\)/);
if (linkMatch) {
const [, text, url] = linkMatch;
result += `[${escapePlainMarkdownV2(text)}](${escapeLinkUrlMarkdownV2(url)})`;
i += linkMatch[0].length;
continue;
}
}
// monospace: `text`
if (s[i] === "`") {
const end = s.indexOf("`", i + 1);
if (end !== -1) {
const content = s.slice(i + 1, end);
result += "`" + escapeCodeMarkdownV2(content) + "`";
i = end + 1;
continue;
}
}
// spoiler: ||text||
if (s.startsWith("||", i)) {
const end = s.indexOf("||", i + 2);
if (end !== -1) {
const content = s.slice(i + 2, end);
result += "||" + escapeMarkdownV2PreservingAllowedFormatting(content) + "||";
i = end + 2;
continue;
}
}
// underline: __text__
if (s.startsWith("__", i)) {
const end = s.indexOf("__", i + 2);
if (end !== -1) {
const content = s.slice(i + 2, end);
result += "__" + escapeMarkdownV2PreservingAllowedFormatting(content) + "__";
i = end + 2;
continue;
}
}
// bold: *text*
if (s[i] === "*") {
const end = s.indexOf("*", i + 1);
if (end !== -1) {
const content = s.slice(i + 1, end);
result += "*" + escapeMarkdownV2PreservingAllowedFormatting(content) + "*";
i = end + 1;
continue;
}
}
// italic: _text_
if (s[i] === "_") {
const end = s.indexOf("_", i + 1);
if (end !== -1) {
const content = s.slice(i + 1, end);
result += "_" + escapeMarkdownV2PreservingAllowedFormatting(content) + "_";
i = end + 1;
continue;
}
}
// strikethrough: ~text~
if (s[i] === "~") {
const end = s.indexOf("~", i + 1);
if (end !== -1) {
const content = s.slice(i + 1, end);
result += "~" + escapeMarkdownV2PreservingAllowedFormatting(content) + "~";
i = end + 1;
continue;
}
}
result += escapePlainMarkdownV2(s[i]);
i++;
}
return result;
}
function unescapeAccidentalMarkdownV2(s: string): string {
let prev: string;
do {
prev = s;
s = s.replace(/\\([_*\[\]()~`>#+\-=|{}.!\\])/g, "$1");
} while (s !== prev);
return s;
}
function escapeTelegramQuoteLine(line: string): string {
const content = line.replace(/^>\s*/, "");
if (!content.trim()) {
return ">";
}
return ">" + escapeMarkdownV2PreservingAllowedFormatting(content);
}
function normalizeTelegramQuoteLines(s: string): string {
return s
.split("\n")
.map(line => {
if (!line.startsWith(">")) return line;
return line.replace(/^>\s+/, ">");
})
.join("\n");
}
function looksLikeMarkdownTableRow(line: string): boolean {
const trimmed = line.trim();
if (trimmed.startsWith("||") && trimmed.endsWith("||")) {
return false;
}
const pipeCount = (trimmed.match(/\|/g) ?? []).length;
if (pipeCount < 2) {
return false;
}
return trimmed.startsWith("|") || trimmed.endsWith("|") || pipeCount >= 2;
}
function isMarkdownTableSeparator(line: string): boolean {
return /^\s*\|?\s*:?-{3,}:?\s*(\|\s*:?-{3,}:?\s*)+\|?\s*$/.test(line);
}
function normalizeMarkdownTables(s: string): string {
return s
.split("\n")
.filter(line => !isMarkdownTableSeparator(line))
.map(line => {
if (!looksLikeMarkdownTableRow(line)) {
return line;
}
return line
.replace(/^\s*\|/, "")
.replace(/\|\s*$/, "")
.split("|")
.map(cell => cell.trim())
.filter(Boolean)
.join(" — ");
})
.join("\n");
}
export function escapeMarkdownV2Text(s: string): string {
s = unescapeAccidentalMarkdownV2(s);
s = normalizeTelegramQuoteLines(s);
s = s.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
s = s.replace(/^\s*[-*_]{3,}\s*$/gm, "— — —");
s = s.replace(/^\s*[-*+]\s+(?=\S)/gm, "• ");
s = s.replace(/\*\*(.+?)\*\*/gs, "*$1*");
s = s.replace(/~~(.+?)~~/gs, "~$1~");
s = s.replace(/^#{1,6}\s+/gm, "");
s = s.replace(/```[a-zA-Z0-9_-]*\n?([\s\S]*?)```/g, (_, code) => {
return code.trim();
});
s = s.replace(/!\[([^\]]*)]\(([^)]+)\)/g, (_, alt, url) => {
return alt ? `${alt}: ${url}` : url;
});
s = normalizeMarkdownTables(s);
s = s
.split("\n")
.map(line => {
if (line.startsWith(">")) {
return escapeTelegramQuoteLine(line);
}
if (line === ">") {
return ">";
}
return escapeMarkdownV2PreservingAllowedFormatting(line);
})
.join("\n");
s = s.replace(/\n{3,}/g, "\n\n");
return s.trim();
}
export async function getFileUrl(fileId: string): Promise<string> {
const file = await bot.getFile({file_id: fileId});
return `https://api.telegram.org/file/bot${bot.botToken}/${file.file_path}`;
@@ -463,25 +710,35 @@ export async function getUserAvatar(userId: number): Promise<Buffer | null> {
}
export function extractTextMessage(msg: Message | StoredMessage | string): string | null {
const text = (typeof msg === "string" ? msg : isStoredMessage(msg) ? msg.text : msg?.text ?? msg?.caption ?? "").trim();
if (!msg) return null;
if (typeof msg === "string") return msg;
const text = (isStoredMessage(msg) ? msg.text : msg.text || msg.caption || "").trim();
if (text.length === 0) return null;
return text;
}
export function cutPrefixes(msg: Message | StoredMessage | string): string {
const prefixes = [
Environment.BOT_PREFIX,
`/ollamathink@${botUser.username}`,
"/ollamathink",
`/ollama@${botUser.username}`,
"/ollama",
`/gemini@${botUser.username}`,
"/gemini",
`/mistral@${botUser.username}`,
"/mistral",
];
const chatCommands = commands.filter(c => c instanceof ChatCommand);
const prefixes = [Environment.BOT_PREFIX];
const pushPrefix = (c: string) => {
prefixes.push(`/${c}@${botUser.username}`);
prefixes.push(`/${c}`);
};
chatCommands.forEach((cmd) => {
const command = cmd.command;
if (Array.isArray(command)) {
command.forEach(pushPrefix);
} else {
pushPrefix(command);
}
});
const text = extractTextMessage(msg);
if (!text || !text.length) return "";
let newText = text;
for (const prefix of prefixes) {
@@ -516,12 +773,7 @@ export async function loadImagesIfExists(msg: Message | StoredMessage): Promise<
const maxSize = await mapPhotoSizeToMax(getPhotoMaxSize(msg.photo));
if (maxSize) {
const imagePath = path.join(Environment.DATA_PATH, "photo");
if (!fs.existsSync(imagePath)) {
fs.mkdirSync(imagePath);
}
let imageFilePath = path.join(imagePath, maxSize.unique_file_id + ".jpg");
let imageFilePath = path.join(photoDir, maxSize.unique_file_id + ".jpg");
if (!fs.existsSync(imageFilePath)) {
const res = await axios.get<ArrayBuffer>(maxSize.url, {responseType: "arraybuffer"});
const src = Buffer.from(res.data);
@@ -545,11 +797,6 @@ export async function loadImagesIfExists(msg: Message | StoredMessage): Promise<
export async function loadImagesFromFileIds(sizes: PhotoSize[]): Promise<string[] | null> {
if (!sizes?.length) return null;
const dataPath = path.join(Environment.DATA_PATH, "photo");
if (!fs.existsSync(dataPath)) {
fs.mkdirSync(dataPath);
}
const existing =
sizes.filter(s => fs.existsSync(photoPathByUniqueId(s.file_unique_id)))
.map(s => s.file_unique_id);
@@ -567,7 +814,7 @@ export async function loadImagesFromFileIds(sizes: PhotoSize[]): Promise<string[
const paths = responses.map((res, index) => {
try {
const uniqueFileId = maxSizes[index].unique_file_id;
const imageFilePath = path.join(dataPath, uniqueFileId + ".jpg");
const imageFilePath = path.join(photoDir, uniqueFileId + ".jpg");
const src = Buffer.from(res.data);
fs.writeFileSync(imageFilePath, src);
return uniqueFileId;
@@ -974,13 +1221,11 @@ export function getPhotoMaxSize(photos: PhotoSize[], target: number = Environmen
return photos[0];
}
const max = photos.reduce((prev, cur) => {
return photos.reduce((prev, cur) => {
if (!prev) return cur;
return cur.width * cur.height > prev.width * prev.height ? cur : prev;
}, null);
return max;
}
export async function mapPhotoSizeToMax(size: PhotoSize): Promise<PhotoMaxSize | null> {
@@ -1024,8 +1269,93 @@ export function boolToEmoji(bool: boolean): string {
export const albumCache = new Map<string, { messages: Message[], timer: NodeJS.Timeout }>();
export async function processNewMessage(msg: Message) {
console.log("message", msg);
async function processAlbum(groupId: string): Promise<string[]> {
const entry = albumCache.get(groupId);
if (!entry) return;
const allPhotos = entry.messages
.filter(m => m.photo)
.map(m => m.photo);
const allPhotoMaxSizes = await Promise.all(allPhotos.map(photo => getPhotoMaxSize(photo)));
const ids = await loadImagesFromFileIds(allPhotoMaxSizes);
console.log(`Received album ${groupId} with ${ids.length} photos.`);
console.log("File IDs:", ids);
albumCache.delete(groupId);
return ids;
}
export function photoPathByUniqueId(uniqueId: string): string {
return path.join(photoDir, uniqueId + ".jpg");
}
export function getCurrentModel(): string {
switch (Environment.DEFAULT_AI_PROVIDER) {
case AiProvider.OLLAMA:
return Environment.OLLAMA_MODEL;
case AiProvider.GEMINI:
return Environment.GEMINI_MODEL;
case AiProvider.MISTRAL:
return Environment.MISTRAL_MODEL;
case AiProvider.OPENAI:
return Environment.OPENAI_MODEL;
}
}
export async function getCurrentModelCapabilities(): Promise<AiModelCapabilities | null> {
let promise: Promise<AiModelCapabilities | null> = null;
switch (Environment.DEFAULT_AI_PROVIDER) {
case AiProvider.OLLAMA: {
const ollamaGetModel = commands.find(c => c instanceof OllamaGetModel);
// eslint-disable-next-line no-async-promise-executor
promise = new Promise(async (resolve, reject) => {
try {
const result = {
vision: (await ollamaGetModel.loadImageModelInfo()).vision,
ocr: null,
thinking: (await ollamaGetModel.loadThinkModelInfo()).thinking,
tools: (await ollamaGetModel.getModelCapabilities()).tools
};
resolve(result);
} catch (e) {
reject(e);
}
});
break;
}
case AiProvider.GEMINI: {
promise = commands.find(c => c instanceof GeminiGetModel).getModelCapabilities();
break;
}
case AiProvider.MISTRAL: {
promise = commands.find(c => c instanceof MistralGetModel).getModelCapabilities();
break;
}
case AiProvider.OPENAI: {
promise = commands.find(c => c instanceof OpenAIGetModel).getModelCapabilities();
break;
}
}
if (!promise) return null;
try {
return await promise;
} catch (e) {
logError(e);
return null;
}
}
export async function processMyChatMember(u: ChatMemberUpdated): Promise<void> {
console.log("my_chat_member", u);
}
export async function processNewMessage(msg: Message): Promise<void> {
console.log("New Message", msg);
let storedMsg: StoredMessage | null = null;
@@ -1044,7 +1374,7 @@ export async function processNewMessage(msg: Message) {
logError(e);
}
if ((msg.new_chat_members?.length || 0 > 0)) {
if ((msg.new_chat_members?.length)) {
await bot.sendMessage({chat_id: msg.chat.id, text: randomValue(Environment.ANSWERS.invite)}).catch(logError);
return;
}
@@ -1084,7 +1414,7 @@ export async function processNewMessage(msg: Message) {
const then = Date.now();
const cmd = searchChatCommand(chatCommands, cmdText);
const cmd = searchChatCommand(commands, cmdText);
const executed = await executeChatCommand(cmd, msg, cmdText);
const now = Date.now();
@@ -1105,54 +1435,212 @@ export async function processNewMessage(msg: Message) {
}
const textToCheck = startsWithPrefix ? messageWithoutPrefix : cmdText;
if (Environment.PROCESS_LINKS && await processYouTubeLink(msg, getFirstLink(msg))) return;
if (msg.chat.type !== "private" && (!msg.reply_to_message || msg.reply_to_message.from.id !== botUser.id) && !startsWithPrefix) return;
if (msg.chat.type === "private" && !Environment.ADMIN_IDS.has(msg.chat.id)) return;
switch (Environment.DEFAULT_AI_PROVIDER) {
case AiProvider.OLLAMA: {
await commands.find(e => e instanceof OllamaChat).executeOllama(msg, textToCheck);
break;
}
case AiProvider.GEMINI: {
await commands.find(e => e instanceof GeminiChat).executeGemini(msg, textToCheck);
break;
}
case AiProvider.MISTRAL: {
await commands.find(e => e instanceof MistralChat).executeMistral(msg, textToCheck);
break;
}
case AiProvider.OPENAI: {
await commands.find(e => e instanceof OpenAIChat).executeOpenAI(msg, textToCheck);
break;
}
}
}
function getFirstLink(msg: Message): string | null {
if (msg.entities) {
const urlEntities = msg.entities.filter(e => e.type === "url");
if (urlEntities.length) {
for (const e of urlEntities) {
const url = msg.text.substring(e.offset, e.offset + e.length);
// TODO: 31/01/2026, Danil Nikolaev: implement proper checking
try {
getYouTubeVideoId(url);
const yt = chatCommands.find(e => e instanceof YouTubeDownload);
if (await checkRequirements(yt, msg)) {
await yt.downloadYouTubeVideo(msg, url);
}
return;
} catch (e) {
logError(e);
}
}
const e = urlEntities[0];
return msg.text.substring(e.offset, e.offset + e.length);
}
}
if (!startsWithPrefix && msg.chat.type !== "private") return;
if (msg.chat.type === "private" && !Environment.ADMIN_IDS.has(msg.chat.id)) return;
return null;
}
const chat = chatCommands.find(e => e instanceof OllamaChat);
if (await checkRequirements(chat, msg)) {
await chat.executeOllama(msg, textToCheck);
export async function processYouTubeLink(msg: Message, url?: string, id?: string): Promise<boolean> {
if (!url && !id) return false;
let waitMessage: Message | null = msg.from.id === botUser.id ? msg : null;
let videoId: string | null = null;
try {
try {
videoId = id || getYouTubeVideoId(url);
} catch (e) {
logError(e);
return false;
}
const yt = commands.find(e => e instanceof YouTubeDownload);
if (await checkRequirements(yt, msg)) {
if (!waitMessage) {
waitMessage = await replyToMessage({
message: msg,
text: "⏳ Ищу информацию о видео..."
});
} else {
await editMessageText({message: msg, text: "⏳ Ищу информацию о видео..."});
}
let videoInfo: VideoInfo | null = null;
let ytError: string = null;
try {
videoInfo = await getYouTubeVideoInfo(videoId);
} catch (e) {
logError(e);
if ("version" in e) {
ytError = e.message;
}
}
console.log("VIDEO_INFO", videoInfo);
let text: string = null;
const inCache = isVideoExists({videoId: videoId});
const duration = videoInfo?.basic_info?.duration || null;
const canDownload = inCache || duration && duration <= 300;
if (videoInfo) {
text = "Видео с YouTube\n\n" +
`Название: ${videoInfo.basic_info?.title}\n` +
`Автор: ${videoInfo.secondary_info?.owner?.author?.name}\n` +
`Длительность: ${duration} сек.`;
if (!canDownload) {
text += `\n\nВидео слишком длинное (${duration} сек. > 300 сек.)`;
}
} else if (!ytError) {
text = "Информация о видео не найдена";
}
const errorButInCache = !videoInfo && ytError && inCache;
if (errorButInCache) {
text = "Я не смог получить информацию о видео, но нашёл его в кэше.";
}
if (!text && ytError) {
await editMessageText({
message: waitMessage,
text: Environment.errorText,
reply_markup: {
inline_keyboard: [[
TryAgain.withData("/ytinfo " + videoId).asButton()
]]
}
});
} else {
await editMessageText({
message: waitMessage,
text: text,
reply_markup: canDownload ? {
inline_keyboard: [[
DownloadYtVideo.withData(inCache, "/ytdl " + videoId).asButton()
]]
} : {inline_keyboard: []}
});
}
}
return true;
} catch (e) {
logError(e);
await editMessageText({
message: waitMessage,
text: Environment.errorText,
reply_markup: {
inline_keyboard: [[
TryAgain.withData("/ytinfo " + videoId).asButton()
]]
}
});
}
return false;
}
export async function processEditedMessage(msg: Message): Promise<void> {
console.log("Edited Message", msg);
await UserStore.put(msg.from);
if (!extractTextMessage(msg) || msg.from.id === botUser.id) return;
await MessageStore.put(msg);
}
export async function processInlineQuery(query: InlineQuery): Promise<void> {
console.log("InlineQuery", query);
if (Environment.CREATOR_ID !== query.from.id) {
await bot.answerInlineQuery({
inline_query_id: query.id,
results: [],
button: {
text: "No access",
start_parameter: "nope"
}
}).catch(logError);
return;
}
if (query.query.trim().length !== 0) {
try {
const queryResults: InlineQueryResult[] = [];
const results = await ollama.webSearch({query: query.query});
console.log("results", results);
results.results.forEach((result, i) => {
const r = result as WebSearchResponse;
queryResults.push({
type: "article",
id: `${i}`,
title: `${r.title}`,
input_message_content: {
message_text: `${r.title}\n\n${r.url}`
}
});
});
await bot.answerInlineQuery({
inline_query_id: query.id,
results: queryResults,
});
} catch (e) {
logError(e);
}
} else {
await bot.answerInlineQuery({
inline_query_id: query.id,
results: [],
}).catch(logError);
}
}
async function processAlbum(groupId: string): Promise<string[]> {
const entry = albumCache.get(groupId);
if (!entry) return;
const allPhotos = entry.messages
.filter(m => m.photo)
.map(m => m.photo);
const allPhotoMaxSizes = await Promise.all(allPhotos.map(photo => getPhotoMaxSize(photo)));
const ids = await loadImagesFromFileIds(allPhotoMaxSizes);
console.log(`Received album ${groupId} with ${ids.length} photos.`);
console.log("File IDs:", ids);
albumCache.delete(groupId);
return ids;
}
export function photoPathByUniqueId(uniqueId: string): string {
return path.join(Environment.DATA_PATH, "photo", uniqueId + ".jpg");
export async function processCallbackQuery(query: CallbackQuery): Promise<void> {
console.log("CallbackQuery", query);
await findAndExecuteCallbackCommand(callbackCommands, query);
}
+107 -31
View File
@@ -1,16 +1,62 @@
import Innertube, {Platform, Types, Utils} from "youtubei.js";
import fs, {createWriteStream} from "node:fs";
import fs from "node:fs";
import path from "node:path";
import {Environment} from "../common/environment";
import {videoDir, videoTempDir} from "../index";
import ffmpeg from "fluent-ffmpeg";
import Innertube, {Platform, Types} from "youtubei.js";
import {Readable} from "node:stream";
import {logError} from "./utils";
import {performFFmpeg} from "./ffmpeg";
import VideoInfo from "youtubei.js/dist/src/parser/youtube/VideoInfo";
let innertube: Innertube | null = null;
export async function getYT(): Promise<Innertube> {
if (innertube) {
return innertube;
} else {
innertube = await Innertube.create({
generate_session_locally: true,
retrieve_player: true
});
return innertube;
}
}
export function getYouTubeVideoId(url: string): string {
const regex = /(?:youtube\.com\/(?:[^\/]+\/.+\/|(?:v|e(?:mbed)?|shorts)\/|.*[?&]v=)|youtu\.be\/)([^"&?\/\s]{11})/i;
const regex = /(?:(?:youtube\.com|music\.youtube\.com)\/(?:[^\/]+\/.+\/|(?:v|e(?:mbed)?|shorts|clip)\/|.*[?&]v=)|youtu\.be\/)([^"&?/\s]{11})/i;
const match = url.match(regex);
if (!match || !match[1]) throw new Error("Invalid YouTube or Shorts URL");
return match[1];
}
export async function downloadVideoFromYouTube(url: string, targetQuality: string = "720p"): Promise<{
export async function getYouTubeVideoInfo(videoId: string): Promise<VideoInfo> {
try {
return (await getYT()).getInfo(videoId, {client: "ANDROID"});
} catch (e) {
logError(e);
}
}
export function isVideoExists(options: DownloadOptions): boolean {
const videoId = "videoId" in options ? options.videoId : getYouTubeVideoId(options.url);
const filePath = path.join(videoDir, `${videoId}.mp4`);
return fs.existsSync(filePath);
}
export function getVideoFromCache(videoId: string): Buffer | null {
if (!isVideoExists({videoId: videoId})) return null;
const filePath = path.join(videoDir, `${videoId}.mp4`);
return Buffer.from(fs.readFileSync(filePath));
}
export type DownloadOptions = {
url: string
} | {
videoId: string;
}
export async function downloadVideoFromYouTube(options: DownloadOptions): Promise<{
time: number,
exists?: boolean,
buffer: Buffer | null
@@ -19,13 +65,8 @@ export async function downloadVideoFromYouTube(url: string, targetQuality: strin
let buffer: Buffer | null = null;
try {
const videoId = getYouTubeVideoId(url);
const videoFolder = path.join(Environment.DATA_PATH, "video");
if (!fs.existsSync(videoFolder)) {
fs.mkdirSync(videoFolder);
}
const filePath = path.join(videoFolder, `${videoId}.mp4`);
const videoId = "videoId" in options ? options.videoId : getYouTubeVideoId(options.url);
const filePath = path.join(videoDir, `${videoId}.mp4`);
if (fs.existsSync(filePath)) {
const buffer = Buffer.from(fs.readFileSync(filePath));
return {
@@ -43,39 +84,74 @@ export async function downloadVideoFromYouTube(url: string, targetQuality: strin
const code = `${data.output}\nreturn { ${properties.join(", ")} }`;
return new Function(code)();
};
const yt = await Innertube.create({
generate_session_locally: true,
retrieve_player: true
});
const info = await yt.getInfo(videoId);
const yt = await getYT();
const videoInfo = await yt.getInfo(videoId, {client: "ANDROID"});
console.log("Video info", videoInfo);
console.log(`Fetching metadata for: ${videoId}...`);
const format = info.streaming_data?.formats.find(f => f.quality_label === targetQuality)
|| info.streaming_data?.adaptive_formats.find(f => f.quality_label === targetQuality);
const targetQuality = "360p";
if (!format) {
const videoFormat = videoInfo.streaming_data?.formats.find(f => f.quality_label.startsWith(targetQuality))
|| videoInfo.streaming_data?.adaptive_formats.find(f => f.quality_label.startsWith(targetQuality));
const audioFormat = videoInfo.chooseFormat({type: "audio", quality: "best", language: "original"});
console.log("Video format: ", videoFormat);
console.log("Audio Format: ", audioFormat);
if (!videoFormat) {
console.log(`Quality ${targetQuality} not found. Falling back to best available.`);
}
const stream = await yt.download(videoId, {
type: "video+audio",
quality: "best",
format: "mp4"
const videoWebStream = await videoInfo.download({
itag: videoFormat.itag,
client: "ANDROID"
});
const file = createWriteStream(filePath);
const audioWebStream = await videoInfo.download({
itag: audioFormat.itag,
client: "ANDROID"
});
console.log("Downloading...");
const videoStream = Readable.fromWeb(videoWebStream as any);
const audioStream = Readable.fromWeb(audioWebStream as any);
for await (const chunk of Utils.streamToIterable(stream)) {
file.write(chunk);
}
const videoPath = path.join(videoTempDir, `temp_video_${videoId}.mp4`);
const audioPath = path.join(videoTempDir, `temp_audio_${videoId}.mp4`);
file.end();
const writeStream = (stream: any, path: string) =>
new Promise((resolve, reject) => {
const file = fs.createWriteStream(path);
stream.pipe(file);
file.on("finish", resolve);
file.on("error", reject);
});
await Promise.all([
writeStream(videoStream, videoPath),
writeStream(audioStream, audioPath)
]);
await performFFmpeg(() =>
ffmpeg()
.input(videoPath)
.input(audioPath)
.videoCodec("copy")
.audioCodec("copy")
.save(filePath)
.on("progress", (progress) => {
console.log("progress", progress);
})
).catch(logError);
fs.unlinkSync(videoPath);
fs.unlinkSync(audioPath);
buffer = fs.readFileSync(filePath);
console.log(`✅ Saved to ${videoId}.mp4`);
} catch (error) {
console.error("❌ Download failed:", error instanceof Error ? error.message : error);
@@ -84,7 +160,7 @@ export async function downloadVideoFromYouTube(url: string, targetQuality: strin
const end = Date.now();
const diff = end - start;
console.log(`Video downloaded. URL: ${url}\ntook ${diff}ms`);
console.log(`Video downloaded.\ntook ${diff}ms`);
return {
time: diff,