Metadata-Version: 2.4
Name: luffa-sdk
Version: 0.1.0
Summary: A Telegram-style Python SDK for the Luffa Bot API
Project-URL: Homepage, https://github.com/its-mc/luffa-python-sdk
Project-URL: Documentation, https://github.com/its-mc/luffa-python-sdk#readme
Project-URL: Repository, https://github.com/its-mc/luffa-python-sdk
Project-URL: Issues, https://github.com/its-mc/luffa-python-sdk/issues
License-Expression: MIT
License-File: LICENSE
Keywords: bot,chatbot,luffa,messaging,sdk
Classifier: Development Status :: 3 - Alpha
Classifier: Framework :: AsyncIO
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Communications :: Chat
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Typing :: Typed
Requires-Python: >=3.10
Requires-Dist: httpx>=0.24
Provides-Extra: dotenv
Requires-Dist: python-dotenv>=1.0; extra == 'dotenv'
Description-Content-Type: text/markdown

# Luffa Python SDK

A Telegram-style Python SDK for the [Luffa](https://luffa.im) Bot API. Build bots in minutes with a clean decorator-based interface.

## Install

```bash
pip install luffa
```

With `.env` support:

```bash
pip install luffa[dotenv]
```

## Quickstart

```python
import os
from dotenv import load_dotenv
from luffa import LuffaBot

load_dotenv()
bot = LuffaBot(secret=os.getenv("BOT_SECRET"))


@bot.command("ping")
async def ping(msg):
    await msg.reply("Pong!")


@bot.on_message()
async def echo(msg):
    await msg.reply(f"You said: {msg.text}")


bot.run()
```

That's it. Save as `bot.py`, add your `BOT_SECRET` to `.env`, and run it.

## Getting Your Bot Secret

1. Open [robot.luffa.im](https://robot.luffa.im) and scan the QR code with Luffa
2. Click **New Bot** to create a bot
3. Copy the **SecretKey** — that's your `BOT_SECRET`
4. Add the bot as a friend in Luffa to start chatting

## Features

### Commands

Register command handlers with the `@bot.command()` decorator. The leading `/` is handled automatically. Arguments are parsed into `msg.args`.

```python
@bot.command("greet")
async def greet(msg):
    name = msg.args[0] if msg.args else "stranger"
    await msg.reply(f"Hello, {name}!")
```

User sends `/greet World` → bot replies `Hello, World!`

### Fallback Handler

Catch all non-command messages (or unregistered commands) with `@bot.on_message()`:

```python
@bot.on_message()
async def fallback(msg):
    await msg.reply("I don't understand that. Try /help")
```

### Interactive Buttons

Send menu-style buttons in group chats. Private chats automatically fall back to a text list.

```python
from luffa import button

@bot.command("menu")
async def menu(msg):
    await msg.reply_buttons(
        "What would you like to do?",
        buttons=[
            button("📋 Help", "/help"),
            button("🏓 Ping", "/ping"),
            button("ℹ️ About", "/about"),
        ],
    )
```

### Confirm Dialogs

Two side-by-side buttons for yes/no style interactions:

```python
from luffa import confirm_button

@bot.command("delete")
async def delete(msg):
    await msg.reply_confirm(
        "Are you sure you want to delete?",
        confirm=[
            confirm_button("Yes", "/confirm_delete", style="destructive"),
            confirm_button("Cancel", "/cancel"),
        ],
    )
```

### @Mentions

Mention users in group messages:

```python
from luffa import mention

await bot.send_group_text(
    group_id,
    "@abc123 you've been invited!",
    at_list=[mention("abc123", location=0, length=8)],
)
```

### Hidden Buttons

Buttons can be hidden so the tapped message isn't visible to others:

```python
button("Secret vote", "/vote yes", hidden=True)
```

## API Reference

### `LuffaBot(secret, poll_interval=1)`

The main bot class.

| Method | Description |
|---|---|
| `bot.command(name)` | Decorator — register a `/command` handler |
| `bot.on_message()` | Decorator — register a fallback handler |
| `bot.send_text(uid, text)` | Send a private message |
| `bot.send_group_text(uid, text, at_list?)` | Send a group text message |
| `bot.send_group_buttons(uid, text, buttons, dismiss?, at_list?)` | Send group message with buttons |
| `bot.send_group_confirm(uid, text, confirm, dismiss?, at_list?)` | Send group message with confirm buttons |
| `bot.run()` | Start polling (blocking) |
| `bot.start()` | Start polling (async) |

### `Message`

Passed to every handler.

| Property | Type | Description |
|---|---|---|
| `msg.text` | `str` | Message text |
| `msg.args` | `list[str]` | Command arguments |
| `msg.uid` | `str` | Chat ID (user or group) |
| `msg.sender_uid` | `str` | ID of the user who sent it |
| `msg.is_group` | `bool` | Whether it's a group message |
| `msg.msg_id` | `str` | Unique message ID |
| `msg.at_list` | `list` | @mentions in the message |
| `msg.url_link` | `str \| None` | Attached URL |

| Method | Description |
|---|---|
| `await msg.reply(text)` | Reply with text (auto-routes private/group) |
| `await msg.reply_buttons(text, buttons, dismiss?)` | Reply with menu buttons |
| `await msg.reply_confirm(text, confirm, dismiss?)` | Reply with confirm buttons |

### Components

| Function | Description |
|---|---|
| `button(name, selector, hidden?)` | Create a menu button |
| `confirm_button(name, selector, style?, hidden?)` | Create a confirm button (`"default"` or `"destructive"`) |
| `mention(uid, location?, length?)` | Create an @mention |

## Limitations

The Luffa Bot API currently supports:

- ✅ Text messages (private & group)
- ✅ Interactive buttons (group only)
- ✅ @mentions (group only)
- ❌ Voice / audio messages
- ❌ Images / files
- ❌ Message deletion
- ❌ Admin actions (kick, mute, pin)

## License

MIT
