@codebam/cf-workers-telegram-bot 9.4.1 → 11.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.
@@ -4,6 +4,7 @@ import TelegramInlineQueryResultVideo from './types/TelegramInlineQueryResultVid
4
4
  /** Interface for common Telegram API parameters */
5
5
  export interface TelegramApiBaseParams {
6
6
  chat_id: number | string;
7
+ message_thread_id?: number;
7
8
  business_connection_id?: string | number;
8
9
  }
9
10
  /** Interface for message parameters */
@@ -12,7 +12,9 @@ export default class TelegramBot {
12
12
  /** The telegram update object */
13
13
  update: TelegramUpdate;
14
14
  /** The telegram commands record map */
15
- commands: Record<string, (ctx: TelegramExecutionContext) => Promise<Response>>;
15
+ commands: Record<string, (ctx: TelegramExecutionContext) => Promise<Response | void>>;
16
+ /** Middleware functions to run before handlers */
17
+ middleware: ((ctx: TelegramExecutionContext) => Promise<Response | void>)[];
16
18
  /** The current bot context */
17
19
  currentContext: TelegramExecutionContext;
18
20
  /** Default command to use when no matching command is found */
@@ -30,12 +32,38 @@ export default class TelegramBot {
30
32
  * @param event - the event or command name
31
33
  * @param callback - the bot context
32
34
  */
33
- on(event: string, callback: (ctx: TelegramExecutionContext) => Promise<Response>): this;
35
+ on(event: string, callback: (ctx: TelegramExecutionContext) => Promise<Response | void>): this;
36
+ /**
37
+ * Register middleware to run before all handlers
38
+ * @param callback - the middleware function
39
+ */
40
+ use(callback: (ctx: TelegramExecutionContext) => Promise<Response | void>): this;
41
+ /**
42
+ * Register a command handler
43
+ * @param commandName - the command name (without /)
44
+ * @param callback - the handler function
45
+ */
46
+ command(commandName: string, callback: (ctx: TelegramExecutionContext) => Promise<Response | void>): this;
47
+ /**
48
+ * Register a message handler
49
+ * @param callback - the handler function
50
+ */
51
+ onMessage(callback: (ctx: TelegramExecutionContext) => Promise<Response | void>): this;
52
+ /**
53
+ * Register a photo handler
54
+ * @param callback - the handler function
55
+ */
56
+ onPhoto(callback: (ctx: TelegramExecutionContext) => Promise<Response | void>): this;
57
+ /**
58
+ * Register a callback query handler
59
+ * @param callback - the handler function
60
+ */
61
+ onCallback(callback: (ctx: TelegramExecutionContext) => Promise<Response | void>): this;
34
62
  /**
35
63
  * Register multiple command handlers at once
36
64
  * @param handlers - object mapping command names to handler functions
37
65
  */
38
- registerHandlers(handlers: Record<string, (ctx: TelegramExecutionContext) => Promise<Response>>): this;
66
+ registerHandlers(handlers: Record<string, (ctx: TelegramExecutionContext) => Promise<Response | void>>): this;
39
67
  /**
40
68
  * Determine the command from the update
41
69
  * @param ctx - the execution context
@@ -43,12 +71,6 @@ export default class TelegramBot {
43
71
  * @returns the command string
44
72
  */
45
73
  private determineCommand;
46
- /**
47
- * Parse arguments from the update
48
- * @param ctx - the execution context
49
- * @returns array of argument strings
50
- */
51
- private parseArguments;
52
74
  /**
53
75
  * Handle a request on a given bot
54
76
  * @param request - the request to handle
@@ -13,6 +13,8 @@ export default class TelegramBot {
13
13
  update = new TelegramUpdate({});
14
14
  /** The telegram commands record map */
15
15
  commands = {};
16
+ /** Middleware functions to run before handlers */
17
+ middleware = [];
16
18
  /** The current bot context */
17
19
  currentContext;
18
20
  /** Default command to use when no matching command is found */
@@ -40,6 +42,43 @@ export default class TelegramBot {
40
42
  this.commands[event] = callback;
41
43
  return this;
42
44
  }
45
+ /**
46
+ * Register middleware to run before all handlers
47
+ * @param callback - the middleware function
48
+ */
49
+ use(callback) {
50
+ this.middleware.push(callback);
51
+ return this;
52
+ }
53
+ /**
54
+ * Register a command handler
55
+ * @param commandName - the command name (without /)
56
+ * @param callback - the handler function
57
+ */
58
+ command(commandName, callback) {
59
+ return this.on(commandName, callback);
60
+ }
61
+ /**
62
+ * Register a message handler
63
+ * @param callback - the handler function
64
+ */
65
+ onMessage(callback) {
66
+ return this.on(':message', callback);
67
+ }
68
+ /**
69
+ * Register a photo handler
70
+ * @param callback - the handler function
71
+ */
72
+ onPhoto(callback) {
73
+ return this.on(':photo', callback);
74
+ }
75
+ /**
76
+ * Register a callback query handler
77
+ * @param callback - the handler function
78
+ */
79
+ onCallback(callback) {
80
+ return this.on(':callback', callback);
81
+ }
43
82
  /**
44
83
  * Register multiple command handlers at once
45
84
  * @param handlers - object mapping command names to handler functions
@@ -81,23 +120,6 @@ export default class TelegramBot {
81
120
  }
82
121
  return this.defaultCommand;
83
122
  }
84
- /**
85
- * Parse arguments from the update
86
- * @param ctx - the execution context
87
- * @returns array of argument strings
88
- */
89
- parseArguments(ctx) {
90
- switch (ctx.update_type) {
91
- case 'message':
92
- case 'business_message':
93
- case 'guest_message':
94
- return (this.update.message?.text ?? this.update.guest_message?.text)?.split(' ') ?? [];
95
- case 'inline':
96
- return this.update.inline_query?.query.split(' ') ?? [];
97
- default:
98
- return [];
99
- }
100
- }
101
123
  /**
102
124
  * Handle a request on a given bot
103
125
  * @param request - the request to handle
@@ -117,9 +139,16 @@ export default class TelegramBot {
117
139
  console.log(this.update);
118
140
  const ctx = new TelegramExecutionContext(this, this.update);
119
141
  this.currentContext = ctx;
120
- const args = this.parseArguments(ctx);
121
- const command = this.determineCommand(ctx, args);
122
- return await this.commands[command](ctx);
142
+ // Run middleware
143
+ for (const middleware of this.middleware) {
144
+ const result = await middleware(ctx);
145
+ if (result instanceof Response) {
146
+ return result;
147
+ }
148
+ }
149
+ const command = this.determineCommand(ctx, ctx.args);
150
+ const response = await this.commands[command](ctx);
151
+ return response instanceof Response ? response : new Response('ok');
123
152
  }
124
153
  catch (error) {
125
154
  console.error('Error handling Telegram update:', error);
@@ -11,12 +11,34 @@ export default class TelegramExecutionContext {
11
11
  update_type: string;
12
12
  /** reference to TelegramApi class */
13
13
  api: TelegramApi;
14
+ /** array of arguments parsed from the message */
15
+ args: string[];
14
16
  /**
15
17
  * Create a telegram execution context
16
18
  * @param bot - the telegram bot
17
19
  * @param update - the telegram update
18
20
  */
19
21
  constructor(bot: TelegramBot, update: TelegramUpdate);
22
+ /**
23
+ * Get the message text from the current update
24
+ * @returns The message text as a string or empty string if not available
25
+ */
26
+ get text(): string;
27
+ /**
28
+ * Get the chat ID as a string
29
+ * @returns The chat ID
30
+ */
31
+ get chatId(): string;
32
+ /**
33
+ * Get the user ID from the current update
34
+ * @returns The user ID or undefined if not available
35
+ */
36
+ get userId(): number | undefined;
37
+ /**
38
+ * Parse arguments from the update
39
+ * @returns array of argument strings
40
+ */
41
+ private parseArguments;
20
42
  /**
21
43
  * Determine the type of update received
22
44
  * @returns The update type as a string
@@ -32,6 +54,11 @@ export default class TelegramExecutionContext {
32
54
  * @returns The message ID as a string or empty string if not available
33
55
  */
34
56
  private getMessageId;
57
+ /**
58
+ * Get the message thread ID from the current update
59
+ * @returns The message thread ID as a number or undefined
60
+ */
61
+ private getThreadId;
35
62
  /**
36
63
  * Reply to the last message with a video
37
64
  * @param video - string to a video on the internet or a file_id on telegram
@@ -12,6 +12,8 @@ export default class TelegramExecutionContext {
12
12
  update_type = '';
13
13
  /** reference to TelegramApi class */
14
14
  api = new TelegramApi();
15
+ /** array of arguments parsed from the message */
16
+ args = [];
15
17
  /**
16
18
  * Create a telegram execution context
17
19
  * @param bot - the telegram bot
@@ -21,6 +23,44 @@ export default class TelegramExecutionContext {
21
23
  this.bot = bot;
22
24
  this.update = update;
23
25
  this.update_type = this.determineUpdateType();
26
+ this.args = this.parseArguments();
27
+ }
28
+ /**
29
+ * Get the message text from the current update
30
+ * @returns The message text as a string or empty string if not available
31
+ */
32
+ get text() {
33
+ return (this.update.message?.text ?? this.update.business_message?.text ?? this.update.guest_message?.text)?.toString() ?? '';
34
+ }
35
+ /**
36
+ * Get the chat ID as a string
37
+ * @returns The chat ID
38
+ */
39
+ get chatId() {
40
+ return this.getChatId();
41
+ }
42
+ /**
43
+ * Get the user ID from the current update
44
+ * @returns The user ID or undefined if not available
45
+ */
46
+ get userId() {
47
+ return this.update.message?.from.id ?? this.update.business_message?.from.id ?? this.update.guest_message?.from.id;
48
+ }
49
+ /**
50
+ * Parse arguments from the update
51
+ * @returns array of argument strings
52
+ */
53
+ parseArguments() {
54
+ switch (this.update_type) {
55
+ case 'message':
56
+ case 'business_message':
57
+ case 'guest_message':
58
+ return (this.update.message?.text ?? this.update.guest_message?.text)?.split(' ') ?? [];
59
+ case 'inline':
60
+ return this.update.inline_query?.query.split(' ') ?? [];
61
+ default:
62
+ return [];
63
+ }
24
64
  }
25
65
  /**
26
66
  * Determine the type of update received
@@ -85,6 +125,13 @@ export default class TelegramExecutionContext {
85
125
  }
86
126
  return '';
87
127
  }
128
+ /**
129
+ * Get the message thread ID from the current update
130
+ * @returns The message thread ID as a number or undefined
131
+ */
132
+ getThreadId() {
133
+ return this.update.message?.message_thread_id;
134
+ }
88
135
  /**
89
136
  * Reply to the last message with a video
90
137
  * @param video - string to a video on the internet or a file_id on telegram
@@ -98,6 +145,7 @@ export default class TelegramExecutionContext {
98
145
  return await this.api.sendVideo(this.bot.api.toString(), {
99
146
  ...options,
100
147
  chat_id: this.getChatId(),
148
+ message_thread_id: this.getThreadId(),
101
149
  reply_to_message_id: this.getMessageId(),
102
150
  video,
103
151
  });
@@ -134,6 +182,7 @@ export default class TelegramExecutionContext {
134
182
  return await this.api.sendPhoto(this.bot.api.toString(), {
135
183
  ...options,
136
184
  chat_id: this.getChatId(),
185
+ message_thread_id: this.getThreadId(),
137
186
  reply_to_message_id: this.getMessageId(),
138
187
  photo,
139
188
  caption,
@@ -156,15 +205,16 @@ export default class TelegramExecutionContext {
156
205
  case 'message':
157
206
  case 'photo':
158
207
  case 'document':
159
- case 'guest_message':
160
208
  return await this.api.sendChatAction(this.bot.api.toString(), {
161
209
  chat_id: this.getChatId(),
210
+ message_thread_id: this.getThreadId(),
162
211
  action: 'typing',
163
212
  });
164
213
  case 'business_message':
165
214
  return await this.api.sendChatAction(this.bot.api.toString(), {
166
215
  business_connection_id: this.update.business_message?.business_connection_id.toString() ?? '',
167
216
  chat_id: this.getChatId(),
217
+ message_thread_id: this.getThreadId(),
168
218
  action: 'typing',
169
219
  });
170
220
  default:
@@ -210,6 +260,7 @@ export default class TelegramExecutionContext {
210
260
  return await this.api.sendMessageDraft(this.bot.api.toString(), {
211
261
  ...options,
212
262
  chat_id: this.getChatId(),
263
+ message_thread_id: this.getThreadId(),
213
264
  text: message,
214
265
  parse_mode,
215
266
  draft_id,
@@ -235,6 +286,7 @@ export default class TelegramExecutionContext {
235
286
  return await this.api.sendMessage(this.bot.api.toString(), {
236
287
  ...options,
237
288
  chat_id: this.getChatId(),
289
+ message_thread_id: this.getThreadId(),
238
290
  reply_to_message_id: this.getMessageId(),
239
291
  text: message,
240
292
  parse_mode,
@@ -243,12 +295,14 @@ export default class TelegramExecutionContext {
243
295
  return await this.api.sendMessage(this.bot.api.toString(), {
244
296
  ...options,
245
297
  chat_id: this.getChatId(),
298
+ message_thread_id: this.getThreadId(),
246
299
  text: message,
247
300
  parse_mode,
248
301
  });
249
302
  case 'business_message':
250
303
  return await this.api.sendMessage(this.bot.api.toString(), {
251
304
  chat_id: this.getChatId(),
305
+ message_thread_id: this.getThreadId(),
252
306
  text: message,
253
307
  business_connection_id: this.update.business_message?.business_connection_id.toString() ?? '',
254
308
  parse_mode,
@@ -258,6 +312,7 @@ export default class TelegramExecutionContext {
258
312
  return await this.api.sendMessage(this.bot.api.toString(), {
259
313
  ...options,
260
314
  chat_id: this.update.callback_query.message.chat.id.toString(),
315
+ message_thread_id: this.getThreadId(),
261
316
  text: message,
262
317
  parse_mode,
263
318
  });
@@ -280,6 +335,7 @@ export default class TelegramExecutionContext {
280
335
  async sendStarsInvoice(title, description, payload, amount) {
281
336
  return await this.api.sendInvoice(this.bot.api.toString(), {
282
337
  chat_id: this.getChatId(),
338
+ message_thread_id: this.getThreadId(),
283
339
  title,
284
340
  description,
285
341
  payload,
@@ -7,6 +7,7 @@ import TelegramUser from './TelegramUser.js';
7
7
  import TelegramSuccessfulPayment from './TelegramSuccessfulPayment.js';
8
8
  interface TelegramMessage {
9
9
  message_id: number;
10
+ message_thread_id?: number;
10
11
  from: TelegramFrom;
11
12
  sender_chat?: TelegramChat;
12
13
  date: number;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@codebam/cf-workers-telegram-bot",
3
- "version": "9.4.1",
3
+ "version": "11.0.0",
4
4
  "description": "serverless telegram bot on cf workers",
5
5
  "main": "./dist/main.js",
6
6
  "module": "./dist/main.js",
@@ -8,7 +8,6 @@
8
8
  "files": [
9
9
  "dist",
10
10
  "LICENSE",
11
- "LICENSE_MIT",
12
11
  "README.md"
13
12
  ],
14
13
  "keywords": [
@@ -25,7 +24,10 @@
25
24
  "scripts": {
26
25
  "build": "tsc --project tsconfig.json",
27
26
  "lint": "eslint src",
28
- "test": "vitest --config vitest.config.js"
27
+ "test": "vitest --config vitest.config.js",
28
+ "docs": "typedoc --options typedoc.json",
29
+ "deploy:docs": "npm run docs && wrangler pages deploy docs",
30
+ "ncu": "npx npm-check-updates -i --root -u"
29
31
  },
30
32
  "author": "codebam",
31
33
  "license": "Apache-2.0",
@@ -41,13 +43,17 @@
41
43
  "eslint": "^10.3.0",
42
44
  "eslint-config-prettier": "^10.1.8",
43
45
  "globals": "^17.6.0",
46
+ "npm-check-updates": "^22.1.1",
44
47
  "prettier": "^3.8.3",
48
+ "typedoc": "^0.28.19",
49
+ "typedoc-plugin-extras": "^4.0.1",
45
50
  "typescript": "^6.0.3",
46
51
  "typescript-eslint": "^8.59.2",
47
- "vitest": "^4.1.5"
52
+ "vitest": "^4.1.5",
53
+ "wrangler": "^4.90.0"
48
54
  },
49
55
  "dependencies": {
50
- "typedoc": "0.28.19"
56
+ "@eslint/eslintrc": "^3.3.5"
51
57
  },
52
58
  "typedocOptions": {
53
59
  "entryPoints": [