chz-telegram-bot 0.0.16 → 0.0.18

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 (57) hide show
  1. package/dist/entities/botInstance.js +3 -3
  2. package/dist/entities/context/chatContext.d.ts +6 -4
  3. package/dist/entities/context/chatContext.d.ts.map +1 -1
  4. package/dist/entities/context/chatContext.js +12 -7
  5. package/dist/entities/context/messageContext.d.ts +4 -4
  6. package/dist/entities/context/messageContext.d.ts.map +1 -1
  7. package/dist/entities/context/messageContext.js +9 -9
  8. package/dist/entities/responses/imageMessage.d.ts +5 -2
  9. package/dist/entities/responses/imageMessage.d.ts.map +1 -1
  10. package/dist/entities/responses/imageMessage.js +5 -1
  11. package/dist/entities/responses/reaction.d.ts +5 -2
  12. package/dist/entities/responses/reaction.d.ts.map +1 -1
  13. package/dist/entities/responses/reaction.js +4 -1
  14. package/dist/entities/responses/textMessage.d.ts +5 -2
  15. package/dist/entities/responses/textMessage.d.ts.map +1 -1
  16. package/dist/entities/responses/textMessage.js +5 -1
  17. package/dist/entities/responses/unpin.d.ts +10 -0
  18. package/dist/entities/responses/unpin.d.ts.map +1 -0
  19. package/dist/entities/responses/unpin.js +14 -0
  20. package/dist/entities/responses/videoMessage.d.ts +5 -2
  21. package/dist/entities/responses/videoMessage.d.ts.map +1 -1
  22. package/dist/entities/responses/videoMessage.js +5 -1
  23. package/dist/entities/states/actionStateBase.d.ts +1 -0
  24. package/dist/entities/states/actionStateBase.d.ts.map +1 -1
  25. package/dist/entities/states/actionStateBase.js +1 -0
  26. package/dist/services/jsonFileStorage.d.ts +1 -0
  27. package/dist/services/jsonFileStorage.d.ts.map +1 -1
  28. package/dist/services/jsonFileStorage.js +8 -0
  29. package/dist/services/logger.d.ts +1 -1
  30. package/dist/services/logger.d.ts.map +1 -1
  31. package/dist/services/telegramApi.d.ts +15 -10
  32. package/dist/services/telegramApi.d.ts.map +1 -1
  33. package/dist/services/telegramApi.js +43 -33
  34. package/dist/types/actionState.d.ts +1 -0
  35. package/dist/types/actionState.d.ts.map +1 -1
  36. package/dist/types/response.d.ts +26 -0
  37. package/dist/types/response.d.ts.map +1 -0
  38. package/dist/types/response.js +10 -0
  39. package/dist/types/storage.d.ts +1 -0
  40. package/dist/types/storage.d.ts.map +1 -1
  41. package/entities/botInstance.ts +3 -3
  42. package/entities/context/chatContext.ts +31 -6
  43. package/entities/context/messageContext.ts +29 -8
  44. package/entities/responses/imageMessage.ts +10 -2
  45. package/entities/responses/reaction.ts +8 -2
  46. package/entities/responses/textMessage.ts +10 -2
  47. package/entities/responses/unpin.ts +22 -0
  48. package/entities/responses/videoMessage.ts +10 -2
  49. package/entities/states/actionStateBase.ts +1 -0
  50. package/package.json +1 -1
  51. package/services/jsonFileStorage.ts +15 -0
  52. package/services/logger.ts +1 -1
  53. package/services/telegramApi.ts +86 -49
  54. package/types/actionState.ts +1 -0
  55. package/types/response.ts +34 -0
  56. package/types/storage.ts +5 -0
  57. package/types/replyMessage.ts +0 -7
@@ -1,33 +1,34 @@
1
- import { Telegraf } from 'telegraf';
2
- import { InputFile } from 'telegraf/types';
1
+ import { InputFile, Message } from 'telegraf/types';
3
2
  import { ChatContext } from '../entities/context/chatContext';
4
3
  import { MessageContext } from '../entities/context/messageContext';
5
- import { ImageMessage } from '../entities/responses/imageMessage';
6
- import { TextMessage } from '../entities/responses/textMessage';
7
- import { VideoMessage } from '../entities/responses/videoMessage';
8
4
  import { reverseMap } from '../helpers/reverseMap';
9
- import { IReplyMessage } from '../types/replyMessage';
10
5
  import { IStorageClient } from '../types/storage';
11
6
  import { Milliseconds } from '../types/timeValues';
12
7
  import { Scheduler } from './taskScheduler';
13
8
  import { Logger } from './logger';
14
9
  import { Reaction } from '../entities/responses/reaction';
15
10
  import { IncomingMessage } from '../entities/incomingMessage';
11
+ import { BotResponse, IReplyMessage } from '../types/response';
12
+ import { UnpinResponse } from '../entities/responses/unpin';
13
+ import { TextMessage } from '../entities/responses/textMessage';
14
+ import { VideoMessage } from '../entities/responses/videoMessage';
15
+ import { ImageMessage } from '../entities/responses/imageMessage';
16
+ import { Telegram } from 'telegraf/typings/telegram';
16
17
 
