split

break long messages into telegram-sized chunks. adds ctx.sendLong and ctx.replyLong to the context, and also exports a pure split() function for use outside a handler.

installation

terminal
pnpm add @yaebal/split

basic usage

install the splitter() plugin with bot.use(). it adds sendLong and replyLong to every handler's context. both accept the same options as ctx.send / ctx.reply.

bot.ts
import { Bot } from "@yaebal/core";
import { splitter } from "@yaebal/split";

const bot = new Bot(token);
bot.install(splitter()); // adds ctx.sendLong / ctx.replyLong

bot.command("essay", async (ctx) => {
  const text = await fetchLongArticle(); // might be 10 000+ characters
  await ctx.replyLong(text);             // sent as multiple messages automatically
});

custom chunk size

pass a number to splitter() to override the default 4096-character limit. useful for adding padding (captions, parse overhead) or during tests.

bot.ts
// default max is 4096 (telegram's limit); lower it for testing or padding
const bot = new Bot(token);
bot.install(splitter(2000));

ctx.sendLong and ctx.replyLong

both return Promise<Message[]> — one Message per chunk sent.

handler.ts
bot.on("message:text", async (ctx) => {
  const messages = await ctx.sendLong(bigText, { parse_mode: "HTML" });
  // messages: Message[] — one entry per chunk sent
});

the pure split() function

split(text, max?) is exported separately so you can use the splitting logic without a bot context — in tests, pre-processing pipelines, or anywhere you just need the chunks.

util.ts
import { split } from "@yaebal/split";

const chunks = split("hello\nworld\n" + "x".repeat(5000));
// chunks is string[] — no bot, no context needed

splitting rules

the algorithm prefers line breaks over hard cuts:

  • text shorter than or equal to max is returned as a single-element array
  • lines are accumulated until the next line would exceed the limit, then a chunk is flushed
  • a single line that is itself longer than max is hard-split at the byte boundary
  • rejoining all chunks with "\n" reconstructs the original text exactly
split-rules.ts
import { split } from "@yaebal/split";

// prefers breaking on newlines
split("line1\nline2\nline3", 10);
// → ["line1\nline2", "line3"]  (joined until limit, then flushed)

// hard-splits a single line longer than max
split("a".repeat(250), 100);
// → ["a".repeat(100), "a".repeat(100), "a".repeat(50)]

api

exportkinddescription
splitter(max?)Plugininstalls sendLong / replyLong on the context
split(text, max?)functionpure splitter — returns string[]
MAX_MESSAGE_LENGTHconst4096 — telegram's per-message text limit
SplitControlinterfacethe shape added to the context by splitter()

SplitControl interface

methodreturnsdescription
sendLong(text, extra?)Promise<Message[]>send text split into chunks via ctx.send
replyLong(text, extra?)Promise<Message[]>reply with text split into chunks via ctx.reply
chunks are sent sequentially, not in parallel — telegram preserves message order within a chat but parallel sends from one bot can arrive out of order.