telegram-user: load mtcute deps via ESM

This commit is contained in:
Muhammed Mukhthar CM 2026-01-27 00:34:23 +00:00
parent 525c148959
commit a3184b920a
4 changed files with 54 additions and 22 deletions

View File

@ -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<MtcuteNode> | null = null;
async function loadMtcuteNode(): Promise<MtcuteNode> {
mtcuteNodePromise ??= import("@mtcute/node");
return mtcuteNodePromise;
}
export function createTelegramUserClient(params: {
export async function createTelegramUserClient(params: {
apiId: number;
apiHash: string;
storagePath: string;
}) {
}): Promise<import("@mtcute/node").TelegramClient> {
// 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,

View File

@ -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;

View File

@ -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<MtcuteDispatcher> | null = null;
async function loadMtcuteDispatcher(): Promise<MtcuteDispatcher> {
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({

View File

@ -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<MtcuteCore> | null = null;
async function loadMtcuteCore(): Promise<MtcuteCore> {
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);