Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 69 additions & 0 deletions .cursor/rules/telegram-bot-api-updates.mdc
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
---
description: How Telegram Bot API version updates are applied in this library
alwaysApply: true
---

# Telegram Bot API Update Workflow

## Source of truth

1. Official changelog: https://core.telegram.org/bots/api-changelog
2. Method/type docs: https://core.telegram.org/bots/api
3. Parity schema (CI): `https://raw.githubusercontent.com/PaulSonOfLars/telegram-bot-api-spec/main/api.json` → local gitignored `api.json`

Implement **one Bot API version per PR/branch**. Branch: `bot-api-X.Y`. Do not skip versions.

## File map (touch only what the changelog needs)

| Area | File | What to add |
|------|------|-------------|
| Types / Update fields | `types.go` | New types; fields on `Update`, `Message`, etc. with `json:"snake_case,omitempty"` |
| Request configs | `configs.go` | `*Config` + `method()` + `params()` (+ `files()` if uploads) |
| Shared bases | `helper_structs.go` | Embeddable bases (`BaseChat`, `BaseEdit`, `BaseEphemeralMessage`, …) |
| Helpers | `helper_methods.go` | `New*` constructors for required params |
| Uploads | `upload.go` | Recursive attach/`file_id` logic for media-heavy configs |
| Convenience API | `bot.go` | Typed wrappers when return ≠ `Message` via `Send` (or bool/string/etc.) |
| Compile checks | `parity_interfaces_test.go` | `_ Chattable = …{}` / `_ Fileable = …{}` |
| Tests | `configs_test.go`, `types_test.go`, optional `bot_api_X_Y_test.go` | Params/JSON/unmarshal coverage |
| Docs/examples | `docs/examples/`, `examples/` | Only for major user-facing features |

## Naming & patterns

- Config: PascalCase of API method + `Config` (`sendRichMessage` → `SendRichMessageConfig`).
- Helper: `New` + Config name without suffix (`NewSendRichMessage`).
- Bot method: PascalCase API method (`EditEphemeralMessageText`).
- Prefer embedding bases over duplicating chat/ephemeral/edit fields.
- `params()`: start from embedded base, then `Params` helpers (`AddNonEmpty`, `AddNonZero`, `AddNonZero64`, `AddBool`, `AddFirstValid`, `AddInterface`, `Merge`).
- Chat targeting: `ChatID int64` + `ChannelUsername` (via `ChatConfig` / `BaseChat`), never invent alternate ID shapes.
- New `Update` fields: add JSON field + extend `SentFrom` / `FromChat` switch arms when applicable.
- **Docs field order:** keep struct fields / new types / method params in the same order as on core.telegram.org/bots/api (legacy code often doesn’t; don’t churn old order unless already editing that struct—see `telegram-type-patterns` rule).
- No comments unless behavior is non-obvious; match surrounding style (tabs in Go).

## Validation order

1. Mirror changelog bullets completely (types → fields → methods → params).
2. `go vet ./...` (do not use full `go build` for intermediate checks).
3. Unit tests for new params/JSON.
4. Optional: fetch `api.json`, run `go test -tags=api_parity ./...`; only extend allowlists in `api_parity_test.go` for documented legacy/promoted extras.

## Commit / PR style (from history)

- Message: `Add Telegram Bot API X.Y support` or `Bot API X.Y: <focus>`.
- Follow-up fixes for the same version are separate small PRs (e.g. missing ephemeral params).
- Keep parity/serialization fixes separate from the version bump when possible.

## Version baseline (do not confuse tag ≠ master)

| Signal | Value |
|--------|--------|
| Latest **git tag** | `v9.4.0` (tags lag; README discourages tagging) |
| Latest **code on `master`** | Bot API **10.3** present |
| Latest **explicit version commit** | Bot API 10.3 implementation (this branch) |
| Next official | — track changelog after 10.3 |

Notes:

- **8.3 is not current** on `master` (that landing was `61bd317` / PR #65, 2025-05).
- No commits titled 9.0–9.3 or 10.1; those features were bundled (`2f2184e` ≈ 9.0–9.4 catch-up; `c20b6c3` ≈ 10.1).
- Always judge “implemented” by **types/methods on `master`**, not by the newest tag or a single commit title.
- Coverage gate: follow `telegram-bot-api-verification-pipeline` (curated audit: 9.0–10.3 OK after 10.3 landing).
61 changes: 61 additions & 0 deletions .cursor/rules/telegram-bot-api-verification-pipeline.mdc
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
---
description: Pipeline to verify Bot API version coverage before/during implementation
alwaysApply: true
---

# Bot API Verification Pipeline

Run this before choosing a version bump and again before declaring a version done.

## A. Establish baseline

1. Read https://core.telegram.org/bots/api-changelog from last implemented version → target.
2. Treat **`master` types/methods** as truth (not git tags). Current implemented ceiling: **10.3**.
3. Skip Mini App **client-only** APIs (`WebApp.hideKeyboard`, DeviceStorage, etc.) — not HTTP Bot API.

## B. Changelog → checklist

For each version bullet, classify:

| Kind | How to verify in repo |
|------|------------------------|
| New class | `type Name` or alias `Name =` in `types.go` |
| New method | `method()` returns `"camelCaseName"` in a `*Config` |
| New field | `json:"snake_case` on the owning struct (prefer docs field order) |
| New parameter | serialized in that config’s `params()` / embedded base |
| Replacement | old name gone or migrated; new name present |
| Update payload | field on `Update`/`Message` + `SentFrom`/`FromChat` if needed |

Ignore regex false positives (`allowing`, `and`, `from` from changelog prose).

## C. Commands (local)

```bash
go vet ./...
go test -count=1 ./...
curl -fsSL -o api.json \
https://raw.githubusercontent.com/PaulSonOfLars/telegram-bot-api-spec/main/api.json
go test -tags=api_parity -run '^TestAPIParity' -count=1 .
```

`api.json` is gitignored. Spec may lag a fresh Telegram release by hours/days — changelog wins if they disagree.

## D. Pattern gates (must pass for new code)

1. Embed bases (`BaseChat`, `BaseEphemeralMessage`, …) — see `telegram-type-patterns`.
2. Inbound unions flattened (`TransactionPartner`-style), not interface JSON.
3. Field/param order follows core.telegram.org/bots/api for **new** fields.
4. Helpers `New*`, `parity_interfaces_test.go` compile checks, tests for params/JSON.
5. Breaking renames (e.g. 10.3 `ephemeral_message_parameters`): update configs + helpers + tests + examples together.

## E. Decision rule

- If any **prior** version on the checklist has gaps → implement the **oldest** gapped version first.
- Else implement the **next** changelog version only (one version per branch/PR).
- After merge, update the Version baseline table in `telegram-bot-api-updates.mdc`.

## F. Post-8.3 audit snapshot

| Version | Curated checklist |
|---------|-------------------|
| 9.0–10.3 | Present on `master` (as of Bot API 10.3 landing) |
87 changes: 87 additions & 0 deletions .cursor/rules/telegram-type-patterns.mdc
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
---
description: Embedding and Telegram polymorphic type patterns (TransactionPartner-style)
globs: "{types.go,configs.go,helper_structs.go,helper_methods.go,upload.go}"
alwaysApply: false
---

# Type & Embedding Patterns

Reuse these shapes for new Bot API types. Do not invent interface-based JSON unions for inbound Telegram objects.

## 0) Field & type order (docs order)

Match https://core.telegram.org/bots/api field order as closely as practical:

- Struct fields: same order as listed on the type/method page (required first as Telegram lists them, then optionals in doc order).
- New types in a version bump: introduce them in changelog / docs appearance order when adding a block of related types.
- Method params in `*Config` / `params()`: follow the Bot API parameter table order after embedded base fields.
- Do **not** mass-reorder old structs just to fix legacy drift; previous authors often ignored this. Apply docs order for **new** fields/types and when you already touch a struct for an API change (place the new field where the docs put it).

## 1) Config embedding (requests)

Shared request fields live in `helper_structs.go` and are **embedded** into configs:

| Base | Use for |
|------|---------|
| `ChatConfig` | chat_id / channel username |
| `BaseChat` | outgoing chat messages (reply, protect, effects, …) |
| `BaseChatMessage` / `BaseChatMessages` | edit/delete by message id(s) |
| `BaseEdit` | inline-or-chat edits |
| `BaseFile` | single-file sends |
| `BaseEphemeralMessage` | ephemeral edit/delete |
| `BaseInputMedia` | `InputMedia*` variants |

```go
type EditEphemeralMessageTextConfig struct {
BaseEphemeralMessage
Text string
// ...
}

func (c EditEphemeralMessageTextConfig) params() (Params, error) {
params, err := c.BaseEphemeralMessage.params()
// add only this config's fields
return params, err
}
```

Never copy-paste the same chat/ephemeral fields into each config.

## 2) Flattened polymorphic types (responses)

Telegram docs list exclusive variants (`TransactionPartnerUser`, `PaidMediaPhoto`, …). In this library, **inbound** unions are one struct with a discriminator + optional variant fields:

```go
type TransactionPartner struct {
Type string `json:"type"`
User User `json:"user,omitempty"` // "user"
Chat Chat `json:"chat,omitempty"` // "chat"
WithdrawalState *RevenueWithdrawalState `json:"withdrawal_state,omitempty"` // "fragment"
RequestCount int `json:"request_count,omitempty"` // "telegram_api"
// ...
}
```

Same pattern: `ChatMember`, `MessageOrigin`, `ReactionType`, `PaidMedia`, `ChatBoostSource`, `RevenueWithdrawalState`, `BackgroundType`, `StoryAreaType`.

Rules:

- Discriminator: `Type` or `Source` / `Status` as Telegram names it.
- Variant-only fields: `omitempty` + comment which variant(s) use them.
- Optional helpers: `IsUser()`, `IsEmoji()`, …
- Type-name constants when needed for parity (`MessageOriginUser = "user"`).
- At file end, add **aliases** so Telegram type names compile: `TransactionPartnerOther = TransactionPartner`, `PaidMediaPhoto = PaidMedia`.
- Dedicated variant structs (`TransactionPartnerUser`) are for **docs/constructors/outbound clarity**, not separate JSON unmarshal targets for that union.

## 3) Outbound interfaces (when needed)

Use small interfaces only for **sending** polymorphic payloads the bot builds:

- `InputMedia` (+ `BaseInputMedia` embed)
- `InputProfilePhoto`, `InputStoryContent`, `InlineQueryResults`

Prefer concrete structs with `Type` set in `New*` helpers.

## 4) Update / Message field wiring

New update payload → field on `Update` / `Message` with `json:"snake,omitempty"`, then extend `(*Update).SentFrom` / `FromChat` if a user/chat is primary.
Loading