itd-api 0.0.3 → 0.0.5
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 +133 -25
- package/dist/{chunk-JIT55WDH.js → chunk-RUPF4X5L.js} +351 -184
- package/dist/chunk-RUPF4X5L.js.map +1 -0
- package/dist/{chunk-3ODOEKQO.cjs → chunk-YM2YUO4D.cjs} +364 -183
- package/dist/chunk-YM2YUO4D.cjs.map +1 -0
- package/dist/{index-BCuk8jNA.d.cts → index-Dv0LXpMf.d.cts} +216 -42
- package/dist/{index-BCuk8jNA.d.ts → index-Dv0LXpMf.d.ts} +216 -42
- package/dist/index.cjs +126 -70
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/node.cjs +125 -69
- package/dist/node.cjs.map +1 -1
- package/dist/node.d.cts +8 -12
- package/dist/node.d.ts +8 -12
- package/dist/node.js +2 -2
- package/dist/node.js.map +1 -1
- package/package.json +7 -3
- package/dist/chunk-3ODOEKQO.cjs.map +0 -1
- package/dist/chunk-JIT55WDH.js.map +0 -1
|
@@ -16,6 +16,30 @@ function resolveInput(input, factory, validate) {
|
|
|
16
16
|
|
|
17
17
|
// src/core/errors.ts
|
|
18
18
|
var ITD_ERROR = /* @__PURE__ */ Symbol.for("itd.error");
|
|
19
|
+
var ItdErrorKind = Object.freeze({
|
|
20
|
+
/** Сервер ответил статусом ≥ 400. */
|
|
21
|
+
Api: "api",
|
|
22
|
+
/** Запрос не дошёл до сервера. */
|
|
23
|
+
Network: "network",
|
|
24
|
+
/** Истёк таймаут запроса. */
|
|
25
|
+
Timeout: "timeout",
|
|
26
|
+
/** Запрос отменён через `AbortSignal`. */
|
|
27
|
+
Abort: "abort",
|
|
28
|
+
/** Некорректная конфигурация или аргументы — обнаружено до обращения к сети. */
|
|
29
|
+
Config: "config"
|
|
30
|
+
});
|
|
31
|
+
var ItdApiErrorKind = Object.freeze({
|
|
32
|
+
/** Ни одна из специализаций не подошла. */
|
|
33
|
+
Generic: "generic",
|
|
34
|
+
Validation: "validation",
|
|
35
|
+
Auth: "auth",
|
|
36
|
+
Forbidden: "forbidden",
|
|
37
|
+
NotFound: "not_found",
|
|
38
|
+
Conflict: "conflict",
|
|
39
|
+
RateLimit: "rate_limit",
|
|
40
|
+
PhoneVerification: "phone_verification",
|
|
41
|
+
Server: "server"
|
|
42
|
+
});
|
|
19
43
|
var ItdError = class extends Error {
|
|
20
44
|
/** @internal */
|
|
21
45
|
[ITD_ERROR] = true;
|
|
@@ -28,6 +52,13 @@ var ItdError = class extends Error {
|
|
|
28
52
|
}
|
|
29
53
|
};
|
|
30
54
|
var ItdApiError = class extends ItdError {
|
|
55
|
+
/**
|
|
56
|
+
* Разновидность ошибки: та же информация, что и класс, но пригодная для сравнения.
|
|
57
|
+
*
|
|
58
|
+
* Позволяет разбирать ошибку через `switch`, а проверкам вроде {@link isItdAuthError} —
|
|
59
|
+
* работать даже когда в проекте оказались две копии библиотеки.
|
|
60
|
+
*/
|
|
61
|
+
apiKind;
|
|
31
62
|
/** HTTP-статус ответа. */
|
|
32
63
|
status;
|
|
33
64
|
/** Строковый код ошибки, например `VALIDATION_ERROR`. */
|
|
@@ -58,9 +89,13 @@ var ItdApiError = class extends ItdError {
|
|
|
58
89
|
rateLimit;
|
|
59
90
|
/** Сколько запросов осталось в окне — заголовок `x-ratelimit-remaining`. */
|
|
60
91
|
rateLimitRemaining;
|
|
61
|
-
|
|
62
|
-
|
|
92
|
+
/**
|
|
93
|
+
* @param apiKind разновидность; подставляется подклассами, снаружи задавать не нужно
|
|
94
|
+
*/
|
|
95
|
+
constructor(init, apiKind = ItdApiErrorKind.Generic) {
|
|
96
|
+
super(ItdErrorKind.Api, init.message);
|
|
63
97
|
this.name = "ItdApiError";
|
|
98
|
+
this.apiKind = apiKind;
|
|
64
99
|
this.status = init.status;
|
|
65
100
|
this.code = init.code;
|
|
66
101
|
this.detail = init.detail;
|
|
@@ -93,37 +128,37 @@ var ItdApiError = class extends ItdError {
|
|
|
93
128
|
};
|
|
94
129
|
var ItdValidationError = class extends ItdApiError {
|
|
95
130
|
constructor(init) {
|
|
96
|
-
super(init);
|
|
131
|
+
super(init, ItdApiErrorKind.Validation);
|
|
97
132
|
this.name = "ItdValidationError";
|
|
98
133
|
}
|
|
99
134
|
};
|
|
100
135
|
var ItdAuthError = class extends ItdApiError {
|
|
101
136
|
constructor(init) {
|
|
102
|
-
super(init);
|
|
137
|
+
super(init, ItdApiErrorKind.Auth);
|
|
103
138
|
this.name = "ItdAuthError";
|
|
104
139
|
}
|
|
105
140
|
};
|
|
106
141
|
var ItdForbiddenError = class extends ItdApiError {
|
|
107
142
|
constructor(init) {
|
|
108
|
-
super(init);
|
|
143
|
+
super(init, ItdApiErrorKind.Forbidden);
|
|
109
144
|
this.name = "ItdForbiddenError";
|
|
110
145
|
}
|
|
111
146
|
};
|
|
112
147
|
var ItdNotFoundError = class extends ItdApiError {
|
|
113
148
|
constructor(init) {
|
|
114
|
-
super(init);
|
|
149
|
+
super(init, ItdApiErrorKind.NotFound);
|
|
115
150
|
this.name = "ItdNotFoundError";
|
|
116
151
|
}
|
|
117
152
|
};
|
|
118
153
|
var ItdConflictError = class extends ItdApiError {
|
|
119
154
|
constructor(init) {
|
|
120
|
-
super(init);
|
|
155
|
+
super(init, ItdApiErrorKind.Conflict);
|
|
121
156
|
this.name = "ItdConflictError";
|
|
122
157
|
}
|
|
123
158
|
};
|
|
124
159
|
var ItdRateLimitError = class extends ItdApiError {
|
|
125
160
|
constructor(init) {
|
|
126
|
-
super(init);
|
|
161
|
+
super(init, ItdApiErrorKind.RateLimit);
|
|
127
162
|
this.name = "ItdRateLimitError";
|
|
128
163
|
}
|
|
129
164
|
};
|
|
@@ -131,14 +166,14 @@ var ItdPhoneVerificationError = class extends ItdApiError {
|
|
|
131
166
|
/** Ссылка на бота подтверждения, если удалось определить идентификатор пользователя. */
|
|
132
167
|
verificationUrl;
|
|
133
168
|
constructor(init) {
|
|
134
|
-
super(init);
|
|
169
|
+
super(init, ItdApiErrorKind.PhoneVerification);
|
|
135
170
|
this.name = "ItdPhoneVerificationError";
|
|
136
171
|
this.verificationUrl = init.userId ? `https://t.me/itd_verification_bot?start=${encodeURIComponent(init.userId)}` : void 0;
|
|
137
172
|
}
|
|
138
173
|
};
|
|
139
174
|
var ItdServerError = class extends ItdApiError {
|
|
140
175
|
constructor(init) {
|
|
141
|
-
super(init);
|
|
176
|
+
super(init, ItdApiErrorKind.Server);
|
|
142
177
|
this.name = "ItdServerError";
|
|
143
178
|
}
|
|
144
179
|
};
|
|
@@ -148,7 +183,7 @@ var ItdNetworkError = class extends ItdError {
|
|
|
148
183
|
/** Путь запроса без базового URL. */
|
|
149
184
|
path;
|
|
150
185
|
constructor(message, init) {
|
|
151
|
-
super(
|
|
186
|
+
super(ItdErrorKind.Network, message, { cause: init.cause });
|
|
152
187
|
this.name = "ItdNetworkError";
|
|
153
188
|
this.method = init.method;
|
|
154
189
|
this.path = init.path;
|
|
@@ -162,7 +197,10 @@ var ItdTimeoutError = class extends ItdError {
|
|
|
162
197
|
/** Путь запроса без базового URL. */
|
|
163
198
|
path;
|
|
164
199
|
constructor(init) {
|
|
165
|
-
super(
|
|
200
|
+
super(
|
|
201
|
+
ItdErrorKind.Timeout,
|
|
202
|
+
`\u0417\u0430\u043F\u0440\u043E\u0441 ${init.method} ${init.path} \u043F\u0440\u0435\u0432\u044B\u0441\u0438\u043B \u0442\u0430\u0439\u043C\u0430\u0443\u0442 ${init.timeout} \u043C\u0441`
|
|
203
|
+
);
|
|
166
204
|
this.name = "ItdTimeoutError";
|
|
167
205
|
this.timeout = init.timeout;
|
|
168
206
|
this.method = init.method;
|
|
@@ -171,13 +209,13 @@ var ItdTimeoutError = class extends ItdError {
|
|
|
171
209
|
};
|
|
172
210
|
var ItdAbortError = class extends ItdError {
|
|
173
211
|
constructor(message = "\u0417\u0430\u043F\u0440\u043E\u0441 \u043E\u0442\u043C\u0435\u043D\u0451\u043D") {
|
|
174
|
-
super(
|
|
212
|
+
super(ItdErrorKind.Abort, message);
|
|
175
213
|
this.name = "ItdAbortError";
|
|
176
214
|
}
|
|
177
215
|
};
|
|
178
216
|
var ItdConfigError = class extends ItdError {
|
|
179
217
|
constructor(message) {
|
|
180
|
-
super(
|
|
218
|
+
super(ItdErrorKind.Config, message);
|
|
181
219
|
this.name = "ItdConfigError";
|
|
182
220
|
}
|
|
183
221
|
};
|
|
@@ -185,16 +223,34 @@ function isItdError(value) {
|
|
|
185
223
|
return typeof value === "object" && value !== null && ITD_ERROR in value;
|
|
186
224
|
}
|
|
187
225
|
function isItdApiError(value) {
|
|
188
|
-
return isItdError(value) && value.kind ===
|
|
226
|
+
return isItdError(value) && value.kind === ItdErrorKind.Api;
|
|
227
|
+
}
|
|
228
|
+
function hasApiKind(value, kind) {
|
|
229
|
+
return isItdApiError(value) && value.apiKind === kind;
|
|
189
230
|
}
|
|
190
231
|
function isItdValidationError(value) {
|
|
191
|
-
return
|
|
232
|
+
return hasApiKind(value, ItdApiErrorKind.Validation);
|
|
192
233
|
}
|
|
193
234
|
function isItdAuthError(value) {
|
|
194
|
-
return
|
|
235
|
+
return hasApiKind(value, ItdApiErrorKind.Auth);
|
|
236
|
+
}
|
|
237
|
+
function isItdForbiddenError(value) {
|
|
238
|
+
return hasApiKind(value, ItdApiErrorKind.Forbidden);
|
|
239
|
+
}
|
|
240
|
+
function isItdNotFoundError(value) {
|
|
241
|
+
return hasApiKind(value, ItdApiErrorKind.NotFound);
|
|
242
|
+
}
|
|
243
|
+
function isItdConflictError(value) {
|
|
244
|
+
return hasApiKind(value, ItdApiErrorKind.Conflict);
|
|
195
245
|
}
|
|
196
246
|
function isItdRateLimitError(value) {
|
|
197
|
-
return
|
|
247
|
+
return hasApiKind(value, ItdApiErrorKind.RateLimit);
|
|
248
|
+
}
|
|
249
|
+
function isItdPhoneVerificationError(value) {
|
|
250
|
+
return hasApiKind(value, ItdApiErrorKind.PhoneVerification);
|
|
251
|
+
}
|
|
252
|
+
function isItdServerError(value) {
|
|
253
|
+
return hasApiKind(value, ItdApiErrorKind.Server);
|
|
198
254
|
}
|
|
199
255
|
|
|
200
256
|
// src/builders/comment.ts
|
|
@@ -624,13 +680,14 @@ var ItdErrorCode = Object.freeze({
|
|
|
624
680
|
|
|
625
681
|
// src/builders/report.ts
|
|
626
682
|
var REASONS = new Set(Object.values(ReportReason));
|
|
683
|
+
var TARGET_TYPES = new Set(Object.values(ReportTargetType));
|
|
627
684
|
function validateReport(input) {
|
|
628
685
|
if (!input?.targetId || typeof input.targetId !== "string") {
|
|
629
686
|
throw new ItdConfigError("\u0416\u0430\u043B\u043E\u0431\u0430 \u0442\u0440\u0435\u0431\u0443\u0435\u0442 \u0438\u0434\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0442\u043E\u0440 \u043E\u0431\u044A\u0435\u043A\u0442\u0430 (targetId)");
|
|
630
687
|
}
|
|
631
|
-
if (
|
|
688
|
+
if (!TARGET_TYPES.has(input.targetType)) {
|
|
632
689
|
throw new ItdConfigError(
|
|
633
|
-
`targetType \u0434\u043E\u043B\u0436\u0435\u043D \u0431\u044B\u0442\u044C
|
|
690
|
+
`targetType \u0434\u043E\u043B\u0436\u0435\u043D \u0431\u044B\u0442\u044C \u043E\u0434\u043D\u0438\u043C \u0438\u0437 ${[...TARGET_TYPES].join(", ")}, \u043F\u043E\u043B\u0443\u0447\u0435\u043D\u043E: ${String(input.targetType)}`
|
|
634
691
|
);
|
|
635
692
|
}
|
|
636
693
|
if (!REASONS.has(input.reason)) {
|
|
@@ -668,11 +725,11 @@ function start(targetType, targetId) {
|
|
|
668
725
|
}
|
|
669
726
|
var report = Object.freeze({
|
|
670
727
|
/** Жалоба на пост. */
|
|
671
|
-
post: (postId) => start(
|
|
728
|
+
post: (postId) => start(ReportTargetType.Post, postId),
|
|
672
729
|
/** Жалоба на комментарий. */
|
|
673
|
-
comment: (commentId) => start(
|
|
730
|
+
comment: (commentId) => start(ReportTargetType.Comment, commentId),
|
|
674
731
|
/** Жалоба на пользователя. */
|
|
675
|
-
user: (userId) => start(
|
|
732
|
+
user: (userId) => start(ReportTargetType.User, userId)
|
|
676
733
|
});
|
|
677
734
|
function resolveReport(input) {
|
|
678
735
|
return resolveInput(input, () => new ReportBuilder({}), validateReport);
|
|
@@ -1101,21 +1158,35 @@ var Emitter = class {
|
|
|
1101
1158
|
};
|
|
1102
1159
|
|
|
1103
1160
|
// src/core/runtime.ts
|
|
1161
|
+
var RuntimeMode = Object.freeze({
|
|
1162
|
+
/** Определяется по среде исполнения. Значение по умолчанию. */
|
|
1163
|
+
Auto: "auto",
|
|
1164
|
+
/** Cookie ведёт браузер, запросы уходят с `credentials: 'include'`. */
|
|
1165
|
+
Browser: "browser",
|
|
1166
|
+
/** Cookie ведёт встроенный jar, заголовок `Cookie` подставляется вручную. */
|
|
1167
|
+
Server: "server"
|
|
1168
|
+
});
|
|
1169
|
+
var DetectedRuntime = Object.freeze({
|
|
1170
|
+
Browser: "browser",
|
|
1171
|
+
/** Есть `window`, но нет `document`; cookie ведёт нативный сетевой слой. */
|
|
1172
|
+
ReactNative: "react-native",
|
|
1173
|
+
Server: "server"
|
|
1174
|
+
});
|
|
1104
1175
|
function detectRuntime() {
|
|
1105
1176
|
const nav = globalThis.navigator;
|
|
1106
|
-
if (nav?.product === "ReactNative") return
|
|
1107
|
-
if (typeof document !== "undefined") return
|
|
1108
|
-
return
|
|
1177
|
+
if (nav?.product === "ReactNative") return DetectedRuntime.ReactNative;
|
|
1178
|
+
if (typeof document !== "undefined") return DetectedRuntime.Browser;
|
|
1179
|
+
return DetectedRuntime.Server;
|
|
1109
1180
|
}
|
|
1110
1181
|
function shouldUseCookieJar(mode) {
|
|
1111
|
-
if (mode ===
|
|
1112
|
-
if (mode ===
|
|
1113
|
-
return detectRuntime() ===
|
|
1182
|
+
if (mode === RuntimeMode.Browser) return false;
|
|
1183
|
+
if (mode === RuntimeMode.Server) return true;
|
|
1184
|
+
return detectRuntime() === DetectedRuntime.Server;
|
|
1114
1185
|
}
|
|
1115
1186
|
function shouldSendCredentials(mode) {
|
|
1116
|
-
if (mode ===
|
|
1117
|
-
if (mode ===
|
|
1118
|
-
return detectRuntime() ===
|
|
1187
|
+
if (mode === RuntimeMode.Browser) return true;
|
|
1188
|
+
if (mode === RuntimeMode.Server) return false;
|
|
1189
|
+
return detectRuntime() === DetectedRuntime.Browser;
|
|
1119
1190
|
}
|
|
1120
1191
|
function resolveFetch(custom) {
|
|
1121
1192
|
if (custom) return custom;
|
|
@@ -1126,6 +1197,12 @@ function resolveFetch(custom) {
|
|
|
1126
1197
|
"\u0412 \u044D\u0442\u043E\u0439 \u0441\u0440\u0435\u0434\u0435 \u043D\u0435\u0442 \u0433\u043B\u043E\u0431\u0430\u043B\u044C\u043D\u043E\u0433\u043E fetch. \u041E\u0431\u043D\u043E\u0432\u0438\u0442\u0435\u0441\u044C \u0434\u043E Node 18+ \u043B\u0438\u0431\u043E \u043F\u0435\u0440\u0435\u0434\u0430\u0439\u0442\u0435 \u0441\u0432\u043E\u044E \u0440\u0435\u0430\u043B\u0438\u0437\u0430\u0446\u0438\u044E \u0447\u0435\u0440\u0435\u0437 \u043E\u043F\u0446\u0438\u044E fetch."
|
|
1127
1198
|
);
|
|
1128
1199
|
}
|
|
1200
|
+
function isBlob(value) {
|
|
1201
|
+
return typeof Blob !== "undefined" && value instanceof Blob;
|
|
1202
|
+
}
|
|
1203
|
+
function isFile(value) {
|
|
1204
|
+
return typeof File !== "undefined" && value instanceof File;
|
|
1205
|
+
}
|
|
1129
1206
|
function supportsStreamingBody() {
|
|
1130
1207
|
return typeof ReadableStream !== "undefined" && typeof TextDecoder !== "undefined";
|
|
1131
1208
|
}
|
|
@@ -1200,11 +1277,19 @@ var AuthManager = class {
|
|
|
1200
1277
|
/**
|
|
1201
1278
|
* Есть ли признак живой refresh-сессии.
|
|
1202
1279
|
*
|
|
1203
|
-
*
|
|
1204
|
-
*
|
|
1280
|
+
* Рядом с refresh-токеном сервер ставит незакрытую cookie `is_auth` — по ней видно,
|
|
1281
|
+
* что продлевать сессию вообще есть смысл, и API не дёргается у анонимов.
|
|
1205
1282
|
* В браузере cookie ведёт сама среда, поэтому там ответ всегда `true`.
|
|
1283
|
+
*
|
|
1284
|
+
* Асинхронный, потому что признак может лежать в {@link TokenStorage}: до чтения оттуда
|
|
1285
|
+
* ответ был бы `false` даже при полностью рабочей сохранённой сессии.
|
|
1206
1286
|
*/
|
|
1207
|
-
hasRefreshSession() {
|
|
1287
|
+
async hasRefreshSession() {
|
|
1288
|
+
await this.#loadSession();
|
|
1289
|
+
return this.#hasRefreshSession();
|
|
1290
|
+
}
|
|
1291
|
+
/** То же самое, но без чтения хранилища — для вызовов, где сессия уже загружена. */
|
|
1292
|
+
#hasRefreshSession() {
|
|
1208
1293
|
if (!this.#config.useCookieJar) return true;
|
|
1209
1294
|
if (this.#jar.has(AUTH_FLAG_COOKIE)) return true;
|
|
1210
1295
|
return Boolean(this.#session?.refreshToken);
|
|
@@ -1390,7 +1475,7 @@ var AuthManager = class {
|
|
|
1390
1475
|
}
|
|
1391
1476
|
async #performRefresh() {
|
|
1392
1477
|
await this.#loadSession();
|
|
1393
|
-
if (!this
|
|
1478
|
+
if (!this.#hasRefreshSession()) {
|
|
1394
1479
|
return this.#reloginOrNull();
|
|
1395
1480
|
}
|
|
1396
1481
|
try {
|
|
@@ -1401,7 +1486,10 @@ var AuthManager = class {
|
|
|
1401
1486
|
// #seedRefreshCookie. По той же причине не нужен и устаревший Bearer.
|
|
1402
1487
|
skipAuth: true,
|
|
1403
1488
|
// Без этого 401 на самом обновлении вызвал бы новое обновление — и так по кругу.
|
|
1404
|
-
skipAuthRefresh: true
|
|
1489
|
+
skipAuthRefresh: true,
|
|
1490
|
+
// Обновление почти всегда запускается изнутри запроса, который занимает место
|
|
1491
|
+
// в очереди и ждёт его результата. Встать в ту же очередь — значит зависнуть.
|
|
1492
|
+
skipQueue: true
|
|
1405
1493
|
});
|
|
1406
1494
|
const accessToken = readAccessToken(payload);
|
|
1407
1495
|
if (!accessToken) return this.#reloginOrNull();
|
|
@@ -1468,7 +1556,7 @@ var AuthManager = class {
|
|
|
1468
1556
|
}
|
|
1469
1557
|
if (credentials.turnstileToken) return credentials.turnstileToken;
|
|
1470
1558
|
throw new ItdConfigError(
|
|
1471
|
-
"\u0412\u0445\u043E\u0434 \u043F\u043E email \u0438 \u043F\u0430\u0440\u043E\u043B\u044E \u0442\u0440\u0435\u0431\u0443\u0435\u0442 \u0442\u043E\u043A\u0435\u043D \u043A\u0430\u043F\u0447\u0438 Cloudflare Turnstile: \u0431\u0435\u0437 \u043D\u0435\u0433\u043E \u0441\u0435\u0440\u0432\u0435\u0440 \u043E\u0442\u0432\u0435\u0447\u0430\u0435\u0442 422. \u041F\u0435\u0440\u0435\u0434\u0430\u0439\u0442\u0435 auth.getTurnstileToken (\u0438\u0441\u0442\u043E\u0447\u043D\u0438\u043A \u0441\u0432\u0435\u0436\u0435\u0433\u043E \u0442\u043E\u043A\u0435\u043D\u0430) \u043B\u0438\u0431\u043E \u0440\u0430\u0437\u043E\u0432\u044B\u0439 auth.turnstileToken. \u041A\u043B\u044E\u0447 \u0432\u0438\u0434\u0436\u0435\u0442\u0430 \u2014 TURNSTILE_SITE_KEY."
|
|
1559
|
+
"\u0412\u0445\u043E\u0434 \u043F\u043E email \u0438 \u043F\u0430\u0440\u043E\u043B\u044E \u0442\u0440\u0435\u0431\u0443\u0435\u0442 \u0442\u043E\u043A\u0435\u043D \u043A\u0430\u043F\u0447\u0438 Cloudflare Turnstile: \u0431\u0435\u0437 \u043D\u0435\u0433\u043E \u0441\u0435\u0440\u0432\u0435\u0440 \u043E\u0442\u0432\u0435\u0447\u0430\u0435\u0442 422. \u041F\u0435\u0440\u0435\u0434\u0430\u0439\u0442\u0435 auth.getTurnstileToken (\u0438\u0441\u0442\u043E\u0447\u043D\u0438\u043A \u0441\u0432\u0435\u0436\u0435\u0433\u043E \u0442\u043E\u043A\u0435\u043D\u0430) \u043B\u0438\u0431\u043E \u0440\u0430\u0437\u043E\u0432\u044B\u0439 auth.turnstileToken. \u041A\u043B\u044E\u0447 \u0432\u0438\u0434\u0436\u0435\u0442\u0430 \u2014 TURNSTILE_SITE_KEY. \u0412 Node \u0442\u043E\u043A\u0435\u043D \u0443\u043C\u0435\u0435\u0442 \u0434\u043E\u0431\u044B\u0432\u0430\u0442\u044C \u043E\u0442\u0434\u0435\u043B\u044C\u043D\u044B\u0439 \u043F\u0430\u043A\u0435\u0442: npm i itd-api-turnstile, \u0437\u0430\u0442\u0435\u043C getTurnstileToken: createTurnstileSolver()."
|
|
1472
1560
|
);
|
|
1473
1561
|
}
|
|
1474
1562
|
async #performSignIn(credentials) {
|
|
@@ -1478,7 +1566,10 @@ var AuthManager = class {
|
|
|
1478
1566
|
path: AUTH_PATHS.signIn,
|
|
1479
1567
|
body: { email: credentials.email, password: credentials.password, turnstileToken },
|
|
1480
1568
|
skipAuth: true,
|
|
1481
|
-
skipAuthRefresh: true
|
|
1569
|
+
skipAuthRefresh: true,
|
|
1570
|
+
// Отложенный вход происходит при сборке заголовков уже начатого запроса — тот держит
|
|
1571
|
+
// место в очереди и ждёт токена. См. `skipQueue` в RawRequestOptions.
|
|
1572
|
+
skipQueue: true
|
|
1482
1573
|
});
|
|
1483
1574
|
const accessToken = readAccessToken(payload);
|
|
1484
1575
|
if (!accessToken) {
|
|
@@ -1607,7 +1698,7 @@ function normalizeBaseUrl(baseUrl) {
|
|
|
1607
1698
|
// src/core/config.ts
|
|
1608
1699
|
var DEFAULT_BASE_URL = "https://xn--d1ah4a.com";
|
|
1609
1700
|
var DEFAULT_TIMEOUT = 3e4;
|
|
1610
|
-
var LIBRARY_VERSION = "0.0.
|
|
1701
|
+
var LIBRARY_VERSION = "0.0.5";
|
|
1611
1702
|
var DEFAULT_USER_AGENT = `Mozilla/5.0 (compatible; itd-api/${LIBRARY_VERSION}; +https://github.com/KiowDev/itd-api)`;
|
|
1612
1703
|
var DEFAULT_RATE_LIMIT_DELAYS = Object.freeze([1e3, 5e3, 3e4, 6e4, 9e4]);
|
|
1613
1704
|
function requirePositive(value, name) {
|
|
@@ -1720,9 +1811,11 @@ function validateAuth(auth) {
|
|
|
1720
1811
|
);
|
|
1721
1812
|
}
|
|
1722
1813
|
function resolveConfig(options = {}) {
|
|
1723
|
-
const mode = options.mode ??
|
|
1724
|
-
if (mode
|
|
1725
|
-
throw new ItdConfigError(
|
|
1814
|
+
const mode = options.mode ?? RuntimeMode.Auto;
|
|
1815
|
+
if (!Object.values(RuntimeMode).includes(mode)) {
|
|
1816
|
+
throw new ItdConfigError(
|
|
1817
|
+
`mode \u0434\u043E\u043B\u0436\u0435\u043D \u0431\u044B\u0442\u044C \u043E\u0434\u043D\u0438\u043C \u0438\u0437 ${Object.values(RuntimeMode).join(", ")}, \u043F\u043E\u043B\u0443\u0447\u0435\u043D\u043E: ${mode}`
|
|
1818
|
+
);
|
|
1726
1819
|
}
|
|
1727
1820
|
const timeout = requirePositive(options.timeout ?? DEFAULT_TIMEOUT, "timeout");
|
|
1728
1821
|
if (options.deviceId !== void 0 && (typeof options.deviceId !== "string" || options.deviceId.trim() === "")) {
|
|
@@ -1783,7 +1876,7 @@ function redactHeaders(headers) {
|
|
|
1783
1876
|
function redactBody(body) {
|
|
1784
1877
|
if (body === null || body === void 0) return body;
|
|
1785
1878
|
if (typeof FormData !== "undefined" && body instanceof FormData) return "[FormData]";
|
|
1786
|
-
if (
|
|
1879
|
+
if (isBlob(body)) return "[Blob]";
|
|
1787
1880
|
if (body instanceof ArrayBuffer || ArrayBuffer.isView(body)) return "[binary]";
|
|
1788
1881
|
if (Array.isArray(body)) return body.map(redactBody);
|
|
1789
1882
|
if (typeof body === "object") {
|
|
@@ -1796,13 +1889,47 @@ function redactBody(body) {
|
|
|
1796
1889
|
return body;
|
|
1797
1890
|
}
|
|
1798
1891
|
|
|
1799
|
-
// src/core/
|
|
1892
|
+
// src/core/unwrap.ts
|
|
1893
|
+
function unwrapData(body) {
|
|
1894
|
+
if (typeof body !== "object" || body === null || Array.isArray(body)) return body;
|
|
1895
|
+
const keys = Object.keys(body);
|
|
1896
|
+
if (keys.length !== 1 || keys[0] !== "data") return body;
|
|
1897
|
+
return body.data;
|
|
1898
|
+
}
|
|
1800
1899
|
function isRecord(value) {
|
|
1801
1900
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1802
1901
|
}
|
|
1803
1902
|
function asString(value) {
|
|
1804
1903
|
return typeof value === "string" && value.length > 0 ? value : void 0;
|
|
1805
1904
|
}
|
|
1905
|
+
function pickArray(source, field) {
|
|
1906
|
+
if (typeof source !== "object" || source === null) return [];
|
|
1907
|
+
const value = source[field];
|
|
1908
|
+
return Array.isArray(value) ? value : [];
|
|
1909
|
+
}
|
|
1910
|
+
function pickObject(source, field) {
|
|
1911
|
+
if (typeof source !== "object" || source === null) return void 0;
|
|
1912
|
+
const value = source[field];
|
|
1913
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) return void 0;
|
|
1914
|
+
return value;
|
|
1915
|
+
}
|
|
1916
|
+
function pickBoolean(source, field, fallback = false) {
|
|
1917
|
+
if (typeof source !== "object" || source === null) return fallback;
|
|
1918
|
+
const value = source[field];
|
|
1919
|
+
return typeof value === "boolean" ? value : fallback;
|
|
1920
|
+
}
|
|
1921
|
+
function pickNumber(source, field, fallback) {
|
|
1922
|
+
if (typeof source !== "object" || source === null) return fallback;
|
|
1923
|
+
const value = source[field];
|
|
1924
|
+
return typeof value === "number" && Number.isFinite(value) ? value : fallback;
|
|
1925
|
+
}
|
|
1926
|
+
function pickString(source, field) {
|
|
1927
|
+
if (typeof source !== "object" || source === null) return void 0;
|
|
1928
|
+
const value = source[field];
|
|
1929
|
+
return typeof value === "string" && value.length > 0 ? value : void 0;
|
|
1930
|
+
}
|
|
1931
|
+
|
|
1932
|
+
// src/core/error-factory.ts
|
|
1806
1933
|
function collectFieldErrors(source) {
|
|
1807
1934
|
const result = {};
|
|
1808
1935
|
const errors = source.errors;
|
|
@@ -1962,40 +2089,6 @@ function createApiError(context) {
|
|
|
1962
2089
|
return new Ctor(init);
|
|
1963
2090
|
}
|
|
1964
2091
|
|
|
1965
|
-
// src/core/unwrap.ts
|
|
1966
|
-
function unwrapData(body) {
|
|
1967
|
-
if (typeof body !== "object" || body === null || Array.isArray(body)) return body;
|
|
1968
|
-
const keys = Object.keys(body);
|
|
1969
|
-
if (keys.length !== 1 || keys[0] !== "data") return body;
|
|
1970
|
-
return body.data;
|
|
1971
|
-
}
|
|
1972
|
-
function pickArray(source, field) {
|
|
1973
|
-
if (typeof source !== "object" || source === null) return [];
|
|
1974
|
-
const value = source[field];
|
|
1975
|
-
return Array.isArray(value) ? value : [];
|
|
1976
|
-
}
|
|
1977
|
-
function pickObject(source, field) {
|
|
1978
|
-
if (typeof source !== "object" || source === null) return void 0;
|
|
1979
|
-
const value = source[field];
|
|
1980
|
-
if (typeof value !== "object" || value === null || Array.isArray(value)) return void 0;
|
|
1981
|
-
return value;
|
|
1982
|
-
}
|
|
1983
|
-
function pickBoolean(source, field, fallback = false) {
|
|
1984
|
-
if (typeof source !== "object" || source === null) return fallback;
|
|
1985
|
-
const value = source[field];
|
|
1986
|
-
return typeof value === "boolean" ? value : fallback;
|
|
1987
|
-
}
|
|
1988
|
-
function pickNumber(source, field, fallback) {
|
|
1989
|
-
if (typeof source !== "object" || source === null) return fallback;
|
|
1990
|
-
const value = source[field];
|
|
1991
|
-
return typeof value === "number" && Number.isFinite(value) ? value : fallback;
|
|
1992
|
-
}
|
|
1993
|
-
function pickString(source, field) {
|
|
1994
|
-
if (typeof source !== "object" || source === null) return void 0;
|
|
1995
|
-
const value = source[field];
|
|
1996
|
-
return typeof value === "string" && value.length > 0 ? value : void 0;
|
|
1997
|
-
}
|
|
1998
|
-
|
|
1999
2092
|
// src/core/http.ts
|
|
2000
2093
|
function sleep(ms) {
|
|
2001
2094
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
@@ -2011,7 +2104,7 @@ function setHeader(headers, name, value) {
|
|
|
2011
2104
|
}
|
|
2012
2105
|
function isRawBody(body) {
|
|
2013
2106
|
if (typeof body !== "object" || body === null) return typeof body === "string";
|
|
2014
|
-
return typeof FormData !== "undefined" && body instanceof FormData ||
|
|
2107
|
+
return typeof FormData !== "undefined" && body instanceof FormData || isBlob(body) || typeof URLSearchParams !== "undefined" && body instanceof URLSearchParams || typeof ReadableStream !== "undefined" && body instanceof ReadableStream || body instanceof ArrayBuffer || ArrayBuffer.isView(body);
|
|
2015
2108
|
}
|
|
2016
2109
|
async function readBody(response) {
|
|
2017
2110
|
if (response.status === 204 || response.status === 205) return void 0;
|
|
@@ -2081,7 +2174,8 @@ var HttpClient = class {
|
|
|
2081
2174
|
*/
|
|
2082
2175
|
async request(options) {
|
|
2083
2176
|
const task = () => this.#withRetries(options);
|
|
2084
|
-
|
|
2177
|
+
if (!this.#collaborators.schedule || options.skipQueue) return task();
|
|
2178
|
+
return this.#collaborators.schedule(task);
|
|
2085
2179
|
}
|
|
2086
2180
|
async #withRetries(options) {
|
|
2087
2181
|
const method = options.method.toUpperCase();
|
|
@@ -2350,21 +2444,15 @@ function isKnownNotificationType(type) {
|
|
|
2350
2444
|
}
|
|
2351
2445
|
|
|
2352
2446
|
// src/notifications/normalize.ts
|
|
2353
|
-
function isRecord2(value) {
|
|
2354
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
2355
|
-
}
|
|
2356
|
-
function asString2(value) {
|
|
2357
|
-
return typeof value === "string" && value.length > 0 ? value : void 0;
|
|
2358
|
-
}
|
|
2359
2447
|
function asActor(value) {
|
|
2360
|
-
if (!
|
|
2361
|
-
const id =
|
|
2448
|
+
if (!isRecord(value)) return void 0;
|
|
2449
|
+
const id = asString(value.id);
|
|
2362
2450
|
if (!id) return void 0;
|
|
2363
2451
|
return {
|
|
2364
2452
|
id,
|
|
2365
|
-
username:
|
|
2366
|
-
displayName:
|
|
2367
|
-
avatar:
|
|
2453
|
+
username: asString(value.username) ?? "",
|
|
2454
|
+
displayName: asString(value.displayName) ?? "",
|
|
2455
|
+
avatar: asString(value.avatar) ?? "",
|
|
2368
2456
|
...typeof value.isFollowing === "boolean" ? { isFollowing: value.isFollowing } : {},
|
|
2369
2457
|
...typeof value.isFollowedBy === "boolean" ? { isFollowedBy: value.isFollowedBy } : {}
|
|
2370
2458
|
};
|
|
@@ -2377,33 +2465,34 @@ function readActors(source) {
|
|
|
2377
2465
|
return single ? [single] : [];
|
|
2378
2466
|
}
|
|
2379
2467
|
function normalizeNotification(input) {
|
|
2380
|
-
const source =
|
|
2381
|
-
const payload =
|
|
2382
|
-
const rawType =
|
|
2383
|
-
const createdAt =
|
|
2384
|
-
const readAt =
|
|
2468
|
+
const source = isRecord(input) ? input : {};
|
|
2469
|
+
const payload = isRecord(source.payload) ? source.payload : source;
|
|
2470
|
+
const rawType = asString(payload.type) ?? asString(source.type) ?? "";
|
|
2471
|
+
const createdAt = asString(payload.createdAt) ?? asString(source.createdAt) ?? "";
|
|
2472
|
+
const readAt = asString(payload.readAt) ?? asString(source.readAt);
|
|
2385
2473
|
const isRead = typeof payload.isRead === "boolean" ? payload.isRead : typeof payload.read === "boolean" ? payload.read : Boolean(readAt);
|
|
2386
|
-
const subjectId =
|
|
2387
|
-
const targetId =
|
|
2474
|
+
const subjectId = asString(payload.subjectId);
|
|
2475
|
+
const targetId = asString(payload.targetId);
|
|
2388
2476
|
const subjectIsComment = payload.subjectType === "comment";
|
|
2477
|
+
const clickUrl = asString(payload.clickUrl);
|
|
2389
2478
|
return {
|
|
2390
|
-
id:
|
|
2479
|
+
id: asString(payload.id) ?? asString(source.id) ?? "",
|
|
2391
2480
|
type: canonicalNotificationType(rawType),
|
|
2392
2481
|
rawType,
|
|
2393
|
-
entityId:
|
|
2394
|
-
parentEntityId:
|
|
2482
|
+
entityId: asString(payload.entityId) ?? (subjectIsComment ? subjectId ?? targetId : targetId) ?? null,
|
|
2483
|
+
parentEntityId: asString(payload.parentEntityId) ?? (subjectIsComment ? targetId ?? null : null),
|
|
2395
2484
|
isRead,
|
|
2396
2485
|
actors: readActors(payload),
|
|
2397
2486
|
count: typeof payload.count === "number" && payload.count > 0 ? payload.count : 1,
|
|
2398
|
-
preview:
|
|
2399
|
-
...
|
|
2487
|
+
preview: asString(payload.entityPreview) ?? asString(payload.preview) ?? null,
|
|
2488
|
+
...clickUrl ? { clickUrl } : {},
|
|
2400
2489
|
createdAt,
|
|
2401
|
-
updatedAt:
|
|
2490
|
+
updatedAt: asString(payload.updatedAt) ?? readAt ?? createdAt,
|
|
2402
2491
|
raw: input
|
|
2403
2492
|
};
|
|
2404
2493
|
}
|
|
2405
2494
|
function readNotificationEvent(data) {
|
|
2406
|
-
const source =
|
|
2495
|
+
const source = isRecord(data) ? data : {};
|
|
2407
2496
|
return {
|
|
2408
2497
|
notification: normalizeNotification(data),
|
|
2409
2498
|
unreadCount: typeof source.unreadCount === "number" ? source.unreadCount : void 0,
|
|
@@ -2411,8 +2500,8 @@ function readNotificationEvent(data) {
|
|
|
2411
2500
|
};
|
|
2412
2501
|
}
|
|
2413
2502
|
function readUnreadCountEvent(data) {
|
|
2414
|
-
if (!
|
|
2415
|
-
const payload =
|
|
2503
|
+
if (!isRecord(data)) return void 0;
|
|
2504
|
+
const payload = isRecord(data.payload) ? data.payload : void 0;
|
|
2416
2505
|
if (!payload) return void 0;
|
|
2417
2506
|
return typeof payload.count === "number" ? payload.count : void 0;
|
|
2418
2507
|
}
|
|
@@ -2491,6 +2580,7 @@ var PollTransport = class {
|
|
|
2491
2580
|
}
|
|
2492
2581
|
/** Ждёт следующего опроса, прерываясь при отмене. */
|
|
2493
2582
|
#wait(signal) {
|
|
2583
|
+
if (signal.aborted) return Promise.resolve();
|
|
2494
2584
|
return new Promise((resolve) => {
|
|
2495
2585
|
const timer = setTimeout(finish, this.#interval);
|
|
2496
2586
|
function finish() {
|
|
@@ -2763,6 +2853,14 @@ var SseTransport = class {
|
|
|
2763
2853
|
};
|
|
2764
2854
|
|
|
2765
2855
|
// src/realtime/stream.ts
|
|
2856
|
+
var RealtimeTransportKind = Object.freeze({
|
|
2857
|
+
/** Поток событий, если среда умеет читать тело по частям, иначе опрос. */
|
|
2858
|
+
Auto: "auto",
|
|
2859
|
+
/** Поток `text/event-stream`. */
|
|
2860
|
+
Sse: "sse",
|
|
2861
|
+
/** Периодический опрос REST. */
|
|
2862
|
+
Poll: "poll"
|
|
2863
|
+
});
|
|
2766
2864
|
var ItdRealtime = class {
|
|
2767
2865
|
#deps;
|
|
2768
2866
|
#options;
|
|
@@ -2770,6 +2868,15 @@ var ItdRealtime = class {
|
|
|
2770
2868
|
#transport;
|
|
2771
2869
|
#maxAttempts;
|
|
2772
2870
|
#controller;
|
|
2871
|
+
/**
|
|
2872
|
+
* Хочет ли вызывающий код, чтобы соединение было живо.
|
|
2873
|
+
*
|
|
2874
|
+
* Отдельно от `#controller`, потому что тот появляется только после `await` внутри
|
|
2875
|
+
* {@link connect}. Без этого флага два вызова подряд проскочили бы проверку оба
|
|
2876
|
+
* и подняли два соединения, а `disconnect()` во время ожидания счётчика не был бы
|
|
2877
|
+
* замечен и соединение поднялось бы уже после отмены.
|
|
2878
|
+
*/
|
|
2879
|
+
#wanted = false;
|
|
2773
2880
|
#status = RealtimeStatus.Disconnected;
|
|
2774
2881
|
#attempt = 0;
|
|
2775
2882
|
#timer;
|
|
@@ -2805,7 +2912,8 @@ var ItdRealtime = class {
|
|
|
2805
2912
|
* Возвращает управление сразу после запуска: соединение живёт в фоне.
|
|
2806
2913
|
*/
|
|
2807
2914
|
async connect() {
|
|
2808
|
-
if (this.#
|
|
2915
|
+
if (this.#wanted) return;
|
|
2916
|
+
this.#wanted = true;
|
|
2809
2917
|
this.#attachEnvironmentListeners();
|
|
2810
2918
|
if (this.#options.syncCount !== false) {
|
|
2811
2919
|
try {
|
|
@@ -2814,10 +2922,11 @@ var ItdRealtime = class {
|
|
|
2814
2922
|
this.#deps.logger?.debug("\u043D\u0435 \u0443\u0434\u0430\u043B\u043E\u0441\u044C \u043F\u043E\u043B\u0443\u0447\u0438\u0442\u044C \u0447\u0438\u0441\u043B\u043E \u043D\u0435\u043F\u0440\u043E\u0447\u0438\u0442\u0430\u043D\u043D\u044B\u0445", error);
|
|
2815
2923
|
}
|
|
2816
2924
|
}
|
|
2817
|
-
this.#run();
|
|
2925
|
+
if (this.#wanted) this.#run();
|
|
2818
2926
|
}
|
|
2819
2927
|
/** Закрывает соединение и отменяет запланированные попытки. */
|
|
2820
2928
|
disconnect() {
|
|
2929
|
+
this.#wanted = false;
|
|
2821
2930
|
if (this.#timer !== void 0) {
|
|
2822
2931
|
clearTimeout(this.#timer);
|
|
2823
2932
|
this.#timer = void 0;
|
|
@@ -2834,9 +2943,9 @@ var ItdRealtime = class {
|
|
|
2834
2943
|
this.#emitter.removeAllListeners();
|
|
2835
2944
|
}
|
|
2836
2945
|
#createTransport() {
|
|
2837
|
-
const kind = this.#options.transport ??
|
|
2946
|
+
const kind = this.#options.transport ?? RealtimeTransportKind.Auto;
|
|
2838
2947
|
if (typeof kind === "object") return kind;
|
|
2839
|
-
if (kind ===
|
|
2948
|
+
if (kind === RealtimeTransportKind.Poll || kind === RealtimeTransportKind.Auto && !supportsStreamingBody()) {
|
|
2840
2949
|
return new PollTransport({
|
|
2841
2950
|
...this.#options.pollInterval !== void 0 ? { interval: this.#options.pollInterval } : {}
|
|
2842
2951
|
});
|
|
@@ -2847,6 +2956,7 @@ var ItdRealtime = class {
|
|
|
2847
2956
|
}
|
|
2848
2957
|
/** Запускает попытку подключения; повторы планирует сам. */
|
|
2849
2958
|
#run() {
|
|
2959
|
+
this.#controller?.abort();
|
|
2850
2960
|
const controller = new AbortController();
|
|
2851
2961
|
this.#controller = controller;
|
|
2852
2962
|
this.#setStatus(RealtimeStatus.Connecting);
|
|
@@ -2876,8 +2986,7 @@ var ItdRealtime = class {
|
|
|
2876
2986
|
#handleEvent(name, data) {
|
|
2877
2987
|
this.#emitter.emit("message", { name, data });
|
|
2878
2988
|
if (name === "connected") {
|
|
2879
|
-
|
|
2880
|
-
this.#emitter.emit("ready", { userId });
|
|
2989
|
+
this.#emitter.emit("ready", { userId: pickString(data, "userId") });
|
|
2881
2990
|
return;
|
|
2882
2991
|
}
|
|
2883
2992
|
if (name === "notification") {
|
|
@@ -2965,13 +3074,22 @@ var ItdRealtime = class {
|
|
|
2965
3074
|
};
|
|
2966
3075
|
|
|
2967
3076
|
// src/core/pagination.ts
|
|
3077
|
+
var PaginationMode = Object.freeze({
|
|
3078
|
+
/** Следующая страница запрашивается непрозрачным курсором. */
|
|
3079
|
+
Cursor: "cursor",
|
|
3080
|
+
/** Следующая страница запрашивается номером. */
|
|
3081
|
+
Page: "page",
|
|
3082
|
+
/** Следующая страница запрашивается смещением от начала списка. */
|
|
3083
|
+
Offset: "offset"
|
|
3084
|
+
});
|
|
2968
3085
|
function readItems(body, fields) {
|
|
2969
3086
|
if (Array.isArray(body)) return body;
|
|
2970
3087
|
for (const field of fields) {
|
|
2971
3088
|
const items = pickArray(body, field);
|
|
2972
3089
|
if (items.length > 0) return items;
|
|
2973
3090
|
}
|
|
2974
|
-
|
|
3091
|
+
const primary = fields[0];
|
|
3092
|
+
return primary === void 0 ? [] : pickArray(body, primary);
|
|
2975
3093
|
}
|
|
2976
3094
|
function readCursor(body) {
|
|
2977
3095
|
const pagination = pickObject(body, "pagination");
|
|
@@ -3030,12 +3148,13 @@ function readOffsetPage(body, field, offset) {
|
|
|
3030
3148
|
var Paginator = class {
|
|
3031
3149
|
#options;
|
|
3032
3150
|
#maxPages;
|
|
3033
|
-
#state
|
|
3151
|
+
#state;
|
|
3034
3152
|
#finished = false;
|
|
3035
3153
|
#pagesLoaded = 0;
|
|
3036
3154
|
constructor(options) {
|
|
3037
3155
|
this.#options = options;
|
|
3038
3156
|
this.#maxPages = options.maxPages ?? 1e3;
|
|
3157
|
+
this.#state = options.start ?? {};
|
|
3039
3158
|
}
|
|
3040
3159
|
/**
|
|
3041
3160
|
* Загружает следующую страницу.
|
|
@@ -3101,7 +3220,7 @@ var Paginator = class {
|
|
|
3101
3220
|
this.#finished = true;
|
|
3102
3221
|
return previous;
|
|
3103
3222
|
}
|
|
3104
|
-
if (this.#options.mode ===
|
|
3223
|
+
if (this.#options.mode === PaginationMode.Cursor) {
|
|
3105
3224
|
const cursor = page.nextCursor ?? void 0;
|
|
3106
3225
|
if (!cursor || cursor === previous.cursor) {
|
|
3107
3226
|
this.#finished = true;
|
|
@@ -3109,7 +3228,7 @@ var Paginator = class {
|
|
|
3109
3228
|
}
|
|
3110
3229
|
return { cursor };
|
|
3111
3230
|
}
|
|
3112
|
-
if (this.#options.mode ===
|
|
3231
|
+
if (this.#options.mode === PaginationMode.Page) {
|
|
3113
3232
|
return { page: (previous.page ?? 1) + 1 };
|
|
3114
3233
|
}
|
|
3115
3234
|
return { offset: page.nextOffset ?? (previous.offset ?? 0) + page.items.length };
|
|
@@ -3138,13 +3257,15 @@ var BaseResource = class {
|
|
|
3138
3257
|
*
|
|
3139
3258
|
* @param mode схема пагинации эндпоинта
|
|
3140
3259
|
* @param load загружает одну страницу для указанной позиции
|
|
3260
|
+
* @param options `maxPages` и `signal`, а также `start` — позиция, с которой продолжить
|
|
3141
3261
|
*/
|
|
3142
3262
|
paginate(mode, load, options) {
|
|
3143
3263
|
return new Paginator({
|
|
3144
3264
|
mode,
|
|
3145
3265
|
load,
|
|
3146
3266
|
...options?.maxPages !== void 0 ? { maxPages: options.maxPages } : {},
|
|
3147
|
-
...options?.signal !== void 0 ? { signal: options.signal } : {}
|
|
3267
|
+
...options?.signal !== void 0 ? { signal: options.signal } : {},
|
|
3268
|
+
...options?.start !== void 0 ? { start: options.start } : {}
|
|
3148
3269
|
});
|
|
3149
3270
|
}
|
|
3150
3271
|
};
|
|
@@ -3158,6 +3279,14 @@ function withPageState(query, state) {
|
|
|
3158
3279
|
}
|
|
3159
3280
|
|
|
3160
3281
|
// src/resources/auth.ts
|
|
3282
|
+
var OAuthProvider = Object.freeze({
|
|
3283
|
+
Yandex: "yandex",
|
|
3284
|
+
Google: "google"
|
|
3285
|
+
});
|
|
3286
|
+
var SignInStatus = Object.freeze({
|
|
3287
|
+
Authenticated: "authenticated",
|
|
3288
|
+
OtpRequired: "otp_required"
|
|
3289
|
+
});
|
|
3161
3290
|
var AuthResource = class extends BaseResource {
|
|
3162
3291
|
#auth;
|
|
3163
3292
|
constructor(http, deps) {
|
|
@@ -3206,9 +3335,9 @@ var AuthResource = class extends BaseResource {
|
|
|
3206
3335
|
const accessToken = pickString(body, "accessToken");
|
|
3207
3336
|
if (accessToken) {
|
|
3208
3337
|
await this.#auth.setAccessToken(accessToken);
|
|
3209
|
-
return { status:
|
|
3338
|
+
return { status: SignInStatus.Authenticated, accessToken };
|
|
3210
3339
|
}
|
|
3211
|
-
return { status:
|
|
3340
|
+
return { status: SignInStatus.OtpRequired, flowToken: pickString(body, "flowToken") };
|
|
3212
3341
|
}
|
|
3213
3342
|
/**
|
|
3214
3343
|
* Подтверждает вход кодом из письма.
|
|
@@ -3263,7 +3392,7 @@ var AuthResource = class extends BaseResource {
|
|
|
3263
3392
|
async signInWithOtp(input, options = {}) {
|
|
3264
3393
|
const { getOtp, ...credentials } = input;
|
|
3265
3394
|
const result = await this.signIn(credentials, options);
|
|
3266
|
-
if (result.status ===
|
|
3395
|
+
if (result.status === SignInStatus.Authenticated) return result.accessToken;
|
|
3267
3396
|
if (!result.flowToken) {
|
|
3268
3397
|
throw new ItdConfigError(
|
|
3269
3398
|
"\u0421\u0435\u0440\u0432\u0435\u0440 \u0437\u0430\u043F\u0440\u043E\u0441\u0438\u043B \u043A\u043E\u0434 \u043F\u043E\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043D\u0438\u044F, \u043D\u043E \u043D\u0435 \u0432\u0435\u0440\u043D\u0443\u043B flowToken \u2014 \u043F\u0440\u043E\u0434\u043E\u043B\u0436\u0438\u0442\u044C \u0432\u0445\u043E\u0434 \u043D\u0435\u0432\u043E\u0437\u043C\u043E\u0436\u043D\u043E"
|
|
@@ -3292,9 +3421,18 @@ var AuthResource = class extends BaseResource {
|
|
|
3292
3421
|
/**
|
|
3293
3422
|
* Есть ли признак живой сессии обновления.
|
|
3294
3423
|
*
|
|
3295
|
-
* Проверяет cookie `is_auth`, которую сервер ставит рядом с refresh
|
|
3296
|
-
* не дёргать API у неавторизованного
|
|
3297
|
-
* cookie ведёт сама среда, и прочитать её
|
|
3424
|
+
* Проверяет cookie `is_auth`, которую сервер ставит рядом с refresh-токеном, а также
|
|
3425
|
+
* refresh-токен, переданный строкой. Позволяет не дёргать API у неавторизованного
|
|
3426
|
+
* пользователя. В браузере всегда `true`: cookie ведёт сама среда, и прочитать её
|
|
3427
|
+
* из JS нельзя.
|
|
3428
|
+
*
|
|
3429
|
+
* Читает {@link TokenStorage}, поэтому результат верен и до первого запроса.
|
|
3430
|
+
*
|
|
3431
|
+
* @example
|
|
3432
|
+
* ```ts
|
|
3433
|
+
* if (await itd.auth.hasRefreshSession()) await itd.auth.refresh();
|
|
3434
|
+
* else redirectToLogin();
|
|
3435
|
+
* ```
|
|
3298
3436
|
*/
|
|
3299
3437
|
hasRefreshSession() {
|
|
3300
3438
|
return this.#auth.hasRefreshSession();
|
|
@@ -3469,7 +3607,7 @@ var CommentsResource = class extends BaseResource {
|
|
|
3469
3607
|
iterateReplies(commentId, params = {}) {
|
|
3470
3608
|
const path = `/api/comments/${encodePathSegment(commentId, "commentId")}/replies`;
|
|
3471
3609
|
return this.paginate(
|
|
3472
|
-
|
|
3610
|
+
PaginationMode.Page,
|
|
3473
3611
|
async (state) => {
|
|
3474
3612
|
const body = await this.http.request({
|
|
3475
3613
|
method: "GET",
|
|
@@ -3479,7 +3617,7 @@ var CommentsResource = class extends BaseResource {
|
|
|
3479
3617
|
});
|
|
3480
3618
|
return readPagedPage(body, "replies");
|
|
3481
3619
|
},
|
|
3482
|
-
params
|
|
3620
|
+
{ ...params, ...params.page !== void 0 ? { start: { page: params.page } } : {} }
|
|
3483
3621
|
);
|
|
3484
3622
|
}
|
|
3485
3623
|
/**
|
|
@@ -3560,7 +3698,11 @@ var IMAGE_MIME_TYPES = Object.freeze([
|
|
|
3560
3698
|
"image/heic",
|
|
3561
3699
|
"image/heif"
|
|
3562
3700
|
]);
|
|
3563
|
-
var VIDEO_MIME_TYPES = Object.freeze([
|
|
3701
|
+
var VIDEO_MIME_TYPES = Object.freeze([
|
|
3702
|
+
"video/mp4",
|
|
3703
|
+
"video/webm",
|
|
3704
|
+
"video/quicktime"
|
|
3705
|
+
]);
|
|
3564
3706
|
var AUDIO_MIME_TYPES = Object.freeze(["audio/ogg"]);
|
|
3565
3707
|
var ALLOWED_MIME_TYPES = Object.freeze([
|
|
3566
3708
|
...IMAGE_MIME_TYPES,
|
|
@@ -3639,7 +3781,7 @@ var FilesResource = class extends BaseResource {
|
|
|
3639
3781
|
* ```
|
|
3640
3782
|
*/
|
|
3641
3783
|
async upload(input, options = {}) {
|
|
3642
|
-
const prepared = await this
|
|
3784
|
+
const prepared = await this.#prepare(input, options);
|
|
3643
3785
|
const form = new FormData();
|
|
3644
3786
|
form.set("file", prepared.blob, prepared.filename);
|
|
3645
3787
|
return this.http.request({
|
|
@@ -3690,11 +3832,11 @@ var FilesResource = class extends BaseResource {
|
|
|
3690
3832
|
});
|
|
3691
3833
|
}
|
|
3692
3834
|
/** Приводит любой поддерживаемый вход к `Blob` с именем и проверенным типом. */
|
|
3693
|
-
async prepare(input, options) {
|
|
3835
|
+
async #prepare(input, options) {
|
|
3694
3836
|
const { data, filename, contentType } = await this.#normalize(input, options);
|
|
3695
|
-
const type = contentType ?? ((data
|
|
3837
|
+
const type = contentType ?? ((isBlob(data) ? data.type : void 0) || mimeFromFilename(filename));
|
|
3696
3838
|
if (options.validateMime !== false) assertAllowedMime(type || void 0, filename);
|
|
3697
|
-
const blob = data
|
|
3839
|
+
const blob = isBlob(data) && (!type || data.type === type) ? data : new Blob([data], { type: type ?? "" });
|
|
3698
3840
|
return { blob, filename };
|
|
3699
3841
|
}
|
|
3700
3842
|
async #normalize(input, options) {
|
|
@@ -3711,8 +3853,8 @@ var FilesResource = class extends BaseResource {
|
|
|
3711
3853
|
...options.contentType ? { contentType: options.contentType } : {}
|
|
3712
3854
|
};
|
|
3713
3855
|
}
|
|
3714
|
-
if (input instanceof ArrayBuffer || ArrayBuffer.isView(input) || input
|
|
3715
|
-
const fallbackName = input
|
|
3856
|
+
if (input instanceof ArrayBuffer || ArrayBuffer.isView(input) || isBlob(input)) {
|
|
3857
|
+
const fallbackName = isFile(input) ? input.name : options.filename ?? this.#nameFromMime(options.contentType);
|
|
3716
3858
|
return {
|
|
3717
3859
|
data: input,
|
|
3718
3860
|
filename: options.filename ?? fallbackName,
|
|
@@ -3778,7 +3920,7 @@ var HashtagsResource = class extends BaseResource {
|
|
|
3778
3920
|
iteratePosts(tag, params = {}) {
|
|
3779
3921
|
const path = `/api/hashtags/${encodePathSegment(tag, "tag")}/posts`;
|
|
3780
3922
|
return this.paginate(
|
|
3781
|
-
|
|
3923
|
+
PaginationMode.Cursor,
|
|
3782
3924
|
async (state) => {
|
|
3783
3925
|
const body = await this.http.request({
|
|
3784
3926
|
method: "GET",
|
|
@@ -3788,7 +3930,7 @@ var HashtagsResource = class extends BaseResource {
|
|
|
3788
3930
|
});
|
|
3789
3931
|
return readCursorPage(body, "posts");
|
|
3790
3932
|
},
|
|
3791
|
-
params
|
|
3933
|
+
{ ...params, ...params.cursor ? { start: { cursor: params.cursor } } : {} }
|
|
3792
3934
|
);
|
|
3793
3935
|
}
|
|
3794
3936
|
};
|
|
@@ -4019,8 +4161,11 @@ var NotificationsResource = class extends BaseResource {
|
|
|
4019
4161
|
* const next = await itd.notifications.list({ limit: 20, offset: page.nextOffset });
|
|
4020
4162
|
* ```
|
|
4021
4163
|
*/
|
|
4022
|
-
|
|
4023
|
-
|
|
4164
|
+
list(params = {}) {
|
|
4165
|
+
return this.#loadPage(params, params.offset ?? 0);
|
|
4166
|
+
}
|
|
4167
|
+
/** Общая загрузка страницы для {@link list} и {@link iterate}. */
|
|
4168
|
+
async #loadPage(params, offset) {
|
|
4024
4169
|
const body = await this.http.request({
|
|
4025
4170
|
method: "GET",
|
|
4026
4171
|
// Завершающий слэш обязателен: без него сервер отвечает ошибкой.
|
|
@@ -4043,19 +4188,9 @@ var NotificationsResource = class extends BaseResource {
|
|
|
4043
4188
|
*/
|
|
4044
4189
|
iterate(params = {}) {
|
|
4045
4190
|
return this.paginate(
|
|
4046
|
-
|
|
4047
|
-
|
|
4048
|
-
|
|
4049
|
-
const body = await this.http.request({
|
|
4050
|
-
method: "GET",
|
|
4051
|
-
path: "/api/notifications/",
|
|
4052
|
-
query: { limit: params.limit, offset },
|
|
4053
|
-
...this.requestOptions(params)
|
|
4054
|
-
});
|
|
4055
|
-
const page = readOffsetPage(body, "notifications", offset);
|
|
4056
|
-
return { ...page, items: page.items.map(normalizeNotification) };
|
|
4057
|
-
},
|
|
4058
|
-
params
|
|
4191
|
+
PaginationMode.Offset,
|
|
4192
|
+
(state) => this.#loadPage(params, state.offset ?? 0),
|
|
4193
|
+
{ ...params, ...params.offset !== void 0 ? { start: { offset: params.offset } } : {} }
|
|
4059
4194
|
);
|
|
4060
4195
|
}
|
|
4061
4196
|
/** Загружает число непрочитанных уведомлений. */
|
|
@@ -4187,7 +4322,7 @@ var PostsResource = class extends BaseResource {
|
|
|
4187
4322
|
*/
|
|
4188
4323
|
iterate(params = {}) {
|
|
4189
4324
|
return this.paginate(
|
|
4190
|
-
|
|
4325
|
+
PaginationMode.Cursor,
|
|
4191
4326
|
async (state) => {
|
|
4192
4327
|
const body = await this.http.request({
|
|
4193
4328
|
method: "GET",
|
|
@@ -4197,7 +4332,7 @@ var PostsResource = class extends BaseResource {
|
|
|
4197
4332
|
});
|
|
4198
4333
|
return readCursorPage(body, "posts");
|
|
4199
4334
|
},
|
|
4200
|
-
params
|
|
4335
|
+
{ ...params, ...params.cursor ? { start: { cursor: params.cursor } } : {} }
|
|
4201
4336
|
);
|
|
4202
4337
|
}
|
|
4203
4338
|
/**
|
|
@@ -4342,7 +4477,16 @@ var PostsResource = class extends BaseResource {
|
|
|
4342
4477
|
});
|
|
4343
4478
|
return pickArray(body, "posts");
|
|
4344
4479
|
}
|
|
4345
|
-
/**
|
|
4480
|
+
/**
|
|
4481
|
+
* Загружает страницу стены пользователя.
|
|
4482
|
+
*
|
|
4483
|
+
* Это **не только его собственные посты**: сюда попадают и записи, которые другие
|
|
4484
|
+
* оставили на его стене — у них `author` чужой, а `wallRecipient` указывает на владельца
|
|
4485
|
+
* стены. Поэтому число записей обычно больше, чем `postsCount` из профиля; чтобы
|
|
4486
|
+
* получить только авторские посты, отфильтруйте по `post.author.id`.
|
|
4487
|
+
*
|
|
4488
|
+
* Принимает и UUID, и имя пользователя.
|
|
4489
|
+
*/
|
|
4346
4490
|
async byUser(user, params = {}) {
|
|
4347
4491
|
const body = await this.http.request({
|
|
4348
4492
|
method: "GET",
|
|
@@ -4357,11 +4501,11 @@ var PostsResource = class extends BaseResource {
|
|
|
4357
4501
|
});
|
|
4358
4502
|
return readCursorPage(body, "posts");
|
|
4359
4503
|
}
|
|
4360
|
-
/** Перебирает
|
|
4504
|
+
/** Перебирает стену пользователя. Что именно в неё входит — см. {@link byUser}. */
|
|
4361
4505
|
iterateByUser(user, params = {}) {
|
|
4362
4506
|
const path = `/api/posts/user/${encodePathSegment(user, "user")}`;
|
|
4363
4507
|
return this.paginate(
|
|
4364
|
-
|
|
4508
|
+
PaginationMode.Cursor,
|
|
4365
4509
|
async (state) => {
|
|
4366
4510
|
const body = await this.http.request({
|
|
4367
4511
|
method: "GET",
|
|
@@ -4374,7 +4518,7 @@ var PostsResource = class extends BaseResource {
|
|
|
4374
4518
|
});
|
|
4375
4519
|
return readCursorPage(body, "posts");
|
|
4376
4520
|
},
|
|
4377
|
-
params
|
|
4521
|
+
{ ...params, ...params.cursor ? { start: { cursor: params.cursor } } : {} }
|
|
4378
4522
|
);
|
|
4379
4523
|
}
|
|
4380
4524
|
/** Загружает страницу постов, которые пользователь отметил реакцией. */
|
|
@@ -4391,7 +4535,7 @@ var PostsResource = class extends BaseResource {
|
|
|
4391
4535
|
iterateLikedByUser(user, params = {}) {
|
|
4392
4536
|
const path = `/api/posts/user/${encodePathSegment(user, "user")}/liked`;
|
|
4393
4537
|
return this.paginate(
|
|
4394
|
-
|
|
4538
|
+
PaginationMode.Cursor,
|
|
4395
4539
|
async (state) => {
|
|
4396
4540
|
const body = await this.http.request({
|
|
4397
4541
|
method: "GET",
|
|
@@ -4401,7 +4545,7 @@ var PostsResource = class extends BaseResource {
|
|
|
4401
4545
|
});
|
|
4402
4546
|
return readCursorPage(body, "posts");
|
|
4403
4547
|
},
|
|
4404
|
-
params
|
|
4548
|
+
{ ...params, ...params.cursor ? { start: { cursor: params.cursor } } : {} }
|
|
4405
4549
|
);
|
|
4406
4550
|
}
|
|
4407
4551
|
/**
|
|
@@ -4423,7 +4567,7 @@ var PostsResource = class extends BaseResource {
|
|
|
4423
4567
|
iterateComments(postId, params = {}) {
|
|
4424
4568
|
const path = `/api/posts/${encodePathSegment(postId, "postId")}/comments`;
|
|
4425
4569
|
return this.paginate(
|
|
4426
|
-
|
|
4570
|
+
PaginationMode.Cursor,
|
|
4427
4571
|
async (state) => {
|
|
4428
4572
|
const body = await this.http.request({
|
|
4429
4573
|
method: "GET",
|
|
@@ -4433,7 +4577,7 @@ var PostsResource = class extends BaseResource {
|
|
|
4433
4577
|
});
|
|
4434
4578
|
return readFlatCursorPage(body, "comments");
|
|
4435
4579
|
},
|
|
4436
|
-
params
|
|
4580
|
+
{ ...params, ...params.cursor ? { start: { cursor: params.cursor } } : {} }
|
|
4437
4581
|
);
|
|
4438
4582
|
}
|
|
4439
4583
|
/**
|
|
@@ -4600,19 +4744,34 @@ var UsersResource = class extends BaseResource {
|
|
|
4600
4744
|
...this.requestOptions(options)
|
|
4601
4745
|
});
|
|
4602
4746
|
}
|
|
4603
|
-
/**
|
|
4747
|
+
/**
|
|
4748
|
+
* Загружает подписчиков пользователя.
|
|
4749
|
+
*
|
|
4750
|
+
* ⚠️ **Сервер этот список не листает.** Возвращаются первые 20 записей и только они:
|
|
4751
|
+
* параметр `page` игнорируется (любая страница отдаёт те же записи и `pagination.page: 1`),
|
|
4752
|
+
* `limit` больше 20 молча уменьшается, а `hasMore` всегда `false`. Последнее честно —
|
|
4753
|
+
* получить продолжение нечем.
|
|
4754
|
+
*
|
|
4755
|
+
* Числу `total` доверять тоже не стоит: оно расходится с `followersCount` из профиля —
|
|
4756
|
+
* на проверенных аккаунтах занижено примерно на 1–4%.
|
|
4757
|
+
*/
|
|
4604
4758
|
followers(user, params = {}) {
|
|
4605
4759
|
return this.#userPage(`/api/users/${encodePathSegment(user, "user")}/followers`, params);
|
|
4606
4760
|
}
|
|
4607
|
-
/**
|
|
4761
|
+
/**
|
|
4762
|
+
* Перебирает подписчиков.
|
|
4763
|
+
*
|
|
4764
|
+
* ⚠️ Перебор закончится после первых 20 записей: сервер список не листает —
|
|
4765
|
+
* см. {@link followers}. Метод оставлен на случай, если пагинацию починят.
|
|
4766
|
+
*/
|
|
4608
4767
|
iterateFollowers(user, params = {}) {
|
|
4609
4768
|
return this.#userPaginator(`/api/users/${encodePathSegment(user, "user")}/followers`, params);
|
|
4610
4769
|
}
|
|
4611
|
-
/** Загружает
|
|
4770
|
+
/** Загружает подписки пользователя. Ограничения те же, что у {@link followers}. */
|
|
4612
4771
|
following(user, params = {}) {
|
|
4613
4772
|
return this.#userPage(`/api/users/${encodePathSegment(user, "user")}/following`, params);
|
|
4614
4773
|
}
|
|
4615
|
-
/** Перебирает подписки. */
|
|
4774
|
+
/** Перебирает подписки. Закончится после первых 20 записей — см. {@link followers}. */
|
|
4616
4775
|
iterateFollowing(user, params = {}) {
|
|
4617
4776
|
return this.#userPaginator(`/api/users/${encodePathSegment(user, "user")}/following`, params);
|
|
4618
4777
|
}
|
|
@@ -4652,11 +4811,11 @@ var UsersResource = class extends BaseResource {
|
|
|
4652
4811
|
...this.requestOptions(options)
|
|
4653
4812
|
});
|
|
4654
4813
|
}
|
|
4655
|
-
/** Загружает
|
|
4814
|
+
/** Загружает заблокированных пользователей. Ограничения те же, что у {@link followers}. */
|
|
4656
4815
|
blocked(params = {}) {
|
|
4657
4816
|
return this.#userPage("/api/users/me/blocked", params);
|
|
4658
4817
|
}
|
|
4659
|
-
/** Перебирает
|
|
4818
|
+
/** Перебирает заблокированных. Закончится после первых 20 записей — см. {@link followers}. */
|
|
4660
4819
|
iterateBlocked(params = {}) {
|
|
4661
4820
|
return this.#userPaginator("/api/users/me/blocked", params);
|
|
4662
4821
|
}
|
|
@@ -4711,28 +4870,36 @@ var UsersResource = class extends BaseResource {
|
|
|
4711
4870
|
...this.requestOptions(options)
|
|
4712
4871
|
});
|
|
4713
4872
|
}
|
|
4714
|
-
|
|
4873
|
+
/**
|
|
4874
|
+
* Загружает одну страницу списка пользователей.
|
|
4875
|
+
*
|
|
4876
|
+
* Имена полей перечислены с запасом: списки подписчиков и заблокированных приходят
|
|
4877
|
+
* под `users`, но альтернативное имя ничего не стоит и спасает, если эндпоинт назовёт
|
|
4878
|
+
* список по-своему.
|
|
4879
|
+
*
|
|
4880
|
+
* `page` уходит в запрос, хотя сервер его сейчас не читает (см. {@link followers}):
|
|
4881
|
+
* когда пагинацию починят, работать начнёт само.
|
|
4882
|
+
*/
|
|
4883
|
+
async #loadUserPage(path, params, state) {
|
|
4715
4884
|
const body = await this.http.request({
|
|
4716
4885
|
method: "GET",
|
|
4717
4886
|
path,
|
|
4718
|
-
query: { limit: params.limit
|
|
4887
|
+
query: withPageState({ limit: params.limit }, state),
|
|
4719
4888
|
...this.requestOptions(params)
|
|
4720
4889
|
});
|
|
4721
|
-
return readPagedPage(body, "users");
|
|
4890
|
+
return readPagedPage(body, "users", "followers", "following", "blocked");
|
|
4891
|
+
}
|
|
4892
|
+
#userPage(path, params) {
|
|
4893
|
+
return this.#loadUserPage(path, params, {
|
|
4894
|
+
...params.page !== void 0 ? { page: params.page } : {}
|
|
4895
|
+
});
|
|
4722
4896
|
}
|
|
4723
4897
|
#userPaginator(path, params) {
|
|
4724
4898
|
return this.paginate(
|
|
4725
|
-
|
|
4726
|
-
|
|
4727
|
-
|
|
4728
|
-
|
|
4729
|
-
path,
|
|
4730
|
-
query: withPageState({ limit: params.limit }, state),
|
|
4731
|
-
...this.requestOptions(params)
|
|
4732
|
-
});
|
|
4733
|
-
return readPagedPage(body, "users");
|
|
4734
|
-
},
|
|
4735
|
-
params
|
|
4899
|
+
PaginationMode.Page,
|
|
4900
|
+
(state) => this.#loadUserPage(path, params, state),
|
|
4901
|
+
// Без `start` перебор начинался бы с первой страницы, молча игнорируя `page`.
|
|
4902
|
+
{ ...params, ...params.page !== void 0 ? { start: { page: params.page } } : {} }
|
|
4736
4903
|
);
|
|
4737
4904
|
}
|
|
4738
4905
|
};
|
|
@@ -5061,16 +5228,19 @@ exports.DEFAULT_BASE_URL = DEFAULT_BASE_URL;
|
|
|
5061
5228
|
exports.DEFAULT_TIMEOUT = DEFAULT_TIMEOUT;
|
|
5062
5229
|
exports.DEFAULT_USER_AGENT = DEFAULT_USER_AGENT;
|
|
5063
5230
|
exports.DEVICE_ID_HEADER = DEVICE_ID_HEADER;
|
|
5231
|
+
exports.DetectedRuntime = DetectedRuntime;
|
|
5064
5232
|
exports.FeedTab = FeedTab;
|
|
5065
5233
|
exports.IMAGE_MIME_TYPES = IMAGE_MIME_TYPES;
|
|
5066
5234
|
exports.ItdAbortError = ItdAbortError;
|
|
5067
5235
|
exports.ItdApiError = ItdApiError;
|
|
5236
|
+
exports.ItdApiErrorKind = ItdApiErrorKind;
|
|
5068
5237
|
exports.ItdAuthError = ItdAuthError;
|
|
5069
5238
|
exports.ItdClient = ItdClient;
|
|
5070
5239
|
exports.ItdConfigError = ItdConfigError;
|
|
5071
5240
|
exports.ItdConflictError = ItdConflictError;
|
|
5072
5241
|
exports.ItdError = ItdError;
|
|
5073
5242
|
exports.ItdErrorCode = ItdErrorCode;
|
|
5243
|
+
exports.ItdErrorKind = ItdErrorKind;
|
|
5074
5244
|
exports.ItdForbiddenError = ItdForbiddenError;
|
|
5075
5245
|
exports.ItdNetworkError = ItdNetworkError;
|
|
5076
5246
|
exports.ItdNotFoundError = ItdNotFoundError;
|
|
@@ -5087,16 +5257,22 @@ exports.MAX_RECONNECT_ATTEMPTS = MAX_RECONNECT_ATTEMPTS;
|
|
|
5087
5257
|
exports.MemoryTokenStorage = MemoryTokenStorage;
|
|
5088
5258
|
exports.NOTIFICATION_TYPE_ALIASES = NOTIFICATION_TYPE_ALIASES;
|
|
5089
5259
|
exports.NotificationType = NotificationType;
|
|
5260
|
+
exports.OAuthProvider = OAuthProvider;
|
|
5261
|
+
exports.PaginationMode = PaginationMode;
|
|
5090
5262
|
exports.Paginator = Paginator;
|
|
5091
5263
|
exports.RECONNECT_BACKOFF = RECONNECT_BACKOFF;
|
|
5092
5264
|
exports.RECONNECT_JITTER = RECONNECT_JITTER;
|
|
5093
5265
|
exports.REFRESH_COOKIE = REFRESH_COOKIE;
|
|
5094
5266
|
exports.REFRESH_COOKIE_PATH = REFRESH_COOKIE_PATH;
|
|
5095
5267
|
exports.RealtimeStatus = RealtimeStatus;
|
|
5268
|
+
exports.RealtimeTransportKind = RealtimeTransportKind;
|
|
5096
5269
|
exports.ReportReason = ReportReason;
|
|
5097
5270
|
exports.ReportTargetType = ReportTargetType;
|
|
5271
|
+
exports.RuntimeMode = RuntimeMode;
|
|
5098
5272
|
exports.STREAM_PATH = STREAM_PATH;
|
|
5273
|
+
exports.SignInStatus = SignInStatus;
|
|
5099
5274
|
exports.TURNSTILE_SITE_KEY = TURNSTILE_SITE_KEY;
|
|
5275
|
+
exports.UnauthorizedStreamError = UnauthorizedStreamError;
|
|
5100
5276
|
exports.VIDEO_MIME_TYPES = VIDEO_MIME_TYPES;
|
|
5101
5277
|
exports.WallAccess = WallAccess;
|
|
5102
5278
|
exports.canonicalNotificationType = canonicalNotificationType;
|
|
@@ -5107,8 +5283,13 @@ exports.formatNotificationText = formatNotificationText;
|
|
|
5107
5283
|
exports.isBuilder = isBuilder;
|
|
5108
5284
|
exports.isItdApiError = isItdApiError;
|
|
5109
5285
|
exports.isItdAuthError = isItdAuthError;
|
|
5286
|
+
exports.isItdConflictError = isItdConflictError;
|
|
5110
5287
|
exports.isItdError = isItdError;
|
|
5288
|
+
exports.isItdForbiddenError = isItdForbiddenError;
|
|
5289
|
+
exports.isItdNotFoundError = isItdNotFoundError;
|
|
5290
|
+
exports.isItdPhoneVerificationError = isItdPhoneVerificationError;
|
|
5111
5291
|
exports.isItdRateLimitError = isItdRateLimitError;
|
|
5292
|
+
exports.isItdServerError = isItdServerError;
|
|
5112
5293
|
exports.isItdValidationError = isItdValidationError;
|
|
5113
5294
|
exports.isKnownNotificationType = isKnownNotificationType;
|
|
5114
5295
|
exports.isMyProfile = isMyProfile;
|
|
@@ -5120,5 +5301,5 @@ exports.readUnreadCountEvent = readUnreadCountEvent;
|
|
|
5120
5301
|
exports.report = report;
|
|
5121
5302
|
exports.resolveNotificationUrl = resolveNotificationUrl;
|
|
5122
5303
|
exports.toDate = toDate;
|
|
5123
|
-
//# sourceMappingURL=chunk-
|
|
5124
|
-
//# sourceMappingURL=chunk-
|
|
5304
|
+
//# sourceMappingURL=chunk-YM2YUO4D.cjs.map
|
|
5305
|
+
//# sourceMappingURL=chunk-YM2YUO4D.cjs.map
|