17
18
  export class TelegramApiService {
18
19
  botName: string;
19
- telegraf: Telegraf;
20
+ telegram: Telegram;
20
21
  chats: Map<number, string>;
21
- messageQueue: Array<IReplyMessage<unknown> | Reaction> = [];
22
+ messageQueue: Array<BotResponse> = [];
22
23
  storage: IStorageClient;
23
24
 
24
25
  constructor(
25
26
  botName: string,
26
- telegraf: Telegraf,
27
+ telegram: Telegram,
27
28
  storage: IStorageClient,
28
29
  chats: Map<string, number>
29
30
  ) {
30
- this.telegraf = telegraf;
31
+ this.telegram = telegram;
31
32
  this.botName = botName;
32
33
  this.chats = reverseMap(chats);
33
34
  this.storage = storage;
@@ -51,38 +52,44 @@ export class TelegramApiService {
51
52
  try {
52
53
  await this.processResponse(message);
53
54
  } catch (error) {
55
+ console.dir(error);
54
56
  Logger.errorWithTraceId(
55
57
  this.botName,
56
58
  message.traceId,
57
59
  this.chats.get(message.chatId)!,
58
- error as string | Error,
60
+ error,
59
61
  message
60
62
  );
61
63
  }
62
64
  }
63
65
 
64
- private async processResponse<TType>(
65
- response: IReplyMessage<TType> | Reaction
66
+ private async pinIfShould<T>(
67
+ response: IReplyMessage<T>,
68
+ sentMessage: Message
66
69
  ) {
67
- if ('emoji' in response) {
68
- this.telegraf.telegram.setMessageReaction(
70
+ if (response.shouldPin) {
71
+ await this.telegram.pinChatMessage(
69
72
  response.chatId,
70
- response.messageId,
71
- [
72
- {
73
- type: 'emoji',
74
- emoji: response.emoji
75
- }
76
- ],
77
- true
73
+ sentMessage.message_id,
74
+ { disable_notification: true }
78
75
  );
79
76
 
80
- return;
77
+ await this.storage.updateStateFor(
78
+ response.sourceActionKey,
79
+ response.chatId,
80
+ async (state) => {
81
+ state.pinnedMessages.push(sentMessage.message_id);
82
+ }
83
+ );
81
84
  }
85
+ }
86
+
87
+ private async processResponse(response: BotResponse) {
88
+ let sentMessage: Message;
82
89
 
83
- switch (response.constructor) {
84
- case TextMessage:
85
- await this.telegraf.telegram.sendMessage(
90
+ switch (response.kind) {
91
+ case 'text':
92
+ sentMessage = await this.telegram.sendMessage(
86
93
  response.chatId,
87
94
  response.content as string,
88
95
  {
@@ -92,9 +99,11 @@ export class TelegramApiService {
92
99
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
93
100
  } as any
94
101
  );
102
+
103
+ await this.pinIfShould(response, sentMessage);
95
104
  break;
96
- case ImageMessage:
97
- await this.telegraf.telegram.sendPhoto(
105
+ case 'image':
106
+ sentMessage = await this.telegram.sendPhoto(
98
107
  response.chatId,
99
108
  response.content as InputFile,
100
109
  response.replyId
@@ -102,9 +111,11 @@ export class TelegramApiService {
102
111
  ({ reply_to_message_id: response.replyId } as any)
103
112
  : undefined
104
113
  );
114
+
115
+ await this.pinIfShould(response, sentMessage);
105
116
  break;
106
- case VideoMessage:
107
- await this.telegraf.telegram.sendVideo(
117
+ case 'video':
118
+ sentMessage = await this.telegram.sendVideo(
108
119
  response.chatId,
109
120
  response.content as InputFile,
110
121
  response.replyId
@@ -112,35 +123,58 @@ export class TelegramApiService {
112
123
  ({ reply_to_message_id: response.replyId } as any)
113
124
  : undefined
114
125
  );
126
+
127
+ await this.pinIfShould(response, sentMessage);
115
128
  break;
116
- default:
117
- Logger.errorWithTraceId(
118
- this.botName,
119
- response.traceId,
120
- this.chats.get(response.chatId)!,
121
- `Unknown message type: ${response.constructor}`,
122
- response
129
+ case 'react':
130
+ await this.telegram.setMessageReaction(
131
+ response.chatId,
132
+ response.messageId,
133
+ [
134
+ {
135
+ type: 'emoji',
136
+ emoji: response.emoji
137
+ }
138
+ ],
139
+ true
140
+ );
141
+
142
+ return;
143
+ case 'unpin':
144
+ await this.telegram.unpinChatMessage(
145
+ response.chatId,
146
+ response.messageId
147
+ );
148
+
149
+ await this.storage.updateStateFor(
150
+ response.sourceActionKey,
151
+ response.chatId,
152
+ async (state) => {
153
+ state.pinnedMessages = state.pinnedMessages.filter(
154
+ (x) => x != response.messageId
155
+ );
156
+ }
123
157
  );
124
158
  break;
125
159
  }
126
160
  }
127
161
 
128
- private enqueueResponse<TType>(response: IReplyMessage<TType>) {
129
- this.messageQueue.push(response);
130
- }
131
-
132
- private enqueueReaction(reaction: Reaction) {
162
+ private enqueue(reaction: BotResponse) {
133
163
  this.messageQueue.push(reaction);
134
164
  }
135
165
 
136
166
  private getInteractions() {
137
167
  return {
138
- react: (reaction) => this.enqueueReaction(reaction),
139
- respond: (response) => this.enqueueResponse(response)
168
+ react: (reaction) => this.enqueue(reaction),
169
+ respond: (response) => this.enqueue(response),
170
+ unpin: (unpinMessage) => this.enqueue(unpinMessage)
140
171
  } as IBotApiInteractions;
141
172
  }
142
173
 
143
- createContextForMessage(incomingMessage: IncomingMessage) {
174
+ createContextForMessage(
175
+ incomingMessage: IncomingMessage,
176
+ commandKey: string
177
+ ) {
144
178
  const firstName = incomingMessage.from?.first_name ?? 'Unknown user';
145
179
  const lastName = incomingMessage.from?.last_name
146
180
  ? ` ${incomingMessage.from?.last_name}`
@@ -148,6 +182,7 @@ export class TelegramApiService {
148
182
 
149
183
  return new MessageContext(
150
184
  this.botName,
185
+ commandKey,
151
186
  this.getInteractions(),
152
187
  incomingMessage.chat.id,
153
188
  incomingMessage.chatName,
@@ -160,19 +195,21 @@ export class TelegramApiService {
160
195
  );
161
196
  }
162
197
 
163
- createContextForChat(chatId: number, scheduledName: string) {
198
+ createContextForChat(chatId: number, scheduledKey: string) {
164
199
  return new ChatContext(
165
200
  this.botName,
201
+ scheduledKey,
166
202
  this.getInteractions(),
167
203
  chatId,
168
204
  this.chats.get(chatId)!,
169
- `Scheduled:${scheduledName}:${chatId}`,
205
+ `Scheduled:${scheduledKey}:${chatId}`,
170
206
  this.storage
171
207
  );
172
208
  }
173
209
  }
174
210
 
175
211
  export interface IBotApiInteractions {
176
- respond: <TType>(response: IReplyMessage<TType>) => void;
212
+ respond: (response: TextMessage | VideoMessage | ImageMessage) => void;
177
213
  react: (reaction: Reaction) => void;
214
+ unpin: (unpinMessage: UnpinResponse) => void;
178
215
  }
@@ -1,3 +1,4 @@
1
1
  export interface IActionState {
2
2
  lastExecutedDate: number;
3
+ pinnedMessages: number[];
3
4
  }
@@ -0,0 +1,34 @@
1
+ import { ImageMessage } from '../entities/responses/imageMessage';
2
+ import { Reaction } from '../entities/responses/reaction';
3
+ import { TextMessage } from '../entities/responses/textMessage';
4
+ import { UnpinResponse } from '../entities/responses/unpin';
5
+ import { VideoMessage } from '../entities/responses/videoMessage';
6
+
7
+ export const BotResponseTypes = {
8
+ unpin: 'unpin',
9
+ text: 'text',
10
+ image: 'image',
11
+ video: 'video',
12
+ react: 'react'
13
+ } as const;
14
+
15
+ export type BotResponse =
16
+ | UnpinResponse
17
+ | Reaction
18
+ | TextMessage
19
+ | VideoMessage
20
+ | ImageMessage;
21
+
22
+ export interface IChatResponse {
23
+ kind: keyof typeof BotResponseTypes;
24
+ chatId: number;
25
+ traceId: number | string;
26
+ sourceActionKey: string;
27
+ }
28
+
29
+ export interface IReplyMessage<TType> extends IChatResponse {
30
+ content: TType;
31
+ replyId: number | undefined;
32
+ disableWebPreview: boolean;
33
+ shouldPin: boolean;
34
+ }
package/types/storage.ts CHANGED
@@ -3,6 +3,11 @@ import { IActionState } from './actionState';
3
3
  import { IActionWithState } from './actionWithState';
4
4
 
5
5
  export interface IStorageClient {
6
+ updateStateFor<TActionState extends IActionState>(
7
+ sourceActionKey: string,
8
+ chatId: number,
9
+ update: (state: TActionState) => Promise<void>
10
+ ): Promise<void>;
6
11
  close(): Promise<void>;
7
12
  load<TActionState extends IActionState>(
8
13
  key: string
@@ -1,7 +0,0 @@
1
- export interface IReplyMessage<TType> {
2
- content: TType;
3
- chatId: number;
4
- replyId: number | undefined;
5
- traceId: number | string;
6
- disableWebPreview: boolean;
7
- }