mirror of
https://github.com/harivansh-afk/pi-telegram-webhook.git
synced 2026-04-15 03:00:47 +00:00
- webhook server with secret validation, rate limiting, body guards - streaming replies via sendMessage + editMessageText throttled loop - RPC session management for persistent conversations - 15/15 tests passing
97 lines
2.6 KiB
TypeScript
97 lines
2.6 KiB
TypeScript
/**
|
|
* pi-telegram-webhook — Thin Telegram Bot API wrapper.
|
|
*/
|
|
|
|
const BASE_URL = "https://api.telegram.org/bot";
|
|
|
|
export class TelegramAPI {
|
|
private token: string;
|
|
|
|
constructor(token: string) {
|
|
this.token = token;
|
|
}
|
|
|
|
private url(method: string): string {
|
|
return `${BASE_URL}${this.token}/${method}`;
|
|
}
|
|
|
|
private async request(method: string, body?: Record<string, unknown>): Promise<unknown> {
|
|
const res = await fetch(this.url(method), {
|
|
method: "POST",
|
|
headers: { "Content-Type": "application/json" },
|
|
body: body ? JSON.stringify(body) : undefined,
|
|
});
|
|
|
|
if (!res.ok) {
|
|
const text = await res.text().catch(() => "unknown");
|
|
throw new Error(`Telegram API ${method} failed (${res.status}): ${text}`);
|
|
}
|
|
|
|
const data = await res.json();
|
|
if (!(data as { ok: boolean }).ok) {
|
|
throw new Error(`Telegram API ${method} failed: ${JSON.stringify(data)}`);
|
|
}
|
|
|
|
return (data as { result: unknown }).result;
|
|
}
|
|
|
|
async getMe(): Promise<unknown> {
|
|
return this.request("getMe");
|
|
}
|
|
|
|
async sendMessage(
|
|
chatId: string | number,
|
|
text: string,
|
|
options?: { parse_mode?: string; reply_to_message_id?: number }
|
|
): Promise<{ message_id: number }> {
|
|
const body: Record<string, unknown> = { chat_id: chatId, text };
|
|
if (options?.parse_mode) body.parse_mode = options.parse_mode;
|
|
if (options?.reply_to_message_id) body.reply_to_message_id = options.reply_to_message_id;
|
|
|
|
return (await this.request("sendMessage", body)) as { message_id: number };
|
|
}
|
|
|
|
async editMessageText(
|
|
chatId: string | number,
|
|
messageId: number,
|
|
text: string,
|
|
options?: { parse_mode?: string }
|
|
): Promise<void> {
|
|
const body: Record<string, unknown> = {
|
|
chat_id: chatId,
|
|
message_id: messageId,
|
|
text,
|
|
};
|
|
if (options?.parse_mode) body.parse_mode = options.parse_mode;
|
|
|
|
await this.request("editMessageText", body);
|
|
}
|
|
|
|
async deleteMessage(chatId: string | number, messageId: number): Promise<void> {
|
|
await this.request("deleteMessage", {
|
|
chat_id: chatId,
|
|
message_id: messageId,
|
|
});
|
|
}
|
|
|
|
async sendChatAction(chatId: string | number, action = "typing"): Promise<void> {
|
|
await this.request("sendChatAction", {
|
|
chat_id: chatId,
|
|
action,
|
|
}).catch(() => {
|
|
// Best-effort
|
|
});
|
|
}
|
|
|
|
async setWebhook(url: string, secret: string): Promise<void> {
|
|
await this.request("setWebhook", {
|
|
url,
|
|
secret_token: secret,
|
|
allowed_updates: ["message"],
|
|
});
|
|
}
|
|
|
|
async deleteWebhook(): Promise<void> {
|
|
await this.request("deleteWebhook", { drop_pending_updates: false });
|
|
}
|
|
}
|