Telegram Send
Send messages, photos, and documents to Telegram chats and channels via the Telegram Bot API.
Methods:
getMe— verify the bot token and fetch bot identity (smoke test)sendMessage— text with optional MarkdownV2 / HTML formattingsendPhoto— image by URL, Telegramfile_id, or local file pathsendDocument— arbitrary file (PDF, ZIP, …) up to 50 MB
The botToken is stored as a sensitive globalArgument and routed to a
vault automatically. Set defaultChatId on the model instance to avoid
repeating the chat target on every call.
A natural complement to @magistr/telegram-import, which goes the other
direction — importing Telegram channel exports into Obsidian.
| Argument | Type | Description |
|---|---|---|
| text | string | Message text (1-4096 characters) |
| disableWebPagePreview? | boolean | |
| disableNotification? | boolean | |
| replyToMessageId? | number |
| Argument | Type | Description |
|---|---|---|
| chatId? | string | |
| caption? | string | |
| disableNotification? | boolean |
| Argument | Type | Description |
|---|---|---|
| chatId? | string | |
| caption? | string | |
| disableNotification? | boolean |
Resources
2026.08.01.1
Security hardening: closes the HIGH bot-token credential-leak tracked below as a
"Known gap" in the Unreleased entry (filed and planned as the issue-lifecycle
model telegram-send-hardening-richmessage-port).
- Added a module-private
redactToken(message, token)pure helper totelegram_send.ts. It replaces the live/bot<token>/URL segment with/bot<redacted>/, then applies a generic/bot[^/]+/regex backstop so any/bot.../path segment is scrubbed even if the token reaches the message reformatted (re-cased, percent-encoded, or otherwise transformed) rather than byte-for-byte.messageis accepted asunknownand safely coerced to a string — a fetch rejection is not guaranteed to be anErrorwith a string.message(it may be aDOMException, a thrown string, or an arbitrary non-Error value) — so no unsanitized shape can pass through unredacted. telegramJsonandtelegramMultipartnow wrap theirfetch()call in try/catch: a network-layer rejection (DNS failure, TLS error, connection reset) is caught and rethrown with its message redacted viaredactToken, preserving the original rejection ascausefor downstream diagnostics. Only thefetch()call itself is wrapped — theok:falseAPI-error throw (never carries the token, pinned GREEN and covered by property test c) is untouched.- Behavior-preserving otherwise: legitimate sends and the
ok:falseAPI-error path are unchanged. - Tests: flipped the two adversarial suite's former "HONEST GAP pin" tests
(
telegram_send_adversarial_test.ts,telegramJson/getMeandtelegramMultipart/sendPhoto) to assert the fetch-rejection message is now redacted (contains/bot<redacted>/, excludes the raw token, preserves.cause) instead of asserting verbatim propagation. Added directredactTokenunit tests: exact-token redaction, token-free passthrough, the generic backstop for a reformatted token, and non-Error/DOMException/ thrown-string/plain-object coercion (including a case where a non-Error value's own string form embeds the token). All 72 suite tests green; property suite green atFC_NUM_RUNS=5000. README.md: updated the Security note — the token-in-URL fetch-rejection gap is now redacted rather than an open gap.quality.yaml: the byte-frozen-source justification no longer applies (source is modified); ratchet re-measured live.- Deferred, tracked separately: porting
sendRichMessagefrom the homelab dev copy is OUT OF SCOPE for this security fix (its homelab source-of-truth is not in this read-only snapshot, so folding it in would be a blind, unverifiable port). It remains tracked by the issue-lifecycle modeltelegram-send-hardening-richmessage-portas a follow-up.
Release 2026.07.16.2 — align model versions with manifests
Maintenance release across the @magistr extensions. For most packages this
carries no functional change: the only edit is the model's version: field,
brought back in line with its manifest version so the published model type
version and the package version no longer drift.
Functional changes in this release are limited to:
anime-cron: normalizeTitle now strips a ": subtitle" suffix and a trailing parenthesized year before comparison, fixing dedup false-misses where the torrent title carries a subtitle or year that the AniList romaji does not.
arckit: first publish. Standalone ArcKit port — a 12-phase architecture governance state machine with 65 bundled templates, driven by a bundled skill.
Also tracks three extensions (kaiten, observability-agent, music-library) that previously existed only as untracked working-tree directories, recovered from stashes.
- Has README or module doc2/2earned
- README has a code example1/1earned
- README is substantive1/1earned
- Most symbols documented1/1earned
- No slow types (deprecated)1/1earned
- Dependencies pass trust audit2/2earned
- Has description1/1earned
- Platform support declared (or universal)2/2earned
- License declared1/1earned
- Verified public repository2/2earned