@2byte/tgbot-framework 1.0.3 → 1.0.5

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 (58) hide show
  1. package/README.md +300 -300
  2. package/bin/2byte-cli.ts +97 -97
  3. package/package.json +6 -5
  4. package/src/cli/CreateBotCommand.ts +181 -181
  5. package/src/cli/GenerateCommand.ts +195 -195
  6. package/src/cli/InitCommand.ts +107 -107
  7. package/src/cli/TgAccountManager.ts +50 -0
  8. package/src/console/migrate.ts +82 -82
  9. package/src/core/ApiService.ts +20 -20
  10. package/src/core/ApiServiceManager.ts +63 -63
  11. package/src/core/App.ts +1143 -1113
  12. package/src/core/BotArtisan.ts +79 -79
  13. package/src/core/BotMigration.ts +30 -30
  14. package/src/core/BotSeeder.ts +66 -66
  15. package/src/core/Model.ts +84 -84
  16. package/src/core/utils.ts +2 -2
  17. package/src/illumination/Artisan.ts +149 -149
  18. package/src/illumination/InlineKeyboard.ts +61 -61
  19. package/src/illumination/Message2Byte.ts +255 -255
  20. package/src/illumination/Message2ByteLiveProgressive.ts +278 -278
  21. package/src/illumination/Message2bytePool.ts +107 -107
  22. package/src/illumination/Migration.ts +186 -186
  23. package/src/illumination/RunSectionRoute.ts +85 -85
  24. package/src/illumination/Section.ts +410 -410
  25. package/src/illumination/SectionComponent.ts +64 -64
  26. package/src/illumination/Telegraf2byteContext.ts +32 -32
  27. package/src/index.ts +42 -35
  28. package/src/libs/TelegramAccountControl.ts +1140 -738
  29. package/src/libs/TgSender.ts +53 -0
  30. package/src/models/Model.ts +67 -0
  31. package/src/models/Proxy.ts +218 -0
  32. package/src/models/TgAccount.ts +362 -0
  33. package/src/models/index.ts +3 -0
  34. package/src/types.ts +191 -188
  35. package/src/user/UserModel.ts +297 -297
  36. package/src/user/UserStore.ts +119 -119
  37. package/src/workflow/services/MassSendApiService.ts +80 -80
  38. package/templates/bot/.env.example +23 -19
  39. package/templates/bot/artisan.ts +8 -8
  40. package/templates/bot/bot.ts +82 -79
  41. package/templates/bot/database/dbConnector.ts +4 -4
  42. package/templates/bot/database/migrate.ts +9 -9
  43. package/templates/bot/database/migrations/001_create_users.sql +18 -18
  44. package/templates/bot/database/migrations/007_proxy.sql +27 -0
  45. package/templates/bot/database/migrations/008_tg_accounts.sql +32 -0
  46. package/templates/bot/database/seed.ts +14 -14
  47. package/templates/bot/docs/CLI_SERVICES.md +536 -0
  48. package/templates/bot/docs/INPUT_SYSTEM.md +211 -0
  49. package/templates/bot/docs/SERVICE_EXAMPLES.md +384 -0
  50. package/templates/bot/docs/TASK_SYSTEM.md +156 -0
  51. package/templates/bot/models/Model.ts +7 -0
  52. package/templates/bot/models/index.ts +2 -0
  53. package/templates/bot/package.json +30 -30
  54. package/templates/bot/sectionList.ts +9 -9
  55. package/templates/bot/sections/ExampleInputSection.ts +85 -85
  56. package/templates/bot/sections/ExampleLiveTaskerSection.ts +60 -60
  57. package/templates/bot/sections/HomeSection.ts +63 -63
  58. package/templates/bot/workflow/services/{ExampleServise.ts → ExampleService.ts} +23 -23
