@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
package/bin/2byte-cli.ts CHANGED
@@ -1,85 +1,98 @@
1
- #!/usr/bin/env bun
2
-
3
- import { Command } from 'commander';
4
- import { CreateBotCommand } from '../src/cli/CreateBotCommand';
5
- import { InitCommand } from'../src/cli/InitCommand';
6
- import { GenerateCommand } from '../src/cli/GenerateCommand';
7
- import chalk from 'chalk';
8
-
9
- const program = new Command();
10
-
11
- program
12
- .name('2byte')
13
- .description('CLI for 2byte Telegram Bot Framework')
14
- .version('1.0.0');
15
-
16
- // Create Bot command
17
- program
18
- .command('create-bot <name>')
19
- .description('Create a new telegram bot with sections-based architecture')
20
- .option('-p, --path [path]', 'Target directory path', process.cwd())
21
- .option('--no-database', 'Skip database setup')
22
- .action(async (name, options) => {
23
- try {
24
- const command = new CreateBotCommand();
25
- await command.execute(name, options);
26
- } catch (error) {
27
- console.error(chalk.red('❌ Error:'), error.message);
28
- process.exit(1);
29
- }
30
- });
31
-
32
- // Init command
33
- program
34
- .command('init')
35
- .description('Initialize 2byte bot in current directory')
36
- .option('-f, --force', 'Override existing files')
37
- .action(async (options) => {
38
- try {
39
- const command = new InitCommand();
40
- await command.execute(options);
41
- } catch (error) {
42
- console.error(chalk.red('❌ Error:'), error.message);
43
- process.exit(1);
44
- }
45
- });
46
-
47
- // Generate commands
48
- const generate = program
49
- .command('generate')
50
- .alias('g')
51
- .description('Generate various bot components');
52
-
53
- generate
54
- .command('section <name>')
55
- .description('Generate a new section')
56
- .action(async (name) => {
57
- try {
58
- const command = new GenerateCommand();
59
- await command.generateSection(name);
60
- } catch (error) {
61
- console.error(chalk.red('❌ Error:'), error.message);
62
- process.exit(1);
63
- }
64
- });
65
-
66
- generate
67
- .command('migration <name>')
68
- .description('Generate a new migration')
69
- .action(async (name) => {
70
- try {
71
- const command = new GenerateCommand();
72
- await command.generateMigration(name);
73
- } catch (error) {
74
- console.error(chalk.red('❌ Error:'), error.message);
75
- process.exit(1);
76
- }
77
- });
78
-
79
- // Parse arguments
80
- program.parse(process.argv);
81
-
82
- // Show help if no command provided
83
- if (!process.argv.slice(2).length) {
84
- program.outputHelp();
1
+ #!/usr/bin/env bun
2
+
3
+ import { Command } from 'commander';
4
+ import { CreateBotCommand } from '../src/cli/CreateBotCommand';
5
+ import { InitCommand } from'../src/cli/InitCommand';
6
+ import { GenerateCommand } from '../src/cli/GenerateCommand';
7
+ import chalk from 'chalk';
8
+
9
+ const program = new Command();
10
+
11
+ program
12
+ .name('2byte')
13
+ .description('CLI for 2byte Telegram Bot Framework')
14
+ .version('1.0.0');
15
+
16
+ // Create Bot command
17
+ program
18
+ .command('create-bot <name>')
19
+ .description('Create a new telegram bot with sections-based architecture')
20
+ .option('-p, --path [path]', 'Target directory path', process.cwd())
21
+ .option('--no-database', 'Skip database setup')
22
+ .action(async (name, options) => {
23
+ try {
24
+ const command = new CreateBotCommand();
25
+ await command.execute(name, options);
26
+ } catch (error) {
27
+ console.error(chalk.red('❌ Error:'), error.message);
28
+ process.exit(1);
29
+ }
30
+ });
31
+
32
+ // Init command
33
+ program
34
+ .command('init')
35
+ .description('Initialize 2byte bot in current directory')
36
+ .option('-f, --force', 'Override existing files')
37
+ .action(async (options) => {
38
+ try {
39
+ const command = new InitCommand();
40
+ await command.execute(options);
41
+ } catch (error) {
42
+ console.error(chalk.red('❌ Error:'), error.message);
43
+ process.exit(1);
44
+ }
45
+ });
46
+
47
+ // Generate commands
48
+ const generate = program
49
+ .command('generate')
50
+ .alias('g')
51
+ .description('Generate various bot components');
52
+
53
+ generate
54
+ .command('section <name>')
55
+ .description('Generate a new section')
56
+ .action(async (name) => {
57
+ try {
58
+ const command = new GenerateCommand();
59
+ await command.generateSection(name);
60
+ } catch (error) {
61
+ console.error(chalk.red('❌ Error:'), error.message);
62
+ process.exit(1);
63
+ }
64
+ });
65
+
66
+ generate
67
+ .command('service <name>')
68
+ .description('Generate a new API service')
69
+ .action(async (name) => {
70
+ try {
71
+ const command = new GenerateCommand();
72
+ await command.generateService(name);
73
+ } catch (error) {
74
+ console.error(chalk.red('❌ Error:'), error.message);
75
+ process.exit(1);
76
+ }
77
+ });
78
+
79
+ generate
80
+ .command('migration <name>')
81
+ .description('Generate a new migration')
82
+ .action(async (name) => {
83
+ try {
84
+ const command = new GenerateCommand();
85
+ await command.generateMigration(name);
86
+ } catch (error) {
87
+ console.error(chalk.red('❌ Error:'), error.message);
88
+ process.exit(1);
89
+ }
90
+ });
91
+
92
+ // Parse arguments
93
+ program.parse(process.argv);
94
+
95
+ // Show help if no command provided
96
+ if (!process.argv.slice(2).length) {
97
+ program.outputHelp();
85
98
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@2byte/tgbot-framework",
3
- "version": "1.0.2",
3
+ "version": "1.0.3",
4
4
  "description": "A TypeScript framework for creating Telegram bots with sections-based architecture (Bun optimized)",
5
5
  "main": "src/index.ts",
6
6
  "types": "src/index.ts",
@@ -34,9 +34,13 @@
34
34
  "mustache": "^4.2.0",
35
35
  "socks": "^2.8.6",
36
36
  "telegraf": "^4.16.3",
37
- "telegram": "^2.26.22"
37
+ "telegram": "^2.26.22",
38
+ "chalk": "^5.6.2",
39
+ "commander": "^14.0.2",
40
+ "fs-extra": "^11.3.2"
38
41
  },
39
42
  "devDependencies": {
43
+ "@types/bun": "^1.3.1",
40
44
  "@types/node": "^20.19.8",
41
45
  "bun-types": "^1.2.18",
42
46
  "typescript": "^5.8.3"
@@ -1,182 +1,182 @@
1
- import * as fs from 'fs-extra';
2
- import * as path from 'path';
3
- import inquirer from 'inquirer';
4
- import chalk from 'chalk';
5
- import Mustache from 'mustache';
6
-
7
- export class CreateBotCommand {
8
- private templatesPath: string;
9
-
10
- constructor() {
11
- this.templatesPath = path.join(__dirname, '../../templates');
12
- }
13
-
14
- async execute(botName: string, options: any): Promise<void> {
15
- console.log(chalk.blue(`🚀 Creating new bot: ${botName}`));
16
-
17
- const targetPath = path.join(options.path, botName);
18
-
19
- // Check if directory already exists
20
- if (await fs.pathExists(targetPath)) {
21
- const { overwrite } = await inquirer.prompt([
22
- {
23
- type: 'confirm',
24
- name: 'overwrite',
25
- message: `Directory ${botName} already exists. Overwrite?`,
26
- default: false,
27
- },
28
- ]);
29
-
30
- if (!overwrite) {
31
- console.log(chalk.yellow('⚠️ Operation cancelled'));
32
- return;
33
- }
34
-
35
- await fs.remove(targetPath);
36
- }
37
-
38
- // Create directory
39
- await fs.ensureDir(targetPath);
40
-
41
- // Get bot configuration
42
- const config = await this.getBotConfig(botName, options);
43
-
44
- // Copy templates
45
- await this.copyTemplates(targetPath, config);
46
-
47
- // Install dependencies if requested
48
- if (config.installDeps) {
49
- await this.installDependencies(targetPath);
50
- }
51
-
52
- // Setup database if requested
53
- if (config.useDatabase) {
54
- console.log(chalk.blue('🗄️ Setting up database...'));
55
-
56
- fs.createFileSync(path.join(targetPath, 'database', 'database.sqlite'));
57
-
58
- console.log(chalk.green('✅ Database setup complete!'));
59
- }
60
-
61
- // Rename .env.example to .env
62
- await fs.rename(
63
- path.join(targetPath, '.env.example'),
64
- path.join(targetPath, '.env')
65
- );
66
-
67
- console.log(chalk.green('✅ .env file created! Please update it with your bot token and settings.'));
68
-
69
- console.log(chalk.green(`✅ Bot ${botName} created successfully!`));
70
- console.log(chalk.blue('📋 Next steps:'));
71
- console.log(` cd ${botName}`);
72
- console.log(` ${config.installDeps ? '' : 'bun install'}${config.installDeps ? '' : ' # Install dependencies'}`);
73
- console.log(' bun run migrate # Run migrations');
74
- console.log(' bun run seed # Seed database');
75
- console.log(' bun run dev # Start bot');
76
- }
77
-
78
- private async getBotConfig(botName: string, options: any) {
79
- const questions = [
80
- {
81
- type: 'input',
82
- name: 'description',
83
- message: 'Bot description:',
84
- default: `A telegram bot created with 2byte framework`,
85
- },
86
- {
87
- type: 'input',
88
- name: 'author',
89
- message: 'Author:',
90
- default: '',
91
- },
92
- {
93
- type: 'confirm',
94
- name: 'useDatabase',
95
- message: 'Include sqlite 3 database setup?',
96
- default: !options.noDatabase,
97
- },
98
- {
99
- type: 'confirm',
100
- name: 'installDeps',
101
- message: 'Install dependencies now?',
102
- default: true,
103
- },
104
- ];
105
-
106
- const answers = await inquirer.prompt(questions);
107
-
108
- return {
109
- botName,
110
- ...answers,
111
- className: this.toPascalCase(botName),
112
- kebabName: this.toKebabCase(botName),
113
- };
114
- }
115
-
116
- private async copyTemplates(targetPath: string, config: any): Promise<void> {
117
- const templatePath = path.join(this.templatesPath, 'bot');
118
-
119
- // Copy all files from template
120
- await this.copyTemplateFiles(templatePath, targetPath, config);
121
- }
122
-
123
- private async copyTemplateFiles(sourcePath: string, targetPath: string, config: any): Promise<void> {
124
- const items = await fs.readdir(sourcePath);
125
-
126
- for (const item of items) {
127
- const sourceItemPath = path.join(sourcePath, item);
128
- const targetItemPath = path.join(targetPath, item);
129
-
130
- const stat = await fs.stat(sourceItemPath);
131
-
132
- if (stat.isDirectory()) {
133
- await fs.ensureDir(targetItemPath);
134
- await this.copyTemplateFiles(sourceItemPath, targetItemPath, config);
135
- } else {
136
- // Read file content
137
- let content = await fs.readFile(sourceItemPath, 'utf-8');
138
-
139
- // Process template
140
- content = Mustache.render(content, config);
141
-
142
- // Write processed content
143
- await fs.writeFile(targetItemPath, content);
144
- }
145
- }
146
- }
147
-
148
- private async installDependencies(targetPath: string): Promise<void> {
149
- console.log(chalk.blue('📦 Installing dependencies...'));
150
-
151
- const { spawn } = require('child_process');
152
-
153
- return new Promise((resolve, reject) => {
154
- const install = spawn('bun', ['install'], {
155
- cwd: targetPath,
156
- stdio: 'inherit'
157
- });
158
-
159
- install.on('close', (code) => {
160
- if (code === 0) {
161
- resolve(void 0);
162
- } else {
163
- reject(new Error(`Installation failed with code ${code}`));
164
- }
165
- });
166
- });
167
- }
168
-
169
- private toPascalCase(str: string): string {
170
- return str
171
- .split(/[-_\s]+/)
172
- .map(word => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())
173
- .join('');
174
- }
175
-
176
- private toKebabCase(str: string): string {
177
- return str
178
- .replace(/([a-z])([A-Z])/g, '$1-$2')
179
- .replace(/[\s_]+/g, '-')
180
- .toLowerCase();
181
- }
1
+ import * as fs from 'fs-extra';
2
+ import * as path from 'path';
3
+ import inquirer from 'inquirer';
4
+ import chalk from 'chalk';
5
+ import Mustache from 'mustache';
6
+
7
+ export class CreateBotCommand {
8
+ private templatesPath: string;
9
+
10
+ constructor() {
11
+ this.templatesPath = path.join(__dirname, '../../templates');
12
+ }
13
+
14
+ async execute(botName: string, options: any): Promise<void> {
15
+ console.log(chalk.blue(`🚀 Creating new bot: ${botName}`));
16
+
17
+ const targetPath = path.join(options.path, botName);
18
+
19
+ // Check if directory already exists
20
+ if (await fs.pathExists(targetPath)) {
21
+ const { overwrite } = await inquirer.prompt([
22
+ {
23
+ type: 'confirm',
24
+ name: 'overwrite',
25
+ message: `Directory ${botName} already exists. Overwrite?`,
26
+ default: false,
27
+ },
28
+ ]);
29
+
30
+ if (!overwrite) {
31
+ console.log(chalk.yellow('⚠️ Operation cancelled'));
32
+ return;
33
+ }
34
+
35
+ await fs.remove(targetPath);
36
+ }
37
+
38
+ // Create directory
39
+ await fs.ensureDir(targetPath);
40
+
41
+ // Get bot configuration
42
+ const config = await this.getBotConfig(botName, options);
43
+
44
+ // Copy templates
45
+ await this.copyTemplates(targetPath, config);
46
+
47
+ // Install dependencies if requested
48
+ if (config.installDeps) {
49
+ await this.installDependencies(targetPath);
50
+ }
51
+
52
+ // Setup database if requested
53
+ if (config.useDatabase) {
54
+ console.log(chalk.blue('🗄️ Setting up database...'));
55
+
56
+ fs.createFileSync(path.join(targetPath, 'database', 'database.sqlite'));
57
+
58
+ console.log(chalk.green('✅ Database setup complete!'));
59
+ }
60
+
61
+ // Rename .env.example to .env
62
+ await fs.rename(
63
+ path.join(targetPath, '.env.example'),
64
+ path.join(targetPath, '.env')
65
+ );
66
+
67
+ console.log(chalk.green('✅ .env file created! Please update it with your bot token and settings.'));
68
+
69
+ console.log(chalk.green(`✅ Bot ${botName} created successfully!`));
70
+ console.log(chalk.blue('📋 Next steps:'));
71
+ console.log(` cd ${botName}`);
72
+ console.log(` ${config.installDeps ? '' : 'bun install'}${config.installDeps ? '' : ' # Install dependencies'}`);
73
+ console.log(' bun run migrate # Run migrations');
74
+ console.log(' bun run seed # Seed database');
75
+ console.log(' bun run dev # Start bot');
76
+ }
77
+
78
+ private async getBotConfig(botName: string, options: any) {
79
+ const questions = [
80
+ {
81
+ type: 'input',
82
+ name: 'description',
83
+ message: 'Bot description:',
84
+ default: `A telegram bot created with 2byte framework`,
85
+ },
86
+ {
87
+ type: 'input',
88
+ name: 'author',
89
+ message: 'Author:',
90
+ default: '',
91
+ },
92
+ {
93
+ type: 'confirm',
94
+ name: 'useDatabase',
95
+ message: 'Include sqlite 3 database setup?',
96
+ default: !options.noDatabase,
97
+ },
98
+ {
99
+ type: 'confirm',
100
+ name: 'installDeps',
101
+ message: 'Install dependencies now?',
102
+ default: true,
103
+ },
104
+ ];
105
+
106
+ const answers = await inquirer.prompt(questions);
107
+
108
+ return {
109
+ botName,
110
+ ...answers,
111
+ className: this.toPascalCase(botName),
112
+ kebabName: this.toKebabCase(botName),
113
+ };
114
+ }
115
+
116
+ private async copyTemplates(targetPath: string, config: any): Promise<void> {
117
+ const templatePath = path.join(this.templatesPath, 'bot');
118
+
119
+ // Copy all files from template
120
+ await this.copyTemplateFiles(templatePath, targetPath, config);
121
+ }
122
+
123
+ private async copyTemplateFiles(sourcePath: string, targetPath: string, config: any): Promise<void> {
124
+ const items = await fs.readdir(sourcePath);
125
+
126
+ for (const item of items) {
127
+ const sourceItemPath = path.join(sourcePath, item);
128
+ const targetItemPath = path.join(targetPath, item);
129
+
130
+ const stat = await fs.stat(sourceItemPath);
131
+
132
+ if (stat.isDirectory()) {
133
+ await fs.ensureDir(targetItemPath);
134
+ await this.copyTemplateFiles(sourceItemPath, targetItemPath, config);
135
+ } else {
136
+ // Read file content
137
+ let content = await fs.readFile(sourceItemPath, 'utf-8');
138
+
139
+ // Process template
140
+ content = Mustache.render(content, config);
141
+
142
+ // Write processed content
143
+ await fs.writeFile(targetItemPath, content);
144
+ }
145
+ }
146
+ }
147
+
148
+ private async installDependencies(targetPath: string): Promise<void> {
149
+ console.log(chalk.blue('📦 Installing dependencies...'));
150
+
151
+ const { spawn } = require('child_process');
152
+
153
+ return new Promise((resolve, reject) => {
154
+ const install = spawn('bun', ['install'], {
155
+ cwd: targetPath,
156
+ stdio: 'inherit'
157
+ });
158
+
159
+ install.on('close', (code) => {
160
+ if (code === 0) {
161
+ resolve(void 0);
162
+ } else {
163
+ reject(new Error(`Installation failed with code ${code}`));
164
+ }
165
+ });
166
+ });
167
+ }
168
+
169
+ private toPascalCase(str: string): string {
170
+ return str
171
+ .split(/[-_\s]+/)
172
+ .map(word => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())
173
+ .join('');
174
+ }
175
+
176
+ private toKebabCase(str: string): string {
177
+ return str
178
+ .replace(/([a-z])([A-Z])/g, '$1-$2')
179
+ .replace(/[\s_]+/g, '-')
180
+ .toLowerCase();
181
+ }
182
182
  }