itd-sdk-js 1.0.0

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.
@@ -0,0 +1,326 @@
1
+ /**
2
+ * 🚀 QUICK START - Быстрый старт с ITD SDK
3
+ *
4
+ * Этот пример показывает основные возможности SDK с подробными комментариями.
5
+ * Идеально для тех, кто только начинает работать с библиотекой.
6
+ *
7
+ * ПЕРЕД ЗАПУСКОМ:
8
+ * 1. Установите зависимости: npm install
9
+ * 2. Скопируйте .env.example в .env и заполните ITD_ACCESS_TOKEN
10
+ * 3. Создайте файл .cookies и вставьте туда cookies из браузера
11
+ * 4. Запустите: node examples/quick-start.js
12
+ */
13
+
14
+ import { ITDClient } from '../src/client.js';
15
+ import dotenv from 'dotenv';
16
+
17
+ // Загружаем переменные окружения из .env файла
18
+ dotenv.config();
19
+
20
+ async function quickStart() {
21
+ console.log('🚀 === ITD SDK - Quick Start ===\n');
22
+
23
+ // ============================================
24
+ // ШАГ 1: Создание клиента
25
+ // ============================================
26
+ console.log('📦 Шаг 1: Создаю клиент...\n');
27
+
28
+ // Создаем экземпляр клиента
29
+ // Клиент автоматически:
30
+ // - Загружает настройки из .env (ITD_BASE_URL, ITD_USER_AGENT и т.д.)
31
+ // - Загружает cookies из файла .cookies
32
+ // - Настраивает автоматическое обновление токена
33
+ const client = new ITDClient();
34
+
35
+ console.log('✅ Клиент создан\n');
36
+
37
+ // ============================================
38
+ // ШАГ 2: Настройка авторизации
39
+ // ============================================
40
+ console.log('🔐 Шаг 2: Настраиваю авторизацию...\n');
41
+
42
+ // Получаем токен из переменных окружения (.env файл)
43
+ const accessToken = process.env.ITD_ACCESS_TOKEN;
44
+
45
+ if (!accessToken) {
46
+ console.log('❌ ОШИБКА: ITD_ACCESS_TOKEN не найден в .env\n');
47
+ console.log('📋 Как получить токен:');
48
+ console.log('1. Откройте итд.com в браузере и войдите');
49
+ console.log('2. Откройте DevTools (F12) → вкладка Network');
50
+ console.log('3. Найдите запрос POST /api/v1/auth/refresh');
51
+ console.log('4. Откройте Response → скопируйте accessToken');
52
+ console.log('5. Вставьте в .env: ITD_ACCESS_TOKEN=ваш_токен\n');
53
+ return;
54
+ }
55
+
56
+ // Устанавливаем токен в клиент
57
+ // Это нужно для авторизации всех запросов
58
+ client.setAccessToken(accessToken);
59
+
60
+ // Помечаем клиент как авторизованный
61
+ // Это позволяет использовать методы, требующие авторизации
62
+ client.auth.isAuthenticated = true;
63
+
64
+ console.log('✅ Авторизация настроена (токен загружен из .env)\n');
65
+
66
+ // ============================================
67
+ // ШАГ 3: Получение информации о себе
68
+ // ============================================
69
+ console.log('👤 Шаг 3: Получаю информацию о текущем пользователе...\n');
70
+
71
+ // Получаем профиль текущего авторизованного пользователя
72
+ // Этот метод требует авторизации
73
+ const myProfile = await client.getMyProfile();
74
+
75
+ if (myProfile) {
76
+ console.log('✅ Профиль получен:');
77
+ console.log(` Имя: ${myProfile.displayName}`);
78
+ console.log(` Username: @${myProfile.username}`);
79
+ console.log(` Клан (эмодзи): ${myProfile.avatar}`);
80
+ console.log(` Подписчиков: ${myProfile.followersCount || 0}`);
81
+ console.log(` Подписок: ${myProfile.followingCount || 0}`);
82
+ console.log(` Постов: ${myProfile.postsCount || 0}\n`);
83
+ } else {
84
+ console.log('⚠️ Не удалось получить профиль (возможно токен недействителен)\n');
85
+ return;
86
+ }
87
+
88
+ // ============================================
89
+ // ШАГ 4: Получение постов пользователя
90
+ // ============================================
91
+ console.log('📰 Шаг 4: Получаю посты пользователя...\n');
92
+
93
+ // Получаем последние 5 постов пользователя
94
+ // Параметры:
95
+ // - username: имя пользователя (или null для своих постов)
96
+ // - limit: количество постов (по умолчанию 20)
97
+ // - sort: сортировка ('new', 'old', 'popular')
98
+ const username = myProfile.username; // Используем свой username
99
+ const postsResult = await client.getPosts(username, 5, 'new');
100
+
101
+ if (postsResult && postsResult.posts.length > 0) {
102
+ console.log(`✅ Найдено постов: ${postsResult.posts.length}\n`);
103
+
104
+ // Показываем первый пост
105
+ const firstPost = postsResult.posts[0];
106
+ console.log('📝 Первый пост:');
107
+ console.log(` ID: ${firstPost.id}`);
108
+ console.log(` Текст: ${(firstPost.content || 'Без текста').substring(0, 100)}...`);
109
+ console.log(` Лайков: ${firstPost.likesCount || 0}`);
110
+ console.log(` Комментариев: ${firstPost.commentsCount || 0}`);
111
+ console.log(` Просмотров: ${firstPost.viewsCount || 0}`);
112
+ console.log(` Дата: ${new Date(firstPost.createdAt).toLocaleString('ru-RU')}\n`);
113
+
114
+ // Сохраняем ID первого поста для дальнейших примеров
115
+ const postId = firstPost.id;
116
+
117
+ // ============================================
118
+ // ШАГ 5: Лайк поста
119
+ // ============================================
120
+ console.log('❤️ Шаг 5: Ставлю лайк на первый пост...\n');
121
+
122
+ // Ставим лайк на пост
123
+ // Метод возвращает объект с информацией о лайке
124
+ const likeResult = await client.likePost(postId);
125
+
126
+ if (likeResult) {
127
+ console.log(`✅ Лайк поставлен! Всего лайков: ${likeResult.likesCount}\n`);
128
+ } else {
129
+ console.log('⚠️ Не удалось поставить лайк (возможно уже лайкнуто)\n');
130
+ }
131
+
132
+ // ============================================
133
+ // ШАГ 6: Получение комментариев
134
+ // ============================================
135
+ console.log('💬 Шаг 6: Получаю комментарии к посту...\n');
136
+
137
+ // Получаем комментарии к посту
138
+ // Параметры:
139
+ // - postId: ID поста
140
+ // - limit: количество комментариев (по умолчанию 20)
141
+ // - sort: сортировка ('new', 'old', 'popular')
142
+ const commentsResult = await client.getComments(postId, 5, 'new');
143
+
144
+ if (commentsResult && commentsResult.comments.length > 0) {
145
+ console.log(`✅ Найдено комментариев: ${commentsResult.comments.length}\n`);
146
+
147
+ // Показываем первый комментарий
148
+ const firstComment = commentsResult.comments[0];
149
+ console.log('💬 Первый комментарий:');
150
+ console.log(` Автор: @${firstComment.author.username}`);
151
+ console.log(` Текст: ${(firstComment.content || '').substring(0, 80)}...`);
152
+ console.log(` Лайков: ${firstComment.likesCount || 0}\n`);
153
+ } else {
154
+ console.log('📝 Комментариев пока нет\n');
155
+ }
156
+
157
+ // ============================================
158
+ // ШАГ 7: Добавление комментария
159
+ // ============================================
160
+ console.log('✍️ Шаг 7: Добавляю комментарий к посту...\n');
161
+
162
+ // Добавляем комментарий к посту
163
+ // Параметры:
164
+ // - postId: ID поста
165
+ // - text: текст комментария
166
+ // - replyToId: ID комментария для ответа (опционально)
167
+ const commentText = 'Отличный пост! 👍';
168
+ const newComment = await client.addComment(postId, commentText);
169
+
170
+ if (newComment) {
171
+ console.log(`✅ Комментарий добавлен! ID: ${newComment.id}\n`);
172
+ } else {
173
+ console.log('⚠️ Не удалось добавить комментарий\n');
174
+ }
175
+
176
+ } else {
177
+ console.log('📝 Посты не найдены\n');
178
+ }
179
+
180
+ // ============================================
181
+ // ШАГ 8: Получение профиля другого пользователя
182
+ // ============================================
183
+ console.log('🔍 Шаг 8: Получаю профиль другого пользователя...\n');
184
+
185
+ // Получаем профиль другого пользователя (публичная информация)
186
+ // Этот метод НЕ требует авторизации
187
+ const otherUsername = 'nowkie'; // Пример: известный пользователь
188
+ const otherProfile = await client.getUserProfile(otherUsername);
189
+
190
+ if (otherProfile) {
191
+ console.log(`✅ Профиль @${otherUsername}:`);
192
+ console.log(` Имя: ${otherProfile.displayName}`);
193
+ console.log(` Клан: ${otherProfile.avatar}`);
194
+ console.log(` Подписчиков: ${otherProfile.followersCount || 0}`);
195
+ console.log(` Постов: ${otherProfile.postsCount || 0}`);
196
+ console.log(` Верифицирован: ${otherProfile.verified ? '✅' : '❌'}\n`);
197
+ } else {
198
+ console.log(`⚠️ Пользователь @${otherUsername} не найден\n`);
199
+ }
200
+
201
+ // ============================================
202
+ // ШАГ 9: Поиск пользователей
203
+ // ============================================
204
+ console.log('🔎 Шаг 9: Ищу пользователей...\n');
205
+
206
+ // Ищем пользователей по запросу
207
+ // Параметры:
208
+ // - query: поисковый запрос
209
+ // - limit: максимальное количество результатов (по умолчанию 5)
210
+ const searchQuery = 'itd';
211
+ const searchResult = await client.searchUsers(searchQuery, 3);
212
+
213
+ if (searchResult && searchResult.length > 0) {
214
+ console.log(`✅ Найдено пользователей: ${searchResult.length}\n`);
215
+ searchResult.forEach((user, index) => {
216
+ console.log(` ${index + 1}. @${user.username} - ${user.displayName} (${user.followersCount} подписчиков)`);
217
+ });
218
+ console.log();
219
+ } else {
220
+ console.log('📝 Пользователи не найдены\n');
221
+ }
222
+
223
+ // ============================================
224
+ // ШАГ 10: Получение уведомлений
225
+ // ============================================
226
+ console.log('🔔 Шаг 10: Получаю уведомления...\n');
227
+
228
+ // Получаем список уведомлений
229
+ // Параметры:
230
+ // - limit: количество уведомлений (по умолчанию 20)
231
+ // - cursor: курсор для пагинации (опционально)
232
+ const notificationsResult = await client.getNotifications(5);
233
+
234
+ if (notificationsResult && notificationsResult.notifications.length > 0) {
235
+ console.log(`✅ Найдено уведомлений: ${notificationsResult.notifications.length}\n`);
236
+
237
+ // Показываем первое уведомление
238
+ const firstNotification = notificationsResult.notifications[0];
239
+ console.log('🔔 Первое уведомление:');
240
+ console.log(` Тип: ${firstNotification.type || 'N/A'}`);
241
+ console.log(` Прочитано: ${firstNotification.read ? '✅' : '❌'}`);
242
+ console.log(` Дата: ${new Date(firstNotification.createdAt).toLocaleString('ru-RU')}\n`);
243
+ } else {
244
+ console.log('📭 Уведомлений нет\n');
245
+ }
246
+
247
+ // ============================================
248
+ // ШАГ 11: Получение трендовых хэштегов
249
+ // ============================================
250
+ console.log('🏷️ Шаг 11: Получаю трендовые хэштеги...\n');
251
+
252
+ // Получаем трендовые хэштеги
253
+ // Параметры:
254
+ // - limit: количество хэштегов (по умолчанию 10)
255
+ const hashtagsResult = await client.getTrendingHashtags(5);
256
+
257
+ if (hashtagsResult && hashtagsResult.hashtags.length > 0) {
258
+ console.log(`✅ Найдено хэштегов: ${hashtagsResult.hashtags.length}\n`);
259
+ hashtagsResult.hashtags.forEach((hashtag, index) => {
260
+ console.log(` ${index + 1}. #${hashtag.name} - ${hashtag.postsCount} постов`);
261
+ });
262
+ console.log();
263
+ } else {
264
+ console.log('📝 Хэштеги не найдены\n');
265
+ }
266
+
267
+ // ============================================
268
+ // ШАГ 12: Получение популярных постов (лента)
269
+ // ============================================
270
+ console.log('🔥 Шаг 12: Получаю популярные посты...\n');
271
+
272
+ // Получаем популярные посты (публичная лента)
273
+ // Параметры:
274
+ // - limit: количество постов (по умолчанию 20)
275
+ // - cursor: курсор для пагинации (опционально)
276
+ const popularPosts = await client.getFeedPopular(3);
277
+
278
+ if (popularPosts && popularPosts.posts.length > 0) {
279
+ console.log(`✅ Найдено популярных постов: ${popularPosts.posts.length}\n`);
280
+
281
+ // Показываем самый популярный пост
282
+ const topPost = popularPosts.posts[0];
283
+ console.log('🔥 Самый популярный пост:');
284
+ console.log(` Автор: @${topPost.author.username}`);
285
+ console.log(` Лайков: ${topPost.likesCount}`);
286
+ console.log(` Просмотров: ${topPost.viewsCount}`);
287
+ console.log(` Текст: ${(topPost.content || 'Без текста').substring(0, 60)}...\n`);
288
+ } else {
289
+ console.log('📝 Популярные посты не найдены\n');
290
+ }
291
+
292
+ // ============================================
293
+ // ЗАВЕРШЕНИЕ
294
+ // ============================================
295
+ console.log('✅ === Quick Start завершен! ===\n');
296
+ console.log('📚 Что дальше?');
297
+ console.log('1. Изучите API_REFERENCE.md для полного списка методов');
298
+ console.log('2. Посмотрите другие примеры в папке examples/');
299
+ console.log('3. Создайте свой проект используя ITD SDK!\n');
300
+ }
301
+
302
+ // Запускаем quick start
303
+ (async () => {
304
+ try {
305
+ await quickStart();
306
+ } catch (error) {
307
+ console.error('\n❌ ОШИБКА при выполнении:');
308
+ console.error(error.message);
309
+
310
+ // Если есть детали ошибки - показываем их
311
+ if (error.response) {
312
+ console.error('\n📋 Детали ошибки:');
313
+ console.error(` Статус: ${error.response.status}`);
314
+ console.error(` Данные: ${JSON.stringify(error.response.data, null, 2)}`);
315
+ }
316
+
317
+ // Полезные советы при ошибках
318
+ console.error('\n💡 Возможные решения:');
319
+ console.error('1. Проверьте, что ITD_ACCESS_TOKEN указан в .env');
320
+ console.error('2. Проверьте, что файл .cookies существует и содержит refresh_token');
321
+ console.error('3. Обновите токен в .env из браузера (DevTools → Network → /api/v1/auth/refresh)');
322
+ console.error('4. Обновите cookies в .cookies из браузера\n');
323
+
324
+ process.exit(1);
325
+ }
326
+ })();
@@ -0,0 +1,79 @@
1
+ /**
2
+ * ✨ Пример 2: Удобные методы (User-Friendly)
3
+ *
4
+ * Демонстрирует преимущества удобных методов SDK.
5
+ * Показывает, как просто работать с данными без сложных запросов.
6
+ */
7
+
8
+ import { ITDClient } from '../src/client.js';
9
+ import dotenv from 'dotenv';
10
+
11
+ dotenv.config();
12
+
13
+ async function main() {
14
+ console.log('✨ === Удобные методы SDK ===\n');
15
+
16
+ const client = new ITDClient();
17
+ client.setAccessToken(process.env.ITD_ACCESS_TOKEN);
18
+ client.auth.isAuthenticated = true;
19
+
20
+ try {
21
+ // Пример 1: Проверка подписки - одна строка вместо сложного запроса
22
+ console.log('1️⃣ Проверка подписки:');
23
+ const username = 'BobrishYa';
24
+ const isFollowing = await client.isFollowing(username);
25
+ console.log(` Подписан на ${username}: ${isFollowing ? '✅ Да' : '❌ Нет'}`);
26
+ console.log();
27
+
28
+ // Пример 2: Получение статистики поста - просто и понятно
29
+ console.log('2️⃣ Статистика поста:');
30
+ const postId = '936bd898-f1f4-4fcd-a498-f3a7ee8e67bb'; // Замените на реальный ID
31
+ const stats = await client.getPostStats(postId);
32
+ if (stats) {
33
+ console.log(` Лайков: ${stats.likes}`);
34
+ console.log(` Просмотров: ${stats.views}`);
35
+ console.log(` Комментариев: ${stats.comments}`);
36
+ console.log(` Репостов: ${stats.reposts}`);
37
+ } else {
38
+ console.log(' Пост не найден');
39
+ }
40
+ console.log();
41
+
42
+ // Пример 3: Проверка уведомлений - удобно и быстро
43
+ console.log('3️⃣ Проверка уведомлений:');
44
+ const hasUnread = await client.hasUnreadNotifications();
45
+ if (hasUnread) {
46
+ const unread = await client.getUnreadNotifications(5);
47
+ console.log(` Непрочитанных: ${unread.notifications.length}`);
48
+ unread.notifications.forEach((notif, i) => {
49
+ console.log(` ${i + 1}. ${notif.type} - ${notif.read ? '✅' : '🔔'}`);
50
+ });
51
+ } else {
52
+ console.log(' Нет непрочитанных уведомлений');
53
+ }
54
+ console.log();
55
+
56
+ // Пример 4: Получение клана пользователя - просто
57
+ console.log('4️⃣ Клан пользователя:');
58
+ const myClan = await client.getMyClan();
59
+ const userClan = await client.getUserClan(username);
60
+ console.log(` Мой клан: ${myClan}`);
61
+ console.log(` Клан ${username}: ${userClan}`);
62
+ console.log();
63
+
64
+ // Пример 5: Получение последнего поста - удобно
65
+ console.log('5️⃣ Последний пост пользователя:');
66
+ const latestPost = await client.getUserLatestPost(username);
67
+ if (latestPost) {
68
+ console.log(` Последний пост: ${latestPost.content?.substring(0, 60)}...`);
69
+ console.log(` Лайков: ${latestPost.likesCount}, Просмотров: ${latestPost.viewsCount}`);
70
+ } else {
71
+ console.log(' Постов не найдено');
72
+ }
73
+
74
+ } catch (error) {
75
+ console.error('❌ Ошибка:', error.message);
76
+ }
77
+ }
78
+
79
+ main();
package/package.json ADDED
@@ -0,0 +1,57 @@
1
+ {
2
+ "name": "itd-sdk-js",
3
+ "version": "1.0.0",
4
+ "description": "Unofficial SDK for итд.com - Node.js library for working with API. Automatic token refresh, session management, and convenient methods for posts, comments, users, and notifications.",
5
+ "main": "src/client.js",
6
+ "type": "module",
7
+ "exports": {
8
+ ".": "./src/client.js"
9
+ },
10
+ "files": [
11
+ "src/",
12
+ "README.md",
13
+ "API_REFERENCE.md",
14
+ "examples/auto-refresh.js",
15
+ "examples/basic-usage.js",
16
+ "examples/quick-start.js",
17
+ "examples/user-friendly.js",
18
+ "examples/README.md",
19
+ ".env.example",
20
+ ".cookies.example"
21
+ ],
22
+ "scripts": {
23
+ "test": "node examples/basic-usage.js"
24
+ },
25
+ "keywords": [
26
+ "itd",
27
+ "itd.com",
28
+ "api",
29
+ "client",
30
+ "sdk",
31
+ "blog",
32
+ "social-media",
33
+ "unofficial-api",
34
+ "nodejs",
35
+ "javascript"
36
+ ],
37
+ "author": "FriceKa",
38
+ "license": "MIT",
39
+ "repository": {
40
+ "type": "git",
41
+ "url": "git+https://github.com/FriceKa/ITD-SDK-js.git"
42
+ },
43
+ "bugs": {
44
+ "url": "https://github.com/FriceKa/ITD-SDK-js/issues"
45
+ },
46
+ "homepage": "https://github.com/FriceKa/ITD-SDK-js#readme",
47
+ "engines": {
48
+ "node": ">=14.0.0"
49
+ },
50
+ "dependencies": {
51
+ "axios": "^1.6.0",
52
+ "axios-cookiejar-support": "^6.0.4",
53
+ "dotenv": "^16.3.1",
54
+ "form-data": "^4.0.0",
55
+ "tough-cookie": "^4.1.3"
56
+ }
57
+ }
package/src/auth.js ADDED
@@ -0,0 +1,126 @@
1
+ /**
2
+ * Модуль аутентификации
3
+ */
4
+ import { saveAccessToken, saveCookieHeader } from './token-storage.js';
5
+
6
+ export class AuthManager {
7
+ /**
8
+ * Управление аутентификацией
9
+ *
10
+ * @param {ITDClient} client - Главный клиент
11
+ */
12
+ constructor(client) {
13
+ this.client = client;
14
+ this.axios = client.axios;
15
+ this.isAuthenticated = false;
16
+ this.userData = null;
17
+ }
18
+
19
+ /**
20
+ * Обновляет accessToken через /api/v1/auth/refresh
21
+ * ВАЖНО: обычно этот endpoint работает только при наличии refresh-cookie,
22
+ * который браузер/сервер поставил ранее.
23
+ *
24
+ * @returns {Promise<string|null>} accessToken или null
25
+ */
26
+ async refreshAccessToken() {
27
+ try {
28
+ const refreshUrl = `${this.client.baseUrl}/api/v1/auth/refresh`;
29
+
30
+ const headers = {
31
+ 'Referer': `${this.client.baseUrl}/`,
32
+ 'Origin': this.client.baseUrl,
33
+ };
34
+
35
+ const response = await this.axios.post(refreshUrl, {}, { headers });
36
+
37
+ if (response.status === 200 && response.data?.accessToken) {
38
+ const newToken = response.data.accessToken;
39
+
40
+ // Обновляем токен в клиенте
41
+ this.client.setAccessToken(newToken);
42
+ this.isAuthenticated = true;
43
+
44
+ // Сохраняем токен в .env файл
45
+ await saveAccessToken(newToken);
46
+
47
+ // Обновляем cookies, если они пришли в ответе
48
+ if (response.headers['set-cookie']) {
49
+ const cookies = response.headers['set-cookie'];
50
+ // Обновляем CookieJar с новыми cookies
51
+ for (const cookieString of cookies) {
52
+ try {
53
+ this.client.cookieJar.setCookieSync(cookieString, this.client.baseUrl);
54
+ } catch (e) {
55
+ // Игнорируем ошибки парсинга отдельных cookies
56
+ }
57
+ }
58
+
59
+ // Получаем все cookies из jar и обновляем .cookies файл
60
+ try {
61
+ const allCookies = await this.client.cookieJar.getCookiesSync(this.client.baseUrl);
62
+ // Сохраняем только важные cookies (refresh_token и другие auth cookies)
63
+ const importantCookies = allCookies.filter(c =>
64
+ c.key === 'refresh_token' ||
65
+ c.key.startsWith('__ddg') ||
66
+ c.key === 'is_auth'
67
+ );
68
+ if (importantCookies.length > 0) {
69
+ const cookieHeader = importantCookies.map(c => `${c.key}=${c.value}`).join('; ');
70
+ await saveCookieHeader(cookieHeader);
71
+ }
72
+ } catch (e) {
73
+ console.warn('⚠️ Не удалось сохранить обновленные cookies:', e.message);
74
+ }
75
+ }
76
+
77
+ return newToken;
78
+ }
79
+
80
+ return null;
81
+ } catch (error) {
82
+ if (error.response) {
83
+ console.error('refreshAccessToken failed:', error.response.status, error.response.data);
84
+ } else {
85
+ console.error('refreshAccessToken failed:', error.message);
86
+ }
87
+ return null;
88
+ }
89
+ }
90
+
91
+ /**
92
+ * Выход из аккаунта
93
+ *
94
+ * @returns {Promise<boolean>} True если успешно
95
+ */
96
+ async logout() {
97
+ try {
98
+ const logoutUrl = `${this.client.baseUrl}/api/v1/auth/sign-out`;
99
+ const response = await this.axios.post(logoutUrl);
100
+
101
+ if (response.status === 200) {
102
+ this.isAuthenticated = false;
103
+ this.userData = null;
104
+ this.client.setAccessToken(null);
105
+ // Очистка cookies
106
+ this.axios.defaults.headers.common['Cookie'] = '';
107
+ return true;
108
+ }
109
+ return false;
110
+ } catch (error) {
111
+ console.error('Ошибка выхода:', error.message);
112
+ return false;
113
+ }
114
+ }
115
+
116
+ /**
117
+ * Проверяет, авторизован ли пользователь
118
+ *
119
+ * @returns {Promise<boolean>} True если авторизован
120
+ */
121
+ async checkAuth() {
122
+ // Проверяем наличие accessToken - если он есть, считаем что авторизован
123
+ // Реальная проверка происходит на уровне API (401 ошибка)
124
+ return !!(this.client.accessToken || this.isAuthenticated);
125
+ }
126
+ }