Files
openclaw/extensions/telegram/src/api-fetch.ts
Cypherm 6b4c24c2e5 feat(telegram): support custom apiRoot for alternative API endpoints (#48842)
* feat(telegram): support custom apiRoot for alternative API endpoints

Add `apiRoot` config option to allow users to specify custom Telegram Bot
API endpoints (e.g., self-hosted Bot API servers). Threads the configured
base URL through all Telegram API call sites: bot creation, send, probe,
audit, media download, and api-fetch. Extends SSRF policy to dynamically
trust custom apiRoot hostname for media downloads.

Closes #28535

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(telegram): thread apiRoot through allowFrom lookups

* fix(telegram): honor lookup transport and local file paths

* refactor(telegram): unify username lookup plumbing

* fix(telegram): restore doctor lookup imports

* fix: document Telegram apiRoot support (#48842) (thanks @Cypherm)

---------

Co-authored-by: Cypherm <28184436+Cypherm@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: Ayaan Zaidi <hi@obviy.us>
2026-03-21 10:10:38 +05:30

62 lines
1.8 KiB
TypeScript

import type { TelegramNetworkConfig } from "../runtime-api.js";
import { resolveTelegramApiBase, resolveTelegramFetch } from "./fetch.js";
import { makeProxyFetch } from "./proxy.js";
export function resolveTelegramChatLookupFetch(params?: {
proxyUrl?: string;
network?: TelegramNetworkConfig;
}): typeof fetch {
const proxyUrl = params?.proxyUrl?.trim();
const proxyFetch = proxyUrl ? makeProxyFetch(proxyUrl) : undefined;
return resolveTelegramFetch(proxyFetch, { network: params?.network });
}
export async function lookupTelegramChatId(params: {
token: string;
chatId: string;
signal?: AbortSignal;
apiRoot?: string;
proxyUrl?: string;
network?: TelegramNetworkConfig;
}): Promise<string | null> {
return fetchTelegramChatId({
token: params.token,
chatId: params.chatId,
signal: params.signal,
apiRoot: params.apiRoot,
fetchImpl: resolveTelegramChatLookupFetch({
proxyUrl: params.proxyUrl,
network: params.network,
}),
});
}
export async function fetchTelegramChatId(params: {
token: string;
chatId: string;
signal?: AbortSignal;
apiRoot?: string;
fetchImpl?: typeof fetch;
}): Promise<string | null> {
const apiBase = resolveTelegramApiBase(params.apiRoot);
const url = `${apiBase}/bot${params.token}/getChat?chat_id=${encodeURIComponent(params.chatId)}`;
const fetchImpl = params.fetchImpl ?? fetch;
try {
const res = await fetchImpl(url, params.signal ? { signal: params.signal } : undefined);
if (!res.ok) {
return null;
}
const data = (await res.json().catch(() => null)) as {
ok?: boolean;
result?: { id?: number | string };
} | null;
const id = data?.ok ? data?.result?.id : undefined;
if (typeof id === "number" || typeof id === "string") {
return String(id);
}
return null;
} catch {
return null;
}
}