@2byte/tgbot-framework 1.0.2 → 1.0.3

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/README.md +300 -300
  2. package/bin/2byte-cli.ts +97 -84
  3. package/package.json +6 -2
  4. package/src/cli/CreateBotCommand.ts +181 -181
  5. package/src/cli/GenerateCommand.ts +195 -111
  6. package/src/cli/InitCommand.ts +107 -107
  7. package/src/console/migrate.ts +82 -82
  8. package/src/core/ApiService.ts +21 -0
  9. package/src/core/ApiServiceManager.ts +63 -0
  10. package/src/core/App.ts +1113 -1042
  11. package/src/core/BotArtisan.ts +79 -79
  12. package/src/core/BotMigration.ts +30 -30
  13. package/src/core/BotSeeder.ts +66 -66
  14. package/src/core/Model.ts +84 -84
  15. package/src/core/utils.ts +2 -2
  16. package/src/illumination/Artisan.ts +149 -149
  17. package/src/illumination/InlineKeyboard.ts +61 -60
  18. package/src/illumination/Message2Byte.ts +255 -254
  19. package/src/illumination/Message2ByteLiveProgressive.ts +278 -278
  20. package/src/illumination/Message2bytePool.ts +107 -107
  21. package/src/illumination/Migration.ts +186 -186
  22. package/src/illumination/RunSectionRoute.ts +85 -85
  23. package/src/illumination/Section.ts +410 -410
  24. package/src/illumination/SectionComponent.ts +64 -64
  25. package/src/illumination/Telegraf2byteContext.ts +32 -32
  26. package/src/index.ts +35 -33
  27. package/src/libs/TelegramAccountControl.ts +738 -738
  28. package/src/types.ts +188 -186
  29. package/src/user/UserModel.ts +297 -288
  30. package/src/user/UserStore.ts +119 -119
  31. package/src/workflow/services/MassSendApiService.ts +80 -0
  32. package/templates/bot/.env.example +18 -17
  33. package/templates/bot/artisan.ts +8 -8
  34. package/templates/bot/bot.ts +79 -77
  35. package/templates/bot/database/dbConnector.ts +4 -4
  36. package/templates/bot/database/migrate.ts +9 -9
  37. package/templates/bot/database/migrations/001_create_users.sql +18 -18
  38. package/templates/bot/database/seed.ts +14 -14
  39. package/templates/bot/package.json +30 -30
  40. package/templates/bot/sectionList.ts +9 -7
  41. package/templates/bot/sections/ExampleInputSection.ts +85 -0
  42. package/templates/bot/sections/ExampleLiveTaskerSection.ts +60 -0
  43. package/templates/bot/sections/HomeSection.ts +63 -63
  44. package/templates/bot/workflow/services/ExampleServise.ts +24 -0
@@ -1,254 +1,255 @@
1
- import { Telegraf2byteContext } from "./Telegraf2byteContext";
2
- import { Input, Markup } from "telegraf";
3
- import type { ReplyKeyboardMarkup } from 'telegraf/core/types/telegram';
4
- import { InlineKeyboard } from "./InlineKeyboard";
5
- import { RequestInputOptions } from "../types";
6
- import { Message } from "telegraf/types";
7
- import Message2bytePool from "./Message2bytePool";
8
- import { Section } from "./Section";
9
-
10
- export default class Message2byte {
11
- public messageValue: string = "";
12
- public messageExtra: any = {};
13
- public isUpdate: boolean = false;
14
- private ctx: Telegraf2byteContext;
15
- private imagePath: string | null = null;
16
- private imageCaption: string | null = null;
17
- private messageId: number | null = null;
18
- private doAnswerCbQuery: boolean = true;
19
- private section: Section;
20
-
21
- constructor(ctx: Telegraf2byteContext, section: Section) {
22
- this.ctx = ctx;
23
- this.section = section;
24
- }
25
-
26
- static init(ctx: Telegraf2byteContext, section: Section) {
27
- return new Message2byte(ctx, section);
28
- }
29
-
30
- setNotAnswerCbQuery(): this {
31
- this.doAnswerCbQuery = false;
32
- return this;
33
- }
34
-
35
- message(message: string): this {
36
- this.messageValue = message;
37
- return this;
38
- }
39
-
40
- createPoolMessage(message: string): Message2bytePool {
41
- this.doAnswerCbQuery = false;
42
- this.messageValue = message;
43
- return Message2bytePool.init(this, this.ctx, this.section);
44
- }
45
-
46
- createUpdatePoolMessage(message: string): Message2bytePool {
47
- this.isUpdate = true;
48
- this.messageValue = message;
49
- return Message2bytePool.init(this, this.ctx, this.section);
50
- }
51
-
52
- updateMessage(message: string): this {
53
- this.messageValue = message;
54
- this.isUpdate = true;
55
- this.messageExtra.message_id &&= this.messageId;
56
- return this;
57
- }
58
-
59
- markdown(): this {
60
- this.messageExtra.parse_mode = "markdown";
61
- return this;
62
- }
63
-
64
- html(): this {
65
- this.messageExtra.parse_mode = "html";
66
- return this;
67
- }
68
-
69
- extra(extra: Object): this {
70
- this.messageExtra = extra;
71
- return this;
72
- }
73
-
74
- keyboard(keyboard: ReplyKeyboardMarkup): this {
75
- this.messageExtra.reply_markup = {
76
- keyboard: keyboard.keyboard,
77
- resize_keyboard: keyboard.resize_keyboard,
78
- one_time_keyboard: keyboard.one_time_keyboard,
79
- };
80
- return this;
81
- }
82
-
83
- inlineKeyboard(keyboard: any[][] | InlineKeyboard) {
84
- let keyboardArray: any[][];
85
-
86
- if (keyboard instanceof InlineKeyboard) {
87
- keyboardArray = keyboard.valueOf();
88
- } else {
89
- keyboardArray = keyboard;
90
- }
91
-
92
- Object.assign(this.messageExtra, {
93
- ...Markup.inlineKeyboard(keyboardArray),
94
- });
95
-
96
- return this;
97
- }
98
-
99
- requestInput(inputKey: string, options: RequestInputOptions = {}): this {
100
- // Устанавливаем значения по умолчанию
101
- const allowCancel = options.allowCancel !== false; // по умолчанию true
102
- const cancelButtonText = options.cancelButtonText || "Отмена";
103
- const cancelAction = options.cancelAction || "home.index[cancel_wait=1]";
104
-
105
- // Если разрешена отмена, добавляем кнопку отмены к клавиатуре
106
- if (allowCancel && this.messageExtra && "reply_markup" in this.messageExtra) {
107
- const replyMarkup = (this.messageExtra as any).reply_markup;
108
- if (replyMarkup && replyMarkup.inline_keyboard) {
109
- // Добавляем кнопку отмены в начало клавиатуры
110
- replyMarkup.inline_keyboard.unshift([
111
- {
112
- text: `❌ ${cancelButtonText}`,
113
- callback_data: cancelAction,
114
- },
115
- ]);
116
- }
117
- }
118
-
119
- // Сохраняем информацию о запрашиваемом вводе в сессии пользователя
120
- this.ctx.userSession.awaitingInput = {
121
- key: inputKey,
122
- validator: options.validator,
123
- errorMessage: options.errorMessage || "Неверный формат ввода",
124
- allowCancel,
125
- cancelButtonText: `❌ ${cancelButtonText}`,
126
- cancelAction,
127
- fileValidation: options.fileValidation,
128
- runSection: options.runSection,
129
- retryCount: 0,
130
- };
131
-
132
- return this;
133
- }
134
-
135
- async requestInputWithAwait(
136
- inputKey: string,
137
- options: RequestInputOptions = {}
138
- ): Promise<string | any> {
139
- // Устанавливаем значения по умолчанию
140
- const allowCancel = options.allowCancel !== false; // по умолчанию true
141
- const cancelButtonText = options.cancelButtonText || "Отмена";
142
- const cancelAction = options.cancelAction || "home.index[cancel_wait=1]";
143
-
144
- // Если разрешена отмена, добавляем кнопку отмены к клавиатуре
145
- if (allowCancel && this.messageExtra && "reply_markup" in this.messageExtra) {
146
- const replyMarkup = (this.messageExtra as any).reply_markup;
147
- if (replyMarkup && replyMarkup.inline_keyboard) {
148
- // Добавляем кнопку отмены в начало клавиатуры
149
- replyMarkup.inline_keyboard.unshift([
150
- {
151
- text: `❌ ${cancelButtonText}`,
152
- callback_data: cancelAction,
153
- },
154
- ]);
155
- }
156
- }
157
-
158
- // Отправляем сообщение
159
- await this.send();
160
-
161
- // Возвращаем Promise, который будет разрешен когда пользователь введет данные
162
- return new Promise((resolve, reject) => {
163
- this.ctx.userSession.awaitingInputPromise = {
164
- key: inputKey,
165
- validator: options.validator,
166
- errorMessage: options.errorMessage || "Неверный формат ввода",
167
- allowCancel,
168
- cancelButtonText: `❌ ${cancelButtonText}`,
169
- cancelAction,
170
- fileValidation: options.fileValidation,
171
- retryCount: 0,
172
- resolve,
173
- reject,
174
- };
175
- });
176
- }
177
-
178
- image(pathImage: string): this {
179
- this.imagePath = pathImage;
180
- this.imageCaption = this.messageValue;
181
- this.messageExtra.caption = this.imageCaption;
182
- return this;
183
- }
184
-
185
- editMessageCaption(message: string, extra: any = {}) {
186
- return this.ctx.editMessageCaption(message, extra);
187
- }
188
-
189
- editMessageText(message: string, extra: any = {}) {
190
- return this.ctx.editMessageText(message, extra);
191
- }
192
-
193
- async send() {
194
- if (this.isUpdate) {
195
- if (this.section.route.runIsCallbackQuery && this.doAnswerCbQuery) {
196
- await this.ctx.answerCbQuery();
197
- }
198
-
199
- const message = this.ctx.callbackQuery?.message as Message;
200
-
201
- if (message) {
202
- if ('media_group_id' in message || 'caption' in message) {
203
- const editMessageCaption = this.editMessageCaption(this.messageValue, this.messageExtra);
204
-
205
- if (editMessageCaption && 'message_id' in editMessageCaption) {
206
- this.messageId = editMessageCaption.message_id as number;
207
- }
208
-
209
- return editMessageCaption;
210
- } else {
211
-
212
- const editedText = this.editMessageText(this.messageValue, this.messageExtra);
213
-
214
- if (editedText && 'message_id' in editedText) {
215
- this.messageId = editedText.message_id as number;
216
- }
217
-
218
- return editedText;
219
- }
220
- } else {
221
- this.messageExtra.message_id = this.messageId;
222
-
223
- const messageEntity = await this.editMessageText(this.messageValue, this.messageExtra);
224
-
225
- if (typeof messageEntity === "object" && 'message_id' in messageEntity) {
226
- this.messageId = messageEntity.message_id as number;
227
- }
228
-
229
- return messageEntity;
230
- }
231
- }
232
-
233
- if (this.imagePath) {
234
- return this.ctx.replyWithPhoto(Input.fromLocalFile(this.imagePath), this.messageExtra);
235
- }
236
-
237
- const replyEntity = this.ctx.reply(this.messageValue, this.messageExtra);
238
-
239
- this.messageId = (await replyEntity).message_id;
240
-
241
- return replyEntity;
242
- }
243
-
244
- sendReturnThis(): this {
245
- this.send();
246
- return this;
247
- }
248
-
249
- setMessageId(messageId: number): this {
250
- this.messageId = messageId;
251
- this.messageExtra.message_id = messageId;
252
- return this;
253
- }
254
- }
1
+ import { Telegraf2byteContext } from "./Telegraf2byteContext";
2
+ import { Input, Markup } from "telegraf";
3
+ import type { ReplyKeyboardMarkup } from 'telegraf/core/types/telegram';
4
+ import { InlineKeyboard } from "./InlineKeyboard";
5
+ import { RequestInputOptions } from "../types";
6
+ import { Message } from "telegraf/types";
7
+ import Message2bytePool from "./Message2bytePool";
8
+ import { Section } from "./Section";
9
+
10
+ export default class Message2byte {
11
+ public messageValue: string = "";
12
+ public messageExtra: any = {};
13
+ public isUpdate: boolean = false;
14
+ private ctx: Telegraf2byteContext;
15
+ private imagePath: string | null = null;
16
+ private imageCaption: string | null = null;
17
+ private messageId: number | null = null;
18
+ private doAnswerCbQuery: boolean = true;
19
+ private section: Section;
20
+
21
+ constructor(ctx: Telegraf2byteContext, section: Section) {
22
+ this.ctx = ctx;
23
+ this.section = section;
24
+ }
25
+
26
+ static init(ctx: Telegraf2byteContext, section: Section) {
27
+ return new Message2byte(ctx, section);
28
+ }
29
+
30
+ setNotAnswerCbQuery(): this {
31
+ this.doAnswerCbQuery = false;
32
+ return this;
33
+ }
34
+
35
+ message(message: string): this {
36
+ this.messageValue = message;
37
+ return this;
38
+ }
39
+
40
+ createPoolMessage(message: string): Message2bytePool {
41
+ this.doAnswerCbQuery = false;
42
+ this.messageValue = message;
43
+ return Message2bytePool.init(this, this.ctx, this.section);
44
+ }
45
+
46
+ createUpdatePoolMessage(message: string): Message2bytePool {
47
+ this.isUpdate = true;
48
+ this.messageValue = message;
49
+ return Message2bytePool.init(this, this.ctx, this.section);
50
+ }
51
+
52
+ updateMessage(message: string): this {
53
+ this.messageValue = message;
54
+ this.isUpdate = true;
55
+ this.messageExtra.message_id &&= this.messageId;
56
+ return this;
57
+ }
58
+
59
+ markdown(): this {
60
+ this.messageExtra.parse_mode = "markdown";
61
+ return this;
62
+ }
63
+
64
+ html(): this {
65
+ this.messageExtra.parse_mode = "html";
66
+ return this;
67
+ }
68
+
69
+ extra(extra: Object): this {
70
+ this.messageExtra = extra;
71
+ return this;
72
+ }
73
+
74
+ keyboard(keyboard: ReplyKeyboardMarkup): this {
75
+ this.messageExtra.reply_markup = {
76
+ keyboard: keyboard.keyboard,
77
+ resize_keyboard: keyboard.resize_keyboard,
78
+ one_time_keyboard: keyboard.one_time_keyboard,
79
+ };
80
+ return this;
81
+ }
82
+
83
+ inlineKeyboard(keyboard: any[][] | InlineKeyboard) {
84
+ let keyboardArray: any[][];
85
+
86
+ if (keyboard instanceof InlineKeyboard) {
87
+ keyboardArray = keyboard.valueOf();
88
+ } else {
89
+ keyboardArray = keyboard;
90
+ }
91
+
92
+ Object.assign(this.messageExtra, {
93
+ ...Markup.inlineKeyboard(keyboardArray),
94
+ });
95
+
96
+ return this;
97
+ }
98
+
99
+ requestInput(inputKey: string, options: RequestInputOptions = {}): this {
100
+ // Устанавливаем значения по умолчанию
101
+ const allowCancel = options.allowCancel !== false; // по умолчанию true
102
+ const cancelButtonText = options.cancelButtonText || "Отмена";
103
+ const cancelAction = options.cancelAction || "home.index[cancel_wait=1]";
104
+
105
+ // Если разрешена отмена, добавляем кнопку отмены к клавиатуре
106
+ if (allowCancel && this.messageExtra && "reply_markup" in this.messageExtra) {
107
+ const replyMarkup = (this.messageExtra as any).reply_markup;
108
+ if (replyMarkup && replyMarkup.inline_keyboard) {
109
+ // Добавляем кнопку отмены в начало клавиатуры
110
+ replyMarkup.inline_keyboard.unshift([
111
+ {
112
+ text: `❌ ${cancelButtonText}`,
113
+ callback_data: cancelAction,
114
+ },
115
+ ]);
116
+ }
117
+ }
118
+
119
+ // Сохраняем информацию о запрашиваемом вводе в сессии пользователя
120
+ this.ctx.userSession.awaitingInput = {
121
+ key: inputKey,
122
+ validator: options.validator,
123
+ errorMessage: options.errorMessage || "Неверный формат ввода",
124
+ allowCancel,
125
+ cancelButtonText: `❌ ${cancelButtonText}`,
126
+ cancelAction,
127
+ fileValidation: options.fileValidation,
128
+ runSection: options.runSection,
129
+ retryCount: 0,
130
+ };
131
+
132
+ return this;
133
+ }
134
+
135
+ async requestInputWithAwait(
136
+ inputKey: string,
137
+ options: RequestInputOptions = {}
138
+ ): Promise<string | any> {
139
+ // Устанавливаем значения по умолчанию
140
+ const allowCancel = options.allowCancel !== false; // по умолчанию true
141
+ const cancelButtonText = options.cancelButtonText || "Отмена";
142
+ const cancelAction = options.cancelAction || "home.index[cancel_wait=1]";
143
+
144
+ // Если разрешена отмена, добавляем кнопку отмены к клавиатуре
145
+ if (allowCancel && this.messageExtra && "reply_markup" in this.messageExtra) {
146
+ const replyMarkup = (this.messageExtra as any).reply_markup;
147
+ if (replyMarkup && replyMarkup.inline_keyboard) {
148
+ // Добавляем кнопку отмены в начало клавиатуры
149
+ replyMarkup.inline_keyboard.unshift([
150
+ {
151
+ text: `❌ ${cancelButtonText}`,
152
+ callback_data: cancelAction,
153
+ },
154
+ ]);
155
+ }
156
+ }
157
+
158
+ // Отправляем сообщение
159
+ await this.send();
160
+
161
+ // Возвращаем Promise, который будет разрешен когда пользователь введет данные
162
+ return new Promise((resolve, reject) => {
163
+ this.ctx.userSession.awaitingInputPromise = {
164
+ key: inputKey,
165
+ validator: options.validator,
166
+ errorMessage: options.errorMessage || "Неверный формат ввода",
167
+ allowCancel,
168
+ cancelButtonText: `❌ ${cancelButtonText}`,
169
+ cancelAction,
170
+ fileValidation: options.fileValidation,
171
+ retryCount: 0,
172
+ resolve,
173
+ reject,
174
+ };
175
+ });
176
+ }
177
+
178
+ image(pathImage: string): this {
179
+ this.imagePath = pathImage;
180
+ this.imageCaption = this.messageValue;
181
+ this.messageExtra.caption = this.imageCaption;
182
+ return this;
183
+ }
184
+
185
+ editMessageCaption(message: string, extra: any = {}) {
186
+ return this.ctx.editMessageCaption(message, extra);
187
+ }
188
+
189
+ editMessageText(message: string, extra: any = {}) {
190
+ return this.ctx.editMessageText(message, extra);
191
+ }
192
+
193
+ async send() {
194
+ // console.log("Sending message:", this.messageValue, ' Extra:', this.messageExtra, 'IsUpdate:', this.isUpdate);
195
+ if (this.isUpdate) {
196
+ if (this.section.route.runIsCallbackQuery && this.doAnswerCbQuery) {
197
+ await this.ctx.answerCbQuery();
198
+ }
199
+
200
+ const message = this.ctx.callbackQuery?.message as Message;
201
+
202
+ if (message) {
203
+ if ('media_group_id' in message || 'caption' in message) {
204
+ const editMessageCaption = this.editMessageCaption(this.messageValue, this.messageExtra);
205
+
206
+ if (editMessageCaption && 'message_id' in editMessageCaption) {
207
+ this.messageId = editMessageCaption.message_id as number;
208
+ }
209
+
210
+ return editMessageCaption;
211
+ } else {
212
+
213
+ const editedText = this.editMessageText(this.messageValue, this.messageExtra);
214
+
215
+ if (editedText && 'message_id' in editedText) {
216
+ this.messageId = editedText.message_id as number;
217
+ }
218
+
219
+ return editedText;
220
+ }
221
+ } else {
222
+ this.messageExtra.message_id = this.messageId;
223
+
224
+ const messageEntity = await this.editMessageText(this.messageValue, this.messageExtra);
225
+
226
+ if (typeof messageEntity === "object" && 'message_id' in messageEntity) {
227
+ this.messageId = messageEntity.message_id as number;
228
+ }
229
+
230
+ return messageEntity;
231
+ }
232
+ }
233
+
234
+ if (this.imagePath) {
235
+ return this.ctx.replyWithPhoto(Input.fromLocalFile(this.imagePath), this.messageExtra);
236
+ }
237
+
238
+ const replyEntity = this.ctx.reply(this.messageValue, this.messageExtra);
239
+
240
+ this.messageId = (await replyEntity).message_id;
241
+
242
+ return replyEntity;
243
+ }
244
+
245
+ sendReturnThis(): this {
246
+ this.send();
247
+ return this;
248
+ }
249
+
250
+ setMessageId(messageId: number): this {
251
+ this.messageId = messageId;
252
+ this.messageExtra.message_id = messageId;
253
+ return this;
254
+ }
255
+ }