manual improvement 2 & add telegram bot
This commit is contained in:
@@ -0,0 +1,76 @@
|
||||
import { config } from './env.js';
|
||||
|
||||
const API_BASE = `https://api.telegram.org/bot${config.botToken}`;
|
||||
|
||||
async function callApi(method, payload, { timeoutMs = 10_000 } = {}) {
|
||||
const controller = new AbortController();
|
||||
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
||||
|
||||
try {
|
||||
const response = await fetch(`${API_BASE}/${method}`, {
|
||||
method: 'POST',
|
||||
headers: { 'content-type': 'application/json' },
|
||||
body: JSON.stringify(payload),
|
||||
signal: controller.signal,
|
||||
});
|
||||
|
||||
const body = await response.json().catch(() => ({}));
|
||||
if (!response.ok || body.ok !== true) {
|
||||
// Telegram carries the real failure in `description` (e.g. "chat not found" when the
|
||||
// recipient never messaged the bot first) — surface it verbatim so the cause is obvious.
|
||||
const reason = body.description ?? `HTTP ${response.status}`;
|
||||
throw new Error(reason);
|
||||
}
|
||||
|
||||
return body.result;
|
||||
} finally {
|
||||
clearTimeout(timer);
|
||||
}
|
||||
}
|
||||
|
||||
/** Sends one message to every configured chat id. Never rejects — per-recipient outcomes are returned. */
|
||||
export async function broadcast(text) {
|
||||
const results = await Promise.all(
|
||||
config.chatIds.map(async (chatId) => {
|
||||
try {
|
||||
await callApi('sendMessage', { chat_id: chatId, text, disable_notification: false });
|
||||
return { chatId, ok: true };
|
||||
} catch (error) {
|
||||
return { chatId, ok: false, error: error.message };
|
||||
}
|
||||
}),
|
||||
);
|
||||
|
||||
return {
|
||||
delivered: results.filter((r) => r.ok).map((r) => r.chatId),
|
||||
failed: results.filter((r) => !r.ok).map(({ chatId, error }) => ({ chatId, error })),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Lists the chat ids that have messaged the bot recently, so a new recipient can be discovered
|
||||
* without hunting through the Telegram API by hand. getUpdates only sees messages newer than the
|
||||
* last 24h and returns nothing while a webhook is set.
|
||||
*/
|
||||
export async function discoverChatIds() {
|
||||
const updates = await callApi('getUpdates', { limit: 100, timeout: 0 });
|
||||
const seen = new Map();
|
||||
|
||||
for (const update of updates) {
|
||||
const chat = update.message?.chat ?? update.edited_message?.chat ?? update.channel_post?.chat;
|
||||
if (!chat) continue;
|
||||
|
||||
seen.set(String(chat.id), {
|
||||
chat_id: String(chat.id),
|
||||
type: chat.type,
|
||||
username: chat.username ?? null,
|
||||
title: chat.title ?? ([chat.first_name, chat.last_name].filter(Boolean).join(' ') || null),
|
||||
});
|
||||
}
|
||||
|
||||
return [...seen.values()];
|
||||
}
|
||||
|
||||
export async function getBotIdentity() {
|
||||
return callApi('getMe', {});
|
||||
}
|
||||
Reference in New Issue
Block a user