evogram-gramjs 1.1.0 → 1.1.1

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 (62) hide show
  1. package/lib/EvogramGramJS.d.ts +51 -0
  2. package/lib/EvogramGramJS.js +99 -0
  3. package/lib/commands/Accounts.command.d.ts +6 -0
  4. package/lib/commands/Accounts.command.js +95 -0
  5. package/lib/commands/AddAccount.command.d.ts +19 -0
  6. package/lib/commands/AddAccount.command.js +461 -0
  7. package/lib/commands/index.d.ts +2 -0
  8. package/lib/commands/index.js +5 -0
  9. package/lib/commands/managment/DeleteAccount.command.d.ts +0 -0
  10. package/{src/commands/managment/DeleteAccount.command.ts → lib/commands/managment/DeleteAccount.command.js} +1 -2
  11. package/lib/config/database.config.d.ts +26 -0
  12. package/lib/config/database.config.js +31 -0
  13. package/lib/entities/Session.entity.d.ts +28 -0
  14. package/lib/entities/Session.entity.js +71 -0
  15. package/lib/entities/SessionEventLog.entity.d.ts +22 -0
  16. package/lib/entities/SessionEventLog.entity.js +50 -0
  17. package/lib/examples/auth.example.d.ts +10 -0
  18. package/lib/examples/auth.example.js +126 -0
  19. package/lib/examples/database.example.d.ts +13 -0
  20. package/lib/examples/database.example.js +109 -0
  21. package/lib/examples/usage.example.d.ts +13 -0
  22. package/lib/examples/usage.example.js +127 -0
  23. package/lib/index.d.ts +7 -0
  24. package/lib/index.js +10 -0
  25. package/lib/services/DatabaseService.d.ts +30 -0
  26. package/lib/services/DatabaseService.js +93 -0
  27. package/lib/services/ImageUploadService.d.ts +15 -0
  28. package/lib/services/ImageUploadService.js +56 -0
  29. package/lib/sessions/Session.d.ts +13 -0
  30. package/lib/sessions/Session.js +25 -0
  31. package/lib/sessions/SessionAuth.d.ts +72 -0
  32. package/lib/sessions/SessionAuth.js +327 -0
  33. package/lib/sessions/SessionLogger.d.ts +84 -0
  34. package/lib/sessions/SessionLogger.js +196 -0
  35. package/lib/sessions/SessionManager.d.ts +84 -0
  36. package/lib/sessions/SessionManager.js +198 -0
  37. package/lib/test.d.ts +1 -0
  38. package/lib/test.js +144 -0
  39. package/lib/types/auth.types.d.ts +90 -0
  40. package/lib/types/auth.types.js +19 -0
  41. package/lib/types/session.types.d.ts +87 -0
  42. package/lib/types/session.types.js +21 -0
  43. package/lib/utils/Deferrer.d.ts +6 -0
  44. package/lib/utils/Deferrer.js +14 -0
  45. package/package.json +1 -2
  46. package/src/EvogramGramJS.ts +0 -98
  47. package/src/commands/Accounts.command.ts +0 -89
  48. package/src/commands/AddAccount.command.ts +0 -449
  49. package/src/commands/index.ts +0 -2
  50. package/src/config/database.config.ts +0 -75
  51. package/src/entities/Session.entity.ts +0 -58
  52. package/src/entities/SessionEventLog.entity.ts +0 -41
  53. package/src/index.ts +0 -7
  54. package/src/services/DatabaseService.ts +0 -82
  55. package/src/services/ImageUploadService.ts +0 -49
  56. package/src/sessions/Session.ts +0 -21
  57. package/src/sessions/SessionAuth.ts +0 -356
  58. package/src/sessions/SessionLogger.ts +0 -208
  59. package/src/sessions/SessionManager.ts +0 -211
  60. package/src/types/auth.types.ts +0 -94
  61. package/src/types/session.types.ts +0 -96
  62. package/src/utils/Deferrer.ts +0 -12
