chz-telegram-bot 0.4.0 → 0.5.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 (51) hide show
  1. package/bun.lock +301 -630
  2. package/dist/dtos/chatHistoryMessage.d.ts +3 -3
  3. package/dist/dtos/chatHistoryMessage.d.ts.map +1 -1
  4. package/dist/dtos/incomingMessage.d.ts +4 -4
  5. package/dist/dtos/incomingMessage.d.ts.map +1 -1
  6. package/dist/dtos/incomingMessage.js +1 -1
  7. package/dist/dtos/messageInfo.d.ts +3 -3
  8. package/dist/dtos/messageInfo.d.ts.map +1 -1
  9. package/dist/dtos/responses/inlineQueryResponse.d.ts +3 -3
  10. package/dist/dtos/responses/inlineQueryResponse.d.ts.map +1 -1
  11. package/dist/dtos/responses/reaction.d.ts +1 -1
  12. package/dist/dtos/responses/reaction.d.ts.map +1 -1
  13. package/dist/entities/context/inlineQueryContext.d.ts +3 -3
  14. package/dist/entities/context/inlineQueryContext.d.ts.map +1 -1
  15. package/dist/entities/context/messageContext.d.ts +2 -2
  16. package/dist/entities/context/messageContext.d.ts.map +1 -1
  17. package/dist/entities/context/replyContext.d.ts +2 -2
  18. package/dist/entities/context/replyContext.d.ts.map +1 -1
  19. package/dist/index.d.ts +1 -0
  20. package/dist/index.d.ts.map +1 -1
  21. package/dist/index.js +1 -0
  22. package/dist/services/actionProcessingService.d.ts +1 -1
  23. package/dist/services/actionProcessingService.d.ts.map +1 -1
  24. package/dist/services/actionProcessingService.js +7 -9
  25. package/dist/services/actionProcessors/commandActionProcessor.d.ts +2 -2
  26. package/dist/services/actionProcessors/commandActionProcessor.d.ts.map +1 -1
  27. package/dist/services/actionProcessors/commandActionProcessor.js +3 -3
  28. package/dist/services/actionProcessors/inlineQueryActionProcessor.d.ts +1 -1
  29. package/dist/services/actionProcessors/inlineQueryActionProcessor.d.ts.map +1 -1
  30. package/dist/services/actionProcessors/inlineQueryActionProcessor.js +1 -1
  31. package/dist/services/telegramApi.d.ts +2 -2
  32. package/dist/services/telegramApi.d.ts.map +1 -1
  33. package/dist/services/telegramApi.js +15 -16
  34. package/dist/types/externalAliases.d.ts +11 -0
  35. package/dist/types/externalAliases.d.ts.map +1 -0
  36. package/dist/types/externalAliases.js +2 -0
  37. package/dtos/chatHistoryMessage.ts +2 -2
  38. package/dtos/incomingMessage.ts +7 -7
  39. package/dtos/messageInfo.ts +2 -2
  40. package/dtos/responses/inlineQueryResponse.ts +3 -3
  41. package/dtos/responses/reaction.ts +1 -1
  42. package/entities/context/inlineQueryContext.ts +3 -3
  43. package/entities/context/messageContext.ts +2 -2
  44. package/entities/context/replyContext.ts +2 -2
  45. package/index.ts +1 -0
  46. package/package.json +37 -40
  47. package/services/actionProcessingService.ts +10 -9
  48. package/services/actionProcessors/commandActionProcessor.ts +7 -7
  49. package/services/actionProcessors/inlineQueryActionProcessor.ts +2 -2
  50. package/services/telegramApi.ts +28 -25
  51. package/types/externalAliases.ts +17 -0
@@ -5,7 +5,7 @@ import {
5
5
  BaseContextInternal,
6
6
  BaseContextPropertiesToOmit
7
7
  } from './baseContext';
8
- import { InlineQueryResult } from 'node-telegram-bot-api';
8
+ import { TelegramInlineQueryResult } from '../../types/externalAliases';
9
9
 
10
10
  export type InlineQueryContext = Omit<
11
11
  InlineQueryContextInternal,
@@ -13,7 +13,7 @@ export type InlineQueryContext = Omit<
13
13
  >;
14
14
 
