Metadata-Version: 2.5
Name: telegram-kit
Version: 0.2.1
Summary: Secure Telegram Bot API notifications for any Python project. Stdlib only.
License: MIT
License-File: LICENSE
Requires-Python: >=3.10
Description-Content-Type: text/markdown

# telegram-kit

Secure Telegram Bot API notifications for any Python project. Stdlib only —
no dependencies, no vendoring.

```python
import telegram_kit

telegram_kit.notify("build finished", service="my-app", chat_id="123456789")

store = telegram_kit.CredentialStore("my-app")
token = telegram_kit.read_hidden("Telegram bot token (hidden): ")
if token and store.set("telegram_bot_token", token):
    print("stored as", telegram_kit.mask_secret(token))
```

## Install

```bash
uv add "telegram-kit>=0.1.2,<0.2"
```

Published to [PyPI](https://pypi.org/project/telegram-kit/) on every `v*` tag (`.github/workflows/release.yml`).
`uv lock --upgrade-package telegram-kit` is how every project using this kit
picks up a fix — no file to copy, no diff to reapply. A project that is never
published to PyPI can pin the git tag instead:
`uv add "telegram-kit @ git+https://github.com/weskao/telegram-kit@v0.1.2"`.

## What it guarantees, whichever project uses it

- **No plaintext fallback.** `CredentialStore` writes to the OS credential
  store (macOS Keychain, Linux Secret Service, Windows DPAPI). With none
  available, it refuses to store rather than falling back to a plaintext
  file or home-rolled obfuscation.
- **Each caller gets its own namespace.** `CredentialStore(service)` keys
  every item under that service name, so two projects on the same machine
  never collide. Each Keychain / Secret Service item is labelled
  `<service>: <key>` so you can tell items apart in Keychain Access or
  Seahorse; an older item picks up the label the next time it's written.
  DPAPI items are already easy to tell apart: each one is a `<key>.dpapi` file.
- **Credentials never touch argv or the process list** — batch-mode/stdin
  paths are used for every backend.
- **Owner-only atomic writes** (`write_private`) for anything that must live
  on disk, on POSIX and Windows alike.

## API

| Function | Purpose |
|---|---|
| `CredentialStore(service, dpapi_dir=None)` | Get/set/delete a secret in the OS store. |
| `resolve_credentials(token, chat_id, environ=None)` | Configured value, else `TG_BOT_TOKEN`/`TG_CHAT_ID`. |
| `send_message(token, chat_id, text, timeout=10)` | One `sendMessage` call. Inside tmux the text ends with a `tmux_line()` on its own line (a `send_photo` caption too). `False` on any failure. |
| `send_photo(token, chat_id, photo, caption="", timeout=30)` | Image + caption in one `sendPhoto` message. A caption over 1024 UTF-16 units is sent right after the image as a `sendMessage`. `False` on any failure. |
| `notify(text, service, chat_id="", token_key=..., store=None)` | Resolve + send in one call. |
| `read_hidden(prompt, ask=None)` | Hidden input; `None` if the terminal can't hide it. |
| `mask_secret(secret)` | `********` plus at most the last 4 characters. |
| `tmux_line()` | `🪟 Tmux: <session>` inside tmux, else `""`. |
| `write_private(target, content)` | Atomic, owner-only file write. |

## Develop

```bash
uv run python -m unittest discover -s tests -t . -v
uv run ruff check .
```

## CI notifications

`.github/workflows/ci.yml` runs the test matrix (macOS/Linux/Windows) on every push and PR,
then a separate `notify-telegram` job sends a Telegram message only when the test job fails on
a `push` (never on green runs, never on `pull_request`, to avoid pinging on forks/external PRs).
Configure it once per repo:

```bash
gh secret set TELEGRAM_BOT_TOKEN
gh secret set TELEGRAM_CHAT_ID
```

Unconfigured secrets are a valid state — the job skips quietly instead of failing a second time
on top of the real failure.
