feat: ретранслятор Bot API на домашнем сервере и TELEGRAM_API_BASE

С VPS api.telegram.org недоступен. deploy/tg-relay: nginx на адресе
Tailscale домашнего сервера, пропускает только запросы нашего бота из
tailnet, без логов доступа (токен в URL). api: базовый URL Bot API из
TELEGRAM_API_BASE; сетевые сбои polling пишутся в лог раз в 10 минут.
This commit is contained in:
2026-10-17 16:56:52 +03:00
parent 55ecf7c9d8
commit 66d69c1245
9 changed files with 99 additions and 4 deletions
+6 -3
View File
@@ -50,14 +50,17 @@ export type SendMessageParams = {
export type TelegramClient = ReturnType<typeof createTelegramClient>;
const API = 'https://api.telegram.org';
// С VPS в РФ api.telegram.org недоступен — ходим через ретранслятор (TELEGRAM_API_BASE, см. deploy/tg-relay).
export const DEFAULT_API_BASE = 'https://api.telegram.org';
export function createTelegramClient({
token,
apiBase = DEFAULT_API_BASE,
fetch = globalThis.fetch,
timeoutMs = 5000,
}: {
token: string;
apiBase?: string;
fetch?: FetchLike;
timeoutMs?: number;
}) {
@@ -81,7 +84,7 @@ export function createTelegramClient({
params instanceof FormData
? { method: 'POST', body: params }
: { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify(params) };
const res = await request(method, `${API}/bot${token}/${method}`, init, opts.timeoutMs ?? timeoutMs, opts.signal);
const res = await request(method, `${apiBase}/bot${token}/${method}`, init, opts.timeoutMs ?? timeoutMs, opts.signal);
let body: { ok?: boolean; result?: T; description?: string; parameters?: { retry_after?: number } };
try {
@@ -133,7 +136,7 @@ export function createTelegramClient({
call<TgMessage | boolean>('editMessageText', params),
getFile: (file_id: string) => call<{ file_id: string; file_path?: string; file_size?: number }>('getFile', { file_id }),
async downloadFile(filePath: string, maxBytes: number): Promise<Uint8Array> {
const res = await request('downloadFile', `${API}/file/bot${token}/${filePath}`, {}, 60_000);
const res = await request('downloadFile', `${apiBase}/file/bot${token}/${filePath}`, {}, 60_000);
if (!res.ok) throw new TelegramError(`downloadFile: ${res.status}`, res.status >= 500 ? 'retryable' : 'config', res.status);
const data = new Uint8Array(await res.arrayBuffer());
if (data.byteLength > maxBytes) throw new TelegramError('downloadFile: файл больше лимита', 'config');