itd-sdk-js 1.0.9 → 1.1.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.
package/src/client.js CHANGED
@@ -16,6 +16,7 @@ import { HashtagsManager } from './hashtags.js';
16
16
  import { FilesManager } from './files.js';
17
17
  import { ReportsManager } from './reports.js';
18
18
  import { SearchManager } from './search.js';
19
+ import { VerificationManager } from './verification.js';
19
20
 
20
21
  dotenv.config();
21
22
 
@@ -200,6 +201,7 @@ export class ITDClient {
200
201
  this.files = new FilesManager(this);
201
202
  this.reports = new ReportsManager(this);
202
203
  this.searchManager = new SearchManager(this);
204
+ this.verification = new VerificationManager(this);
203
205
  }
204
206
 
205
207
  /**
@@ -343,6 +345,17 @@ export class ITDClient {
343
345
  async logout() {
344
346
  return await this.auth.logout();
345
347
  }
348
+
349
+ /**
350
+ * Смена пароля. POST /api/v1/auth/change-password. Требует cookies (refresh_token).
351
+ *
352
+ * @param {string} oldPassword - Текущий пароль
353
+ * @param {string} newPassword - Новый пароль
354
+ * @returns {Promise<Object|null>} Ответ API или null
355
+ */
356
+ async changePassword(oldPassword, newPassword) {
357
+ return await this.auth.changePassword(oldPassword, newPassword);
358
+ }
346
359
 
347
360
  /**
348
361
  * Создает пост (удобный метод)
@@ -413,6 +426,19 @@ export class ITDClient {
413
426
  async getFeedFollowing(limit = 20, cursor = null) {
414
427
  return await this.posts.getFeedFollowing(limit, cursor);
415
428
  }
429
+
430
+ /**
431
+ * Получает лайкнутые посты пользователя.
432
+ * GET /api/posts/user/{username}/liked → { posts: [], pagination: {} }
433
+ *
434
+ * @param {string} username - Имя пользователя
435
+ * @param {number} limit - Количество постов
436
+ * @param {string|null} cursor - Курсор для пагинации
437
+ * @returns {Promise<Object>} { posts: [], pagination: {} }
438
+ */
439
+ async getLikedPosts(username, limit = 20, cursor = null) {
440
+ return await this.posts.getLikedPosts(username, limit, cursor);
441
+ }
416
442
 
417
443
  /**
418
444
  * Получает список постов (простой вариант - только массив)
@@ -435,6 +461,28 @@ export class ITDClient {
435
461
  async getPost(postId) {
436
462
  return await this.posts.getPost(postId);
437
463
  }
464
+
465
+ /**
466
+ * Отмечает пост как просмотренный. POST /api/posts/{id}/view
467
+ *
468
+ * @param {string} postId - ID поста
469
+ * @returns {Promise<boolean>} True если успешно
470
+ */
471
+ async viewPost(postId) {
472
+ return await this.posts.viewPost(postId);
473
+ }
474
+
475
+ /**
476
+ * Получает посты на стене пользователя. GET /api/posts/user/{username}/wall
477
+ *
478
+ * @param {string} username - Имя пользователя
479
+ * @param {number} limit - Количество
480
+ * @param {string|null} cursor - Курсор пагинации
481
+ * @returns {Promise<Object>} { posts: [], pagination: {} }
482
+ */
483
+ async getWallByUser(username, limit = 20, cursor = null) {
484
+ return await this.posts.getWallByUser(username, limit, cursor);
485
+ }
438
486
 
439
487
  /**
440
488
  * Удаляет пост (удобный метод)
@@ -445,16 +493,36 @@ export class ITDClient {
445
493
  async deletePost(postId) {
446
494
  return await this.posts.deletePost(postId);
447
495
  }
496
+
497
+ /**
498
+ * Восстанавливает удалённый пост. POST /api/posts/{id}/restore
499
+ *
500
+ * @param {string} postId - ID поста
501
+ * @returns {Promise<boolean>} True если успешно
502
+ */
503
+ async restorePost(postId) {
504
+ return await this.posts.restorePost(postId);
505
+ }
448
506
 
