@gramforge/transport-grammy
v0.1.0
Published
A [grammY](https://grammy.dev)-backed adapter that presents the **same `DeliveryResult` / `LiveMessage` surface** as [`@gramforge/transport-fetch`](../transport-fetch) — so you can swap `createBotClient` for `createGrammyClient` without touching a single
Readme
@gramforge/transport-grammy
A grammY-backed adapter that presents the same
DeliveryResult / LiveMessage surface as
@gramforge/transport-fetch — so you can swap
createBotClient for createGrammyClient without touching a single call site.
grammY owns the HTTP, retries, and serialization; this package only
- renders a core
MessageText/CaptionTextto{ text, entities }via@gramforge/render(formatting travels as entities,parse_modeNONE), - calls the injected grammY
Api, and - adapts grammY's success value / thrown
GrammyError/HttpErrorinto the shared typedDeliveryResultdiscriminated union — nothing ever throws to the caller.
DeliveryResult, LiveMessage, TelegramMessage, and EditMessageResult are
re-exported from @gramforge/transport-fetch; this package never redefines
them. Edit-coalescing (liveMessage) reuses transport-fetch's createLiveMessage
verbatim through the LiveMessagePort seam.
npm-only (native grammy peer + Node); not published to JSR.
Usage
import { Bot } from "grammy";
import { bold, createMessageText, text } from "@gramforge/core";
import { createGrammyClient } from "@gramforge/transport-grammy";
import { match } from "ts-pattern";
const bot = new Bot(process.env.BOT_TOKEN!);
const client = createGrammyClient(bot.api);
const msg = createMessageText([text("build "), bold(text("passed"))]);
if (msg.kind === "ok") {
const result = await client.sendMessage({ chatId, message: msg.value });
match(result)
.with({ kind: "ok" }, () => {})
.with({ kind: "rateLimited" }, (r) => scheduleRetry(r.retryAfterSeconds))
.otherwise((r) => log(r.kind));
}