itd-api 0.0.5 → 0.0.6
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 +107 -1
- package/dist/{chunk-RUPF4X5L.js → chunk-CCRQI3ON.js} +182 -7
- package/dist/chunk-CCRQI3ON.js.map +1 -0
- package/dist/{chunk-YM2YUO4D.cjs → chunk-K7NBFQEE.cjs} +182 -6
- package/dist/chunk-K7NBFQEE.cjs.map +1 -0
- package/dist/{index-Dv0LXpMf.d.cts → index-CDGXKy8r.d.cts} +178 -7
- package/dist/{index-Dv0LXpMf.d.ts → index-CDGXKy8r.d.ts} +178 -7
- package/dist/index.cjs +88 -84
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/node.cjs +87 -83
- package/dist/node.d.cts +2 -2
- package/dist/node.d.ts +2 -2
- package/dist/node.js +2 -2
- package/package.json +5 -4
- package/dist/chunk-RUPF4X5L.js.map +0 -1
- package/dist/chunk-YM2YUO4D.cjs.map +0 -1
|
@@ -579,6 +579,24 @@ var AttachmentType = Object.freeze({
|
|
|
579
579
|
/** Голосовые комментарии: `audio/ogg`, с полем `duration`. */
|
|
580
580
|
Audio: "audio"
|
|
581
581
|
});
|
|
582
|
+
var SpanType = Object.freeze({
|
|
583
|
+
/** Хэштег. Название без решётки лежит в `tag`. */
|
|
584
|
+
Hashtag: "hashtag",
|
|
585
|
+
/** Упоминание. Имя пользователя лежит в `tag`. */
|
|
586
|
+
Mention: "mention",
|
|
587
|
+
/** Ссылка. Адрес лежит в `url`, а не в `tag`. */
|
|
588
|
+
Link: "link",
|
|
589
|
+
Bold: "bold",
|
|
590
|
+
Italic: "italic",
|
|
591
|
+
Underline: "underline",
|
|
592
|
+
/** Зачёркнутый. */
|
|
593
|
+
Strike: "strike",
|
|
594
|
+
/** Спойлер: текст скрыт до нажатия. */
|
|
595
|
+
Spoiler: "spoiler",
|
|
596
|
+
/** Моноширинный. */
|
|
597
|
+
Monospace: "monospace",
|
|
598
|
+
Quote: "quote"
|
|
599
|
+
});
|
|
582
600
|
var ReportTargetType = Object.freeze({
|
|
583
601
|
Post: "post",
|
|
584
602
|
Comment: "comment",
|
|
@@ -1698,7 +1716,7 @@ function normalizeBaseUrl(baseUrl) {
|
|
|
1698
1716
|
// src/core/config.ts
|
|
1699
1717
|
var DEFAULT_BASE_URL = "https://xn--d1ah4a.com";
|
|
1700
1718
|
var DEFAULT_TIMEOUT = 3e4;
|
|
1701
|
-
var LIBRARY_VERSION = "0.0.
|
|
1719
|
+
var LIBRARY_VERSION = "0.0.6";
|
|
1702
1720
|
var DEFAULT_USER_AGENT = `Mozilla/5.0 (compatible; itd-api/${LIBRARY_VERSION}; +https://github.com/KiowDev/itd-api)`;
|
|
1703
1721
|
var DEFAULT_RATE_LIMIT_DELAYS = Object.freeze([1e3, 5e3, 3e4, 6e4, 9e4]);
|
|
1704
1722
|
function requirePositive(value, name) {
|
|
@@ -2093,6 +2111,7 @@ function createApiError(context) {
|
|
|
2093
2111
|
function sleep(ms) {
|
|
2094
2112
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
2095
2113
|
}
|
|
2114
|
+
var EMPTY_KEYS = /* @__PURE__ */ new Set();
|
|
2096
2115
|
function setHeader(headers, name, value) {
|
|
2097
2116
|
try {
|
|
2098
2117
|
headers.set(name, value);
|
|
@@ -2146,6 +2165,7 @@ function createAbortBundle(userSignal, timeout) {
|
|
|
2146
2165
|
var HttpClient = class {
|
|
2147
2166
|
#config;
|
|
2148
2167
|
#collaborators;
|
|
2168
|
+
#plugins;
|
|
2149
2169
|
constructor(config, collaborators = {}) {
|
|
2150
2170
|
this.#config = config;
|
|
2151
2171
|
this.#collaborators = collaborators;
|
|
@@ -2154,6 +2174,19 @@ var HttpClient = class {
|
|
|
2154
2174
|
get baseUrl() {
|
|
2155
2175
|
return this.#config.baseUrl;
|
|
2156
2176
|
}
|
|
2177
|
+
/**
|
|
2178
|
+
* Имена опций запроса, заявленные плагинами.
|
|
2179
|
+
*
|
|
2180
|
+
* Читается ресурсами: они переносят в транспорт только известные поля, а чужие,
|
|
2181
|
+
* если их никто не заявил, отсеивают.
|
|
2182
|
+
*/
|
|
2183
|
+
get pluginOptionKeys() {
|
|
2184
|
+
return this.#plugins?.optionKeys ?? EMPTY_KEYS;
|
|
2185
|
+
}
|
|
2186
|
+
/** Подключает список плагинов. Реестр общий с клиентом и пополняется через `itd.use()`. */
|
|
2187
|
+
usePlugins(plugins) {
|
|
2188
|
+
this.#plugins = plugins;
|
|
2189
|
+
}
|
|
2157
2190
|
/**
|
|
2158
2191
|
* Подключает недостающие части конвейера.
|
|
2159
2192
|
*
|
|
@@ -2173,10 +2206,22 @@ var HttpClient = class {
|
|
|
2173
2206
|
* @throws {ItdNetworkError} если запрос не дошёл до сервера
|
|
2174
2207
|
*/
|
|
2175
2208
|
async request(options) {
|
|
2176
|
-
const task = () => this.#
|
|
2209
|
+
const task = () => this.#withPlugins(options);
|
|
2177
2210
|
if (!this.#collaborators.schedule || options.skipQueue) return task();
|
|
2178
2211
|
return this.#collaborators.schedule(task);
|
|
2179
2212
|
}
|
|
2213
|
+
/**
|
|
2214
|
+
* Прогоняет запрос через обёртки плагинов.
|
|
2215
|
+
*
|
|
2216
|
+
* Цепочка стоит **снаружи повторов и внутри очереди**: плагин должен увидеть запрос
|
|
2217
|
+
* и ответ по одному разу, независимо от того, сколько попыток понадобилось, — иначе,
|
|
2218
|
+
* например, текст поста зашифруется повторно на второй попытке.
|
|
2219
|
+
*/
|
|
2220
|
+
#withPlugins(options) {
|
|
2221
|
+
const plugins = this.#plugins;
|
|
2222
|
+
if (!plugins || plugins.size === 0) return this.#withRetries(options);
|
|
2223
|
+
return plugins.run(options, (request) => this.#withRetries(request));
|
|
2224
|
+
}
|
|
2180
2225
|
async #withRetries(options) {
|
|
2181
2226
|
const method = options.method.toUpperCase();
|
|
2182
2227
|
for (let attempt = 1; ; attempt++) {
|
|
@@ -2322,6 +2367,97 @@ var HttpClient = class {
|
|
|
2322
2367
|
}
|
|
2323
2368
|
};
|
|
2324
2369
|
|
|
2370
|
+
// src/core/plugins.ts
|
|
2371
|
+
var NO_KEYS = /* @__PURE__ */ new Set();
|
|
2372
|
+
var RESERVED_OPTION_KEYS = /* @__PURE__ */ new Set([
|
|
2373
|
+
"signal",
|
|
2374
|
+
"timeout",
|
|
2375
|
+
"headers",
|
|
2376
|
+
"retry",
|
|
2377
|
+
"method",
|
|
2378
|
+
"path",
|
|
2379
|
+
"query",
|
|
2380
|
+
"body",
|
|
2381
|
+
"skipAuth",
|
|
2382
|
+
"skipAuthRefresh",
|
|
2383
|
+
"skipQueue",
|
|
2384
|
+
"raw"
|
|
2385
|
+
]);
|
|
2386
|
+
var PluginRegistry = class {
|
|
2387
|
+
#transformers = [];
|
|
2388
|
+
#optionKeys = /* @__PURE__ */ new Set();
|
|
2389
|
+
#names = /* @__PURE__ */ new Set();
|
|
2390
|
+
/** Сколько обёрток подключено. Ноль означает, что запрос идёт прежним путём. */
|
|
2391
|
+
get size() {
|
|
2392
|
+
return this.#transformers.length;
|
|
2393
|
+
}
|
|
2394
|
+
/** Имена опций запроса, заявленные плагинами. */
|
|
2395
|
+
get optionKeys() {
|
|
2396
|
+
return this.#optionKeys.size === 0 ? NO_KEYS : this.#optionKeys;
|
|
2397
|
+
}
|
|
2398
|
+
/**
|
|
2399
|
+
* Подключает плагин.
|
|
2400
|
+
*
|
|
2401
|
+
* @throws {ItdConfigError} если плагин задан неверно, уже подключён или заявил занятое
|
|
2402
|
+
* имя опции
|
|
2403
|
+
*/
|
|
2404
|
+
add(plugin, context) {
|
|
2405
|
+
if (typeof plugin?.install !== "function") {
|
|
2406
|
+
throw new ItdConfigError("\u041F\u043B\u0430\u0433\u0438\u043D \u0434\u043E\u043B\u0436\u0435\u043D \u0431\u044B\u0442\u044C \u043E\u0431\u044A\u0435\u043A\u0442\u043E\u043C \u0441 \u043C\u0435\u0442\u043E\u0434\u043E\u043C install()");
|
|
2407
|
+
}
|
|
2408
|
+
const name = plugin.name;
|
|
2409
|
+
if (typeof name !== "string" || name.trim() === "") {
|
|
2410
|
+
throw new ItdConfigError("\u0423 \u043F\u043B\u0430\u0433\u0438\u043D\u0430 \u0434\u043E\u043B\u0436\u043D\u043E \u0431\u044B\u0442\u044C \u043D\u0435\u043F\u0443\u0441\u0442\u043E\u0435 \u0438\u043C\u044F");
|
|
2411
|
+
}
|
|
2412
|
+
if (this.#names.has(name)) {
|
|
2413
|
+
throw new ItdConfigError(`\u041F\u043B\u0430\u0433\u0438\u043D \xAB${name}\xBB \u0443\u0436\u0435 \u043F\u043E\u0434\u043A\u043B\u044E\u0447\u0451\u043D`);
|
|
2414
|
+
}
|
|
2415
|
+
const keys = plugin.optionKeys ?? [];
|
|
2416
|
+
for (const key of keys) {
|
|
2417
|
+
if (typeof key !== "string" || key.trim() === "") {
|
|
2418
|
+
throw new ItdConfigError(`\u041F\u043B\u0430\u0433\u0438\u043D \xAB${name}\xBB \u0437\u0430\u044F\u0432\u0438\u043B \u043F\u0443\u0441\u0442\u043E\u0435 \u0438\u043C\u044F \u043E\u043F\u0446\u0438\u0438`);
|
|
2419
|
+
}
|
|
2420
|
+
if (RESERVED_OPTION_KEYS.has(key)) {
|
|
2421
|
+
throw new ItdConfigError(
|
|
2422
|
+
`\u041F\u043B\u0430\u0433\u0438\u043D \xAB${name}\xBB \u0437\u0430\u044F\u0432\u0438\u043B \u043E\u043F\u0446\u0438\u044E \xAB${key}\xBB: \u044D\u0442\u043E \u043F\u043E\u043B\u0435 \u0437\u0430\u043F\u0440\u043E\u0441\u0430, \u0438\u043C\u044F \u0437\u0430\u043D\u044F\u0442\u043E. \u0417\u0430\u043D\u044F\u0442\u044B\u0435 \u0438\u043C\u0435\u043D\u0430: ${[...RESERVED_OPTION_KEYS].join(", ")}`
|
|
2423
|
+
);
|
|
2424
|
+
}
|
|
2425
|
+
}
|
|
2426
|
+
const before = this.#transformers.length;
|
|
2427
|
+
try {
|
|
2428
|
+
plugin.install({
|
|
2429
|
+
...context,
|
|
2430
|
+
use: (transformer) => {
|
|
2431
|
+
if (typeof transformer !== "function") {
|
|
2432
|
+
throw new ItdConfigError(`\u041F\u043B\u0430\u0433\u0438\u043D \xAB${name}\xBB \u043F\u0435\u0440\u0435\u0434\u0430\u043B \u0432 use() \u043D\u0435 \u0444\u0443\u043D\u043A\u0446\u0438\u044E`);
|
|
2433
|
+
}
|
|
2434
|
+
this.#transformers.push(transformer);
|
|
2435
|
+
}
|
|
2436
|
+
});
|
|
2437
|
+
} catch (error) {
|
|
2438
|
+
this.#transformers.length = before;
|
|
2439
|
+
throw error;
|
|
2440
|
+
}
|
|
2441
|
+
this.#names.add(name);
|
|
2442
|
+
for (const key of keys) this.#optionKeys.add(key);
|
|
2443
|
+
}
|
|
2444
|
+
/**
|
|
2445
|
+
* Прогоняет запрос через цепочку обёрток.
|
|
2446
|
+
*
|
|
2447
|
+
* Цепочка собирается на каждый запрос заново: плагин можно подключить в любой момент,
|
|
2448
|
+
* а обёрток единицы — экономить тут не на чем.
|
|
2449
|
+
*
|
|
2450
|
+
* @param execute настоящий запрос, вызывается самой внутренней обёрткой
|
|
2451
|
+
*/
|
|
2452
|
+
run(request, execute) {
|
|
2453
|
+
const chain = this.#transformers.reduceRight(
|
|
2454
|
+
(next, transformer) => (current) => transformer(current, next),
|
|
2455
|
+
execute
|
|
2456
|
+
);
|
|
2457
|
+
return chain(request);
|
|
2458
|
+
}
|
|
2459
|
+
};
|
|
2460
|
+
|
|
2325
2461
|
// src/core/rate-limit.ts
|
|
2326
2462
|
var RequestQueue = class {
|
|
2327
2463
|
#concurrency;
|
|
@@ -3242,15 +3378,31 @@ var BaseResource = class {
|
|
|
3242
3378
|
constructor(http) {
|
|
3243
3379
|
this.http = http;
|
|
3244
3380
|
}
|
|
3245
|
-
/**
|
|
3381
|
+
/**
|
|
3382
|
+
* Переносит общие поля опций запроса в параметры транспорта.
|
|
3383
|
+
*
|
|
3384
|
+
* Поля перечислены поимённо, а не скопированы целиком: параметры методов наследуют
|
|
3385
|
+
* {@link RequestOptions} и приносят с собой `limit`, `cursor` и прочее, чему в описании
|
|
3386
|
+
* запроса делать нечего. Исключение — опции, заявленные плагинами: их библиотека
|
|
3387
|
+
* не понимает, но обязана донести до обёрток нетронутыми.
|
|
3388
|
+
*/
|
|
3246
3389
|
requestOptions(options) {
|
|
3247
3390
|
if (!options) return {};
|
|
3248
|
-
|
|
3391
|
+
const result = {
|
|
3249
3392
|
...options.signal !== void 0 ? { signal: options.signal } : {},
|
|
3250
3393
|
...options.timeout !== void 0 ? { timeout: options.timeout } : {},
|
|
3251
3394
|
...options.headers !== void 0 ? { headers: options.headers } : {},
|
|
3252
3395
|
...options.retry !== void 0 ? { retry: options.retry } : {}
|
|
3253
3396
|
};
|
|
3397
|
+
const pluginKeys = this.http.pluginOptionKeys;
|
|
3398
|
+
if (pluginKeys.size === 0) return result;
|
|
3399
|
+
const source = options;
|
|
3400
|
+
const target = result;
|
|
3401
|
+
for (const key of pluginKeys) {
|
|
3402
|
+
const value = source[key];
|
|
3403
|
+
if (value !== void 0) target[key] = value;
|
|
3404
|
+
}
|
|
3405
|
+
return result;
|
|
3254
3406
|
}
|
|
3255
3407
|
/**
|
|
3256
3408
|
* Собирает перебор страниц.
|
|
@@ -4911,6 +5063,7 @@ var ItdClient = class {
|
|
|
4911
5063
|
#authManager;
|
|
4912
5064
|
#jar;
|
|
4913
5065
|
#queue;
|
|
5066
|
+
#plugins = new PluginRegistry();
|
|
4914
5067
|
/** Авторизация, сессии и пароли. */
|
|
4915
5068
|
auth;
|
|
4916
5069
|
/** Профили, подписки, блокировки, приватность. */
|
|
@@ -4947,6 +5100,7 @@ var ItdClient = class {
|
|
|
4947
5100
|
this.#http = new HttpClient(this.#config);
|
|
4948
5101
|
this.#authManager = new AuthManager(this.#config, this.#http, this.#jar);
|
|
4949
5102
|
this.#queue = this.#config.rateLimit ? new RequestQueue(this.#config.rateLimit) : void 0;
|
|
5103
|
+
this.#http.usePlugins(this.#plugins);
|
|
4950
5104
|
this.#http.setCollaborators({
|
|
4951
5105
|
getAuthHeaders: () => this.#authManager.getAuthHeaders(),
|
|
4952
5106
|
getDeviceId: () => this.#authManager.getDeviceId(),
|
|
@@ -4992,6 +5146,27 @@ var ItdClient = class {
|
|
|
4992
5146
|
request(options) {
|
|
4993
5147
|
return this.#http.request(options);
|
|
4994
5148
|
}
|
|
5149
|
+
/**
|
|
5150
|
+
* Подключает плагин.
|
|
5151
|
+
*
|
|
5152
|
+
* Плагин работает на уровне транспорта: видит запрос до отправки и разобранный ответ,
|
|
5153
|
+
* поэтому одна обёртка охватывает сразу все методы клиента. Подключать можно в любой
|
|
5154
|
+
* момент, но обычно это делают сразу после создания клиента.
|
|
5155
|
+
*
|
|
5156
|
+
* @throws {ItdConfigError} если плагин задан неверно или уже подключён
|
|
5157
|
+
*
|
|
5158
|
+
* @example
|
|
5159
|
+
* ```ts
|
|
5160
|
+
* import { crypt } from 'itd-api-crypto';
|
|
5161
|
+
*
|
|
5162
|
+
* itd.use(crypt());
|
|
5163
|
+
* await itd.posts.create({ content: 'секрет' }, { encrypt: 'invis' });
|
|
5164
|
+
* ```
|
|
5165
|
+
*/
|
|
5166
|
+
use(plugin) {
|
|
5167
|
+
this.#plugins.add(plugin, { baseUrl: this.#config.baseUrl, logger: this.#config.logger });
|
|
5168
|
+
return this;
|
|
5169
|
+
}
|
|
4995
5170
|
/**
|
|
4996
5171
|
* Подписывается на события авторизации.
|
|
4997
5172
|
*
|
|
@@ -5271,6 +5446,7 @@ exports.ReportTargetType = ReportTargetType;
|
|
|
5271
5446
|
exports.RuntimeMode = RuntimeMode;
|
|
5272
5447
|
exports.STREAM_PATH = STREAM_PATH;
|
|
5273
5448
|
exports.SignInStatus = SignInStatus;
|
|
5449
|
+
exports.SpanType = SpanType;
|
|
5274
5450
|
exports.TURNSTILE_SITE_KEY = TURNSTILE_SITE_KEY;
|
|
5275
5451
|
exports.UnauthorizedStreamError = UnauthorizedStreamError;
|
|
5276
5452
|
exports.VIDEO_MIME_TYPES = VIDEO_MIME_TYPES;
|
|
@@ -5301,5 +5477,5 @@ exports.readUnreadCountEvent = readUnreadCountEvent;
|
|
|
5301
5477
|
exports.report = report;
|
|
5302
5478
|
exports.resolveNotificationUrl = resolveNotificationUrl;
|
|
5303
5479
|
exports.toDate = toDate;
|
|
5304
|
-
//# sourceMappingURL=chunk-
|
|
5305
|
-
//# sourceMappingURL=chunk-
|
|
5480
|
+
//# sourceMappingURL=chunk-K7NBFQEE.cjs.map
|
|
5481
|
+
//# sourceMappingURL=chunk-K7NBFQEE.cjs.map
|