Metadata-Version: 2.5
Name: quiety
Version: 0.1.0
Summary: Typed Python SDK for the Quiety Bot API
Author: Quiety
License: MIT
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Typing :: Typed
Requires-Python: >=3.10
Requires-Dist: httpx<1,>=0.27
Provides-Extra: dev
Requires-Dist: build>=1.2; extra == 'dev'
Requires-Dist: mypy>=1.11; extra == 'dev'
Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
Requires-Dist: pytest>=8; extra == 'dev'
Requires-Dist: ruff>=0.6; extra == 'dev'
Description-Content-Type: text/markdown

# quiety

Typed Python SDK for the Quiety Bot API implemented in `.server-app/BOT_API.md` and `.server-app/botapi.js`. Bot processes are hosted and run by developers; this package does not upload or host bot code.

## Install locally

```bash
python -m pip install -e .
```

Python 3.10+ and `httpx` are required. No trustworthy production origin is present in the project configuration (the client defaults to `http://127.0.0.1:3008`), so `base_url` is intentionally required. It may be either the server origin or a URL already ending in `/bot/api`.

```python
from quiety import AsyncBot

bot = AsyncBot("BOT_TOKEN", base_url="http://127.0.0.1:3008")
```

## API

`AsyncBot` provides `get_me`, `send_message`, `send_photo`, `send_document`, `edit_message_text`, `edit_message_dynamically`, `delete_message`, `answer_callback_query`, `get_updates`, `set_webhook`, `delete_webhook`, `get_webhook_info`, `set_my_commands`, and `get_my_commands`. `Bot` is a small blocking facade for common methods.

The server currently accepts rich text as plain `text`; `RichTextBuilder` also emits Telegram-style entities for forward compatibility. Inline keyboards are supported through `InlineKeyboardButton` and `InlineKeyboardMarkup`.

```python
from quiety import RichTextBuilder

text = RichTextBuilder().bold("Status: ").text("ready").build()
await bot.send_message(chat_id, text)
```

## Polling and routing

```python
from quiety import PollingRunner, Router

router = Router()


@router.command("start")
async def start(message, bot):
    await bot.send_message(message.chat.id, "Hello")


@router.callback_query("confirm")
async def confirm(query, bot):
    await bot.answer_callback_query(query.id)


@router.reaction
async def reacted(event, bot):
    print(event.emoji, event.reactions)


await PollingRunner(bot, router).run()
```

Polling acknowledges processed updates by advancing `offset`. It cannot be used while a webhook is configured.

## Webhooks

```python
await bot.set_webhook("https://example.test/hook", secret_token="secret_123")
info = await bot.get_webhook_info()
await bot.delete_webhook()
```

Use `dispatch_webhook` in your own HTTPS framework and pass the received `X-Quiety-Bot-Api-Secret-Token` for validation. Quiety persists updates before webhook delivery; failed deliveries remain queued.

## Reliability

The client has configurable timeouts and exponential retries for network failures, 429, 502, 503, and 504 responses. API failures map to typed exceptions. The server limit is 120 requests/minute per token/IP; dynamic edits should use a sensible interval.

## Development

```bash
python -m pip install -e ".[dev]"
pytest
ruff check .
mypy src
python -m build
```

Tests use `httpx.MockTransport` and never contact a remote server. See `examples/echo_bot.py`.