15
15
  export class InlineQueryContextInternal extends BaseContextInternal<InlineQueryAction> {
16
- queryResults: InlineQueryResult[] = [];
16
+ queryResults: TelegramInlineQueryResult[] = [];
17
17
  /**
18
18
  * Abort signal to be utilized in query handler.
19
19
  * Signal will be aborted if new query comes from the same user.
@@ -42,7 +42,7 @@ export class InlineQueryContextInternal extends BaseContextInternal<InlineQueryA
42
42
  * This result will be shown to user as a response to inline query.
43
43
  * @param queryResult Inline query result to be shown to user.
44
44
  */
45
- showInlineQueryResult(queryResult: InlineQueryResult) {
45
+ showInlineQueryResult(queryResult: TelegramInlineQueryResult) {
46
46
  this.queryResults.push(queryResult);
47
47
  }
48
48
  }
@@ -15,7 +15,7 @@ import { Seconds } from '../../types/timeValues';
15
15
  import { BaseContextPropertiesToOmit } from './baseContext';
16
16
  import { MessageInfo } from '../../dtos/messageInfo';
17
17
  import { UserInfo } from '../../dtos/userInfo';
18
- import { TelegramEmoji, User } from 'node-telegram-bot-api';
18
+ import { BotInfo, TelegramEmoji } from '../../types/externalAliases';
19
19
 
20
20
  export type MessageContext<TActionState extends IActionState> = Omit<
21
21
  MessageContextInternal<TActionState>,
@@ -37,7 +37,7 @@ export class MessageContextInternal<
37
37
  /** Indicates if cooldown should be started after action is executed. Set to `true` by default. */
38
38
  startCooldown: boolean = true;
39
39
  /** Bot info from Telegram */
40
- botInfo!: User;
40
+ botInfo!: BotInfo;
41
41
  customCooldown: Seconds | undefined;
42
42
 
43
43
  private getQuotePart(quote: boolean | string) {
@@ -16,7 +16,7 @@ import {
16
16
  } from './baseContext';
17
17
  import { UserInfo } from '../../dtos/userInfo';
18
18
  import { MessageInfo } from '../../dtos/messageInfo';
19
- import { TelegramEmoji, User } from 'node-telegram-bot-api';
19
+ import { TelegramUser, TelegramEmoji } from '../../types/externalAliases';
20
20
 
21
21
  export type ReplyContext<TActionState extends IActionState> = Omit<
22
22
  ReplyContextInternal<TActionState>,
@@ -38,7 +38,7 @@ export class ReplyContextInternal<
38
38
  /** Information about the message that triggered this action */
39
39
  messageInfo!: MessageInfo;
40
40
  /** Bot info from Telegram */
41
- botInfo!: User;
41
+ botInfo!: TelegramUser;
42
42
 
43
43
  isInitialized = false;
44
44
 
package/index.ts CHANGED
@@ -7,6 +7,7 @@ export * from './entities/states/actionStateBase';
7
7
  export * from './types/messageTypes';
8
8
  export * from './helpers/timeConvertions';
9
9
  export * from './types/action';
10
+ export * from './types/externalAliases';
10
11
  export { CommandAction } from './entities/actions/commandAction';
11
12
  export { InlineQueryAction } from './entities/actions/inlineQueryAction';
12
13
  export { ReplyCaptureAction } from './entities/actions/replyCaptureAction';
package/package.json CHANGED
@@ -1,40 +1,37 @@
1
- {
2
- "name": "chz-telegram-bot",
3
- "description": "Opinionated TypeScript framework that provides a structured approach to building Telegram bots.",
4
- "author": {
5
- "name": "Alex Halanin",
6
- "url": "https://github.com/AlexSolari"
7
- },
8
- "license": "MIT",
9
- "keywords": [
10
- "telegram",
11
- "telegram bot"
12
- ],
13
- "repository": {
14
- "type": "git",
15
- "url": "https://github.com/AlexSolari/botFramework.git"
16
- },
17
- "version": "0.4.0",
18
- "type": "module",
19
- "dependencies": {
20
- "async-sema": "^3.1.1",
21
- "moment": "^2.29.4",
22
- "node-telegram-bot-api": "^0.66.0"
23
- },
24
- "main": "dist/index.js",
25
- "types": "dist/index.d.ts",
26
- "devDependencies": {
27
- "@types/node-telegram-bot-api": "^0.64.10",
28
- "@eslint/js": "^9.29.0",
29
- "@types/markdown-escape": "^1.1.3",
30
- "@types/node": "^22.5.5",
31
- "eslint": "^9.29.0",
32
- "globals": "^16.2.0",
33
- "typescript": "^5.9.0-beta",
34
- "typescript-eslint": "^8.34.1"
35
- },
36
- "scripts": {
37
- "build": "tsc",
38
- "lint": "npx eslint && tsc --noEmit"
39
- }
40
- }
1
+ {
2
+ "name": "chz-telegram-bot",
3
+ "description": "Opinionated TypeScript framework that provides a structured approach to building Telegram bots.",
4
+ "author": {
5
+ "name": "Alex Halanin",
6
+ "url": "https://github.com/AlexSolari"
7
+ },
8
+ "license": "MIT",
9
+ "keywords": [
10
+ "telegram",
11
+ "telegram bot"
12
+ ],
13
+ "repository": {
14
+ "type": "git",
15
+ "url": "https://github.com/AlexSolari/botFramework.git"
16
+ },
17
+ "version": "0.5.0",
18
+ "type": "module",
19
+ "dependencies": {
20
+ "async-sema": "^3.1.1",
21
+ "moment": "^2.29.4",
22
+ "telegraf": "^4.16.3"
23
+ },
24
+ "main": "dist/index.js",
25
+ "types": "dist/index.d.ts",
26
+ "devDependencies": {
27
+ "@eslint/js": "^9.29.0",
28
+ "@types/node": "^22.5.5",
29
+ "eslint": "^9.29.0",
30
+ "typescript": "^5.9.0-beta",
31
+ "typescript-eslint": "^8.34.1"
32
+ },
33
+ "scripts": {
34
+ "build": "tsc",
35
+ "lint": "npx eslint && tsc --noEmit"
36
+ }
37
+ }
@@ -12,7 +12,8 @@ import { buildHelpCommand } from '../builtin/helpAction';
12
12
  import { CommandActionProcessor } from './actionProcessors/commandActionProcessor';
13
13
  import { InlineQueryActionProcessor } from './actionProcessors/inlineQueryActionProcessor';
14
14
  import { ScheduledActionProcessor } from './actionProcessors/scheduledActionProcessor';
15
- import TelegramBot from 'node-telegram-bot-api';
15
+ import { TelegramBot } from '../types/externalAliases';
16
+ import { Telegraf } from 'telegraf';
16
17
 
17
18
  export class ActionProcessingService {
18
19
  private readonly storage: IStorageClient;
@@ -69,10 +70,10 @@ export class ActionProcessingService {
69
70
  scheduledPeriod?: Seconds,
70
71
  verboseLoggingForIncomingMessage?: boolean
71
72
  ) {
72
- this.telegramBot = new TelegramBot(token, { polling: true });
73
+ this.telegramBot = new Telegraf(token);
73
74
  const api = new TelegramApiService(
74
75
  this.botName,
75
- this.telegramBot,
76
+ this.telegramBot.telegram,
76
77
  this.storage,
77
78
  this.logger,
78
79
  (capture, id, chatInfo, traceId) => {
@@ -85,15 +86,13 @@ export class ActionProcessingService {
85
86
  }
86
87
  );
87
88
 
88
- const botInfo = await this.telegramBot.getMe();
89
+ const botInfo = await this.telegramBot.telegram.getMe();
89
90
  const commandActions =
90
91
  actions.commands.length > 0 && botInfo.username
91
92
  ? [
92
93
  buildHelpCommand(
93
94
  actions.commands
94
- .map((x) =>
95
- x.readmeFactory(botInfo.username as string)
96
- )
95
+ .map((x) => x.readmeFactory(botInfo.username))
97
96
  .filter((x) => !!x),
98
97
  botInfo.username
99
98
  ),
@@ -120,13 +119,15 @@ export class ActionProcessingService {
120
119
  scheduledPeriod ?? hoursToSeconds(1 as Hours)
121
120
  );
122
121
 
122
+ void this.telegramBot.launch();
123
+
123
124
  void this.storage.saveMetadata([
124
125
  ...actions.scheduled,
125
126
  ...commandActions
126
127
  ]);
127
128
  }
128
129
 
129
- async stop() {
130
- await this.telegramBot.stopPolling();
130
+ stop() {
131
+ this.telegramBot.stop();
131
132
  }
132
133
  }
@@ -18,14 +18,14 @@ import { getOrSetIfNotExists } from '../../helpers/mapUtils';
18
18
  import { MessageInfo } from '../../dtos/messageInfo';
19
19
  import { UserInfo } from '../../dtos/userInfo';
20
20
  import { ChatHistoryMessage } from '../../dtos/chatHistoryMessage';
21
- import TelegramBot from 'node-telegram-bot-api';
21
+ import { BotInfo, TelegramBot } from '../../types/externalAliases';
22
22
 
23
23
  const MESSAGE_HISTORY_LENGTH_LIMIT = 100;
24
24
 
25
25
  export class CommandActionProcessor extends BaseActionProcessor {
26
26
  private readonly replyCaptures: ReplyCaptureAction<IActionState>[] = [];
27
27
  private readonly chatHistory = new Map<number, ChatHistoryMessage[]>();
28
- private botInfo!: TelegramBot.User;
28
+ private botInfo!: BotInfo;
29
29
 
30
30
  private commands = typeSafeObjectFromEntries(
31
31
  Object.values(MessageType).map((x) => [
@@ -39,7 +39,7 @@ export class CommandActionProcessor extends BaseActionProcessor {
39
39
  telegram: TelegramBot,
40
40
  commands: CommandAction<IActionState>[],
41
41
  verboseLoggingForIncomingMessage: boolean,
42
- botInfo: TelegramBot.User
42
+ botInfo: BotInfo
43
43
  ) {
44
44
  this.botInfo = botInfo;
45
45
  this.initializeDependencies(api);
@@ -70,11 +70,11 @@ export class CommandActionProcessor extends BaseActionProcessor {
70
70
  }
71
71
 
72
72
  if (commands.length > 0) {
73
- telegram.on('message', (msg) => {
73
+ telegram.on('message', ({ message }) => {
74
74
  const internalMessage = new IncomingMessage(
75
- msg,
75
+ message,
76
76
  this.botName,
77
- getOrSetIfNotExists(this.chatHistory, msg.chat.id, [])
77
+ getOrSetIfNotExists(this.chatHistory, message.chat.id, [])
78
78
  );
79
79
 
80
80
  const logger = this.logger.createScope(
@@ -84,7 +84,7 @@ export class CommandActionProcessor extends BaseActionProcessor {
84
84
  );
85
85
 
86
86
  if (verboseLoggingForIncomingMessage) {
87
- logger.logObjectWithTraceId(msg);
87
+ logger.logObjectWithTraceId(message);
88
88
  } else {
89
89
  logger.logWithTraceId(
90
90
  `${internalMessage.from?.first_name ?? 'Unknown'} (${
@@ -1,8 +1,8 @@
1
- import TelegramBot from 'node-telegram-bot-api';
2
1
  import { IncomingInlineQuery } from '../../dtos/incomingQuery';
3
2
  import { InlineQueryAction } from '../../entities/actions/inlineQueryAction';
4
3
  import { InlineQueryContextInternal } from '../../entities/context/inlineQueryContext';
5
4
  import { createTrace } from '../../helpers/traceFactory';
5
+ import { TelegramBot } from '../../types/externalAliases';
6
6
  import { Milliseconds } from '../../types/timeValues';
7
7
  import { TraceId } from '../../types/trace';
8
8
  import { TelegramApiService } from '../telegramApi';
@@ -25,7 +25,7 @@ export class InlineQueryActionProcessor extends BaseActionProcessor {
25
25
  const queriesInProcessing = new Map<number, IncomingInlineQuery>();
26
26
 
27
27
  if (this.inlineQueries.length > 0) {
28
- telegram.on('inline_query', (inlineQuery) => {
28
+ telegram.on('inline_query', ({ inlineQuery }) => {
29
29
  const query = new IncomingInlineQuery(
30
30
  inlineQuery.id,
31
31
  inlineQuery.query,
@@ -7,14 +7,13 @@ import { IActionWithState } from '../types/action';
7
7
  import { IActionState } from '../types/actionState';
8
8
  import { TraceId } from '../types/trace';
9
9
  import { ChatInfo } from '../dtos/chatInfo';
10
- import TelegramBot, { Message } from 'node-telegram-bot-api';
11
- import { createReadStream } from 'fs';
10
+ import { TelegramApiClient, TelegramMessage } from '../types/externalAliases';
12
11
 
13
12
  export const TELEGRAM_ERROR_QUOTE_INVALID = 'QUOTE_TEXT_INVALID';
14
13
 
15
14
  export class TelegramApiService {
16
15
  private readonly queue = new ResponseProcessingQueue();
17
- private readonly telegram: TelegramBot;
16
+ private readonly telegram: TelegramApiClient;
18
17
  private readonly storage: IStorageClient;
19
18
  private readonly logger: ILogger;
20
19
  private readonly captureRegistrationCallback: (
@@ -28,7 +27,7 @@ export class TelegramApiService {
28
27
 
29
28
  constructor(
30
29
  botName: string,
31
- telegram: TelegramBot,
30
+ telegram: TelegramApiClient,
32
31
  storage: IStorageClient,
33
32
  logger: ILogger,
34
33
  captureRegistrationCallback: (
@@ -105,7 +104,10 @@ export class TelegramApiService {
105
104
  void this.queue.flushReadyItems();
106
105
  }
107
106
 
108
- private async pinIfShould(response: IReplyResponse, message: Message) {
107
+ private async pinIfShould(
108
+ response: IReplyResponse,
109
+ message: TelegramMessage
110
+ ) {
109
111
  if (response.shouldPin) {
110
112
  await this.telegram.pinChatMessage(
111
113
  response.chatInfo.id,
@@ -124,7 +126,7 @@ export class TelegramApiService {
124
126
  }
125
127
 
126
128
  private async processResponse(response: BotResponse, ignoreQuote = false) {
127
- let sentMessage: Message | null = null;
129
+ let sentMessage: TelegramMessage | null = null;
128
130
 
129
131
  switch (response.kind) {
130
132
  case 'text':
@@ -150,22 +152,24 @@ export class TelegramApiService {
150
152
  case 'image':
151
153
  sentMessage = await this.telegram.sendPhoto(
152
154
  response.chatInfo.id,
153
- createReadStream(response.content.source),
155
+ response.content,
156
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
154
157
  response.replyInfo?.id
155
- ? {
156
- reply_to_message_id: response.replyInfo.id
157
- }
158
+ ? ({
159
+ reply_to_message_id: response.replyInfo.id // eslint-disable-next-line @typescript-eslint/no-explicit-any
160
+ } as any)
158
161
  : undefined
159
162
  );
160
163
  break;
161
164
  case 'video':
162
165
  sentMessage = await this.telegram.sendVideo(
163
166
  response.chatInfo.id,
164
- createReadStream(response.content.source),
167
+ response.content,
168
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
165
169
  response.replyInfo?.id
166
- ? {
167
- reply_to_message_id: response.replyInfo.id
168
- }
170
+ ? ({
171
+ reply_to_message_id: response.replyInfo.id // eslint-disable-next-line @typescript-eslint/no-explicit-any
172
+ } as any)
169
173
  : undefined
170
174
  );
171
175
  break;
@@ -173,21 +177,20 @@ export class TelegramApiService {
173
177
  await this.telegram.setMessageReaction(
174
178
  response.chatInfo.id,
175
179
  response.messageId,
176
- {
177
- reaction: [
178
- {
179
- type: 'emoji',
180
- emoji: response.emoji
181
- }
182
- ]
183
- }
180
+ [
181
+ {
182
+ type: 'emoji',
183
+ emoji: response.emoji
184
+ }
185
+ ]
184
186
  );
185
187
 
186
188
  return;
187
189
  case 'unpin':
188
- await this.telegram.unpinChatMessage(response.chatInfo.id, {
189
- message_id: response.messageId
190
- });
190
+ await this.telegram.unpinChatMessage(
191
+ response.chatInfo.id,
192
+ response.messageId
193
+ );
191
194
 
192
195
  await this.storage.updateStateFor(
193
196
  response.action,
@@ -0,0 +1,17 @@
1
+ import {
2
+ User,
3
+ Message,
4
+ InlineQueryResult,
5
+ TelegramEmoji as Emoji,
6
+ UserFromGetMe
7
+ } from 'telegraf/typings/core/types/typegram';
8
+ import { Telegraf } from 'telegraf';
9
+ import Telegram from 'telegraf/typings/telegram';
10
+
11
+ export type TelegramUser = User;
12
+ export type TelegramMessage = Message;
13
+ export type TelegramInlineQueryResult = InlineQueryResult;
14
+ export type TelegramEmoji = Emoji;
15
+ export type TelegramApiClient = Telegram;
16
+ export type BotInfo = UserFromGetMe;
17
+ export type TelegramBot = Telegraf;