@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
@@ -1,108 +1,108 @@
1
- import type { Section, Telegraf2byteContext } from "@2byte/tgbot-framework";
2
- import Message2byte from "./Message2Byte";
3
- import Message2ByteLiveProgressive from "./Message2ByteLiveProgressive";
4
-
5
- export default class Message2bytePool {
6
- private message2byte: Message2byte;
7
- private ctx: Telegraf2byteContext;
8
- private messageValue: string = "";
9
- private section: Section;
10
-
11
- static init(message2byte: Message2byte, ctx: Telegraf2byteContext, section: Section) {
12
- return new Message2bytePool(message2byte, ctx, section);
13
- }
14
-
15
- constructor(message2byte: Message2byte, ctx: Telegraf2byteContext, section: Section) {
16
- this.message2byte = message2byte;
17
- this.message2byte.setNotAnswerCbQuery();
18
- this.ctx = ctx;
19
- this.section = section;
20
- }
21
-
22
- markdown(): this {
23
- this.message2byte.markdown();
24
- return this;
25
- }
26
-
27
- html(): this {
28
- this.message2byte.html();
29
- return this;
30
- }
31
-
32
- message(message: string): this {
33
- this.messageValue = message;
34
- if (this.section.route.runIsCallbackQuery) {
35
- this.message2byte.updateMessage(message);
36
- } else {
37
- this.message2byte.message(message);
38
- }
39
- return this;
40
- }
41
-
42
- update(message: string): this {
43
- this.messageValue = message;
44
- this.message2byte.updateMessage(message);
45
- return this;
46
- }
47
-
48
- append(message: string): this {
49
- this.messageValue += message;
50
- this.message2byte.updateMessage(this.messageValue);
51
- return this;
52
- }
53
-
54
- prepend(message: string): this {
55
- this.messageValue = message + this.messageValue;
56
- this.message2byte.updateMessage(this.messageValue);
57
- return this;
58
- }
59
-
60
- liveProgressive(): Message2ByteLiveProgressive {
61
- return Message2ByteLiveProgressive.init(this.message2byte, this);
62
- }
63
-
64
- async send() {
65
-
66
- const entity = await this.message2byte.send();
67
-
68
- // if (typeof entity === "object" && entity.message_id) {
69
- // this.messageId = entity.message_id;
70
- // console.log("Pool message sent with ID:", this.messageId);
71
- // }
72
-
73
- return entity;
74
- }
75
-
76
- async sendReturnThis(): Promise<this> {
77
- await this.send();
78
- return this;
79
- }
80
-
81
- async sleepProgressBar(messageWait: string, ms: number): Promise<void> {
82
- return new Promise<void>((resolve, reject) => {
83
- const pgIcons = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
84
-
85
- let pgIndex = 0;
86
- let currentMessage = this.messageValue + `[pg]${pgIcons[pgIndex]} ${messageWait}`;
87
-
88
- const pgIntervalTimer = setInterval(() => {
89
- // Update progress message here
90
- currentMessage = this.messageValue + `[pg]${pgIcons[pgIndex]} ${messageWait}`;
91
- pgIndex = (pgIndex + 1) % pgIcons.length;
92
-
93
- this.message(currentMessage)
94
- .send()
95
- .catch((err) => {
96
- clearInterval(pgIntervalTimer);
97
- reject(err);
98
- });
99
- }, 1000);
100
-
101
- setTimeout(() => {
102
- clearInterval(pgIntervalTimer);
103
- this.message(this.messageValue);
104
- resolve();
105
- }, ms);
106
- });
107
- }
1
+ import type { Section, Telegraf2byteContext } from "@2byte/tgbot-framework";
2
+ import Message2byte from "./Message2Byte";
3
+ import Message2ByteLiveProgressive from "./Message2ByteLiveProgressive";
4
+
5
+ export default class Message2bytePool {
6
+ private message2byte: Message2byte;
7
+ private ctx: Telegraf2byteContext;
8
+ private messageValue: string = "";
9
+ private section: Section;
10
+
11
+ static init(message2byte: Message2byte, ctx: Telegraf2byteContext, section: Section) {
12
+ return new Message2bytePool(message2byte, ctx, section);
13
+ }
14
+
15
+ constructor(message2byte: Message2byte, ctx: Telegraf2byteContext, section: Section) {
16
+ this.message2byte = message2byte;
17
+ this.message2byte.setNotAnswerCbQuery();
18
+ this.ctx = ctx;
19
+ this.section = section;
20
+ }
21
+
22
+ markdown(): this {
23
+ this.message2byte.markdown();
24
+ return this;
25
+ }
26
+
27
+ html(): this {
28
+ this.message2byte.html();
29
+ return this;
30
+ }
31
+
32
+ message(message: string): this {
33
+ this.messageValue = message;
34
+ if (this.section.route.runIsCallbackQuery) {
35
+ this.message2byte.updateMessage(message);
36
+ } else {
37
+ this.message2byte.message(message);
38
+ }
39
+ return this;
40
+ }
41
+
42
+ update(message: string): this {
43
+ this.messageValue = message;
44
+ this.message2byte.updateMessage(message);
45
+ return this;
46
+ }
47
+
48
+ append(message: string): this {
49
+ this.messageValue += message;
50
+ this.message2byte.updateMessage(this.messageValue);
51
+ return this;
52
+ }
53
+
54
+ prepend(message: string): this {
55
+ this.messageValue = message + this.messageValue;
56
+ this.message2byte.updateMessage(this.messageValue);
57
+ return this;
58
+ }
59
+
60
+ liveProgressive(): Message2ByteLiveProgressive {
61
+ return Message2ByteLiveProgressive.init(this.message2byte, this);
62
+ }
63
+
64
+ async send() {
65
+
66
+ const entity = await this.message2byte.send();
67
+
68
+ // if (typeof entity === "object" && entity.message_id) {
69
+ // this.messageId = entity.message_id;
70
+ // console.log("Pool message sent with ID:", this.messageId);
71
+ // }
72
+
73
+ return entity;
74
+ }
75
+
76
+ async sendReturnThis(): Promise<this> {
77
+ await this.send();
78
+ return this;
79
+ }
80
+
81
+ async sleepProgressBar(messageWait: string, ms: number): Promise<void> {
82
+ return new Promise<void>((resolve, reject) => {
83
+ const pgIcons = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
84
+
85
+ let pgIndex = 0;
86
+ let currentMessage = this.messageValue + `[pg]${pgIcons[pgIndex]} ${messageWait}`;
87
+
88
+ const pgIntervalTimer = setInterval(() => {
89
+ // Update progress message here
90
+ currentMessage = this.messageValue + `[pg]${pgIcons[pgIndex]} ${messageWait}`;
91
+ pgIndex = (pgIndex + 1) % pgIcons.length;
92
+
93
+ this.message(currentMessage)
94
+ .send()
95
+ .catch((err) => {
96
+ clearInterval(pgIntervalTimer);
97
+ reject(err);
98
+ });
99
+ }, 1000);
100
+
101
+ setTimeout(() => {
102
+ clearInterval(pgIntervalTimer);
103
+ this.message(this.messageValue);
104
+ resolve();
105
+ }, ms);
106
+ });
107
+ }
108
108
  }
@@ -1,186 +1,186 @@
1
- import { Database } from 'bun:sqlite';
2
- import fs from 'fs';
3
- import path from 'path';
4
-
5
- export interface MigrationFile {
6
- id: number;
7
- name: string;
8
- path: string;
9
- }
10
-
11
- export class Migration {
12
- private db: Database;
13
- private migrationsPath: string;
14
-
15
- constructor(db: Database, migrationsPath: string) {
16
- this.db = db;
17
- this.migrationsPath = migrationsPath;
18
- this.initMigrationsTable();
19
- }
20
-
21
- /**
22
- * Инициализация таблицы миграций
23
- */
24
- private initMigrationsTable(): void {
25
- this.db.query(`
26
- CREATE TABLE IF NOT EXISTS migrations (
27
- id INTEGER PRIMARY KEY AUTOINCREMENT,
28
- name TEXT NOT NULL,
29
- batch INTEGER NOT NULL,
30
- created_at DATETIME DEFAULT CURRENT_TIMESTAMP
31
- )
32
- `).run();
33
- }
34
-
35
- /**
36
- * Получение списка файлов миграций
37
- */
38
- private getMigrationFiles(): MigrationFile[] {
39
- const files = fs.readdirSync(this.migrationsPath)
40
- .filter(file => file.endsWith('.sql'))
41
- .map(file => {
42
- const [id, ...nameParts] = file.replace('.sql', '').split('_');
43
- return {
44
- id: parseInt(id),
45
- name: nameParts.join('_'),
46
- path: path.join(this.migrationsPath, file)
47
- };
48
- })
49
- .sort((a, b) => a.id - b.id);
50
-
51
- return files;
52
- }
53
-
54
- /**
55
- * Получение списка выполненных миграций
56
- */
57
- private getExecutedMigrations(): string[] {
58
- const result = this.db.query('SELECT name FROM migrations').all() as { name: string }[];
59
- return result.map(row => row.name);
60
- }
61
-
62
- /**
63
- * Выполнение миграции
64
- */
65
- async up(): Promise<void> {
66
- const executed = this.getExecutedMigrations();
67
- const files = this.getMigrationFiles();
68
- const batch = this.getLastBatch() + 1;
69
-
70
- for (const file of files) {
71
- if (!executed.includes(file.name)) {
72
- try {
73
- const sql = fs.readFileSync(file.path, 'utf-8');
74
- this.db.transaction(() => {
75
- this.db.query(sql).run();
76
- this.db.query('INSERT INTO migrations (name, batch) VALUES (?, ?)')
77
- .run(file.name, batch);
78
- })();
79
- console.log(`✅ Миграция ${file.name} выполнена успешно`);
80
- } catch (error) {
81
- console.error(`❌ Ошибка при выполнении миграции ${file.name}:`, error);
82
- throw error;
83
- }
84
- }
85
- }
86
- }
87
-
88
- /**
89
- * Откат миграций
90
- */
91
- async down(steps: number = 1): Promise<void> {
92
- const batch = this.getLastBatch();
93
- if (batch === 0) {
94
- console.log('Нет миграций для отката');
95
- return;
96
- }
97
-
98
- const migrations = this.db.query(`
99
- SELECT * FROM migrations
100
- WHERE batch >= ?
101
- ORDER BY batch DESC, id DESC
102
- LIMIT ?
103
- `).all(batch - steps + 1, steps) as { name: string }[];
104
-
105
- for (const migration of migrations) {
106
- const file = this.getMigrationFiles().find(f => f.name === migration.name);
107
- if (file) {
108
- try {
109
- const sql = fs.readFileSync(file.path, 'utf-8');
110
- const downSql = this.extractDownSQL(sql);
111
-
112
- if (downSql) {
113
- this.db.transaction(() => {
114
- this.db.query(downSql).run();
115
- this.db.query('DELETE FROM migrations WHERE name = ?').run(migration.name);
116
- })();
117
- console.log(`✅ Откат миграции ${migration.name} выполнен успешно`);
118
- } else {
119
- console.warn(`⚠️ Секция DOWN не найдена в миграции ${migration.name}`);
120
- }
121
- } catch (error) {
122
- console.error(`❌ Ошибка при откате миграции ${migration.name}:`, error);
123
- throw error;
124
- }
125
- }
126
- }
127
- }
128
-
129
- /**
130
- * Получение последнего номера batch
131
- */
132
- private getLastBatch(): number {
133
- const result = this.db.query('SELECT MAX(batch) as max_batch FROM migrations').get() as { max_batch: number };
134
- return result.max_batch || 0;
135
- }
136
-
137
- /**
138
- * Извлечение SQL для отката из файла миграции
139
- */
140
- private extractDownSQL(sql: string): string | null {
141
- const downMatch = sql.match(/-- DOWN\s+([\s\S]+?)(?=-- UP|$)/i);
142
- return downMatch ? downMatch[1].trim() : null;
143
- }
144
-
145
- /**
146
- * Создание новой миграции
147
- */
148
- static async create(name: string, migrationsPath: string): Promise<void> {
149
- const files = fs.readdirSync(migrationsPath)
150
- .filter(file => file.endsWith('.sql'))
151
- .map(file => parseInt(file.split('_')[0]));
152
-
153
- const nextId = (Math.max(0, ...files) + 1).toString().padStart(3, '0');
154
- const fileName = `${nextId}_${name}.sql`;
155
- const filePath = path.join(migrationsPath, fileName);
156
-
157
- const template = `-- UP
158
- CREATE TABLE IF NOT EXISTS ${name} (
159
- id INTEGER PRIMARY KEY AUTOINCREMENT,
160
- created_at DATETIME DEFAULT CURRENT_TIMESTAMP
161
- );
162
-
163
- -- DOWN
164
- DROP TABLE IF EXISTS ${name};
165
- `;
166
-
167
- fs.writeFileSync(filePath, template);
168
- console.log(`✅ Создана новая миграция: ${fileName}`);
169
- }
170
-
171
- /**
172
- * Статус миграций
173
- */
174
- status(): void {
175
- const executed = this.getExecutedMigrations();
176
- const files = this.getMigrationFiles();
177
-
178
- console.log('\n📊 Статус миграций:\n');
179
-
180
- for (const file of files) {
181
- const status = executed.includes(file.name) ? '✅' : '⏳';
182
- console.log(`${status} ${file.id}_${file.name}`);
183
- }
184
- console.log();
185
- }
186
- }
1
+ import { Database } from 'bun:sqlite';
2
+ import fs from 'fs';
3
+ import path from 'path';
4
+
5
+ export interface MigrationFile {
6
+ id: number;
7
+ name: string;
8
+ path: string;
9
+ }
10
+
11
+ export class Migration {
12
+ private db: Database;
13
+ private migrationsPath: string;
14
+
15
+ constructor(db: Database, migrationsPath: string) {
16
+ this.db = db;
17
+ this.migrationsPath = migrationsPath;
18
+ this.initMigrationsTable();
19
+ }
20
+
21
+ /**
22
+ * Инициализация таблицы миграций
23
+ */
24
+ private initMigrationsTable(): void {
25
+ this.db.query(`
26
+ CREATE TABLE IF NOT EXISTS migrations (
27
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
28
+ name TEXT NOT NULL,
29
+ batch INTEGER NOT NULL,
30
+ created_at DATETIME DEFAULT CURRENT_TIMESTAMP
31
+ )
32
+ `).run();
33
+ }
34
+
35
+ /**
36
+ * Получение списка файлов миграций
37
+ */
38
+ private getMigrationFiles(): MigrationFile[] {
39
+ const files = fs.readdirSync(this.migrationsPath)
40
+ .filter(file => file.endsWith('.sql'))
41
+ .map(file => {
42
+ const [id, ...nameParts] = file.replace('.sql', '').split('_');
43
+ return {
44
+ id: parseInt(id),
45
+ name: nameParts.join('_'),
46
+ path: path.join(this.migrationsPath, file)
47
+ };
48
+ })
49
+ .sort((a, b) => a.id - b.id);
50
+
51
+ return files;
52
+ }
53
+
54
+ /**
55
+ * Получение списка выполненных миграций
56
+ */
57
+ private getExecutedMigrations(): string[] {
58
+ const result = this.db.query('SELECT name FROM migrations').all() as { name: string }[];
59
+ return result.map(row => row.name);
60
+ }
61
+
62
+ /**
63
+ * Выполнение миграции
64
+ */
65
+ async up(): Promise<void> {
66
+ const executed = this.getExecutedMigrations();
67
+ const files = this.getMigrationFiles();
68
+ const batch = this.getLastBatch() + 1;
69
+
70
+ for (const file of files) {
71
+ if (!executed.includes(file.name)) {
72
+ try {
73
+ const sql = fs.readFileSync(file.path, 'utf-8');
74
+ this.db.transaction(() => {
75
+ this.db.query(sql).run();
76
+ this.db.query('INSERT INTO migrations (name, batch) VALUES (?, ?)')
77
+ .run(file.name, batch);
78
+ })();
79
+ console.log(`✅ Миграция ${file.name} выполнена успешно`);
80
+ } catch (error) {
81
+ console.error(`❌ Ошибка при выполнении миграции ${file.name}:`, error);
82
+ throw error;
83
+ }
84
+ }
85
+ }
86
+ }
87
+
88
+ /**
89
+ * Откат миграций
90
+ */
91
+ async down(steps: number = 1): Promise<void> {
92
+ const batch = this.getLastBatch();
93
+ if (batch === 0) {
94
+ console.log('Нет миграций для отката');
95
+ return;
96
+ }
97
+
98
+ const migrations = this.db.query(`
99
+ SELECT * FROM migrations
100
+ WHERE batch >= ?
101
+ ORDER BY batch DESC, id DESC
102
+ LIMIT ?
103
+ `).all(batch - steps + 1, steps) as { name: string }[];
104
+
105
+ for (const migration of migrations) {
106
+ const file = this.getMigrationFiles().find(f => f.name === migration.name);
107
+ if (file) {
108
+ try {
109
+ const sql = fs.readFileSync(file.path, 'utf-8');
110
+ const downSql = this.extractDownSQL(sql);
111
+
112
+ if (downSql) {
113
+ this.db.transaction(() => {
114
+ this.db.query(downSql).run();
115
+ this.db.query('DELETE FROM migrations WHERE name = ?').run(migration.name);
116
+ })();
117
+ console.log(`✅ Откат миграции ${migration.name} выполнен успешно`);
118
+ } else {
119
+ console.warn(`⚠️ Секция DOWN не найдена в миграции ${migration.name}`);
120
+ }
121
+ } catch (error) {
122
+ console.error(`❌ Ошибка при откате миграции ${migration.name}:`, error);
123
+ throw error;
124
+ }
125
+ }
126
+ }
127
+ }
128
+
129
+ /**
130
+ * Получение последнего номера batch
131
+ */
132
+ private getLastBatch(): number {
133
+ const result = this.db.query('SELECT MAX(batch) as max_batch FROM migrations').get() as { max_batch: number };
134
+ return result.max_batch || 0;
135
+ }
136
+
137
+ /**
138
+ * Извлечение SQL для отката из файла миграции
139
+ */
140
+ private extractDownSQL(sql: string): string | null {
141
+ const downMatch = sql.match(/-- DOWN\s+([\s\S]+?)(?=-- UP|$)/i);
142
+ return downMatch ? downMatch[1].trim() : null;
143
+ }
144
+
145
+ /**
146
+ * Создание новой миграции
147
+ */
148
+ static async create(name: string, migrationsPath: string): Promise<void> {
149
+ const files = fs.readdirSync(migrationsPath)
150
+ .filter(file => file.endsWith('.sql'))
151
+ .map(file => parseInt(file.split('_')[0]));
152
+
153
+ const nextId = (Math.max(0, ...files) + 1).toString().padStart(3, '0');
154
+ const fileName = `${nextId}_${name}.sql`;
155
+ const filePath = path.join(migrationsPath, fileName);
156
+
157
+ const template = `-- UP
158
+ CREATE TABLE IF NOT EXISTS ${name} (
159
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
160
+ created_at DATETIME DEFAULT CURRENT_TIMESTAMP
161
+ );
162
+
163
+ -- DOWN
164
+ DROP TABLE IF EXISTS ${name};
165
+ `;
166
+
167
+ fs.writeFileSync(filePath, template);
168
+ console.log(`✅ Создана новая миграция: ${fileName}`);
169
+ }
170
+
171
+ /**
172
+ * Статус миграций
173
+ */
174
+ status(): void {
175
+ const executed = this.getExecutedMigrations();
176
+ const files = this.getMigrationFiles();
177
+
178
+ console.log('\n📊 Статус миграций:\n');
179
+
180
+ for (const file of files) {
181
+ const status = executed.includes(file.name) ? '✅' : '⏳';
182
+ console.log(`${status} ${file.id}_${file.name}`);
183
+ }
184
+ console.log();
185
+ }
186
+ }