telegram-notify-mcp 1.0.0 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,244 @@
1
+ /**
2
+ * Inbound routing: allowlist, reply→mapping, /to <agent_id> fallback, approval callbacks.
3
+ * Unroutable allowlisted messages are ignored (counted); never executed as shell.
4
+ */
5
+ /**
6
+ * Allowed chats from TELEGRAM_CHAT_ALLOWLIST (comma-separated) or TELEGRAM_CHAT_ID.
7
+ * If neither is set, no chat is allowed for inbound commands.
8
+ */
9
+ export function getAllowedChatIds(env = process.env) {
10
+ const allowlist = (env.TELEGRAM_CHAT_ALLOWLIST ?? '').trim();
11
+ const ids = new Set();
12
+ if (allowlist) {
13
+ for (const part of allowlist.split(',')) {
14
+ const id = part.trim();
15
+ if (id)
16
+ ids.add(id);
17
+ }
18
+ }
19
+ const single = (env.TELEGRAM_CHAT_ID ?? '').trim();
20
+ if (single)
21
+ ids.add(single);
22
+ return ids;
23
+ }
24
+ export function isChatAllowed(chatId, env = process.env) {
25
+ const allowed = getAllowedChatIds(env);
26
+ if (allowed.size === 0)
27
+ return false;
28
+ return allowed.has(String(chatId));
29
+ }
30
+ /** Parse `/to <agent_id> <rest…>` — agent_id is the first whitespace-delimited token after /to. */
31
+ export function parseToAgentCommand(text) {
32
+ const trimmed = text.trim();
33
+ const match = trimmed.match(/^\/to\s+(\S+)\s+([\s\S]+)$/i);
34
+ if (!match)
35
+ return undefined;
36
+ const agentId = match[1];
37
+ const body = match[2].trim();
38
+ if (!agentId || !body)
39
+ return undefined;
40
+ return { agentId, body };
41
+ }
42
+ export function truncateAgentLabel(idOrName, maxLen = 32) {
43
+ const s = idOrName.trim();
44
+ if (s.length <= maxLen)
45
+ return s;
46
+ return `${s.slice(0, maxLen - 1)}…`;
47
+ }
48
+ /**
49
+ * Footer appended to outbound notify text (UX only; routing uses reply_to mapping).
50
+ */
51
+ export function formatAgentFooter(sourceAgentId, sourceAgentName) {
52
+ const label = truncateAgentLabel((sourceAgentName ?? '').trim() || sourceAgentId);
53
+ return `\n\n— from agent ${label}\nReply to this message to continue with this agent.`;
54
+ }
55
+ export function formatNotifyWithFooter(title, body, sourceAgentId, sourceAgentName, formatBase = defaultFormatBase) {
56
+ return formatBase(title, body) + formatAgentFooter(sourceAgentId, sourceAgentName);
57
+ }
58
+ function defaultFormatBase(title, body) {
59
+ const t = (title ?? '').trim();
60
+ const b = body.trim();
61
+ if (t)
62
+ return `✅ ${t}\n\n${b}`;
63
+ return `✅ ${b}`;
64
+ }
65
+ /** Parse callback_data: ok:TOKEN | no:TOKEN | cu:TOKEN */
66
+ export function parseApprovalCallbackData(data) {
67
+ if (!data)
68
+ return undefined;
69
+ const match = data.match(/^(ok|no|cu):(.+)$/);
70
+ if (!match)
71
+ return undefined;
72
+ const action = match[1];
73
+ const token = match[2];
74
+ if (!token)
75
+ return undefined;
76
+ return { action, token };
77
+ }
78
+ export function routeInboundMessage(store, message, env = process.env) {
79
+ const chatId = message.chat?.id;
80
+ if (chatId === undefined || chatId === null) {
81
+ return { kind: 'ignored_unroutable' };
82
+ }
83
+ if (!isChatAllowed(chatId, env)) {
84
+ return { kind: 'ignored_not_allowlisted' };
85
+ }
86
+ const text = (message.text ?? '').trim();
87
+ if (!text) {
88
+ return { kind: 'ignored_no_text' };
89
+ }
90
+ const replyToId = message.reply_to_message?.message_id;
91
+ if (replyToId !== undefined) {
92
+ const mapping = store.getMapping(chatId, replyToId);
93
+ if (mapping) {
94
+ const command = store.enqueuePending({
95
+ source_agent_id: mapping.source_agent_id,
96
+ source_agent_name: mapping.source_agent_name,
97
+ conversation_hint: mapping.conversation_hint,
98
+ chat_id: String(chatId),
99
+ telegram_message_id: message.message_id,
100
+ reply_to_telegram_message_id: replyToId,
101
+ text,
102
+ });
103
+ return { kind: 'enqueued', command, via: 'reply' };
104
+ }
105
+ }
106
+ const toCmd = parseToAgentCommand(text);
107
+ if (toCmd) {
108
+ const command = store.enqueuePending({
109
+ source_agent_id: toCmd.agentId,
110
+ chat_id: String(chatId),
111
+ telegram_message_id: message.message_id,
112
+ reply_to_telegram_message_id: replyToId,
113
+ text: toCmd.body,
114
+ });
115
+ return { kind: 'enqueued', command, via: 'to_command' };
116
+ }
117
+ // Prefer ignore with count (documented): no mapping and no /to → drop
118
+ return { kind: 'ignored_unroutable' };
119
+ }
120
+ /**
121
+ * Route an inline-keyboard callback_query into pending queue or custom_prompt disposition.
122
+ */
123
+ export function routeCallbackQuery(store, callback, env = process.env) {
124
+ const chatId = callback.message?.chat?.id;
125
+ if (chatId === undefined || chatId === null) {
126
+ return { kind: 'ignored_unroutable' };
127
+ }
128
+ if (!isChatAllowed(chatId, env)) {
129
+ return { kind: 'ignored_not_allowlisted' };
130
+ }
131
+ const parsed = parseApprovalCallbackData(callback.data);
132
+ if (!parsed) {
133
+ return { kind: 'ignored_unknown_callback' };
134
+ }
135
+ const session = store.getApproval(parsed.token);
136
+ if (!session) {
137
+ return { kind: 'ignored_unknown_callback' };
138
+ }
139
+ const originalMessageId = session.telegram_message_id;
140
+ const callbackMessageId = callback.message?.message_id ?? 0;
141
+ if (parsed.action === 'cu') {
142
+ return {
143
+ kind: 'custom_prompt',
144
+ session,
145
+ callback_query_id: callback.id,
146
+ via: 'approval',
147
+ };
148
+ }
149
+ const text = parsed.action === 'ok' ? session.accept_command : session.decline_command;
150
+ const command = store.enqueuePending({
151
+ source_agent_id: session.source_agent_id,
152
+ source_agent_name: session.source_agent_name,
153
+ chat_id: String(chatId),
154
+ telegram_message_id: callbackMessageId,
155
+ reply_to_telegram_message_id: originalMessageId,
156
+ text,
157
+ });
158
+ // One-shot: remove session after Accept/Decline so re-presses don't re-enqueue
159
+ store.deleteApproval(parsed.token);
160
+ return { kind: 'enqueued', command, via: 'approval' };
161
+ }
162
+ export function processUpdates(store, updates, env = process.env) {
163
+ const summary = {
164
+ updates_seen: updates.length,
165
+ enqueued: 0,
166
+ ignored_not_allowlisted: 0,
167
+ ignored_unroutable: 0,
168
+ ignored_no_text: 0,
169
+ ignored_unknown_callback: 0,
170
+ custom_prompts: 0,
171
+ commands: [],
172
+ callback_actions: [],
173
+ };
174
+ let maxUpdateId;
175
+ for (const u of updates) {
176
+ if (maxUpdateId === undefined || u.update_id > maxUpdateId) {
177
+ maxUpdateId = u.update_id;
178
+ }
179
+ if (u.callback_query) {
180
+ const result = routeCallbackQuery(store, u.callback_query, env);
181
+ switch (result.kind) {
182
+ case 'enqueued':
183
+ summary.enqueued += 1;
184
+ summary.commands.push(result.command);
185
+ summary.callback_actions.push({
186
+ kind: 'answer',
187
+ callback_query_id: u.callback_query.id,
188
+ text: result.command.text.slice(0, 200),
189
+ });
190
+ break;
191
+ case 'custom_prompt':
192
+ summary.custom_prompts += 1;
193
+ summary.callback_actions.push({
194
+ kind: 'custom_prompt',
195
+ callback_query_id: result.callback_query_id,
196
+ session: result.session,
197
+ });
198
+ break;
199
+ case 'ignored_not_allowlisted':
200
+ summary.ignored_not_allowlisted += 1;
201
+ break;
202
+ case 'ignored_unroutable':
203
+ summary.ignored_unroutable += 1;
204
+ break;
205
+ case 'ignored_unknown_callback':
206
+ summary.ignored_unknown_callback += 1;
207
+ // Still answer so Telegram stops the spinner
208
+ summary.callback_actions.push({
209
+ kind: 'answer',
210
+ callback_query_id: u.callback_query.id,
211
+ text: 'Unknown or expired approval',
212
+ });
213
+ break;
214
+ default:
215
+ break;
216
+ }
217
+ continue;
218
+ }
219
+ const message = u.message ?? u.edited_message;
220
+ if (!message)
221
+ continue;
222
+ const result = routeInboundMessage(store, message, env);
223
+ switch (result.kind) {
224
+ case 'enqueued':
225
+ summary.enqueued += 1;
226
+ summary.commands.push(result.command);
227
+ break;
228
+ case 'ignored_not_allowlisted':
229
+ summary.ignored_not_allowlisted += 1;
230
+ break;
231
+ case 'ignored_unroutable':
232
+ summary.ignored_unroutable += 1;
233
+ break;
234
+ case 'ignored_no_text':
235
+ summary.ignored_no_text += 1;
236
+ break;
237
+ }
238
+ }
239
+ if (maxUpdateId !== undefined) {
240
+ summary.next_offset = maxUpdateId + 1;
241
+ }
242
+ return summary;
243
+ }
244
+ //# sourceMappingURL=routing.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"routing.js","sourceRoot":"","sources":["../src/routing.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,75 @@
1
+ /**
2
+ * Local JSON persistence for outbound message→agent mappings and pending inbound commands.
3
+ * Path: TELEGRAM_NOTIFY_DATA_DIR or ./.telegram-notify-data
4
+ * Does not log secrets. Never execute Telegram text as shell.
5
+ */
6
+ export interface OutboundMapping {
7
+ chat_id: string;
8
+ telegram_message_id: number;
9
+ source_agent_id: string;
10
+ source_agent_name?: string;
11
+ conversation_hint?: string;
12
+ created_at: string;
13
+ /** Optional: command text enqueued when Accept is pressed on this message. */
14
+ accept_command?: string;
15
+ /** Optional: command text enqueued when Decline is pressed on this message. */
16
+ decline_command?: string;
17
+ }
18
+ export interface ApprovalSession {
19
+ token: string;
20
+ chat_id: string;
21
+ telegram_message_id: number;
22
+ source_agent_id: string;
23
+ source_agent_name?: string;
24
+ accept_command: string;
25
+ decline_command: string;
26
+ created_at: string;
27
+ }
28
+ export type PendingCommandStatus = 'pending' | 'acked';
29
+ export interface PendingCommand {
30
+ id: string;
31
+ source_agent_id: string;
32
+ source_agent_name?: string;
33
+ conversation_hint?: string;
34
+ chat_id: string;
35
+ telegram_message_id: number;
36
+ reply_to_telegram_message_id?: number;
37
+ text: string;
38
+ created_at: string;
39
+ status: PendingCommandStatus;
40
+ error?: string;
41
+ }
42
+ export declare function getDataDir(env?: NodeJS.ProcessEnv): string;
43
+ export declare class LocalStore {
44
+ readonly dataDir: string;
45
+ private readonly filePath;
46
+ constructor(dataDir?: string);
47
+ private ensureDir;
48
+ private read;
49
+ private write;
50
+ putMapping(entry: Omit<OutboundMapping, 'created_at'> & {
51
+ created_at?: string;
52
+ }): OutboundMapping;
53
+ getMapping(chatId: string | number, messageId: number): OutboundMapping | undefined;
54
+ putApproval(entry: Omit<ApprovalSession, 'created_at'> & {
55
+ created_at?: string;
56
+ }): ApprovalSession;
57
+ getApproval(token: string): ApprovalSession | undefined;
58
+ deleteApproval(token: string): boolean;
59
+ enqueuePending(input: Omit<PendingCommand, 'id' | 'created_at' | 'status'> & {
60
+ id?: string;
61
+ created_at?: string;
62
+ status?: PendingCommandStatus;
63
+ }): PendingCommand;
64
+ listPending(filter?: {
65
+ source_agent_id?: string;
66
+ includeAcked?: boolean;
67
+ }): PendingCommand[];
68
+ /**
69
+ * Idempotent ack: marks pending→acked and removes from active list (or keeps as acked).
70
+ * Returns the command if found; undefined if unknown id.
71
+ */
72
+ ackCommand(id: string): PendingCommand | undefined;
73
+ getUpdateOffset(): number | undefined;
74
+ setUpdateOffset(offset: number): void;
75
+ }
package/dist/store.js ADDED
@@ -0,0 +1,157 @@
1
+ /**
2
+ * Local JSON persistence for outbound message→agent mappings and pending inbound commands.
3
+ * Path: TELEGRAM_NOTIFY_DATA_DIR or ./.telegram-notify-data
4
+ * Does not log secrets. Never execute Telegram text as shell.
5
+ */
6
+ import { randomUUID } from 'node:crypto';
7
+ import { mkdirSync, readFileSync, writeFileSync, existsSync } from 'node:fs';
8
+ import { join } from 'node:path';
9
+ function mappingKey(chatId, messageId) {
10
+ return `${chatId}:${messageId}`;
11
+ }
12
+ export function getDataDir(env = process.env) {
13
+ const fromEnv = (env.TELEGRAM_NOTIFY_DATA_DIR ?? '').trim();
14
+ if (fromEnv)
15
+ return fromEnv;
16
+ return join(process.cwd(), '.telegram-notify-data');
17
+ }
18
+ function emptyStore() {
19
+ return { mappings: {}, pending: [], approvals: {}, update_offset: undefined };
20
+ }
21
+ export class LocalStore {
22
+ dataDir;
23
+ filePath;
24
+ constructor(dataDir) {
25
+ this.dataDir = dataDir ?? getDataDir();
26
+ this.filePath = join(this.dataDir, 'store.json');
27
+ }
28
+ ensureDir() {
29
+ if (!existsSync(this.dataDir)) {
30
+ mkdirSync(this.dataDir, { recursive: true });
31
+ }
32
+ }
33
+ read() {
34
+ this.ensureDir();
35
+ if (!existsSync(this.filePath)) {
36
+ return emptyStore();
37
+ }
38
+ try {
39
+ const raw = readFileSync(this.filePath, 'utf8');
40
+ const parsed = JSON.parse(raw);
41
+ return {
42
+ mappings: parsed.mappings ?? {},
43
+ pending: Array.isArray(parsed.pending) ? parsed.pending : [],
44
+ approvals: parsed.approvals ?? {},
45
+ update_offset: parsed.update_offset,
46
+ };
47
+ }
48
+ catch {
49
+ return emptyStore();
50
+ }
51
+ }
52
+ write(data) {
53
+ this.ensureDir();
54
+ writeFileSync(this.filePath, JSON.stringify(data, null, 2), 'utf8');
55
+ }
56
+ putMapping(entry) {
57
+ const data = this.read();
58
+ const full = {
59
+ chat_id: String(entry.chat_id),
60
+ telegram_message_id: entry.telegram_message_id,
61
+ source_agent_id: entry.source_agent_id,
62
+ source_agent_name: entry.source_agent_name,
63
+ conversation_hint: entry.conversation_hint,
64
+ created_at: entry.created_at ?? new Date().toISOString(),
65
+ accept_command: entry.accept_command,
66
+ decline_command: entry.decline_command,
67
+ };
68
+ data.mappings[mappingKey(full.chat_id, full.telegram_message_id)] = full;
69
+ this.write(data);
70
+ return full;
71
+ }
72
+ getMapping(chatId, messageId) {
73
+ const data = this.read();
74
+ return data.mappings[mappingKey(chatId, messageId)];
75
+ }
76
+ putApproval(entry) {
77
+ const data = this.read();
78
+ const full = {
79
+ token: entry.token,
80
+ chat_id: String(entry.chat_id),
81
+ telegram_message_id: entry.telegram_message_id,
82
+ source_agent_id: entry.source_agent_id,
83
+ source_agent_name: entry.source_agent_name,
84
+ accept_command: entry.accept_command,
85
+ decline_command: entry.decline_command,
86
+ created_at: entry.created_at ?? new Date().toISOString(),
87
+ };
88
+ data.approvals[full.token] = full;
89
+ this.write(data);
90
+ return full;
91
+ }
92
+ getApproval(token) {
93
+ const data = this.read();
94
+ return data.approvals[token];
95
+ }
96
+ deleteApproval(token) {
97
+ const data = this.read();
98
+ if (!(token in data.approvals))
99
+ return false;
100
+ delete data.approvals[token];
101
+ this.write(data);
102
+ return true;
103
+ }
104
+ enqueuePending(input) {
105
+ const data = this.read();
106
+ const cmd = {
107
+ id: input.id ?? randomUUID(),
108
+ source_agent_id: input.source_agent_id,
109
+ source_agent_name: input.source_agent_name,
110
+ conversation_hint: input.conversation_hint,
111
+ chat_id: String(input.chat_id),
112
+ telegram_message_id: input.telegram_message_id,
113
+ reply_to_telegram_message_id: input.reply_to_telegram_message_id,
114
+ text: input.text,
115
+ created_at: input.created_at ?? new Date().toISOString(),
116
+ status: input.status ?? 'pending',
117
+ error: input.error,
118
+ };
119
+ data.pending.push(cmd);
120
+ this.write(data);
121
+ return cmd;
122
+ }
123
+ listPending(filter) {
124
+ const data = this.read();
125
+ return data.pending.filter((c) => {
126
+ if (!filter?.includeAcked && c.status !== 'pending')
127
+ return false;
128
+ if (filter?.source_agent_id && c.source_agent_id !== filter.source_agent_id)
129
+ return false;
130
+ return true;
131
+ });
132
+ }
133
+ /**
134
+ * Idempotent ack: marks pending→acked and removes from active list (or keeps as acked).
135
+ * Returns the command if found; undefined if unknown id.
136
+ */
137
+ ackCommand(id) {
138
+ const data = this.read();
139
+ const idx = data.pending.findIndex((c) => c.id === id);
140
+ if (idx < 0)
141
+ return undefined;
142
+ const cmd = { ...data.pending[idx], status: 'acked' };
143
+ // Drop acked rows to keep the file small (at-least-once already delivered)
144
+ data.pending.splice(idx, 1);
145
+ this.write(data);
146
+ return cmd;
147
+ }
148
+ getUpdateOffset() {
149
+ return this.read().update_offset;
150
+ }
151
+ setUpdateOffset(offset) {
152
+ const data = this.read();
153
+ data.update_offset = offset;
154
+ this.write(data);
155
+ }
156
+ }
157
+ //# sourceMappingURL=store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store.js","sourceRoot":"","sources":["../src/store.ts"],"names":[],"mappings":"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"}
@@ -30,12 +30,20 @@ export interface TelegramMessage {
30
30
  chat: TelegramChat;
31
31
  text?: string;
32
32
  from?: TelegramUser;
33
+ reply_to_message?: TelegramMessage;
34
+ }
35
+ export interface TelegramCallbackQuery {
36
+ id: string;
37
+ from?: TelegramUser;
38
+ data?: string;
39
+ message?: TelegramMessage;
33
40
  }
