first commit
This commit is contained in:
@@ -0,0 +1,94 @@
|
||||
# Build Bodies
|
||||
|
||||
## Purpose
|
||||
|
||||
Pure, side-effect-free helpers that translate the camelCase public message /
|
||||
reply-markup shape used by callers into the snake_case wire shape that the
|
||||
Telegram Bot API expects. Splitting these helpers out of the client keeps
|
||||
the wire-format translation independently testable, makes it cheap to add
|
||||
new optional fields, and means every option permutation can be exercised
|
||||
without an HTTP round trip.
|
||||
|
||||
Telegram's Bot API mixes top-level fields (`chat_id`, `parse_mode`) with
|
||||
nested objects (`reply_markup.inline_keyboard`). Hand-rolling each
|
||||
conversion in the client would scatter snake-case knowledge across the
|
||||
codebase; centralising it here means the wire-format contract is one file
|
||||
to audit when Telegram releases a new option.
|
||||
|
||||
## Features
|
||||
|
||||
- `buildSendMessageBody(message)` — converts `TelegramMessage` → wire body
|
||||
- `buildReplyMarkup(markup)` — converts `TelegramReplyMarkup` → wire markup
|
||||
- `MEDIA_METHOD_MAP` — frozen record of `TelegramMediaType` → Bot API method
|
||||
- Drops optional fields when falsy/absent — minimises wire payload
|
||||
- Preserves caller-provided `chatId` type (string or number) — Telegram accepts both
|
||||
|
||||
## Usage: Basic
|
||||
|
||||
```ts
|
||||
import { buildSendMessageBody } from "@suaveplan/telegram-client";
|
||||
|
||||
const body = buildSendMessageBody({
|
||||
chatId: 100,
|
||||
text: "Hello",
|
||||
parseMode: "HTML",
|
||||
});
|
||||
// body === { chat_id: 100, text: "Hello", parse_mode: "HTML" }
|
||||
```
|
||||
|
||||
## Usage: Advanced
|
||||
|
||||
```ts
|
||||
import {
|
||||
buildReplyMarkup,
|
||||
buildSendMessageBody,
|
||||
MEDIA_METHOD_MAP,
|
||||
} from "@suaveplan/telegram-client";
|
||||
|
||||
// Compose a fully-featured message body with inline + custom keyboards.
|
||||
const body = buildSendMessageBody({
|
||||
chatId: "@my_channel",
|
||||
text: "*Pick one*",
|
||||
parseMode: "MarkdownV2",
|
||||
disableWebPagePreview: true,
|
||||
replyToMessageId: 42,
|
||||
replyMarkup: {
|
||||
inlineKeyboard: [
|
||||
[
|
||||
{ text: "Docs", url: "https://core.telegram.org/bots/api" },
|
||||
{ text: "Yes", callbackData: "yes" },
|
||||
],
|
||||
],
|
||||
oneTimeKeyboard: true,
|
||||
},
|
||||
});
|
||||
|
||||
// Pick the Bot API method for a media upload.
|
||||
const method = MEDIA_METHOD_MAP.photo; // "sendPhoto"
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
- `buildSendMessageBody(message: TelegramMessage): Record<string, unknown>`
|
||||
- Always emits `chat_id` and `text`.
|
||||
- Emits `parse_mode`, `disable_web_page_preview`, `disable_notification`,
|
||||
`reply_to_message_id`, `reply_markup` only when the corresponding camelCase
|
||||
field is truthy.
|
||||
- `buildReplyMarkup(markup: TelegramReplyMarkup): Record<string, unknown>`
|
||||
- Emits `inline_keyboard` when `inlineKeyboard` is set; each button is
|
||||
`{ text, url?, callback_data? }`.
|
||||
- Emits `keyboard` when `keyboard` is set; each button is
|
||||
`{ text, request_contact?, request_location? }`.
|
||||
- Emits `remove_keyboard: true` / `one_time_keyboard: true` when requested.
|
||||
- `MEDIA_METHOD_MAP: Record<TelegramMediaType, "send<Type>">` — frozen.
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
The helpers are pure: identical input → identical output, no global state,
|
||||
no `Date.now()`/`Math.random()`. That makes the test suite a flat property
|
||||
table — one expectation per option combination — and keeps coverage trivial.
|
||||
The "emit-only-when-truthy" rule is important: Telegram interprets
|
||||
`disable_notification: false` as the silent-mode opt-out, but a payload that
|
||||
never sent the field at all reverts to the chat's default. To match upstream
|
||||
behaviour exactly we drop the field when callers leave it `undefined` /
|
||||
`false` and only include it when the caller explicitly opts in.
|
||||
Reference in New Issue
Block a user