449
507
  /**
450
- * Закрепляет пост (удобный метод)
451
- *
508
+ * Закрепляет пост. POST /api/posts/{id}/pin → { success: true, pinnedPostId }
509
+ *
452
510
  * @param {string} postId - ID поста
453
511
  * @returns {Promise<boolean>} True если успешно
454
512
  */
455
513
  async pinPost(postId) {
456
514
  return await this.posts.pinPost(postId);
457
515
  }
516
+
517
+ /**
518
+ * Открепляет пост. DELETE /api/posts/{id}/pin → { success: true, pinnedPostId: null }
519
+ *
520
+ * @param {string} postId - ID поста
521
+ * @returns {Promise<boolean>} True если успешно
522
+ */
523
+ async unpinPost(postId) {
524
+ return await this.posts.unpinPost(postId);
525
+ }
458
526
 
459
527
  /**
460
528
  * Делает репост (удобный метод)
@@ -537,12 +605,25 @@ export class ITDClient {
537
605
  * Добавляет комментарий к посту
538
606
  *
539
607
  * @param {string} postId - ID поста
540
- * @param {string} text - Текст комментария
608
+ * @param {string} text - Текст (пустая строка для голосового)
541
609
  * @param {string|null} replyToCommentId - ID комментария для ответа (опционально)
610
+ * @param {string[]|null} attachmentIds - ID загруженных файлов (audio/ogg для голосовых)
542
611
  * @returns {Promise<Object|null>} Данные комментария
543
612
  */
