@2byte/tgbot-framework 1.0.1 → 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.
- package/README.md +300 -300
- package/bin/2byte-cli.ts +97 -84
- package/package.json +6 -2
- package/src/cli/CreateBotCommand.ts +181 -181
- package/src/cli/GenerateCommand.ts +195 -111
- package/src/cli/InitCommand.ts +107 -107
- package/src/console/migrate.ts +82 -82
- package/src/core/ApiService.ts +21 -0
- package/src/core/ApiServiceManager.ts +63 -0
- package/src/core/App.ts +1113 -1042
- package/src/core/BotArtisan.ts +79 -79
- package/src/core/BotMigration.ts +30 -30
- package/src/core/BotSeeder.ts +66 -66
- package/src/core/Model.ts +84 -80
- package/src/core/utils.ts +2 -2
- package/src/illumination/Artisan.ts +149 -149
- package/src/illumination/InlineKeyboard.ts +61 -44
- package/src/illumination/Message2Byte.ts +255 -254
- package/src/illumination/Message2ByteLiveProgressive.ts +278 -278
- package/src/illumination/Message2bytePool.ts +107 -107
- package/src/illumination/Migration.ts +186 -186
- package/src/illumination/RunSectionRoute.ts +85 -85
- package/src/illumination/Section.ts +410 -430
- package/src/illumination/SectionComponent.ts +64 -64
- package/src/illumination/Telegraf2byteContext.ts +32 -32
- package/src/index.ts +35 -33
- package/src/libs/TelegramAccountControl.ts +738 -523
- package/src/types.ts +188 -186
- package/src/user/UserModel.ts +297 -288
- package/src/user/UserStore.ts +119 -119
- package/src/workflow/services/MassSendApiService.ts +80 -0
- package/templates/bot/.env.example +18 -17
- package/templates/bot/artisan.ts +8 -8
- package/templates/bot/bot.ts +79 -77
- package/templates/bot/database/dbConnector.ts +4 -4
- package/templates/bot/database/migrate.ts +9 -9
- package/templates/bot/database/migrations/001_create_users.sql +18 -18
- package/templates/bot/database/seed.ts +14 -14
- package/templates/bot/package.json +30 -30
- package/templates/bot/sectionList.ts +9 -7
- package/templates/bot/sections/ExampleInputSection.ts +85 -0
- package/templates/bot/sections/ExampleLiveTaskerSection.ts +60 -0
- package/templates/bot/sections/HomeSection.ts +63 -65
- 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('
|
|
68
|
-
.description('Generate a new
|
|
69
|
-
.action(async (name) => {
|
|
70
|
-
try {
|
|
71
|
-
const command = new GenerateCommand();
|
|
72
|
-
await command.
|
|
73
|
-
} catch (error) {
|
|
74
|
-
console.error(chalk.red('❌ Error:'), error.message);
|
|
75
|
-
process.exit(1);
|
|
76
|
-
}
|
|
77
|
-
});
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
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.
|
|
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
|
}
|