@2byte/tgbot-framework 1.0.5 → 1.0.7
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 -97
- package/package.json +54 -54
- package/src/cli/CreateBotCommand.ts +181 -181
- package/src/cli/GenerateCommand.ts +195 -195
- package/src/cli/InitCommand.ts +107 -107
- package/src/cli/TgAccountManager.ts +50 -50
- package/src/console/migrate.ts +82 -82
- package/src/core/ApiService.ts +20 -20
- package/src/core/ApiServiceManager.ts +63 -63
- package/src/core/App.ts +1157 -1143
- 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 -84
- package/src/core/utils.ts +2 -2
- package/src/illumination/Artisan.ts +149 -149
- package/src/illumination/InlineKeyboard.ts +61 -61
- package/src/illumination/Message2Byte.ts +255 -255
- 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 -410
- package/src/illumination/SectionComponent.ts +64 -64
- package/src/illumination/Telegraf2byteContext.ts +32 -32
- package/src/index.ts +42 -42
- package/src/libs/TelegramAccountControl.ts +1140 -1140
- package/src/libs/TgSender.ts +53 -53
- package/src/models/Model.ts +67 -67
- package/src/models/Proxy.ts +217 -217
- package/src/models/TgAccount.ts +362 -362
- package/src/models/index.ts +2 -2
- package/src/types.ts +191 -191
- package/src/user/UserModel.ts +297 -297
- package/src/user/UserStore.ts +119 -119
- package/src/workflow/services/MassSendApiService.ts +80 -80
- package/templates/bot/.env.example +34 -23
- package/templates/bot/artisan.ts +8 -8
- package/templates/bot/bot.ts +82 -82
- 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/migrations/007_proxy.sql +27 -27
- package/templates/bot/database/migrations/008_tg_accounts.sql +32 -32
- package/templates/bot/database/seed.ts +14 -14
- package/templates/bot/docs/CLI_SERVICES.md +536 -536
- package/templates/bot/docs/INPUT_SYSTEM.md +211 -211
- package/templates/bot/docs/SERVICE_EXAMPLES.md +384 -384
- package/templates/bot/docs/TASK_SYSTEM.md +156 -156
- package/templates/bot/models/Model.ts +7 -7
- package/templates/bot/models/index.ts +1 -1
- package/templates/bot/package.json +30 -30
- package/templates/bot/sectionList.ts +9 -9
- package/templates/bot/sections/ExampleInputSection.ts +85 -85
- package/templates/bot/sections/ExampleLiveTaskerSection.ts +60 -60
- package/templates/bot/sections/HomeSection.ts +63 -63
- package/templates/bot/workflow/services/ExampleService.ts +23 -23
|
@@ -1,536 +1,536 @@
|
|
|
1
|
-
# Service Generator - CLI Documentation
|
|
2
|
-
|
|
3
|
-
## Описание
|
|
4
|
-
|
|
5
|
-
Генератор для создания API сервисов в 2byte Telegram Bot Framework. Сервисы - это переиспользуемые компоненты, которые предоставляют функциональность для всего бота.
|
|
6
|
-
|
|
7
|
-
## Использование
|
|
8
|
-
|
|
9
|
-
### Базовая команда
|
|
10
|
-
|
|
11
|
-
```bash
|
|
12
|
-
2byte generate service <name>
|
|
13
|
-
# или короткая форма
|
|
14
|
-
2byte g service <name>
|
|
15
|
-
```
|
|
16
|
-
|
|
17
|
-
### Примеры
|
|
18
|
-
|
|
19
|
-
```bash
|
|
20
|
-
# Создать сервис для работы с API
|
|
21
|
-
2byte generate service PaymentAPI
|
|
22
|
-
|
|
23
|
-
# Создать сервис для уведомлений
|
|
24
|
-
2byte g service Notification
|
|
25
|
-
|
|
26
|
-
# Создать сервис для кеширования
|
|
27
|
-
2byte g service Cache
|
|
28
|
-
|
|
29
|
-
# Создать сервис для логирования
|
|
30
|
-
2byte g service Logger
|
|
31
|
-
```
|
|
32
|
-
|
|
33
|
-
## Что создается
|
|
34
|
-
|
|
35
|
-
### Структура файла
|
|
36
|
-
|
|
37
|
-
Генератор создает файл в директории `workflow/services/`:
|
|
38
|
-
|
|
39
|
-
```
|
|
40
|
-
your-bot/
|
|
41
|
-
├── workflow/
|
|
42
|
-
│ └── services/
|
|
43
|
-
│ ├── PaymentAPIService.ts ← новый файл
|
|
44
|
-
│ ├── NotificationService.ts
|
|
45
|
-
│ └── ...
|
|
46
|
-
```
|
|
47
|
-
|
|
48
|
-
### Имя файла
|
|
49
|
-
|
|
50
|
-
- Автоматически добавляется суффикс `Service` если его нет
|
|
51
|
-
- Используется PascalCase форматирование
|
|
52
|
-
|
|
53
|
-
**Примеры:**
|
|
54
|
-
- `payment` → `PaymentService.ts`
|
|
55
|
-
- `PaymentAPI` → `PaymentAPIService.ts`
|
|
56
|
-
- `notification-sender` → `Notification-senderService.ts` (лучше использовать camelCase)
|
|
57
|
-
|
|
58
|
-
## Структура сервиса
|
|
59
|
-
|
|
60
|
-
Сгенерированный сервис содержит:
|
|
61
|
-
|
|
62
|
-
```typescript
|
|
63
|
-
import { App } from "@2byte/tgbot-framework";
|
|
64
|
-
import { ApiService } from "@2byte/tgbot-framework";
|
|
65
|
-
|
|
66
|
-
export default class PaymentAPIService extends ApiService {
|
|
67
|
-
|
|
68
|
-
constructor(
|
|
69
|
-
protected app: App,
|
|
70
|
-
public name: string = "PaymentAPIService"
|
|
71
|
-
) {
|
|
72
|
-
super(app, name);
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
public async setup(): Promise<void> {
|
|
76
|
-
// Инициализация при запуске
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
public async unsetup(): Promise<void> {
|
|
80
|
-
// Очистка при остановке
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
public async run(): Promise<void> {
|
|
84
|
-
// Основная логика сервиса
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
```
|
|
88
|
-
|
|
89
|
-
## Методы сервиса
|
|
90
|
-
|
|
91
|
-
### `setup()`
|
|
92
|
-
|
|
93
|
-
Вызывается при регистрации сервиса во время запуска бота.
|
|
94
|
-
|
|
95
|
-
**Используйте для:**
|
|
96
|
-
- Инициализации подключений к БД
|
|
97
|
-
- Загрузки конфигураций
|
|
98
|
-
- Настройки HTTP клиентов
|
|
99
|
-
- Подписки на события
|
|
100
|
-
|
|
101
|
-
**Пример:**
|
|
102
|
-
```typescript
|
|
103
|
-
public async setup(): Promise<void> {
|
|
104
|
-
this.apiClient = axios.create({
|
|
105
|
-
baseURL: 'https://api.example.com',
|
|
106
|
-
timeout: 5000
|
|
107
|
-
});
|
|
108
|
-
|
|
109
|
-
this.app.debugLog(`[${this.name}] API client initialized`);
|
|
110
|
-
}
|
|
111
|
-
```
|
|
112
|
-
|
|
113
|
-
### `unsetup()`
|
|
114
|
-
|
|
115
|
-
Вызывается при остановке бота или выгрузке сервиса.
|
|
116
|
-
|
|
117
|
-
**Используйте для:**
|
|
118
|
-
- Закрытия подключений
|
|
119
|
-
- Сохранения состояния
|
|
120
|
-
- Отписки от событий
|
|
121
|
-
- Освобождения ресурсов
|
|
122
|
-
|
|
123
|
-
**Пример:**
|
|
124
|
-
```typescript
|
|
125
|
-
public async unsetup(): Promise<void> {
|
|
126
|
-
await this.apiClient?.disconnect();
|
|
127
|
-
this.app.debugLog(`[${this.name}] Cleanup completed`);
|
|
128
|
-
}
|
|
129
|
-
```
|
|
130
|
-
|
|
131
|
-
### `run()`
|
|
132
|
-
|
|
133
|
-
Основной метод для логики сервиса.
|
|
134
|
-
|
|
135
|
-
**Используйте для:**
|
|
136
|
-
- Запуска фоновых задач
|
|
137
|
-
- Периодических операций
|
|
138
|
-
- Обработки очередей
|
|
139
|
-
- Любой основной логики
|
|
140
|
-
|
|
141
|
-
**Пример:**
|
|
142
|
-
```typescript
|
|
143
|
-
public async run(): Promise<void> {
|
|
144
|
-
// Запуск периодической задачи
|
|
145
|
-
setInterval(async () => {
|
|
146
|
-
await this.checkPayments();
|
|
147
|
-
}, 60000); // каждую минуту
|
|
148
|
-
}
|
|
149
|
-
```
|
|
150
|
-
|
|
151
|
-
## Автоматическая загрузка
|
|
152
|
-
|
|
153
|
-
Сервисы автоматически загружаются из директории `workflow/services/` при запуске бота.
|
|
154
|
-
|
|
155
|
-
**Процесс:**
|
|
156
|
-
1. Бот сканирует `workflow/services/`
|
|
157
|
-
2. Импортирует все `.ts` файлы
|
|
158
|
-
3. Создает экземпляры сервисов
|
|
159
|
-
4. Вызывает `setup()` для каждого
|
|
160
|
-
5. Регистрирует в `ApiServiceManager`
|
|
161
|
-
|
|
162
|
-
## Использование сервисов
|
|
163
|
-
|
|
164
|
-
### Из секций
|
|
165
|
-
|
|
166
|
-
```typescript
|
|
167
|
-
// В любой секции
|
|
168
|
-
export default class HomeSection extends Section {
|
|
169
|
-
async index() {
|
|
170
|
-
// Получить сервис
|
|
171
|
-
const paymentService = this.app.getService('PaymentAPIService');
|
|
172
|
-
|
|
173
|
-
// Использовать
|
|
174
|
-
const result = await paymentService.processPayment(100);
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
```
|
|
178
|
-
|
|
179
|
-
### Из других сервисов
|
|
180
|
-
|
|
181
|
-
```typescript
|
|
182
|
-
export default class NotificationService extends ApiService {
|
|
183
|
-
public async sendNotification(userId: number, message: string) {
|
|
184
|
-
// Получить другой сервис
|
|
185
|
-
const logger = this.app.getService('LoggerService');
|
|
186
|
-
logger.log(`Sending notification to ${userId}`);
|
|
187
|
-
|
|
188
|
-
// Ваша логика
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
```
|
|
192
|
-
|
|
193
|
-
### Из App
|
|
194
|
-
|
|
195
|
-
```typescript
|
|
196
|
-
const app = new App(config);
|
|
197
|
-
|
|
198
|
-
// После инициализации
|
|
199
|
-
const service = app.getService('PaymentAPIService');
|
|
200
|
-
```
|
|
201
|
-
|
|
202
|
-
## Примеры сервисов
|
|
203
|
-
|
|
204
|
-
### 1. API клиент
|
|
205
|
-
|
|
206
|
-
```typescript
|
|
207
|
-
import { App, ApiService } from "@2byte/tgbot-framework";
|
|
208
|
-
import axios, { AxiosInstance } from 'axios';
|
|
209
|
-
|
|
210
|
-
export default class PaymentAPIService extends ApiService {
|
|
211
|
-
private client: AxiosInstance;
|
|
212
|
-
|
|
213
|
-
constructor(protected app: App, public name: string = "PaymentAPIService") {
|
|
214
|
-
super(app, name);
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
public async setup(): Promise<void> {
|
|
218
|
-
this.client = axios.create({
|
|
219
|
-
baseURL: process.env.PAYMENT_API_URL,
|
|
220
|
-
headers: {
|
|
221
|
-
'Authorization': `Bearer ${process.env.PAYMENT_API_KEY}`
|
|
222
|
-
}
|
|
223
|
-
});
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
public async createPayment(amount: number, userId: number) {
|
|
227
|
-
const response = await this.client.post('/payments', {
|
|
228
|
-
amount,
|
|
229
|
-
userId,
|
|
230
|
-
currency: 'USD'
|
|
231
|
-
});
|
|
232
|
-
return response.data;
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
public async checkPaymentStatus(paymentId: string) {
|
|
236
|
-
const response = await this.client.get(`/payments/${paymentId}`);
|
|
237
|
-
return response.data;
|
|
238
|
-
}
|
|
239
|
-
}
|
|
240
|
-
```
|
|
241
|
-
|
|
242
|
-
### 2. Кеш сервис
|
|
243
|
-
|
|
244
|
-
```typescript
|
|
245
|
-
import { App, ApiService } from "@2byte/tgbot-framework";
|
|
246
|
-
|
|
247
|
-
export default class CacheService extends ApiService {
|
|
248
|
-
private cache: Map<string, any> = new Map();
|
|
249
|
-
private ttl: Map<string, number> = new Map();
|
|
250
|
-
|
|
251
|
-
constructor(protected app: App, public name: string = "CacheService") {
|
|
252
|
-
super(app, name);
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
public async setup(): Promise<void> {
|
|
256
|
-
// Очистка истекших записей каждые 5 минут
|
|
257
|
-
setInterval(() => this.cleanExpired(), 5 * 60 * 1000);
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
public set(key: string, value: any, ttlSeconds: number = 3600): void {
|
|
261
|
-
this.cache.set(key, value);
|
|
262
|
-
this.ttl.set(key, Date.now() + ttlSeconds * 1000);
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
public get(key: string): any | null {
|
|
266
|
-
if (!this.cache.has(key)) return null;
|
|
267
|
-
|
|
268
|
-
const expiry = this.ttl.get(key);
|
|
269
|
-
if (expiry && expiry < Date.now()) {
|
|
270
|
-
this.cache.delete(key);
|
|
271
|
-
this.ttl.delete(key);
|
|
272
|
-
return null;
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
return this.cache.get(key);
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
private cleanExpired(): void {
|
|
279
|
-
const now = Date.now();
|
|
280
|
-
for (const [key, expiry] of this.ttl.entries()) {
|
|
281
|
-
if (expiry < now) {
|
|
282
|
-
this.cache.delete(key);
|
|
283
|
-
this.ttl.delete(key);
|
|
284
|
-
}
|
|
285
|
-
}
|
|
286
|
-
}
|
|
287
|
-
}
|
|
288
|
-
```
|
|
289
|
-
|
|
290
|
-
### 3. Логгер сервис
|
|
291
|
-
|
|
292
|
-
```typescript
|
|
293
|
-
import { App, ApiService } from "@2byte/tgbot-framework";
|
|
294
|
-
import * as fs from 'fs-extra';
|
|
295
|
-
import * as path from 'path';
|
|
296
|
-
|
|
297
|
-
export default class LoggerService extends ApiService {
|
|
298
|
-
private logPath: string;
|
|
299
|
-
|
|
300
|
-
constructor(protected app: App, public name: string = "LoggerService") {
|
|
301
|
-
super(app, name);
|
|
302
|
-
this.logPath = path.join(process.cwd(), 'logs');
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
public async setup(): Promise<void> {
|
|
306
|
-
await fs.ensureDir(this.logPath);
|
|
307
|
-
}
|
|
308
|
-
|
|
309
|
-
public async log(message: string, level: 'info' | 'error' | 'warn' = 'info'): Promise<void> {
|
|
310
|
-
const timestamp = new Date().toISOString();
|
|
311
|
-
const logMessage = `[${timestamp}] [${level.toUpperCase()}] ${message}\n`;
|
|
312
|
-
|
|
313
|
-
const filename = `${new Date().toISOString().split('T')[0]}.log`;
|
|
314
|
-
const filepath = path.join(this.logPath, filename);
|
|
315
|
-
|
|
316
|
-
await fs.appendFile(filepath, logMessage);
|
|
317
|
-
|
|
318
|
-
// Также выводим в консоль
|
|
319
|
-
console.log(logMessage);
|
|
320
|
-
}
|
|
321
|
-
|
|
322
|
-
public async error(message: string): Promise<void> {
|
|
323
|
-
await this.log(message, 'error');
|
|
324
|
-
}
|
|
325
|
-
|
|
326
|
-
public async warn(message: string): Promise<void> {
|
|
327
|
-
await this.log(message, 'warn');
|
|
328
|
-
}
|
|
329
|
-
}
|
|
330
|
-
```
|
|
331
|
-
|
|
332
|
-
### 4. Планировщик задач
|
|
333
|
-
|
|
334
|
-
```typescript
|
|
335
|
-
import { App, ApiService } from "@2byte/tgbot-framework";
|
|
336
|
-
|
|
337
|
-
interface ScheduledTask {
|
|
338
|
-
id: string;
|
|
339
|
-
callback: () => Promise<void>;
|
|
340
|
-
interval: number;
|
|
341
|
-
timer?: NodeJS.Timeout;
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
export default class SchedulerService extends ApiService {
|
|
345
|
-
private tasks: Map<string, ScheduledTask> = new Map();
|
|
346
|
-
|
|
347
|
-
constructor(protected app: App, public name: string = "SchedulerService") {
|
|
348
|
-
super(app, name);
|
|
349
|
-
}
|
|
350
|
-
|
|
351
|
-
public async setup(): Promise<void> {
|
|
352
|
-
this.app.debugLog(`[${this.name}] Scheduler ready`);
|
|
353
|
-
}
|
|
354
|
-
|
|
355
|
-
public async unsetup(): Promise<void> {
|
|
356
|
-
// Останавливаем все задачи
|
|
357
|
-
for (const task of this.tasks.values()) {
|
|
358
|
-
if (task.timer) {
|
|
359
|
-
clearInterval(task.timer);
|
|
360
|
-
}
|
|
361
|
-
}
|
|
362
|
-
this.tasks.clear();
|
|
363
|
-
}
|
|
364
|
-
|
|
365
|
-
public addTask(id: string, callback: () => Promise<void>, intervalMs: number): void {
|
|
366
|
-
if (this.tasks.has(id)) {
|
|
367
|
-
throw new Error(`Task ${id} already exists`);
|
|
368
|
-
}
|
|
369
|
-
|
|
370
|
-
const timer = setInterval(async () => {
|
|
371
|
-
try {
|
|
372
|
-
await callback();
|
|
373
|
-
} catch (error) {
|
|
374
|
-
this.app.debugLog(`[${this.name}] Task ${id} error:`, error);
|
|
375
|
-
}
|
|
376
|
-
}, intervalMs);
|
|
377
|
-
|
|
378
|
-
this.tasks.set(id, { id, callback, interval: intervalMs, timer });
|
|
379
|
-
this.app.debugLog(`[${this.name}] Task ${id} scheduled every ${intervalMs}ms`);
|
|
380
|
-
}
|
|
381
|
-
|
|
382
|
-
public removeTask(id: string): boolean {
|
|
383
|
-
const task = this.tasks.get(id);
|
|
384
|
-
if (!task) return false;
|
|
385
|
-
|
|
386
|
-
if (task.timer) {
|
|
387
|
-
clearInterval(task.timer);
|
|
388
|
-
}
|
|
389
|
-
this.tasks.delete(id);
|
|
390
|
-
return true;
|
|
391
|
-
}
|
|
392
|
-
|
|
393
|
-
public async run(): Promise<void> {
|
|
394
|
-
// Пример: добавление задачи при запуске
|
|
395
|
-
// this.addTask('example', async () => {
|
|
396
|
-
// console.log('Scheduled task executed');
|
|
397
|
-
// }, 60000);
|
|
398
|
-
}
|
|
399
|
-
}
|
|
400
|
-
```
|
|
401
|
-
|
|
402
|
-
## Best Practices
|
|
403
|
-
|
|
404
|
-
### 1. Именование
|
|
405
|
-
- ✅ Используйте описательные имена: `EmailService`, `PaymentAPIService`
|
|
406
|
-
- ❌ Избегайте общих имен: `Service1`, `Helper`
|
|
407
|
-
|
|
408
|
-
### 2. Ответственность
|
|
409
|
-
- ✅ Один сервис - одна ответственность
|
|
410
|
-
- ❌ Не создавайте "God Objects"
|
|
411
|
-
|
|
412
|
-
### 3. Зависимости
|
|
413
|
-
- ✅ Инжектите зависимости через конструктор
|
|
414
|
-
- ✅ Используйте другие сервисы через `app.getService()`
|
|
415
|
-
- ❌ Не создавайте жесткие связи
|
|
416
|
-
|
|
417
|
-
### 4. Обработка ошибок
|
|
418
|
-
```typescript
|
|
419
|
-
public async setup(): Promise<void> {
|
|
420
|
-
try {
|
|
421
|
-
// Инициализация
|
|
422
|
-
} catch (error) {
|
|
423
|
-
this.app.debugLog(`[${this.name}] Setup failed:`, error);
|
|
424
|
-
throw error; // Пробросить для остановки бота
|
|
425
|
-
}
|
|
426
|
-
}
|
|
427
|
-
```
|
|
428
|
-
|
|
429
|
-
### 5. Логирование
|
|
430
|
-
```typescript
|
|
431
|
-
this.app.debugLog(`[${this.name}] Important action`);
|
|
432
|
-
```
|
|
433
|
-
|
|
434
|
-
## Жизненный цикл
|
|
435
|
-
|
|
436
|
-
```
|
|
437
|
-
Bot Start
|
|
438
|
-
↓
|
|
439
|
-
Load Services from workflow/services/
|
|
440
|
-
↓
|
|
441
|
-
new Service(app, name)
|
|
442
|
-
↓
|
|
443
|
-
service.setup()
|
|
444
|
-
↓
|
|
445
|
-
service.run()
|
|
446
|
-
↓
|
|
447
|
-
[Service is active]
|
|
448
|
-
↓
|
|
449
|
-
Bot Stop
|
|
450
|
-
↓
|
|
451
|
-
service.unsetup()
|
|
452
|
-
↓
|
|
453
|
-
Service destroyed
|
|
454
|
-
```
|
|
455
|
-
|
|
456
|
-
## Отладка
|
|
457
|
-
|
|
458
|
-
### Включить debug логи
|
|
459
|
-
|
|
460
|
-
```typescript
|
|
461
|
-
const app = new App({
|
|
462
|
-
debug: true,
|
|
463
|
-
// ...
|
|
464
|
-
});
|
|
465
|
-
```
|
|
466
|
-
|
|
467
|
-
### Проверить загруженные сервисы
|
|
468
|
-
|
|
469
|
-
```typescript
|
|
470
|
-
// В коде
|
|
471
|
-
const services = app.getAllServices();
|
|
472
|
-
console.log('Loaded services:', Array.from(services.keys()));
|
|
473
|
-
```
|
|
474
|
-
|
|
475
|
-
### Логи при загрузке
|
|
476
|
-
|
|
477
|
-
```
|
|
478
|
-
[App] Registered API services: [ 'PaymentAPIService', 'CacheService', 'LoggerService' ]
|
|
479
|
-
[PaymentAPIService] Service setup completed
|
|
480
|
-
[CacheService] Service setup completed
|
|
481
|
-
[LoggerService] Service setup completed
|
|
482
|
-
```
|
|
483
|
-
|
|
484
|
-
## Troubleshooting
|
|
485
|
-
|
|
486
|
-
### Сервис не загружается
|
|
487
|
-
|
|
488
|
-
**Проверьте:**
|
|
489
|
-
1. Файл находится в `workflow/services/`
|
|
490
|
-
2. Файл экспортирует класс как `export default`
|
|
491
|
-
3. Класс наследуется от `ApiService`
|
|
492
|
-
4. Нет ошибок в конструкторе
|
|
493
|
-
|
|
494
|
-
### Ошибка при setup()
|
|
495
|
-
|
|
496
|
-
```
|
|
497
|
-
Error: Service setup failed
|
|
498
|
-
```
|
|
499
|
-
|
|
500
|
-
**Решение:**
|
|
501
|
-
- Проверьте логи в консоли
|
|
502
|
-
- Добавьте try-catch в setup()
|
|
503
|
-
- Проверьте доступность внешних ресурсов
|
|
504
|
-
|
|
505
|
-
### Сервис недоступен из секций
|
|
506
|
-
|
|
507
|
-
```typescript
|
|
508
|
-
const service = this.app.getService('ServiceName');
|
|
509
|
-
if (!service) {
|
|
510
|
-
console.error('Service not found!');
|
|
511
|
-
}
|
|
512
|
-
```
|
|
513
|
-
|
|
514
|
-
**Решение:**
|
|
515
|
-
- Проверьте имя сервиса (case-sensitive)
|
|
516
|
-
- Убедитесь что сервис загружен
|
|
517
|
-
- Проверьте `app.getAllServices()`
|
|
518
|
-
|
|
519
|
-
## Дополнительные команды
|
|
520
|
-
|
|
521
|
-
```bash
|
|
522
|
-
# Создать секцию
|
|
523
|
-
2byte generate section Settings
|
|
524
|
-
|
|
525
|
-
# Создать миграцию
|
|
526
|
-
2byte generate migration create_users_table
|
|
527
|
-
|
|
528
|
-
# Показать помощь
|
|
529
|
-
2byte generate --help
|
|
530
|
-
```
|
|
531
|
-
|
|
532
|
-
## См. также
|
|
533
|
-
|
|
534
|
-
- [API Reference - ApiService](../API_SERVICE.md)
|
|
535
|
-
- [Architecture - Services](../ARCHITECTURE.md#services)
|
|
536
|
-
- [Examples - Service Patterns](../examples/services/)
|
|
1
|
+
# Service Generator - CLI Documentation
|
|
2
|
+
|
|
3
|
+
## Описание
|
|
4
|
+
|
|
5
|
+
Генератор для создания API сервисов в 2byte Telegram Bot Framework. Сервисы - это переиспользуемые компоненты, которые предоставляют функциональность для всего бота.
|
|
6
|
+
|
|
7
|
+
## Использование
|
|
8
|
+
|
|
9
|
+
### Базовая команда
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
2byte generate service <name>
|
|
13
|
+
# или короткая форма
|
|
14
|
+
2byte g service <name>
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
### Примеры
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
# Создать сервис для работы с API
|
|
21
|
+
2byte generate service PaymentAPI
|
|
22
|
+
|
|
23
|
+
# Создать сервис для уведомлений
|
|
24
|
+
2byte g service Notification
|
|
25
|
+
|
|
26
|
+
# Создать сервис для кеширования
|
|
27
|
+
2byte g service Cache
|
|
28
|
+
|
|
29
|
+
# Создать сервис для логирования
|
|
30
|
+
2byte g service Logger
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Что создается
|
|
34
|
+
|
|
35
|
+
### Структура файла
|
|
36
|
+
|
|
37
|
+
Генератор создает файл в директории `workflow/services/`:
|
|
38
|
+
|
|
39
|
+
```
|
|
40
|
+
your-bot/
|
|
41
|
+
├── workflow/
|
|
42
|
+
│ └── services/
|
|
43
|
+
│ ├── PaymentAPIService.ts ← новый файл
|
|
44
|
+
│ ├── NotificationService.ts
|
|
45
|
+
│ └── ...
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### Имя файла
|
|
49
|
+
|
|
50
|
+
- Автоматически добавляется суффикс `Service` если его нет
|
|
51
|
+
- Используется PascalCase форматирование
|
|
52
|
+
|
|
53
|
+
**Примеры:**
|
|
54
|
+
- `payment` → `PaymentService.ts`
|
|
55
|
+
- `PaymentAPI` → `PaymentAPIService.ts`
|
|
56
|
+
- `notification-sender` → `Notification-senderService.ts` (лучше использовать camelCase)
|
|
57
|
+
|
|
58
|
+
## Структура сервиса
|
|
59
|
+
|
|
60
|
+
Сгенерированный сервис содержит:
|
|
61
|
+
|
|
62
|
+
```typescript
|
|
63
|
+
import { App } from "@2byte/tgbot-framework";
|
|
64
|
+
import { ApiService } from "@2byte/tgbot-framework";
|
|
65
|
+
|
|
66
|
+
export default class PaymentAPIService extends ApiService {
|
|
67
|
+
|
|
68
|
+
constructor(
|
|
69
|
+
protected app: App,
|
|
70
|
+
public name: string = "PaymentAPIService"
|
|
71
|
+
) {
|
|
72
|
+
super(app, name);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
public async setup(): Promise<void> {
|
|
76
|
+
// Инициализация при запуске
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
public async unsetup(): Promise<void> {
|
|
80
|
+
// Очистка при остановке
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
public async run(): Promise<void> {
|
|
84
|
+
// Основная логика сервиса
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
## Методы сервиса
|
|
90
|
+
|
|
91
|
+
### `setup()`
|
|
92
|
+
|
|
93
|
+
Вызывается при регистрации сервиса во время запуска бота.
|
|
94
|
+
|
|
95
|
+
**Используйте для:**
|
|
96
|
+
- Инициализации подключений к БД
|
|
97
|
+
- Загрузки конфигураций
|
|
98
|
+
- Настройки HTTP клиентов
|
|
99
|
+
- Подписки на события
|
|
100
|
+
|
|
101
|
+
**Пример:**
|
|
102
|
+
```typescript
|
|
103
|
+
public async setup(): Promise<void> {
|
|
104
|
+
this.apiClient = axios.create({
|
|
105
|
+
baseURL: 'https://api.example.com',
|
|
106
|
+
timeout: 5000
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
this.app.debugLog(`[${this.name}] API client initialized`);
|
|
110
|
+
}
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
### `unsetup()`
|
|
114
|
+
|
|
115
|
+
Вызывается при остановке бота или выгрузке сервиса.
|
|
116
|
+
|
|
117
|
+
**Используйте для:**
|
|
118
|
+
- Закрытия подключений
|
|
119
|
+
- Сохранения состояния
|
|
120
|
+
- Отписки от событий
|
|
121
|
+
- Освобождения ресурсов
|
|
122
|
+
|
|
123
|
+
**Пример:**
|
|
124
|
+
```typescript
|
|
125
|
+
public async unsetup(): Promise<void> {
|
|
126
|
+
await this.apiClient?.disconnect();
|
|
127
|
+
this.app.debugLog(`[${this.name}] Cleanup completed`);
|
|
128
|
+
}
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
### `run()`
|
|
132
|
+
|
|
133
|
+
Основной метод для логики сервиса.
|
|
134
|
+
|
|
135
|
+
**Используйте для:**
|
|
136
|
+
- Запуска фоновых задач
|
|
137
|
+
- Периодических операций
|
|
138
|
+
- Обработки очередей
|
|
139
|
+
- Любой основной логики
|
|
140
|
+
|
|
141
|
+
**Пример:**
|
|
142
|
+
```typescript
|
|
143
|
+
public async run(): Promise<void> {
|
|
144
|
+
// Запуск периодической задачи
|
|
145
|
+
setInterval(async () => {
|
|
146
|
+
await this.checkPayments();
|
|
147
|
+
}, 60000); // каждую минуту
|
|
148
|
+
}
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
## Автоматическая загрузка
|
|
152
|
+
|
|
153
|
+
Сервисы автоматически загружаются из директории `workflow/services/` при запуске бота.
|
|
154
|
+
|
|
155
|
+
**Процесс:**
|
|
156
|
+
1. Бот сканирует `workflow/services/`
|
|
157
|
+
2. Импортирует все `.ts` файлы
|
|
158
|
+
3. Создает экземпляры сервисов
|
|
159
|
+
4. Вызывает `setup()` для каждого
|
|
160
|
+
5. Регистрирует в `ApiServiceManager`
|
|
161
|
+
|
|
162
|
+
## Использование сервисов
|
|
163
|
+
|
|
164
|
+
### Из секций
|
|
165
|
+
|
|
166
|
+
```typescript
|
|
167
|
+
// В любой секции
|
|
168
|
+
export default class HomeSection extends Section {
|
|
169
|
+
async index() {
|
|
170
|
+
// Получить сервис
|
|
171
|
+
const paymentService = this.app.getService('PaymentAPIService');
|
|
172
|
+
|
|
173
|
+
// Использовать
|
|
174
|
+
const result = await paymentService.processPayment(100);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
### Из других сервисов
|
|
180
|
+
|
|
181
|
+
```typescript
|
|
182
|
+
export default class NotificationService extends ApiService {
|
|
183
|
+
public async sendNotification(userId: number, message: string) {
|
|
184
|
+
// Получить другой сервис
|
|
185
|
+
const logger = this.app.getService('LoggerService');
|
|
186
|
+
logger.log(`Sending notification to ${userId}`);
|
|
187
|
+
|
|
188
|
+
// Ваша логика
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
### Из App
|
|
194
|
+
|
|
195
|
+
```typescript
|
|
196
|
+
const app = new App(config);
|
|
197
|
+
|
|
198
|
+
// После инициализации
|
|
199
|
+
const service = app.getService('PaymentAPIService');
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
## Примеры сервисов
|
|
203
|
+
|
|
204
|
+
### 1. API клиент
|
|
205
|
+
|
|
206
|
+
```typescript
|
|
207
|
+
import { App, ApiService } from "@2byte/tgbot-framework";
|
|
208
|
+
import axios, { AxiosInstance } from 'axios';
|
|
209
|
+
|
|
210
|
+
export default class PaymentAPIService extends ApiService {
|
|
211
|
+
private client: AxiosInstance;
|
|
212
|
+
|
|
213
|
+
constructor(protected app: App, public name: string = "PaymentAPIService") {
|
|
214
|
+
super(app, name);
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
public async setup(): Promise<void> {
|
|
218
|
+
this.client = axios.create({
|
|
219
|
+
baseURL: process.env.PAYMENT_API_URL,
|
|
220
|
+
headers: {
|
|
221
|
+
'Authorization': `Bearer ${process.env.PAYMENT_API_KEY}`
|
|
222
|
+
}
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
public async createPayment(amount: number, userId: number) {
|
|
227
|
+
const response = await this.client.post('/payments', {
|
|
228
|
+
amount,
|
|
229
|
+
userId,
|
|
230
|
+
currency: 'USD'
|
|
231
|
+
});
|
|
232
|
+
return response.data;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
public async checkPaymentStatus(paymentId: string) {
|
|
236
|
+
const response = await this.client.get(`/payments/${paymentId}`);
|
|
237
|
+
return response.data;
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
### 2. Кеш сервис
|
|
243
|
+
|
|
244
|
+
```typescript
|
|
245
|
+
import { App, ApiService } from "@2byte/tgbot-framework";
|
|
246
|
+
|
|
247
|
+
export default class CacheService extends ApiService {
|
|
248
|
+
private cache: Map<string, any> = new Map();
|
|
249
|
+
private ttl: Map<string, number> = new Map();
|
|
250
|
+
|
|
251
|
+
constructor(protected app: App, public name: string = "CacheService") {
|
|
252
|
+
super(app, name);
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
public async setup(): Promise<void> {
|
|
256
|
+
// Очистка истекших записей каждые 5 минут
|
|
257
|
+
setInterval(() => this.cleanExpired(), 5 * 60 * 1000);
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
public set(key: string, value: any, ttlSeconds: number = 3600): void {
|
|
261
|
+
this.cache.set(key, value);
|
|
262
|
+
this.ttl.set(key, Date.now() + ttlSeconds * 1000);
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
public get(key: string): any | null {
|
|
266
|
+
if (!this.cache.has(key)) return null;
|
|
267
|
+
|
|
268
|
+
const expiry = this.ttl.get(key);
|
|
269
|
+
if (expiry && expiry < Date.now()) {
|
|
270
|
+
this.cache.delete(key);
|
|
271
|
+
this.ttl.delete(key);
|
|
272
|
+
return null;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
return this.cache.get(key);
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
private cleanExpired(): void {
|
|
279
|
+
const now = Date.now();
|
|
280
|
+
for (const [key, expiry] of this.ttl.entries()) {
|
|
281
|
+
if (expiry < now) {
|
|
282
|
+
this.cache.delete(key);
|
|
283
|
+
this.ttl.delete(key);
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
### 3. Логгер сервис
|
|
291
|
+
|
|
292
|
+
```typescript
|
|
293
|
+
import { App, ApiService } from "@2byte/tgbot-framework";
|
|
294
|
+
import * as fs from 'fs-extra';
|
|
295
|
+
import * as path from 'path';
|
|
296
|
+
|
|
297
|
+
export default class LoggerService extends ApiService {
|
|
298
|
+
private logPath: string;
|
|
299
|
+
|
|
300
|
+
constructor(protected app: App, public name: string = "LoggerService") {
|
|
301
|
+
super(app, name);
|
|
302
|
+
this.logPath = path.join(process.cwd(), 'logs');
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
public async setup(): Promise<void> {
|
|
306
|
+
await fs.ensureDir(this.logPath);
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
public async log(message: string, level: 'info' | 'error' | 'warn' = 'info'): Promise<void> {
|
|
310
|
+
const timestamp = new Date().toISOString();
|
|
311
|
+
const logMessage = `[${timestamp}] [${level.toUpperCase()}] ${message}\n`;
|
|
312
|
+
|
|
313
|
+
const filename = `${new Date().toISOString().split('T')[0]}.log`;
|
|
314
|
+
const filepath = path.join(this.logPath, filename);
|
|
315
|
+
|
|
316
|
+
await fs.appendFile(filepath, logMessage);
|
|
317
|
+
|
|
318
|
+
// Также выводим в консоль
|
|
319
|
+
console.log(logMessage);
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
public async error(message: string): Promise<void> {
|
|
323
|
+
await this.log(message, 'error');
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
public async warn(message: string): Promise<void> {
|
|
327
|
+
await this.log(message, 'warn');
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
### 4. Планировщик задач
|
|
333
|
+
|
|
334
|
+
```typescript
|
|
335
|
+
import { App, ApiService } from "@2byte/tgbot-framework";
|
|
336
|
+
|
|
337
|
+
interface ScheduledTask {
|
|
338
|
+
id: string;
|
|
339
|
+
callback: () => Promise<void>;
|
|
340
|
+
interval: number;
|
|
341
|
+
timer?: NodeJS.Timeout;
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
export default class SchedulerService extends ApiService {
|
|
345
|
+
private tasks: Map<string, ScheduledTask> = new Map();
|
|
346
|
+
|
|
347
|
+
constructor(protected app: App, public name: string = "SchedulerService") {
|
|
348
|
+
super(app, name);
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
public async setup(): Promise<void> {
|
|
352
|
+
this.app.debugLog(`[${this.name}] Scheduler ready`);
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
public async unsetup(): Promise<void> {
|
|
356
|
+
// Останавливаем все задачи
|
|
357
|
+
for (const task of this.tasks.values()) {
|
|
358
|
+
if (task.timer) {
|
|
359
|
+
clearInterval(task.timer);
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
this.tasks.clear();
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
public addTask(id: string, callback: () => Promise<void>, intervalMs: number): void {
|
|
366
|
+
if (this.tasks.has(id)) {
|
|
367
|
+
throw new Error(`Task ${id} already exists`);
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
const timer = setInterval(async () => {
|
|
371
|
+
try {
|
|
372
|
+
await callback();
|
|
373
|
+
} catch (error) {
|
|
374
|
+
this.app.debugLog(`[${this.name}] Task ${id} error:`, error);
|
|
375
|
+
}
|
|
376
|
+
}, intervalMs);
|
|
377
|
+
|
|
378
|
+
this.tasks.set(id, { id, callback, interval: intervalMs, timer });
|
|
379
|
+
this.app.debugLog(`[${this.name}] Task ${id} scheduled every ${intervalMs}ms`);
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
public removeTask(id: string): boolean {
|
|
383
|
+
const task = this.tasks.get(id);
|
|
384
|
+
if (!task) return false;
|
|
385
|
+
|
|
386
|
+
if (task.timer) {
|
|
387
|
+
clearInterval(task.timer);
|
|
388
|
+
}
|
|
389
|
+
this.tasks.delete(id);
|
|
390
|
+
return true;
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
public async run(): Promise<void> {
|
|
394
|
+
// Пример: добавление задачи при запуске
|
|
395
|
+
// this.addTask('example', async () => {
|
|
396
|
+
// console.log('Scheduled task executed');
|
|
397
|
+
// }, 60000);
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
```
|
|
401
|
+
|
|
402
|
+
## Best Practices
|
|
403
|
+
|
|
404
|
+
### 1. Именование
|
|
405
|
+
- ✅ Используйте описательные имена: `EmailService`, `PaymentAPIService`
|
|
406
|
+
- ❌ Избегайте общих имен: `Service1`, `Helper`
|
|
407
|
+
|
|
408
|
+
### 2. Ответственность
|
|
409
|
+
- ✅ Один сервис - одна ответственность
|
|
410
|
+
- ❌ Не создавайте "God Objects"
|
|
411
|
+
|
|
412
|
+
### 3. Зависимости
|
|
413
|
+
- ✅ Инжектите зависимости через конструктор
|
|
414
|
+
- ✅ Используйте другие сервисы через `app.getService()`
|
|
415
|
+
- ❌ Не создавайте жесткие связи
|
|
416
|
+
|
|
417
|
+
### 4. Обработка ошибок
|
|
418
|
+
```typescript
|
|
419
|
+
public async setup(): Promise<void> {
|
|
420
|
+
try {
|
|
421
|
+
// Инициализация
|
|
422
|
+
} catch (error) {
|
|
423
|
+
this.app.debugLog(`[${this.name}] Setup failed:`, error);
|
|
424
|
+
throw error; // Пробросить для остановки бота
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
```
|
|
428
|
+
|
|
429
|
+
### 5. Логирование
|
|
430
|
+
```typescript
|
|
431
|
+
this.app.debugLog(`[${this.name}] Important action`);
|
|
432
|
+
```
|
|
433
|
+
|
|
434
|
+
## Жизненный цикл
|
|
435
|
+
|
|
436
|
+
```
|
|
437
|
+
Bot Start
|
|
438
|
+
↓
|
|
439
|
+
Load Services from workflow/services/
|
|
440
|
+
↓
|
|
441
|
+
new Service(app, name)
|
|
442
|
+
↓
|
|
443
|
+
service.setup()
|
|
444
|
+
↓
|
|
445
|
+
service.run()
|
|
446
|
+
↓
|
|
447
|
+
[Service is active]
|
|
448
|
+
↓
|
|
449
|
+
Bot Stop
|
|
450
|
+
↓
|
|
451
|
+
service.unsetup()
|
|
452
|
+
↓
|
|
453
|
+
Service destroyed
|
|
454
|
+
```
|
|
455
|
+
|
|
456
|
+
## Отладка
|
|
457
|
+
|
|
458
|
+
### Включить debug логи
|
|
459
|
+
|
|
460
|
+
```typescript
|
|
461
|
+
const app = new App({
|
|
462
|
+
debug: true,
|
|
463
|
+
// ...
|
|
464
|
+
});
|
|
465
|
+
```
|
|
466
|
+
|
|
467
|
+
### Проверить загруженные сервисы
|
|
468
|
+
|
|
469
|
+
```typescript
|
|
470
|
+
// В коде
|
|
471
|
+
const services = app.getAllServices();
|
|
472
|
+
console.log('Loaded services:', Array.from(services.keys()));
|
|
473
|
+
```
|
|
474
|
+
|
|
475
|
+
### Логи при загрузке
|
|
476
|
+
|
|
477
|
+
```
|
|
478
|
+
[App] Registered API services: [ 'PaymentAPIService', 'CacheService', 'LoggerService' ]
|
|
479
|
+
[PaymentAPIService] Service setup completed
|
|
480
|
+
[CacheService] Service setup completed
|
|
481
|
+
[LoggerService] Service setup completed
|
|
482
|
+
```
|
|
483
|
+
|
|
484
|
+
## Troubleshooting
|
|
485
|
+
|
|
486
|
+
### Сервис не загружается
|
|
487
|
+
|
|
488
|
+
**Проверьте:**
|
|
489
|
+
1. Файл находится в `workflow/services/`
|
|
490
|
+
2. Файл экспортирует класс как `export default`
|
|
491
|
+
3. Класс наследуется от `ApiService`
|
|
492
|
+
4. Нет ошибок в конструкторе
|
|
493
|
+
|
|
494
|
+
### Ошибка при setup()
|
|
495
|
+
|
|
496
|
+
```
|
|
497
|
+
Error: Service setup failed
|
|
498
|
+
```
|
|
499
|
+
|
|
500
|
+
**Решение:**
|
|
501
|
+
- Проверьте логи в консоли
|
|
502
|
+
- Добавьте try-catch в setup()
|
|
503
|
+
- Проверьте доступность внешних ресурсов
|
|
504
|
+
|
|
505
|
+
### Сервис недоступен из секций
|
|
506
|
+
|
|
507
|
+
```typescript
|
|
508
|
+
const service = this.app.getService('ServiceName');
|
|
509
|
+
if (!service) {
|
|
510
|
+
console.error('Service not found!');
|
|
511
|
+
}
|
|
512
|
+
```
|
|
513
|
+
|
|
514
|
+
**Решение:**
|
|
515
|
+
- Проверьте имя сервиса (case-sensitive)
|
|
516
|
+
- Убедитесь что сервис загружен
|
|
517
|
+
- Проверьте `app.getAllServices()`
|
|
518
|
+
|
|
519
|
+
## Дополнительные команды
|
|
520
|
+
|
|
521
|
+
```bash
|
|
522
|
+
# Создать секцию
|
|
523
|
+
2byte generate section Settings
|
|
524
|
+
|
|
525
|
+
# Создать миграцию
|
|
526
|
+
2byte generate migration create_users_table
|
|
527
|
+
|
|
528
|
+
# Показать помощь
|
|
529
|
+
2byte generate --help
|
|
530
|
+
```
|
|
531
|
+
|
|
532
|
+
## См. также
|
|
533
|
+
|
|
534
|
+
- [API Reference - ApiService](../API_SERVICE.md)
|
|
535
|
+
- [Architecture - Services](../ARCHITECTURE.md#services)
|
|
536
|
+
- [Examples - Service Patterns](../examples/services/)
|