diff --git a/extensions/telegram-user/src/client.ts b/extensions/telegram-user/src/client.ts index 4716c1969..156083c49 100644 --- a/extensions/telegram-user/src/client.ts +++ b/extensions/telegram-user/src/client.ts @@ -1,26 +1,39 @@ -import { BaseTelegramClient, NodePlatform, TelegramClient } from "@mtcute/node"; +type MtcuteNode = typeof import("@mtcute/node"); -class ClawdbotTelegramUserPlatform extends NodePlatform { - // mtcute's NodePlatform.beforeExit installs SIGINT/SIGTERM handlers that re-send the signal, - // which can race with Clawdbot's graceful shutdown and close sqlite while writes are pending. - // We only hook into process exit events (no signal handlers) and rely on Clawdbot to stop cleanly. - override beforeExit(fn: () => void): () => void { - const onBeforeExit = () => fn(); - const onExit = () => fn(); - process.once("beforeExit", onBeforeExit); - process.once("exit", onExit); - return () => { - process.off("beforeExit", onBeforeExit); - process.off("exit", onExit); - }; - } +let mtcuteNodePromise: Promise | null = null; + +async function loadMtcuteNode(): Promise { + mtcuteNodePromise ??= import("@mtcute/node"); + return mtcuteNodePromise; } -export function createTelegramUserClient(params: { +export async function createTelegramUserClient(params: { apiId: number; apiHash: string; storagePath: string; -}) { +}): Promise { + // When loaded via jiti (plugin loader), dependencies often resolve through the "require" export + // condition. mtcute prints a deprecation warning from its CommonJS bundle. Dynamic import forces + // the "import" condition (ESM), eliminating the warning. + const { BaseTelegramClient, TelegramClient, NodePlatform } = await loadMtcuteNode(); + + class ClawdbotTelegramUserPlatform extends NodePlatform { + // mtcute's default NodePlatform.beforeExit installs SIGINT/SIGTERM handlers that re-send the + // signal, which can race with Clawdbot's graceful shutdown and close sqlite while writes are + // pending. We only hook into process exit events (no signal handlers) and rely on Clawdbot to + // stop cleanly. + override beforeExit(fn: () => void): () => void { + const onBeforeExit = () => fn(); + const onExit = () => fn(); + process.once("beforeExit", onBeforeExit); + process.once("exit", onExit); + return () => { + process.off("beforeExit", onBeforeExit); + process.off("exit", onExit); + }; + } + } + const client = new BaseTelegramClient({ apiId: params.apiId, apiHash: params.apiHash, diff --git a/extensions/telegram-user/src/login.ts b/extensions/telegram-user/src/login.ts index f2d8cbc90..e8363942e 100644 --- a/extensions/telegram-user/src/login.ts +++ b/extensions/telegram-user/src/login.ts @@ -39,7 +39,7 @@ export async function loginTelegramUser(params: { }) { const { apiId, apiHash, storagePath, runtime } = params; ensureTelegramUserSessionDir({ sessionPath: storagePath }); - const client = createTelegramUserClient({ apiId, apiHash, storagePath }); + const client = await createTelegramUserClient({ apiId, apiHash, storagePath }); let lastUrl = ""; const passwordEnv = process.env.TELEGRAM_USER_PASSWORD?.trim() || undefined; diff --git a/extensions/telegram-user/src/monitor/index.ts b/extensions/telegram-user/src/monitor/index.ts index 3aff04f2a..5e7486089 100644 --- a/extensions/telegram-user/src/monitor/index.ts +++ b/extensions/telegram-user/src/monitor/index.ts @@ -1,5 +1,4 @@ import fs from "node:fs"; -import { Dispatcher, filters } from "@mtcute/dispatcher"; import type { RuntimeEnv } from "clawdbot/plugin-sdk"; import { createTelegramUserClient } from "../client.js"; @@ -10,6 +9,15 @@ import { setActiveTelegramUserClient } from "../active-client.js"; import { createTelegramUserMessageHandler } from "./handler.js"; import type { CoreConfig } from "../types.js"; +type MtcuteDispatcher = typeof import("@mtcute/dispatcher"); + +let mtcuteDispatcherPromise: Promise | null = null; + +async function loadMtcuteDispatcher(): Promise { + mtcuteDispatcherPromise ??= import("@mtcute/dispatcher"); + return mtcuteDispatcherPromise; +} + export type MonitorTelegramUserOpts = { runtime?: RuntimeEnv; abortSignal?: AbortSignal; @@ -48,7 +56,7 @@ export async function monitorTelegramUserProvider(opts: MonitorTelegramUserOpts "Telegram user session missing. Run `clawdbot channels login --channel telegram-user` first.", ); } - const client = createTelegramUserClient({ apiId, apiHash, storagePath }); + const client = await createTelegramUserClient({ apiId, apiHash, storagePath }); setActiveTelegramUserClient(client); const stop = async () => { @@ -66,6 +74,7 @@ export async function monitorTelegramUserProvider(opts: MonitorTelegramUserOpts await client.start(); + const { Dispatcher, filters } = await loadMtcuteDispatcher(); const dispatcher = Dispatcher.for(client); const self = await client.getMe().catch(() => undefined); const handleMessage = createTelegramUserMessageHandler({ diff --git a/extensions/telegram-user/src/send.ts b/extensions/telegram-user/src/send.ts index c2ec04885..2afbd4645 100644 --- a/extensions/telegram-user/src/send.ts +++ b/extensions/telegram-user/src/send.ts @@ -1,6 +1,5 @@ import fs from "node:fs"; import type { TelegramClient } from "@mtcute/node"; -import { InputMedia } from "@mtcute/core"; import type { PollInput } from "clawdbot/plugin-sdk"; import { getTelegramUserRuntime } from "./runtime.js"; @@ -14,6 +13,15 @@ export type TelegramUserSendResult = { chatId: string; }; +type MtcuteCore = typeof import("@mtcute/core"); + +let mtcuteCorePromise: Promise | null = null; + +async function loadMtcuteCore(): Promise { + mtcuteCorePromise ??= import("@mtcute/core"); + return mtcuteCorePromise; +} + type NormalizedPollInput = { question: string; options: string[]; @@ -129,7 +137,7 @@ async function resolveClient(params: { "Telegram user session missing. Run `clawdbot channels login --channel telegram-user` first.", ); } - const client = createTelegramUserClient({ apiId, apiHash, storagePath }); + const client = await createTelegramUserClient({ apiId, apiHash, storagePath }); await client.start(); return { client, stopOnDone: true }; } @@ -180,6 +188,7 @@ export async function sendMediaTelegramUser( accountId: opts.accountId, }); try { + const { InputMedia } = await loadMtcuteCore(); const resolved = resolveTargetAndThread(to, opts.threadId); const target = resolveTelegramUserPeer(resolved.target); const media = await getTelegramUserRuntime().media.loadWebMedia(opts.mediaUrl, opts.maxBytes); @@ -220,6 +229,7 @@ export async function sendPollTelegramUser( accountId: opts.accountId, }); try { + const { InputMedia } = await loadMtcuteCore(); const resolved = resolveTargetAndThread(to, opts.threadId); const target = resolveTelegramUserPeer(resolved.target); const normalized = normalizePollInput(poll);