├── .dockerignore ├── .example.env ├── .gitignore ├── .husky └── pre-commit ├── .oxlintignore ├── .prettierrc.json ├── Dockerfile ├── LICENSE ├── README.md ├── bun.lock ├── changelog.md ├── ecosystem.config.json ├── eslint.config.js ├── package.json ├── src ├── config.ts ├── controllers │ ├── health │ │ └── index.ts │ ├── sharing │ │ └── index.ts │ └── summarize │ │ └── index.ts ├── errors.ts ├── index.ts ├── logging.ts ├── models │ ├── health.model.ts │ ├── sharing.model.ts │ └── summarize.model.ts ├── schemas │ └── config.ts └── types │ └── global.d.ts └── tsconfig.json /.dockerignore: -------------------------------------------------------------------------------- 1 | .vscode 2 | .git 3 | .gitignore 4 | .husky 5 | *.env 6 | 7 | logs/* 8 | tests/* 9 | 10 | Dockerfile 11 | docker-compose.yml 12 | 13 | ecosystem.config.json -------------------------------------------------------------------------------- /.example.env: -------------------------------------------------------------------------------- 1 | SERVICE_PORT=3312 2 | USE_WORKER=false 3 | LOG_TO_FILE=false 4 | API_TOKEN="" # For get sharing url 5 | # SESSION_ID_COOKIE="XXXX" # If lib YaHMAC is invalid you can set your cookies and summarize articles/text (video requires valid YaHMAC) -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .vscode 2 | .env 3 | 4 | # dependencies 5 | /node_modules 6 | 7 | # local env files 8 | .env.local 9 | .env.development.local 10 | .env.test.local 11 | .env.production.local 12 | 13 | **/*.log 14 | **/*.bun -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | 2 | bunx pretty-quick --staged -------------------------------------------------------------------------------- /.oxlintignore: -------------------------------------------------------------------------------- 1 | **/*.d.ts 2 | ecosystem.config.js 3 | eslint.config.js -------------------------------------------------------------------------------- /.prettierrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "printWidth": 100, 3 | "tabWidth": 2, 4 | "semi": true, 5 | "trailingComma": "all" 6 | } 7 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM oven/bun:latest AS base 2 | WORKDIR /usr/src/app 3 | 4 | FROM base AS release 5 | COPY package.json bun.lock tsconfig.json ./ 6 | COPY src src 7 | RUN bun install 8 | 9 | ENV SERVICE_PORT=3312 10 | ENV LOG_TO_FILE=false 11 | # ENV USE_WORKER="true" 12 | # ENV WORKER_HOST="http://127.0.0.1:7674/browser" 13 | # ENV WORKER_HOST_TH="http://127.0.0.1:7674/th" 14 | # ENV API_TOKEN="" 15 | 16 | ENTRYPOINT [ "bun", "run", "start" ] -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 FOSWLY 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Summarize Backend 2 | 3 | [![GitHub Stars](https://img.shields.io/github/stars/FOSWLY/summarize-backend?logo=github&style=for-the-badge)](https://github.com/FOSWLY/summarize-backend/stargazers) 4 | [![GitHub Issues](https://img.shields.io/github/issues/FOSWLY/summarize-backend?style=for-the-badge)](https://github.com/FOSWLY/summarize-backend/issues) 5 | [![Current Version](https://img.shields.io/github/v/release/FOSWLY/summarize-backend?style=for-the-badge)](https://github.com/FOSWLY/summarize-backend) 6 | [![GitHub License](https://img.shields.io/github/license/FOSWLY/summarize-backend?style=for-the-badge)](https://github.com/FOSWLY/summarize-backend/blob/master/LICENSE) 7 | 8 | **Summarize Backend** - cервер, предоставляющий унифицированные конечные точки для API суммаризации из библиотеки [@toil/neurojs](https://github.com/FOSWLY/neurojs). 9 | 10 | ## 📝 Функционал 11 | 12 | - Суммаризация статей 13 | - Суммаризация текста 14 | - Суммаризация видео 15 | - Получение ссылки на суммаризацию статей (необходимо указать токен к оф. апи) 16 | - Получение суммаризации по токену (`https://300.ya.ru/TOKEN`) 17 | 18 | ## 📦 Деплой 19 | 20 | ### С Docker 21 | 22 | 1. Установите Docker 23 | 2. Соберите образ 24 | 25 | ```bash 26 | docker build -t "summarize-backend" . 27 | ``` 28 | 29 | 3. Запустите контейнер 30 | 31 | ```bash 32 | docker run -p 3312:3312 summarize-backend 33 | ``` 34 | 35 | ### Вручную 36 | 37 | 1. Установите [Bun](https://bun.sh/) 38 | 2. Клонируйте репозиторий: 39 | 40 | ```bash 41 | git clone https://github.com/FOSWLY/summarize-backend 42 | ``` 43 | 44 | 3. Установите зависимости 45 | 46 | ```bash 47 | bun install 48 | ``` 49 | 50 | 3.1. (опционально) Переименуйте `.example.env` в `.env` и заполните необходимые поля 51 | 52 | 4. Запустите сервер 53 | 54 | ```bash 55 | bun start 56 | ``` 57 | 58 | Если вы хотите использовать PM2: 59 | 60 | 1. Установите зависимости: 61 | 62 | ```bash 63 | bun install -g pm2-beta && pm2 install pm2-logrotate 64 | ``` 65 | 66 | 2. Запустите сервер 67 | 68 | ```bash 69 | pm2 start ecosystem.config.json 70 | ``` 71 | 72 | ## 📖 Кому это будет полезно 73 | 74 | 1. Если вы хотите использовать логику из [neurojs](https://github.com/FOSWLY/neurojs) с помощью другого языка программирования, но не хотите переносить весь функционал в ваш код 75 | 2. Если вы не хотите тянуть зависимости от neurojs 76 | 3. Если вы хотите иметь простой унифицированный апи 77 | -------------------------------------------------------------------------------- /bun.lock: -------------------------------------------------------------------------------- 1 | { 2 | "lockfileVersion": 1, 3 | "workspaces": { 4 | "": { 5 | "name": "summarize-backend", 6 | "dependencies": { 7 | "@elysiajs/swagger": "^1.2.0", 8 | "@toil/neurojs": "^1.1.2", 9 | "elysia": "1.2.6", 10 | "elysia-http-status-code": "^1.0.9", 11 | "pino": "^9.5.0", 12 | "pino-loki": "^2.4.0", 13 | }, 14 | "devDependencies": { 15 | "@elysiajs/cors": "^1.2.0", 16 | "@sinclair/typebox": "^0.34.13", 17 | "bun-types": "^1.1.41", 18 | "eslint": "^9.17.0", 19 | "eslint-plugin-oxlint": "^0.15.10", 20 | "husky": "^9.1.7", 21 | "oxlint": "^0.15.10", 22 | "pino-pretty": "^13.0.0", 23 | "typescript-eslint": "^8.18.1", 24 | }, 25 | "peerDependencies": { 26 | "typescript": "^5.6.3", 27 | }, 28 | }, 29 | }, 30 | "packages": { 31 | "@bufbuild/protobuf": ["@bufbuild/protobuf@2.2.3", "", {}, "sha512-tFQoXHJdkEOSwj5tRIZSPNUuXK3RaR7T1nUrPgbYX1pUbvqqaaZAsfo+NXBPsz5rZMSKVFrgK1WL8Q/MSLvprg=="], 32 | 33 | "@elysiajs/cors": ["@elysiajs/cors@1.2.0", "", { "peerDependencies": { "elysia": ">= 1.2.0" } }, "sha512-qsJwDAg6WfdQRMfj6uSMcDPSpXvm/zQFeAX1uuJXhIgazH8itSfcDxcH9pMuXVRX1yQNi2pPwNQLJmAcw5mzvw=="], 34 | 35 | "@elysiajs/swagger": ["@elysiajs/swagger@1.2.0", "", { "dependencies": { "@scalar/themes": "^0.9.52", "@scalar/types": "^0.0.12", "openapi-types": "^12.1.3", "pathe": "^1.1.2" }, "peerDependencies": { "elysia": ">= 1.2.0" } }, "sha512-OPx93DP6rM2VHjA3D44Xiz5MYm9AYlO2NGWPsnSsdyvaOCiL9wJj529583h7arX4iIEYE5LiLB0/A45unqbopw=="], 36 | 37 | "@eslint-community/eslint-utils": ["@eslint-community/eslint-utils@4.4.1", "", { "dependencies": { "eslint-visitor-keys": "^3.4.3" }, "peerDependencies": { "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } }, "sha512-s3O3waFUrMV8P/XaF/+ZTp1X9XBZW1a4B97ZnjQF2KYWaFD2A8KyFBsrsfSjEmjn3RGWAIuvlneuZm3CUK3jbA=="], 38 | 39 | "@eslint-community/regexpp": ["@eslint-community/regexpp@4.12.1", "", {}, "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ=="], 40 | 41 | "@eslint/config-array": ["@eslint/config-array@0.19.2", "", { "dependencies": { "@eslint/object-schema": "^2.1.6", "debug": "^4.3.1", "minimatch": "^3.1.2" } }, "sha512-GNKqxfHG2ySmJOBSHg7LxeUx4xpuCoFjacmlCoYWEbaPXLwvfIjixRI12xCQZeULksQb23uiA8F40w5TojpV7w=="], 42 | 43 | "@eslint/core": ["@eslint/core@0.11.0", "", { "dependencies": { "@types/json-schema": "^7.0.15" } }, "sha512-DWUB2pksgNEb6Bz2fggIy1wh6fGgZP4Xyy/Mt0QZPiloKKXerbqq9D3SBQTlCRYOrcRPu4vuz+CGjwdfqxnoWA=="], 44 | 45 | "@eslint/eslintrc": ["@eslint/eslintrc@3.2.0", "", { "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.0", "minimatch": "^3.1.2", "strip-json-comments": "^3.1.1" } }, "sha512-grOjVNN8P3hjJn/eIETF1wwd12DdnwFDoyceUJLYYdkpbwq3nLi+4fqrTAONx7XDALqlL220wC/RHSC/QTI/0w=="], 46 | 47 | "@eslint/js": ["@eslint/js@9.20.0", "", {}, "sha512-iZA07H9io9Wn836aVTytRaNqh00Sad+EamwOVJT12GTLw1VGMFV/4JaME+JjLtr9fiGaoWgYnS54wrfWsSs4oQ=="], 48 | 49 | "@eslint/object-schema": ["@eslint/object-schema@2.1.6", "", {}, "sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA=="], 50 | 51 | "@eslint/plugin-kit": ["@eslint/plugin-kit@0.2.5", "", { "dependencies": { "@eslint/core": "^0.10.0", "levn": "^0.4.1" } }, "sha512-lB05FkqEdUg2AA0xEbUz0SnkXT1LcCTa438W4IWTUh4hdOnVbQyOJ81OrDXsJk/LSiJHubgGEFoR5EHq1NsH1A=="], 52 | 53 | "@humanfs/core": ["@humanfs/core@0.19.1", "", {}, "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA=="], 54 | 55 | "@humanfs/node": ["@humanfs/node@0.16.6", "", { "dependencies": { "@humanfs/core": "^0.19.1", "@humanwhocodes/retry": "^0.3.0" } }, "sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw=="], 56 | 57 | "@humanwhocodes/module-importer": ["@humanwhocodes/module-importer@1.0.1", "", {}, "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA=="], 58 | 59 | "@humanwhocodes/retry": ["@humanwhocodes/retry@0.4.1", "", {}, "sha512-c7hNEllBlenFTHBky65mhq8WD2kbN9Q6gk0bTk8lSBvc554jpXSkST1iePudpt7+A/AQvuHs9EMqjHDXMY1lrA=="], 60 | 61 | "@nodelib/fs.scandir": ["@nodelib/fs.scandir@2.1.5", "", { "dependencies": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" } }, "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g=="], 62 | 63 | "@nodelib/fs.stat": ["@nodelib/fs.stat@2.0.5", "", {}, "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A=="], 64 | 65 | "@nodelib/fs.walk": ["@nodelib/fs.walk@1.2.8", "", { "dependencies": { "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" } }, "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg=="], 66 | 67 | "@oxlint/darwin-arm64": ["@oxlint/darwin-arm64@0.15.11", "", { "os": "darwin", "cpu": "arm64" }, "sha512-cSW5LCqoHAp+zvKNUmzvKXzvh90o0J50HOJj7HARXWes/fqKQ2U2NX36Grc19lOxhP5ItoNeZN6x88opPdVtDw=="], 68 | 69 | "@oxlint/darwin-x64": ["@oxlint/darwin-x64@0.15.11", "", { "os": "darwin", "cpu": "x64" }, "sha512-6iisoeMdIGBvga+dKe6UnAH8jN58lkbwApQh0IAJzSpkS9B0MPFFy2LjT9qq6J4WyHWh8oYnDJhNOJVBGynApQ=="], 70 | 71 | "@oxlint/linux-arm64-gnu": ["@oxlint/linux-arm64-gnu@0.15.11", "", { "os": "linux", "cpu": "arm64" }, "sha512-3zmkAYm309ZWf0Af3YiQMbx2kV8SKRThyaw32x65NvZje/RfnqDSaUJ/juT32DyWNGgRSI2KaWExbbVKZGj6Bw=="], 72 | 73 | "@oxlint/linux-arm64-musl": ["@oxlint/linux-arm64-musl@0.15.11", "", { "os": "linux", "cpu": "arm64" }, "sha512-kj6t4GxNfYvSkC9HbdnQFyK1AXXmWN+d53lyDVWUKByRNAOLn6hBrzl9WByJ6ZGCTwTOyrkqu1Om4itlILqodA=="], 74 | 75 | "@oxlint/linux-x64-gnu": ["@oxlint/linux-x64-gnu@0.15.11", "", { "os": "linux", "cpu": "x64" }, "sha512-1RNUw+nWjv8EXI1wa6A4oc/UXwdCk4l29y3JgCZ7s1aPdZhn3sWLng0SFVruZAf5QFY9bxKS2ffr1s84T1uXhQ=="], 76 | 77 | "@oxlint/linux-x64-musl": ["@oxlint/linux-x64-musl@0.15.11", "", { "os": "linux", "cpu": "x64" }, "sha512-7uUD13t5WUg7TrZlViW0oYwg2npwoFvzA+1wOPtDu9Kyy24WggUIg8dAExTb5OFkj5jxKKAT17EcvtSNxxLdww=="], 78 | 79 | "@oxlint/win32-arm64": ["@oxlint/win32-arm64@0.15.11", "", { "os": "win32", "cpu": "arm64" }, "sha512-6tMc5UYWGwzxa+AsgNQGFktoqewkdV5pmMXlQboGIOUWYYIQfl2/X7owbv+3y3n7EmO7EBniIB2G/5m8teDzGQ=="], 80 | 81 | "@oxlint/win32-x64": ["@oxlint/win32-x64@0.15.11", "", { "os": "win32", "cpu": "x64" }, "sha512-etEXnRNT3Lep/jAvBxgFqHGGAZTnjvRNKSOKSQ0jFNTIzAhaqCpJrH25LKuvIqDPTDOPNA5DjmfuT2AFNhAI0g=="], 82 | 83 | "@scalar/openapi-types": ["@scalar/openapi-types@0.1.1", "", {}, "sha512-NMy3QNk6ytcCoPUGJH0t4NNr36OWXgZhA3ormr3TvhX1NDgoF95wFyodGVH8xiHeUyn2/FxtETm8UBLbB5xEmg=="], 84 | 85 | "@scalar/themes": ["@scalar/themes@0.9.66", "", { "dependencies": { "@scalar/types": "0.0.32" } }, "sha512-Fm2dUlIQoWCG83yZ2QNdIG7j+3eHgmSQHSnGOfd59+XIC/JxmCVbiOCYyhzfCXl1Zb8YcPlu6Ka2wY++GlrEeQ=="], 86 | 87 | "@scalar/types": ["@scalar/types@0.0.12", "", { "dependencies": { "@scalar/openapi-types": "0.1.1", "@unhead/schema": "^1.9.5" } }, "sha512-XYZ36lSEx87i4gDqopQlGCOkdIITHHEvgkuJFrXFATQs9zHARop0PN0g4RZYWj+ZpCUclOcaOjbCt8JGe22mnQ=="], 88 | 89 | "@sinclair/typebox": ["@sinclair/typebox@0.34.25", "", {}, "sha512-gu+tdy9WZIRulrR4CAcGXZAAixwakKszkUXudMJ4EhtNflBEify5Pm5vnVEVqdmMkxnT4tcdfJps5XYqaNeF9Q=="], 90 | 91 | "@toil/neurojs": ["@toil/neurojs@1.1.2", "", { "dependencies": { "@bufbuild/protobuf": "^2.2.3", "@vot.js/core": "^2.2.6", "@vot.js/shared": "^2.2.6" }, "peerDependencies": { "typescript": "^5.7.3" } }, "sha512-moUNsyoVaQpaCNrAsqkvrVkDak2hZtQraDfxmq8iicYAKk97pjAChRIXgXbj0xQbsM2o78u8yvs1Wm/p5HifYg=="], 92 | 93 | "@types/estree": ["@types/estree@1.0.6", "", {}, "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw=="], 94 | 95 | "@types/json-schema": ["@types/json-schema@7.0.15", "", {}, "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA=="], 96 | 97 | "@types/node": ["@types/node@22.13.4", "", { "dependencies": { "undici-types": "~6.20.0" } }, "sha512-ywP2X0DYtX3y08eFVx5fNIw7/uIv8hYUKgXoK8oayJlLnKcRfEYCxWMVE1XagUdVtCJlZT1AU4LXEABW+L1Peg=="], 98 | 99 | "@types/ws": ["@types/ws@8.5.14", "", { "dependencies": { "@types/node": "*" } }, "sha512-bd/YFLW+URhBzMXurx7lWByOu+xzU9+kb3RboOteXYDfW+tr+JZa99OyNmPINEGB/ahzKrEuc8rcv4gnpJmxTw=="], 100 | 101 | "@typescript-eslint/eslint-plugin": ["@typescript-eslint/eslint-plugin@8.24.0", "", { "dependencies": { "@eslint-community/regexpp": "^4.10.0", "@typescript-eslint/scope-manager": "8.24.0", "@typescript-eslint/type-utils": "8.24.0", "@typescript-eslint/utils": "8.24.0", "@typescript-eslint/visitor-keys": "8.24.0", "graphemer": "^1.4.0", "ignore": "^5.3.1", "natural-compare": "^1.4.0", "ts-api-utils": "^2.0.1" }, "peerDependencies": { "@typescript-eslint/parser": "^8.0.0 || ^8.0.0-alpha.0", "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <5.8.0" } }, "sha512-aFcXEJJCI4gUdXgoo/j9udUYIHgF23MFkg09LFz2dzEmU0+1Plk4rQWv/IYKvPHAtlkkGoB3m5e6oUp+JPsNaQ=="], 102 | 103 | "@typescript-eslint/parser": ["@typescript-eslint/parser@8.24.0", "", { "dependencies": { "@typescript-eslint/scope-manager": "8.24.0", "@typescript-eslint/types": "8.24.0", "@typescript-eslint/typescript-estree": "8.24.0", "@typescript-eslint/visitor-keys": "8.24.0", "debug": "^4.3.4" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <5.8.0" } }, "sha512-MFDaO9CYiard9j9VepMNa9MTcqVvSny2N4hkY6roquzj8pdCBRENhErrteaQuu7Yjn1ppk0v1/ZF9CG3KIlrTA=="], 104 | 105 | "@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@8.24.0", "", { "dependencies": { "@typescript-eslint/types": "8.24.0", "@typescript-eslint/visitor-keys": "8.24.0" } }, "sha512-HZIX0UByphEtdVBKaQBgTDdn9z16l4aTUz8e8zPQnyxwHBtf5vtl1L+OhH+m1FGV9DrRmoDuYKqzVrvWDcDozw=="], 106 | 107 | "@typescript-eslint/type-utils": ["@typescript-eslint/type-utils@8.24.0", "", { "dependencies": { "@typescript-eslint/typescript-estree": "8.24.0", "@typescript-eslint/utils": "8.24.0", "debug": "^4.3.4", "ts-api-utils": "^2.0.1" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <5.8.0" } }, "sha512-8fitJudrnY8aq0F1wMiPM1UUgiXQRJ5i8tFjq9kGfRajU+dbPyOuHbl0qRopLEidy0MwqgTHDt6CnSeXanNIwA=="], 108 | 109 | "@typescript-eslint/types": ["@typescript-eslint/types@8.24.0", "", {}, "sha512-VacJCBTyje7HGAw7xp11q439A+zeGG0p0/p2zsZwpnMzjPB5WteaWqt4g2iysgGFafrqvyLWqq6ZPZAOCoefCw=="], 110 | 111 | "@typescript-eslint/typescript-estree": ["@typescript-eslint/typescript-estree@8.24.0", "", { "dependencies": { "@typescript-eslint/types": "8.24.0", "@typescript-eslint/visitor-keys": "8.24.0", "debug": "^4.3.4", "fast-glob": "^3.3.2", "is-glob": "^4.0.3", "minimatch": "^9.0.4", "semver": "^7.6.0", "ts-api-utils": "^2.0.1" }, "peerDependencies": { "typescript": ">=4.8.4 <5.8.0" } }, "sha512-ITjYcP0+8kbsvT9bysygfIfb+hBj6koDsu37JZG7xrCiy3fPJyNmfVtaGsgTUSEuTzcvME5YI5uyL5LD1EV5ZQ=="], 112 | 113 | "@typescript-eslint/utils": ["@typescript-eslint/utils@8.24.0", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", "@typescript-eslint/scope-manager": "8.24.0", "@typescript-eslint/types": "8.24.0", "@typescript-eslint/typescript-estree": "8.24.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <5.8.0" } }, "sha512-07rLuUBElvvEb1ICnafYWr4hk8/U7X9RDCOqd9JcAMtjh/9oRmcfN4yGzbPVirgMR0+HLVHehmu19CWeh7fsmQ=="], 114 | 115 | "@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.24.0", "", { "dependencies": { "@typescript-eslint/types": "8.24.0", "eslint-visitor-keys": "^4.2.0" } }, "sha512-kArLq83QxGLbuHrTMoOEWO+l2MwsNS2TGISEdx8xgqpkbytB07XmlQyQdNDrCc1ecSqx0cnmhGvpX+VBwqqSkg=="], 116 | 117 | "@unhead/schema": ["@unhead/schema@1.11.19", "", { "dependencies": { "hookable": "^5.5.3", "zhead": "^2.2.4" } }, "sha512-7VhYHWK7xHgljdv+C01MepCSYZO2v6OhgsfKWPxRQBDDGfUKCUaChox0XMq3tFvXP6u4zSp6yzcDw2yxCfVMwg=="], 118 | 119 | "@vot.js/core": ["@vot.js/core@2.2.6", "", { "dependencies": { "@vot.js/shared": "^2.2.6" }, "peerDependencies": { "typescript": "^5.0.0" } }, "sha512-cUrvCNlkc2FfmEZZ5Xt1A0Qisc8LnrbP9rcMAH+pMRDtvfX5dPfw+vLNTDu1RBw54tNJaGs5xWWsFlOYHN+P6g=="], 120 | 121 | "@vot.js/shared": ["@vot.js/shared@2.2.6", "", { "dependencies": { "@bufbuild/protobuf": "^2.0.0" }, "peerDependencies": { "typescript": "^5.0.0" } }, "sha512-M4uqKlMFFDFSpzKofywUpdXo/0ZfnzhX1sfwmVDy0+ZVFOboPP7ZRRZLiOkDJlFUHGUnn7tb+FYnJ7LGhfH3lA=="], 122 | 123 | "acorn": ["acorn@8.14.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA=="], 124 | 125 | "acorn-jsx": ["acorn-jsx@5.3.2", "", { "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ=="], 126 | 127 | "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=="], 128 | 129 | "ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="], 130 | 131 | "argparse": ["argparse@2.0.1", "", {}, "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="], 132 | 133 | "atomic-sleep": ["atomic-sleep@1.0.0", "", {}, "sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ=="], 134 | 135 | "balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], 136 | 137 | "brace-expansion": ["brace-expansion@1.1.11", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA=="], 138 | 139 | "braces": ["braces@3.0.3", "", { "dependencies": { "fill-range": "^7.1.1" } }, "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA=="], 140 | 141 | "bun-types": ["bun-types@1.2.2", "", { "dependencies": { "@types/node": "*", "@types/ws": "~8.5.10" } }, "sha512-RCbMH5elr9gjgDGDhkTTugA21XtJAy/9jkKe/G3WR2q17VPGhcquf9Sir6uay9iW+7P/BV0CAHA1XlHXMAVKHg=="], 142 | 143 | "callsites": ["callsites@3.1.0", "", {}, "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ=="], 144 | 145 | "chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="], 146 | 147 | "color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="], 148 | 149 | "color-name": ["color-name@1.1.4", "", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="], 150 | 151 | "colorette": ["colorette@2.0.20", "", {}, "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w=="], 152 | 153 | "commander": ["commander@12.1.0", "", {}, "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA=="], 154 | 155 | "concat-map": ["concat-map@0.0.1", "", {}, "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="], 156 | 157 | "cookie": ["cookie@1.0.2", "", {}, "sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA=="], 158 | 159 | "cross-spawn": ["cross-spawn@7.0.6", "", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA=="], 160 | 161 | "dateformat": ["dateformat@4.6.3", "", {}, "sha512-2P0p0pFGzHS5EMnhdxQi7aJN+iMheud0UhG4dlE1DLAlvL8JHjJJTX/CSm4JXwV0Ka5nGk3zC5mcb5bUQUxxMA=="], 162 | 163 | "debug": ["debug@4.4.0", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA=="], 164 | 165 | "deep-is": ["deep-is@0.1.4", "", {}, "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ=="], 166 | 167 | "elysia": ["elysia@1.2.6", "", { "dependencies": { "@sinclair/typebox": "^0.34.13", "cookie": "^1.0.2", "fast-decode-uri-component": "^1.0.1", "memoirist": "^0.2.0", "openapi-types": "^12.1.3" }, "peerDependencies": { "typescript": ">= 5.0.0" }, "optionalPeers": ["typescript"] }, "sha512-bIGCPMB4tLA8k06Cr1Cz9TBYGJlXXuivH3iwTgUIK2hqSTyUXW/i4eXbK/E52B3AwXZytl8AUyT79LSTiMjRNw=="], 168 | 169 | "elysia-http-status-code": ["elysia-http-status-code@1.0.9", "", { "peerDependencies": { "elysia": "0.7.12", "typescript": "^5.0.0" } }, "sha512-ae+R6NInUsFbzqxjm+Fax36/cCHnnIL7MfQCx7kyCtl14D16ZwIaSbAiECttX96VGSZEX1KehWmVw/zdwc/XwA=="], 170 | 171 | "end-of-stream": ["end-of-stream@1.4.4", "", { "dependencies": { "once": "^1.4.0" } }, "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q=="], 172 | 173 | "escape-string-regexp": ["escape-string-regexp@4.0.0", "", {}, "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA=="], 174 | 175 | "eslint": ["eslint@9.20.1", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.12.1", "@eslint/config-array": "^0.19.0", "@eslint/core": "^0.11.0", "@eslint/eslintrc": "^3.2.0", "@eslint/js": "9.20.0", "@eslint/plugin-kit": "^0.2.5", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/retry": "^0.4.1", "@types/estree": "^1.0.6", "@types/json-schema": "^7.0.15", "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.2.0", "eslint-visitor-keys": "^4.2.0", "espree": "^10.3.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-m1mM33o6dBUjxl2qb6wv6nGNwCAsns1eKtaQ4l/NPHeTvhiUPbtdfMyktxN4B3fgHIgsYh1VT3V9txblpQHq+g=="], 176 | 177 | "eslint-plugin-oxlint": ["eslint-plugin-oxlint@0.15.11", "", { "dependencies": { "jsonc-parser": "^3.3.1" } }, "sha512-sQMNroPApNS85ZPyO5fWjnLVlA6aPuKk7lzP/TpKMVfpFpX/V2FzYtZm/A7RQd0N9ufcP5aKj1rL25OskhvV2g=="], 178 | 179 | "eslint-scope": ["eslint-scope@8.2.0", "", { "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^5.2.0" } }, "sha512-PHlWUfG6lvPc3yvP5A4PNyBL1W8fkDUccmI21JUu/+GKZBoH/W5u6usENXUrWFRsyoW5ACUjFGgAFQp5gUlb/A=="], 180 | 181 | "eslint-visitor-keys": ["eslint-visitor-keys@4.2.0", "", {}, "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw=="], 182 | 183 | "espree": ["espree@10.3.0", "", { "dependencies": { "acorn": "^8.14.0", "acorn-jsx": "^5.3.2", "eslint-visitor-keys": "^4.2.0" } }, "sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg=="], 184 | 185 | "esquery": ["esquery@1.6.0", "", { "dependencies": { "estraverse": "^5.1.0" } }, "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg=="], 186 | 187 | "esrecurse": ["esrecurse@4.3.0", "", { "dependencies": { "estraverse": "^5.2.0" } }, "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag=="], 188 | 189 | "estraverse": ["estraverse@5.3.0", "", {}, "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA=="], 190 | 191 | "esutils": ["esutils@2.0.3", "", {}, "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g=="], 192 | 193 | "fast-copy": ["fast-copy@3.0.2", "", {}, "sha512-dl0O9Vhju8IrcLndv2eU4ldt1ftXMqqfgN4H1cpmGV7P6jeB9FwpN9a2c8DPGE1Ys88rNUJVYDHq73CGAGOPfQ=="], 194 | 195 | "fast-decode-uri-component": ["fast-decode-uri-component@1.0.1", "", {}, "sha512-WKgKWg5eUxvRZGwW8FvfbaH7AXSh2cL+3j5fMGzUMCxWBJ3dV3a7Wz8y2f/uQ0e3B6WmodD3oS54jTQ9HVTIIg=="], 196 | 197 | "fast-deep-equal": ["fast-deep-equal@3.1.3", "", {}, "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="], 198 | 199 | "fast-glob": ["fast-glob@3.3.3", "", { "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", "glob-parent": "^5.1.2", "merge2": "^1.3.0", "micromatch": "^4.0.8" } }, "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg=="], 200 | 201 | "fast-json-stable-stringify": ["fast-json-stable-stringify@2.1.0", "", {}, "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw=="], 202 | 203 | "fast-levenshtein": ["fast-levenshtein@2.0.6", "", {}, "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw=="], 204 | 205 | "fast-redact": ["fast-redact@3.5.0", "", {}, "sha512-dwsoQlS7h9hMeYUq1W++23NDcBLV4KqONnITDV9DjfS3q1SgDGVrBdvvTLUotWtPSD7asWDV9/CmsZPy8Hf70A=="], 206 | 207 | "fast-safe-stringify": ["fast-safe-stringify@2.1.1", "", {}, "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA=="], 208 | 209 | "fastq": ["fastq@1.19.0", "", { "dependencies": { "reusify": "^1.0.4" } }, "sha512-7SFSRCNjBQIZH/xZR3iy5iQYR8aGBE0h3VG6/cwlbrpdciNYBMotQav8c1XI3HjHH+NikUpP53nPdlZSdWmFzA=="], 210 | 211 | "file-entry-cache": ["file-entry-cache@8.0.0", "", { "dependencies": { "flat-cache": "^4.0.0" } }, "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ=="], 212 | 213 | "fill-range": ["fill-range@7.1.1", "", { "dependencies": { "to-regex-range": "^5.0.1" } }, "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg=="], 214 | 215 | "find-up": ["find-up@5.0.0", "", { "dependencies": { "locate-path": "^6.0.0", "path-exists": "^4.0.0" } }, "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng=="], 216 | 217 | "flat-cache": ["flat-cache@4.0.1", "", { "dependencies": { "flatted": "^3.2.9", "keyv": "^4.5.4" } }, "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw=="], 218 | 219 | "flatted": ["flatted@3.3.2", "", {}, "sha512-AiwGJM8YcNOaobumgtng+6NHuOqC3A7MixFeDafM3X9cIUM+xUXoS5Vfgf+OihAYe20fxqNM9yPBXJzRtZ/4eA=="], 220 | 221 | "glob-parent": ["glob-parent@6.0.2", "", { "dependencies": { "is-glob": "^4.0.3" } }, "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A=="], 222 | 223 | "globals": ["globals@14.0.0", "", {}, "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ=="], 224 | 225 | "graphemer": ["graphemer@1.4.0", "", {}, "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag=="], 226 | 227 | "has-flag": ["has-flag@4.0.0", "", {}, "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="], 228 | 229 | "help-me": ["help-me@5.0.0", "", {}, "sha512-7xgomUX6ADmcYzFik0HzAxh/73YlKR9bmFzf51CZwR+b6YtzU2m0u49hQCqV6SvlqIqsaxovfwdvbnsw3b/zpg=="], 230 | 231 | "hookable": ["hookable@5.5.3", "", {}, "sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ=="], 232 | 233 | "husky": ["husky@9.1.7", "", { "bin": { "husky": "bin.js" } }, "sha512-5gs5ytaNjBrh5Ow3zrvdUUY+0VxIuWVL4i9irt6friV+BqdCfmV11CQTWMiBYWHbXhco+J1kHfTOUkePhCDvMA=="], 234 | 235 | "ignore": ["ignore@5.3.2", "", {}, "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g=="], 236 | 237 | "import-fresh": ["import-fresh@3.3.1", "", { "dependencies": { "parent-module": "^1.0.0", "resolve-from": "^4.0.0" } }, "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ=="], 238 | 239 | "imurmurhash": ["imurmurhash@0.1.4", "", {}, "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA=="], 240 | 241 | "is-extglob": ["is-extglob@2.1.1", "", {}, "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ=="], 242 | 243 | "is-glob": ["is-glob@4.0.3", "", { "dependencies": { "is-extglob": "^2.1.1" } }, "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg=="], 244 | 245 | "is-number": ["is-number@7.0.0", "", {}, "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng=="], 246 | 247 | "isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="], 248 | 249 | "joycon": ["joycon@3.1.1", "", {}, "sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw=="], 250 | 251 | "js-yaml": ["js-yaml@4.1.0", "", { "dependencies": { "argparse": "^2.0.1" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA=="], 252 | 253 | "json-buffer": ["json-buffer@3.0.1", "", {}, "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ=="], 254 | 255 | "json-schema-traverse": ["json-schema-traverse@0.4.1", "", {}, "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="], 256 | 257 | "json-stable-stringify-without-jsonify": ["json-stable-stringify-without-jsonify@1.0.1", "", {}, "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw=="], 258 | 259 | "jsonc-parser": ["jsonc-parser@3.3.1", "", {}, "sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ=="], 260 | 261 | "keyv": ["keyv@4.5.4", "", { "dependencies": { "json-buffer": "3.0.1" } }, "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw=="], 262 | 263 | "levn": ["levn@0.4.1", "", { "dependencies": { "prelude-ls": "^1.2.1", "type-check": "~0.4.0" } }, "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ=="], 264 | 265 | "locate-path": ["locate-path@6.0.0", "", { "dependencies": { "p-locate": "^5.0.0" } }, "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw=="], 266 | 267 | "lodash.merge": ["lodash.merge@4.6.2", "", {}, "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ=="], 268 | 269 | "memoirist": ["memoirist@0.2.0", "", {}, "sha512-DA1V11OWsKmYjgYHfT1luus0FtTjUbILfI9s5M+ckK29tBLON6GDhH5GwxDz7E1ou4Bdzm9vhbeCaRAWxwG+0g=="], 270 | 271 | "merge2": ["merge2@1.4.1", "", {}, "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg=="], 272 | 273 | "micromatch": ["micromatch@4.0.8", "", { "dependencies": { "braces": "^3.0.3", "picomatch": "^2.3.1" } }, "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA=="], 274 | 275 | "minimatch": ["minimatch@3.1.2", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw=="], 276 | 277 | "minimist": ["minimist@1.2.8", "", {}, "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA=="], 278 | 279 | "ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="], 280 | 281 | "natural-compare": ["natural-compare@1.4.0", "", {}, "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw=="], 282 | 283 | "on-exit-leak-free": ["on-exit-leak-free@2.1.2", "", {}, "sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA=="], 284 | 285 | "once": ["once@1.4.0", "", { "dependencies": { "wrappy": "1" } }, "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w=="], 286 | 287 | "openapi-types": ["openapi-types@12.1.3", "", {}, "sha512-N4YtSYJqghVu4iek2ZUvcN/0aqH1kRDuNqzcycDxhOUpg7GdvLa2F3DgS6yBNhInhv2r/6I0Flkn7CqL8+nIcw=="], 288 | 289 | "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=="], 290 | 291 | "oxlint": ["oxlint@0.15.11", "", { "optionalDependencies": { "@oxlint/darwin-arm64": "0.15.11", "@oxlint/darwin-x64": "0.15.11", "@oxlint/linux-arm64-gnu": "0.15.11", "@oxlint/linux-arm64-musl": "0.15.11", "@oxlint/linux-x64-gnu": "0.15.11", "@oxlint/linux-x64-musl": "0.15.11", "@oxlint/win32-arm64": "0.15.11", "@oxlint/win32-x64": "0.15.11" }, "bin": { "oxlint": "bin/oxlint", "oxc_language_server": "bin/oxc_language_server" } }, "sha512-SvNbuA5KiGzA1/E5TCzbhC0veVFdJRQW0CfeRCUG2AKzfH2j3KkQMmBA8JwVsdOhfPMCjwomAL1xE6+RglyCCA=="], 292 | 293 | "p-limit": ["p-limit@3.1.0", "", { "dependencies": { "yocto-queue": "^0.1.0" } }, "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ=="], 294 | 295 | "p-locate": ["p-locate@5.0.0", "", { "dependencies": { "p-limit": "^3.0.2" } }, "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw=="], 296 | 297 | "parent-module": ["parent-module@1.0.1", "", { "dependencies": { "callsites": "^3.0.0" } }, "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g=="], 298 | 299 | "path-exists": ["path-exists@4.0.0", "", {}, "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w=="], 300 | 301 | "path-key": ["path-key@3.1.1", "", {}, "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="], 302 | 303 | "pathe": ["pathe@1.1.2", "", {}, "sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ=="], 304 | 305 | "picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], 306 | 307 | "pino": ["pino@9.6.0", "", { "dependencies": { "atomic-sleep": "^1.0.0", "fast-redact": "^3.1.1", "on-exit-leak-free": "^2.1.0", "pino-abstract-transport": "^2.0.0", "pino-std-serializers": "^7.0.0", "process-warning": "^4.0.0", "quick-format-unescaped": "^4.0.3", "real-require": "^0.2.0", "safe-stable-stringify": "^2.3.1", "sonic-boom": "^4.0.1", "thread-stream": "^3.0.0" }, "bin": { "pino": "bin.js" } }, "sha512-i85pKRCt4qMjZ1+L7sy2Ag4t1atFcdbEt76+7iRJn1g2BvsnRMGu9p8pivl9fs63M2kF/A0OacFZhTub+m/qMg=="], 308 | 309 | "pino-abstract-transport": ["pino-abstract-transport@2.0.0", "", { "dependencies": { "split2": "^4.0.0" } }, "sha512-F63x5tizV6WCh4R6RHyi2Ml+M70DNRXt/+HANowMflpgGFMAym/VKm6G7ZOQRjqN7XbGxK1Lg9t6ZrtzOaivMw=="], 310 | 311 | "pino-loki": ["pino-loki@2.5.0", "", { "dependencies": { "commander": "^12.1.0", "pino-abstract-transport": "^2.0.0", "pump": "^3.0.2" }, "bin": { "pino-loki": "dist/cli.cjs" } }, "sha512-/QCSukecqbjXWcVB58st0bKJFQiXg4ZEGXslnnMCMbcrDr5LT36XvkS0dy0eBvZvI8bWoh3efjLYLmN+94iLSQ=="], 312 | 313 | "pino-pretty": ["pino-pretty@13.0.0", "", { "dependencies": { "colorette": "^2.0.7", "dateformat": "^4.6.3", "fast-copy": "^3.0.2", "fast-safe-stringify": "^2.1.1", "help-me": "^5.0.0", "joycon": "^3.1.1", "minimist": "^1.2.6", "on-exit-leak-free": "^2.1.0", "pino-abstract-transport": "^2.0.0", "pump": "^3.0.0", "secure-json-parse": "^2.4.0", "sonic-boom": "^4.0.1", "strip-json-comments": "^3.1.1" }, "bin": { "pino-pretty": "bin.js" } }, "sha512-cQBBIVG3YajgoUjo1FdKVRX6t9XPxwB9lcNJVD5GCnNM4Y6T12YYx8c6zEejxQsU0wrg9TwmDulcE9LR7qcJqA=="], 314 | 315 | "pino-std-serializers": ["pino-std-serializers@7.0.0", "", {}, "sha512-e906FRY0+tV27iq4juKzSYPbUj2do2X2JX4EzSca1631EB2QJQUqGbDuERal7LCtOpxl6x3+nvo9NPZcmjkiFA=="], 316 | 317 | "prelude-ls": ["prelude-ls@1.2.1", "", {}, "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g=="], 318 | 319 | "process-warning": ["process-warning@4.0.1", "", {}, "sha512-3c2LzQ3rY9d0hc1emcsHhfT9Jwz0cChib/QN89oME2R451w5fy3f0afAhERFZAwrbDU43wk12d0ORBpDVME50Q=="], 320 | 321 | "pump": ["pump@3.0.2", "", { "dependencies": { "end-of-stream": "^1.1.0", "once": "^1.3.1" } }, "sha512-tUPXtzlGM8FE3P0ZL6DVs/3P58k9nk8/jZeQCurTJylQA8qFYzHFfhBJkuqyE0FifOsQ0uKWekiZ5g8wtr28cw=="], 322 | 323 | "punycode": ["punycode@2.3.1", "", {}, "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg=="], 324 | 325 | "queue-microtask": ["queue-microtask@1.2.3", "", {}, "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A=="], 326 | 327 | "quick-format-unescaped": ["quick-format-unescaped@4.0.4", "", {}, "sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg=="], 328 | 329 | "real-require": ["real-require@0.2.0", "", {}, "sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg=="], 330 | 331 | "resolve-from": ["resolve-from@4.0.0", "", {}, "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g=="], 332 | 333 | "reusify": ["reusify@1.0.4", "", {}, "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw=="], 334 | 335 | "run-parallel": ["run-parallel@1.2.0", "", { "dependencies": { "queue-microtask": "^1.2.2" } }, "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA=="], 336 | 337 | "safe-stable-stringify": ["safe-stable-stringify@2.5.0", "", {}, "sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA=="], 338 | 339 | "secure-json-parse": ["secure-json-parse@2.7.0", "", {}, "sha512-6aU+Rwsezw7VR8/nyvKTx8QpWH9FrcYiXXlqC4z5d5XQBDRqtbfsRjnwGyqbi3gddNtWHuEk9OANUotL26qKUw=="], 340 | 341 | "semver": ["semver@7.7.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA=="], 342 | 343 | "shebang-command": ["shebang-command@2.0.0", "", { "dependencies": { "shebang-regex": "^3.0.0" } }, "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA=="], 344 | 345 | "shebang-regex": ["shebang-regex@3.0.0", "", {}, "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="], 346 | 347 | "sonic-boom": ["sonic-boom@4.2.0", "", { "dependencies": { "atomic-sleep": "^1.0.0" } }, "sha512-INb7TM37/mAcsGmc9hyyI6+QR3rR1zVRu36B0NeGXKnOOLiZOfER5SA+N7X7k3yUYRzLWafduTDvJAfDswwEww=="], 348 | 349 | "split2": ["split2@4.2.0", "", {}, "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg=="], 350 | 351 | "strip-json-comments": ["strip-json-comments@3.1.1", "", {}, "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig=="], 352 | 353 | "supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="], 354 | 355 | "thread-stream": ["thread-stream@3.1.0", "", { "dependencies": { "real-require": "^0.2.0" } }, "sha512-OqyPZ9u96VohAyMfJykzmivOrY2wfMSf3C5TtFJVgN+Hm6aj+voFhlK+kZEIv2FBh1X6Xp3DlnCOfEQ3B2J86A=="], 356 | 357 | "to-regex-range": ["to-regex-range@5.0.1", "", { "dependencies": { "is-number": "^7.0.0" } }, "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ=="], 358 | 359 | "ts-api-utils": ["ts-api-utils@2.0.1", "", { "peerDependencies": { "typescript": ">=4.8.4" } }, "sha512-dnlgjFSVetynI8nzgJ+qF62efpglpWRk8isUEWZGWlJYySCTD6aKvbUDu+zbPeDakk3bg5H4XpitHukgfL1m9w=="], 360 | 361 | "type-check": ["type-check@0.4.0", "", { "dependencies": { "prelude-ls": "^1.2.1" } }, "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew=="], 362 | 363 | "typescript": ["typescript@5.7.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw=="], 364 | 365 | "typescript-eslint": ["typescript-eslint@8.24.0", "", { "dependencies": { "@typescript-eslint/eslint-plugin": "8.24.0", "@typescript-eslint/parser": "8.24.0", "@typescript-eslint/utils": "8.24.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <5.8.0" } }, "sha512-/lmv4366en/qbB32Vz5+kCNZEMf6xYHwh1z48suBwZvAtnXKbP+YhGe8OLE2BqC67LMqKkCNLtjejdwsdW6uOQ=="], 366 | 367 | "undici-types": ["undici-types@6.20.0", "", {}, "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg=="], 368 | 369 | "uri-js": ["uri-js@4.4.1", "", { "dependencies": { "punycode": "^2.1.0" } }, "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg=="], 370 | 371 | "which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="], 372 | 373 | "word-wrap": ["word-wrap@1.2.5", "", {}, "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA=="], 374 | 375 | "wrappy": ["wrappy@1.0.2", "", {}, "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="], 376 | 377 | "yocto-queue": ["yocto-queue@0.1.0", "", {}, "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q=="], 378 | 379 | "zhead": ["zhead@2.2.4", "", {}, "sha512-8F0OI5dpWIA5IGG5NHUg9staDwz/ZPxZtvGVf01j7vHqSyZ0raHY+78atOVxRqb73AotX22uV1pXt3gYSstGag=="], 380 | 381 | "@eslint-community/eslint-utils/eslint-visitor-keys": ["eslint-visitor-keys@3.4.3", "", {}, "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag=="], 382 | 383 | "@eslint/plugin-kit/@eslint/core": ["@eslint/core@0.10.0", "", { "dependencies": { "@types/json-schema": "^7.0.15" } }, "sha512-gFHJ+xBOo4G3WRlR1e/3G8A6/KZAH6zcE/hkLRCZTi/B9avAG365QhFA8uOGzTMqgTghpn7/fSnscW++dpMSAw=="], 384 | 385 | "@humanfs/node/@humanwhocodes/retry": ["@humanwhocodes/retry@0.3.1", "", {}, "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA=="], 386 | 387 | "@scalar/themes/@scalar/types": ["@scalar/types@0.0.32", "", { "dependencies": { "@scalar/openapi-types": "0.1.7", "@unhead/schema": "^1.11.11" } }, "sha512-WHMkFQw4cu1mrG4pEiTUXVBBs205kHECdLM/5F7ATI0A7Axv6G1GgofkwbyCAayUjNk82uaCXzSOgPojbq4iGQ=="], 388 | 389 | "@typescript-eslint/typescript-estree/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="], 390 | 391 | "fast-glob/glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="], 392 | 393 | "@scalar/themes/@scalar/types/@scalar/openapi-types": ["@scalar/openapi-types@0.1.7", "", {}, "sha512-oOTG3JQifg55U3DhKB7WdNIxFnJzbPJe7rqdyWdio977l8IkxQTVmObftJhdNIMvhV2K+1f/bDoMQGu6yTaD0A=="], 394 | 395 | "@typescript-eslint/typescript-estree/minimatch/brace-expansion": ["brace-expansion@2.0.1", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA=="], 396 | } 397 | } 398 | -------------------------------------------------------------------------------- /changelog.md: -------------------------------------------------------------------------------- 1 | # 2.0.3 2 | 3 | - Добавлена обработка Preflight CORS запросов 4 | - Изменена логика добавления CORS 5 | 6 | # 2.0.2 7 | 8 | - Добавлена проверка на значение logToFile перед созданием папки logs 9 | - Обновлена версия библиотеки `@toil/neurojs` 10 | 11 | # 2.0.1 12 | 13 | - Добавлено управление логированием в файл с помощью переменной окружения LOG_TO_FILE (по умолчанию отключено) 14 | 15 | # 2.0.0 16 | 17 | > [!CAUTION] 18 | > Эта версия не имеет совместимости с 1.x.x версиями. 19 | > Для обновления до этой версии необходимо выполнить чистую установку 20 | 21 | - Сервер переписан на Bun с использованием фреймворка Elysia 22 | - Основная логика сервера вынесена в библиотеку [@toil/neurojs](https://github.com/FOSWLY/neurojs) 23 | - Произведена полная переработка дизайна эндпоинтов: 24 | 25 | - Добавлен префикс `/v2` ко всем путям. 26 | 27 | - Удален путь `/redoc` 28 | 29 | - Универсальный путь `/generation` был переосмыслен и разделен на: 30 | 31 | - `/summarize/video` 32 | - `/summarize/text` 33 | - `/summarize/article` 34 | 35 | - Добавлена поддержка использования [neuro-worker](https://github.com/FOSWLY/neuro-worker) 36 | - Убраны разные варианты документации. Стандартная документация, теперь, расположена по пути `/v2/docs` 37 | - Переменная окружения `YANDEX_COOKIE` была переименована в `SESSION_ID_COOKIE`. Теперь, она не является обязательной, и больше не требует указания части `Session_id=` в начале и `;` в конце 38 | - Переменная окружения `API_KEY` была переименована в `API_TOKEN`. 39 | - Добавлена возможность установить большую часть значения в конфиге через переменные окружения 40 | - Добавлена поддержка логирования в Loki 41 | - Добавлен докер образ 42 | 43 | # 1.2.0 44 | 45 | - Добавлена возможность суммаризации текста. (В нашем расширение этого не будет) 46 | - Обновлена структура ответа на `/health`. Теперь, в ответе так же возвращается версия нашего API сервера. 47 | - Теперь, если при ответе сервера Яндекса статус код будет отличным от 200, то будет возвращаться ошибка `{ "detail": "Unable to access Yandex API" }` с 403 статус кодом 48 | - Переработана структура настроек. Теперь, все настройки хранятся в `core/settings.py` и `.env` 49 | - Обновлены зависимости 50 | 51 | # 1.1.0 52 | 53 | - Добавлена поддержка суммаризатора видео 54 | - Обновлена структура ответов и запросов 55 | - Сервер переименован из `[FOSWLY] Summarize Articles` в `[FOSWLY] Summarize` 56 | - Библиотека `tomli` заменена на `tomlib` (python 3.11+) 57 | 58 | # 1.0.0 59 | 60 | - Первичный релиз 61 | -------------------------------------------------------------------------------- /ecosystem.config.json: -------------------------------------------------------------------------------- 1 | { 2 | "apps": [ 3 | { 4 | "name": "summarize-backend", 5 | "namespace": "FOSWLY", 6 | "script": "bun", 7 | "args": "run start" 8 | } 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /eslint.config.js: -------------------------------------------------------------------------------- 1 | import js from "@eslint/js"; 2 | // import globals from "globals"; 3 | import oxlint from "eslint-plugin-oxlint"; 4 | import tseslint from "typescript-eslint"; 5 | 6 | export default tseslint.config( 7 | { 8 | ignores: ["**/*.d.ts", "ecosystem.config.js", "eslint.config.js"], 9 | }, 10 | js.configs.recommended, 11 | ...tseslint.configs.recommendedTypeChecked, 12 | ...tseslint.configs.stylisticTypeChecked, 13 | { 14 | languageOptions: { 15 | ecmaVersion: "latest", 16 | sourceType: "module", 17 | parserOptions: { 18 | project: true, 19 | tsconfigDirName: import.meta.dirname, 20 | }, 21 | }, 22 | }, 23 | oxlint.configs["flat/recommended"], // oxlint should be the last one 24 | ); 25 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "summarize-backend", 3 | "version": "2.0.3", 4 | "author": "Toil", 5 | "repository": { 6 | "type": "git", 7 | "url": "git+https://github.com/FOSWLY/summarize-backend" 8 | }, 9 | "scripts": { 10 | "dev": "bun run --watch src/index.ts", 11 | "start": "bun src/index.ts", 12 | "lint": "bunx oxlint --ignore-path=.oxlintignore && bunx eslint", 13 | "prepare": "husky" 14 | }, 15 | "dependencies": { 16 | "@elysiajs/swagger": "^1.2.0", 17 | "@toil/neurojs": "^1.1.2", 18 | "elysia": "1.2.6", 19 | "elysia-http-status-code": "^1.0.9", 20 | "pino": "^9.5.0", 21 | "pino-loki": "^2.4.0" 22 | }, 23 | "devDependencies": { 24 | "@elysiajs/cors": "^1.2.0", 25 | "@sinclair/typebox": "^0.34.13", 26 | "bun-types": "^1.1.41", 27 | "eslint": "^9.17.0", 28 | "eslint-plugin-oxlint": "^0.15.10", 29 | "husky": "^9.1.7", 30 | "oxlint": "^0.15.10", 31 | "pino-pretty": "^13.0.0", 32 | "typescript-eslint": "^8.18.1" 33 | }, 34 | "module": "src/index.js", 35 | "bun-create": { 36 | "start": "bun run src/index.ts" 37 | }, 38 | "type": "module", 39 | "peerDependencies": { 40 | "typescript": "^5.6.3" 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/config.ts: -------------------------------------------------------------------------------- 1 | import * as path from "node:path"; 2 | 3 | import { Value } from "@sinclair/typebox/value"; 4 | 5 | import { ConfigSchema } from "@/schemas/config"; 6 | 7 | export default Value.Parse(ConfigSchema, { 8 | server: { 9 | port: Bun.env.SERVICE_PORT, 10 | hostname: Bun.env.SERVICE_HOST, 11 | }, 12 | app: { 13 | name: Bun.env.APP_NAME, 14 | desc: Bun.env.APP_DESC, 15 | contact_email: Bun.env.APP_CONTACT_EMAIL, 16 | }, 17 | cors: {}, 18 | logging: { 19 | level: Bun.env.NODE_ENV === "production" ? "info" : "debug", 20 | logPath: path.join(__dirname, "..", "logs"), 21 | logToFile: Bun.env.LOG_TO_FILE === "true", 22 | loki: { 23 | host: Bun.env.LOKI_HOST, 24 | user: Bun.env.LOKI_USER, 25 | password: Bun.env.LOKI_PASSWORD, 26 | label: Bun.env.LOKI_LABEL, 27 | }, 28 | }, 29 | client: { 30 | useWorker: Bun.env.USE_WORKER === "true", 31 | workerHost: Bun.env.WORKER_HOST, 32 | workerHostTH: Bun.env.WORKER_HOST_TH, 33 | apiToken: Bun.env.API_TOKEN, 34 | sessionId: Bun.env.SESSION_ID_COOKIE, 35 | }, 36 | }); 37 | -------------------------------------------------------------------------------- /src/controllers/health/index.ts: -------------------------------------------------------------------------------- 1 | import { Elysia } from "elysia"; 2 | 3 | import config from "../../config"; 4 | import { HealthResponse } from "@/models/health.model"; 5 | 6 | export default new Elysia().group("/health", (app) => 7 | app.get( 8 | "/", 9 | () => ({ 10 | version: config.app.version, 11 | status: "ok" as const, 12 | }), 13 | { 14 | response: { 15 | 200: HealthResponse, 16 | }, 17 | detail: { 18 | summary: "Get health", 19 | tags: ["Health"], 20 | }, 21 | }, 22 | ), 23 | ); 24 | -------------------------------------------------------------------------------- /src/controllers/sharing/index.ts: -------------------------------------------------------------------------------- 1 | import { Elysia } from "elysia"; 2 | 3 | import { NeuroClient, NeuroWorkerClient } from "@toil/neurojs"; 4 | 5 | import config from "@/config"; 6 | import { 7 | GetSharingBody, 8 | GetSharingResponse, 9 | GetSharingUrlAPITokenNotFound, 10 | GetSharingUrlBody, 11 | GetSharingUrlNotFound, 12 | GetSharingUrlResponse, 13 | } from "@/models/sharing.model"; 14 | import { SharingAPITokenNotFoundError, SharingUrlNotFoundError } from "@/errors"; 15 | 16 | const { 17 | client: { useWorker, workerHost, workerHostTH, sessionId: sessionIdCookie, apiToken }, 18 | } = config; 19 | 20 | const client = useWorker 21 | ? new NeuroWorkerClient({ 22 | host: workerHost, 23 | hostTH: workerHostTH, 24 | sessionIdCookie, 25 | apiToken, 26 | }) 27 | : new NeuroClient({ 28 | sessionIdCookie, 29 | apiToken, 30 | }); 31 | 32 | export default new Elysia() 33 | .post( 34 | "/sharing", 35 | async ({ body: { token } }) => { 36 | return (await client.getSharingContent({ 37 | token, 38 | })) as unknown as GetSharingResponse; 39 | }, 40 | { 41 | body: GetSharingBody, 42 | response: { 43 | 200: GetSharingResponse, 44 | }, 45 | detail: { 46 | summary: "Get sharing content by token", 47 | tags: ["Sharing"], 48 | }, 49 | }, 50 | ) 51 | .post( 52 | "/sharing-url", 53 | async ({ body: { url } }) => { 54 | if (!apiToken) { 55 | throw new SharingAPITokenNotFoundError(); 56 | } 57 | 58 | try { 59 | return await client.getSharingUrl({ 60 | url, 61 | }); 62 | } catch { 63 | throw new SharingUrlNotFoundError(); 64 | } 65 | }, 66 | { 67 | body: GetSharingUrlBody, 68 | response: { 69 | 200: GetSharingUrlResponse, 70 | 404: GetSharingUrlNotFound, 71 | 503: GetSharingUrlAPITokenNotFound, 72 | }, 73 | detail: { 74 | summary: "Get sharing url", 75 | tags: ["Sharing"], 76 | }, 77 | }, 78 | ); 79 | -------------------------------------------------------------------------------- /src/controllers/summarize/index.ts: -------------------------------------------------------------------------------- 1 | import { Elysia } from "elysia"; 2 | 3 | import { NeuroClient, NeuroWorkerClient } from "@toil/neurojs"; 4 | 5 | import config from "@/config"; 6 | import { 7 | ArticleSummarizeBody, 8 | TextSummarizeBody, 9 | VideoSummarizeBody, 10 | TextSummarizeResponse, 11 | ArticleSummarizeResponse, 12 | VideoSummarizeResponse, 13 | } from "@/models/summarize.model"; 14 | 15 | const { 16 | client: { useWorker, workerHost, workerHostTH, sessionId: sessionIdCookie }, 17 | } = config; 18 | 19 | const client = useWorker 20 | ? new NeuroWorkerClient({ 21 | host: workerHost, 22 | hostTH: workerHostTH, 23 | sessionIdCookie, 24 | }) 25 | : new NeuroClient({ 26 | sessionIdCookie, 27 | }); 28 | 29 | export default new Elysia().group("/summarize", (app) => 30 | app 31 | .post( 32 | "/text", 33 | async ({ body: { text, sessionId, bypassCache } }) => { 34 | return (await client.summarizeText({ 35 | text, 36 | extraOpts: { 37 | sessionId, 38 | bypassCache, 39 | }, 40 | })) as unknown as TextSummarizeResponse; 41 | }, 42 | { 43 | body: TextSummarizeBody, 44 | response: { 45 | 200: TextSummarizeResponse, 46 | }, 47 | detail: { 48 | summary: "Summarize text", 49 | tags: ["Summarize"], 50 | }, 51 | }, 52 | ) 53 | .post( 54 | "/article", 55 | async ({ body: { url, sessionId, bypassCache } }) => { 56 | return (await client.summarizeArticle({ 57 | url, 58 | extraOpts: { 59 | sessionId, 60 | bypassCache, 61 | }, 62 | })) as unknown as ArticleSummarizeResponse; 63 | }, 64 | { 65 | body: ArticleSummarizeBody, 66 | response: { 67 | 200: ArticleSummarizeResponse, 68 | }, 69 | detail: { 70 | summary: "Summarize article", 71 | tags: ["Summarize"], 72 | }, 73 | }, 74 | ) 75 | .post( 76 | "/video", 77 | async ({ body: { url, language, videoTitle, sessionId, bypassCache } }) => { 78 | return (await client.summarizeVideo({ 79 | url, 80 | language, 81 | extraOpts: { 82 | sessionId, 83 | videoTitle, 84 | bypassCache, 85 | }, 86 | })) as unknown as VideoSummarizeResponse; 87 | }, 88 | { 89 | body: VideoSummarizeBody, 90 | response: { 91 | 200: VideoSummarizeResponse, 92 | }, 93 | detail: { 94 | summary: "Summarize video", 95 | tags: ["Summarize"], 96 | }, 97 | }, 98 | ), 99 | ); 100 | -------------------------------------------------------------------------------- /src/errors.ts: -------------------------------------------------------------------------------- 1 | export class SharingUrlNotFoundError extends Error { 2 | constructor() { 3 | super("Sharing url not found"); 4 | } 5 | } 6 | 7 | export class SharingAPITokenNotFoundError extends Error { 8 | constructor() { 9 | super("Server is missing an API token. This endpoint is unavailable"); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | import fs from "node:fs/promises"; 2 | 3 | import { Elysia } from "elysia"; 4 | import { swagger } from "@elysiajs/swagger"; 5 | import { cors } from "@elysiajs/cors"; 6 | import { HttpStatusCode } from "elysia-http-status-code"; 7 | 8 | import config from "./config"; 9 | import { log } from "./logging"; 10 | 11 | import health from "./controllers/health"; 12 | import summarizeController from "./controllers/summarize"; 13 | import sharingController from "./controllers/sharing"; 14 | import { SharingAPITokenNotFoundError, SharingUrlNotFoundError } from "./errors"; 15 | 16 | if (config.logging.logToFile && !(await fs.exists(config.logging.logPath))) { 17 | await fs.mkdir(config.logging.logPath, { recursive: true }); 18 | log.info(`Created log directory`); 19 | } 20 | 21 | const app = new Elysia({ 22 | prefix: "/v2", 23 | }) 24 | .use( 25 | swagger({ 26 | path: "/docs", 27 | scalarCDN: config.app.scalarCDN, 28 | scalarConfig: { 29 | spec: { 30 | url: "/v2/docs/json", 31 | }, 32 | }, 33 | documentation: { 34 | info: { 35 | title: config.app.name, 36 | description: config.app.desc, 37 | version: config.app.version, 38 | license: { 39 | name: config.app.license, 40 | }, 41 | contact: { 42 | name: "Developer", 43 | url: config.app.github_url, 44 | email: config.app.contact_email, 45 | }, 46 | }, 47 | }, 48 | }), 49 | ) 50 | .use(HttpStatusCode()) 51 | .use(cors(config.cors)) 52 | .error({ 53 | SHARING_URL_NOT_FOUND: SharingUrlNotFoundError, 54 | SHARING_API_TOKEN_NOT_FOUND: SharingAPITokenNotFoundError, 55 | }) 56 | .onError(({ set, code, error, httpStatus }) => { 57 | switch (code) { 58 | case "NOT_FOUND": 59 | return { 60 | detail: "Route not found :(", 61 | }; 62 | case "SHARING_URL_NOT_FOUND": 63 | set.status = httpStatus.HTTP_400_BAD_REQUEST; 64 | break; 65 | case "SHARING_API_TOKEN_NOT_FOUND": 66 | set.status = httpStatus.HTTP_503_SERVICE_UNAVAILABLE; 67 | break; 68 | case "VALIDATION": 69 | return error.all; 70 | } 71 | 72 | log.error( 73 | { 74 | message: error.message, 75 | }, 76 | code, 77 | ); 78 | 79 | return { 80 | error: error.message, 81 | }; 82 | }) 83 | .use(health) 84 | .use(summarizeController) 85 | .use(sharingController) 86 | .listen({ 87 | port: config.server.port, 88 | hostname: config.server.hostname, 89 | }); 90 | 91 | log.info(`🦊 Elysia is running at ${app.server?.hostname}:${app.server?.port}`); 92 | -------------------------------------------------------------------------------- /src/logging.ts: -------------------------------------------------------------------------------- 1 | import * as path from "node:path"; 2 | import { pino, type TransportMultiOptions, type TransportTargetOptions } from "pino"; 3 | 4 | import config from "@/config"; 5 | 6 | const { loki, logToFile } = config.logging; 7 | const startingDate = new Date().toISOString().split("T")[0]; 8 | 9 | type PinoOpts = Parameters[0] & { 10 | transport: TransportMultiOptions & { targets: TransportTargetOptions[] }; 11 | }; 12 | 13 | // https://github.com/pinojs/pino/issues/1791 14 | // if don't take out the options separately, it willn't work 15 | const opts: PinoOpts = { 16 | level: config.logging.level, 17 | redact: { 18 | // these just cause clutter 19 | paths: ["pid", "hostname"], 20 | remove: true, 21 | }, 22 | transport: { 23 | targets: [], 24 | }, 25 | }; 26 | 27 | // it may be higher level than global, but it cann't be lower 28 | opts.transport.targets.push({ 29 | level: config.logging.level, 30 | target: "pino-pretty", 31 | options: { 32 | colorized: true, 33 | }, 34 | }); 35 | 36 | if (logToFile) { 37 | opts.transport.targets.push({ 38 | level: config.logging.level, 39 | target: "pino/file", 40 | options: { 41 | destination: path.join(config.logging.logPath, `${startingDate}.log`), 42 | }, 43 | }); 44 | } 45 | 46 | if (loki.host) { 47 | opts.transport.targets.push({ 48 | level: config.logging.level, 49 | target: "pino-loki", 50 | options: { 51 | batching: true, 52 | interval: 5, 53 | labels: { application: config.logging.loki.label }, 54 | host: loki.host, 55 | basicAuth: 56 | loki.user && loki.password 57 | ? { 58 | username: loki.user, 59 | password: loki.password, 60 | } 61 | : undefined, 62 | }, 63 | }); 64 | } 65 | 66 | export const log = pino(opts); 67 | -------------------------------------------------------------------------------- /src/models/health.model.ts: -------------------------------------------------------------------------------- 1 | import { t } from "elysia"; 2 | 3 | export const HealthResponse = t.Object({ 4 | version: t.String(), 5 | status: t.Literal("ok", { 6 | default: "ok", 7 | }), 8 | }); 9 | -------------------------------------------------------------------------------- /src/models/sharing.model.ts: -------------------------------------------------------------------------------- 1 | import { GetSharingUrlSuccess as GetSharingUrlSuccessOG } from "@toil/neurojs/typebox/thapi"; 2 | import { 3 | TextSummarizeResponse as TextSummarizeResponseOG, 4 | ArticleSummarizeResponse as ArticleSummarizeResponseOG, 5 | SharingVideoSummarizeResponse as SharingVideoSummarizeResponseOG, 6 | } from "@toil/neurojs/typebox/yandex"; 7 | import { t, Static } from "elysia"; 8 | 9 | export const GetSharingBody = t.Object({ 10 | token: t.String({ 11 | description: "Token from sharing url", 12 | examples: ["hoOAM7gs"], 13 | }), 14 | }); 15 | 16 | export const GetSharingUrlBody = t.Object({ 17 | url: t.String({ 18 | description: "Url for summarize", 19 | format: "uri", 20 | examples: ["https://habr.com/ru/news/729422"], 21 | }), 22 | }); 23 | 24 | // use composite for fix binding types with elysia typebox 25 | export const GetSharingResponse = t.Union([ 26 | TextSummarizeResponseOG, 27 | ArticleSummarizeResponseOG, 28 | SharingVideoSummarizeResponseOG, 29 | ]); 30 | export type GetSharingResponse = Static; 31 | 32 | export const GetSharingUrlResponse = t.Composite([GetSharingUrlSuccessOG]); 33 | export type GetSharingUrlResponse = Static; 34 | 35 | export const GetSharingUrlNotFound = t.Object({ 36 | error: t.Literal("Sharing url not found", { 37 | default: "Sharing url not found", 38 | }), 39 | }); 40 | 41 | export const GetSharingUrlAPITokenNotFound = t.Object({ 42 | error: t.Literal("Server is missing an API token. This endpoint is unavailable", { 43 | default: "Server is missing an API token. This endpoint is unavailable", 44 | }), 45 | }); 46 | -------------------------------------------------------------------------------- /src/models/summarize.model.ts: -------------------------------------------------------------------------------- 1 | import { 2 | TextSummarizeResponse as TextSummarizeResponseOG, 3 | ArticleSummarizeResponse as ArticleSummarizeResponseOG, 4 | VideoSummarizeResponse as VideoSummarizeResponseOG, 5 | } from "@toil/neurojs/typebox/yandex"; 6 | import { t, Static } from "elysia"; 7 | 8 | export const SessionId = t.String({ 9 | description: "Session ID from first response", 10 | examples: ["xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"], 11 | }); 12 | 13 | export const BypassCache = t.Boolean({ 14 | description: "Bypass cache", 15 | default: false, 16 | examples: [false], 17 | }); 18 | 19 | export const TextSummarizeBody = t.Object({ 20 | text: t.String({ 21 | minLength: 300, 22 | description: "Text for summarize", 23 | examples: ["Very long text with 300+ symbols"], 24 | }), 25 | sessionId: t.Optional(SessionId), 26 | bypassCache: t.Optional(BypassCache), 27 | }); 28 | 29 | export const ArticleSummarizeBody = t.Object({ 30 | url: t.String({ 31 | description: "Url for summarize", 32 | format: "uri", 33 | examples: ["https://toil.cc"], 34 | }), 35 | sessionId: t.Optional(SessionId), 36 | bypassCache: t.Optional(BypassCache), 37 | }); 38 | 39 | export const VideoSummarizeBody = t.Object({ 40 | url: t.String({ 41 | description: "Video url for summarize", 42 | format: "uri", 43 | examples: ["https://youtu.be/dQw4w9WgXcQ"], 44 | }), 45 | language: t.String({ 46 | description: "Video language", 47 | default: "en", 48 | }), 49 | videoTitle: t.Optional( 50 | t.String({ 51 | description: "Video title", 52 | examples: ["Rick Astley - Never Gonna Give You Up (Official Music Video)"], 53 | }), 54 | ), 55 | sessionId: t.Optional(SessionId), 56 | bypassCache: t.Optional(BypassCache), 57 | }); 58 | 59 | // use composite for fix binding types with elysia typebox 60 | export const TextSummarizeResponse = t.Composite([TextSummarizeResponseOG]); 61 | export type TextSummarizeResponse = Static; 62 | export const ArticleSummarizeResponse = t.Composite([ArticleSummarizeResponseOG]); 63 | export type ArticleSummarizeResponse = Static; 64 | export const VideoSummarizeResponse = t.Composite([VideoSummarizeResponseOG]); 65 | export type VideoSummarizeResponse = Static; 66 | -------------------------------------------------------------------------------- /src/schemas/config.ts: -------------------------------------------------------------------------------- 1 | import { Type as t, type Static } from "@sinclair/typebox"; 2 | 3 | import { version } from "../../package.json"; 4 | 5 | export const LoggingLevel = t.Union( 6 | [ 7 | t.Literal("info"), 8 | t.Literal("debug"), 9 | t.Literal("fatal"), 10 | t.Literal("error"), 11 | t.Literal("warn"), 12 | t.Literal("trace"), 13 | ], 14 | { 15 | default: "info", 16 | }, 17 | ); 18 | 19 | const license = "MIT"; 20 | const scalarCDN = "https://unpkg.com/@scalar/api-reference@1.25.118/dist/browser/standalone.js"; 21 | 22 | export const ConfigSchema = t.Object({ 23 | server: t.Object({ 24 | port: t.Number({ default: 3312 }), 25 | hostname: t.String({ default: "0.0.0.0" }), 26 | }), 27 | app: t.Object({ 28 | name: t.String({ default: "[FOSWLY] Summarize" }), 29 | desc: t.String({ 30 | default: 31 | "[FOSWLY] Summarize is a server that implements unified endpoints for summarize logic from @toil/neurojs library", 32 | }), 33 | version: t.Literal(version, { readOnly: true, default: version }), 34 | license: t.Literal(license, { readOnly: true, default: license }), 35 | github_url: t.String({ 36 | default: "https://github.com/FOSWLY/summarize-backend", 37 | }), 38 | contact_email: t.String({ default: "me@toil.cc" }), 39 | scalarCDN: t.Literal(scalarCDN, { readOnly: true, default: scalarCDN }), 40 | }), 41 | cors: t.Object({ 42 | allowedHeaders: t.String({ default: "*" }), 43 | origin: t.String({ default: "*" }), 44 | methods: t.String({ default: "GET, POST, OPTIONS" }), 45 | maxAge: t.Number({ default: 86400 }), 46 | }), 47 | logging: t.Object({ 48 | level: LoggingLevel, 49 | logPath: t.String(), 50 | logToFile: t.Boolean({ default: false }), 51 | loki: t.Object({ 52 | host: t.String({ default: "" }), 53 | user: t.String({ default: "" }), 54 | password: t.String({ default: "" }), 55 | label: t.String({ default: "summarize-backend" }), 56 | }), 57 | }), 58 | client: t.Object({ 59 | // use yandex server directly by default 60 | useWorker: t.Boolean({ default: false }), 61 | workerHost: t.String({ default: "http://127.0.0.1:7674/browser" }), 62 | workerHostTH: t.String({ default: "http://127.0.0.1:7674/th" }), 63 | // allow get sharing url 64 | apiToken: t.Optional(t.String()), 65 | // use cookie Session_id instead of YaHMAC (summarize video support only YaHMAC) 66 | sessionId: t.Optional(t.String()), 67 | }), 68 | }); 69 | 70 | export type ConfigSchemaType = Static; 71 | -------------------------------------------------------------------------------- /src/types/global.d.ts: -------------------------------------------------------------------------------- 1 | declare module "bun" { 2 | interface Env { 3 | SERVICE_HOST: string; 4 | SERVICE_PORT: number; 5 | APP_NAME: string; 6 | APP_DESC: string; 7 | APP_CONTACT_EMAIL: string; 8 | LOG_TO_FILE: string; 9 | LOKI_HOST: string; 10 | LOKI_USER: string; 11 | LOKI_PASSWORD: string; 12 | LOKI_LABEL: string; 13 | USE_WORKER: string; 14 | WORKER_HOST: string; 15 | WORKER_HOST_TH: string; 16 | API_TOKEN: string; 17 | SESSION_ID_COOKIE: string; 18 | NODE_ENV: string; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2021" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */, 4 | "module": "ES2022" /* Specify what module code is generated. */, 5 | "moduleResolution": "Bundler" /* Specify how TypeScript looks up a file from a given module specifier. */, 6 | "types": [ 7 | "bun-types" 8 | ] /* Specify type package names to be included without being referenced in a source file. */, 9 | "resolveJsonModule": true /* Enable importing .json files. */, 10 | "esModuleInterop": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */, 11 | "forceConsistentCasingInFileNames": true /* Ensure that casing is correct in imports. */, 12 | 13 | "strict": true /* Enable all strict type-checking options. */, 14 | "paths": { 15 | "@/*": ["./src/*"] 16 | }, 17 | 18 | "skipLibCheck": true /* Skip type checking all .d.ts files. */ 19 | } 20 | } 21 | --------------------------------------------------------------------------------