mirror of
https://github.com/harivansh-afk/pi-telegram-webhook.git
synced 2026-04-15 09:01:16 +00:00
initial: webhook telegram adapter for pi with streaming replies
- 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
This commit is contained in:
parent
809e9b1df5
commit
ce9abc2a8e
18 changed files with 6991 additions and 1 deletions
97
src/telegram-api.ts
Normal file
97
src/telegram-api.ts
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
/**
|
||||
* 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 });
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue