@codebam/cf-workers-telegram-bot 11.13.0 → 12.0.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.
Files changed (59) hide show
  1. package/dist/main.d.ts +1 -21
  2. package/dist/main.js +1 -7
  3. package/dist/telegram_api.d.ts +24 -13
  4. package/dist/telegram_api.js +52 -25
  5. package/dist/telegram_bot.d.ts +2 -3
  6. package/dist/telegram_bot.js +5 -3
  7. package/dist/telegram_execution_context.d.ts +16 -11
  8. package/dist/telegram_execution_context.js +229 -201
  9. package/dist/types/PartialTelegramUpdate.d.ts +6 -6
  10. package/dist/types/TelegramCommand.d.ts +1 -1
  11. package/dist/types/TelegramGuestMessage.d.ts +1 -1
  12. package/dist/types.d.ts +1 -13
  13. package/dist/types.js +1 -5
  14. package/dist/utils.js +4 -3
  15. package/package.json +3 -3
  16. package/dist/types/ChatPermissions.d.ts +0 -17
  17. package/dist/types/ChatPermissions.js +0 -1
  18. package/dist/types/TelegramBusinessConnection.d.ts +0 -10
  19. package/dist/types/TelegramBusinessConnection.js +0 -1
  20. package/dist/types/TelegramBusinessMessage.d.ts +0 -47
  21. package/dist/types/TelegramBusinessMessage.js +0 -1
  22. package/dist/types/TelegramCallbackQuery.d.ts +0 -15
  23. package/dist/types/TelegramCallbackQuery.js +0 -1
  24. package/dist/types/TelegramChat.d.ts +0 -21
  25. package/dist/types/TelegramChat.js +0 -1
  26. package/dist/types/TelegramDocument.d.ts +0 -10
  27. package/dist/types/TelegramDocument.js +0 -1
  28. package/dist/types/TelegramFrom.d.ts +0 -8
  29. package/dist/types/TelegramFrom.js +0 -1
  30. package/dist/types/TelegramInlineQuery.d.ts +0 -9
  31. package/dist/types/TelegramInlineQuery.js +0 -1
  32. package/dist/types/TelegramInlineQueryResult.d.ts +0 -6
  33. package/dist/types/TelegramInlineQueryResult.js +0 -8
  34. package/dist/types/TelegramInlineQueryResultArticle.d.ts +0 -13
  35. package/dist/types/TelegramInlineQueryResultArticle.js +0 -15
  36. package/dist/types/TelegramInlineQueryResultPhoto.d.ts +0 -21
  37. package/dist/types/TelegramInlineQueryResultPhoto.js +0 -23
  38. package/dist/types/TelegramInlineQueryResultVideo.d.ts +0 -21
  39. package/dist/types/TelegramInlineQueryResultVideo.js +0 -23
  40. package/dist/types/TelegramInlineQueryResultVoice.d.ts +0 -13
  41. package/dist/types/TelegramInlineQueryResultVoice.js +0 -14
  42. package/dist/types/TelegramInputMessageContent.d.ts +0 -5
  43. package/dist/types/TelegramInputMessageContent.js +0 -1
  44. package/dist/types/TelegramMessage.d.ts +0 -53
  45. package/dist/types/TelegramMessage.js +0 -1
  46. package/dist/types/TelegramMessageEntity.d.ts +0 -10
  47. package/dist/types/TelegramMessageEntity.js +0 -1
  48. package/dist/types/TelegramPhotoSize.d.ts +0 -8
  49. package/dist/types/TelegramPhotoSize.js +0 -1
  50. package/dist/types/TelegramPreCheckoutQuery.d.ts +0 -23
  51. package/dist/types/TelegramPreCheckoutQuery.js +0 -1
  52. package/dist/types/TelegramSuccessfulPayment.d.ts +0 -22
  53. package/dist/types/TelegramSuccessfulPayment.js +0 -1
  54. package/dist/types/TelegramUpdate.d.ts +0 -22
  55. package/dist/types/TelegramUpdate.js +0 -40
  56. package/dist/types/TelegramUser.d.ts +0 -13
  57. package/dist/types/TelegramUser.js +0 -1
  58. package/dist/types/TelegramVoice.d.ts +0 -7
  59. package/dist/types/TelegramVoice.js +0 -1
@@ -1,10 +1,10 @@
1
1
  import TelegramApi from './telegram_api.js';
2
- import TelegramInlineQueryResultArticle from './types/TelegramInlineQueryResultArticle.js';
3
- import TelegramInlineQueryResultPhoto from './types/TelegramInlineQueryResultPhoto.js';
4
- import TelegramInlineQueryResultVideo from './types/TelegramInlineQueryResultVideo.js';
5
- import TelegramInlineQueryResultVoice from './types/TelegramInlineQueryResultVoice.js';
6
2
  /** Class representing the context of execution */
7
3
  export default class TelegramExecutionContext {
4
+ /** Cache for business connection owners */
5
+ static businessOwners = new Map();
6
+ /** Cache for dead business connections */
7
+ static poisonedConnections = new Set();
8
8
  /** an instance of the telegram bot */
9
9
  bot;
10
10
  /** an instance of the telegram update */
@@ -45,7 +45,7 @@ export default class TelegramExecutionContext {
45
45
  * @returns The user ID or undefined if not available
46
46
  */
47
47
  get userId() {
48
- return this.update.message?.from.id ?? this.update.business_message?.from.id ?? this.update.guest_message?.from.id;
48
+ return this.update.message?.from?.id ?? this.update.business_message?.from?.id ?? this.update.guest_message?.from?.id;
49
49
  }
50
50
  /**
51
51
  * Parse arguments from the update
@@ -67,6 +67,54 @@ export default class TelegramExecutionContext {
67
67
  * Determine the type of update received
68
68
  * @returns The update type as a string
69
69
  */
70
+ /**
71
+ * Determine if the current update should be processed.
72
+ * For business messages, this checks if the connection is valid and has reply permissions.
73
+ */
74
+ async shouldProcess() {
75
+ if (this.update_type !== 'business_message') {
76
+ return true;
77
+ }
78
+ const connectionId = this.update.business_message?.business_connection_id?.toString();
79
+ if (!connectionId) {
80
+ return true;
81
+ }
82
+ if (TelegramExecutionContext.poisonedConnections.has(connectionId)) {
83
+ return false;
84
+ }
85
+ let ownerId = TelegramExecutionContext.businessOwners.get(connectionId);
86
+ if (ownerId === undefined) {
87
+ try {
88
+ const response = await this.api.getBusinessConnection(this.bot.api.toString(), connectionId);
89
+ if (response.status === 200) {
90
+ const json = await response.json();
91
+ if (json.ok && json.result) {
92
+ ownerId = json.result.user?.id || json.result.user_chat_id;
93
+ if (ownerId) {
94
+ TelegramExecutionContext.businessOwners.set(connectionId, ownerId);
95
+ }
96
+ if (json.result.can_reply === false) {
97
+ console.warn('Business connection ' + connectionId + ' lacks reply permissions, poisoning connection');
98
+ TelegramExecutionContext.poisonedConnections.add(connectionId);
99
+ return false;
100
+ }
101
+ }
102
+ }
103
+ }
104
+ catch (e) {
105
+ if (e instanceof Error && e.message === 'BUSINESS_CONNECTION_INVALID') {
106
+ console.warn('Business connection ' + connectionId + ' is invalid, poisoning connection');
107
+ TelegramExecutionContext.poisonedConnections.add(connectionId);
108
+ return false;
109
+ }
110
+ console.warn('Failed to fetch business connection info:', e);
111
+ }
112
+ }
113
+ if (ownerId !== undefined && this.getChatId() === ownerId.toString()) {
114
+ return false;
115
+ }
116
+ return true;
117
+ }
70
118
  determineUpdateType() {
71
119
  if (this.update.message?.photo) {
72
120
  return 'photo';
@@ -127,6 +175,9 @@ export default class TelegramExecutionContext {
127
175
  if (this.update.message?.message_id) {
128
176
  return this.update.message.message_id.toString();
129
177
  }
178
+ else if (this.update.business_message?.message_id) {
179
+ return this.update.business_message.message_id.toString();
180
+ }
130
181
  else if (this.update.guest_message?.message_id) {
131
182
  return this.update.guest_message.message_id.toString();
132
183
  }
@@ -137,7 +188,7 @@ export default class TelegramExecutionContext {
137
188
  * @returns The message thread ID as a number or undefined
138
189
  */
139
190
  getThreadId() {
140
- return this.update.message?.message_thread_id;
191
+ return this.update.message?.message_thread_id ?? this.update.business_message?.message_thread_id;
141
192
  }
142
193
  /**
143
194
  * Reply to the last message with a video
@@ -145,36 +196,85 @@ export default class TelegramExecutionContext {
145
196
  * @param options - any additional options to pass to sendVideo
146
197
  * @returns Promise with the API response
147
198
  */
148
- async replyVideo(video, options = {}) {
149
- switch (this.update_type) {
150
- case 'voice':
151
- case 'message':
152
- return await this.api.sendVideo(this.bot.api.toString(), {
153
- ...options,
154
- chat_id: this.getChatId(),
155
- message_thread_id: this.getThreadId(),
156
- reply_to_message_id: this.getMessageId(),
157
- video,
158
- });
159
- case 'business_message':
160
- return await this.api.sendVideo(this.bot.api.toString(), {
161
- ...options,
162
- chat_id: this.getChatId(),
163
- message_thread_id: this.getThreadId(),
164
- business_connection_id: this.update.business_message?.business_connection_id.toString() ?? '',
165
- video,
166
- });
167
- case 'guest_message':
168
- return await this.answerGuestQueryVideo(video);
169
- case 'inline':
170
- return await this.api.answerInline(this.bot.api.toString(), {
171
- ...options,
172
- inline_query_id: this.update.inline_query?.id.toString() ?? '',
173
- results: [new TelegramInlineQueryResultVideo({ video })],
174
- });
175
- default:
199
+ /**
200
+ * Helper to handle business connection fallbacks
201
+ */
202
+ async withBusinessFallback(params, apiMethod) {
203
+ const connectionId = params.business_connection_id?.toString();
204
+ if (connectionId) {
205
+ if (TelegramExecutionContext.poisonedConnections.has(connectionId)) {
206
+ return null;
207
+ }
208
+ let ownerId = TelegramExecutionContext.businessOwners.get(connectionId);
209
+ if (ownerId === undefined) {
210
+ try {
211
+ const response = await this.api.getBusinessConnection(this.bot.api.toString(), connectionId);
212
+ if (response.status === 200) {
213
+ const json = await response.json();
214
+ if (json.ok && json.result) {
215
+ ownerId = json.result.user?.id || json.result.user_chat_id;
216
+ if (ownerId) {
217
+ TelegramExecutionContext.businessOwners.set(connectionId, ownerId);
218
+ }
219
+ if (json.result.can_reply === false) {
220
+ TelegramExecutionContext.poisonedConnections.add(connectionId);
221
+ return null;
222
+ }
223
+ }
224
+ }
225
+ }
226
+ catch (e) {
227
+ if (e instanceof Error && e.message === 'BUSINESS_CONNECTION_INVALID') {
228
+ TelegramExecutionContext.poisonedConnections.add(connectionId);
229
+ return null;
230
+ }
231
+ }
232
+ }
233
+ if (ownerId !== undefined && params.chat_id?.toString() === ownerId.toString()) {
176
234
  return null;
235
+ }
236
+ }
237
+ try {
238
+ return await apiMethod(this.bot.api.toString(), params);
177
239
  }
240
+ catch (e) {
241
+ if (e instanceof Error) {
242
+ if (e.message === 'BUSINESS_CONNECTION_INVALID') {
243
+ if (connectionId) {
244
+ TelegramExecutionContext.poisonedConnections.add(connectionId);
245
+ }
246
+ return null;
247
+ }
248
+ if (e.message === 'PEER_ID_INVALID') {
249
+ return null;
250
+ }
251
+ }
252
+ throw e;
253
+ }
254
+ }
255
+ async replyVideo(video, options = {}) {
256
+ const params = {
257
+ ...options,
258
+ chat_id: this.getChatId(),
259
+ message_thread_id: this.getThreadId(),
260
+ reply_to_message_id: this.getMessageId(),
261
+ video,
262
+ };
263
+ if (this.update_type === 'business_message') {
264
+ params['business_connection_id'] = this.update.business_message?.business_connection_id;
265
+ return await this.withBusinessFallback(params, (api, data) => this.api.sendVideo(api, data));
266
+ }
267
+ if (this.update_type === 'guest_message') {
268
+ return await this.answerGuestQueryVideo(video);
269
+ }
270
+ if (this.update_type === 'inline') {
271
+ return await this.api.answerInline(this.bot.api.toString(), {
272
+ ...options,
273
+ inline_query_id: this.update.inline_query?.id.toString() ?? '',
274
+ results: [{ type: 'video', id: crypto.randomUUID(), video_url: video, mime_type: 'video/mp4', thumbnail_url: video, title: 'Video' }],
275
+ });
276
+ }
277
+ return await this.api.sendVideo(this.bot.api.toString(), params);
178
278
  }
179
279
  /**
180
280
  * Get File from telegram file_id
@@ -192,37 +292,28 @@ export default class TelegramExecutionContext {
192
292
  * @returns Promise with the API response
193
293
  */
194
294
  async replyPhoto(photo, caption = '', options = {}) {
195
- switch (this.update_type) {
196
- case 'voice':
197
- case 'photo':
198
- case 'message':
199
- return await this.api.sendPhoto(this.bot.api.toString(), {
200
- ...options,
201
- chat_id: this.getChatId(),
202
- message_thread_id: this.getThreadId(),
203
- reply_to_message_id: this.getMessageId(),
204
- photo,
205
- caption,
206
- });
207
- case 'business_message':
208
- return await this.api.sendPhoto(this.bot.api.toString(), {
209
- ...options,
210
- chat_id: this.getChatId(),
211
- message_thread_id: this.getThreadId(),
212
- business_connection_id: this.update.business_message?.business_connection_id.toString() ?? '',
213
- photo,
214
- caption,
215
- });
216
- case 'guest_message':
217
- return await this.answerGuestQueryPhoto(photo, caption);
218
- case 'inline':
219
- return await this.api.answerInline(this.bot.api.toString(), {
220
- inline_query_id: this.update.inline_query?.id.toString() ?? '',
221
- results: [new TelegramInlineQueryResultPhoto({ photo })],
222
- });
223
- default:
224
- return null;
295
+ const params = {
296
+ ...options,
297
+ chat_id: this.getChatId(),
298
+ message_thread_id: this.getThreadId(),
299
+ reply_to_message_id: this.getMessageId(),
300
+ photo,
301
+ caption,
302
+ };
303
+ if (this.update_type === 'business_message') {
304
+ params['business_connection_id'] = this.update.business_message?.business_connection_id;
305
+ return await this.withBusinessFallback(params, (api, data) => this.api.sendPhoto(api, data));
306
+ }
307
+ if (this.update_type === 'guest_message') {
308
+ return await this.answerGuestQueryPhoto(photo, caption);
225
309
  }
310
+ if (this.update_type === 'inline') {
311
+ return await this.api.answerInline(this.bot.api.toString(), {
312
+ inline_query_id: this.update.inline_query?.id.toString() ?? '',
313
+ results: [{ type: 'photo', id: crypto.randomUUID(), photo_url: photo, thumbnail_url: photo }],
314
+ });
315
+ }
316
+ return await this.api.sendPhoto(this.bot.api.toString(), params);
226
317
  }
227
318
  /**
228
319
  * Reply to the last message with a voice message
@@ -232,57 +323,38 @@ export default class TelegramExecutionContext {
232
323
  * @returns Promise with the API response
233
324
  */
234
325
  async replyVoice(voice, caption = '', options = {}) {
235
- switch (this.update_type) {
236
- case 'voice':
237
- case 'message':
238
- return await this.api.sendVoice(this.bot.api.toString(), {
239
- ...options,
240
- chat_id: this.getChatId(),
241
- message_thread_id: this.getThreadId(),
242
- reply_to_message_id: this.getMessageId(),
243
- voice,
244
- caption,
245
- });
246
- case 'business_message':
247
- return await this.api.sendVoice(this.bot.api.toString(), {
248
- ...options,
249
- chat_id: this.getChatId(),
250
- message_thread_id: this.getThreadId(),
251
- business_connection_id: this.update.business_message?.business_connection_id.toString() ?? '',
252
- voice,
253
- caption,
254
- });
255
- case 'guest_message':
256
- return await this.answerGuestQueryVoice(voice, caption);
257
- default:
258
- return null;
326
+ const params = {
327
+ ...options,
328
+ chat_id: this.getChatId(),
329
+ message_thread_id: this.getThreadId(),
330
+ reply_to_message_id: this.getMessageId(),
331
+ voice,
332
+ caption,
333
+ };
334
+ if (this.update_type === 'business_message') {
335
+ params['business_connection_id'] = this.update.business_message?.business_connection_id;
336
+ return await this.withBusinessFallback(params, (api, data) => this.api.sendVoice(api, data));
337
+ }
338
+ if (this.update_type === 'guest_message') {
339
+ return await this.answerGuestQueryVoice(voice, caption);
259
340
  }
341
+ return await this.api.sendVoice(this.bot.api.toString(), params);
260
342
  }
261
343
  /**
262
344
  * Send typing in a chat
263
345
  * @returns Promise with the API response
264
346
  */
265
347
  async sendTyping() {
266
- switch (this.update_type) {
267
- case 'voice':
268
- case 'message':
269
- case 'photo':
270
- case 'document':
271
- return await this.api.sendChatAction(this.bot.api.toString(), {
272
- chat_id: this.getChatId(),
273
- message_thread_id: this.getThreadId(),
274
- action: 'typing',
275
- });
276
- case 'business_message':
277
- return await this.api.sendChatAction(this.bot.api.toString(), {
278
- business_connection_id: this.update.business_message?.business_connection_id.toString() ?? '',
279
- chat_id: this.getChatId(),
280
- message_thread_id: this.getThreadId(),
281
- action: 'typing',
282
- });
283
- default:
284
- return null;
348
+ const params = {
349
+ chat_id: this.getChatId(),
350
+ message_thread_id: this.getThreadId(),
351
+ action: 'typing',
352
+ };
353
+ if (this.update_type === 'business_message') {
354
+ params['business_connection_id'] = this.update.business_message?.business_connection_id;
355
+ return await this.withBusinessFallback(params, (api, data) => this.api.sendChatAction(api, data));
285
356
  }
357
+ return await this.api.sendChatAction(this.bot.api.toString(), params);
286
358
  }
287
359
  /**
288
360
  * Reply to an inline message with a title and content
@@ -295,7 +367,7 @@ export default class TelegramExecutionContext {
295
367
  if (this.update_type === 'inline') {
296
368
  return await this.api.answerInline(this.bot.api.toString(), {
297
369
  inline_query_id: this.update.inline_query?.id.toString() ?? '',
298
- results: [new TelegramInlineQueryResultArticle({ content: message, title, parse_mode })],
370
+ results: [{ type: 'article', id: crypto.randomUUID(), title: title ?? '', input_message_content: { message_text: message, parse_mode: parse_mode } }],
299
371
  });
300
372
  }
301
373
  return null;
@@ -318,7 +390,7 @@ export default class TelegramExecutionContext {
318
390
  * @returns Promise with the API response
319
391
  */
320
392
  async answerGuestQueryText(message, parse_mode = '') {
321
- return await this.answerGuestQuery(new TelegramInlineQueryResultArticle({ content: message, title: 'Response', parse_mode }));
393
+ return await this.answerGuestQuery({ type: 'article', id: crypto.randomUUID(), title: 'Response', input_message_content: { message_text: message, parse_mode: parse_mode } });
322
394
  }
323
395
  /**
324
396
  * Answer a guest query with a photo
@@ -328,7 +400,7 @@ export default class TelegramExecutionContext {
328
400
  * @returns Promise with the API response
329
401
  */
330
402
  async answerGuestQueryPhoto(photo, caption = '', parse_mode = '') {
331
- return await this.answerGuestQuery(new TelegramInlineQueryResultPhoto({ photo, caption, parse_mode }));
403
+ return await this.answerGuestQuery({ type: 'photo', id: crypto.randomUUID(), photo_url: photo, thumbnail_url: photo, caption, parse_mode: parse_mode });
332
404
  }
333
405
  /**
334
406
  * Answer a guest query with a video
@@ -338,7 +410,7 @@ export default class TelegramExecutionContext {
338
410
  * @returns Promise with the API response
339
411
  */
340
412
  async answerGuestQueryVideo(video, caption = '', parse_mode = '') {
341
- return await this.answerGuestQuery(new TelegramInlineQueryResultVideo({ video, caption, parse_mode }));
413
+ return await this.answerGuestQuery({ type: 'video', id: crypto.randomUUID(), video_url: video, mime_type: 'video/mp4', thumbnail_url: video, title: 'Video', caption, parse_mode: parse_mode });
342
414
  }
343
415
  /**
344
416
  * Answer a guest query with a voice message
@@ -348,7 +420,7 @@ export default class TelegramExecutionContext {
348
420
  * @returns Promise with the API response
349
421
  */
350
422
  async answerGuestQueryVoice(voice, caption = '', parse_mode = '') {
351
- return await this.answerGuestQuery(new TelegramInlineQueryResultVoice({ voice, caption, parse_mode }));
423
+ return await this.answerGuestQuery({ type: 'voice', id: crypto.randomUUID(), voice_url: voice, title: 'Voice', caption, parse_mode: parse_mode });
352
424
  }
353
425
  /** Map of draft IDs to message IDs for streaming */
354
426
  drafts = new Map();
@@ -360,104 +432,56 @@ export default class TelegramExecutionContext {
360
432
  * @param options - any additional options to pass to sendMessage/editMessageText
361
433
  * @returns Promise with the API response
362
434
  */
363
- async streamReply(message, draft_id, parse_mode = '', options = {}) {
364
- const message_id = this.drafts.get(draft_id);
365
- const business_connection_id = this.update.business_message?.business_connection_id.toString();
366
- if (message_id) {
367
- return await this.api.editMessageText(this.bot.api.toString(), {
368
- chat_id: this.getChatId(),
369
- message_id,
370
- text: message,
371
- parse_mode,
372
- business_connection_id,
373
- ...options,
374
- });
375
- }
435
+ async streamReply(message, draft_id, parse_mode = '', options = {}, finish = false) {
376
436
  if (this.update_type === 'guest_message') {
377
- if (this.drafts.has(draft_id)) {
378
- return new Response('Query already answered', { status: 200 });
437
+ if (finish) {
438
+ return await this.answerGuestQueryText(message, parse_mode);
379
439
  }
380
- this.drafts.set(draft_id, -1);
381
- return await this.answerGuestQueryText(message, parse_mode);
440
+ return null;
441
+ }
442
+ if (finish) {
443
+ return await this.reply(message, parse_mode, true, options);
382
444
  }
383
- const response = await this.api.sendMessage(this.bot.api.toString(), {
445
+ const params = {
384
446
  ...options,
385
447
  chat_id: this.getChatId(),
386
448
  message_thread_id: this.getThreadId(),
387
449
  text: message,
388
450
  parse_mode,
389
- business_connection_id,
390
- });
391
- if (response.status === 200) {
392
- const cloned = response.clone();
393
- try {
394
- const json = (await cloned.json());
395
- if (json.ok && json.result?.message_id) {
396
- this.drafts.set(draft_id, json.result.message_id);
397
- }
398
- }
399
- catch {
400
- // ignore
401
- }
451
+ draft_id,
452
+ };
453
+ if (this.update_type === 'business_message') {
454
+ params.business_connection_id = this.update.business_message?.business_connection_id;
402
455
  }
403
- return response;
456
+ return await this.withBusinessFallback(params, (api, data) => this.api.sendMessageDraft(api, data));
404
457
  }
405
- /**
406
- * Reply to the last message with text
407
- * @param message - text to reply with
408
- * @param parse_mode - one of HTML, MarkdownV2, Markdown, or an empty string for ascii
409
- * @param options - any additional options to pass to sendMessage
410
- * @returns Promise with the API response
411
- */
412
458
  async reply(message, parse_mode = '', reply = true, options = {}) {
413
- switch (this.update_type) {
414
- case 'voice':
415
- case 'message':
416
- case 'photo':
417
- case 'document':
418
- if (reply) {
419
- return await this.api.sendMessage(this.bot.api.toString(), {
420
- ...options,
421
- chat_id: this.getChatId(),
422
- message_thread_id: this.getThreadId(),
423
- reply_to_message_id: this.getMessageId(),
424
- text: message,
425
- parse_mode,
426
- });
427
- }
428
- return await this.api.sendMessage(this.bot.api.toString(), {
429
- ...options,
430
- chat_id: this.getChatId(),
431
- message_thread_id: this.getThreadId(),
432
- text: message,
433
- parse_mode,
434
- });
435
- case 'guest_message':
436
- return await this.answerGuestQueryText(message, parse_mode);
437
- case 'business_message':
438
- return await this.api.sendMessage(this.bot.api.toString(), {
439
- chat_id: this.getChatId(),
440
- message_thread_id: this.getThreadId(),
441
- text: message,
442
- business_connection_id: this.update.business_message?.business_connection_id.toString() ?? '',
443
- parse_mode,
444
- });
445
- case 'callback':
446
- if (this.update.callback_query?.message.chat.id) {
447
- return await this.api.sendMessage(this.bot.api.toString(), {
448
- ...options,
449
- chat_id: this.update.callback_query.message.chat.id.toString(),
450
- message_thread_id: this.getThreadId(),
451
- text: message,
452
- parse_mode,
453
- });
454
- }
455
- return null;
456
- case 'inline':
457
- return await this.replyInline('Response', message, parse_mode);
458
- default:
459
- return null;
459
+ if (this.update_type === 'guest_message') {
460
+ return await this.answerGuestQueryText(message, parse_mode);
461
+ }
462
+ if (this.update_type === 'inline') {
463
+ return await this.replyInline('Response', message, parse_mode);
460
464
  }
465
+ const params = {
466
+ ...options,
467
+ chat_id: this.getChatId(),
468
+ message_thread_id: this.getThreadId(),
469
+ text: message,
470
+ parse_mode,
471
+ };
472
+ if (reply) {
473
+ params.reply_to_message_id = this.getMessageId();
474
+ }
475
+ if (this.update_type === 'business_message') {
476
+ params['business_connection_id'] = this.update.business_message?.business_connection_id;
477
+ return await this.withBusinessFallback(params, (api, data) => this.api.sendMessage(api, data));
478
+ }
479
+ if (this.update_type === 'callback') {
480
+ if (this.update.callback_query?.message?.chat.id) {
481
+ params['chat_id'] = this.update.callback_query.message.chat.id.toString();
482
+ }
483
+ }
484
+ return await this.api.sendMessage(this.bot.api.toString(), params);
461
485
  }
462
486
  /**
463
487
  * Send an invoice for Telegram Stars
@@ -468,17 +492,21 @@ export default class TelegramExecutionContext {
468
492
  * @returns Promise with the API response
469
493
  */
470
494
  async sendStarsInvoice(title, description, payload, amount) {
471
- return await this.api.sendInvoice(this.bot.api.toString(), {
495
+ const params = {
472
496
  chat_id: this.getChatId(),
473
497
  message_thread_id: this.getThreadId(),
474
- business_connection_id: this.update.business_message?.business_connection_id.toString(),
475
498
  title,
476
499
  description,
477
500
  payload,
478
501
  provider_token: '',
479
502
  currency: 'XTR',
480
503
  prices: [{ label: title, amount }],
481
- });
504
+ };
505
+ if (this.update_type === 'business_message') {
506
+ params['business_connection_id'] = this.update.business_message?.business_connection_id;
507
+ return await this.withBusinessFallback(params, (api, data) => this.api.sendInvoice(api, data));
508
+ }
509
+ return await this.api.sendInvoice(this.bot.api.toString(), params);
482
510
  }
483
511
  /**
484
512
  * Answer a pre-checkout query
@@ -1,10 +1,10 @@
1
- import TelegramBusinessMessage from './TelegramBusinessMessage.js';
2
- import TelegramInlineQuery from './TelegramInlineQuery.js';
3
- import TelegramMessage from './TelegramMessage.js';
1
+ import { Message as TelegramBusinessMessage } from '@grammyjs/types';
2
+ import { InlineQuery as TelegramInlineQuery } from '@grammyjs/types';
3
+ import { Message as TelegramMessage } from '@grammyjs/types';
4
4
  import TelegramGuestMessage from './TelegramGuestMessage.js';
5
- import TelegramPreCheckoutQuery from './TelegramPreCheckoutQuery.js';
6
- import TelegramCallbackQuery from './TelegramCallbackQuery.js';
7
- import TelegramBusinessConnection from './TelegramBusinessConnection.js';
5
+ import { PreCheckoutQuery as TelegramPreCheckoutQuery } from '@grammyjs/types';
6
+ import { CallbackQuery as TelegramCallbackQuery } from '@grammyjs/types';
7
+ import { BusinessConnection as TelegramBusinessConnection } from '@grammyjs/types';
8
8
  interface PartialTelegramUpdate {
9
9
  update_id?: number;
10
10
  message?: TelegramMessage;
@@ -1,4 +1,4 @@
1
1
  import TelegramBot from '../telegram_bot.js';
2
- import TelegramUpdate from './TelegramUpdate.js';
2
+ import { Update as TelegramUpdate } from '@grammyjs/types';
3
3
  type TelegramCommand = (bot: TelegramBot, update: TelegramUpdate, args: string[]) => Promise<Response>;
4
4
  export default TelegramCommand;
@@ -1,4 +1,4 @@
1
- import TelegramMessage from "./TelegramMessage.js";
1
+ import { Message as TelegramMessage } from '@grammyjs/types';
2
2
  export default interface TelegramGuestMessage extends TelegramMessage {
3
3
  guest_query_id: string;
4
4
  }
package/dist/types.d.ts CHANGED
@@ -1,22 +1,10 @@
1
+ import { Chat as TelegramChat, User as TelegramUser, User as TelegramFrom, MessageEntity as TelegramMessageEntity, PhotoSize as TelegramPhotoSize, Message as TelegramMessage, InputMessageContent as TelegramInputMessageContent, InlineQuery as TelegramInlineQuery, Update as TelegramUpdate, InlineQueryResult as TelegramInlineQueryResult, InlineQueryResultPhoto as TelegramInlineQueryResultPhoto, InlineQueryResultArticle as TelegramInlineQueryResultArticle, ChatPermissions as ChatPermissions } from '@grammyjs/types';
1
2
  import TelegramBot from './telegram_bot.js';
2
3
  import TelegramExecutionContext from './telegram_execution_context.js';
3
4
  import Webhook from './webhook.js';
4
5
  import TelegramApi from './telegram_api.js';
5
6
  import TelegramCommand from './types/TelegramCommand.js';
6
- import TelegramFrom from './types/TelegramFrom.js';
7
- import TelegramChat from './types/TelegramChat.js';
8
- import TelegramUser from './types/TelegramUser.js';
9
- import TelegramMessageEntity from './types/TelegramMessageEntity.js';
10
- import TelegramPhotoSize from './types/TelegramPhotoSize.js';
11
- import TelegramMessage from './types/TelegramMessage.js';
12
- import TelegramInputMessageContent from './types/TelegramInputMessageContent.js';
13
- import TelegramInlineQuery from './types/TelegramInlineQuery.js';
14
- import TelegramUpdate from './types/TelegramUpdate.js';
15
7
  import PartialTelegramUpdate from './types/PartialTelegramUpdate.js';
16
8
  import TelegramInlineQueryType from './types/TelegramInlineQueryType.js';
17
- import TelegramInlineQueryResult from './types/TelegramInlineQueryResult.js';
18
- import TelegramInlineQueryResultPhoto from './types/TelegramInlineQueryResultPhoto.js';
19
- import TelegramInlineQueryResultArticle from './types/TelegramInlineQueryResultArticle.js';
20
- import ChatPermissions from './types/ChatPermissions.js';
21
9
  export default TelegramBot;
22
10
  export { TelegramBot, TelegramExecutionContext, Webhook, TelegramApi, TelegramCommand, TelegramFrom, TelegramChat, TelegramUser, TelegramMessageEntity, TelegramPhotoSize, TelegramMessage, TelegramInputMessageContent, TelegramInlineQuery, TelegramUpdate, PartialTelegramUpdate, TelegramInlineQueryType, TelegramInlineQueryResult, TelegramInlineQueryResultPhoto, TelegramInlineQueryResultArticle, ChatPermissions, };
package/dist/types.js CHANGED
@@ -2,9 +2,5 @@ import TelegramBot from './telegram_bot.js';
2
2
  import TelegramExecutionContext from './telegram_execution_context.js';
3
3
  import Webhook from './webhook.js';
4
4
  import TelegramApi from './telegram_api.js';
5
- import TelegramUpdate from './types/TelegramUpdate.js';
6
- import TelegramInlineQueryResult from './types/TelegramInlineQueryResult.js';
7
- import TelegramInlineQueryResultPhoto from './types/TelegramInlineQueryResultPhoto.js';
8
- import TelegramInlineQueryResultArticle from './types/TelegramInlineQueryResultArticle.js';
9
5
  export default TelegramBot;
10
- export { TelegramBot, TelegramExecutionContext, Webhook, TelegramApi, TelegramUpdate, TelegramInlineQueryResult, TelegramInlineQueryResultPhoto, TelegramInlineQueryResultArticle, };
6
+ export { TelegramBot, TelegramExecutionContext, Webhook, TelegramApi, };
package/dist/utils.js CHANGED
@@ -27,16 +27,17 @@ export async function markdownToHtml(s) {
27
27
  return result;
28
28
  };
29
29
  renderer.listitem = (item) => {
30
- return renderer.parser.parseInline(item.tokens);
30
+ return renderer.parser.parse(item.tokens).trim();
31
31
  };
32
32
  renderer.strong = ({ tokens }) => `<b>${renderer.parser.parseInline(tokens)}</b>`;
33
33
  renderer.em = ({ tokens }) => `<i>${renderer.parser.parseInline(tokens)}</i>`;
34
34
  renderer.codespan = ({ text }) => `<code>${text}</code>`;
35
35
  renderer.code = ({ text, lang }) => {
36
+ const escapedText = text.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
36
37
  if (lang) {
37
- return `<pre><code class="language-${lang}">${text}</code></pre>\n`;
38
+ return `<pre><code class="language-${lang}">${escapedText}</code></pre>\n`;
38
39
  }
39
- return `<pre><code>${text}</code></pre>\n`;
40
+ return `<pre><code>${escapedText}</code></pre>\n`;
40
41
  };
41
42
  renderer.del = ({ tokens }) => `<s>${renderer.parser.parseInline(tokens)}</s>`;
42
43
  renderer.link = ({ href, tokens }) => `<a href="${href}">${renderer.parser.parseInline(tokens)}</a>`;