544
- async addComment(postId, text, replyToCommentId = null) {
545
- return await this.comments.addComment(postId, text, replyToCommentId);
613
+ async addComment(postId, text, replyToCommentId = null, attachmentIds = null) {
614
+ return await this.comments.addComment(postId, text, replyToCommentId, attachmentIds);
615
+ }
616
+
617
+ /**
618
+ * Добавляет голосовое сообщение в комментарий. Загружает audio/ogg и создаёт комментарий.
619
+ *
620
+ * @param {string} postId - ID поста
621
+ * @param {string} audioPath - Путь к аудиофайлу (audio/ogg)
622
+ * @param {string|null} replyToCommentId - ID комментария для ответа (опционально)
623
+ * @returns {Promise<Object|null>} Данные созданного комментария или null
624
+ */
625
+ async addVoiceComment(postId, audioPath, replyToCommentId = null) {
626
+ return await this.comments.addVoiceComment(postId, audioPath, replyToCommentId);
546
627
  }
547
628
 
548
629
  /**
@@ -586,6 +667,16 @@ export class ITDClient {
586
667
  async deleteComment(commentId) {
587
668
  return await this.comments.deleteComment(commentId);
588
669
  }
670
+
671
+ /**
672
+ * Восстанавливает удалённый комментарий. POST /api/comments/{id}/restore
673
+ *
674
+ * @param {string} commentId - ID комментария
675
+ * @returns {Promise<boolean>} True если успешно
676
+ */
677
+ async restoreComment(commentId) {
678
+ return await this.comments.restoreComment(commentId);
679
+ }
589
680
 
590
681
  /**
591
682
  * Получает комментарии к посту
@@ -600,14 +691,38 @@ export class ITDClient {
600
691
  }
601
692
 
602
693
  /**
603
- * Обновляет описание профиля текущего пользователя
604
- *
605
- * @param {string} bio - Новое описание профиля
694
+ * Обновляет профиль текущего пользователя.
695
+ * PUT /api/users/me → { id, username, displayName, bio, updatedAt }
696
+ *
697
+ * @param {string|null} bio - Новое описание профиля (опционально)
606
698
  * @param {string|null} displayName - Новое отображаемое имя (опционально)
699
+ * @param {string|null} username - Новый username (опционально)
700
+ * @param {string|null} bannerId - ID загруженного баннера (опционально)
607
701
  * @returns {Promise<Object|null>} Обновленные данные профиля или null при ошибке
608
702
  */
609
- async updateProfile(bio, displayName = null) {
610
- return await this.users.updateProfile(bio, displayName);
703
+ async updateProfile(bio = null, displayName = null, username = null, bannerId = null) {
704
+ return await this.users.updateProfile(bio, displayName, username, bannerId);
705
+ }
706
+
707
+ /**
708
+ * Получает настройки приватности.
709
+ * GET /api/users/me/privacy → { isPrivate, wallClosed }
710
+ *
711
+ * @returns {Promise<Object|null>} { isPrivate, wallClosed } или null
712
+ */
713
+ async getPrivacy() {
714
+ return await this.users.getPrivacy();
715
+ }
716
+
717
+ /**
718
+ * Обновляет настройки приватности.
719
+ * PUT /api/users/me/privacy → { isPrivate, wallClosed }
720
+ *
721
+ * @param {Object} options - { isPrivate?: boolean, wallClosed?: boolean }
722
+ * @returns {Promise<Object|null>} { isPrivate, wallClosed } или null
723
+ */
724
+ async updatePrivacy(options = {}) {
725
+ return await this.users.updatePrivacy(options);
611
726
  }
612
727
 
613
728
  /**
@@ -684,27 +799,39 @@ export class ITDClient {
684
799
  }
685
800
 
686
801
  /**
687
- * Получает список уведомлений
688
- *
802
+ * Получает список уведомлений.
803
+ * GET /api/notifications/?offset=0&limit=20 → { notifications: [], hasMore }
804
+ *
689
805
  * @param {number} limit - Количество уведомлений
690
- * @param {string|null} cursor - Курсор для пагинации
691
- * @param {string|null} type - Фильтр по типу: 'reply', 'like', 'wall_post', 'follow', 'comment' (опционально)
692
- * @returns {Promise<Object|null>} { notifications: [], pagination: {} } или null
806
+ * @param {number} offset - Смещение для пагинации
807
+ * @param {string|null} type - Фильтр по типу: 'reply', 'like', 'wall_post', 'follow', 'comment'
808
+ * @returns {Promise<Object|null>} { notifications: [], hasMore } или null
693
809
  */
694
- async getNotifications(limit = 20, cursor = null, type = null) {
695
- return await this.notifications.getNotifications(limit, cursor, type);
810
+ async getNotifications(limit = 20, offset = 0, type = null) {
811
+ return await this.notifications.getNotifications(limit, offset, type);
696
812
  }
697
-
813
+
698
814
  /**
699
815
  * Получает уведомления определенного типа
700
- *
701
- * @param {string} type - Тип уведомления: 'reply', 'like', 'wall_post', 'follow', 'comment'
702
- * @param {number} limit - Количество уведомлений (по умолчанию 20)
703
- * @param {string|null} cursor - Курсор для пагинации
704
- * @returns {Promise<Object|null>} { notifications: [], pagination: {} } или null
816
+ *
817
+ * @param {string} type - Тип: 'reply', 'like', 'wall_post', 'follow', 'comment'
818
+ * @param {number} limit - Количество
819
+ * @param {number} offset - Смещение
820
+ * @returns {Promise<Object|null>} { notifications: [], hasMore } или null
821
+ */
822
+ async getNotificationsByType(type, limit = 20, offset = 0) {
823
+ return await this.notifications.getNotifications(limit, offset, type);
824
+ }
825
+
826
+ /**
827
+ * Отмечает несколько уведомлений как прочитанные.
828
+ * POST /api/notifications/read-batch → { success: true, count }
829
+ *
830
+ * @param {string[]} ids - Массив ID уведомлений
831
+ * @returns {Promise<Object|null>} { success: true, count } или null
705
832
  */
706
- async getNotificationsByType(type, limit = 20, cursor = null) {
707
- return await this.notifications.getNotifications(limit, cursor, type);
833
+ async markNotificationsAsReadBatch(ids) {
834
+ return await this.notifications.markAsReadBatch(ids);
708
835
  }
709
836
 
710
837
  /**
@@ -784,6 +911,26 @@ export class ITDClient {
784
911
  async uploadFile(filePath) {
785
912
  return await this.files.uploadFile(filePath);
786
913
  }
914
+
915
+ /**
916
+ * Получает информацию о файле. GET /api/files/{id}
917
+ *
918
+ * @param {string} fileId - ID файла
919
+ * @returns {Promise<Object|null>} { id, url, filename, mimeType, size } или null
920
+ */
921
+ async getFile(fileId) {
922
+ return await this.files.getFile(fileId);
923
+ }
924
+
925
+ /**
926
+ * Удаляет файл. DELETE /api/files/{id}
927
+ *
928
+ * @param {string} fileId - ID файла
929
+ * @returns {Promise<boolean>} True если успешно
930
+ */
931
+ async deleteFile(fileId) {
932
+ return await this.files.deleteFile(fileId);
933
+ }
787
934
 
788
935
  /**
789
936
  * Отправляет репорт на пост, комментарий или пользователя
@@ -833,6 +980,43 @@ export class ITDClient {
833
980
  async reportUser(userId, reason = 'other', description = '') {
834
981
  return await this.reports.reportUser(userId, reason, description);
835
982
  }
983
+
984
+ /**
985
+ * Получает статус верификации. GET /api/verification/status
986
+ *
987
+ * @returns {Promise<Object|null>} Статус верификации или null
988
+ */
989
+ async getVerificationStatus() {
990
+ return await this.verification.getStatus();
991
+ }
992
+
993
+ /**
994
+ * Подаёт заявку на верификацию. POST /api/verification/submit
995
+ *
996
+ * @param {string} videoUrl - URL загруженного видео (из uploadFile)
997
+ * @returns {Promise<Object|null>} { success, request } или null
998
+ */
999
+ async submitVerification(videoUrl) {
1000
+ return await this.verification.submit(videoUrl);
1001
+ }
1002
+
1003
+ /**
1004
+ * Получает статус платформы. GET /api/platform/status
1005
+ *
1006
+ * @returns {Promise<Object|null>} Статус платформы или null
1007
+ */
1008
+ async getPlatformStatus() {
1009
+ try {
1010
+ const response = await this.axios.get('/api/platform/status');
1011
+ if (response.status === 200) {
1012
+ return response.data?.data ?? response.data;
1013
+ }
1014
+ return null;
1015
+ } catch (error) {
1016
+ console.error('Ошибка получения статуса платформы:', error.message);
1017
+ return null;
1018
+ }
1019
+ }
836
1020
 
837
1021
  /**
838
1022
  * Выполняет поиск пользователей и хэштегов
@@ -1030,12 +1214,12 @@ export class ITDClient {
1030
1214
 
1031
1215
  /**
1032
1216
  * Получает только непрочитанные уведомления (удобный метод)
1033
- *
1034
- * @param {number} limit - Количество уведомлений
1035
- * @param {string|null} cursor - Курсор для пагинации
1036
- * @returns {Promise<Object|null>} { notifications: [], pagination: {} } или null
1217
+ *
1218
+ * @param {number} limit - Количество
1219
+ * @param {number} offset - Смещение
1220
+ * @returns {Promise<Object|null>} { notifications: [], hasMore } или null
1037
1221
  */
1038
- async getUnreadNotifications(limit = 20, cursor = null) {
1039
- return await this.notifications.getUnreadNotifications(limit, cursor);
1222
+ async getUnreadNotifications(limit = 20, offset = 0) {
1223
+ return await this.notifications.getUnreadNotifications(limit, offset);
1040
1224
  }
1041
1225
  }
package/src/comments.js CHANGED
@@ -13,30 +13,28 @@ export class CommentsManager {
13
13
  }
14
14
 
15
15
  /**
16
- * Добавляет комментарий к посту
17
- *
16
+ * Добавляет комментарий к посту.
17
+ * POST /api/posts/{postId}/comments → { id, content, author, attachments, ... }
18
+ * Поддерживает текст, голосовые (attachmentIds с audio/ogg) и ответы (replyTo).
19
+ *
18
20
  * @param {string} postId - ID поста
19
- * @param {string} text - Текст комментария
21
+ * @param {string} text - Текст комментария (пустая строка для голосового)
20
22
  * @param {string|null} replyToCommentId - ID комментария для ответа (опционально)
23
+ * @param {string[]|null} attachmentIds - ID загруженных файлов (audio/ogg для голосовых)
21
24
  * @returns {Promise<Object|null>} Данные созданного комментария или null
22
25
  */
23
- async addComment(postId, text, replyToCommentId = null) {
26
+ async addComment(postId, text, replyToCommentId = null, attachmentIds = null) {
24
27
  if (!await this.client.auth.checkAuth()) {
25
28
  console.error('Ошибка: необходимо войти в аккаунт');
26
29
  return null;
27
30
  }
28
-
29
31
  try {
30
32
  const commentUrl = `${this.client.baseUrl}/api/posts/${postId}/comments`;
31
- const commentData = {
32
- content: text, // Реальное поле - content
33
- };
34
-
35
- // Если это ответ на комментарий
36
- if (replyToCommentId) {
37
- commentData.replyTo = replyToCommentId;
33
+ const commentData = { content: text ?? '' };
34
+ if (replyToCommentId) commentData.replyTo = replyToCommentId;
35
+ if (Array.isArray(attachmentIds) && attachmentIds.length > 0) {
36
+ commentData.attachmentIds = attachmentIds;
38
37
  }
39
-
40
38
  const response = await this.axios.post(commentUrl, commentData);
41
39
 
42
40
  if (response.status === 200 || response.status === 201) {
@@ -55,6 +53,25 @@ export class CommentsManager {
55
53
  }
56
54
  }
57
55
 
56
+ /**
57
+ * Добавляет голосовое сообщение в комментарий.
58
+ * Загружает audio/ogg через /api/files/upload и создаёт комментарий с attachmentIds.
59
+ *
60
+ * @param {string} postId - ID поста
61
+ * @param {string} audioPath - Путь к аудиофайлу (audio/ogg)
62
+ * @param {string|null} replyToCommentId - ID комментария для ответа (опционально)
63
+ * @returns {Promise<Object|null>} Данные созданного комментария или null
64
+ */
65
+ async addVoiceComment(postId, audioPath, replyToCommentId = null) {
66
+ if (!await this.client.auth.checkAuth()) {
67
+ console.error('Ошибка: необходимо войти в аккаунт');
68
+ return null;
69
+ }
70
+ const uploaded = await this.client.files.uploadFile(audioPath);
71
+ if (!uploaded) return null;
72
+ return await this.addComment(postId, '', replyToCommentId, [uploaded.id]);
73
+ }
74
+
58
75
  /**
59
76
  * Ответ на комментарий (отдельный эндпоинт /api/comments/:id/replies).
60
77
  *
@@ -257,6 +274,24 @@ export class CommentsManager {
257
274
  return false;
258
275
  }
259
276
  }
277
+
278
+ /**
279
+ * Восстанавливает удалённый комментарий. POST /api/comments/{id}/restore
280
+ *
281
+ * @param {string} commentId - ID комментария
282
+ * @returns {Promise<boolean>} True если успешно
283
+ */
284
+ async restoreComment(commentId) {
285
+ if (!await this.client.auth.checkAuth()) return false;
286
+ try {
287
+ const url = `${this.client.baseUrl}/api/comments/${commentId}/restore`;
288
+ const response = await this.axios.post(url);
289
+ return response.status === 200 || response.status === 201 || response.status === 204;
290
+ } catch (error) {
291
+ console.error('Исключение при восстановлении комментария:', error.message);
292
+ return false;
293
+ }
294
+ }
260
295
 
261
296
  // ========== USER-FRIENDLY МЕТОДЫ ==========
262
297
 
package/src/files.js CHANGED
@@ -11,7 +11,8 @@ export class FilesManager {
11
11
  }
12
12
 
13
13
  /**
14
- * Загружает файл (изображение) на сервер.
14
+ * Загружает файл на сервер. POST /api/files/upload.
15
+ * Поддерживает изображения и аудио (audio/ogg для голосовых в комментариях).
15
16
  * Таймаут — client.uploadTimeout (по умолчанию 120 с). При ошибке возвращает null.
16
17
  *
17
18
  * @param {string} filePath - Путь к файлу
@@ -58,4 +59,43 @@ export class FilesManager {
58
59
  return null;
59
60
  }
60
61
  }
62
+
63
+ /**
64
+ * Получает информацию о файле. GET /api/files/{id}
65
+ *
66
+ * @param {string} fileId - ID файла
67
+ * @returns {Promise<Object|null>} { id, url, filename, mimeType, size, ... } или null
68
+ */
69
+ async getFile(fileId) {
70
+ if (!await this.client.auth.checkAuth()) return null;
71
+ try {
72
+ const url = `${this.client.baseUrl}/api/files/${fileId}`;
73
+ const response = await this.axios.get(url);
74
+ if (response.status === 200) {
75
+ return response.data?.data ?? response.data;
76
+ }
77
+ return null;
78
+ } catch (error) {
79
+ console.error('Ошибка получения файла:', error.message);
80
+ return null;
81
+ }
82
+ }
83
+
84
+ /**
85
+ * Удаляет файл. DELETE /api/files/{id}
86
+ *
87
+ * @param {string} fileId - ID файла
88
+ * @returns {Promise<boolean>} True если успешно
89
+ */
90
+ async deleteFile(fileId) {
91
+ if (!await this.client.auth.checkAuth()) return false;
92
+ try {
93
+ const url = `${this.client.baseUrl}/api/files/${fileId}`;
94
+ const response = await this.axios.delete(url);
95
+ return response.status === 200 || response.status === 204;
96
+ } catch (error) {
97
+ console.error('Ошибка удаления файла:', error.message);
98
+ return false;
99
+ }
100
+ }
61
101
  }
@@ -8,14 +8,15 @@ export class NotificationsManager {
8
8
  }
9
9
 
10
10
  /**
11
- * Получает список уведомлений
12
- *
11
+ * Получает список уведомлений.
12
+ * GET /api/notifications/?offset=0&limit=20 → { notifications: [], hasMore }
13
+ *
13
14
  * @param {number} limit - Количество уведомлений
14
- * @param {string|null} cursor - Курсор для пагинации
15
- * @param {string|null} type - Фильтр по типу: 'reply', 'like', 'wall_post', 'follow', 'comment' (опционально)
16
- * @returns {Promise<Object|null>} { notifications: [], pagination: {} } или null при ошибке
15
+ * @param {number} offset - Смещение для пагинации
16
+ * @param {string|null} type - Фильтр по типу: 'reply', 'like', 'wall_post', 'follow', 'comment' (на клиенте)
17
+ * @returns {Promise<Object|null>} { notifications: [], hasMore } или null при ошибке
17
18
  */
18
- async getNotifications(limit = 20, cursor = null, type = null) {
19
+ async getNotifications(limit = 20, offset = 0, type = null) {
19
20
  if (!await this.client.auth.checkAuth()) {
20
21
  console.error('Ошибка: необходимо войти в аккаунт');
21
22
  return null;
@@ -23,42 +24,20 @@ export class NotificationsManager {
23
24
 
24
25
  try {
25
26
  const notificationsUrl = `${this.client.baseUrl}/api/notifications`;
26
- const params = { limit };
27
- if (cursor) {
28
- params.cursor = cursor;
29
- }
30
- // Пробуем передать type в параметрах (если API поддерживает)
31
- if (type) {
32
- params.type = type;
33
- }
27
+ const params = { limit, offset };
34
28
 
35
29
  const response = await this.axios.get(notificationsUrl, { params });
36
30
 
37
31
  if (response.status === 200) {
38
32
  const data = response.data;
39
- let notifications = [];
40
- let pagination = {};
41
-
42
- // Предполагаемая структура: { data: { notifications: [...], pagination: {...} } }
43
- if (data.data && data.data.notifications) {
44
- notifications = data.data.notifications;
45
- pagination = data.data.pagination || {};
46
- } else if (Array.isArray(data)) {
47
- notifications = data;
48
- } else if (data.notifications) {
49
- notifications = data.notifications;
50
- pagination = data.pagination || {};
51
- }
52
-
53
- // Фильтруем по типу на клиенте (если API не поддерживает фильтрацию)
33
+ let notifications = Array.isArray(data?.notifications) ? data.notifications : [];
34
+ const hasMore = Boolean(data?.hasMore);
35
+
54
36
  if (type && notifications.length > 0) {
55
37
  notifications = notifications.filter(notif => notif.type === type);
56
38
  }
57
-
58
- return {
59
- notifications: notifications,
60
- pagination: pagination
61
- };
39
+
40
+ return { notifications, hasMore };
62
41
  } else {
63
42
  console.error(`Ошибка получения уведомлений: ${response.status}`);
64
43
  return null;
@@ -73,6 +52,34 @@ export class NotificationsManager {
73
52
  }
74
53
  }
75
54
 
55
+ /**
56
+ * Отмечает несколько уведомлений как прочитанные.
57
+ * POST /api/notifications/read-batch → { success: true, count: number }
58
+ *
59
+ * @param {string[]} ids - Массив ID уведомлений
60
+ * @returns {Promise<Object|null>} { success: true, count } или null при ошибке
61
+ */
62
+ async markAsReadBatch(ids) {
63
+ if (!await this.client.auth.checkAuth()) {
64
+ console.error('Ошибка: необходимо войти в аккаунт');
65
+ return null;
66
+ }
67
+ if (!Array.isArray(ids) || ids.length === 0) {
68
+ return { success: true, count: 0 };
69
+ }
70
+ try {
71
+ const url = `${this.client.baseUrl}/api/notifications/read-batch`;
72
+ const response = await this.axios.post(url, { ids });
73
+ if (response.status === 200) {
74
+ return response.data;
75
+ }
76
+ return null;
77
+ } catch (error) {
78
+ console.error('Исключение при отметке уведомлений:', error.message);
79
+ return null;
80
+ }
81
+ }
82
+
76
83
  /**
77
84
  * Отмечает уведомление как прочитанное
78
85
  *
@@ -144,8 +151,8 @@ export class NotificationsManager {
144
151
 
145
152
  /**
146
153
  * Отмечает все уведомления как прочитанные.
147
- * Экспериментально: endpoint /api/notifications/read-all может отличаться.
148
- *
154
+ * POST /api/notifications/read-all { success: true }
155
+ *
149
156
  * @returns {Promise<boolean>} True если успешно
150
157
  */
151
158
  async markAllAsRead() {
@@ -155,12 +162,11 @@ export class NotificationsManager {
155
162
  }
156
163
 
157
164
  try {
158
- // Нужно найти реальный endpoint, пока используем предположительный
159
165
  const readAllUrl = `${this.client.baseUrl}/api/notifications/read-all`;
160
166
  const response = await this.axios.post(readAllUrl);
161
167
 
162
168
  if (response.status === 200 || response.status === 204) {
163
- return true;
169
+ return response.data?.success !== false;
164
170
  } else {
165
171
  console.error(`Ошибка отметки всех уведомлений: ${response.status}`);
166
172
  if (response.data) {
@@ -173,10 +179,6 @@ export class NotificationsManager {
173
179
  if (error.response) {
174
180
  console.error('Response status:', error.response.status);
175
181
  console.error('Response data:', error.response.data);
176
- // Если 404 - значит endpoint неправильный, нужно найти реальный
177
- if (error.response.status === 404) {
178
- console.error('💡 Endpoint не найден. Найди реальный URL в DevTools');
179
- }
180
182
  }
181
183
  return false;
182
184
  }
@@ -196,21 +198,16 @@ export class NotificationsManager {
196
198
 
197
199
  /**
198
200
  * Получает только непрочитанные уведомления (удобный метод)
199
- *
201
+ *
200
202
  * @param {number} limit - Количество уведомлений
201
- * @param {string|null} cursor - Курсор для пагинации
202
- * @returns {Promise<Object|null>} { notifications: [], pagination: {} } или null
203
+ * @param {number} offset - Смещение для пагинации
204
+ * @returns {Promise<Object|null>} { notifications: [], hasMore } или null
203
205
  */
204
- async getUnreadNotifications(limit = 20, cursor = null) {
205
- const all = await this.getNotifications(limit, cursor);
206
+ async getUnreadNotifications(limit = 20, offset = 0) {
207
+ const all = await this.getNotifications(limit, offset);
206
208
  if (!all) return null;
207
-
208
- // Фильтруем только непрочитанные
209
209
  const unread = all.notifications.filter(n => !n.read);
210
- return {
211
- notifications: unread,
212
- pagination: all.pagination
213
- };
210
+ return { notifications: unread, hasMore: all.hasMore };
214
211
  }
215
212
 
216
213
  }