chz-telegram-bot 0.0.23 → 0.0.25

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 (44) hide show
  1. package/dist/entities/actions/scheduledAction.d.ts +1 -1
  2. package/dist/entities/actions/scheduledAction.d.ts.map +1 -1
  3. package/dist/entities/actions/scheduledAction.js +1 -0
  4. package/dist/entities/botInstance.d.ts +1 -1
  5. package/dist/entities/botInstance.d.ts.map +1 -1
  6. package/dist/entities/botInstance.js +30 -12
  7. package/dist/entities/context/chatContext.d.ts +37 -4
  8. package/dist/entities/context/chatContext.d.ts.map +1 -1
  9. package/dist/entities/context/chatContext.js +30 -0
  10. package/dist/entities/context/messageContext.d.ts +34 -3
  11. package/dist/entities/context/messageContext.d.ts.map +1 -1
  12. package/dist/entities/context/messageContext.js +29 -4
  13. package/dist/helpers/builders/commandActionBuilder.d.ts +38 -0
  14. package/dist/helpers/builders/commandActionBuilder.d.ts.map +1 -1
  15. package/dist/helpers/builders/commandActionBuilder.js +38 -0
  16. package/dist/helpers/builders/scheduledActionBuilder.d.ts +34 -0
  17. package/dist/helpers/builders/scheduledActionBuilder.d.ts.map +1 -1
  18. package/dist/helpers/builders/scheduledActionBuilder.js +34 -0
  19. package/dist/helpers/reverseRecord.d.ts +2 -0
  20. package/dist/helpers/reverseRecord.d.ts.map +1 -0
  21. package/dist/helpers/reverseRecord.js +6 -0
  22. package/dist/main.d.ts +14 -1
  23. package/dist/main.d.ts.map +1 -1
  24. package/dist/main.js +7 -1
  25. package/dist/services/taskScheduler.d.ts.map +1 -1
  26. package/dist/services/taskScheduler.js +1 -2
  27. package/dist/services/telegramApi.d.ts +7 -4
  28. package/dist/services/telegramApi.d.ts.map +1 -1
  29. package/dist/services/telegramApi.js +8 -7
  30. package/dist/types/handlers.d.ts +12 -2
  31. package/dist/types/handlers.d.ts.map +1 -1
  32. package/entities/actions/scheduledAction.ts +2 -1
  33. package/entities/botInstance.ts +52 -17
  34. package/entities/context/chatContext.ts +42 -4
  35. package/entities/context/messageContext.ts +34 -8
  36. package/helpers/builders/commandActionBuilder.ts +38 -0
  37. package/helpers/builders/scheduledActionBuilder.ts +34 -0
  38. package/helpers/reverseRecord.ts +7 -0
  39. package/main.ts +15 -2
  40. package/package.json +1 -1
  41. package/services/taskScheduler.ts +2 -3
  42. package/services/telegramApi.ts +22 -14
  43. package/types/handlers.ts +6 -1
  44. package/helpers/reverseMap.ts +0 -3
@@ -7,6 +7,9 @@ import { IActionState } from '../../types/actionState';
7
7
  import { toArray } from '../toArray';
8
8
  import { Noop } from '../noop';
9
9
 
10
+ /**
11
+ * Builder for `CommandAction` with state represented by `TActionState`
12
+ */
10
13
  export class CommandActionBuilderWithState<TActionState extends IActionState> {
11
14
  name: string;
12
15
  trigger: string | RegExp | Array<string> | Array<RegExp> = [];
@@ -19,53 +22,82 @@ export class CommandActionBuilderWithState<TActionState extends IActionState> {
19
22
  handler: CommandHandler<TActionState> = Noop.call;
20
23
  condition: CommandCondition<TActionState> = Noop.true;
21
24
 
25
+ /**
26
+ * Builder for `CommandAction` with state represented by `TActionState`
27
+ * @param name Action name, will be used for logging and storage
28
+ * @param stateConstructor Function that creates default state object
29
+ */
22
30
  constructor(name: string, stateConstructor: () => TActionState) {
23
31
  this.name = name;
24
32
  this.stateConstructor = stateConstructor;
25
33
  }
26
34
 
35
+ /**
36
+ * Defines action trigger
37
+ * @param trigger If `string` or `string[]` is provided, will be triggered only on exact message match.
38
+ *
39
+ * If `RegExp` or `RegExp[]` is provided, will be triggered on successful match.
40
+ */
27
41
  on(trigger: string | RegExp | Array<string> | Array<RegExp>) {
28
42
  this.trigger = trigger;
29
43
 
30
44
  return this;
31
45
  }
32
46
 
47
+ /** Defines id (or ids) of users that are allowed to trigger this action.
48
+ * @param id User id or ids
49
+ */
33
50
  from(id: number | Array<number>) {
34
51
  this.allowedUsers = toArray(id);
35
52
 
36
53
  return this;
37
54
  }
38
55
 
56
+ /** Defines action logic itself, will be executed on trigger.
57
+ * @param handler Callback that will be called on trigger
58
+ */
39
59
  do(handler: CommandHandler<TActionState>) {
40
60
  this.handler = handler;
41
61
 
42
62
  return this;
43
63
  }
44
64
 
65
+ /** Defines condition that will be checked before trigger match check is executed.
66
+ * @param condition Condition check predicate
67
+ */
45
68
  when(condition: CommandCondition<TActionState>) {
46
69
  this.condition = condition;
47
70
 
48
71
  return this;
49
72
  }
50
73
 
74
+ /** If called during building, action is marked as disabled and never checked. */
51
75
  disabled() {
52
76
  this.active = false;
53
77
 
54
78
  return this;
55
79
  }
56
80
 
81
+ /** Sets action cooldown.
82
+ * @param seconds Cooldown in seconds.
83
+ */
57
84
  cooldown(seconds: Seconds) {
58
85
  this.cooldownSeconds = seconds;
59
86
 
60
87
  return this;
61
88
  }
62
89
 
90
+ /**
91
+ * Adds a chat to ignore list for this action.
92
+ * @param chatId Chat id to ignore.
93
+ */
63
94
  ignoreChat(chatId: number) {
64
95
  this.blacklist.push(chatId);
65
96
 
66
97
  return this;
67
98
  }
68
99
 
100
+ /** Builds action */
69
101
  build() {
70
102
  return new CommandAction(
71
103
  this.trigger,
@@ -81,7 +113,13 @@ export class CommandActionBuilderWithState<TActionState extends IActionState> {
81
113
  }
82
114
  }
83
115
 
116
+ /**
117
+ * Builder for `CommandAction` with state represented by default state (containing only last execution date).
118
+ */
84
119
  export class CommandActionBuilder extends CommandActionBuilderWithState<ActionStateBase> {
120
+ /**
121
+ * Builder for `CommandAction` with state represented by default state (containing only last execution date).
122
+ */
85
123
  constructor(name: string) {
86
124
  super(name, () => new ActionStateBase());
87
125
  }
@@ -6,6 +6,9 @@ import { ScheduledHandler } from '../../types/handlers';
6
6
  import { Hours, HoursOfDay } from '../../types/timeValues';
7
7
  import { Noop } from '../noop';
8
8
 
9
+ /**
10
+ * Builder for `ScheduledAction` with state represented by `TActionState`
11
+ */
9
12
  export class ScheduledActionBuilderWithState<
10
13
  TActionState extends IActionState
11
14
  > {
@@ -18,29 +21,52 @@ export class ScheduledActionBuilderWithState<
18
21
 
19
22
  name: string;
20
23
 
24
+ /**
25
+ * Builder for `ScheduledAction` with state represented by `TActionState`
26
+ * @param name Action name, will be used for logging and storage
27
+ * @param stateConstructor Function that creates default state object
28
+ */
21
29
  constructor(name: string, stateConstructor: () => TActionState) {
22
30
  this.name = name;
23
31
  this.stateConstructor = stateConstructor;
24
32
  }
25
33
 
34
+ /**
35
+ * Adds a chat to whitelist for this action.
36
+ * @param chatId Chat id to execute in.
37
+ */
26
38
  allowIn(chatId: number) {
27
39
  this.whitelist.push(chatId);
28
40
 
29
41
  return this;
30
42
  }
31
43
 
44
+ /**
45
+ * Defines time for scheduled item execution.
46
+ * @param time Time of day (0 - 23) to execute action.
47
+ */
32
48
  runAt(time: HoursOfDay) {
33
49
  this.time = time;
34
50
 
35
51
  return this;
36
52
  }
37
53
 
54
+ /** Defines action logic itself, will be executed on timer.
55
+ * @param handler Callback that will be called on timer.
56
+ */
38
57
  do(handler: ScheduledHandler<TActionState>) {
39
58
  this.handler = handler;
40
59
 
41
60
  return this;
42
61
  }
43
62
 
63
+ /**
64
+ * Defines process-wide cache, that is shared by all actions of this type (even in different bot instances).
65
+ * Can be used for fetch request de-duping, etc.
66
+ * @param key Key that will be used to retrieve value from cache.
67
+ * @param itemFactory Callback that will be executed once to create cached value.
68
+ * @param invalidationTimeoutInHours Timeout for cache invalidation.
69
+ */
44
70
  withSharedCache(
45
71
  key: string,
46
72
  itemFactory: () => Promise<unknown>,
@@ -54,12 +80,14 @@ export class ScheduledActionBuilderWithState<
54
80
  return this;
55
81
  }
56
82
 
83
+ /** If called during building, action is marked as disabled and never checked. */
57
84
  disabled() {
58
85
  this.active = false;
59
86
 
60
87
  return this;
61
88
  }
62
89
 
90
+ /** Builds action */
63
91
  build() {
64
92
  return new ScheduledAction<TActionState>(
65
93
  this.name,
@@ -73,7 +101,13 @@ export class ScheduledActionBuilderWithState<
73
101
  }
74
102
  }
75
103
 
104
+ /**
105
+ * Builder for `ScheduledAction` with state represented by default state (containing only last execution date).
106
+ */
76
107
  export class ScheduledActionBuilder extends ScheduledActionBuilderWithState<ActionStateBase> {
108
+ /**
109
+ * Builder for `ScheduledAction` with state represented by default state (containing only last execution date).
110
+ */
77
111
  constructor(name: string) {
78
112
  super(name, () => new ActionStateBase());
79
113
  }
@@ -0,0 +1,7 @@
1
+ export function reverseRecord<T extends PropertyKey, U extends PropertyKey>(
2
+ input: Record<T, U>
3
+ ) {
4
+ return Object.fromEntries(
5
+ Object.entries(input).map(([key, value]) => [value, key])
6
+ ) as Record<U, T>;
7
+ }
package/main.ts CHANGED
@@ -13,13 +13,23 @@ function log(text: string) {
13
13
  Logger.logWithTraceId('ALL BOTS', 'System:Bot', 'System', text);
14
14
  }
15
15
 
16
+ /**
17
+ * Starts bot
18
+ */
16
19
  async function startBot(options: {
20
+ /** Bot name, used in logging */
17
21
  name: string;
22
+ /** Path to file containing Telegram Bot token. */
18
23
  tokenFilePath: string;
24
+ /** Collection of actions that will be executed as a response to message from used. Created using `CommandActionBuilder`.*/
19
25
  commands: CommandAction<IActionState>[];
26
+ /** Collection of actions that will be executed on timer. Created using `ScheduledActionBuilder`.*/
20
27
  scheduled: ScheduledAction<IActionState>[];
21
- chats: Map<string, number>;
28
+ /** Object containing chat name and chat id pairs. Used for logging and execution of scheduled action. */
29
+ chats: Record<string, number>;
30
+ /** Storage client for bot state storage. If not provided, default `JsonFileStorage` will be used. */
22
31
  storageClient?: IStorageClient;
32
+ /** Storage path for default `JsonFileStorage` client. Will be used only if `storageClient` is not provided. If not provided, default value of `./storage/` will be used.*/
23
33
  storagePath?: string;
24
34
  }) {
25
35
  const token = await readFile(options.tokenFilePath, 'utf8');
@@ -37,6 +47,9 @@ async function startBot(options: {
37
47
  return bot;
38
48
  }
39
49
 
50
+ /**
51
+ * Terminates all scheduled tasks, closes storage connections and stops all bots.
52
+ */
40
53
  async function stopBots(reason: string) {
41
54
  log(`Recieved termination code: ${reason}`);
42
55
  Scheduler.stopAll();
@@ -44,7 +57,7 @@ async function stopBots(reason: string) {
44
57
 
45
58
  log('Stopping bots...');
46
59
  for (const bot of bots) {
47
- bot.stop(reason);
60
+ await bot.stop(reason);
48
61
  }
49
62
  }
50
63
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "chz-telegram-bot",
3
- "version": "0.0.23",
3
+ "version": "0.0.25",
4
4
  "type": "module",
5
5
  "dependencies": {
6
6
  "async-sema": "^3.1.1",
@@ -1,6 +1,5 @@
1
1
  import { TaskRecord } from '../entities/taskRecord';
2
- import { secondsToMilliseconds } from '../helpers/timeConvertions';
3
- import { Milliseconds, Seconds } from '../types/timeValues';
2
+ import { Milliseconds } from '../types/timeValues';
4
3
  import { Logger } from './logger';
5
4
 
6
5
  class TaskScheduler {
@@ -24,7 +23,7 @@ class TaskScheduler {
24
23
  const task = new TaskRecord(name, taskId, interval);
25
24
 
26
25
  if (executeRightAway) {
27
- setTimeout(action, secondsToMilliseconds(1 as Seconds));
26
+ setImmediate(action);
28
27
  }
29
28
 
30
29
  Logger.logWithTraceId(
@@ -1,7 +1,7 @@
1
1
  import { InputFile, Message } from 'telegraf/types';
2
2
  import { ChatContext } from '../entities/context/chatContext';
3
3
  import { MessageContext } from '../entities/context/messageContext';
4
- import { reverseMap } from '../helpers/reverseMap';
4
+ import { reverseRecord } from '../helpers/reverseRecord';
5
5
  import { IStorageClient } from '../types/storage';
6
6
  import { Logger } from './logger';
7
7
  import { Reaction } from '../entities/responses/reaction';
@@ -14,6 +14,9 @@ import { ImageMessage } from '../entities/responses/imageMessage';
14
14
  import { Telegram } from 'telegraf/typings/telegram';
15
15
  import { setTimeout } from 'timers/promises';
16
16
  import { Milliseconds } from '../types/timeValues';
17
+ import { ScheduledAction } from '../entities/actions/scheduledAction';
18
+ import { IActionState } from '../types/actionState';
19
+ import { CommandAction } from '../entities/actions/commandAction';
17
20
 
18
21
  export class TelegramApiService {
19
22
  isFlushing = false;
@@ -21,24 +24,26 @@ export class TelegramApiService {
21
24
 
22
25
  botName: string;
23
26
  telegram: Telegram;
24
- chats: Map<number, string>;
27
+ chats: Record<number, string>;
25
28
  storage: IStorageClient;
26
29
 
27
30
  constructor(
28
31
  botName: string,
29
32
  telegram: Telegram,
30
33
  storage: IStorageClient,
31
- chats: Map<string, number>
34
+ chats: Record<string, number>
32
35
  ) {
33
36
  this.telegram = telegram;
34
37
  this.botName = botName;
35
- this.chats = reverseMap(chats);
38
+ this.chats = reverseRecord(chats);
36
39
  this.storage = storage;
37
40
  }
38
41
 
39
42
  async flushResponses() {
40
43
  if (this.isFlushing) return;
41
44
 
45
+ this.isFlushing = true;
46
+
42
47
  while (this.messageQueue.length) {
43
48
  const message = this.messageQueue.pop();
44
49
 
@@ -51,7 +56,7 @@ export class TelegramApiService {
51
56
  Logger.errorWithTraceId(
52
57
  this.botName,
53
58
  message.traceId,
54
- this.chats.get(message.chatId)!,
59
+ this.chats[message.chatId],
55
60
  error,
56
61
  message
57
62
  );
@@ -169,18 +174,18 @@ export class TelegramApiService {
169
174
  } as IBotApiInteractions;
170
175
  }
171
176
 
172
- createContextForMessage(
177
+ createContextForMessage<TActionState extends IActionState>(
173
178
  incomingMessage: IncomingMessage,
174
- commandKey: string
179
+ command: CommandAction<TActionState>
175
180
  ) {
176
181
  const firstName = incomingMessage.from?.first_name ?? 'Unknown user';
177
182
  const lastName = incomingMessage.from?.last_name
178
183
  ? ` ${incomingMessage.from?.last_name}`
179
184
  : '';
180
185
 
181
- return new MessageContext(
186
+ return new MessageContext<TActionState>(
182
187
  this.botName,
183
- commandKey,
188
+ command.key,
184
189
  this.getInteractions(),
185
190
  incomingMessage.chat.id,
186
191
  incomingMessage.chatName,
@@ -193,14 +198,17 @@ export class TelegramApiService {
193
198
  );
194
199
  }
195
200
 
196
- createContextForChat(chatId: number, scheduledKey: string) {
197
- return new ChatContext(
201
+ createContextForChat<TActionState extends IActionState>(
202
+ chatId: number,
203
+ scheduledAction: ScheduledAction<TActionState>
204
+ ) {
205
+ return new ChatContext<TActionState>(
198
206
  this.botName,
199
- scheduledKey,
207
+ scheduledAction.key,
200
208
  this.getInteractions(),
201
209
  chatId,
202
- this.chats.get(chatId)!,
203
- `Scheduled:${scheduledKey}:${chatId}`,
210
+ this.chats[chatId],
211
+ `Scheduled:${scheduledAction.key}:${chatId}`,
204
212
  this.storage
205
213
  );
206
214
  }
package/types/handlers.ts CHANGED
@@ -4,12 +4,17 @@ import { IActionState } from './actionState';
4
4
  import { CachedValueAccessor } from './cachedValueAccessor';
5
5
 
6
6
  export type CommandHandler<TActionState extends IActionState> = (
7
+ /** Context of action executed in chat, in response to a message. */
7
8
  ctx: MessageContext<TActionState>,
9
+ /** State of an action being executed. */
8
10
  state: TActionState
9
11
  ) => Promise<void>;
10
12
 
11
13
  export type ScheduledHandler<TActionState extends IActionState> = (
12
- ctx: ChatContext,
14
+ /** Context of action executed in chat. */
15
+ ctx: ChatContext<TActionState>,
16
+ /** Function that will attempt to get value from cache. If there is no value found, corresponding cached state factory will be called. */
13
17
  getCached: CachedValueAccessor,
18
+ /** State of an action being executed. */
14
19
  state: TActionState
15
20
  ) => Promise<void>;
@@ -1,3 +0,0 @@
1
- export function reverseMap<K, V>(map: Map<K, V>): Map<V, K> {
2
- return new Map(Array.from(map, ([key, value]) => [value, key]));
3
- }