# @suaveplan/telegram-client - Telegram Bot API client — send/edit/delete messages, media, inline + custom keyboards, typed errors, injectable fetch + clock, OTel instrumented Telegram Bot API client: send/edit/delete messages, six media variants, inline + custom keyboards, typed errors, injectable `fetch` + `clock`, and OpenTelemetry counters/histograms on every code path. Runtime-agnostic (works in Bun, Node, Deno, browsers). ## Documentation tree - [telegram-bot-client](./src/core/telegram-bot-client/telegram-bot-client.md) — `TelegramBotClient` is the public, runtime-agnostic Telegram Bot API client. It wraps the handful of Bot API endpoints… - [telegram-bot-client](./src/core/telegram-bot-client/telegram-bot-client.md) — `TelegramBotClient` is the public, runtime-agnostic Telegram Bot API client. It wraps the handful of Bot API endpoints… - [errors](./src/errors/telegram-client-error.md) — Defines the namespaced, frozen error-code registry and the typed `TelegramClientError` class used by every runtime fail… - [telegram-client-error](./src/errors/telegram-client-error.md) — Defines the namespaced, frozen error-code registry and the typed `TelegramClientError` class used by every runtime fail… - [types](./src/types/telegram-bot-config.md) — Defines the Zod schema that validates `TelegramBotConfig` at the public construction boundary of `TelegramBotClient`. T… - [telegram-bot-config](./src/types/telegram-bot-config.md) — Defines the Zod schema that validates `TelegramBotConfig` at the public construction boundary of `TelegramBotClient`. T… - [build-bodies](./src/utils/build-bodies.md) — Pure, side-effect-free helpers that translate the camelCase public message / reply-markup shape used by callers into th… - [classify-error](./src/utils/classify-error.md) — Pure helpers that turn an outgoing-protocol failure (HTTP status + Telegram `description` + parsed body) into a stable… ## Installation ```bash bun add @suaveplan/telegram-client ``` ## Quick Start ```ts import { createTelegramBotClient } from "@suaveplan/telegram-client"; const bot = createTelegramBotClient({ token: process.env.TELEGRAM_TOKEN! }); const sent = await bot.sendMessage({ chatId: 12345, text: "Hello", parseMode: "HTML", }); console.log(sent.messageId); ``` ## Modules | Module | Path | Description | |--------|------|-------------| | Client | [src/core/telegram-bot-client/telegram-bot-client.md](src/core/telegram-bot-client/telegram-bot-client.md) | `TelegramBotClient` class, factory, OTel metrics | | Body Builders | [src/utils/build-bodies.md](src/utils/build-bodies.md) | Pure camelCase → snake_case translators | | Error Classifier | [src/utils/classify-error.md](src/utils/classify-error.md) | Pure status + retry-after classifier | | Errors | [src/errors/telegram-client-error.md](src/errors/telegram-client-error.md) | Code registry + typed error class | | Config Schema | [src/types/telegram-bot-config.md](src/types/telegram-bot-config.md) | Zod validation at the boundary | | Types | [src/types/telegram-client.types.md](src/types/telegram-client.types.md) | Public type surface | ## Subpath Exports ```ts import { createTelegramBotClient } from "@suaveplan/telegram-client"; import { TELEGRAM_CLIENT_CODES, TelegramClientError, } from "@suaveplan/telegram-client/errors"; import type { TelegramMessage } from "@suaveplan/telegram-client/types"; ``` ## Error Codes | Code | When | |---|---| | `TELEGRAM_CLIENT.CONFIG_MISSING` | Config rejected by Zod schema (missing token, invalid URL, etc.) | | `TELEGRAM_CLIENT.TIMEOUT` | Request aborted before completion | | `TELEGRAM_CLIENT.AUTH_ERROR` | Telegram returned HTTP 401 | | `TELEGRAM_CLIENT.RATE_LIMITED` | Telegram returned HTTP 429 (`context.retryAfterMs` set if parseable) | | `TELEGRAM_CLIENT.CHAT_NOT_FOUND` | HTTP 404, or HTTP 400 with `chat not found` / `channel not found` | | `TELEGRAM_CLIENT.BOT_BLOCKED` | HTTP 403 with `bot was blocked` / `user is deactivated` | | `TELEGRAM_CLIENT.FORBIDDEN` | Other HTTP 403, or HTTP 400 with `not enough rights` / `forbidden` | | `TELEGRAM_CLIENT.API_ERROR` | Catch-all for unclassified Telegram failures | ## OTel Instruments - Counter `telegram_client.request.total` — keyed by `{ method, outcome }` - Histogram `telegram_client.request.duration_ms` — keyed by `{ method, outcome }` - `outcome ∈ { "success", "error", "timeout" }` Call `resetTelegramClientMetrics()` from tests after replacing the global `MeterProvider` so each test sees a fresh meter. ## Verification - Tests use injected `fetch` / `clock` — no mocks, no network. - 100% istanbul coverage on touched modules.