itd-sdk-js 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/API_REFERENCE.md +27 -5
- package/README.md +6 -0
- package/package.json +1 -1
- package/src/client.js +25 -1
- package/src/comments.js +90 -41
- package/src/files.js +4 -2
- package/src/posts.js +17 -10
- package/src/users.js +4 -3
package/API_REFERENCE.md
CHANGED
|
@@ -60,15 +60,18 @@ const client = new ITDClient({
|
|
|
60
60
|
baseUrl: 'https://xn--d1ah4a.com',
|
|
61
61
|
userAgent: '...',
|
|
62
62
|
projectRoot: process.cwd(), // корень проекта (по умолчанию process.cwd())
|
|
63
|
-
// либо явные пути:
|
|
64
63
|
// envPath: '/path/to/project/.env',
|
|
65
64
|
// cookiesPath: '/path/to/project/.cookies',
|
|
65
|
+
requestTimeout: 60000, // таймаут обычных запросов, мс (по умолчанию 60 с)
|
|
66
|
+
uploadTimeout: 120000, // таймаут загрузки файлов и создания поста, мс (по умолчанию 120 с)
|
|
66
67
|
});
|
|
67
68
|
client.setAccessToken(process.env.ITD_ACCESS_TOKEN);
|
|
68
69
|
```
|
|
69
70
|
|
|
70
71
|
- `projectRoot` — директория, в которой ищутся `.env` и `.cookies` (по умолчанию `process.cwd()`).
|
|
71
72
|
- `envPath` / `cookiesPath` — при указании переопределяют пути, собранные из `projectRoot`.
|
|
73
|
+
- `requestTimeout` — таймаут обычных запросов в мс (по умолчанию 60000). Предотвращает бесконечное ожидание при «тяжёлой» сети.
|
|
74
|
+
- `uploadTimeout` — таймаут для загрузки файлов и создания поста в мс (по умолчанию 120000). Используется в `uploadFile`, `createPost`, `createWallPost`.
|
|
72
75
|
|
|
73
76
|
### Автоматическое обновление (Refresh Token)
|
|
74
77
|
|
|
@@ -112,6 +115,10 @@ const post = await client.createPost('Текст поста', 'image.jpg');
|
|
|
112
115
|
|
|
113
116
|
Создает новый пост. При указании `imagePath` файл предварительно загружается через `/api/files/upload`, после чего ID файла прикрепляется к посту через поле `attachmentIds`.
|
|
114
117
|
|
|
118
|
+
- **Возвращает:** объект поста при успехе; **`null`** при любой ошибке (сеть, 5xx, 429, не удалось загрузить файл, неверный ответ). Всегда проверяйте результат на `null`.
|
|
119
|
+
- **Таймаут:** для загрузки файла и создания поста используется `uploadTimeout` (по умолчанию 120 с), чтобы запрос не зависал при 504 или медленной сети.
|
|
120
|
+
- **Ретраи:** при 5xx/429 или «API вернул null» рекомендуется повторять запрос в приложении (например, до 3–8 попыток с экспоненциальной задержкой). Встроенных ретраев в SDK нет.
|
|
121
|
+
|
|
115
122
|
**Важно:** API использует поле `attachmentIds` (массив ID файлов), а не `attachments`. SDK автоматически использует правильное поле.
|
|
116
123
|
|
|
117
124
|
- **Параметры**: `text` (string), `imagePath` (string, опционально).
|
|
@@ -120,6 +127,8 @@ const post = await client.createPost('Текст поста', 'image.jpg');
|
|
|
120
127
|
|
|
121
128
|
Создает пост **на стене другого пользователя** (wall post).
|
|
122
129
|
|
|
130
|
+
- **Возвращает:** объект поста при успехе; **`null`** при любой ошибке. Проверяйте результат на `null`; при 5xx/429 рекомендуется ретраи в приложении.
|
|
131
|
+
- **Таймаут:** используется `uploadTimeout` (по умолчанию 120 с).
|
|
123
132
|
- Делается через `POST /api/posts` с телом `{ content, wallRecipientId, attachmentIds? }`.
|
|
124
133
|
- `wallRecipientId` — это **ID пользователя-получателя**, поэтому метод сначала запрашивает профиль через `getUserProfile(username)` и берет `profile.id`.
|
|
125
134
|
- При указании `imagePath` файл загружается и прикрепляется через `attachmentIds`.
|
|
@@ -165,11 +174,24 @@ const post = await client.createPost('Текст поста', 'image.jpg');
|
|
|
165
174
|
|
|
166
175
|
Получает дерево комментариев к посту.
|
|
167
176
|
|
|
168
|
-
- **Параметры**: `postId`, `limit
|
|
177
|
+
- **Параметры**: `postId`, `limit` (по умолчанию 20, в запросе ограничивается 1–100), `sort` — в SDK можно передавать `"popular"`, `"new"`, `"old"`; в API уходит `popular`, `newest`, `oldest` соответственно.
|
|
178
|
+
- **Ответ API:** `{ data: { comments: [], total, hasMore, nextCursor } }`. Комментарии могут содержать вложенные `replies`, у ответов — поле `replyTo`.
|
|
169
179
|
|
|
170
180
|
### addComment(postId, text, replyToCommentId?)
|
|
171
181
|
|
|
172
|
-
Добавляет новый комментарий или ответ на
|
|
182
|
+
Добавляет новый комментарий или ответ на существующий (POST к посту: `/api/posts/:postId/comments`).
|
|
183
|
+
|
|
184
|
+
### replyToComment(commentId, content, replyToUserId)
|
|
185
|
+
|
|
186
|
+
Ответ на комментарий через отдельный эндпоинт **POST** `/api/comments/:commentId/replies`.
|
|
187
|
+
|
|
188
|
+
- **Параметры**:
|
|
189
|
+
- `commentId` — ID комментария, на который отвечаем.
|
|
190
|
+
- `content` — текст ответа.
|
|
191
|
+
- `replyToUserId` — ID пользователя-автора комментария (обязательно для API).
|
|
192
|
+
- **Возвращает:** объект созданного комментария-ответа или `null` при ошибке.
|
|
193
|
+
|
|
194
|
+
Пример: `client.replyToComment('80a775df-811a-4b60-b2fd-24651c1e546e', 'кака', '220e565c-45b9-4634-bdba-a6ebe6e8c5d1')`.
|
|
173
195
|
|
|
174
196
|
### Управление комментариями
|
|
175
197
|
|
|
@@ -216,14 +238,14 @@ const post = await client.createPost('Текст поста', 'image.jpg');
|
|
|
216
238
|
- `search(query, userLimit?, hashtagLimit?)` — универсальный поиск пользователей и хэштегов. Возвращает `{ users: [], hashtags: [] }`.
|
|
217
239
|
- `searchUsers(query, limit?)` — поиск только пользователей.
|
|
218
240
|
- `searchHashtags(query, limit?)` — поиск только хэштегов.
|
|
219
|
-
- `getTopClans()` — рейтинг кланов по количеству участников.
|
|
241
|
+
- `getTopClans()` — рейтинг кланов по количеству участников. **Возвращает массив** `Array<{ avatar, memberCount }>` или **`null`** при ошибке (не объект с полем `clans`).
|
|
220
242
|
- `getWhoToFollow()` — рекомендованные пользователи.
|
|
221
243
|
- `getTrendingHashtags(limit)` — список популярных тегов.
|
|
222
244
|
- `getPostsByHashtag(tagName, limit, cursor)` — поиск постов по тегу. Возвращает `{ posts: [], hashtag: {}, pagination: {} }`.
|
|
223
245
|
|
|
224
246
|
### Файлы и репорты
|
|
225
247
|
|
|
226
|
-
- `uploadFile(filePath)` — загрузка файла через `/api/files/upload`. Возвращает `{ id, url, filename, mimeType, size }
|
|
248
|
+
- `uploadFile(filePath)` — загрузка файла через `/api/files/upload`. Возвращает `{ id, url, filename, mimeType, size }` или **`null`** при ошибке. Таймаут — `uploadTimeout` (по умолчанию 120 с). Используется автоматически при создании поста с изображением.
|
|
227
249
|
- `report(targetType, targetId, reason?, description?)` — отправка репорта. `targetType`: `"post"`, `"comment"`, `"user"`. Возвращает `{ id, createdAt }`.
|
|
228
250
|
- `reportPost(postId, reason?, description?)` — репорт поста.
|
|
229
251
|
- `reportComment(commentId, reason?, description?)` — репорт комментария.
|
package/README.md
CHANGED
|
@@ -91,6 +91,12 @@ console.log(`${stats.likes} лайков, ${stats.views} просмотров`);
|
|
|
91
91
|
await client.createWallPost('ITD_API', 'Тестовый пост на чужой стене 🦫');
|
|
92
92
|
```
|
|
93
93
|
|
|
94
|
+
## Рекомендации при создании постов
|
|
95
|
+
|
|
96
|
+
- **createPost** и **createWallPost** при любой ошибке возвращают **`null`** — всегда проверяйте результат.
|
|
97
|
+
- Для загрузки файла и создания поста используется таймаут **120 с** по умолчанию (`uploadTimeout` в опциях клиента), чтобы запрос не зависал при 504 или медленной сети.
|
|
98
|
+
- При 5xx/429 или «API вернул null» рекомендуется повторять запрос в приложении (ретраи с задержкой). Подробнее — в [API_REFERENCE.md](API_REFERENCE.md).
|
|
99
|
+
|
|
94
100
|
## Важно
|
|
95
101
|
|
|
96
102
|
Это неофициальный проект. Если разработчики сайта изменят структуру API или введут новую защиту, методы могут временно перестать работать. Используйте аккуратно и не спамьте запросами.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "itd-sdk-js",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.7",
|
|
4
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
5
|
"main": "src/client.js",
|
|
6
6
|
"type": "module",
|
package/src/client.js
CHANGED
|
@@ -32,9 +32,11 @@ export class ITDClient {
|
|
|
32
32
|
* @param {string} [options.projectRoot] - Корень проекта (по умолчанию process.cwd()); .env и .cookies ищутся здесь
|
|
33
33
|
* @param {string} [options.envPath] - Полный путь к .env (переопределяет projectRoot для .env)
|
|
34
34
|
* @param {string} [options.cookiesPath] - Полный путь к .cookies (переопределяет projectRoot для .cookies)
|
|
35
|
+
* @param {number} [options.requestTimeout] - Таймаут обычных запросов в мс (по умолчанию 60000)
|
|
36
|
+
* @param {number} [options.uploadTimeout] - Таймаут загрузки файлов и создания поста в мс (по умолчанию 120000)
|
|
35
37
|
*/
|
|
36
38
|
constructor(baseUrlOrOptions = null, userAgent = null) {
|
|
37
|
-
let baseUrl, projectRoot, envPath, cookiesPath;
|
|
39
|
+
let baseUrl, projectRoot, envPath, cookiesPath, requestTimeout, uploadTimeout;
|
|
38
40
|
|
|
39
41
|
if (baseUrlOrOptions && typeof baseUrlOrOptions === 'object' && !(baseUrlOrOptions instanceof URL)) {
|
|
40
42
|
const opts = baseUrlOrOptions;
|
|
@@ -43,11 +45,15 @@ export class ITDClient {
|
|
|
43
45
|
projectRoot = opts.projectRoot ?? process.cwd();
|
|
44
46
|
envPath = opts.envPath ?? path.join(projectRoot, '.env');
|
|
45
47
|
cookiesPath = opts.cookiesPath ?? path.join(projectRoot, '.cookies');
|
|
48
|
+
requestTimeout = opts.requestTimeout ?? 60000;
|
|
49
|
+
uploadTimeout = opts.uploadTimeout ?? 120000;
|
|
46
50
|
} else {
|
|
47
51
|
projectRoot = process.cwd();
|
|
48
52
|
baseUrl = baseUrlOrOptions || process.env.ITD_BASE_URL || 'https://xn--d1ah4a.com';
|
|
49
53
|
envPath = path.join(projectRoot, '.env');
|
|
50
54
|
cookiesPath = path.join(projectRoot, '.cookies');
|
|
55
|
+
requestTimeout = 60000;
|
|
56
|
+
uploadTimeout = 120000;
|
|
51
57
|
}
|
|
52
58
|
|
|
53
59
|
// Используем реальный домен (IDN: итд.com = xn--d1ah4a.com)
|
|
@@ -59,6 +65,11 @@ export class ITDClient {
|
|
|
59
65
|
this.envPath = envPath;
|
|
60
66
|
this.cookiesPath = cookiesPath;
|
|
61
67
|
|
|
68
|
+
/** Таймаут обычных запросов (мс). Для загрузки и создания поста используется uploadTimeout. */
|
|
69
|
+
this.requestTimeout = requestTimeout;
|
|
70
|
+
/** Таймаут загрузки файлов и создания поста (мс), чтобы не зависать при 504/медленной сети. */
|
|
71
|
+
this.uploadTimeout = uploadTimeout;
|
|
72
|
+
|
|
62
73
|
/** @type {string|null} */
|
|
63
74
|
this.accessToken = null;
|
|
64
75
|
|
|
@@ -78,6 +89,7 @@ export class ITDClient {
|
|
|
78
89
|
// Создание axios instance + cookie jar
|
|
79
90
|
const axiosConfig = {
|
|
80
91
|
baseURL: this.baseUrl,
|
|
92
|
+
timeout: requestTimeout,
|
|
81
93
|
withCredentials: true,
|
|
82
94
|
jar: this.cookieJar,
|
|
83
95
|
headers: {
|
|
@@ -469,6 +481,18 @@ export class ITDClient {
|
|
|
469
481
|
async addComment(postId, text, replyToCommentId = null) {
|
|
470
482
|
return await this.comments.addComment(postId, text, replyToCommentId);
|
|
471
483
|
}
|
|
484
|
+
|
|
485
|
+
/**
|
|
486
|
+
* Ответ на комментарий (POST /api/comments/:id/replies).
|
|
487
|
+
*
|
|
488
|
+
* @param {string} commentId - ID комментария, на который отвечаем
|
|
489
|
+
* @param {string} content - Текст ответа
|
|
490
|
+
* @param {string} replyToUserId - ID пользователя-автора комментария (обязательно для API)
|
|
491
|
+
* @returns {Promise<Object|null>} Данные созданного комментария-ответа или null при ошибке
|
|
492
|
+
*/
|
|
493
|
+
async replyToComment(commentId, content, replyToUserId) {
|
|
494
|
+
return await this.comments.replyToComment(commentId, content, replyToUserId);
|
|
495
|
+
}
|
|
472
496
|
|
|
473
497
|
/**
|
|
474
498
|
* Ставит лайк на комментарий
|
package/src/comments.js
CHANGED
|
@@ -54,58 +54,107 @@ export class CommentsManager {
|
|
|
54
54
|
return null;
|
|
55
55
|
}
|
|
56
56
|
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Ответ на комментарий (отдельный эндпоинт /api/comments/:id/replies).
|
|
60
|
+
*
|
|
61
|
+
* @param {string} commentId - ID комментария, на который отвечаем
|
|
62
|
+
* @param {string} content - Текст ответа
|
|
63
|
+
* @param {string} replyToUserId - ID пользователя-автора комментария (обязательно для API)
|
|
64
|
+
* @returns {Promise<Object|null>} Данные созданного комментария-ответа или null при ошибке
|
|
65
|
+
*/
|
|
66
|
+
async replyToComment(commentId, content, replyToUserId) {
|
|
67
|
+
if (!await this.client.auth.checkAuth()) {
|
|
68
|
+
console.error('Ошибка: необходимо войти в аккаунт');
|
|
69
|
+
return null;
|
|
70
|
+
}
|
|
71
|
+
if (!replyToUserId) {
|
|
72
|
+
console.error('Ошибка: replyToUserId обязателен для ответа на комментарий');
|
|
73
|
+
return null;
|
|
74
|
+
}
|
|
75
|
+
try {
|
|
76
|
+
const url = `${this.client.baseUrl}/api/comments/${commentId}/replies`;
|
|
77
|
+
const response = await this.axios.post(url, {
|
|
78
|
+
content,
|
|
79
|
+
replyToUserId,
|
|
80
|
+
});
|
|
81
|
+
if (response.status === 200 || response.status === 201) {
|
|
82
|
+
return response.data;
|
|
83
|
+
}
|
|
84
|
+
console.error(`Ошибка ответа на комментарий: ${response.status} - ${JSON.stringify(response.data)}`);
|
|
85
|
+
return null;
|
|
86
|
+
} catch (error) {
|
|
87
|
+
console.error('Исключение при ответе на комментарий:', error.message);
|
|
88
|
+
if (error.response) {
|
|
89
|
+
console.error('Response status:', error.response.status);
|
|
90
|
+
console.error('Response data:', error.response.data);
|
|
91
|
+
}
|
|
92
|
+
return null;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
57
95
|
|
|
58
96
|
/**
|
|
59
|
-
* Получает комментарии к
|
|
60
|
-
*
|
|
97
|
+
* Получает комментарии к посту.
|
|
98
|
+
* API ожидает sort: "newest" | "oldest" | "popular". SDK принимает "new"/"old"/"popular" и маппит в newest/oldest/popular.
|
|
99
|
+
*
|
|
61
100
|
* @param {string} postId - ID поста
|
|
62
|
-
* @param {number} limit - Количество комментариев
|
|
63
|
-
* @param {string} sort - Сортировка: "popular", "new", "old" (
|
|
101
|
+
* @param {number} limit - Количество комментариев (по умолчанию 20)
|
|
102
|
+
* @param {string} sort - Сортировка: "popular", "new", "old" (в API уходит как popular, newest, oldest)
|
|
64
103
|
* @returns {Promise<Object>} { comments: [], total, hasMore, nextCursor } или { comments: [] } при ошибке
|
|
65
|
-
*
|
|
66
|
-
* Примечание: Авторизация не требуется для просмотра комментариев
|
|
67
104
|
*/
|
|
68
105
|
async getComments(postId, limit = 20, sort = 'popular') {
|
|
106
|
+
const commentsUrl = `${this.client.baseUrl}/api/posts/${postId}/comments`;
|
|
107
|
+
const reqLimit = Math.min(Math.max(1, Number(limit) || 20), 100);
|
|
108
|
+
const sortMap = { new: 'newest', old: 'oldest', popular: 'popular', newest: 'newest', oldest: 'oldest' };
|
|
109
|
+
const reqSort = sortMap[sort] || 'popular';
|
|
110
|
+
|
|
111
|
+
const parseResponse = (response) => {
|
|
112
|
+
const data = response.data?.data ?? response.data;
|
|
113
|
+
if (data?.comments) {
|
|
114
|
+
return {
|
|
115
|
+
comments: data.comments,
|
|
116
|
+
total: data.total ?? data.comments.length,
|
|
117
|
+
hasMore: data.hasMore ?? false,
|
|
118
|
+
nextCursor: data.nextCursor ?? null
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
if (Array.isArray(data)) {
|
|
122
|
+
return {
|
|
123
|
+
comments: data,
|
|
124
|
+
total: data.length,
|
|
125
|
+
hasMore: false,
|
|
126
|
+
nextCursor: null
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
return { comments: [], total: 0, hasMore: false, nextCursor: null };
|
|
130
|
+
};
|
|
131
|
+
|
|
69
132
|
try {
|
|
70
|
-
const
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
};
|
|
75
|
-
|
|
76
|
-
const response = await this.axios.get(commentsUrl, { params });
|
|
77
|
-
|
|
133
|
+
const response = await this.axios.get(commentsUrl, {
|
|
134
|
+
params: { limit: reqLimit, sort: reqSort },
|
|
135
|
+
});
|
|
136
|
+
|
|
78
137
|
if (response.status === 200) {
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
hasMore: data.data.hasMore || false,
|
|
86
|
-
nextCursor: data.data.nextCursor || null
|
|
87
|
-
};
|
|
88
|
-
} else if (data.comments) {
|
|
89
|
-
return {
|
|
90
|
-
comments: data.comments,
|
|
91
|
-
total: data.total || 0,
|
|
92
|
-
hasMore: data.hasMore || false,
|
|
93
|
-
nextCursor: data.nextCursor || null
|
|
94
|
-
};
|
|
95
|
-
} else if (Array.isArray(data)) {
|
|
96
|
-
return {
|
|
97
|
-
comments: data,
|
|
98
|
-
total: data.length,
|
|
99
|
-
hasMore: false,
|
|
100
|
-
nextCursor: null
|
|
101
|
-
};
|
|
138
|
+
return parseResponse(response);
|
|
139
|
+
}
|
|
140
|
+
if (response.status === 422) {
|
|
141
|
+
const fallback = await this.axios.get(commentsUrl, { params: { limit: reqLimit, sort: 'popular' } });
|
|
142
|
+
if (fallback.status === 200) {
|
|
143
|
+
return parseResponse(fallback);
|
|
102
144
|
}
|
|
103
|
-
|
|
104
|
-
} else {
|
|
105
|
-
console.error(`Ошибка получения комментариев: ${response.status}`);
|
|
106
|
-
return { comments: [], total: 0, hasMore: false, nextCursor: null };
|
|
145
|
+
console.warn('⚠️ GET /api/posts/:postId/comments: 422. API ожидает sort: newest | oldest | popular.');
|
|
107
146
|
}
|
|
147
|
+
console.error(`Ошибка получения комментариев: ${response.status}`);
|
|
148
|
+
return { comments: [], total: 0, hasMore: false, nextCursor: null };
|
|
108
149
|
} catch (error) {
|
|
150
|
+
if (error.response?.status === 422) {
|
|
151
|
+
try {
|
|
152
|
+
const retry = await this.axios.get(commentsUrl, { params: { limit: 20, sort: 'popular' } });
|
|
153
|
+
if (retry.status === 200) {
|
|
154
|
+
return parseResponse(retry);
|
|
155
|
+
}
|
|
156
|
+
} catch (_) {}
|
|
157
|
+
}
|
|
109
158
|
console.error('Исключение при получении комментариев:', error.message);
|
|
110
159
|
if (error.response) {
|
|
111
160
|
console.error('Response status:', error.response.status);
|
package/src/files.js
CHANGED
|
@@ -11,8 +11,9 @@ export class FilesManager {
|
|
|
11
11
|
}
|
|
12
12
|
|
|
13
13
|
/**
|
|
14
|
-
* Загружает файл (изображение) на
|
|
15
|
-
*
|
|
14
|
+
* Загружает файл (изображение) на сервер.
|
|
15
|
+
* Таймаут — client.uploadTimeout (по умолчанию 120 с). При ошибке возвращает null.
|
|
16
|
+
*
|
|
16
17
|
* @param {string} filePath - Путь к файлу
|
|
17
18
|
* @returns {Promise<Object|null>} { id, url, filename, mimeType, size } или null при ошибке
|
|
18
19
|
*/
|
|
@@ -36,6 +37,7 @@ export class FilesManager {
|
|
|
36
37
|
formData.append('file', fs.createReadStream(filePath));
|
|
37
38
|
|
|
38
39
|
const response = await this.axios.post(uploadUrl, formData, {
|
|
40
|
+
timeout: this.client.uploadTimeout ?? 120000,
|
|
39
41
|
headers: {
|
|
40
42
|
...formData.getHeaders(),
|
|
41
43
|
}
|
package/src/posts.js
CHANGED
|
@@ -16,8 +16,10 @@ export class PostsManager {
|
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
/**
|
|
19
|
-
* Создает новый
|
|
20
|
-
*
|
|
19
|
+
* Создает новый пост.
|
|
20
|
+
* При любой ошибке (сеть, 5xx, 429, не удалось загрузить файл) возвращает null.
|
|
21
|
+
* Таймаут загрузки и создания — client.uploadTimeout (по умолчанию 120 с).
|
|
22
|
+
*
|
|
21
23
|
* @param {string} text - Текст поста
|
|
22
24
|
* @param {string|null} imagePath - Путь к изображению (опционально)
|
|
23
25
|
* @returns {Promise<Object|null>} Данные созданного поста или null при ошибке
|
|
@@ -51,9 +53,11 @@ export class PostsManager {
|
|
|
51
53
|
postData.attachmentIds = [uploadedFile.id];
|
|
52
54
|
}
|
|
53
55
|
|
|
54
|
-
// Создаем пост (с изображением или без)
|
|
55
|
-
const response = await this.axios.post(postUrl, postData
|
|
56
|
-
|
|
56
|
+
// Создаем пост (с изображением или без); увеличенный таймаут для тяжёлых запросов
|
|
57
|
+
const response = await this.axios.post(postUrl, postData, {
|
|
58
|
+
timeout: this.client.uploadTimeout ?? 120000,
|
|
59
|
+
});
|
|
60
|
+
|
|
57
61
|
if (response.status === 200 || response.status === 201) {
|
|
58
62
|
return response.data;
|
|
59
63
|
} else {
|
|
@@ -71,8 +75,9 @@ export class PostsManager {
|
|
|
71
75
|
}
|
|
72
76
|
|
|
73
77
|
/**
|
|
74
|
-
* Создает пост на стене другого пользователя (wall post)
|
|
75
|
-
*
|
|
78
|
+
* Создает пост на стене другого пользователя (wall post).
|
|
79
|
+
* При любой ошибке возвращает null. Таймаут — client.uploadTimeout (по умолчанию 120 с).
|
|
80
|
+
*
|
|
76
81
|
* @param {string} username - Имя пользователя, на чью стену нужно написать
|
|
77
82
|
* @param {string} text - Текст поста
|
|
78
83
|
* @param {string|null} imagePath - Путь к изображению (опционально)
|
|
@@ -117,9 +122,11 @@ export class PostsManager {
|
|
|
117
122
|
postData.attachmentIds = [uploadedFile.id];
|
|
118
123
|
}
|
|
119
124
|
|
|
120
|
-
// Создаем пост на
|
|
121
|
-
const response = await this.axios.post(postUrl, postData
|
|
122
|
-
|
|
125
|
+
// Создаем пост на стене; увеличенный таймаут для тяжёлых запросов
|
|
126
|
+
const response = await this.axios.post(postUrl, postData, {
|
|
127
|
+
timeout: this.client.uploadTimeout ?? 120000,
|
|
128
|
+
});
|
|
129
|
+
|
|
123
130
|
if (response.status === 200 || response.status === 201) {
|
|
124
131
|
return response.data;
|
|
125
132
|
} else {
|
package/src/users.js
CHANGED
|
@@ -295,9 +295,10 @@ export class UsersManager {
|
|
|
295
295
|
}
|
|
296
296
|
|
|
297
297
|
/**
|
|
298
|
-
* Получает топ кланов по количеству
|
|
299
|
-
*
|
|
300
|
-
*
|
|
298
|
+
* Получает топ кланов по количеству участников.
|
|
299
|
+
* Возвращает массив (Array), не объект с полем clans.
|
|
300
|
+
*
|
|
301
|
+
* @returns {Promise<Array|null>} Массив кланов [{ avatar, memberCount }, ...] или null при ошибке
|
|
301
302
|
*/
|
|
302
303
|
async getTopClans() {
|
|
303
304
|
try {
|