@@ -1,82 +0,0 @@
1
- import { DataSource, Repository } from 'typeorm'
2
- import { DatabaseConfig, createDataSourceOptions } from '../config/database.config'
3
- import { Session as SessionEntity } from '../entities/Session.entity'
4
- import { SessionEventLog } from '../entities/SessionEventLog.entity'
5
-
6
- /**
7
- * Сервис для работы с базой данных
8
- * Управляет сохранением и загрузкой сессий и их событий
9
- */
10
- export class DatabaseService {
11
- private dataSource!: DataSource
12
- private sessionRepository!: Repository<SessionEntity>
13
- private eventLogRepository!: Repository<SessionEventLog>
14
- private isInitialized: boolean = false
15
-
16
- /**
17
- * Инициализирует подключение к базе данных
18
- *
19
- * @param config Конфигурация базы данных
20
- */
21
- async initialize(config: DatabaseConfig = {}): Promise<void> {
22
- if (this.isInitialized) return
23
-
24
- const options = createDataSourceOptions(config)
25
- this.dataSource = new DataSource(options)
26
-
27
- try {
28
- await this.dataSource.initialize()
29
- this.sessionRepository = this.dataSource.getRepository(SessionEntity)
30
- this.eventLogRepository = this.dataSource.getRepository(SessionEventLog)
31
- this.isInitialized = true
32
- } catch (error) {
33
- console.error('Ошибка инициализации базы данных:', error)
34
- throw error
35
- }
36
- }
37
-
38
- async saveSession(session: Partial<SessionEntity>) {
39
- if (!this.isReady()) throw new Error('База данных не инициализирована')
40
-
41
- const existingSession = await this.sessionRepository.findOne({ where: { sessionId: session.sessionId } })
42
-
43
- if (existingSession) await this.sessionRepository.update({ sessionId: existingSession.sessionId }, session)
44
- else await this.sessionRepository.save(session)
45
-
46
- return this.getSession(session.sessionId!)
47
- }
48
-
49
- async updateSession(sessionId: string, session: Partial<SessionEntity>) {
50
- if (!this.isReady()) throw new Error('База данных не инициализирована')
51
- await this.sessionRepository.update({ sessionId }, session)
52
-
53
- return this.getSession(sessionId)
54
- }
55
-
56
- async getSession(sessionId: string) {
57
- if (!this.isReady()) throw new Error('База данных не инициализирована')
58
- return await this.sessionRepository.findOne({ where: { sessionId } })
59
- }
60
-
61
- async getSessions() {
62
- if (!this.isReady()) throw new Error('База данных не инициализирована')
63
- return await this.sessionRepository.find({ order: { createdAt: 'DESC' } })
64
- }
65
-
66
- /**
67
- * Закрывает подключение к базе данных
68
- */
69
- async close(): Promise<void> {
70
- if (this.dataSource && this.dataSource.isInitialized) {
71
- await this.dataSource.destroy()
72
- this.isInitialized = false
73
- }
74
- }
75
-
76
- /**
77
- * Проверяет, инициализирована ли база данных
78
- */
79
- isReady(): boolean {
80
- return this.isInitialized && this.dataSource?.isInitialized
81
- }
82
- }
@@ -1,49 +0,0 @@
1
- import axios from 'axios'
2
- import FormData from 'form-data'
3
-
4
- /**
5
- * Сервис для загрузки изображений на внешние хостинги
6
- */
7
- export class ImageUploadService {
8
- static readonly UPLOAD_URL = 'https://imgbox.vu/uploads'
9
-
10
- /**
11
- * Загружает изображение на imgbox.vu/uploads
12
- *
13
- * @param imageBuffer Буфер изображения
14
- * @param filename Имя файла (опционально)
15
- * @returns Promise с URL загруженного изображения
16
- * @throws Error если загрузка не удалась
17
- */
18
- static async uploadToImgbox(imageBuffer: Buffer, filename?: string): Promise<string> {
19
- try {
20
- const formData = new FormData()
21
- formData.append('file', imageBuffer, {
22
- filename: filename || 'avatar.jpg',
23
- contentType: 'image/jpeg',
24
- })
25
-
26
- const response = await axios.post(this.UPLOAD_URL, formData, {
27
- headers: formData.getHeaders(),
28
- })
29
-
30
- const result = response.data
31
-
32
- // Проверяем формат ответа imgbox.vu
33
- // API может возвращать URL в разных форматах, нужно проверить структуру ответа
34
- if (result.url) {
35
- return result.url
36
- } else if (result.data?.url) {
37
- return result.data.url
38
- } else if (typeof result === 'string' && result.startsWith('http')) {
39
- return result
40
- } else {
41
- // Если формат ответа неизвестен, возвращаем весь ответ как строку для отладки
42
- throw new Error(`Неожиданный формат ответа от imgbox.vu: ${JSON.stringify(result)}`)
43
- }
44
- } catch (error: any) {
45
- const errorMessage = error instanceof Error ? error.message : String(error)
46
- throw new Error(`Ошибка загрузки изображения на imgbox.vu: ${errorMessage}`)
47
- }
48
- }
49
- }
@@ -1,21 +0,0 @@
1
- import { TelegramClient } from 'telegram'
2
- import { EvogramGramJS } from '../EvogramGramJS'
3
- import { SessionAuth } from './SessionAuth'
4
- import { SessionLogger } from './SessionLogger'
5
-
6
- export class Session {
7
- /** Объект авторизации для сессии */
8
- public auth: SessionAuth
9
-
10
- constructor(public readonly sessionId: string, public readonly client: TelegramClient, public readonly logger: SessionLogger | undefined, auth: SessionAuth) {
11
- this.auth = auth
12
- }
13
-
14
- public async db() {
15
- return (await EvogramGramJS.databaseService.getSession(this.sessionId)) ?? null
16
- }
17
-
18
- public async user() {
19
- return await this.client.getMe()
20
- }
21
- }
@@ -1,356 +0,0 @@
1
- import { EventEmitter } from 'events'
2
- import { Api, TelegramClient } from 'telegram'
3
- import { EvogramGramJS } from '../EvogramGramJS'
4
- import { ImageUploadService } from '../services/ImageUploadService'
5
- import { AuthState } from '../types/auth.types'
6
- import { Deferred } from '../utils/Deferrer'
7
- import { SessionLogger } from './SessionLogger'
8
-
9
- /**
10
- * События авторизации для сессии
11
- */
12
- export enum SessionAuthEvent {
13
- /** Начало авторизации */
14
- AUTH_STARTED = 'auth:started',
15
- /** Код отправлен */
16
- CODE_SENT = 'auth:code_sent',
17
- /** Код получен */
18
- CODE_RECEIVED = 'auth:code_received',
19
- /** Требуется пароль */
20
- PASSWORD_REQUIRED = 'auth:password_required',
21
- /** Авторизация успешна */
22
- AUTH_SUCCESS = 'auth:success',
23
- /** Ошибка авторизации */
24
- AUTH_ERROR = 'auth:error',
25
- /** Авторизация отменена */
26
- AUTH_CANCELLED = 'auth:cancelled',
27
- }
28
-
29
- /**
30
- * Класс авторизации для конкретной сессии
31
- * Предоставляет методы авторизации, привязанные к сессии
32
- */
33
- export class SessionAuth extends EventEmitter {
34
- public state: {
35
- code: Deferred<string>
36
- password: Deferred<string>
37
- isRequiredPassword: boolean
38
- stage: AuthState
39
- connect: Deferred<boolean>
40
- } = null as any
41
-
42
- constructor(private readonly sessionId: string, private readonly client: TelegramClient, private readonly logger?: SessionLogger) {
43
- super()
44
- }
45
-
46
- async start(phoneNumber: string) {
47
- if (this.state) throw new Error(`Авторизация для сессии "${this.sessionId}" уже начата`)
48
-
49
- this.state = {
50
- code: new Deferred<string>(),
51
- password: new Deferred<string>(),
52
- isRequiredPassword: false,
53
- stage: AuthState.INITIAL,
54
- connect: new Deferred<boolean>(),
55
- }
56
-
57
- try {
58
- await new Promise(async (res, rej) => {
59
- await this.client
60
- .start({
61
- phoneNumber,
62
- phoneCode: async () => {
63
- res(true)
64
- this.state.stage = AuthState.WAITING_CODE
65
-
66
- const code = await this.state.code.promise
67
- this.state.code = new Deferred<string>()
68
-
69
- return code
70
- },
71
- password: async () => {
72
- this.state.isRequiredPassword = true
73
- this.state.stage = AuthState.WAITING_PASSWORD
74
-
75
- const password = await this.state.password.promise
76
- this.state.password = new Deferred<string>()
77
-
78
- return password
79
- },
80
- onError: (error) => {
81
- this.state.stage = AuthState.ERROR
82
-
83
- this.emit(SessionAuthEvent.AUTH_ERROR, {
84
- sessionId: this.sessionId,
85
- error: error instanceof Error ? error.message : String(error),
86
- })
87
- },
88
- })
89
- .catch(rej)
90
-
91
- try {
92
- const me = await this.client.getMe()
93
- this.state.connect.resolve(true)
94
-
95
- let avatarBuffer = await this.client.downloadProfilePhoto('me'),
96
- avatarUrl
97
- if (avatarBuffer) avatarUrl = await ImageUploadService.uploadToImgbox(Buffer.isBuffer(avatarBuffer) ? avatarBuffer : Buffer.from(avatarBuffer))
98
-
99
- await EvogramGramJS.databaseService.saveSession({
100
- sessionId: this.sessionId,
101
- apiId: this.client.apiId,
102
- apiHash: this.client.apiHash,
103
- userId: Number(me.id),
104
- username: me.username,
105
- firstName: me.firstName,
106
- lastName: me.lastName,
107
- phoneNumber: me.phone,
108
- sessionString: this.client.session.save()!,
109
- avatarUrl,
110
- })
111
- } catch {}
112
- })
113
-
114
- return {
115
- success: true,
116
- }
117
- } catch (error) {
118
- this.emit(SessionAuthEvent.AUTH_ERROR, {
119
- sessionId: this.sessionId,
120
- error: error instanceof Error ? error.message : String(error),
121
- })
122
-
123
- return {
124
- success: false,
125
- error,
126
- }
127
- }
128
- }
129
-
130
- async setCode(code: string) {
131
- if (!this.state) throw new Error(`Авторизация для сессии "${this.sessionId}" не начата`)
132
- const errorPromise = new Promise<Error>((resolve, reject) => {
133
- this.once(SessionAuthEvent.AUTH_ERROR, (data) => data.sessionId === this.sessionId && resolve(data.error))
134
- setTimeout(resolve, 1_000)
135
- })
136
-
137
- this.state.code.resolve(code)
138
- const error = await errorPromise
139
-
140
- return {
141
- success: error ? false : true,
142
- error: error || undefined,
143
- }
144
- }
145
-
146
- async setPassword(password: string) {
147
- if (!this.state) throw new Error(`Авторизация для сессии "${this.sessionId}" не начата`)
148
-
149
- const errorPromise = new Promise<Error>((resolve, reject) => {
150
- this.once(SessionAuthEvent.AUTH_ERROR, (data) => data.sessionId === this.sessionId && resolve(data.error))
151
- setTimeout(resolve, 1_000)
152
- })
153
-
154
- this.state.password.resolve(password)
155
- const error = await errorPromise
156
-
157
- return {
158
- success: error ? false : true,
159
- error: error || undefined,
160
- }
161
- }
162
-
163
- /**
164
- * Начинает авторизацию через QR-код
165
- *
166
- * @param onQRCode Callback для обработки QR-кода (получает URL и токен)
167
- * @returns Promise с результатом авторизации
168
- */
169
- async startWithQRCode(
170
- onQRCode: (qrUrl: string, qrToken: string, expires: number) => Promise<void>
171
- ): Promise<{ success: boolean; error?: any }> {
172
- console.log(`[QR-AUTH] Начало метода startWithQRCode для сессии "${this.sessionId}"`)
173
- console.log(`[QR-AUTH] Текущее состояние state:`, this.state ? 'уже инициализировано' : 'null')
174
-
175
- if (this.state) throw new Error(`Авторизация для сессии "${this.sessionId}" уже начата`)
176
-
177
- console.log(`[QR-AUTH] Инициализация state для сессии "${this.sessionId}"`)
178
- this.state = {
179
- code: new Deferred<string>(),
180
- password: new Deferred<string>(),
181
- isRequiredPassword: false,
182
- stage: AuthState.INITIAL,
183
- connect: new Deferred<boolean>(),
184
- }
185
- console.log(`[QR-AUTH] State успешно инициализирован:`, {
186
- stage: this.state.stage,
187
- isRequiredPassword: this.state.isRequiredPassword,
188
- })
189
-
190
- try {
191
- console.log(`[QR-AUTH] Получение API credentials для клиента`)
192
- const apiCredentials = {
193
- apiId: this.client.apiId,
194
- apiHash: this.client.apiHash,
195
- }
196
- console.log(`[QR-AUTH] API credentials:`, {
197
- apiId: apiCredentials.apiId,
198
- apiHashLength: apiCredentials.apiHash?.length || 0,
199
- })
200
-
201
- console.log(`[QR-AUTH] Смена стадии на WAITING_CODE`)
202
- this.state.stage = AuthState.WAITING_CODE
203
- console.log(`[QR-AUTH] Текущая стадия:`, this.state.stage)
204
-
205
- console.log(`[QR-AUTH] Вызов client.signInUserWithQrCode для сессии "${this.sessionId}"`)
206
- const user = await this.client.signInUserWithQrCode(apiCredentials, {
207
- qrCode: async (qrCode) => {
208
- console.log(`[QR-AUTH] Получен QR-код callback для сессии "${this.sessionId}"`)
209
- console.log(`[QR-AUTH] QR-код объект:`, {
210
- tokenLength: qrCode.token?.length || 0,
211
- expires: qrCode.expires,
212
- expiresDate: new Date(qrCode.expires * 1000).toISOString(),
213
- })
214
-
215
- const qrToken = qrCode.token.toString('base64url')
216
- console.log(`[QR-AUTH] QR token (base64url):`, qrToken)
217
-
218
- const qrUrl = `tg://login?token=${qrToken}`
219
- console.log(`[QR-AUTH] QR URL:`, qrUrl)
220
-
221
- console.log(`[QR-AUTH] Вызов onQRCode callback`)
222
- await onQRCode(qrUrl, qrToken, qrCode.expires)
223
- console.log(`[QR-AUTH] onQRCode callback выполнен успешно`)
224
- },
225
- password: async (hint) => {
226
- console.log(`[QR-AUTH] Запрошен пароль для сессии "${this.sessionId}"`)
227
- console.log(`[QR-AUTH] Password hint:`, hint)
228
-
229
- this.state.isRequiredPassword = true
230
- this.state.stage = AuthState.WAITING_PASSWORD
231
- console.log(`[QR-AUTH] Состояние обновлено:`, {
232
- stage: this.state.stage,
233
- isRequiredPassword: this.state.isRequiredPassword,
234
- })
235
-
236
- console.log(`[QR-AUTH] Ожидание password promise`)
237
- const password = await this.state.password.promise
238
- console.log(`[QR-AUTH] Password получен, длина:`, password?.length || 0)
239
-
240
- this.state.password = new Deferred<string>()
241
- console.log(`[QR-AUTH] Password promise сброшен`)
242
-
243
- return password
244
- },
245
- onError: (error) => {
246
- console.log(`[QR-AUTH] ❌ Ошибка в callback onError для сессии "${this.sessionId}"`)
247
- console.log(`[QR-AUTH] Тип ошибки:`, error?.constructor?.name)
248
- console.log(`[QR-AUTH] Сообщение ошибки:`, error instanceof Error ? error.message : String(error))
249
- console.log(`[QR-AUTH] Stack trace:`, error instanceof Error ? error.stack : 'N/A')
250
-
251
- this.state.stage = AuthState.ERROR
252
- console.log(`[QR-AUTH] Стадия изменена на ERROR`)
253
-
254
- this.emit(SessionAuthEvent.AUTH_ERROR, {
255
- sessionId: this.sessionId,
256
- error: error instanceof Error ? error.message : String(error),
257
- })
258
- console.log(`[QR-AUTH] Событие AUTH_ERROR отправлено`)
259
- },
260
- })
261
-
262
- console.log(`[QR-AUTH] ✅ signInUserWithQrCode завершен для сессии "${this.sessionId}"`)
263
- console.log(`[QR-AUTH] Полученный user объект:`, {
264
- type: user?.constructor?.name,
265
- isApiUser: user instanceof Api.User,
266
- })
267
-
268
- // Проверяем, что это реальный пользователь
269
- if (!(user instanceof Api.User)) {
270
- console.log(`[QR-AUTH] ❌ Неверный тип пользователя:`, user?.constructor?.name)
271
- throw new Error('Получен неверный тип пользователя')
272
- }
273
-
274
- this.state.stage = AuthState.AUTHORIZED
275
- this.state.connect.resolve(true)
276
-
277
- // Сохраняем сессию в базу данных
278
- console.log(`[QR-AUTH] Начало сохранения сессии в БД`)
279
- try {
280
- let avatarBuffer = await this.client.downloadProfilePhoto('me'),
281
- avatarUrl
282
-
283
- if (avatarBuffer) {
284
- console.log(`[QR-AUTH] Загрузка аватара на Imgbox`)
285
- avatarUrl = await ImageUploadService.uploadToImgbox(Buffer.isBuffer(avatarBuffer) ? avatarBuffer : Buffer.from(avatarBuffer)).catch(() => null)
286
- console.log(`[QR-AUTH] Аватар загружен на Imgbox:`, avatarUrl)
287
- } else {
288
- console.log(`[QR-AUTH] Аватар отсутствует, пропускаем загрузку`)
289
- }
290
-
291
- const sessionString = this.client.session.save()
292
-
293
- const sessionData = {
294
- sessionId: this.sessionId,
295
- apiId: this.client.apiId,
296
- apiHash: this.client.apiHash,
297
- userId: Number(user.id),
298
- username: user.username,
299
- firstName: user.firstName,
300
- lastName: user.lastName,
301
- phoneNumber: user.phone,
302
- sessionString: sessionString!,
303
- avatarUrl,
304
- }
305
-
306
- await EvogramGramJS.databaseService.saveSession(sessionData as any)
307
- } catch (saveError) {
308
- console.log(`[QR-AUTH] ⚠️ Ошибка при сохранении сессии в БД:`, {
309
- error: saveError instanceof Error ? saveError.message : String(saveError),
310
- stack: saveError instanceof Error ? saveError.stack : 'N/A',
311
- })
312
- }
313
-
314
- console.log(`[QR-AUTH] Отправка события AUTH_SUCCESS`)
315
- this.emit(SessionAuthEvent.AUTH_SUCCESS, {
316
- sessionId: this.sessionId,
317
- })
318
-
319
- console.log(`[QR-AUTH] ✅ Авторизация через QR-код успешно завершена для сессии "${this.sessionId}"`)
320
- return {
321
- success: true,
322
- }
323
- } catch (error) {
324
- console.log(`[QR-AUTH] ❌ Критическая ошибка в startWithQRCode для сессии "${this.sessionId}"`)
325
- console.log(`[QR-AUTH] Тип ошибки:`, error?.constructor?.name)
326
- console.log(`[QR-AUTH] Сообщение ошибки:`, error instanceof Error ? error.message : String(error))
327
- console.log(`[QR-AUTH] Stack trace:`, error instanceof Error ? error.stack : 'N/A')
328
- console.log(`[QR-AUTH] Полный объект ошибки:`, error)
329
-
330
- this.state.stage = AuthState.ERROR
331
- console.log(`[QR-AUTH] Стадия изменена на ERROR`)
332
-
333
- this.emit(SessionAuthEvent.AUTH_ERROR, {
334
- sessionId: this.sessionId,
335
- error: error instanceof Error ? error.message : String(error),
336
- })
337
- console.log(`[QR-AUTH] Событие AUTH_ERROR отправлено`)
338
-
339
- return {
340
- success: false,
341
- error: error instanceof Error ? error.message : String(error),
342
- }
343
- }
344
- }
345
-
346
- /**
347
- * Проверяет, требуется ли пароль для авторизации
348
- *
349
- * @returns true, если требуется пароль
350
- */
351
- async isRequiredPassword(): Promise<boolean> {
352
- if (this.state?.isRequiredPassword) return true
353
- await new Promise((resolve) => setTimeout(resolve, 1000))
354
- return this.state?.isRequiredPassword ?? false
355
- }
356
- }