@mastra/telegram 0.1.0 → 0.1.1-alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/telegram-provider.ts","../src/telegram-client.ts","../src/types.ts","../src/commands.ts","../src/crypto.ts","../src/install-store.ts","../src/index.ts"],"sourcesContent":["import { randomUUID, timingSafeEqual } from 'node:crypto';\nimport { AgentChannels, resolveWaitUntil } from '@mastra/core/channels';\nimport type {\n ChannelAdapterConfig,\n ChannelConnectResult,\n ChannelInstallationInfo,\n ChannelPlatformInfo,\n ChannelProvider,\n StreamingConfig,\n} from '@mastra/core/channels';\nimport type { Agent } from '@mastra/core/agent';\nimport type { Mastra } from '@mastra/core/mastra';\nimport type { ApiRoute, ApiRouteHandler } from '@mastra/core/server';\nimport { InMemoryChannelsStorage } from '@mastra/core/storage';\nimport type { ChannelsStorage } from '@mastra/core/storage';\nimport { createTelegramAdapter } from '@chat-adapter/telegram';\nimport type { TelegramAdapter } from '@chat-adapter/telegram';\nimport { deleteWebhook, generateSecretToken, getMe, setMyCommands, setWebhook } from './telegram-client';\nimport { DEFAULT_COMMANDS, normalizeCommands } from './commands';\nimport { PLATFORM, TelegramInstallStore, toInstallationInfo } from './install-store';\nimport { BOTFATHER_DEEP_LINK, DEFAULT_ALLOWED_UPDATES, TELEGRAM_API_BASE_URL } from './types';\nimport type { TelegramConnectOptions, TelegramInstallation, TelegramMode, TelegramProviderConfig } from './types';\n\n/**\n * Resolve the per-adapter streaming/typing config the provider applies to the\n * Telegram entry in `AgentChannels.adapters`. This is the wrapper's stream\n * binding: enabling `streaming` runs the adapter's post-and-edit\n * (`editMessageText`) chunking loop, and `typingStatus` keeps a `sendChatAction`\n * indicator alive — both default on.\n */\nexport function resolveTelegramAdapterConfig(config: Pick<TelegramProviderConfig, 'streaming' | 'typingStatus'>): {\n streaming: StreamingConfig;\n typingStatus: boolean;\n} {\n return {\n streaming: config.streaming ?? true,\n typingStatus: config.typingStatus ?? true,\n };\n}\n\n/** Header Telegram echoes the per-bot secret on for every webhook POST. */\nconst SECRET_HEADER = 'x-telegram-bot-api-secret-token';\n\n/**\n * Telegram channel provider for Mastra — a {@link ChannelProvider} over\n * `@chat-adapter/telegram`. The adapter handles the Bot API transport (webhook\n * parse, send/edit, typing, rich messages); this provider adds the\n * install/lifecycle layer.\n *\n * Implemented:\n * - **`mastra-telegram-i2g.2`** — multi-token install store (one bot = one\n * agent), `connect()`/`disconnect()`, `getMe` token ingestion.\n * - **`mastra-telegram-i2g.3`** — per-bot `setWebhook` lifecycle,\n * `X-Telegram-Bot-Api-Secret-Token` verification, webhook⇄polling exclusion,\n * and a mounted POST route that delegates to `AgentChannels.handleWebhookEvent`.\n *\n * Later: `setMyCommands` + streaming (`mastra-telegram-i2g.4`).\n *\n * @example\n * ```ts\n * const telegram = new TelegramProvider({ baseUrl: 'https://my-app.example.com' })\n * const mastra = new Mastra({ agents: { myAgent }, channels: { telegram } })\n * await telegram.connect('my-agent', { botToken: '123456:ABC-...' }) // → { type: 'immediate' }\n * ```\n */\nexport class TelegramProvider implements ChannelProvider {\n readonly id = PLATFORM;\n\n #config: TelegramProviderConfig;\n #mastra?: Mastra;\n #store?: TelegramInstallStore;\n /** Live adapters, keyed by installation id. */\n #adapters = new Map<string, TelegramAdapter>();\n /** Cached sync view of whether any active bot is registered (for {@link getInfo}). */\n #configured = false;\n #initPromise: Promise<void> | null = null;\n\n constructor(config: TelegramProviderConfig = {}) {\n this.#config = config;\n }\n\n /**\n * Called by Mastra when this channel is registered.\n * @internal\n */\n __attach(mastra: Mastra): void {\n if (this.#mastra && this.#mastra !== mastra) {\n this.#initPromise = null;\n this.#store = undefined;\n this.#adapters.clear();\n this.#configured = false;\n }\n this.#mastra = mastra;\n }\n\n /**\n * Per-bot webhook route. A single POST endpoint keyed by an opaque\n * `webhookId`; the per-bot secret is verified from the request header, never\n * carried in the URL. Auto-initializes on first hit (mirrors `@mastra/slack`).\n */\n getRoutes(): ApiRoute[] {\n const self = this;\n const withInit = (handler: ApiRouteHandler) => {\n return async ({ mastra }: { mastra: Mastra }): Promise<ApiRouteHandler> => {\n self.#mastra = mastra;\n await self.#autoInitialize();\n return handler.bind(self);\n };\n };\n return [\n {\n path: `/${PLATFORM}/events/:webhookId`,\n method: 'POST',\n requiresAuth: false,\n createHandler: withInit(this.#handleWebhook),\n },\n ];\n }\n\n /** Discovery metadata for the editor UI. */\n getInfo(): ChannelPlatformInfo {\n return {\n id: this.id,\n name: 'Telegram',\n isConfigured: this.#configured,\n connectOptionsSchema: {\n type: 'object',\n properties: {\n botToken: {\n type: 'string',\n description: 'BotFather bot token. Omit to receive a BotFather deep link instead.',\n },\n name: {\n type: 'string',\n description: \"Display name for the bot (defaults to the bot's @username).\",\n },\n },\n },\n };\n }\n\n /**\n * Restore installations from storage: rebuild an adapter per active bot and\n * inject `AgentChannels` so the agent can receive events immediately.\n * Idempotent. Does not re-register webhooks (they persist server-side across\n * restarts); reconnect an agent if its `baseUrl` changed.\n */\n async initialize(): Promise<void> {\n if (this.#initPromise) return this.#initPromise;\n this.#initPromise = this.#doInitialize();\n try {\n await this.#initPromise;\n } catch (err) {\n this.#initPromise = null;\n throw err;\n }\n }\n\n async #doInitialize(): Promise<void> {\n const store = await this.#getStore();\n const active = (await store.list()).filter(i => i.status === 'active');\n this.#configured = active.length > 0;\n for (const installation of active) {\n try {\n await this.#activateInstallation(installation);\n } catch (err) {\n console.error(`[Telegram] Failed to restore installation \"${installation.id}\":`, err);\n }\n }\n }\n\n /**\n * Update runtime provider settings. Telegram has no global auth credential to\n * clear (per-bot tokens are managed via {@link connect}/{@link disconnect}),\n * so `null` is a no-op; an object merges `apiBaseUrl`/`baseUrl` overrides.\n */\n async configure(credentials: { apiBaseUrl?: string; baseUrl?: string } | null): Promise<void> {\n if (credentials === null) return;\n const apiBaseUrlChanged =\n credentials.apiBaseUrl !== undefined && credentials.apiBaseUrl !== this.#config.apiBaseUrl;\n this.#config = { ...this.#config, ...credentials };\n if (!apiBaseUrlChanged) return;\n\n // Live adapters captured the previous apiBaseUrl — tear them down and, if\n // installations were already restored, rebuild them against the new host.\n const wasInitialized = this.#initPromise !== null;\n for (const adapter of this.#adapters.values()) {\n try {\n await adapter.stopPolling();\n } catch (err) {\n console.warn('[Telegram] Failed to stop polling while reconfiguring:', err);\n }\n }\n this.#adapters.clear();\n this.#initPromise = null;\n if (wasInitialized) await this.initialize();\n }\n\n /**\n * Connect an agent to a Telegram bot.\n *\n * - With `options.botToken`: validate via `getMe`, mint a per-bot webhook\n * secret, persist the installation, register the transport (webhook or\n * polling), and return `{ type: 'immediate' }`.\n * - Without a token: persist a pending installation and return\n * `{ type: 'deep_link' }` pointing at BotFather.\n */\n async connect(agentId: string, options: TelegramConnectOptions = {}): Promise<ChannelConnectResult> {\n const store = await this.#getStore();\n const existing = await store.getByAgent(agentId);\n if (existing?.status === 'active') {\n throw new Error(`Agent \"${agentId}\" is already connected to Telegram. Disconnect first to reconnect.`);\n }\n\n if (!options.botToken) {\n const installationId = existing?.id ?? randomUUID();\n await store.save({\n id: installationId,\n agentId,\n webhookId: existing?.webhookId ?? randomUUID(),\n status: 'pending',\n installedAt: existing?.installedAt ?? new Date(),\n });\n return { type: 'deep_link', url: BOTFATHER_DEEP_LINK, installationId };\n }\n\n const me = await getMe(options.botToken, this.#apiBaseUrl());\n const installationId = existing?.id ?? randomUUID();\n const webhookId = existing?.webhookId ?? randomUUID();\n const baseUrl = this.#getBaseUrl();\n const mode = this.#resolveMode(baseUrl);\n if (mode === 'webhook' && !baseUrl) {\n throw new Error(\n 'TelegramProvider needs a baseUrl to register a webhook. Set `baseUrl`, configure the Mastra server, or use `mode: \"polling\"`.',\n );\n }\n const webhookUrl = mode === 'webhook' ? `${baseUrl}/${PLATFORM}/events/${webhookId}` : undefined;\n const commands = normalizeCommands(options.commands ?? this.#config.commands ?? DEFAULT_COMMANDS);\n const installation: TelegramInstallation = {\n id: installationId,\n agentId,\n webhookId,\n status: 'active',\n botToken: options.botToken,\n secretToken: generateSecretToken(),\n username: options.name ?? me.username ?? me.first_name,\n webhookUrl,\n commands: commands.length ? commands : undefined,\n installedAt: existing?.installedAt ?? new Date(),\n };\n\n // Register the transport before persisting so a Bot API failure surfaces to\n // the caller instead of leaving a half-connected install.\n await this.#registerTransport(installation, mode);\n await this.#registerCommands(installation);\n await store.save(installation);\n await this.#activateInstallation(installation);\n this.#configured = true;\n await this.#config.onInstall?.(installation);\n return { type: 'immediate', installationId };\n }\n\n /** Disconnect an agent from Telegram, removing its webhook and installation. */\n async disconnect(agentId: string): Promise<void> {\n const store = await this.#getStore();\n const existing = await store.getByAgent(agentId);\n if (!existing) {\n throw new Error(`No Telegram installation found for agent \"${agentId}\"`);\n }\n // Stop the polling loop (no-op in webhook mode) so it isn't orphaned.\n const adapter = this.#adapters.get(existing.id);\n if (adapter) {\n try {\n await adapter.stopPolling();\n } catch (err) {\n console.warn(`[Telegram] Failed to stop polling for agent \"${agentId}\":`, err);\n }\n }\n if (existing.botToken) {\n try {\n await deleteWebhook(existing.botToken, true, this.#apiBaseUrl());\n } catch (err) {\n console.warn(`[Telegram] Failed to delete webhook for agent \"${agentId}\":`, err);\n }\n }\n this.#adapters.delete(existing.id);\n await store.deleteByAgent(agentId);\n this.#configured = (await store.list()).some(i => i.status === 'active');\n }\n\n /** List installations (public info only — no tokens or secrets). */\n async listInstallations(): Promise<ChannelInstallationInfo[]> {\n const store = await this.#getStore();\n const installations = await store.list();\n return installations.map(toInstallationInfo);\n }\n\n /**\n * Get the full installation for an agent (includes the bot token / secret).\n * Returns `null` if the agent has no Telegram installation. Mirrors\n * `SlackProvider.getInstallation`.\n */\n async getInstallation(agentId: string): Promise<TelegramInstallation | null> {\n const store = await this.#getStore();\n return (await store.getByAgent(agentId)) ?? null;\n }\n\n /**\n * Whether at least one bot is actively registered. Mirrors\n * `SlackProvider.isConfigured` (Telegram has no global credential to check —\n * \"configured\" means an active installation exists).\n */\n isConfigured(): boolean {\n return this.#configured;\n }\n\n /**\n * Get the live `TelegramAdapter` for an installation id, if one is active.\n * Used for message formatting/posting. Mirrors `SlackProvider.getAdapter`.\n */\n getAdapter(installationId: string): TelegramAdapter | undefined {\n return this.#adapters.get(installationId);\n }\n\n // ===========================================================================\n // Webhook handling\n // ===========================================================================\n\n async #handleWebhook(c: {\n req: { param: (k: string) => string | undefined; header: (k: string) => string | undefined; raw: Request };\n json: (body: unknown, status?: number) => Response;\n }): Promise<Response> {\n const webhookId = c.req.param('webhookId');\n if (!webhookId) return c.json({ ok: false, error: 'Missing webhookId' }, 400);\n\n const store = await this.#getStore();\n const installation = await store.getByWebhookId(webhookId);\n if (!installation || installation.status !== 'active') {\n return c.json({ ok: false, error: 'Unknown webhook' }, 404);\n }\n\n // Verify the shared secret on every POST (constant-time), before any work.\n const provided = c.req.header(SECRET_HEADER);\n if (!secretMatches(provided, installation.secretToken)) {\n return c.json({ ok: false, error: 'Invalid secret token' }, 401);\n }\n\n const agent = this.#resolveAgent(installation.agentId);\n if (!agent || !this.#mastra) {\n // Verified but nothing to route to — ack so Telegram stops retrying.\n return c.json({ ok: true });\n }\n\n const adapter = this.#getOrCreateAdapter(installation);\n let channels = agent.getChannels();\n if (!channels || channels.adapters[PLATFORM] !== adapter) {\n channels = this.#createAgentChannels(agent, adapter);\n await channels.initialize(this.#mastra);\n }\n\n const waitUntil = this.#config.waitUntil ?? resolveWaitUntil(c as never);\n try {\n return await channels.handleWebhookEvent(PLATFORM, c.req.raw, waitUntil ? { waitUntil } : undefined);\n } catch (err) {\n console.error('[Telegram] Error delegating to AgentChannels:', err);\n return c.json({ ok: true });\n }\n }\n\n // ===========================================================================\n // Internals\n // ===========================================================================\n\n #apiBaseUrl(): string {\n return this.#config.apiBaseUrl ?? TELEGRAM_API_BASE_URL;\n }\n\n #resolveMode(baseUrl: string | undefined): Exclude<TelegramMode, 'auto'> {\n const mode = this.#config.mode ?? 'auto';\n if (mode === 'auto') return baseUrl ? 'webhook' : 'polling';\n return mode;\n }\n\n /** Register (or clear) the receive transport for a bot, enforcing the exclusion. */\n async #registerTransport(installation: TelegramInstallation, mode: Exclude<TelegramMode, 'auto'>): Promise<void> {\n if (!installation.botToken) return;\n if (mode === 'webhook' && installation.webhookUrl && installation.secretToken) {\n await setWebhook(\n installation.botToken,\n {\n url: installation.webhookUrl,\n secretToken: installation.secretToken,\n allowedUpdates: this.#config.allowedUpdates ?? [...DEFAULT_ALLOWED_UPDATES],\n dropPendingUpdates: true,\n },\n this.#apiBaseUrl(),\n );\n } else {\n // Polling: clear any existing webhook so `getUpdates` can run (exclusion).\n await deleteWebhook(installation.botToken, true, this.#apiBaseUrl());\n }\n }\n\n /** Publish the bot's command list (best-effort — a failure won't block connect). */\n async #registerCommands(installation: TelegramInstallation): Promise<void> {\n if (!installation.botToken || !installation.commands?.length) return;\n try {\n await setMyCommands(\n installation.botToken,\n { commands: installation.commands, scope: this.#config.commandScope },\n this.#apiBaseUrl(),\n );\n } catch (err) {\n console.warn(`[Telegram] Failed to register commands for agent \"${installation.agentId}\":`, err);\n }\n }\n\n #getOrCreateAdapter(installation: TelegramInstallation): TelegramAdapter {\n const existing = this.#adapters.get(installation.id);\n if (existing) return existing;\n const adapter = createTelegramAdapter({\n botToken: installation.botToken,\n secretToken: installation.secretToken,\n userName: installation.username,\n apiBaseUrl: this.#apiBaseUrl(),\n mode: installation.webhookUrl ? 'webhook' : (this.#config.mode ?? 'auto'),\n ...(this.#config.logger !== undefined ? { logger: this.#config.logger } : {}),\n ...(this.#config.longPolling !== undefined ? { longPolling: this.#config.longPolling } : {}),\n });\n this.#adapters.set(installation.id, adapter);\n return adapter;\n }\n\n /** Rebuild the adapter and inject AgentChannels for an active installation. */\n async #activateInstallation(installation: TelegramInstallation): Promise<void> {\n const agent = this.#resolveAgent(installation.agentId);\n const adapter = this.#getOrCreateAdapter(installation);\n if (agent && this.#mastra) {\n const channels = this.#createAgentChannels(agent, adapter);\n await channels.initialize(this.#mastra);\n }\n }\n\n /**\n * Create AgentChannels for an agent with the Telegram adapter, preserving any\n * adapters/config the agent author already configured (mirrors `@mastra/slack`).\n */\n #createAgentChannels(agent: Agent, adapter: TelegramAdapter): AgentChannels {\n const existing = agent.getChannels();\n const existingConfig = existing?.channelConfig;\n const cfg = this.#config;\n // Adapter-level (per-Telegram-entry) overrides: streaming binding + webhook\n // route CORS + error formatting.\n const entry = {\n adapter,\n ...resolveTelegramAdapterConfig(cfg),\n // Telegram has no Block Kit; default tool rendering to plain text so\n // 'cards'/'grouped'/'timeline' don't degrade to fallback text unexpectedly.\n toolDisplay: cfg.toolDisplay ?? 'text',\n ...(cfg.cors !== undefined ? { cors: cfg.cors } : {}),\n ...(cfg.formatError !== undefined ? { formatError: cfg.formatError } : {}),\n } as ChannelAdapterConfig;\n // Channel-level options forwarded to AgentChannels for every connected agent.\n // Prefer this provider's config, falling back to anything the agent author\n // already set so we never clobber an explicit choice with `undefined`.\n const channels = new AgentChannels({\n ...existingConfig,\n adapters: { ...existingConfig?.adapters, [PLATFORM]: entry },\n userName: agent.name,\n handlers: cfg.handlers ?? existingConfig?.handlers,\n inlineMedia: cfg.inlineMedia ?? existingConfig?.inlineMedia,\n inlineLinks: cfg.inlineLinks ?? existingConfig?.inlineLinks,\n state: cfg.state ?? existingConfig?.state,\n threadContext: cfg.threadContext ?? existingConfig?.threadContext,\n chatOptions: cfg.chatOptions ?? existingConfig?.chatOptions,\n tools: cfg.tools ?? existingConfig?.tools,\n resolveResourceId: cfg.resolveResourceId ?? existingConfig?.resolveResourceId,\n waitUntil: cfg.waitUntil ?? existingConfig?.waitUntil,\n resolveWaitUntil: cfg.resolveWaitUntil ?? existingConfig?.resolveWaitUntil,\n });\n agent.setChannels(channels);\n return channels;\n }\n\n async #autoInitialize(): Promise<void> {\n if (!this.#mastra) return;\n await this.initialize();\n }\n\n #resolveAgent(agentId: string): Agent | undefined {\n try {\n return this.#mastra?.getAgentById(agentId) as Agent | undefined;\n } catch {\n return undefined;\n }\n }\n\n async #getStore(): Promise<TelegramInstallStore> {\n if (this.#store) return this.#store;\n const encryptionKey = this.#config.encryptionKey ?? process.env.MASTRA_ENCRYPTION_KEY;\n this.#store = new TelegramInstallStore(await this.#resolveStorage(), encryptionKey);\n return this.#store;\n }\n\n async #resolveStorage(): Promise<ChannelsStorage> {\n if (this.#config.storage) return this.#config.storage;\n const mastraStore = this.#mastra?.getStorage();\n if (mastraStore) {\n try {\n await mastraStore.init();\n const channels = await mastraStore.getStore('channels');\n if (channels) return channels;\n } catch {\n // Fall through to the in-memory store below.\n }\n }\n // No persistent storage available — fall back to in-memory. Installations\n // won't survive a restart; pass `storage` or configure Mastra storage in prod.\n return new InMemoryChannelsStorage();\n }\n\n #getBaseUrl(): string | undefined {\n if (this.#config.baseUrl) return stripTrailingSlash(this.#config.baseUrl);\n const server = this.#mastra?.getServer();\n if (!server) return undefined;\n const protocol = server.studioProtocol ?? 'http';\n const host = server.studioHost ?? server.host ?? 'localhost';\n const port = server.studioPort ?? server.port ?? (Number(process.env.PORT) || 4111);\n const includePort = !((protocol === 'https' && port === 443) || (protocol === 'http' && port === 80));\n return includePort ? `${protocol}://${host}:${port}` : `${protocol}://${host}`;\n }\n}\n\n/** Constant-time comparison of the webhook secret header. */\nfunction secretMatches(provided: string | undefined, expected: string | undefined): boolean {\n if (!provided || !expected) return false;\n const a = Buffer.from(provided);\n const b = Buffer.from(expected);\n return a.length === b.length && timingSafeEqual(a, b);\n}\n\nfunction stripTrailingSlash(url: string): string {\n return url.endsWith('/') ? url.slice(0, -1) : url;\n}\n","import { randomBytes } from 'node:crypto';\nimport type { TelegramUser } from '@chat-adapter/telegram';\nimport { TELEGRAM_API_BASE_URL } from './types';\nimport type { BotCommand } from './types';\n\n/**\n * Minimal Telegram Bot API response envelope. The adapter keeps its own copy\n * internally; this local shape covers just what the provider's control-plane\n * calls (`getMe`, `setWebhook`, `deleteWebhook`, and later `setMyCommands`) need.\n * @see https://core.telegram.org/bots/api#making-requests\n */\ninterface TelegramApiResponse<TResult> {\n ok: boolean;\n result?: TResult;\n description?: string;\n error_code?: number;\n}\n\n/**\n * Call a Bot API method. Sends a `GET` when `payload` is omitted and a JSON\n * `POST` otherwise. Throws when the transport fails or the API returns\n * `ok: false`.\n */\nasync function botApiRequest<TResult>(\n botToken: string,\n method: string,\n apiBaseUrl: string,\n payload?: Record<string, unknown>,\n): Promise<TResult> {\n const init: RequestInit | undefined =\n payload === undefined\n ? undefined\n : { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify(payload) };\n let response: Response;\n try {\n response = await fetch(`${apiBaseUrl}/bot${botToken}/${method}`, {\n ...init,\n signal: AbortSignal.timeout(10_000),\n });\n } catch (cause) {\n // Tag transport/timeout failures so callers can tell them apart from an\n // `ok: false` API response (see getMe).\n throw Object.assign(new Error(`Telegram ${method} request failed`, { cause }), {\n isTransportError: true,\n });\n }\n const body = (await response.json().catch(() => null)) as TelegramApiResponse<TResult> | null;\n if (!response.ok || !body?.ok) {\n const detail = body?.description ?? `HTTP ${response.status}`;\n throw new Error(`Telegram ${method} failed: ${detail}`);\n }\n return body.result as TResult;\n}\n\n/**\n * Validate a bot token via `getMe` and resolve the bot's identity. Throws if\n * the token is rejected or the returned user is not a bot.\n *\n * @see https://core.telegram.org/bots/api#getme\n */\nexport async function getMe(botToken: string, apiBaseUrl: string = TELEGRAM_API_BASE_URL): Promise<TelegramUser> {\n let result: TelegramUser;\n try {\n result = await botApiRequest<TelegramUser>(botToken, 'getMe', apiBaseUrl);\n } catch (cause) {\n // A transport/timeout failure is a connectivity problem, not a token\n // rejection — surface it as-is rather than mislabeling it as a bad token.\n if (cause instanceof Error && (cause as { isTransportError?: boolean }).isTransportError) {\n throw cause;\n }\n throw new Error(`Telegram rejected the bot token: ${cause instanceof Error ? cause.message : String(cause)}`, {\n cause,\n });\n }\n if (!result?.is_bot) {\n throw new Error('Telegram getMe returned a non-bot user; expected a BotFather token');\n }\n return result;\n}\n\n/** Options for {@link setWebhook}. */\nexport interface SetWebhookOptions {\n /** Public HTTPS URL Telegram will POST updates to. */\n url: string;\n /** Shared secret echoed back as `X-Telegram-Bot-Api-Secret-Token` on every POST. */\n secretToken: string;\n /** Update types to receive. Note: `message_reaction` must be listed explicitly. */\n allowedUpdates?: string[];\n /** Drop the backlog of updates queued while the bot was offline. */\n dropPendingUpdates?: boolean;\n}\n\n/**\n * Register a per-bot webhook. Setting a webhook disables `getUpdates`\n * (long-polling) for that bot — the two transports are mutually exclusive.\n *\n * @see https://core.telegram.org/bots/api#setwebhook\n */\nexport async function setWebhook(\n botToken: string,\n options: SetWebhookOptions,\n apiBaseUrl: string = TELEGRAM_API_BASE_URL,\n): Promise<void> {\n await botApiRequest<boolean>(botToken, 'setWebhook', apiBaseUrl, {\n url: options.url,\n secret_token: options.secretToken,\n allowed_updates: options.allowedUpdates,\n drop_pending_updates: options.dropPendingUpdates,\n });\n}\n\n/**\n * Remove a bot's webhook. Required before switching a bot to long-polling\n * (`getUpdates` fails while a webhook is set).\n *\n * @see https://core.telegram.org/bots/api#deletewebhook\n */\nexport async function deleteWebhook(\n botToken: string,\n dropPendingUpdates: boolean = false,\n apiBaseUrl: string = TELEGRAM_API_BASE_URL,\n): Promise<void> {\n await botApiRequest<boolean>(botToken, 'deleteWebhook', apiBaseUrl, {\n drop_pending_updates: dropPendingUpdates,\n });\n}\n\n/** Options for {@link setMyCommands}. */\nexport interface SetMyCommandsOptions {\n /** The command list to publish (replaces the existing set for the scope). */\n commands: BotCommand[];\n /** Command scope (e.g. `{ type: 'all_private_chats' }`). Omit for the default scope. */\n scope?: Record<string, unknown>;\n /** Two-letter language code for a localized command set. */\n languageCode?: string;\n}\n\n/**\n * Publish the bot's command list for a scope.\n *\n * @see https://core.telegram.org/bots/api#setmycommands\n */\nexport async function setMyCommands(\n botToken: string,\n options: SetMyCommandsOptions,\n apiBaseUrl: string = TELEGRAM_API_BASE_URL,\n): Promise<void> {\n await botApiRequest<boolean>(botToken, 'setMyCommands', apiBaseUrl, {\n commands: options.commands,\n scope: options.scope,\n language_code: options.languageCode,\n });\n}\n\n/**\n * Generate a webhook secret token within Telegram's `setWebhook` constraint:\n * 1-256 chars from `[A-Za-z0-9_-]`. base64url of 32 random bytes yields 43\n * such chars.\n *\n * @see https://core.telegram.org/bots/api#setwebhook\n */\nexport function generateSecretToken(): string {\n return randomBytes(32).toString('base64url');\n}\n","import type {\n ChannelAdapterConfig,\n ChannelConfig,\n ChannelHandlers,\n StreamingConfig,\n WaitUntilFn,\n} from '@mastra/core/channels';\nimport type { ChannelsStorage } from '@mastra/core/storage';\nimport type { TelegramAdapterConfig } from '@chat-adapter/telegram';\n\n/** Default Telegram Bot API origin. */\nexport const TELEGRAM_API_BASE_URL = 'https://api.telegram.org';\n\n/**\n * Transport for receiving updates.\n * - `webhook` — register a `setWebhook` and receive POSTs (default for hosted/serverless).\n * - `polling` — long-poll `getUpdates` (the provider clears any webhook first).\n * - `auto` — webhook when a `baseUrl` is available, otherwise polling.\n */\nexport type TelegramMode = 'auto' | 'webhook' | 'polling';\n\n/**\n * Default update types requested from Telegram. `message_reaction` must be\n * listed explicitly (Telegram omits it otherwise).\n */\nexport const DEFAULT_ALLOWED_UPDATES = [\n 'message',\n 'edited_message',\n 'channel_post',\n 'edited_channel_post',\n 'callback_query',\n 'message_reaction',\n] as const;\n\n/**\n * A Telegram bot command as it goes over the wire (`setMyCommands`).\n * @see https://core.telegram.org/bots/api#botcommand\n */\nexport interface BotCommand {\n /** 1-32 chars, lowercase `[a-z0-9_]`, no leading slash. */\n command: string;\n /** 1-256 chars. */\n description: string;\n}\n\n/** Command input accepted by {@link TelegramProvider} — a bare name or a `{ command, description }`. */\nexport type TelegramCommand = string | { command: string; description?: string };\n\n/**\n * Deep link that opens BotFather so an operator can create a new bot with\n * `/newbot`. Telegram has no OAuth: the resulting BotFather token is pasted\n * back into {@link TelegramProvider.connect} to finish the installation.\n */\nexport const BOTFATHER_DEEP_LINK = 'https://t.me/botfather';\n\n/**\n * Configuration for {@link TelegramProvider}.\n *\n * Telegram has no OAuth and no org-level parent credential: a BotFather bot\n * token *is* the credential (one token per bot). Multi-tenancy is therefore a\n * store of bot tokens — see {@link TelegramInstallation}.\n */\nexport interface TelegramProviderConfig {\n /**\n * Public HTTPS base URL used to register per-bot webhooks (`setWebhook`).\n * May be omitted and auto-detected from the Mastra server config, or set later.\n */\n baseUrl?: string;\n /**\n * Persistence for bot installations. Defaults to Mastra's channels storage\n * when the provider is attached to a Mastra instance with storage, and falls\n * back to an in-memory store otherwise (dev/test — not persisted across restarts).\n */\n storage?: ChannelsStorage;\n /**\n * Override the Telegram Bot API origin (e.g. a self-hosted Bot API server or\n * a test mock).\n *\n * @default 'https://api.telegram.org'\n */\n apiBaseUrl?: string;\n /**\n * Passphrase for encrypting `botToken`/`secretToken` at rest (AES-256-GCM).\n * Defaults to the `MASTRA_ENCRYPTION_KEY` env var. When unset, secrets are\n * stored in plaintext (fine for the in-memory dev store; set a key for any\n * persistent backend).\n */\n encryptionKey?: string;\n /**\n * Receive transport. Setting a webhook and long-polling are mutually\n * exclusive; the provider manages the switch per bot.\n *\n * @default 'auto'\n */\n mode?: TelegramMode;\n /**\n * Update types to request in `setWebhook`. Defaults to\n * {@link DEFAULT_ALLOWED_UPDATES}.\n */\n allowedUpdates?: string[];\n /**\n * Long-polling tuning forwarded to the adapter's `getUpdates` loop when running\n * in polling mode (`timeout`, `limit`, `allowedUpdates`, `retryDelayMs`, …).\n * Ignored in webhook mode.\n */\n longPolling?: TelegramAdapterConfig['longPolling'];\n /**\n * Keep the serverless invocation alive while the agent stream runs after the\n * webhook returns 200 (Vercel/AWS Lambda). Cloudflare/Netlify resolve this\n * automatically. See `ChannelConfig.waitUntil`.\n */\n waitUntil?: WaitUntilFn;\n /**\n * Default commands registered via `setMyCommands` for every connected agent\n * (a per-agent list can override via {@link TelegramConnectOptions.commands}).\n * Defaults to the conventional `/start` `/help` `/settings` seed.\n */\n commands?: TelegramCommand[];\n /**\n * Command scope passed to `setMyCommands` (e.g. `{ type: 'all_private_chats' }`).\n * Omitted → Telegram's default scope.\n * @see https://core.telegram.org/bots/api#botcommandscope\n */\n commandScope?: Record<string, unknown>;\n /**\n * Stream agent text to Telegram as it generates, via the adapter's\n * post-and-edit (`editMessageText`) loop. Telegram has no native token\n * streaming, so this chunk-edits the reply (4096-char cap handled by the\n * adapter).\n *\n * @default true\n */\n streaming?: StreamingConfig;\n /**\n * Keep a typing indicator alive during generation (`sendChatAction`, re-sent\n * as it auto-clears). Set `false` to disable.\n *\n * @default true\n */\n typingStatus?: boolean;\n\n // ---------------------------------------------------------------------------\n // AgentChannels passthrough — a curated subset of `ChannelConfig` /\n // `ChannelAdapterConfig` forwarded to every agent connected via this\n // provider, mirroring `@mastra/slack`. All optional; defaults apply when unset.\n // ---------------------------------------------------------------------------\n\n /**\n * Override built-in event handlers (`onDirectMessage`, `onMention`,\n * `onSubscribedMessage`). Forwarded to `AgentChannels`.\n */\n handlers?: ChannelHandlers;\n /** Which media types to send inline to the model. See `ChannelConfig.inlineMedia`. */\n inlineMedia?: ChannelConfig['inlineMedia'];\n /** Promote URLs in message text to file parts. See `ChannelConfig.inlineLinks`. */\n inlineLinks?: ChannelConfig['inlineLinks'];\n /** State adapter for deduplication, locking, and subscriptions. See `ChannelConfig.state`. */\n state?: ChannelConfig['state'];\n /** Fetch recent thread messages when the agent joins mid-conversation. See `ChannelConfig.threadContext`. */\n threadContext?: ChannelConfig['threadContext'];\n /** Additional options passed directly to the Chat SDK. See `ChannelConfig.chatOptions`. */\n chatOptions?: ChannelConfig['chatOptions'];\n /** Resolve the memory `resourceId` before a channel thread is created. See `ChannelConfig.resolveResourceId`. */\n resolveResourceId?: ChannelConfig['resolveResourceId'];\n /**\n * Resolve `waitUntil` from the request's Hono `Context` (serverless runtimes\n * whose `waitUntil` derives from the request). See `ChannelConfig.resolveWaitUntil`.\n */\n resolveWaitUntil?: ChannelConfig['resolveWaitUntil'];\n /** CORS configuration for the generated Telegram webhook route. */\n cors?: ChannelAdapterConfig['cors'];\n /** Override how errors are rendered in Telegram messages. See `ChannelAdapterConfig.formatError`. */\n formatError?: ChannelAdapterConfig['formatError'];\n /**\n * How tool calls are rendered in the reply. Telegram has no Block Kit, so\n * `'cards'`/`'grouped'`/`'timeline'` degrade to plain fallback text — this\n * defaults to `'text'` (unlike Slack's `'grouped'`). See `ChannelAdapterConfig.toolDisplay`.\n *\n * @default 'text'\n */\n toolDisplay?: ChannelAdapterConfig['toolDisplay'];\n /**\n * Whether to expose channel reaction tools (`add_reaction`/`remove_reaction`)\n * to the agent. Set `false` for models without function calling. See `ChannelConfig.tools`.\n *\n * @default true\n */\n tools?: ChannelConfig['tools'];\n /** Logger forwarded to the underlying `TelegramAdapter` for internal error reporting. */\n logger?: TelegramAdapterConfig['logger'];\n /** Called after an agent successfully connects a bot and the installation is persisted. */\n onInstall?: (installation: TelegramInstallation) => void | Promise<void>;\n}\n\n/** Options accepted by {@link TelegramProvider.connect}. */\nexport interface TelegramConnectOptions {\n /**\n * A BotFather bot token. When supplied it is validated via `getMe` and the\n * installation becomes active immediately (`{ type: 'immediate' }`). Omit it\n * to receive a BotFather deep link instead (`{ type: 'deep_link' }`).\n */\n botToken?: string;\n /** Display name for the bot. Defaults to the bot's `@username` from `getMe`. */\n name?: string;\n /**\n * Commands to register via `setMyCommands` for this agent. Overrides\n * {@link TelegramProviderConfig.commands}. Defaults to the `/start` `/help`\n * `/settings` seed when neither is set.\n */\n commands?: TelegramCommand[];\n}\n\n/**\n * A registered Telegram bot bound to a single agent (one bot = one agent).\n * Persisted through {@link TelegramInstallStore}.\n */\nexport interface TelegramInstallation {\n /** Stable installation id. */\n id: string;\n /** The agent this bot is bound to. */\n agentId: string;\n /**\n * Opaque id embedded in the webhook route path (`/telegram/events/:webhookId`).\n * Never the secret — the secret travels only in the request header.\n */\n webhookId: string;\n /** Whether a bot token has been ingested and validated. */\n status: 'active' | 'pending';\n /** BotFather bot token — the full credential. Present once ingested. */\n botToken?: string;\n /**\n * Per-bot webhook shared secret, echoed by Telegram as the\n * `X-Telegram-Bot-Api-Secret-Token` header on every inbound POST.\n */\n secretToken?: string;\n /** The bot's `@username`, resolved from `getMe`. */\n username?: string;\n /** The webhook URL registered with `setWebhook` (M1 — issue `mastra-telegram-i2g.3`). */\n webhookUrl?: string;\n /** Normalized commands registered via `setMyCommands`. */\n commands?: BotCommand[];\n /** When the installation was created. */\n installedAt: Date;\n}\n","import type { BotCommand, TelegramCommand } from './types';\n\n/**\n * Conventional command seed registered when a connect provides none.\n * @see https://core.telegram.org/bots/features#commands\n */\nexport const DEFAULT_COMMANDS: readonly TelegramCommand[] = [\n { command: 'start', description: 'Start a conversation' },\n { command: 'help', description: 'Show what this bot can do' },\n { command: 'settings', description: 'Manage your preferences' },\n];\n\n/**\n * Map user-supplied commands (agent capabilities) to Telegram `BotCommand[]`,\n * enforcing the Bot API constraints: `command` is lowercased, stripped of a\n * leading slash, reduced to `[a-z0-9_]`, and clamped to 1-32 chars;\n * `description` defaults to `Run /<command>` and is clamped to 256 chars.\n * Empty or duplicate command names are dropped.\n */\nexport function normalizeCommands(raw: readonly TelegramCommand[] | undefined): BotCommand[] {\n if (!raw) return [];\n const seen = new Set<string>();\n const commands: BotCommand[] = [];\n for (const item of raw) {\n const input = typeof item === 'string' ? { command: item } : item;\n const command = input.command\n .replace(/^\\//, '')\n .toLowerCase()\n .replace(/[^a-z0-9_]/g, '')\n .slice(0, 32);\n if (!command || seen.has(command)) continue;\n seen.add(command);\n const description = (input.description?.trim() || `Run /${command}`).slice(0, 256);\n commands.push({ command, description });\n }\n return commands;\n}\n","import { createCipheriv, createDecipheriv, hkdfSync, randomBytes } from 'node:crypto';\n\n/**\n * Opt-in AES-256-GCM encryption for installation secrets at rest, with\n * HKDF-SHA256 key derivation (mirrors `@mastra/slack`'s `crypto.ts`). Each value\n * gets a fresh random 16-byte salt + 12-byte IV; the salt travels in the\n * ciphertext, so the same passphrase never derives the same key twice. The\n * algorithm prefix lets plaintext and encrypted values coexist during migration,\n * so {@link decrypt} can no-op on plaintext.\n *\n * Format: `aes-256-gcm-hkdf:base64(salt):base64(iv):base64(authTag):base64(ciphertext)`\n */\nconst ALGO_PREFIX = 'aes-256-gcm-hkdf';\nconst HKDF_INFO = 'mastra-telegram-encryption';\n\nfunction deriveKey(passphrase: string, salt: Buffer): Buffer {\n return Buffer.from(hkdfSync('sha256', passphrase, salt, HKDF_INFO, 32));\n}\n\n/** Whether a stored value was produced by {@link encrypt}. */\nexport function isEncrypted(value: string): boolean {\n return value.startsWith(`${ALGO_PREFIX}:`);\n}\n\n/** Encrypt a UTF-8 string with a per-value random salt + IV. */\nexport function encrypt(plaintext: string, passphrase: string): string {\n const salt = randomBytes(16);\n const iv = randomBytes(12);\n const cipher = createCipheriv('aes-256-gcm', deriveKey(passphrase, salt), iv);\n const enc = Buffer.concat([cipher.update(plaintext, 'utf8'), cipher.final()]);\n const tag = cipher.getAuthTag();\n return `${ALGO_PREFIX}:${salt.toString('base64')}:${iv.toString('base64')}:${tag.toString('base64')}:${enc.toString('base64')}`;\n}\n\n/** Decrypt a value from {@link encrypt}. Plaintext (unprefixed) is returned unchanged. */\nexport function decrypt(value: string, passphrase: string): string {\n if (!isEncrypted(value)) return value;\n const [, saltB64, ivB64, tagB64, ctB64] = value.split(':');\n if (!saltB64 || !ivB64 || !tagB64 || ctB64 === undefined) {\n throw new Error('Invalid ciphertext payload');\n }\n const decipher = createDecipheriv(\n 'aes-256-gcm',\n deriveKey(passphrase, Buffer.from(saltB64, 'base64')),\n Buffer.from(ivB64, 'base64'),\n );\n decipher.setAuthTag(Buffer.from(tagB64, 'base64'));\n return Buffer.concat([decipher.update(Buffer.from(ctB64, 'base64')), decipher.final()]).toString('utf8');\n}\n","import type { ChannelInstallationInfo } from '@mastra/core/channels';\nimport type { ChannelInstallation, ChannelsStorage } from '@mastra/core/storage';\nimport type { BotCommand, TelegramInstallation } from './types';\nimport { decrypt, encrypt, isEncrypted } from './crypto';\n\n/** Platform identifier used for every stored record and route. */\nexport const PLATFORM = 'telegram';\n\n/** Per-bot secret fields serialized into a {@link ChannelInstallation.data} blob. */\ninterface TelegramInstallationData {\n botToken?: string;\n secretToken?: string;\n username?: string;\n webhookUrl?: string;\n commands?: BotCommand[];\n}\n\n/**\n * Persistence for Telegram bot installations, layered over the platform-agnostic\n * `ChannelsStorage` (the same store `@mastra/slack` uses). Installations are\n * keyed by agent — one bot = one agent — and the per-bot secret fields live in\n * the record's `data` blob. When an `encryptionKey` is supplied, `botToken` and\n * `secretToken` are AES-256-GCM encrypted at rest.\n */\nexport class TelegramInstallStore {\n constructor(\n private readonly storage: ChannelsStorage,\n private readonly encryptionKey?: string,\n ) {}\n\n /** The active or pending installation for an agent, if any. */\n async getByAgent(agentId: string): Promise<TelegramInstallation | null> {\n const record = await this.storage.getInstallationByAgent(PLATFORM, agentId);\n return record ? this.#fromRecord(record) : null;\n }\n\n /** Look up an installation by the routing id in its webhook path (M1 dispatch). */\n async getByWebhookId(webhookId: string): Promise<TelegramInstallation | null> {\n const record = await this.storage.getInstallationByWebhookId(webhookId);\n return record && record.platform === PLATFORM ? this.#fromRecord(record) : null;\n }\n\n /** Insert or replace an installation. */\n async save(installation: TelegramInstallation): Promise<void> {\n await this.storage.saveInstallation(this.#toRecord(installation));\n }\n\n /** All Telegram installations (active and pending). */\n async list(): Promise<TelegramInstallation[]> {\n const records = await this.storage.listInstallations(PLATFORM);\n return records.map(r => this.#fromRecord(r));\n }\n\n /** Remove an agent's installation, if present. */\n async deleteByAgent(agentId: string): Promise<void> {\n const record = await this.storage.getInstallationByAgent(PLATFORM, agentId);\n if (record) await this.storage.deleteInstallation(record.id);\n }\n\n #enc(value: string | undefined): string | undefined {\n return value && this.encryptionKey ? encrypt(value, this.encryptionKey) : value;\n }\n\n #dec(value: string | undefined): string | undefined {\n if (!value) return value;\n if (!this.encryptionKey) {\n if (isEncrypted(value)) {\n throw new Error(\n 'Telegram installation secrets are encrypted at rest, but no encryption key is configured. Set `encryptionKey` on TelegramProvider or MASTRA_ENCRYPTION_KEY.',\n );\n }\n return value;\n }\n return decrypt(value, this.encryptionKey);\n }\n\n #toRecord(install: TelegramInstallation): ChannelInstallation {\n const data: TelegramInstallationData = {\n botToken: this.#enc(install.botToken),\n secretToken: this.#enc(install.secretToken),\n username: install.username,\n webhookUrl: install.webhookUrl,\n commands: install.commands,\n };\n return {\n id: install.id,\n platform: PLATFORM,\n agentId: install.agentId,\n status: install.status,\n webhookId: install.webhookId,\n data: data as Record<string, unknown>,\n createdAt: install.installedAt,\n updatedAt: new Date(),\n };\n }\n\n #fromRecord(record: ChannelInstallation): TelegramInstallation {\n const data = (record.data ?? {}) as TelegramInstallationData;\n return {\n id: record.id,\n agentId: record.agentId,\n webhookId: record.webhookId ?? '',\n status: record.status === 'active' ? 'active' : 'pending',\n botToken: this.#dec(data.botToken),\n secretToken: this.#dec(data.secretToken),\n username: data.username,\n webhookUrl: data.webhookUrl,\n commands: data.commands,\n installedAt: record.createdAt,\n };\n }\n}\n\n/** Project an installation to its public, secret-free info for the editor UI. */\nexport function toInstallationInfo(install: TelegramInstallation): ChannelInstallationInfo {\n return {\n id: install.id,\n platform: PLATFORM,\n agentId: install.agentId,\n status: install.status,\n displayName: install.username,\n installedAt: install.installedAt,\n };\n}\n","export { TelegramProvider, resolveTelegramAdapterConfig } from './telegram-provider';\nexport { TelegramInstallStore, toInstallationInfo, PLATFORM } from './install-store';\nexport { getMe, generateSecretToken, setWebhook, deleteWebhook, setMyCommands } from './telegram-client';\nexport type { SetWebhookOptions, SetMyCommandsOptions } from './telegram-client';\nexport { DEFAULT_COMMANDS, normalizeCommands } from './commands';\nexport { BOTFATHER_DEEP_LINK, TELEGRAM_API_BASE_URL, DEFAULT_ALLOWED_UPDATES } from './types';\nexport type {\n TelegramProviderConfig,\n TelegramConnectOptions,\n TelegramInstallation,\n TelegramMode,\n TelegramCommand,\n BotCommand,\n} from './types';\n\n// Re-export the underlying adapter for convenience (parity with @mastra/slack).\nexport { createTelegramAdapter, TelegramAdapter } from '@chat-adapter/telegram';\n"],"mappings":"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","names":["randomBytes","installationId","createTelegramAdapter"]}
1
+ {"version":3,"file":"index.js","names":["#fromRecord","#toRecord","#enc","#dec","#config","#mastra","#initPromise","#store","#adapters","#configured","#autoInitialize","#handleWebhook","#doInitialize","#getStore","#activateInstallation","#apiBaseUrl","#getBaseUrl","#resolveMode","#registerTransport","#registerCommands","#resolveAgent","#getOrCreateAdapter","#createAgentChannels","createTelegramAdapter","#resolveStorage"],"sources":["../src/types.ts","../src/telegram-client.ts","../src/commands.ts","../src/crypto.ts","../src/install-store.ts","../src/telegram-provider.ts"],"sourcesContent":["import type {\n ChannelAdapterConfig,\n ChannelConfig,\n ChannelHandlers,\n StreamingConfig,\n WaitUntilFn,\n} from '@mastra/core/channels';\nimport type { ChannelsStorage } from '@mastra/core/storage';\nimport type { TelegramAdapterConfig } from '@chat-adapter/telegram';\n\n/** Default Telegram Bot API origin. */\nexport const TELEGRAM_API_BASE_URL = 'https://api.telegram.org';\n\n/**\n * Transport for receiving updates.\n * - `webhook` — register a `setWebhook` and receive POSTs (default for hosted/serverless).\n * - `polling` — long-poll `getUpdates` (the provider clears any webhook first).\n * - `auto` — webhook when a `baseUrl` is available, otherwise polling.\n */\nexport type TelegramMode = 'auto' | 'webhook' | 'polling';\n\n/**\n * Default update types requested from Telegram. `message_reaction` must be\n * listed explicitly (Telegram omits it otherwise).\n */\nexport const DEFAULT_ALLOWED_UPDATES = [\n 'message',\n 'edited_message',\n 'channel_post',\n 'edited_channel_post',\n 'callback_query',\n 'message_reaction',\n] as const;\n\n/**\n * A Telegram bot command as it goes over the wire (`setMyCommands`).\n * @see https://core.telegram.org/bots/api#botcommand\n */\nexport interface BotCommand {\n /** 1-32 chars, lowercase `[a-z0-9_]`, no leading slash. */\n command: string;\n /** 1-256 chars. */\n description: string;\n}\n\n/** Command input accepted by {@link TelegramProvider} — a bare name or a `{ command, description }`. */\nexport type TelegramCommand = string | { command: string; description?: string };\n\n/**\n * Deep link that opens BotFather so an operator can create a new bot with\n * `/newbot`. Telegram has no OAuth: the resulting BotFather token is pasted\n * back into {@link TelegramProvider.connect} to finish the installation.\n */\nexport const BOTFATHER_DEEP_LINK = 'https://t.me/botfather';\n\n/**\n * Configuration for {@link TelegramProvider}.\n *\n * Telegram has no OAuth and no org-level parent credential: a BotFather bot\n * token *is* the credential (one token per bot). Multi-tenancy is therefore a\n * store of bot tokens — see {@link TelegramInstallation}.\n */\nexport interface TelegramProviderConfig {\n /**\n * Public HTTPS base URL used to register per-bot webhooks (`setWebhook`).\n * May be omitted and auto-detected from the Mastra server config, or set later.\n */\n baseUrl?: string;\n /**\n * Persistence for bot installations. Defaults to Mastra's channels storage\n * when the provider is attached to a Mastra instance with storage, and falls\n * back to an in-memory store otherwise (dev/test — not persisted across restarts).\n */\n storage?: ChannelsStorage;\n /**\n * Override the Telegram Bot API origin (e.g. a self-hosted Bot API server or\n * a test mock).\n *\n * @default 'https://api.telegram.org'\n */\n apiBaseUrl?: string;\n /**\n * Passphrase for encrypting `botToken`/`secretToken` at rest (AES-256-GCM).\n * Defaults to the `MASTRA_ENCRYPTION_KEY` env var. When unset, secrets are\n * stored in plaintext (fine for the in-memory dev store; set a key for any\n * persistent backend).\n */\n encryptionKey?: string;\n /**\n * Receive transport. Setting a webhook and long-polling are mutually\n * exclusive; the provider manages the switch per bot.\n *\n * @default 'auto'\n */\n mode?: TelegramMode;\n /**\n * Update types to request in `setWebhook`. Defaults to\n * {@link DEFAULT_ALLOWED_UPDATES}.\n */\n allowedUpdates?: string[];\n /**\n * Long-polling tuning forwarded to the adapter's `getUpdates` loop when running\n * in polling mode (`timeout`, `limit`, `allowedUpdates`, `retryDelayMs`, …).\n * Ignored in webhook mode.\n */\n longPolling?: TelegramAdapterConfig['longPolling'];\n /**\n * Keep the serverless invocation alive while the agent stream runs after the\n * webhook returns 200 (Vercel/AWS Lambda). Cloudflare/Netlify resolve this\n * automatically. See `ChannelConfig.waitUntil`.\n */\n waitUntil?: WaitUntilFn;\n /**\n * Default commands registered via `setMyCommands` for every connected agent\n * (a per-agent list can override via {@link TelegramConnectOptions.commands}).\n * Defaults to the conventional `/start` `/help` `/settings` seed.\n */\n commands?: TelegramCommand[];\n /**\n * Command scope passed to `setMyCommands` (e.g. `{ type: 'all_private_chats' }`).\n * Omitted → Telegram's default scope.\n * @see https://core.telegram.org/bots/api#botcommandscope\n */\n commandScope?: Record<string, unknown>;\n /**\n * Stream agent text to Telegram as it generates, via the adapter's\n * post-and-edit (`editMessageText`) loop. Telegram has no native token\n * streaming, so this chunk-edits the reply (4096-char cap handled by the\n * adapter).\n *\n * @default true\n */\n streaming?: StreamingConfig;\n /**\n * Keep a typing indicator alive during generation (`sendChatAction`, re-sent\n * as it auto-clears). Set `false` to disable.\n *\n * @default true\n */\n typingStatus?: boolean;\n\n // ---------------------------------------------------------------------------\n // AgentChannels passthrough — a curated subset of `ChannelConfig` /\n // `ChannelAdapterConfig` forwarded to every agent connected via this\n // provider, mirroring `@mastra/slack`. All optional; defaults apply when unset.\n // ---------------------------------------------------------------------------\n\n /**\n * Override built-in event handlers (`onDirectMessage`, `onMention`,\n * `onSubscribedMessage`). Forwarded to `AgentChannels`.\n */\n handlers?: ChannelHandlers;\n /** Which media types to send inline to the model. See `ChannelConfig.inlineMedia`. */\n inlineMedia?: ChannelConfig['inlineMedia'];\n /** Promote URLs in message text to file parts. See `ChannelConfig.inlineLinks`. */\n inlineLinks?: ChannelConfig['inlineLinks'];\n /** State adapter for deduplication, locking, and subscriptions. See `ChannelConfig.state`. */\n state?: ChannelConfig['state'];\n /** Fetch recent thread messages when the agent joins mid-conversation. See `ChannelConfig.threadContext`. */\n threadContext?: ChannelConfig['threadContext'];\n /** Additional options passed directly to the Chat SDK. See `ChannelConfig.chatOptions`. */\n chatOptions?: ChannelConfig['chatOptions'];\n /** Resolve the memory `resourceId` before a channel thread is created. See `ChannelConfig.resolveResourceId`. */\n resolveResourceId?: ChannelConfig['resolveResourceId'];\n /**\n * Resolve `waitUntil` from the request's Hono `Context` (serverless runtimes\n * whose `waitUntil` derives from the request). See `ChannelConfig.resolveWaitUntil`.\n */\n resolveWaitUntil?: ChannelConfig['resolveWaitUntil'];\n /** CORS configuration for the generated Telegram webhook route. */\n cors?: ChannelAdapterConfig['cors'];\n /** Override how errors are rendered in Telegram messages. See `ChannelAdapterConfig.formatError`. */\n formatError?: ChannelAdapterConfig['formatError'];\n /**\n * How tool calls are rendered in the reply. Telegram has no Block Kit, so\n * `'cards'`/`'grouped'`/`'timeline'` degrade to plain fallback text — this\n * defaults to `'text'` (unlike Slack's `'grouped'`). See `ChannelAdapterConfig.toolDisplay`.\n *\n * @default 'text'\n */\n toolDisplay?: ChannelAdapterConfig['toolDisplay'];\n /**\n * Whether to expose channel reaction tools (`add_reaction`/`remove_reaction`)\n * to the agent. Set `false` for models without function calling. See `ChannelConfig.tools`.\n *\n * @default true\n */\n tools?: ChannelConfig['tools'];\n /** Logger forwarded to the underlying `TelegramAdapter` for internal error reporting. */\n logger?: TelegramAdapterConfig['logger'];\n /** Called after an agent successfully connects a bot and the installation is persisted. */\n onInstall?: (installation: TelegramInstallation) => void | Promise<void>;\n}\n\n/** Options accepted by {@link TelegramProvider.connect}. */\nexport interface TelegramConnectOptions {\n /**\n * A BotFather bot token. When supplied it is validated via `getMe` and the\n * installation becomes active immediately (`{ type: 'immediate' }`). Omit it\n * to receive a BotFather deep link instead (`{ type: 'deep_link' }`).\n */\n botToken?: string;\n /** Display name for the bot. Defaults to the bot's `@username` from `getMe`. */\n name?: string;\n /**\n * Commands to register via `setMyCommands` for this agent. Overrides\n * {@link TelegramProviderConfig.commands}. Defaults to the `/start` `/help`\n * `/settings` seed when neither is set.\n */\n commands?: TelegramCommand[];\n}\n\n/**\n * A registered Telegram bot bound to a single agent (one bot = one agent).\n * Persisted through {@link TelegramInstallStore}.\n */\nexport interface TelegramInstallation {\n /** Stable installation id. */\n id: string;\n /** The agent this bot is bound to. */\n agentId: string;\n /**\n * Opaque id embedded in the webhook route path (`/telegram/events/:webhookId`).\n * Never the secret — the secret travels only in the request header.\n */\n webhookId: string;\n /** Whether a bot token has been ingested and validated. */\n status: 'active' | 'pending';\n /** BotFather bot token — the full credential. Present once ingested. */\n botToken?: string;\n /**\n * Per-bot webhook shared secret, echoed by Telegram as the\n * `X-Telegram-Bot-Api-Secret-Token` header on every inbound POST.\n */\n secretToken?: string;\n /** The bot's `@username`, resolved from `getMe`. */\n username?: string;\n /** The webhook URL registered with `setWebhook` (M1 — issue `mastra-telegram-i2g.3`). */\n webhookUrl?: string;\n /** Normalized commands registered via `setMyCommands`. */\n commands?: BotCommand[];\n /** When the installation was created. */\n installedAt: Date;\n}\n","import { randomBytes } from 'node:crypto';\nimport type { TelegramUser } from '@chat-adapter/telegram';\nimport { TELEGRAM_API_BASE_URL } from './types';\nimport type { BotCommand } from './types';\n\n/**\n * Minimal Telegram Bot API response envelope. The adapter keeps its own copy\n * internally; this local shape covers just what the provider's control-plane\n * calls (`getMe`, `setWebhook`, `deleteWebhook`, and later `setMyCommands`) need.\n * @see https://core.telegram.org/bots/api#making-requests\n */\ninterface TelegramApiResponse<TResult> {\n ok: boolean;\n result?: TResult;\n description?: string;\n error_code?: number;\n}\n\n/**\n * Call a Bot API method. Sends a `GET` when `payload` is omitted and a JSON\n * `POST` otherwise. Throws when the transport fails or the API returns\n * `ok: false`.\n */\nasync function botApiRequest<TResult>(\n botToken: string,\n method: string,\n apiBaseUrl: string,\n payload?: Record<string, unknown>,\n): Promise<TResult> {\n const init: RequestInit | undefined =\n payload === undefined\n ? undefined\n : { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify(payload) };\n let response: Response;\n try {\n response = await fetch(`${apiBaseUrl}/bot${botToken}/${method}`, {\n ...init,\n signal: AbortSignal.timeout(10_000),\n });\n } catch (cause) {\n // Tag transport/timeout failures so callers can tell them apart from an\n // `ok: false` API response (see getMe).\n throw Object.assign(new Error(`Telegram ${method} request failed`, { cause }), {\n isTransportError: true,\n });\n }\n const body = (await response.json().catch(() => null)) as TelegramApiResponse<TResult> | null;\n if (!response.ok || !body?.ok) {\n const detail = body?.description ?? `HTTP ${response.status}`;\n throw new Error(`Telegram ${method} failed: ${detail}`);\n }\n return body.result as TResult;\n}\n\n/**\n * Validate a bot token via `getMe` and resolve the bot's identity. Throws if\n * the token is rejected or the returned user is not a bot.\n *\n * @see https://core.telegram.org/bots/api#getme\n */\nexport async function getMe(botToken: string, apiBaseUrl: string = TELEGRAM_API_BASE_URL): Promise<TelegramUser> {\n let result: TelegramUser;\n try {\n result = await botApiRequest<TelegramUser>(botToken, 'getMe', apiBaseUrl);\n } catch (cause) {\n // A transport/timeout failure is a connectivity problem, not a token\n // rejection — surface it as-is rather than mislabeling it as a bad token.\n if (cause instanceof Error && (cause as { isTransportError?: boolean }).isTransportError) {\n throw cause;\n }\n throw new Error(`Telegram rejected the bot token: ${cause instanceof Error ? cause.message : String(cause)}`, {\n cause,\n });\n }\n if (!result?.is_bot) {\n throw new Error('Telegram getMe returned a non-bot user; expected a BotFather token');\n }\n return result;\n}\n\n/** Options for {@link setWebhook}. */\nexport interface SetWebhookOptions {\n /** Public HTTPS URL Telegram will POST updates to. */\n url: string;\n /** Shared secret echoed back as `X-Telegram-Bot-Api-Secret-Token` on every POST. */\n secretToken: string;\n /** Update types to receive. Note: `message_reaction` must be listed explicitly. */\n allowedUpdates?: string[];\n /** Drop the backlog of updates queued while the bot was offline. */\n dropPendingUpdates?: boolean;\n}\n\n/**\n * Register a per-bot webhook. Setting a webhook disables `getUpdates`\n * (long-polling) for that bot — the two transports are mutually exclusive.\n *\n * @see https://core.telegram.org/bots/api#setwebhook\n */\nexport async function setWebhook(\n botToken: string,\n options: SetWebhookOptions,\n apiBaseUrl: string = TELEGRAM_API_BASE_URL,\n): Promise<void> {\n await botApiRequest<boolean>(botToken, 'setWebhook', apiBaseUrl, {\n url: options.url,\n secret_token: options.secretToken,\n allowed_updates: options.allowedUpdates,\n drop_pending_updates: options.dropPendingUpdates,\n });\n}\n\n/**\n * Remove a bot's webhook. Required before switching a bot to long-polling\n * (`getUpdates` fails while a webhook is set).\n *\n * @see https://core.telegram.org/bots/api#deletewebhook\n */\nexport async function deleteWebhook(\n botToken: string,\n dropPendingUpdates: boolean = false,\n apiBaseUrl: string = TELEGRAM_API_BASE_URL,\n): Promise<void> {\n await botApiRequest<boolean>(botToken, 'deleteWebhook', apiBaseUrl, {\n drop_pending_updates: dropPendingUpdates,\n });\n}\n\n/** Options for {@link setMyCommands}. */\nexport interface SetMyCommandsOptions {\n /** The command list to publish (replaces the existing set for the scope). */\n commands: BotCommand[];\n /** Command scope (e.g. `{ type: 'all_private_chats' }`). Omit for the default scope. */\n scope?: Record<string, unknown>;\n /** Two-letter language code for a localized command set. */\n languageCode?: string;\n}\n\n/**\n * Publish the bot's command list for a scope.\n *\n * @see https://core.telegram.org/bots/api#setmycommands\n */\nexport async function setMyCommands(\n botToken: string,\n options: SetMyCommandsOptions,\n apiBaseUrl: string = TELEGRAM_API_BASE_URL,\n): Promise<void> {\n await botApiRequest<boolean>(botToken, 'setMyCommands', apiBaseUrl, {\n commands: options.commands,\n scope: options.scope,\n language_code: options.languageCode,\n });\n}\n\n/**\n * Generate a webhook secret token within Telegram's `setWebhook` constraint:\n * 1-256 chars from `[A-Za-z0-9_-]`. base64url of 32 random bytes yields 43\n * such chars.\n *\n * @see https://core.telegram.org/bots/api#setwebhook\n */\nexport function generateSecretToken(): string {\n return randomBytes(32).toString('base64url');\n}\n","import type { BotCommand, TelegramCommand } from './types';\n\n/**\n * Conventional command seed registered when a connect provides none.\n * @see https://core.telegram.org/bots/features#commands\n */\nexport const DEFAULT_COMMANDS: readonly TelegramCommand[] = [\n { command: 'start', description: 'Start a conversation' },\n { command: 'help', description: 'Show what this bot can do' },\n { command: 'settings', description: 'Manage your preferences' },\n];\n\n/**\n * Map user-supplied commands (agent capabilities) to Telegram `BotCommand[]`,\n * enforcing the Bot API constraints: `command` is lowercased, stripped of a\n * leading slash, reduced to `[a-z0-9_]`, and clamped to 1-32 chars;\n * `description` defaults to `Run /<command>` and is clamped to 256 chars.\n * Empty or duplicate command names are dropped.\n */\nexport function normalizeCommands(raw: readonly TelegramCommand[] | undefined): BotCommand[] {\n if (!raw) return [];\n const seen = new Set<string>();\n const commands: BotCommand[] = [];\n for (const item of raw) {\n const input = typeof item === 'string' ? { command: item } : item;\n const command = input.command\n .replace(/^\\//, '')\n .toLowerCase()\n .replace(/[^a-z0-9_]/g, '')\n .slice(0, 32);\n if (!command || seen.has(command)) continue;\n seen.add(command);\n const description = (input.description?.trim() || `Run /${command}`).slice(0, 256);\n commands.push({ command, description });\n }\n return commands;\n}\n","import { createCipheriv, createDecipheriv, hkdfSync, randomBytes } from 'node:crypto';\n\n/**\n * Opt-in AES-256-GCM encryption for installation secrets at rest, with\n * HKDF-SHA256 key derivation (mirrors `@mastra/slack`'s `crypto.ts`). Each value\n * gets a fresh random 16-byte salt + 12-byte IV; the salt travels in the\n * ciphertext, so the same passphrase never derives the same key twice. The\n * algorithm prefix lets plaintext and encrypted values coexist during migration,\n * so {@link decrypt} can no-op on plaintext.\n *\n * Format: `aes-256-gcm-hkdf:base64(salt):base64(iv):base64(authTag):base64(ciphertext)`\n */\nconst ALGO_PREFIX = 'aes-256-gcm-hkdf';\nconst HKDF_INFO = 'mastra-telegram-encryption';\n\nfunction deriveKey(passphrase: string, salt: Buffer): Buffer {\n return Buffer.from(hkdfSync('sha256', passphrase, salt, HKDF_INFO, 32));\n}\n\n/** Whether a stored value was produced by {@link encrypt}. */\nexport function isEncrypted(value: string): boolean {\n return value.startsWith(`${ALGO_PREFIX}:`);\n}\n\n/** Encrypt a UTF-8 string with a per-value random salt + IV. */\nexport function encrypt(plaintext: string, passphrase: string): string {\n const salt = randomBytes(16);\n const iv = randomBytes(12);\n const cipher = createCipheriv('aes-256-gcm', deriveKey(passphrase, salt), iv);\n const enc = Buffer.concat([cipher.update(plaintext, 'utf8'), cipher.final()]);\n const tag = cipher.getAuthTag();\n return `${ALGO_PREFIX}:${salt.toString('base64')}:${iv.toString('base64')}:${tag.toString('base64')}:${enc.toString('base64')}`;\n}\n\n/** Decrypt a value from {@link encrypt}. Plaintext (unprefixed) is returned unchanged. */\nexport function decrypt(value: string, passphrase: string): string {\n if (!isEncrypted(value)) return value;\n const [, saltB64, ivB64, tagB64, ctB64] = value.split(':');\n if (!saltB64 || !ivB64 || !tagB64 || ctB64 === undefined) {\n throw new Error('Invalid ciphertext payload');\n }\n const decipher = createDecipheriv(\n 'aes-256-gcm',\n deriveKey(passphrase, Buffer.from(saltB64, 'base64')),\n Buffer.from(ivB64, 'base64'),\n );\n decipher.setAuthTag(Buffer.from(tagB64, 'base64'));\n return Buffer.concat([decipher.update(Buffer.from(ctB64, 'base64')), decipher.final()]).toString('utf8');\n}\n","import type { ChannelInstallationInfo } from '@mastra/core/channels';\nimport type { ChannelInstallation, ChannelsStorage } from '@mastra/core/storage';\nimport type { BotCommand, TelegramInstallation } from './types';\nimport { decrypt, encrypt, isEncrypted } from './crypto';\n\n/** Platform identifier used for every stored record and route. */\nexport const PLATFORM = 'telegram';\n\n/** Per-bot secret fields serialized into a {@link ChannelInstallation.data} blob. */\ninterface TelegramInstallationData {\n botToken?: string;\n secretToken?: string;\n username?: string;\n webhookUrl?: string;\n commands?: BotCommand[];\n}\n\n/**\n * Persistence for Telegram bot installations, layered over the platform-agnostic\n * `ChannelsStorage` (the same store `@mastra/slack` uses). Installations are\n * keyed by agent — one bot = one agent — and the per-bot secret fields live in\n * the record's `data` blob. When an `encryptionKey` is supplied, `botToken` and\n * `secretToken` are AES-256-GCM encrypted at rest.\n */\nexport class TelegramInstallStore {\n constructor(\n private readonly storage: ChannelsStorage,\n private readonly encryptionKey?: string,\n ) {}\n\n /** The active or pending installation for an agent, if any. */\n async getByAgent(agentId: string): Promise<TelegramInstallation | null> {\n const record = await this.storage.getInstallationByAgent(PLATFORM, agentId);\n return record ? this.#fromRecord(record) : null;\n }\n\n /** Look up an installation by the routing id in its webhook path (M1 dispatch). */\n async getByWebhookId(webhookId: string): Promise<TelegramInstallation | null> {\n const record = await this.storage.getInstallationByWebhookId(webhookId);\n return record && record.platform === PLATFORM ? this.#fromRecord(record) : null;\n }\n\n /** Insert or replace an installation. */\n async save(installation: TelegramInstallation): Promise<void> {\n await this.storage.saveInstallation(this.#toRecord(installation));\n }\n\n /** All Telegram installations (active and pending). */\n async list(): Promise<TelegramInstallation[]> {\n const records = await this.storage.listInstallations(PLATFORM);\n return records.map(r => this.#fromRecord(r));\n }\n\n /** Remove an agent's installation, if present. */\n async deleteByAgent(agentId: string): Promise<void> {\n const record = await this.storage.getInstallationByAgent(PLATFORM, agentId);\n if (record) await this.storage.deleteInstallation(record.id);\n }\n\n #enc(value: string | undefined): string | undefined {\n return value && this.encryptionKey ? encrypt(value, this.encryptionKey) : value;\n }\n\n #dec(value: string | undefined): string | undefined {\n if (!value) return value;\n if (!this.encryptionKey) {\n if (isEncrypted(value)) {\n throw new Error(\n 'Telegram installation secrets are encrypted at rest, but no encryption key is configured. Set `encryptionKey` on TelegramProvider or MASTRA_ENCRYPTION_KEY.',\n );\n }\n return value;\n }\n return decrypt(value, this.encryptionKey);\n }\n\n #toRecord(install: TelegramInstallation): ChannelInstallation {\n const data: TelegramInstallationData = {\n botToken: this.#enc(install.botToken),\n secretToken: this.#enc(install.secretToken),\n username: install.username,\n webhookUrl: install.webhookUrl,\n commands: install.commands,\n };\n return {\n id: install.id,\n platform: PLATFORM,\n agentId: install.agentId,\n status: install.status,\n webhookId: install.webhookId,\n data: data as Record<string, unknown>,\n createdAt: install.installedAt,\n updatedAt: new Date(),\n };\n }\n\n #fromRecord(record: ChannelInstallation): TelegramInstallation {\n const data = (record.data ?? {}) as TelegramInstallationData;\n return {\n id: record.id,\n agentId: record.agentId,\n webhookId: record.webhookId ?? '',\n status: record.status === 'active' ? 'active' : 'pending',\n botToken: this.#dec(data.botToken),\n secretToken: this.#dec(data.secretToken),\n username: data.username,\n webhookUrl: data.webhookUrl,\n commands: data.commands,\n installedAt: record.createdAt,\n };\n }\n}\n\n/** Project an installation to its public, secret-free info for the editor UI. */\nexport function toInstallationInfo(install: TelegramInstallation): ChannelInstallationInfo {\n return {\n id: install.id,\n platform: PLATFORM,\n agentId: install.agentId,\n status: install.status,\n displayName: install.username,\n installedAt: install.installedAt,\n };\n}\n","import { randomUUID, timingSafeEqual } from 'node:crypto';\nimport { AgentChannels, resolveWaitUntil } from '@mastra/core/channels';\nimport type {\n ChannelAdapterConfig,\n ChannelConnectResult,\n ChannelInstallationInfo,\n ChannelPlatformInfo,\n ChannelProvider,\n StreamingConfig,\n} from '@mastra/core/channels';\nimport type { Agent } from '@mastra/core/agent';\nimport type { Mastra } from '@mastra/core/mastra';\nimport type { ApiRoute, ApiRouteHandler } from '@mastra/core/server';\nimport { InMemoryChannelsStorage } from '@mastra/core/storage';\nimport type { ChannelsStorage } from '@mastra/core/storage';\nimport { createTelegramAdapter } from '@chat-adapter/telegram';\nimport type { TelegramAdapter } from '@chat-adapter/telegram';\nimport { deleteWebhook, generateSecretToken, getMe, setMyCommands, setWebhook } from './telegram-client';\nimport { DEFAULT_COMMANDS, normalizeCommands } from './commands';\nimport { PLATFORM, TelegramInstallStore, toInstallationInfo } from './install-store';\nimport { BOTFATHER_DEEP_LINK, DEFAULT_ALLOWED_UPDATES, TELEGRAM_API_BASE_URL } from './types';\nimport type { TelegramConnectOptions, TelegramInstallation, TelegramMode, TelegramProviderConfig } from './types';\n\n/**\n * Resolve the per-adapter streaming/typing config the provider applies to the\n * Telegram entry in `AgentChannels.adapters`. This is the wrapper's stream\n * binding: enabling `streaming` runs the adapter's post-and-edit\n * (`editMessageText`) chunking loop, and `typingStatus` keeps a `sendChatAction`\n * indicator alive — both default on.\n */\nexport function resolveTelegramAdapterConfig(config: Pick<TelegramProviderConfig, 'streaming' | 'typingStatus'>): {\n streaming: StreamingConfig;\n typingStatus: boolean;\n} {\n return {\n streaming: config.streaming ?? true,\n typingStatus: config.typingStatus ?? true,\n };\n}\n\n/** Header Telegram echoes the per-bot secret on for every webhook POST. */\nconst SECRET_HEADER = 'x-telegram-bot-api-secret-token';\n\n/**\n * Telegram channel provider for Mastra — a {@link ChannelProvider} over\n * `@chat-adapter/telegram`. The adapter handles the Bot API transport (webhook\n * parse, send/edit, typing, rich messages); this provider adds the\n * install/lifecycle layer.\n *\n * Implemented:\n * - **`mastra-telegram-i2g.2`** — multi-token install store (one bot = one\n * agent), `connect()`/`disconnect()`, `getMe` token ingestion.\n * - **`mastra-telegram-i2g.3`** — per-bot `setWebhook` lifecycle,\n * `X-Telegram-Bot-Api-Secret-Token` verification, webhook⇄polling exclusion,\n * and a mounted POST route that delegates to `AgentChannels.handleWebhookEvent`.\n *\n * Later: `setMyCommands` + streaming (`mastra-telegram-i2g.4`).\n *\n * @example\n * ```ts\n * const telegram = new TelegramProvider({ baseUrl: 'https://my-app.example.com' })\n * const mastra = new Mastra({ agents: { myAgent }, channels: { telegram } })\n * await telegram.connect('my-agent', { botToken: '123456:ABC-...' }) // → { type: 'immediate' }\n * ```\n */\nexport class TelegramProvider implements ChannelProvider {\n readonly id = PLATFORM;\n\n #config: TelegramProviderConfig;\n #mastra?: Mastra;\n #store?: TelegramInstallStore;\n /** Live adapters, keyed by installation id. */\n #adapters = new Map<string, TelegramAdapter>();\n /** Cached sync view of whether any active bot is registered (for {@link getInfo}). */\n #configured = false;\n #initPromise: Promise<void> | null = null;\n\n constructor(config: TelegramProviderConfig = {}) {\n this.#config = config;\n }\n\n /**\n * Called by Mastra when this channel is registered.\n * @internal\n */\n __attach(mastra: Mastra): void {\n if (this.#mastra && this.#mastra !== mastra) {\n this.#initPromise = null;\n this.#store = undefined;\n this.#adapters.clear();\n this.#configured = false;\n }\n this.#mastra = mastra;\n }\n\n /**\n * Per-bot webhook route. A single POST endpoint keyed by an opaque\n * `webhookId`; the per-bot secret is verified from the request header, never\n * carried in the URL. Auto-initializes on first hit (mirrors `@mastra/slack`).\n */\n getRoutes(): ApiRoute[] {\n const self = this;\n const withInit = (handler: ApiRouteHandler) => {\n return async ({ mastra }: { mastra: Mastra }): Promise<ApiRouteHandler> => {\n self.#mastra = mastra;\n await self.#autoInitialize();\n return handler.bind(self);\n };\n };\n return [\n {\n path: `/${PLATFORM}/events/:webhookId`,\n method: 'POST',\n requiresAuth: false,\n createHandler: withInit(this.#handleWebhook),\n },\n ];\n }\n\n /** Discovery metadata for the editor UI. */\n getInfo(): ChannelPlatformInfo {\n return {\n id: this.id,\n name: 'Telegram',\n isConfigured: this.#configured,\n connectOptionsSchema: {\n type: 'object',\n properties: {\n botToken: {\n type: 'string',\n description: 'BotFather bot token. Omit to receive a BotFather deep link instead.',\n },\n name: {\n type: 'string',\n description: \"Display name for the bot (defaults to the bot's @username).\",\n },\n },\n },\n };\n }\n\n /**\n * Restore installations from storage: rebuild an adapter per active bot and\n * inject `AgentChannels` so the agent can receive events immediately.\n * Idempotent. Does not re-register webhooks (they persist server-side across\n * restarts); reconnect an agent if its `baseUrl` changed.\n */\n async initialize(): Promise<void> {\n if (this.#initPromise) return this.#initPromise;\n this.#initPromise = this.#doInitialize();\n try {\n await this.#initPromise;\n } catch (err) {\n this.#initPromise = null;\n throw err;\n }\n }\n\n async #doInitialize(): Promise<void> {\n const store = await this.#getStore();\n const active = (await store.list()).filter(i => i.status === 'active');\n this.#configured = active.length > 0;\n for (const installation of active) {\n try {\n await this.#activateInstallation(installation);\n } catch (err) {\n console.error(`[Telegram] Failed to restore installation \"${installation.id}\":`, err);\n }\n }\n }\n\n /**\n * Update runtime provider settings. Telegram has no global auth credential to\n * clear (per-bot tokens are managed via {@link connect}/{@link disconnect}),\n * so `null` is a no-op; an object merges `apiBaseUrl`/`baseUrl` overrides.\n */\n async configure(credentials: { apiBaseUrl?: string; baseUrl?: string } | null): Promise<void> {\n if (credentials === null) return;\n const apiBaseUrlChanged =\n credentials.apiBaseUrl !== undefined && credentials.apiBaseUrl !== this.#config.apiBaseUrl;\n this.#config = { ...this.#config, ...credentials };\n if (!apiBaseUrlChanged) return;\n\n // Live adapters captured the previous apiBaseUrl — tear them down and, if\n // installations were already restored, rebuild them against the new host.\n const wasInitialized = this.#initPromise !== null;\n for (const adapter of this.#adapters.values()) {\n try {\n await adapter.stopPolling();\n } catch (err) {\n console.warn('[Telegram] Failed to stop polling while reconfiguring:', err);\n }\n }\n this.#adapters.clear();\n this.#initPromise = null;\n if (wasInitialized) await this.initialize();\n }\n\n /**\n * Connect an agent to a Telegram bot.\n *\n * - With `options.botToken`: validate via `getMe`, mint a per-bot webhook\n * secret, persist the installation, register the transport (webhook or\n * polling), and return `{ type: 'immediate' }`.\n * - Without a token: persist a pending installation and return\n * `{ type: 'deep_link' }` pointing at BotFather.\n */\n async connect(agentId: string, options: TelegramConnectOptions = {}): Promise<ChannelConnectResult> {\n const store = await this.#getStore();\n const existing = await store.getByAgent(agentId);\n if (existing?.status === 'active') {\n throw new Error(`Agent \"${agentId}\" is already connected to Telegram. Disconnect first to reconnect.`);\n }\n\n if (!options.botToken) {\n const installationId = existing?.id ?? randomUUID();\n await store.save({\n id: installationId,\n agentId,\n webhookId: existing?.webhookId ?? randomUUID(),\n status: 'pending',\n installedAt: existing?.installedAt ?? new Date(),\n });\n return { type: 'deep_link', url: BOTFATHER_DEEP_LINK, installationId };\n }\n\n const me = await getMe(options.botToken, this.#apiBaseUrl());\n const installationId = existing?.id ?? randomUUID();\n const webhookId = existing?.webhookId ?? randomUUID();\n const baseUrl = this.#getBaseUrl();\n const mode = this.#resolveMode(baseUrl);\n if (mode === 'webhook' && !baseUrl) {\n throw new Error(\n 'TelegramProvider needs a baseUrl to register a webhook. Set `baseUrl`, configure the Mastra server, or use `mode: \"polling\"`.',\n );\n }\n const webhookUrl = mode === 'webhook' ? `${baseUrl}/${PLATFORM}/events/${webhookId}` : undefined;\n const commands = normalizeCommands(options.commands ?? this.#config.commands ?? DEFAULT_COMMANDS);\n const installation: TelegramInstallation = {\n id: installationId,\n agentId,\n webhookId,\n status: 'active',\n botToken: options.botToken,\n secretToken: generateSecretToken(),\n username: options.name ?? me.username ?? me.first_name,\n webhookUrl,\n commands: commands.length ? commands : undefined,\n installedAt: existing?.installedAt ?? new Date(),\n };\n\n // Register the transport before persisting so a Bot API failure surfaces to\n // the caller instead of leaving a half-connected install.\n await this.#registerTransport(installation, mode);\n await this.#registerCommands(installation);\n await store.save(installation);\n await this.#activateInstallation(installation);\n this.#configured = true;\n await this.#config.onInstall?.(installation);\n return { type: 'immediate', installationId };\n }\n\n /** Disconnect an agent from Telegram, removing its webhook and installation. */\n async disconnect(agentId: string): Promise<void> {\n const store = await this.#getStore();\n const existing = await store.getByAgent(agentId);\n if (!existing) {\n throw new Error(`No Telegram installation found for agent \"${agentId}\"`);\n }\n // Stop the polling loop (no-op in webhook mode) so it isn't orphaned.\n const adapter = this.#adapters.get(existing.id);\n if (adapter) {\n try {\n await adapter.stopPolling();\n } catch (err) {\n console.warn(`[Telegram] Failed to stop polling for agent \"${agentId}\":`, err);\n }\n }\n if (existing.botToken) {\n try {\n await deleteWebhook(existing.botToken, true, this.#apiBaseUrl());\n } catch (err) {\n console.warn(`[Telegram] Failed to delete webhook for agent \"${agentId}\":`, err);\n }\n }\n this.#adapters.delete(existing.id);\n await store.deleteByAgent(agentId);\n this.#configured = (await store.list()).some(i => i.status === 'active');\n }\n\n /** List installations (public info only — no tokens or secrets). */\n async listInstallations(): Promise<ChannelInstallationInfo[]> {\n const store = await this.#getStore();\n const installations = await store.list();\n return installations.map(toInstallationInfo);\n }\n\n /**\n * Get the full installation for an agent (includes the bot token / secret).\n * Returns `null` if the agent has no Telegram installation. Mirrors\n * `SlackProvider.getInstallation`.\n */\n async getInstallation(agentId: string): Promise<TelegramInstallation | null> {\n const store = await this.#getStore();\n return (await store.getByAgent(agentId)) ?? null;\n }\n\n /**\n * Whether at least one bot is actively registered. Mirrors\n * `SlackProvider.isConfigured` (Telegram has no global credential to check —\n * \"configured\" means an active installation exists).\n */\n isConfigured(): boolean {\n return this.#configured;\n }\n\n /**\n * Get the live `TelegramAdapter` for an installation id, if one is active.\n * Used for message formatting/posting. Mirrors `SlackProvider.getAdapter`.\n */\n getAdapter(installationId: string): TelegramAdapter | undefined {\n return this.#adapters.get(installationId);\n }\n\n // ===========================================================================\n // Webhook handling\n // ===========================================================================\n\n async #handleWebhook(c: {\n req: { param: (k: string) => string | undefined; header: (k: string) => string | undefined; raw: Request };\n json: (body: unknown, status?: number) => Response;\n }): Promise<Response> {\n const webhookId = c.req.param('webhookId');\n if (!webhookId) return c.json({ ok: false, error: 'Missing webhookId' }, 400);\n\n const store = await this.#getStore();\n const installation = await store.getByWebhookId(webhookId);\n if (!installation || installation.status !== 'active') {\n return c.json({ ok: false, error: 'Unknown webhook' }, 404);\n }\n\n // Verify the shared secret on every POST (constant-time), before any work.\n const provided = c.req.header(SECRET_HEADER);\n if (!secretMatches(provided, installation.secretToken)) {\n return c.json({ ok: false, error: 'Invalid secret token' }, 401);\n }\n\n const agent = this.#resolveAgent(installation.agentId);\n if (!agent || !this.#mastra) {\n // Verified but nothing to route to — ack so Telegram stops retrying.\n return c.json({ ok: true });\n }\n\n const adapter = this.#getOrCreateAdapter(installation);\n let channels = agent.getChannels();\n if (!channels || channels.adapters[PLATFORM] !== adapter) {\n channels = this.#createAgentChannels(agent, adapter);\n await channels.initialize(this.#mastra);\n }\n\n const waitUntil = this.#config.waitUntil ?? resolveWaitUntil(c as never);\n try {\n return await channels.handleWebhookEvent(PLATFORM, c.req.raw, waitUntil ? { waitUntil } : undefined);\n } catch (err) {\n console.error('[Telegram] Error delegating to AgentChannels:', err);\n return c.json({ ok: true });\n }\n }\n\n // ===========================================================================\n // Internals\n // ===========================================================================\n\n #apiBaseUrl(): string {\n return this.#config.apiBaseUrl ?? TELEGRAM_API_BASE_URL;\n }\n\n #resolveMode(baseUrl: string | undefined): Exclude<TelegramMode, 'auto'> {\n const mode = this.#config.mode ?? 'auto';\n if (mode === 'auto') return baseUrl ? 'webhook' : 'polling';\n return mode;\n }\n\n /** Register (or clear) the receive transport for a bot, enforcing the exclusion. */\n async #registerTransport(installation: TelegramInstallation, mode: Exclude<TelegramMode, 'auto'>): Promise<void> {\n if (!installation.botToken) return;\n if (mode === 'webhook' && installation.webhookUrl && installation.secretToken) {\n await setWebhook(\n installation.botToken,\n {\n url: installation.webhookUrl,\n secretToken: installation.secretToken,\n allowedUpdates: this.#config.allowedUpdates ?? [...DEFAULT_ALLOWED_UPDATES],\n dropPendingUpdates: true,\n },\n this.#apiBaseUrl(),\n );\n } else {\n // Polling: clear any existing webhook so `getUpdates` can run (exclusion).\n await deleteWebhook(installation.botToken, true, this.#apiBaseUrl());\n }\n }\n\n /** Publish the bot's command list (best-effort — a failure won't block connect). */\n async #registerCommands(installation: TelegramInstallation): Promise<void> {\n if (!installation.botToken || !installation.commands?.length) return;\n try {\n await setMyCommands(\n installation.botToken,\n { commands: installation.commands, scope: this.#config.commandScope },\n this.#apiBaseUrl(),\n );\n } catch (err) {\n console.warn(`[Telegram] Failed to register commands for agent \"${installation.agentId}\":`, err);\n }\n }\n\n #getOrCreateAdapter(installation: TelegramInstallation): TelegramAdapter {\n const existing = this.#adapters.get(installation.id);\n if (existing) return existing;\n const adapter = createTelegramAdapter({\n botToken: installation.botToken,\n secretToken: installation.secretToken,\n userName: installation.username,\n apiBaseUrl: this.#apiBaseUrl(),\n mode: installation.webhookUrl ? 'webhook' : (this.#config.mode ?? 'auto'),\n ...(this.#config.logger !== undefined ? { logger: this.#config.logger } : {}),\n ...(this.#config.longPolling !== undefined ? { longPolling: this.#config.longPolling } : {}),\n });\n this.#adapters.set(installation.id, adapter);\n return adapter;\n }\n\n /** Rebuild the adapter and inject AgentChannels for an active installation. */\n async #activateInstallation(installation: TelegramInstallation): Promise<void> {\n const agent = this.#resolveAgent(installation.agentId);\n const adapter = this.#getOrCreateAdapter(installation);\n if (agent && this.#mastra) {\n const channels = this.#createAgentChannels(agent, adapter);\n await channels.initialize(this.#mastra);\n }\n }\n\n /**\n * Create AgentChannels for an agent with the Telegram adapter, preserving any\n * adapters/config the agent author already configured (mirrors `@mastra/slack`).\n */\n #createAgentChannels(agent: Agent, adapter: TelegramAdapter): AgentChannels {\n const existing = agent.getChannels();\n const existingConfig = existing?.channelConfig;\n const cfg = this.#config;\n // Adapter-level (per-Telegram-entry) overrides: streaming binding + webhook\n // route CORS + error formatting.\n const entry = {\n adapter,\n ...resolveTelegramAdapterConfig(cfg),\n // Telegram has no Block Kit; default tool rendering to plain text so\n // 'cards'/'grouped'/'timeline' don't degrade to fallback text unexpectedly.\n toolDisplay: cfg.toolDisplay ?? 'text',\n ...(cfg.cors !== undefined ? { cors: cfg.cors } : {}),\n ...(cfg.formatError !== undefined ? { formatError: cfg.formatError } : {}),\n } as ChannelAdapterConfig;\n // Channel-level options forwarded to AgentChannels for every connected agent.\n // Prefer this provider's config, falling back to anything the agent author\n // already set so we never clobber an explicit choice with `undefined`.\n const channels = new AgentChannels({\n ...existingConfig,\n adapters: { ...existingConfig?.adapters, [PLATFORM]: entry },\n userName: agent.name,\n handlers: cfg.handlers ?? existingConfig?.handlers,\n inlineMedia: cfg.inlineMedia ?? existingConfig?.inlineMedia,\n inlineLinks: cfg.inlineLinks ?? existingConfig?.inlineLinks,\n state: cfg.state ?? existingConfig?.state,\n threadContext: cfg.threadContext ?? existingConfig?.threadContext,\n chatOptions: cfg.chatOptions ?? existingConfig?.chatOptions,\n tools: cfg.tools ?? existingConfig?.tools,\n resolveResourceId: cfg.resolveResourceId ?? existingConfig?.resolveResourceId,\n waitUntil: cfg.waitUntil ?? existingConfig?.waitUntil,\n resolveWaitUntil: cfg.resolveWaitUntil ?? existingConfig?.resolveWaitUntil,\n });\n agent.setChannels(channels);\n return channels;\n }\n\n async #autoInitialize(): Promise<void> {\n if (!this.#mastra) return;\n await this.initialize();\n }\n\n #resolveAgent(agentId: string): Agent | undefined {\n try {\n return this.#mastra?.getAgentById(agentId) as Agent | undefined;\n } catch {\n return undefined;\n }\n }\n\n async #getStore(): Promise<TelegramInstallStore> {\n if (this.#store) return this.#store;\n const encryptionKey = this.#config.encryptionKey ?? process.env.MASTRA_ENCRYPTION_KEY;\n this.#store = new TelegramInstallStore(await this.#resolveStorage(), encryptionKey);\n return this.#store;\n }\n\n async #resolveStorage(): Promise<ChannelsStorage> {\n if (this.#config.storage) return this.#config.storage;\n const mastraStore = this.#mastra?.getStorage();\n if (mastraStore) {\n try {\n await mastraStore.init();\n const channels = await mastraStore.getStore('channels');\n if (channels) return channels;\n } catch {\n // Fall through to the in-memory store below.\n }\n }\n // No persistent storage available — fall back to in-memory. Installations\n // won't survive a restart; pass `storage` or configure Mastra storage in prod.\n return new InMemoryChannelsStorage();\n }\n\n #getBaseUrl(): string | undefined {\n if (this.#config.baseUrl) return stripTrailingSlash(this.#config.baseUrl);\n const server = this.#mastra?.getServer();\n if (!server) return undefined;\n const protocol = server.studioProtocol ?? 'http';\n const host = server.studioHost ?? server.host ?? 'localhost';\n const port = server.studioPort ?? server.port ?? (Number(process.env.PORT) || 4111);\n const includePort = !((protocol === 'https' && port === 443) || (protocol === 'http' && port === 80));\n return includePort ? `${protocol}://${host}:${port}` : `${protocol}://${host}`;\n }\n}\n\n/** Constant-time comparison of the webhook secret header. */\nfunction secretMatches(provided: string | undefined, expected: string | undefined): boolean {\n if (!provided || !expected) return false;\n const a = Buffer.from(provided);\n const b = Buffer.from(expected);\n return a.length === b.length && timingSafeEqual(a, b);\n}\n\nfunction stripTrailingSlash(url: string): string {\n return url.endsWith('/') ? url.slice(0, -1) : url;\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,14 +1,13 @@
1
1
  {
2
2
  "name": "@mastra/telegram",
3
- "version": "0.1.0",
3
+ "version": "0.1.1-alpha.1",
4
4
  "description": "Telegram integration for Mastra agents — a ChannelProvider over @chat-adapter/telegram with webhooks, secret verification, commands, and streaming replies",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",
7
7
  "main": "dist/index.js",
8
8
  "types": "dist/index.d.ts",
9
9
  "files": [
10
- "dist",
11
- "CHANGELOG.md"
10
+ "dist"
12
11
  ],
13
12
  "exports": {
14
13
  ".": {
@@ -27,11 +26,11 @@
27
26
  },
28
27
  "devDependencies": {
29
28
  "@types/node": "^22.20.1",
30
- "tsup": "^8.5.1",
31
- "typescript": "^6.0.3",
29
+ "tsdown": "0.22.9",
30
+ "typescript": "^7.0.2",
32
31
  "undici": "^6.0.0",
33
32
  "vitest": "^4.1.10",
34
- "@mastra/core": "1.58.0"
33
+ "@mastra/core": "1.64.0-alpha.7"
35
34
  },
36
35
  "peerDependencies": {
37
36
  "@mastra/core": ">=1.22.0 <2.0.0"
@@ -59,8 +58,8 @@
59
58
  "node": ">=22.13.0"
60
59
  },
61
60
  "scripts": {
62
- "build": "tsup",
63
- "dev": "tsup --watch",
61
+ "build": "tsdown",
62
+ "dev": "tsdown --watch",
64
63
  "typecheck": "tsc --noEmit",
65
64
  "test": "vitest run",
66
65
  "test:watch": "vitest"
package/CHANGELOG.md DELETED
@@ -1,55 +0,0 @@
1
- # @mastra/telegram
2
-
3
- ## 0.1.0
4
-
5
- ### Minor Changes
6
-
7
- - Added `@mastra/telegram` for connecting Mastra agents to Telegram bots. It supports multiple bots, webhook or polling delivery, commands, and streaming replies, and ships a dual ESM + CJS build. Set `encryptionKey` or `MASTRA_ENCRYPTION_KEY` to encrypt stored bot tokens and webhook secret tokens at rest. ([#19975](https://github.com/mastra-ai/mastra/pull/19975))
8
-
9
- ```ts
10
- import { Mastra } from '@mastra/core';
11
- import { TelegramProvider } from '@mastra/telegram';
12
-
13
- const telegram = new TelegramProvider();
14
-
15
- export const mastra = new Mastra({
16
- agents: { support },
17
- channels: { telegram },
18
- });
19
-
20
- // Paste a BotFather token to connect an agent instantly:
21
- const result = await telegram.connect('support', { botToken: process.env.TELEGRAM_BOT_TOKEN });
22
- // → { type: 'immediate', installationId: '...' }
23
- ```
24
-
25
- ### Patch Changes
26
-
27
- - Updated dependencies [[`e7109ee`](https://github.com/mastra-ai/mastra/commit/e7109ee6f731bacc79c885906f3c7dca8d8f013a), [`b8ce7ec`](https://github.com/mastra-ai/mastra/commit/b8ce7ec96e39343c6c2f36d12d68a9ad816c09f7), [`2e4624e`](https://github.com/mastra-ai/mastra/commit/2e4624edb6917e61249cb60ee377735e7af7e4a9), [`45a9147`](https://github.com/mastra-ai/mastra/commit/45a914741f578754d79d8b7de7b4e4f304d8e14a), [`a3a3624`](https://github.com/mastra-ai/mastra/commit/a3a3624f646b98e409424d8defccbd334da9e8b8), [`6246914`](https://github.com/mastra-ai/mastra/commit/62469146636911f3cbbe0880bd011c6a897a59a7), [`6445eba`](https://github.com/mastra-ai/mastra/commit/6445eba6020abac681aba1cc9289f446cb400cbe), [`86b7b77`](https://github.com/mastra-ai/mastra/commit/86b7b777980d30f66e1fd134a37d2af4c22e54cc), [`1c75e32`](https://github.com/mastra-ai/mastra/commit/1c75e32f7fc0b9fb6f548b4407feaec8a1440212), [`296dc9a`](https://github.com/mastra-ai/mastra/commit/296dc9af29f3616e786c7825ec32e0df92d754c5), [`f59032a`](https://github.com/mastra-ai/mastra/commit/f59032a73699443555a08a479e7ac578975784f2), [`cdd5c33`](https://github.com/mastra-ai/mastra/commit/cdd5c33ac6c7118a9f139e6dc0e14e6a8ae31658), [`3f73c07`](https://github.com/mastra-ai/mastra/commit/3f73c076727e8c36b4fff7a1b40290fb68957fa8), [`772c0c8`](https://github.com/mastra-ai/mastra/commit/772c0c897cec383258de2e6178147f8014767c7b), [`d7cf7fa`](https://github.com/mastra-ai/mastra/commit/d7cf7fafc1ae1b50bd8462dd0e6c671a8606db93), [`7c1ebb1`](https://github.com/mastra-ai/mastra/commit/7c1ebb15690c4b3f0eabb19077cf8af573311e57), [`0f9a448`](https://github.com/mastra-ai/mastra/commit/0f9a448502157e59f7b76f24360ad497168f5ef8), [`578bf2e`](https://github.com/mastra-ai/mastra/commit/578bf2e6a88e9d5b8bf502204e15a95dfbb679ae), [`c47165c`](https://github.com/mastra-ai/mastra/commit/c47165c983c87594c6952f1fd2fa51a90205034c), [`289f4ce`](https://github.com/mastra-ai/mastra/commit/289f4ce16e3293370440172132c52ee787cbc09f), [`df31eb0`](https://github.com/mastra-ai/mastra/commit/df31eb0c7087d782a0d9346e467f9a4af4b0eef6), [`9571e3a`](https://github.com/mastra-ai/mastra/commit/9571e3a06ed2c5220196460bf82a2129255c3a8b), [`4f16ff8`](https://github.com/mastra-ai/mastra/commit/4f16ff824bf2f9b0ddc93f210477c10c8a4fb1ab), [`b4c89b4`](https://github.com/mastra-ai/mastra/commit/b4c89b4371b0c86da57403ad1a3b3ef0681f3128), [`e6534fa`](https://github.com/mastra-ai/mastra/commit/e6534fab031216f6cb48c4c9907cbfdce9d60bc6), [`210cb7a`](https://github.com/mastra-ai/mastra/commit/210cb7a167998c7bbf72cb3b93e6eb0563330239), [`06b2d87`](https://github.com/mastra-ai/mastra/commit/06b2d87e63bcdd0ed59215c6789692b9b12de376), [`1c67d85`](https://github.com/mastra-ai/mastra/commit/1c67d85e9da8285662f4dbbf47e0378c3fee0747), [`ac01d63`](https://github.com/mastra-ai/mastra/commit/ac01d6355974aec73fdb8781449ed12bac582094), [`80a3324`](https://github.com/mastra-ai/mastra/commit/80a33245d3110204de6f56d61211523ffe338692), [`e44e8f3`](https://github.com/mastra-ai/mastra/commit/e44e8f370b66c339ddcaba946d33da6d3c3f06cd), [`d9d2881`](https://github.com/mastra-ai/mastra/commit/d9d2881ede6dd6c023d144215fc812062aed0890), [`a810a05`](https://github.com/mastra-ai/mastra/commit/a810a058f62ad407cfc1701e0be36ae91145d7cf), [`ba24be6`](https://github.com/mastra-ai/mastra/commit/ba24be662439c331ab23a600041f93803c89eca8), [`842b5fe`](https://github.com/mastra-ai/mastra/commit/842b5fe22b6a7fa811bd14e48eb9af523ac989f2), [`990611b`](https://github.com/mastra-ai/mastra/commit/990611ba76eb876d86c9c594371ae5f02f94b432), [`80bdf3a`](https://github.com/mastra-ai/mastra/commit/80bdf3ae16ade6ff63bde0cb16fa2df8ab7dd4dd), [`c967a5e`](https://github.com/mastra-ai/mastra/commit/c967a5eec150c5dc5418c4a4388982d1fb7ad27c), [`dc4a25d`](https://github.com/mastra-ai/mastra/commit/dc4a25d41af4e2fe97a816070eaec6aa963ab53b), [`9ba1247`](https://github.com/mastra-ai/mastra/commit/9ba12470c77f1c03642d720ce67e517e878f666e), [`fd96298`](https://github.com/mastra-ai/mastra/commit/fd96298a8367622f4ebfcaa97b5b6c1fbbd14564), [`66bbfb5`](https://github.com/mastra-ai/mastra/commit/66bbfb5f05b473d39f88c0e4a481ccac41634f3a), [`dc4a25d`](https://github.com/mastra-ai/mastra/commit/dc4a25d41af4e2fe97a816070eaec6aa963ab53b), [`f8da216`](https://github.com/mastra-ai/mastra/commit/f8da21633e7eb0e31c9ce0fc30567870d19416d3), [`4a09a9c`](https://github.com/mastra-ai/mastra/commit/4a09a9c0474ef643558fcb5f0edc542b82f1cab0), [`5f798b3`](https://github.com/mastra-ai/mastra/commit/5f798b3362e9bdf4d690f85245606e146eef60b9), [`6a84954`](https://github.com/mastra-ai/mastra/commit/6a84954a2667f85b6d59da652dab1bbff007ccb0), [`1e83a47`](https://github.com/mastra-ai/mastra/commit/1e83a4734ab61ba5926af6793e3569a78b72ed37), [`52d8ef0`](https://github.com/mastra-ai/mastra/commit/52d8ef03801f1deb7ee48532fc4190dd4a33916c), [`cdd5c33`](https://github.com/mastra-ai/mastra/commit/cdd5c33ac6c7118a9f139e6dc0e14e6a8ae31658), [`7fdcaa6`](https://github.com/mastra-ai/mastra/commit/7fdcaa66105d64290f9b14432a12ec99f39c4d3a), [`d6c56f9`](https://github.com/mastra-ai/mastra/commit/d6c56f951db3213330b98b0abafa9778c8770e58), [`e08e789`](https://github.com/mastra-ai/mastra/commit/e08e789c1bf4cd2fe46363f7a4728536ceccc9bd), [`bf936e2`](https://github.com/mastra-ai/mastra/commit/bf936e2c89b2ff0dad5695b873ddc009ba96d41e), [`7fb580a`](https://github.com/mastra-ai/mastra/commit/7fb580ac73fbcacf2ff00872a3395f73ae1b9fa5), [`ed5d606`](https://github.com/mastra-ai/mastra/commit/ed5d606739c5e3fbdfa9f272df7809aa5ab43b1d), [`f53d5bd`](https://github.com/mastra-ai/mastra/commit/f53d5bd4885b29e4ac29a428a6044088ea8d6aa3), [`32980a3`](https://github.com/mastra-ai/mastra/commit/32980a3e2413d0274ac244d32c37d910edc13f00), [`01a2943`](https://github.com/mastra-ai/mastra/commit/01a2943a7d886edefdff072bfa51f055bab54437), [`82e3365`](https://github.com/mastra-ai/mastra/commit/82e3365ef7c9bf7bee2e7a7029035ea262d68895), [`6104347`](https://github.com/mastra-ai/mastra/commit/61043473ba6bfd0a25156824e853e13165562e6c), [`35cc901`](https://github.com/mastra-ai/mastra/commit/35cc90102cf834a84827acaf9eee0b6d6d1e2a3b), [`a8b4cf0`](https://github.com/mastra-ai/mastra/commit/a8b4cf02823cffebc4751a53337dfacf097c1ae1), [`9571e3a`](https://github.com/mastra-ai/mastra/commit/9571e3a06ed2c5220196460bf82a2129255c3a8b), [`333785c`](https://github.com/mastra-ai/mastra/commit/333785c93cbb01e42c60167e995457c28897ddbf), [`bda2235`](https://github.com/mastra-ai/mastra/commit/bda22353ee28f2df0eaea555f7cae1549f979c0b), [`efd5c81`](https://github.com/mastra-ai/mastra/commit/efd5c81cc25fde3c2ddd86fc1178deb4ec176e19), [`1b482c2`](https://github.com/mastra-ai/mastra/commit/1b482c2d89244dd758c41e5f927a2b44041388d2), [`45bfb88`](https://github.com/mastra-ai/mastra/commit/45bfb88fd52f1dd3be20e2a38905777c96499c90), [`ff28284`](https://github.com/mastra-ai/mastra/commit/ff2828416f14daff9d956e6a352fdaa23c950979), [`4bcdfaf`](https://github.com/mastra-ai/mastra/commit/4bcdfaf0eac3199d7cb171b0a19a92c9c341eea4), [`e3b9307`](https://github.com/mastra-ai/mastra/commit/e3b9307098daefbfae2a52ae2ef51bc9fc701190), [`d6834c5`](https://github.com/mastra-ai/mastra/commit/d6834c5a7866b16734d23900163c2414ed70d791), [`f33264f`](https://github.com/mastra-ai/mastra/commit/f33264f517ae603279afd5c4251e2b40f6dd3618), [`689f2c4`](https://github.com/mastra-ai/mastra/commit/689f2c4b6c0835fe455702b01d21daa8abcd9331), [`fcd0667`](https://github.com/mastra-ai/mastra/commit/fcd0667a4e378be35c9a1b1eb19cce78fbfd7282), [`cfd0d9e`](https://github.com/mastra-ai/mastra/commit/cfd0d9ec77ec3c69dd96f79cdb579e03d79f22ce), [`acc3513`](https://github.com/mastra-ai/mastra/commit/acc3513b19f79bf0a7ec2998694580edca54086c), [`1670533`](https://github.com/mastra-ai/mastra/commit/1670533986f6bacf567746245348125e3a106448), [`a7eb4a1`](https://github.com/mastra-ai/mastra/commit/a7eb4a11450f6170274ed5141bffe821d4fdd5a6), [`0976933`](https://github.com/mastra-ai/mastra/commit/0976933142333ec78451feef265b68bcb45aa5e7), [`242b945`](https://github.com/mastra-ai/mastra/commit/242b94558777bfbdeb42cbfea84afff0b6ad0633), [`c52d346`](https://github.com/mastra-ai/mastra/commit/c52d3462ec831a5d95926ecd3d3373f5928ad2e5), [`af4636a`](https://github.com/mastra-ai/mastra/commit/af4636a74463275d71c1d13a38f7d2b738f128bf), [`01a2943`](https://github.com/mastra-ai/mastra/commit/01a2943a7d886edefdff072bfa51f055bab54437), [`2eabc09`](https://github.com/mastra-ai/mastra/commit/2eabc097d86d52fbd0123da36a7c874154cc384f), [`0023e79`](https://github.com/mastra-ai/mastra/commit/0023e7919431078280abd11c89d1edeae35fcc69), [`c2ad51e`](https://github.com/mastra-ai/mastra/commit/c2ad51e2467f901eecba8c9f4a45e22a50bd7c18), [`25ca73d`](https://github.com/mastra-ai/mastra/commit/25ca73d25dee7ce9f0ca72939e3a505c4db7257e), [`2f9ef3f`](https://github.com/mastra-ai/mastra/commit/2f9ef3f4ca06fc2dcdd5088c26b7f4da6a016791), [`e7eefcb`](https://github.com/mastra-ai/mastra/commit/e7eefcb162cda7c493e8c3bf43050ead0efbcb2c), [`fea5cae`](https://github.com/mastra-ai/mastra/commit/fea5caedc7e2cfea51784a15e015952692027abf), [`4d7aca2`](https://github.com/mastra-ai/mastra/commit/4d7aca2fe75f225c83d1502d63079568e6ec163f), [`e1cead1`](https://github.com/mastra-ai/mastra/commit/e1cead17b5f3653cf00d2f90cc19b113119c02ba), [`01a2943`](https://github.com/mastra-ai/mastra/commit/01a2943a7d886edefdff072bfa51f055bab54437), [`d9d93b2`](https://github.com/mastra-ai/mastra/commit/d9d93b25e4a65ad5fa153fa35be7ed149c8d587f), [`c4ec889`](https://github.com/mastra-ai/mastra/commit/c4ec889561c0264c43f66d04d587bee4ce35e792), [`4b59f78`](https://github.com/mastra-ai/mastra/commit/4b59f786cbc9a7d1ef07a07517dbd4b96865e99d), [`eeae63e`](https://github.com/mastra-ai/mastra/commit/eeae63e7fbe8e1f237adc69bca6e2ac13c5ca907), [`3dc97ea`](https://github.com/mastra-ai/mastra/commit/3dc97ea415fad353b48a13095fad1835933cc12a), [`94e7ae9`](https://github.com/mastra-ai/mastra/commit/94e7ae970b37c888cd1244ef013292639a2fe6d1), [`e6a2860`](https://github.com/mastra-ai/mastra/commit/e6a2860649cc51f87d32d78b766ae2126446ba07), [`7010c5d`](https://github.com/mastra-ai/mastra/commit/7010c5d15728bf9c5dfe4fb6b1bf80ce23bf143a), [`bab06b1`](https://github.com/mastra-ai/mastra/commit/bab06b18923873a584bdfc71a6b4ec7fb4727fb7), [`3d01cd3`](https://github.com/mastra-ai/mastra/commit/3d01cd387321b6f9c5cac31d487c84bf51b19c78), [`7bf3086`](https://github.com/mastra-ai/mastra/commit/7bf308663f0115ca74ad20554ade740f06640859), [`4c186a0`](https://github.com/mastra-ai/mastra/commit/4c186a017275f45e6ed4c09de0f89550e2d09e8c), [`b0fa077`](https://github.com/mastra-ai/mastra/commit/b0fa077bcbc9b08551846fe372a0d3d15b71ed72), [`0282e16`](https://github.com/mastra-ai/mastra/commit/0282e16115538c8e9b248b90f0748eb01cb5dc98), [`a8dd139`](https://github.com/mastra-ai/mastra/commit/a8dd1391a9fe9a6632c25809ef236980afa9a020), [`6a667b4`](https://github.com/mastra-ai/mastra/commit/6a667b4b7cd6a93fe41fcdd357b08c5a8c09b9ab), [`9be8878`](https://github.com/mastra-ai/mastra/commit/9be8878dcf0388e84fc4873e0eec27bd49b881a4), [`e5786be`](https://github.com/mastra-ai/mastra/commit/e5786be02bb903073082bd9d6da880ebaacc343f), [`2440e09`](https://github.com/mastra-ai/mastra/commit/2440e096ea6c2def1ccc1eb2d0f3f5b88c4af940), [`2093fbd`](https://github.com/mastra-ai/mastra/commit/2093fbd53bb744bae19ec89f6d73db9a66fbe8a7), [`a59049b`](https://github.com/mastra-ai/mastra/commit/a59049b1652a13efff66ac826326b5ed9a550342), [`7bd85ea`](https://github.com/mastra-ai/mastra/commit/7bd85ea7588b71c25ce9f4019c88f8539be5dcbc), [`83fa004`](https://github.com/mastra-ai/mastra/commit/83fa0044bfda8b703a83883dbd8bef204844d13f), [`a463cdf`](https://github.com/mastra-ai/mastra/commit/a463cdf1c95c3059e70f0bff27959e8558bb899d), [`e7a5da4`](https://github.com/mastra-ai/mastra/commit/e7a5da4ef8e4dd452d2f232961b4e682a85ffe43), [`7b4393d`](https://github.com/mastra-ai/mastra/commit/7b4393d557411fdcf07b0e30e5acaf7cc85154ae), [`0ea6b80`](https://github.com/mastra-ai/mastra/commit/0ea6b8001408ce02b56e8be0536b0fd8cbaf8ad2)]:
28
- - @mastra/core@1.58.0
29
-
30
- ## 0.1.0-alpha.0
31
-
32
- ### Minor Changes
33
-
34
- - Added `@mastra/telegram` for connecting Mastra agents to Telegram bots. It supports multiple bots, webhook or polling delivery, commands, and streaming replies, and ships a dual ESM + CJS build. Set `encryptionKey` or `MASTRA_ENCRYPTION_KEY` to encrypt stored bot tokens and webhook secret tokens at rest. ([#19975](https://github.com/mastra-ai/mastra/pull/19975))
35
-
36
- ```ts
37
- import { Mastra } from '@mastra/core';
38
- import { TelegramProvider } from '@mastra/telegram';
39
-
40
- const telegram = new TelegramProvider();
41
-
42
- export const mastra = new Mastra({
43
- agents: { support },
44
- channels: { telegram },
45
- });
46
-
47
- // Paste a BotFather token to connect an agent instantly:
48
- const result = await telegram.connect('support', { botToken: process.env.TELEGRAM_BOT_TOKEN });
49
- // → { type: 'immediate', installationId: '...' }
50
- ```
51
-
52
- ### Patch Changes
53
-
54
- - Updated dependencies [[`66bbfb5`](https://github.com/mastra-ai/mastra/commit/66bbfb5f05b473d39f88c0e4a481ccac41634f3a)]:
55
- - @mastra/core@1.58.0-alpha.10