34
41
  export interface TelegramUpdate {
35
42
  update_id: number;
36
43
  message?: TelegramMessage;
37
44
  edited_message?: TelegramMessage;
38
45
  channel_post?: TelegramMessage;
46
+ callback_query?: TelegramCallbackQuery;
39
47
  }
40
48
  export interface TelegramApiResponse<T> {
41
49
  ok: boolean;
@@ -44,19 +52,48 @@ export interface TelegramApiResponse<T> {
44
52
  error_code?: number;
45
53
  }
46
54
  export type ParseMode = 'Markdown' | 'MarkdownV2' | 'HTML';
55
+ export interface InlineKeyboardButton {
56
+ text: string;
57
+ callback_data?: string;
58
+ url?: string;
59
+ }
60
+ export interface InlineKeyboardMarkup {
61
+ inline_keyboard: InlineKeyboardButton[][];
62
+ }
63
+ export interface ForceReplyMarkup {
64
+ force_reply: true;
65
+ selective?: boolean;
66
+ input_field_placeholder?: string;
67
+ }
68
+ export type ReplyMarkup = InlineKeyboardMarkup | ForceReplyMarkup;
47
69
  export interface SendMessageParams {
48
70
  chat_id: string | number;
49
71
  text: string;
50
72
  parse_mode?: ParseMode;
51
73
  disable_notification?: boolean;
74
+ reply_markup?: ReplyMarkup;
75
+ reply_to_message_id?: number;
76
+ }
77
+ export interface AnswerCallbackQueryParams {
78
+ callback_query_id: string;
79
+ text?: string;
80
+ show_alert?: boolean;
52
81
  }
53
82
  export interface GetUpdatesParams {
54
83
  limit?: number;
55
84
  timeout?: number;
56
85
  offset?: number;
86
+ allowed_updates?: string[];
57
87
  }
58
88
  export declare function getDefaultChatId(explicit?: string | number): string | number;
59
89
  export declare function formatNotifyMessage(title: string | undefined, body: string): string;
90
+ /** Short random token for callback_data (keeps ok:/no:/cu: + token ≤ 64 bytes). */
91
+ export declare function generateApprovalToken(byteLength?: number): string;
92
+ /**
93
+ * Inline keyboard: Accept / Decline / Custom message.
94
+ * callback_data prefixes: ok: | no: | cu: + TOKEN
95
+ */
96
+ export declare function buildApprovalKeyboard(token: string): InlineKeyboardMarkup;
60
97
  export declare class TelegramClient {
61
98
  private readonly fetchImpl;
62
99
  private readonly baseUrl;
@@ -64,6 +101,7 @@ export declare class TelegramClient {
64
101
  private call;
65
102
  getMe(): Promise<TelegramUser>;
66
103
  sendMessage(params: SendMessageParams): Promise<TelegramMessage>;
104
+ answerCallbackQuery(params: AnswerCallbackQueryParams): Promise<boolean>;
67
105
  getUpdates(params?: GetUpdatesParams): Promise<TelegramUpdate[]>;
68
106
  }
69
107
  export declare function createClientFromEnv(fetchImpl?: typeof fetch): TelegramClient;
package/dist/telegram.js CHANGED
@@ -2,6 +2,7 @@
2
2
  * Thin Telegram Bot HTTP API client (api.telegram.org).
3
3
  * Uses Node 20+ global fetch. No secrets are hardcoded.
4
4
  */
5
+ import { randomBytes } from 'node:crypto';
5
6
  export class TelegramApiError extends Error {
6
7
  status;
7
8
  description;
@@ -37,6 +38,34 @@ export function formatNotifyMessage(title, body) {
37
38
  }
38
39
  return `✅ ${b}`;
39
40
  }
41
+ /** Short random token for callback_data (keeps ok:/no:/cu: + token ≤ 64 bytes). */
42
+ export function generateApprovalToken(byteLength = 6) {
43
+ return randomBytes(byteLength).toString('base64url').slice(0, 12);
44
+ }
45
+ /**
46
+ * Inline keyboard: Accept / Decline / Custom message.
47
+ * callback_data prefixes: ok: | no: | cu: + TOKEN
48
+ */
49
+ export function buildApprovalKeyboard(token) {
50
+ const t = token.trim();
51
+ if (!t) {
52
+ throw new Error('approval token must be non-empty');
53
+ }
54
+ for (const prefix of ['ok:', 'no:', 'cu:']) {
55
+ if (Buffer.byteLength(prefix + t, 'utf8') > 64) {
56
+ throw new Error(`callback_data exceeds 64 bytes for prefix ${prefix}`);
57
+ }
58
+ }
59
+ return {
60
+ inline_keyboard: [
61
+ [
62
+ { text: 'Accept', callback_data: `ok:${t}` },
63
+ { text: 'Decline', callback_data: `no:${t}` },
64
+ ],
65
+ [{ text: 'Custom message', callback_data: `cu:${t}` }],
66
+ ],
67
+ };
68
+ }
40
69
  export class TelegramClient {
41
70
  fetchImpl;
42
71
  baseUrl;
@@ -84,8 +113,24 @@ export class TelegramClient {
84
113
  if (params.disable_notification !== undefined) {
85
114
  payload.disable_notification = params.disable_notification;
86
115
  }
116
+ if (params.reply_markup !== undefined) {
117
+ payload.reply_markup = params.reply_markup;
118
+ }
119
+ if (params.reply_to_message_id !== undefined) {
120
+ payload.reply_to_message_id = params.reply_to_message_id;
121
+ }
87
122
  return this.call('sendMessage', payload);
88
123
  }
124
+ answerCallbackQuery(params) {
125
+ const payload = {
126
+ callback_query_id: params.callback_query_id,
127
+ };
128
+ if (params.text !== undefined)
129
+ payload.text = params.text;
130
+ if (params.show_alert !== undefined)
131
+ payload.show_alert = params.show_alert;
132
+ return this.call('answerCallbackQuery', payload);
133
+ }
89
134
  getUpdates(params = {}) {
90
135
  const payload = {};
91
136
  if (params.limit !== undefined)
@@ -94,6 +139,8 @@ export class TelegramClient {
94
139
  payload.timeout = params.timeout;
95
140
  if (params.offset !== undefined)
96
141
  payload.offset = params.offset;
142
+ if (params.allowed_updates !== undefined)
143
+ payload.allowed_updates = params.allowed_updates;
97
144
  return this.call('getUpdates', Object.keys(payload).length ? payload : undefined);
98
145
  }
99
146
  }
@@ -1 +1 @@
1
- {"version":3,"file":"telegram.js","sourceRoot":"","sources":["../src/telegram.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"telegram.js","sourceRoot":"","sources":["../src/telegram.ts"],"names":[],"mappings":"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"}