@@ -0,0 +1,211 @@
1
+ # Улучшенная система ввода пользователя
2
+
3
+ ## Обзор
4
+
5
+ Система ввода была значительно улучшена для поддержки:
6
+ - Возможности отмены ввода пользователем
7
+ - Настраиваемых опций отмены при создании запроса
8
+ - Сохранения состояния ожидания при неверном вводе
9
+ - Расширенной валидации, включая файлы
10
+ - Гибкой системы валидации для различных типов ботов
11
+
12
+ ## Основные возможности
13
+
14
+ ### 1. Настройка отмены ввода
15
+
16
+ При создании запроса на ввод можно настроить возможность отмены:
17
+
18
+ ```typescript
19
+ // Разрешить отмену (по умолчанию)
20
+ .requestInput("phone", {
21
+ validator: "phone",
22
+ allowCancel: true, // по умолчанию true
23
+ cancelButtonText: "Отмена", // текст кнопки
24
+ cancelAction: "home.index[cancel_wait=1]", // действие при отмене
25
+ })
26
+
27
+ // Запретить отмену (обязательный ввод)
28
+ .requestInputWithAwait("password", {
29
+ allowCancel: false, // отмена запрещена
30
+ errorMessage: "Пароль обязателен для ввода"
31
+ })
32
+ ```
33
+
34
+ ### 2. Сохранение состояния при ошибках
35
+
36
+ При неверном вводе пользователь остается в режиме ожидания:
37
+
38
+ ```typescript
39
+ .requestInput("code", {
40
+ validator: "code",
41
+ errorMessage: "Неверный формат кода. Введите 5-6 цифр",
42
+ allowCancel: true
43
+ })
44
+ ```
45
+
46
+ Система будет:
47
+ - Показывать сообщение об ошибке
48
+ - Увеличивать счетчик попыток
49
+ - Сохранять состояние ожидания
50
+ - Позволять отмену только если `allowCancel: true`
51
+
52
+ ### 3. Валидация файлов
53
+
54
+ Поддержка загрузки и валидации файлов:
55
+
56
+ ```typescript
57
+ .requestInput("uploadedFile", {
58
+ validator: "file",
59
+ errorMessage: "Неподдерживаемый формат файла",
60
+ fileValidation: {
61
+ allowedTypes: ['image/jpeg', 'image/png', 'application/pdf'],
62
+ maxSize: 10 * 1024 * 1024, // 10 МБ
63
+ minSize: 1024, // 1 КБ
64
+ },
65
+ allowCancel: true
66
+ })
67
+ ```
68
+
69
+ ### 4. Кастомная валидация
70
+
71
+ Поддержка асинхронных валидаторов:
72
+
73
+ ```typescript
74
+ .requestInput("customData", {
75
+ validator: async (value) => {
76
+ // Асинхронная проверка
77
+ const isValid = await checkInDatabase(value);
78
+ return isValid;
79
+ },
80
+ errorMessage: "Данные не прошли проверку"
81
+ })
82
+ ```
83
+
84
+ ## Типы валидаторов
85
+
86
+ ### Встроенные валидаторы:
87
+ - `"number"` - числовые значения
88
+ - `"phone"` - российские номера телефонов (79xxxxxxxxx)
89
+ - `"code"` - коды подтверждения (5-6 цифр)
90
+ - `"file"` - файлы (с дополнительными опциями)
91
+
92
+ ### Кастомные валидаторы:
93
+ ```typescript
94
+ // Синхронный валидатор
95
+ validator: (value: string) => value.length > 5
96
+
97
+ // Асинхронный валидатор
98
+ validator: async (value: string) => {
99
+ const result = await apiCall(value);
100
+ return result.isValid;
101
+ }
102
+ ```
103
+
104
+ ## Примеры использования
105
+
106
+ ### Базовый ввод с отменой
107
+ ```typescript
108
+ async startRegistration() {
109
+ await this.message("Введите ваш номер телефона:")
110
+ .requestInput("phone", {
111
+ validator: "phone",
112
+ errorMessage: "Неверный формат. Используйте: 79000000000",
113
+ allowCancel: true,
114
+ cancelButtonText: "Отмена",
115
+ cancelAction: "home.index[cancel_wait=1]",
116
+ runSection: new RunSectionRoute().section("home").method("processPhone")
117
+ })
118
+ .send();
119
+ }
120
+ ```
121
+
122
+ ### Обязательный ввод без отмены
123
+ ```typescript
124
+ async requestPassword() {
125
+ return await this.message("Введите пароль:")
126
+ .requestInputWithAwait("password", {
127
+ errorMessage: "Пароль не может быть пустым",
128
+ allowCancel: false // отмена запрещена
129
+ });
130
+ }
131
+ ```
132
+
133
+ ### Загрузка файлов с валидацией
134
+ ```typescript
135
+ async uploadDocument() {
136
+ await this.message("Отправьте документ (PDF, до 5 МБ):")
137
+ .requestInput("document", {
138
+ validator: "file",
139
+ fileValidation: {
140
+ allowedTypes: ['application/pdf'],
141
+ maxSize: 5 * 1024 * 1024,
142
+ minSize: 1024
143
+ },
144
+ errorMessage: "Только PDF файлы до 5 МБ",
145
+ allowCancel: true,
146
+ runSection: new RunSectionRoute().section("home").method("processDocument")
147
+ })
148
+ .send();
149
+ }
150
+ ```
151
+
152
+ ### Кастомная валидация с API
153
+ ```typescript
154
+ async requestUsername() {
155
+ await this.message("Введите желаемое имя пользователя:")
156
+ .requestInput("username", {
157
+ validator: async (username: string) => {
158
+ // Проверяем доступность имени через API
159
+ const response = await fetch(`/api/check-username/${username}`);
160
+ const data = await response.json();
161
+ return data.available;
162
+ },
163
+ errorMessage: "Это имя уже занято. Попробуйте другое.",
164
+ allowCancel: true,
165
+ runSection: new RunSectionRoute().section("user").method("processUsername")
166
+ })
167
+ .send();
168
+ }
169
+ ```
170
+
171
+ ## Обработка отмены
172
+
173
+ Отмена обрабатывается автоматически через параметр `cancel_wait`:
174
+
175
+ ```typescript
176
+ // В конструкторе Section автоматически вызывается:
177
+ this.cancelUserWaitingReply();
178
+
179
+ // Который проверяет параметр cancel_wait и очищает состояние ожидания
180
+ ```
181
+
182
+ ## Миграция с старой системы
183
+
184
+ ### Было:
185
+ ```typescript
186
+ .requestInput("phone", {
187
+ validator: "phone",
188
+ errorMessage: "Неверный номер"
189
+ })
190
+ ```
191
+
192
+ ### Стало:
193
+ ```typescript
194
+ .requestInput("phone", {
195
+ validator: "phone",
196
+ errorMessage: "Неверный номер",
197
+ allowCancel: true, // новый параметр
198
+ cancelButtonText: "Отмена", // настройка текста кнопки
199
+ cancelAction: "home.index[cancel_wait=1]" // действие при отмене
200
+ })
201
+ ```
202
+
203
+ Старый код будет работать с настройками по умолчанию (отмена разрешена).
204
+
205
+ ## Лучшие практики
206
+
207
+ 1. **Всегда предоставляйте возможность отмены** для необязательных действий
208
+ 2. **Используйте понятные сообщения об ошибках** с указанием формата
209
+ 3. **Ограничивайте размеры файлов** для предотвращения злоупотреблений
210
+ 4. **Используйте асинхронную валидацию** для проверок через API
211
+ 5. **Тестируйте различные сценарии** включая отмену и повторные попытки
@@ -0,0 +1,384 @@
1
+ # Примеры использования Service Generator
2
+
3
+ ## Тестовые сценарии
4
+
5
+ ### Сценарий 1: Создание простого сервиса
6
+
7
+ ```bash
8
+ cd your-bot-directory
9
+ 2byte generate service Payment
10
+ ```
11
+
12
+ **Ожидаемый результат:**
13
+ - Создан файл `workflow/services/PaymentService.ts`
14
+ - Выведено: `✅ Created service PaymentService at workflow/services/PaymentService.ts`
15
+
16
+ ### Сценарий 2: Создание с полным именем
17
+
18
+ ```bash
19
+ 2byte g service NotificationService
20
+ ```
21
+
22
+ **Ожидаемый результат:**
23
+ - Создан файл `workflow/services/NotificationService.ts`
24
+ - Суффикс Service не дублируется
25
+
26
+ ### Сценарий 3: Попытка создать существующий сервис
27
+
28
+ ```bash
29
+ 2byte g service Payment # Второй раз
30
+ ```
31
+
32
+ **Ожидаемый результат:**
33
+ - Ошибка: `❌ Service PaymentService already exists`
34
+ - Файл не перезаписывается
35
+
36
+ ### Сценарий 4: Создание нескольких сервисов
37
+
38
+ ```bash
39
+ 2byte g service Cache
40
+ 2byte g service Logger
41
+ 2byte g service EmailSender
42
+ 2byte g service DatabaseConnector
43
+ ```
44
+
45
+ **Структура после создания:**
46
+ ```
47
+ workflow/
48
+ └── services/
49
+ ├── CacheService.ts
50
+ ├── LoggerService.ts
51
+ ├── EmailSenderService.ts
52
+ └── DatabaseConnectorService.ts
53
+ ```
54
+
55
+ ## Проверка работы созданного сервиса
56
+
57
+ ### 1. Создайте тестовый сервис
58
+
59
+ ```bash
60
+ 2byte g service Test
61
+ ```
62
+
63
+ ### 2. Измените сервис
64
+
65
+ Откройте `workflow/services/TestService.ts` и добавьте логику:
66
+
67
+ ```typescript
68
+ import { App } from "@2byte/tgbot-framework";
69
+ import { ApiService } from "@2byte/tgbot-framework";
70
+
71
+ export default class TestService extends ApiService {
72
+
73
+ constructor(
74
+ protected app: App,
75
+ public name: string = "TestService"
76
+ ) {
77
+ super(app, name);
78
+ }
79
+
80
+ public async setup(): Promise<void> {
81
+ this.app.debugLog(`[${this.name}] Setting up test service`);
82
+ return Promise.resolve();
83
+ }
84
+
85
+ public async unsetup(): Promise<void> {
86
+ this.app.debugLog(`[${this.name}] Cleaning up test service`);
87
+ return Promise.resolve();
88
+ }
89
+
90
+ public async run(): Promise<void> {
91
+ this.app.debugLog(`[${this.name}] Test service is running!`);
92
+
93
+ // Тестовая задача каждые 10 секунд
94
+ setInterval(() => {
95
+ this.app.debugLog(`[${this.name}] Heartbeat - ${new Date().toISOString()}`);
96
+ }, 10000);
97
+
98
+ return Promise.resolve();
99
+ }
100
+
101
+ // Кастомный метод для тестирования
102
+ public getStatus(): string {
103
+ return `TestService is active at ${new Date().toISOString()}`;
104
+ }
105
+ }
106
+ ```
107
+
108
+ ### 3. Запустите бота
109
+
110
+ ```bash
111
+ bun run index.ts
112
+ ```
113
+
114
+ **Ожидаемые логи:**
115
+ ```
116
+ [App] Registered API services: [ 'TestService', ... ]
117
+ [TestService] Setting up test service
118
+ [TestService] Service setup completed
119
+ [TestService] Test service is running!
120
+ [TestService] Heartbeat - 2025-10-29T...
121
+ [TestService] Heartbeat - 2025-10-29T...
122
+ ```
123
+
124
+ ### 4. Используйте сервис в секции
125
+
126
+ Создайте или откройте секцию:
127
+
128
+ ```typescript
129
+ import { Section } from "@2byte/tgbot-framework";
130
+
131
+ export default class HomeSection extends Section {
132
+ async index() {
133
+ // Получаем наш тестовый сервис
134
+ const testService = this.app.getService('TestService');
135
+
136
+ if (testService) {
137
+ const status = testService.getStatus();
138
+
139
+ await this.message(`🤖 Bot Status\n\n${status}`)
140
+ .send();
141
+ }
142
+ }
143
+ }
144
+ ```
145
+
146
+ ## Интеграционные тесты
147
+
148
+ ### Test 1: Автозагрузка сервиса
149
+
150
+ ```bash
151
+ # Создать сервис
152
+ 2byte g service AutoLoad
153
+
154
+ # Запустить бота
155
+ bun run index.ts
156
+
157
+ # Проверить логи
158
+ # Должно быть: [App] Registered API services: [ 'AutoLoadService', ... ]
159
+ ```
160
+
161
+ ### Test 2: Использование в секциях
162
+
163
+ ```typescript
164
+ // В любой секции
165
+ const service = this.app.getService('AutoLoadService');
166
+ console.log('Service loaded:', service ? 'YES' : 'NO');
167
+ ```
168
+
169
+ ### Test 3: Жизненный цикл
170
+
171
+ ```bash
172
+ # Запустить бота
173
+ bun run index.ts
174
+ # Лог: [ServiceName] Service setup completed
175
+
176
+ # Остановить бота (Ctrl+C)
177
+ # Лог: [ServiceName] Service cleanup completed
178
+ ```
179
+
180
+ ## Примеры реальных сервисов
181
+
182
+ ### Email Service
183
+
184
+ ```bash
185
+ 2byte g service Email
186
+ ```
187
+
188
+ ```typescript
189
+ // workflow/services/EmailService.ts
190
+ import { App, ApiService } from "@2byte/tgbot-framework";
191
+ import nodemailer from 'nodemailer';
192
+
193
+ export default class EmailService extends ApiService {
194
+ private transporter: any;
195
+
196
+ constructor(protected app: App, public name: string = "EmailService") {
197
+ super(app, name);
198
+ }
199
+
200
+ public async setup(): Promise<void> {
201
+ this.transporter = nodemailer.createTransport({
202
+ host: process.env.SMTP_HOST,
203
+ port: parseInt(process.env.SMTP_PORT || '587'),
204
+ auth: {
205
+ user: process.env.SMTP_USER,
206
+ pass: process.env.SMTP_PASS
207
+ }
208
+ });
209
+
210
+ this.app.debugLog(`[${this.name}] Email service ready`);
211
+ }
212
+
213
+ public async sendEmail(to: string, subject: string, text: string) {
214
+ const info = await this.transporter.sendMail({
215
+ from: process.env.EMAIL_FROM,
216
+ to,
217
+ subject,
218
+ text
219
+ });
220
+
221
+ this.app.debugLog(`[${this.name}] Email sent: ${info.messageId}`);
222
+ return info;
223
+ }
224
+ }
225
+ ```
226
+
227
+ ### Database Service
228
+
229
+ ```bash
230
+ 2byte g service Database
231
+ ```
232
+
233
+ ```typescript
234
+ // workflow/services/DatabaseService.ts
235
+ import { App, ApiService } from "@2byte/tgbot-framework";
236
+ import { Database } from 'sqlite3';
237
+
238
+ export default class DatabaseService extends ApiService {
239
+ private db: Database | null = null;
240
+
241
+ constructor(protected app: App, public name: string = "DatabaseService") {
242
+ super(app, name);
243
+ }
244
+
245
+ public async setup(): Promise<void> {
246
+ return new Promise((resolve, reject) => {
247
+ this.db = new Database('./database.db', (err) => {
248
+ if (err) {
249
+ this.app.debugLog(`[${this.name}] DB connection failed`, err);
250
+ reject(err);
251
+ } else {
252
+ this.app.debugLog(`[${this.name}] DB connected`);
253
+ resolve();
254
+ }
255
+ });
256
+ });
257
+ }
258
+
259
+ public async unsetup(): Promise<void> {
260
+ return new Promise((resolve) => {
261
+ this.db?.close(() => {
262
+ this.app.debugLog(`[${this.name}] DB connection closed`);
263
+ resolve();
264
+ });
265
+ });
266
+ }
267
+
268
+ public async query(sql: string, params: any[] = []): Promise<any> {
269
+ return new Promise((resolve, reject) => {
270
+ this.db?.all(sql, params, (err, rows) => {
271
+ if (err) reject(err);
272
+ else resolve(rows);
273
+ });
274
+ });
275
+ }
276
+ }
277
+ ```
278
+
279
+ ### Redis Cache Service
280
+
281
+ ```bash
282
+ 2byte g service RedisCache
283
+ ```
284
+
285
+ ```typescript
286
+ // workflow/services/RedisCacheService.ts
287
+ import { App, ApiService } from "@2byte/tgbot-framework";
288
+ import Redis from 'ioredis';
289
+
290
+ export default class RedisCacheService extends ApiService {
291
+ private redis: Redis | null = null;
292
+
293
+ constructor(protected app: App, public name: string = "RedisCacheService") {
294
+ super(app, name);
295
+ }
296
+
297
+ public async setup(): Promise<void> {
298
+ this.redis = new Redis({
299
+ host: process.env.REDIS_HOST || 'localhost',
300
+ port: parseInt(process.env.REDIS_PORT || '6379'),
301
+ password: process.env.REDIS_PASSWORD
302
+ });
303
+
304
+ this.redis.on('connect', () => {
305
+ this.app.debugLog(`[${this.name}] Redis connected`);
306
+ });
307
+ }
308
+
309
+ public async unsetup(): Promise<void> {
310
+ await this.redis?.quit();
311
+ this.app.debugLog(`[${this.name}] Redis disconnected`);
312
+ }
313
+
314
+ public async get(key: string): Promise<string | null> {
315
+ return this.redis?.get(key) || null;
316
+ }
317
+
318
+ public async set(key: string, value: string, ttl?: number): Promise<void> {
319
+ if (ttl) {
320
+ await this.redis?.setex(key, ttl, value);
321
+ } else {
322
+ await this.redis?.set(key, value);
323
+ }
324
+ }
325
+
326
+ public async del(key: string): Promise<void> {
327
+ await this.redis?.del(key);
328
+ }
329
+ }
330
+ ```
331
+
332
+ ## Troubleshooting Examples
333
+
334
+ ### Проблема: Сервис не создается
335
+
336
+ ```bash
337
+ $ 2byte g service Test
338
+ Error: EACCES: permission denied
339
+ ```
340
+
341
+ **Решение:**
342
+ ```bash
343
+ # Проверьте права доступа
344
+ ls -la workflow/services/
345
+
346
+ # Создайте директорию вручную если нужно
347
+ mkdir -p workflow/services
348
+ chmod 755 workflow/services
349
+ ```
350
+
351
+ ### Проблема: Сервис создан но не загружается
352
+
353
+ **Проверка:**
354
+ ```bash
355
+ # Запустите бота с debug
356
+ DEBUG=* bun run index.ts
357
+
358
+ # Проверьте структуру файла
359
+ cat workflow/services/TestService.ts
360
+ ```
361
+
362
+ **Типичные ошибки:**
363
+ - Файл не экспортирует класс как default
364
+ - Класс не наследуется от ApiService
365
+ - Синтаксическая ошибка в коде
366
+
367
+ ## Performance Tests
368
+
369
+ ### Тест загрузки множества сервисов
370
+
371
+ ```bash
372
+ # Создать 10 сервисов
373
+ for i in {1..10}; do
374
+ 2byte g service Service$i
375
+ done
376
+
377
+ # Запустить и проверить время загрузки
378
+ time bun run index.ts
379
+ ```
380
+
381
+ **Ожидаемый результат:**
382
+ - Все 10 сервисов загружены
383
+ - Время загрузки < 1 секунды
384
+ - Нет ошибок в логах