{"id":51414943,"url":"https://github.com/ndugram/fastvk","last_synced_at":"2026-07-04T18:01:27.084Z","repository":{"id":363760695,"uuid":"1263033985","full_name":"ndugram/fastvk","owner":"ndugram","description":"Async VK bot framework with FastAPI-style decorators and aiogram-style FSM","archived":false,"fork":false,"pushed_at":"2026-06-27T11:36:45.000Z","size":922,"stargazers_count":16,"open_issues_count":1,"forks_count":0,"subscribers_count":0,"default_branch":"master","last_synced_at":"2026-06-27T12:21:22.643Z","etag":null,"topics":["aiohttp","api","framework","pydantic","pydantic-v2","python","python3","vk","vkontakte"],"latest_commit_sha":null,"homepage":"http://fastvk.ndugram.dev","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ndugram.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-06-08T14:58:06.000Z","updated_at":"2026-06-27T11:36:46.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/ndugram/fastvk","commit_stats":null,"previous_names":["ndugram/fastvk"],"tags_count":15,"template":false,"template_full_name":null,"purl":"pkg:github/ndugram/fastvk","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ndugram%2Ffastvk","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ndugram%2Ffastvk/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ndugram%2Ffastvk/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ndugram%2Ffastvk/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ndugram","download_url":"https://codeload.github.com/ndugram/fastvk/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ndugram%2Ffastvk/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35130738,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-07-04T02:00:05.987Z","response_time":113,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["aiohttp","api","framework","pydantic","pydantic-v2","python","python3","vk","vkontakte"],"created_at":"2026-07-04T18:01:26.185Z","updated_at":"2026-07-04T18:01:27.071Z","avatar_url":"https://github.com/ndugram.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n  \u003cimg src=\"https://raw.githubusercontent.com/ndugram/fastvk/master/docs/logo.svg\" width=\"480\"\u003e\n\u003c/p\u003e\n\u003cp align=\"center\"\u003e\n    \u003cem\u003eAsync VK bot framework with FastAPI-style decorators and aiogram-style FSM.\u003c/em\u003e\n\u003c/p\u003e\n\u003cp align=\"center\"\u003e\n\u003ca href=\"https://pypi.org/project/fastvk\" target=\"_blank\"\u003e\n    \u003cimg src=\"https://img.shields.io/pypi/v/fastvk?color=%234C75A3\u0026label=pypi%20package\" alt=\"Package version\"\u003e\n\u003c/a\u003e\n\u003ca href=\"https://pypi.org/project/fastvk\" target=\"_blank\"\u003e\n    \u003cimg src=\"https://img.shields.io/pypi/pyversions/fastvk.svg?color=%234C75A3\" alt=\"Supported Python versions\"\u003e\n\u003c/a\u003e\n\u003ca href=\"https://pypi.org/project/fastvk\" target=\"_blank\"\u003e\n    \u003cimg src=\"https://img.shields.io/pypi/dm/fastvk?color=%234C75A3\u0026label=downloads\" alt=\"Monthly downloads\"\u003e\n\u003c/a\u003e\n\u003ca href=\"https://pepy.tech/projects/fastvk\" target=\"_blank\"\u003e\n    \u003cimg src=\"https://img.shields.io/pepy/dt/fastvk?color=%234C75A3\u0026label=total%20downloads\" alt=\"Total downloads\"\u003e\n\u003c/a\u003e\n\u003ca href=\"https://github.com/ndugram/fastvk\" target=\"_blank\"\u003e\n    \u003cimg src=\"https://img.shields.io/github/stars/ndugram/fastvk?style=social\" alt=\"GitHub Stars\"\u003e\n\u003c/a\u003e\n\u003ca href=\"https://github.com/ndugram/fastvk/blob/master/LICENSE\" target=\"_blank\"\u003e\n    \u003cimg src=\"https://img.shields.io/badge/license-MIT-blue.svg\" alt=\"License\"\u003e\n\u003c/a\u003e\n\u003c/p\u003e\n\n---\n\n**Source Code**: \u003ca href=\"https://github.com/ndugram/fastvk\" target=\"_blank\"\u003ehttps://github.com/ndugram/fastvk\u003c/a\u003e\n\n---\n\nFastVK is a modern **async VK bot framework** for Python. It brings a decorator-based handler API — similar to FastAPI and aiogram, but for VK — with FSM, middleware, filters, keyboard builder, and a real-time dashboard out of the box.\n\nKey features:\n\n- **Familiar** — if you know FastAPI or aiogram, you already know FastVK. Same patterns, same ergonomics.\n- **CallbackData** — typed callback data factory with `pack()` / `unpack()` — inspired by aiogram.\n- **Auto-retry** — built-in exponential backoff for VK API calls (network errors, flood control).\n- **Auto-pagination** — `bot.collect()` iterates paginated methods (members, posts, history) with no manual loops.\n- **Async** — built on \u003ca href=\"https://docs.aiohttp.org/\" target=\"_blank\"\u003eaiohttp\u003c/a\u003e with full async/await support from top to bottom.\n- **FSM** — built-in Finite State Machine with `State`, `StatesGroup`, and pluggable storage: Memory, Redis, SQLite.\n- **Filters** — `Command`, `Text`, `StateFilter`, `FromUser`, `IsChat` and custom filters via any callable.\n- **Keyboard** — fluent keyboard builder with text, callback, link, location, and VK Pay buttons.\n- **Injection** — handler parameters injected by type: `message`, `state`, `bot`, `update` — no manual wiring.\n- **Routers** — split handlers across multiple `Router` instances and include them into the main bot.\n- **Middleware** — intercept every update before and after handlers with `BaseMiddleware`.\n- **Webhook** — built-in Callback API server via `run_webhook()`, no extra setup needed.\n- **Dashboard** — real-time monitoring UI with live stats, activity feed, and handler search.\n- **Logging** — colored, structured terminal output with per-logger colors and event highlighting.\n- **Typed** — full type annotations throughout; works great with mypy and pyright.\n\n## Requirements\n\nPython 3.10+\n\nFastVK depends on:\n\n- \u003ca href=\"https://docs.aiohttp.org/\" target=\"_blank\"\u003e\u003ccode\u003eaiohttp\u003c/code\u003e\u003c/a\u003e — async HTTP transport for Long Poll, Webhook, and VK API calls.\n- \u003ca href=\"https://docs.pydantic.dev/\" target=\"_blank\"\u003e\u003ccode\u003epydantic\u003c/code\u003e\u003c/a\u003e — typed data models for VK event objects.\n\n## Installation\n\n```console\n$ pip install fastvk\n\n---\u003e 100%\n```\n\n## Example\n\n### Create it\n\nCreate a file `main.py`:\n\n```python\nfrom fastvk import FastVK\nfrom fastvk.filters import Command\nfrom fastvk.types import Message\n\nbot = FastVK(token=\"vk1.a.YOUR_TOKEN\")\n\n\n@bot.message(Command(\"start\"))\nasync def start(message: Message) -\u003e None:\n    await message.answer(\"Привет! Я FastVK бот.\")\n\n\nif __name__ == \"__main__\":\n    bot.run_polling()\n```\n\n### Run it\n\n```console\n$ python main.py\n```\n\n### Check it\n\nYou will see colored output like:\n\n```\n10:35:42  INFO     fastvk                  FastVK started (group_id=123456789)\n10:35:44  INFO     fastvk                  ← message_new  →  start()  [Иван  id=123]\n```\n\nSend `/start` to your bot — it replies instantly.\n\n### Upgrade the example\n\n\u003cdetails markdown=\"1\"\u003e\n\u003csummary\u003eWith FSM (multi-step forms)...\u003c/summary\u003e\n\nUse `StatesGroup` and `State` to collect data across multiple messages:\n\n```python\nfrom fastvk import FastVK\nfrom fastvk.filters import Command, StateFilter\nfrom fastvk.fsm import FSMContext, State, StatesGroup\nfrom fastvk.types import Message\n\nbot = FastVK(token=\"vk1.a.YOUR_TOKEN\")\n\n\nclass Form(StatesGroup):\n    waiting_name = State()\n    waiting_age  = State()\n\n\n@bot.message(Command(\"start\"))\nasync def cmd_start(message: Message, state: FSMContext) -\u003e None:\n    await state.set_state(Form.waiting_name)\n    await message.answer(\"Как тебя зовут?\")\n\n\n@bot.message(StateFilter(Form.waiting_name))\nasync def got_name(message: Message, state: FSMContext) -\u003e None:\n    await state.update_data(name=message.text)\n    await state.set_state(Form.waiting_age)\n    await message.answer(f\"Отлично, {message.text}! Сколько тебе лет?\")\n\n\n@bot.message(StateFilter(Form.waiting_age))\nasync def got_age(message: Message, state: FSMContext) -\u003e None:\n    data = await state.update_data(age=message.text)\n    await state.clear()\n    await message.answer(f\"Готово!\\nИмя: {data['name']}\\nВозраст: {data['age']}\")\n\n\nif __name__ == \"__main__\":\n    bot.run_polling()\n```\n\n\u003c/details\u003e\n\n\u003cdetails markdown=\"1\"\u003e\n\u003csummary\u003eWith persistent FSM storage (SQLite)...\u003c/summary\u003e\n\nFSM state survives restarts — no Redis required:\n\n```python\nfrom fastvk import FastVK\nfrom fastvk.fsm import SQLiteStorage\n\nbot = FastVK(\n    token=\"vk1.a.YOUR_TOKEN\",\n    storage=SQLiteStorage(\"bot.db\"),\n)\n```\n\nInstall the optional dependency first:\n\n```console\n$ pip install fastvk[sqlite]\n```\n\nFor Redis:\n\n```python\nfrom fastvk.fsm import RedisStorage\n\nbot = FastVK(..., storage=RedisStorage(\"redis://localhost:6379/0\"))\n```\n\n```console\n$ pip install fastvk[redis]\n```\n\n\u003c/details\u003e\n\n\u003cdetails markdown=\"1\"\u003e\n\u003csummary\u003eWith keyboard buttons...\u003c/summary\u003e\n\nBuild keyboards with a fluent API:\n\n```python\nfrom fastvk import FastVK\nfrom fastvk.filters import Command\nfrom fastvk.keyboard import Button, Keyboard\nfrom fastvk.enums import Color\nfrom fastvk.types import Message\n\nbot = FastVK(token=\"vk1.a.YOUR_TOKEN\")\n\n\n@bot.message(Command(\"menu\"))\nasync def menu(message: Message) -\u003e None:\n    kb = (\n        Keyboard(one_time=True)\n        .row(\n            Button.text(\"Да\",  color=Color.POSITIVE),\n            Button.text(\"Нет\", color=Color.NEGATIVE),\n        )\n        .row(Button.text(\"Отмена\"))\n    )\n    await message.answer(\"Выберите:\", keyboard=kb)\n\n\n@bot.message(Command(\"pay\"))\nasync def pay(message: Message) -\u003e None:\n    kb = (\n        Keyboard(inline=True)\n        .row(Button.vkpay(action=\"pay-to-group\", group_id=123456789, amount=100, description=\"Донат\"))\n    )\n    await message.answer(\"Поддержать проект:\", keyboard=kb)\n```\n\n\u003c/details\u003e\n\n\u003cdetails markdown=\"1\"\u003e\n\u003csummary\u003eWith inline buttons (callback)...\u003c/summary\u003e\n\nHandle button clicks from inline keyboards:\n\n```python\nfrom fastvk import FastVK\nfrom fastvk.filters import Command\nfrom fastvk.keyboard import Button, Keyboard\nfrom fastvk.types import CallbackQuery, Message\n\nbot = FastVK(token=\"vk1.a.YOUR_TOKEN\")\n\n\n@bot.message(Command(\"vote\"))\nasync def vote(message: Message) -\u003e None:\n    kb = (\n        Keyboard(inline=True)\n        .row(\n            Button.callback(\"👍 За\",    payload={\"v\": \"yes\"}),\n            Button.callback(\"👎 Против\", payload={\"v\": \"no\"}),\n        )\n    )\n    await message.answer(\"Голосование:\", keyboard=kb)\n\n\n@bot.callback()\nasync def on_vote(cb: CallbackQuery) -\u003e None:\n    choice = cb.payload.get(\"v\")\n    await cb.answer(f\"Вы проголосовали: {'за' if choice == 'yes' else 'против'}\")\n```\n\n\u003c/details\u003e\n\n\u003cdetails markdown=\"1\"\u003e\n\u003csummary\u003eWith CallbackData (typed payloads)...\u003c/summary\u003e\n\nUse typed callback data instead of raw dicts — inspired by aiogram's `CallbackData`:\n\n```python\nfrom typing import ClassVar\n\nfrom fastvk import FastVK, CallbackData\nfrom fastvk.filters import Command\nfrom fastvk.keyboard import Button, Keyboard\nfrom fastvk.types import CallbackQuery, Message\n\n\nclass ProductCallback(CallbackData):\n    prefix: ClassVar[str] = \"product\"\n    product_id: int\n    action: str = \"view\"\n\n\nbot = FastVK(token=\"vk1.a.YOUR_TOKEN\")\n\n\n@bot.message(Command(\"shop\"))\nasync def shop(message: Message) -\u003e None:\n    kb = (\n        Keyboard(inline=True)\n        .row(\n            Button.callback(\"Товар 1\", payload=ProductCallback(product_id=1).pack()),\n            Button.callback(\"Товар 2\", payload=ProductCallback(product_id=2).pack()),\n        )\n    )\n    await message.answer(\"Каталог:\", keyboard=kb)\n\n\n@bot.callback()\nasync def on_product(callback: CallbackQuery) -\u003e None:\n    cb = ProductCallback.unpack(callback.payload)\n    await callback.answer(f\"Товар #{cb.product_id}: {cb.action}\")\n```\n\n```python\n# Compact payload format:  product:{\"product_id\":1,\"action\":\"view\"}\n```\n\n\u003c/details\u003e\n\n\u003cdetails markdown=\"1\"\u003e\n\u003csummary\u003eWith routers...\u003c/summary\u003e\n\nSplit handlers into separate modules and include them into the bot:\n\n```python\n# shop.py\nfrom fastvk import Router\nfrom fastvk.filters import Command, Text\nfrom fastvk.types import Message\n\nrouter = Router()\n\n\n@router.message(Command(\"catalog\"))\nasync def catalog(message: Message) -\u003e None:\n    await message.answer(\"Наш каталог: ...\")\n\n\n@router.message(Text(\"цена\", contains=True, ignore_case=True))\nasync def price_mention(message: Message) -\u003e None:\n    await message.answer(\"Цены начинаются от 99₽\")\n```\n\n```python\n# main.py\nfrom fastvk import FastVK\nfrom shop import router\n\nbot = FastVK(token=\"vk1.a.YOUR_TOKEN\")\nbot.include_router(router)\n\nif __name__ == \"__main__\":\n    bot.run_polling()\n```\n\n\u003c/details\u003e\n\n\u003cdetails markdown=\"1\"\u003e\n\u003csummary\u003eWith middleware...\u003c/summary\u003e\n\nIntercept every incoming update to add logging, rate limiting, or custom data:\n\n```python\nfrom collections.abc import Awaitable, Callable\nfrom typing import Any\n\nfrom fastvk import FastVK\nfrom fastvk.middleware import BaseMiddleware\nfrom fastvk.filters import Command\nfrom fastvk.types import Message\n\n\nclass LoggingMiddleware(BaseMiddleware):\n    async def __call__(\n        self,\n        handler: Callable[[Any, dict], Awaitable[Any]],\n        event: Any,\n        data: dict,\n    ) -\u003e Any:\n        print(f\"incoming: {type(event).__name__}\")\n        result = await handler(event, data)\n        print(\"handled\")\n        return result\n\n\nbot = FastVK(\n    token=\"vk1.a.YOUR_TOKEN\",\n    middleware=[LoggingMiddleware()],\n)\n```\n\n\u003c/details\u003e\n\n\u003cdetails markdown=\"1\"\u003e\n\u003csummary\u003eWith error handlers...\u003c/summary\u003e\n\nCatch exceptions raised inside handlers — by type, with full context injection:\n\n```python\nfrom fastvk import FastVK\nfrom fastvk.exceptions import VKAPIError\nfrom fastvk.filters import Command\nfrom fastvk.types import Message\n\nbot = FastVK(token=\"vk1.a.YOUR_TOKEN\")\n\n\n@bot.message(Command(\"risky\"))\nasync def risky(message: Message) -\u003e None:\n    raise ValueError(\"что-то пошло не так\")\n\n\n@bot.exception_handler(VKAPIError)\nasync def on_vk_error(error: VKAPIError, message: Message) -\u003e None:\n    await message.answer(\"VK API недоступен, попробуй позже.\")\n\n\n@bot.exception_handler()\nasync def on_any_error(error: Exception, message: Message) -\u003e None:\n    await message.answer(f\"Ошибка: {error}\")\n\n\nif __name__ == \"__main__\":\n    bot.run_polling()\n```\n\n\u003c/details\u003e\n\n\u003cdetails markdown=\"1\"\u003e\n\u003csummary\u003eWith webhook...\u003c/summary\u003e\n\nReceive updates via VK Callback API instead of Long Poll:\n\n```python\nfrom fastvk import FastVK\nfrom fastvk.filters import Command\nfrom fastvk.types import Message\n\nbot = FastVK(token=\"vk1.a.YOUR_TOKEN\")\n\n\n@bot.message(Command(\"start\"))\nasync def start(message: Message) -\u003e None:\n    await message.answer(\"Привет через webhook!\")\n\n\nif __name__ == \"__main__\":\n    bot.run_webhook(\n        confirmation_token=\"abc123def\",  # from VK group settings\n        host=\"0.0.0.0\",\n        port=8080,\n        path=\"/vk\",\n        secret=\"my_secret\",             # optional\n    )\n```\n\n\u003c/details\u003e\n\n\u003cdetails markdown=\"1\"\u003e\n\u003csummary\u003eWith filters...\u003c/summary\u003e\n\nCombine built-in and custom filters on any handler:\n\n```python\nfrom fastvk import FastVK\nfrom fastvk.filters import Command, FromUser, IsChat, Text\nfrom fastvk.types import Message\n\nADMIN_ID = 123456789\nbot = FastVK(token=\"vk1.a.YOUR_TOKEN\")\n\n\n@bot.message(Command(\"ban\"), FromUser(ADMIN_ID))\nasync def admin_ban(message: Message) -\u003e None:\n    await message.answer(\"Пользователь заблокирован.\")\n\n\n@bot.message(IsChat(\"private\"), Text(\"помощь\", contains=True, ignore_case=True))\nasync def help_in_pm(message: Message) -\u003e None:\n    await message.answer(\"Список команд: /start, /help\")\n\n\ndef is_long_message(message: Message, data: dict) -\u003e bool:\n    return len(message.text or \"\") \u003e 200\n\n\n@bot.message(is_long_message)\nasync def long_message(message: Message) -\u003e None:\n    await message.answer(\"Это очень длинное сообщение!\")\n```\n\n\u003c/details\u003e\n\n\u003cdetails markdown=\"1\"\u003e\n\u003csummary\u003eWith raw VK API calls...\u003c/summary\u003e\n\nAccess the full VK API via the injected `bot` parameter:\n\n```python\nfrom fastvk import Bot, FastVK\nfrom fastvk.filters import Command\nfrom fastvk.types import Message\n\nbot = FastVK(token=\"vk1.a.YOUR_TOKEN\")\n\n\n@bot.message(Command(\"me\"))\nasync def cmd_me(message: Message, bot: Bot) -\u003e None:\n    users = await bot.users.get(user_ids=message.from_id, fields=\"photo_200\")\n    name = f\"{users[0]['first_name']} {users[0]['last_name']}\"\n    await message.answer(f\"Ты: {name}\")\n\n\n@bot.message(Command(\"members\"))\nasync def cmd_members(message: Message, bot: Bot) -\u003e None:\n    data = await bot.groups.getMembers(group_id=123456789, count=1)\n    await message.answer(f\"Участников: {data['count']}\")\n```\n\n\u003c/details\u003e\n\n\u003cdetails markdown=\"1\"\u003e\n\u003csummary\u003eWith event handlers...\u003c/summary\u003e\n\nHandle any VK event type — not just messages:\n\n```python\nfrom fastvk import Bot, FastVK\nfrom fastvk.types import GroupJoinEvent, GroupLeaveEvent, Update, User, WallPostEvent\n\nbot = FastVK(token=\"vk1.a.YOUR_TOKEN\")\n\n\n@bot.group_join()\nasync def on_join(event: GroupJoinEvent, user: User, bot: Bot) -\u003e None:\n    await bot.messages.send(\n        peer_id=event.user_id,\n        message=f\"Добро пожаловать, {user.first_name}!\",\n        random_id=0,\n    )\n\n\n@bot.group_leave()\nasync def on_leave(event: GroupLeaveEvent) -\u003e None:\n    action = \"сам покинул\" if event.is_self else \"был исключён из\"\n    print(f\"Пользователь {event.user_id} {action} группы.\")\n\n\n@bot.wall_post_new()\nasync def on_new_post(event: WallPostEvent) -\u003e None:\n    print(f\"Новый пост #{event.id}: {event.text[:80]!r}\")\n\n\n@bot.on(\"photo_new\")\nasync def on_photo(update: Update) -\u003e None:\n    print(f\"Новое фото: {update.object}\")\n```\n\n\u003c/details\u003e\n\n## Dashboard\n\nEnable the real-time monitoring dashboard by passing a `BaseDashboard` instance:\n\n```python\nfrom fastvk import FastVK\nfrom fastvk.dashboard import BaseDashboard, DashboardConfig\n\nclass MyDashboard(BaseDashboard):\n    config = DashboardConfig(\n        dashboard_host=\"127.0.0.1\",\n        dashboard_port=8080,\n    )\n\nbot = FastVK(\n    token=\"vk1.a.YOUR_TOKEN\",\n    dashboard=MyDashboard(),\n)\n```\n\nOpen \u003ca href=\"http://127.0.0.1:8080\" target=\"_blank\"\u003ehttp://127.0.0.1:8080\u003c/a\u003e in your browser.\n\n\u003cimg src=\"https://raw.githubusercontent.com/ndugram/fastvk/master/docs/dashboard-dark.png\"\u003e\n\n\u003cimg src=\"https://raw.githubusercontent.com/ndugram/fastvk/master/docs/dashboard-light.png\"\u003e\n\nThe dashboard shows:\n\n- **Overview** — total updates, handled, errors, uptime, sparkline, updates/min, event distribution\n- **Handlers** — registered handlers with filters, searchable\n- **Updates** — live event type breakdown with percentages\n- **Activity** — real-time event feed with timestamps, last 200 events\n\n## Dependency injection\n\nHandler parameters are injected **by type** — declare what you need, the framework provides it:\n\n| Type | What you get |\n|---|---|\n| `Message` | Parsed incoming message (`message_new` events) |\n| `CallbackQuery` | Inline button click payload (`message_event` events) |\n| `FSMContext` | FSM state accessor for the current user |\n| `Bot` | VK API client |\n| `Update` | Full raw update object |\n| `BackgroundTasks` | Fire-and-forget background tasks |\n| Your `CallbackData` subclass | Unpacked callback payload (when using `CallbackDataFilter`) |\n\n```python\n@router.message()\nasync def handler(\n    message: Message,\n    state: FSMContext,\n    bot: Bot,\n) -\u003e None:\n    ...\n```\n\n## Optional dependencies\n\n| Extra | Installs | Use |\n|---|---|---|\n| `fastvk[sqlite]` | `aiosqlite` | `SQLiteStorage` — persistent FSM without Redis |\n| `fastvk[redis]` | `redis` | `RedisStorage` — Redis-backed FSM storage |\n\n```console\n$ pip install fastvk[sqlite]\n$ pip install fastvk[redis]\n```\n\n## Contributing\n\nContributions are welcome! Please open an issue before submitting a pull request.\n\nFound a bug? Open an issue on \u003ca href=\"https://github.com/ndugram/fastvk/issues\" target=\"_blank\"\u003eGitHub\u003c/a\u003e.\n\n## License\n\nThis project is licensed under the terms of the \u003ca href=\"https://github.com/ndugram/fastvk/blob/master/LICENSE\" target=\"_blank\"\u003eMIT license\u003c/a\u003e.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fndugram%2Ffastvk","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fndugram%2Ffastvk","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fndugram%2Ffastvk/lists"}