itd-api 0.0.6 → 0.0.8

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.
@@ -156,22 +156,46 @@ declare const RealtimeStatus: Readonly<{
156
156
  }>;
157
157
  type RealtimeStatus = (typeof RealtimeStatus)[keyof typeof RealtimeStatus];
158
158
  /**
159
- * Кто может писать на стену профиля.
159
+ * Уровень доступа к разделу профиля.
160
160
  *
161
- * Документация перечисляет значения не полностью, поэтому тип открытый: объект ниже —
162
- * справочник известных значений, но сервер может прислать и другое.
161
+ * Общий набор значений для полей `wallAccess` и `likesVisibility` настроек приватности.
162
+ * Тип открытый: сервер может прислать значение вне этого перечня.
163
163
  */
164
+ declare const AccessType: Readonly<{
165
+ /** Никто. */
166
+ readonly Nobody: "nobody";
167
+ /** Только взаимные подписки. */
168
+ readonly Mutual: "mutual";
169
+ /** Подписчики. */
170
+ readonly Followers: "followers";
171
+ /** Все. */
172
+ readonly Everyone: "everyone";
173
+ }>;
174
+ type AccessType = Loose<(typeof AccessType)[keyof typeof AccessType]>;
175
+ /** Кто может писать на стену профиля. Псевдоним {@link AccessType}. */
164
176
  declare const WallAccess: Readonly<{
177
+ /** Никто. */
178
+ readonly Nobody: "nobody";
179
+ /** Только взаимные подписки. */
180
+ readonly Mutual: "mutual";
181
+ /** Подписчики. */
182
+ readonly Followers: "followers";
183
+ /** Все. */
165
184
  readonly Everyone: "everyone";
166
185
  }>;
167
- type WallAccess = Loose<(typeof WallAccess)[keyof typeof WallAccess]>;
168
- /** Кто видит реакции пользователя. Список в документации неполный. */
186
+ type WallAccess = AccessType;
187
+ /** Кто видит реакции пользователя. Псевдоним {@link AccessType}. */
169
188
  declare const LikesVisibility: Readonly<{
170
- readonly Everyone: "everyone";
189
+ /** Никто. */
190
+ readonly Nobody: "nobody";
171
191
  /** Только взаимные подписки. */
172
192
  readonly Mutual: "mutual";
193
+ /** Подписчики. */
194
+ readonly Followers: "followers";
195
+ /** Все. */
196
+ readonly Everyone: "everyone";
173
197
  }>;
174
- type LikesVisibility = Loose<(typeof LikesVisibility)[keyof typeof LikesVisibility]>;
198
+ type LikesVisibility = AccessType;
175
199
  /**
176
200
  * Канонический тип уведомления (новое поколение имён).
177
201
  *
@@ -208,6 +232,55 @@ declare const NotificationType: Readonly<{
208
232
  readonly VerificationRejected: "verification_rejected";
209
233
  }>;
210
234
  type NotificationType = Loose<(typeof NotificationType)[keyof typeof NotificationType]>;
235
+ /**
236
+ * Тип взаимодействия с контентом в телеметрии (`POST /api/v1/x`, поле `t`).
237
+ *
238
+ * Кодируется числом.
239
+ */
240
+ declare const InteractionType: Readonly<{
241
+ /** Открытие фотографии. */
242
+ readonly PhotoOpen: 1;
243
+ /** Прогресс просмотра видео. Несёт поля `pm`/`dm`. */
244
+ readonly VideoProgress: 2;
245
+ }>;
246
+ type InteractionType = (typeof InteractionType)[keyof typeof InteractionType];
247
+ /**
248
+ * Источник показа поста в телеметрии (поле `s`).
249
+ *
250
+ * Кодируется числом. Поле применимо к источникам `PostPage` и `Link`; для лент источник
251
+ * передаётся контекстом `sc`.
252
+ */
253
+ declare const ViewSource: Readonly<{
254
+ readonly FeedGlobal: 1;
255
+ readonly FeedFollowing: 2;
256
+ readonly FeedClan: 3;
257
+ readonly Profile: 4;
258
+ readonly Hashtag: 5;
259
+ readonly PostPage: 6;
260
+ readonly Link: 7;
261
+ readonly Search: 8;
262
+ }>;
263
+ type ViewSource = (typeof ViewSource)[keyof typeof ViewSource];
264
+ /**
265
+ * Причина завершения просмотра поста в телеметрии (`POST /api/v1/i`, поле `r`).
266
+ *
267
+ * Кодируется числом.
268
+ */
269
+ declare const ViewReason: Readonly<{
270
+ /** Пост ушёл из зоны видимости при обычной прокрутке. */
271
+ readonly Normal: 0;
272
+ /** Потеря фокуса окна. */
273
+ readonly Blur: 1;
274
+ /** Вкладка скрыта. */
275
+ readonly Hidden: 2;
276
+ /** Уход со страницы (`pagehide`). */
277
+ readonly PageHide: 3;
278
+ /** Элемент перестал наблюдаться. */
279
+ readonly Unobserve: 4;
280
+ /** Достигнут порог времени просмотра. */
281
+ readonly ThresholdMet: 5;
282
+ }>;
283
+ type ViewReason = (typeof ViewReason)[keyof typeof ViewReason];
211
284
  /**
212
285
  * Строковые коды ошибок из поля `code`.
213
286
  *
@@ -1440,7 +1513,7 @@ interface RequestOptions {
1440
1513
  timeout?: number | undefined;
1441
1514
  /** Дополнительные заголовки. */
1442
1515
  headers?: Record<string, string> | undefined;
1443
- /** Повторы только для этого запроса. */
1516
+ /** Повторы только для этого запроса. Переопределяют глобальную настройку `retry`. */
1444
1517
  retry?: RetryOptions | false | undefined;
1445
1518
  }
1446
1519
  /** Полное описание запроса для низкоуровневого `itd.request()`. */
@@ -1467,14 +1540,14 @@ interface RawRequestOptions extends RequestOptions {
1467
1540
  raw?: boolean | undefined;
1468
1541
  }
1469
1542
 
1543
+ /** Версия библиотеки. Попадает в `User-Agent`. */
1544
+ declare const LIBRARY_VERSION = "0.0.8";
1545
+
1470
1546
  /** Базовый URL API итд.com. Домен записан в punycode: `итд.com`. */
1471
1547
  declare const DEFAULT_BASE_URL = "https://xn--d1ah4a.com";
1472
1548
  /** Таймаут запроса по умолчанию. Столько же использует официальный клиент итд.com. */
1473
1549
  declare const DEFAULT_TIMEOUT = 30000;
1474
- /**
1475
- * Версия библиотеки — попадает в `User-Agent`.
1476
- */
1477
- declare const LIBRARY_VERSION = "0.0.6";
1550
+
1478
1551
  /**
1479
1552
  * `User-Agent` по умолчанию.
1480
1553
  *
@@ -1485,51 +1558,22 @@ declare const LIBRARY_VERSION = "0.0.6";
1485
1558
  * В браузере заголовок не выставляется — `User-Agent` там запрещён к изменению, и среда
1486
1559
  * молча его игнорирует.
1487
1560
  */
1488
- declare const DEFAULT_USER_AGENT = "Mozilla/5.0 (compatible; itd-api/0.0.6; +https://github.com/KiowDev/itd-api)";
1561
+ declare const DEFAULT_USER_AGENT = "Mozilla/5.0 (compatible; itd-api/0.0.8; +https://github.com/KiowDev/itd-api)";
1489
1562
  /**
1490
- * Настройки повторов со всеми значениями по умолчанию.
1563
+ * Срез конфигурации, нужный слою авторизации.
1491
1564
  *
1492
- * Поля перечислены явно, а не через `Required<RetryOptions>`: тот снимает необязательность,
1493
- * но оставляет `| undefined` в типе значения, раз оно указано в исходном интерфейсе.
1565
+ * Выделен явно, чтобы {@link AuthManager} не получал целиком `ResolvedConfig` со всеми
1566
+ * настройками транспорта, повторов и очереди, к которым он отношения не имеет.
1567
+ * `ResolvedConfig` содержит все эти поля, поэтому подходит везде, где ждут `AuthConfig`.
1494
1568
  */
1495
- interface ResolvedRetryOptions {
1496
- attempts: number;
1497
- baseDelay: number;
1498
- maxDelay: number;
1499
- jitter: number;
1500
- retryWrites: boolean;
1501
- shouldRetry: ((error: unknown, attempt: number) => boolean) | undefined;
1502
- }
1503
- /** Настройки очереди со всеми значениями по умолчанию. */
1504
- interface ResolvedRateLimitOptions {
1505
- concurrency: number;
1506
- rps: number | undefined;
1507
- retryDelays: readonly number[];
1508
- respectHeaders: boolean;
1509
- }
1510
- /** Конфигурация клиента после подстановки значений по умолчанию и проверок. */
1511
- interface ResolvedConfig {
1569
+ interface AuthConfig {
1512
1570
  baseUrl: string;
1513
1571
  auth: AuthInput | undefined;
1514
1572
  storage: TokenStorage;
1515
- autoRefresh: boolean;
1573
+ useCookieJar: boolean;
1574
+ deviceId: string | undefined;
1516
1575
  reloginOnRefreshFailure: boolean;
1517
- fetch: typeof fetch;
1518
- timeout: number;
1519
- retry: ResolvedRetryOptions | undefined;
1520
- rateLimit: ResolvedRateLimitOptions | undefined;
1521
- hooks: ClientHooks;
1522
1576
  logger: Logger | undefined;
1523
- headers: Record<string, string>;
1524
- /** Значение заголовка `X-Device-Id`, если задано вручную. Иначе заводится само. */
1525
- deviceId: string | undefined;
1526
- /** Значение заголовка `User-Agent`. `undefined` — заголовок не выставляется. */
1527
- userAgent: string | undefined;
1528
- mode: RuntimeMode;
1529
- /** Вести ли собственный cookie-jar (вне браузера и React Native). */
1530
- useCookieJar: boolean;
1531
- /** Отправлять ли `credentials: 'include'` (в браузере). */
1532
- sendCredentials: boolean;
1533
1577
  }
1534
1578
 
1535
1579
  /** Имя cookie-флага «есть refresh-сессия». Ставится сайтом итд.com рядом с refresh-токеном. */
@@ -1646,190 +1690,31 @@ declare class Emitter<Events> {
1646
1690
  }
1647
1691
 
1648
1692
  /**
1649
- * Обёртка вокруг запроса.
1650
- *
1651
- * Получает описание запроса и продолжение цепочки. Может изменить запрос перед отправкой,
1652
- * посмотреть и подменить разобранный ответ или вовсе не вызывать `next` и вернуть своё.
1653
- *
1654
- * @param request что уходит на сервер; изменять сам объект не нужно — передайте копию в `next`
1655
- * @param next продолжение: либо следующая обёртка, либо настоящий запрос
1656
- * @returns тело ответа в том виде, в каком его получит вызывающий код
1657
- *
1658
- * @example Дописать заголовок ко всем запросам
1659
- * ```ts
1660
- * const transformer: Transformer = (request, next) =>
1661
- * next({ ...request, headers: { ...request.headers, 'X-Trace': trace() } });
1662
- * ```
1663
- */
1664
- type Transformer = (request: RawRequestOptions, next: (request: RawRequestOptions) => Promise<unknown>) => Promise<unknown>;
1665
- /** Что плагин получает при подключении. */
1666
- interface PluginContext {
1667
- /** Базовый URL клиента — например чтобы разобрать абсолютные ссылки из ответа. */
1668
- baseUrl: string;
1669
- /** Отладочный вывод клиента, если он включён. */
1670
- logger: Logger | undefined;
1671
- /** Добавляет обёртку запроса. Подключённые раньше оказываются снаружи. */
1672
- use(transformer: Transformer): void;
1673
- }
1674
- /**
1675
- * Плагин клиента.
1676
- *
1677
- * Подключается через `itd.use(plugin)` и работает на уровне транспорта: видит запрос
1678
- * до отправки и разобранный ответ. Библиотека не знает, что именно делает плагин, —
1679
- * ей достаточно списка обёрток и имён опций, которые он читает.
1680
- *
1681
- * @example
1682
- * ```ts
1683
- * const logging: ItdPlugin = {
1684
- * name: 'logging',
1685
- * install({ use, logger }) {
1686
- * use(async (request, next) => {
1687
- * logger?.info(`${request.method} ${request.path}`);
1688
- * return next(request);
1689
- * });
1690
- * },
1691
- * };
1692
- *
1693
- * itd.use(logging);
1694
- * ```
1695
- */
1696
- interface ItdPlugin {
1697
- /** Имя плагина. Должно быть уникальным: повторное подключение — ошибка. */
1698
- name: string;
1699
- /**
1700
- * Имена опций запроса, которые плагин читает у методов ресурсов.
1701
- *
1702
- * Библиотека этих опций не понимает и ничего с ними не делает — только доносит
1703
- * от вызова метода до обёртки нетронутыми. Без такого списка чужие поля отсеиваются,
1704
- * чтобы случайная опечатка в параметрах не уезжала на сервер.
1705
- *
1706
- * Имена полей самого запроса (`path`, `body`, `headers`, `signal` и прочие из
1707
- * `RawRequestOptions`) заявить нельзя: подключение такого плагина завершится ошибкой.
1708
- *
1709
- * Типы для них плагин объявляет сам, дополняя `RequestOptions`:
1710
- * ```ts
1711
- * declare module 'itd-api' {
1712
- * interface RequestOptions { encrypt?: string | undefined }
1713
- * }
1714
- * ```
1715
- */
1716
- optionKeys?: readonly string[];
1717
- /** Вызывается один раз при подключении. */
1718
- install(context: PluginContext): void;
1719
- }
1720
- /**
1721
- * Список подключённых плагинов и собранная из них цепочка обёрток.
1722
- *
1723
- * Живёт в клиенте, а работает в транспорте: {@link HttpClient} прогоняет через `run`
1724
- * каждый запрос, если плагины есть.
1725
- */
1726
- declare class PluginRegistry {
1727
- #private;
1728
- /** Сколько обёрток подключено. Ноль означает, что запрос идёт прежним путём. */
1729
- get size(): number;
1730
- /** Имена опций запроса, заявленные плагинами. */
1731
- get optionKeys(): ReadonlySet<string>;
1732
- /**
1733
- * Подключает плагин.
1734
- *
1735
- * @throws {ItdConfigError} если плагин задан неверно, уже подключён или заявил занятое
1736
- * имя опции
1737
- */
1738
- add(plugin: ItdPlugin, context: Omit<PluginContext, 'use'>): void;
1739
- /**
1740
- * Прогоняет запрос через цепочку обёрток.
1741
- *
1742
- * Цепочка собирается на каждый запрос заново: плагин можно подключить в любой момент,
1743
- * а обёрток единицы — экономить тут не на чем.
1744
- *
1745
- * @param execute настоящий запрос, вызывается самой внутренней обёрткой
1746
- */
1747
- run(request: RawRequestOptions, execute: (request: RawRequestOptions) => Promise<unknown>): Promise<unknown>;
1748
- }
1749
-
1750
- /**
1751
- * Подключаемые части конвейера.
1752
- *
1753
- * Авторизация, cookie, очередь и повторы живут в отдельных модулях и подставляются сюда.
1754
- * Благодаря этому транспорт тестируется изолированно, а `HttpClient` ничего не знает
1755
- * о том, как именно добывается токен.
1756
- */
1757
- interface HttpCollaborators {
1758
- /** Заголовки авторизации для запроса. Вызывается перед каждой попыткой. */
1759
- getAuthHeaders?(): Promise<Record<string, string>> | Record<string, string>;
1760
- /**
1761
- * Реакция на ответ `401`.
1762
- *
1763
- * Должна вернуть `true`, если токен обновлён и запрос имеет смысл повторить.
1764
- * Повтор выполняется ровно один раз.
1765
- */
1766
- onUnauthorized?(): Promise<boolean>;
1767
- /**
1768
- * Идентификатор устройства для заголовка `X-Device-Id`.
1769
- *
1770
- * Отдельно от {@link getAuthHeaders}, потому что нужен и на анонимных запросах —
1771
- * например на `sign-in`, где заголовка авторизации ещё нет.
1772
- */
1773
- getDeviceId?(): Promise<string> | string;
1774
- /** Значение заголовка `Cookie` для указанного URL. */
1775
- getCookieHeader?(url: string): string | undefined;
1776
- /** Приём `Set-Cookie` из ответа. */
1777
- saveCookies?(url: string, response: Response): void;
1778
- /** Очередь запросов: ограничение конкурентности и частоты. */
1779
- schedule?<T>(task: () => Promise<T>): Promise<T>;
1780
- /**
1781
- * Сообщает об остатке лимита из заголовков ответа.
1782
- *
1783
- * Вызывается после **каждого** ответа, включая ошибочные, — так очередь узнаёт
1784
- * об исчерпании лимита заранее и успевает притормозить до отказа сервера.
1785
- */
1786
- onRateLimit?(limit: number | undefined, remaining: number | undefined): void;
1787
- /**
1788
- * Планировщик повторов.
1789
- *
1790
- * Возвращает паузу в мс перед следующей попыткой либо `undefined`, если повторять не нужно.
1791
- */
1792
- nextRetryDelay?(error: unknown, attempt: number, method: string): number | undefined;
1793
- }
1794
- /**
1795
- * Транспортный слой: единственное место, откуда библиотека ходит в сеть.
1693
+ * Описание запроса внутри конвейера.
1796
1694
  *
1797
- * Отвечает за сборку URL, заголовки, таймауты, разбор ответа и превращение любой неудачи
1798
- * в типизированную ошибку. Авторизация, cookie, очередь и повторы подключаются извне
1799
- * через {@link HttpCollaborators}.
1695
+ * Отличается от публичного {@link RawRequestOptions} одним служебным полем: слои конвейера
1696
+ * должны уметь дописать заголовки так, чтобы пользовательские `headers` всё равно остались
1697
+ * важнее. Смешивать их в одном объекте нельзя — тогда слой авторизации перебивал бы
1698
+ * `Authorization`, заданный вызывающим кодом вручную.
1800
1699
  */
1801
- declare class HttpClient {
1802
- #private;
1803
- constructor(config: ResolvedConfig, collaborators?: HttpCollaborators);
1804
- /** Базовый URL, к которому обращается клиент. */
1805
- get baseUrl(): string;
1700
+ interface PipelineRequest extends RawRequestOptions {
1806
1701
  /**
1807
- * Имена опций запроса, заявленные плагинами.
1702
+ * Заголовки, добавленные слоями конвейера.
1808
1703
  *
1809
- * Читается ресурсами: они переносят в транспорт только известные поля, а чужие,
1810
- * если их никто не заявил, отсеивают.
1811
- */
1812
- get pluginOptionKeys(): ReadonlySet<string>;
1813
- /** Подключает список плагинов. Реестр общий с клиентом и пополняется через `itd.use()`. */
1814
- usePlugins(plugins: PluginRegistry): void;
1815
- /**
1816
- * Подключает недостающие части конвейера.
1704
+ * Ставятся до пользовательских `headers` и потому могут быть ими переопределены.
1817
1705
  *
1818
- * Нужно из-за кольцевой зависимости: слой авторизации сам выполняет запросы, поэтому
1819
- * не может быть передан в конструктор до создания транспорта.
1706
+ * @internal
1820
1707
  */
1821
- setCollaborators(collaborators: HttpCollaborators): void;
1708
+ layerHeaders?: Record<string, string> | undefined;
1822
1709
  /**
1823
- * Выполняет запрос к API.
1710
+ * Номер попытки, начиная с 1. Проставляет слой повторов, читают хуки.
1824
1711
  *
1825
- * @typeParam T ожидаемая форма ответа после снятия обёртки `{ data: … }`
1826
- * @throws {ItdApiError} если сервер ответил статусом ≥ 400
1827
- * @throws {ItdTimeoutError} если истёк таймаут
1828
- * @throws {ItdAbortError} если запрос отменён через `signal`
1829
- * @throws {ItdNetworkError} если запрос не дошёл до сервера
1712
+ * @internal
1830
1713
  */
1831
- request<T = unknown>(options: RawRequestOptions): Promise<T>;
1714
+ attempt?: number | undefined;
1832
1715
  }
1716
+ /** Обработчик запроса. Самый внутренний в цепочке — транспорт. */
1717
+ type RequestHandler = (request: PipelineRequest) => Promise<unknown>;
1833
1718
 
1834
1719
  /** Пути авторизации. Вынесены, чтобы не расходиться между модулями. */
1835
1720
  declare const AUTH_PATHS: {
@@ -1880,7 +1765,7 @@ interface AuthEvents {
1880
1765
  */
1881
1766
  declare class AuthManager {
1882
1767
  #private;
1883
- constructor(config: ResolvedConfig, http: HttpClient, jar: CookieJar);
1768
+ constructor(config: AuthConfig, send: RequestHandler, jar: CookieJar);
1884
1769
  /** Подписка на события авторизации. */
1885
1770
  get on(): Emitter<AuthEvents>['on'];
1886
1771
  /** Подписка на одно срабатывание. */
@@ -1942,76 +1827,178 @@ declare class AuthManager {
1942
1827
  clear(): Promise<void>;
1943
1828
  }
1944
1829
 
1945
- /** Событие потока уведомлений после разбора. */
1946
- interface NotificationEvent {
1947
- /** Само уведомление в единой форме. */
1948
- notification: Notification;
1949
- /**
1950
- * Актуальное число непрочитанных, если сервер его сообщил.
1951
- *
1952
- * Клиент не увеличивает счётчик сам: значение приходит с сервера.
1953
- */
1954
- unreadCount: number | undefined;
1955
- /** Нужно ли проиграть звук. */
1956
- sound: boolean;
1957
- }
1958
1830
  /**
1959
- * Приводит уведомление к единой форме.
1960
- *
1961
- * Нужна потому, что REST-список и поток событий описывают одно и то же событие по-разному:
1962
- * различаются имена типов (`like` против `post_reaction`), имена полей
1963
- * (`targetId`/`entityId`, `read`/`isRead`, `preview`/`entityPreview`) и число участников
1964
- * (`actor` против массива `actors`). После приведения объекты из обоих источников
1965
- * можно складывать в один список.
1831
+ * Обёртка вокруг запроса.
1966
1832
  *
1967
- * Исходные данные не теряются: имя типа с сервера остаётся в `rawType`,
1968
- * весь объект целиком в `raw`.
1833
+ * Получает описание запроса и продолжение цепочки. Может изменить запрос перед отправкой,
1834
+ * посмотреть и подменить разобранный ответ или вовсе не вызывать `next` и вернуть своё.
1969
1835
  *
1970
- * @param input уведомление из REST-ответа либо полезная нагрузка события потока
1836
+ * @param request что уходит на сервер; изменять сам объект не нужно — передайте копию в `next`
1837
+ * @param next продолжение: либо следующая обёртка, либо настоящий запрос
1838
+ * @returns тело ответа в том виде, в каком его получит вызывающий код
1971
1839
  *
1972
- * @example
1840
+ * @example Дописать заголовок ко всем запросам
1973
1841
  * ```ts
1974
- * const fromRest = normalizeNotification(restItem);
1975
- * const fromStream = normalizeNotification(event.payload);
1976
- * // одинаковая форма — можно объединять
1842
+ * const transformer: Transformer = (request, next) =>
1843
+ * next({ ...request, headers: { ...request.headers, 'X-Trace': trace() } });
1977
1844
  * ```
1978
1845
  */
1979
- declare function normalizeNotification(input: unknown): Notification;
1980
- /**
1981
- * Разбирает событие `notification` из потока.
1982
- *
1983
- * Кроме самого уведомления событие несёт служебные поля уровня конверта: актуальный
1984
- * счётчик непрочитанных и признак звука.
1985
- */
1986
- declare function readNotificationEvent(data: unknown): NotificationEvent;
1846
+ type Transformer = (request: RawRequestOptions, next: (request: RawRequestOptions) => Promise<unknown>) => Promise<unknown>;
1847
+ /** Что плагин получает при подключении. */
1848
+ interface PluginContext {
1849
+ /** Базовый URL клиента — например чтобы разобрать абсолютные ссылки из ответа. */
1850
+ baseUrl: string;
1851
+ /** Отладочный вывод клиента, если он включён. */
1852
+ logger: Logger | undefined;
1853
+ /** Добавляет обёртку запроса. Подключённые раньше оказываются снаружи. */
1854
+ use(transformer: Transformer): void;
1855
+ }
1987
1856
  /**
1988
- * Разбирает событие `unread_count` из потока.
1857
+ * Плагин клиента.
1989
1858
  *
1990
- * Возвращает `undefined`, если сервер прислал событие без вложенного `payload`.
1991
- * Официальный клиент в этом случае **обнуляет** счётчик это ошибка, из-за которой
1992
- * непрочитанные пропадают из интерфейса.
1993
- */
1994
- declare function readUnreadCountEvent(data: unknown): number | undefined;
1995
-
1996
- /**
1997
- * Паузы перед попытками переподключения, мс.
1859
+ * Подключается через `itd.use(plugin)` и работает на уровне транспорта: видит запрос
1860
+ * до отправки и разобранный ответ. Библиотека не знает, что именно делает плагин, —
1861
+ * ей достаточно списка обёрток и имён опций, которые он читает.
1998
1862
  *
1999
- * Значения совпадают с теми, что использует сайт итд.com, — поведение библиотеки
2000
- * не отличается от привычного пользователю.
2001
- */
2002
- declare const RECONNECT_BACKOFF: readonly number[];
2003
- /** Доля случайного разброса паузы. */
2004
- declare const RECONNECT_JITTER = 0.3;
2005
- /**
2006
- * Сколько раз пытаться переподключиться подряд.
1863
+ * @example
1864
+ * ```ts
1865
+ * const logging: ItdPlugin = {
1866
+ * name: 'logging',
1867
+ * install({ use, logger }) {
1868
+ * use(async (request, next) => {
1869
+ * logger?.info(`${request.method} ${request.path}`);
1870
+ * return next(request);
1871
+ * });
1872
+ * },
1873
+ * };
2007
1874
  *
2008
- * После исчерпания поток сообщает `giveup` и ждёт ручного `connect()`.
1875
+ * itd.use(logging);
1876
+ * ```
2009
1877
  */
2010
- declare const MAX_RECONNECT_ATTEMPTS = 15;
2011
- /** Настройки переподключения. */
2012
- interface ReconnectOptions {
2013
- /** Таблица пауз. Последнее значение действует для всех дальнейших попыток. */
2014
- backoff?: readonly number[];
1878
+ interface ItdPlugin {
1879
+ /** Имя плагина. Должно быть уникальным: повторное подключение — ошибка. */
1880
+ name: string;
1881
+ /**
1882
+ * Имена опций запроса, которые плагин читает у методов ресурсов.
1883
+ *
1884
+ * Библиотека этих опций не понимает и ничего с ними не делает — только доносит
1885
+ * от вызова метода до обёртки нетронутыми. Без такого списка чужие поля отсеиваются,
1886
+ * чтобы случайная опечатка в параметрах не уезжала на сервер.
1887
+ *
1888
+ * Имена полей самого запроса (`path`, `body`, `headers`, `signal` и прочие из
1889
+ * `RawRequestOptions`) заявить нельзя: подключение такого плагина завершится ошибкой.
1890
+ *
1891
+ * Типы для них плагин объявляет сам, дополняя `RequestOptions`:
1892
+ * ```ts
1893
+ * declare module 'itd-api' {
1894
+ * interface RequestOptions { encrypt?: string | undefined }
1895
+ * }
1896
+ * ```
1897
+ */
1898
+ optionKeys?: readonly string[];
1899
+ /** Вызывается один раз при подключении. */
1900
+ install(context: PluginContext): void;
1901
+ }
1902
+ /**
1903
+ * Список подключённых плагинов и собранная из них цепочка обёрток.
1904
+ *
1905
+ * Живёт в клиенте, а работает в транспорте: {@link HttpClient} прогоняет через `run`
1906
+ * каждый запрос, если плагины есть.
1907
+ */
1908
+ declare class PluginRegistry {
1909
+ #private;
1910
+ /** Сколько обёрток подключено. Ноль означает, что запрос идёт прежним путём. */
1911
+ get size(): number;
1912
+ /** Имена опций запроса, заявленные плагинами. */
1913
+ get optionKeys(): ReadonlySet<string>;
1914
+ /**
1915
+ * Подключает плагин.
1916
+ *
1917
+ * @throws {ItdConfigError} если плагин задан неверно, уже подключён или заявил занятое
1918
+ * имя опции
1919
+ */
1920
+ add(plugin: ItdPlugin, context: Omit<PluginContext, 'use'>): void;
1921
+ /**
1922
+ * Прогоняет запрос через цепочку обёрток.
1923
+ *
1924
+ * Цепочка собирается на каждый запрос заново: плагин можно подключить в любой момент,
1925
+ * а обёрток единицы — экономить тут не на чем.
1926
+ *
1927
+ * @param execute настоящий запрос, вызывается самой внутренней обёрткой
1928
+ */
1929
+ run(request: RawRequestOptions, execute: (request: RawRequestOptions) => Promise<unknown>): Promise<unknown>;
1930
+ }
1931
+
1932
+ /** Событие потока уведомлений после разбора. */
1933
+ interface NotificationEvent {
1934
+ /** Само уведомление в единой форме. */
1935
+ notification: Notification;
1936
+ /**
1937
+ * Актуальное число непрочитанных, если сервер его сообщил.
1938
+ *
1939
+ * Клиент не увеличивает счётчик сам: значение приходит с сервера.
1940
+ */
1941
+ unreadCount: number | undefined;
1942
+ /** Нужно ли проиграть звук. */
1943
+ sound: boolean;
1944
+ }
1945
+ /**
1946
+ * Приводит уведомление к единой форме.
1947
+ *
1948
+ * Нужна потому, что REST-список и поток событий описывают одно и то же событие по-разному:
1949
+ * различаются имена типов (`like` против `post_reaction`), имена полей
1950
+ * (`targetId`/`entityId`, `read`/`isRead`, `preview`/`entityPreview`) и число участников
1951
+ * (`actor` против массива `actors`). После приведения объекты из обоих источников
1952
+ * можно складывать в один список.
1953
+ *
1954
+ * Исходные данные не теряются: имя типа с сервера остаётся в `rawType`,
1955
+ * весь объект целиком — в `raw`.
1956
+ *
1957
+ * @param input уведомление из REST-ответа либо полезная нагрузка события потока
1958
+ *
1959
+ * @example
1960
+ * ```ts
1961
+ * const fromRest = normalizeNotification(restItem);
1962
+ * const fromStream = normalizeNotification(event.payload);
1963
+ * // одинаковая форма — можно объединять
1964
+ * ```
1965
+ */
1966
+ declare function normalizeNotification(input: unknown): Notification;
1967
+ /**
1968
+ * Разбирает событие `notification` из потока.
1969
+ *
1970
+ * Кроме самого уведомления событие несёт служебные поля уровня конверта: актуальный
1971
+ * счётчик непрочитанных и признак звука.
1972
+ */
1973
+ declare function readNotificationEvent(data: unknown): NotificationEvent;
1974
+ /**
1975
+ * Разбирает событие `unread_count` из потока.
1976
+ *
1977
+ * Возвращает `undefined`, если сервер прислал событие без вложенного `payload`.
1978
+ * Официальный клиент в этом случае **обнуляет** счётчик — это ошибка, из-за которой
1979
+ * непрочитанные пропадают из интерфейса.
1980
+ */
1981
+ declare function readUnreadCountEvent(data: unknown): number | undefined;
1982
+
1983
+ /**
1984
+ * Паузы перед попытками переподключения, мс.
1985
+ *
1986
+ * Значения совпадают с теми, что использует сайт итд.com, — поведение библиотеки
1987
+ * не отличается от привычного пользователю.
1988
+ */
1989
+ declare const RECONNECT_BACKOFF: readonly number[];
1990
+ /** Доля случайного разброса паузы. */
1991
+ declare const RECONNECT_JITTER = 0.3;
1992
+ /**
1993
+ * Сколько раз пытаться переподключиться подряд.
1994
+ *
1995
+ * После исчерпания поток сообщает `giveup` и ждёт ручного `connect()`.
1996
+ */
1997
+ declare const MAX_RECONNECT_ATTEMPTS = 15;
1998
+ /** Настройки переподключения. */
1999
+ interface ReconnectOptions {
2000
+ /** Таблица пауз. Последнее значение действует для всех дальнейших попыток. */
2001
+ backoff?: readonly number[];
2015
2002
  /** Доля разброса, 0…1. */
2016
2003
  jitter?: number;
2017
2004
  /** Предел числа попыток. */
@@ -2167,6 +2154,8 @@ interface RealtimeDeps {
2167
2154
  refresh: () => Promise<boolean>;
2168
2155
  /** Загружает начальное число непрочитанных. */
2169
2156
  fetchUnreadCount: () => Promise<number>;
2157
+ /** Вызывается при явном закрытии потока. */
2158
+ onClose?: (() => void) | undefined;
2170
2159
  logger?: Logger | undefined;
2171
2160
  }
2172
2161
  /**
@@ -2215,6 +2204,45 @@ declare class ItdRealtime {
2215
2204
  removeAllListeners(): void;
2216
2205
  }
2217
2206
 
2207
+ /** Что нужно фасаду для работы. */
2208
+ interface HttpClientDeps {
2209
+ /** Готовый обработчик — вся цепочка слоёв поверх транспорта. */
2210
+ handler: RequestHandler;
2211
+ /** Реестр плагинов: у него ресурсы спрашивают имена заявленных опций. */
2212
+ plugins: PluginRegistry;
2213
+ baseUrl: string;
2214
+ }
2215
+ /**
2216
+ * Точка входа ресурсов в конвейер запросов.
2217
+ *
2218
+ * Принимает готовый обработчик — цепочку слоёв поверх транспорта, собранную
2219
+ * в {@link ItdClient}, — и отдаёт ресурсам метод `request` и имена опций плагинов.
2220
+ * О слоях и их порядке ресурсы не знают.
2221
+ */
2222
+ declare class HttpClient {
2223
+ #private;
2224
+ constructor(deps: HttpClientDeps);
2225
+ /** Базовый URL, к которому обращается клиент. */
2226
+ get baseUrl(): string;
2227
+ /**
2228
+ * Имена опций запроса, заявленные плагинами.
2229
+ *
2230
+ * Читается ресурсами: они переносят в транспорт только известные поля, а чужие,
2231
+ * если их никто не заявил, отсеивают.
2232
+ */
2233
+ get pluginOptionKeys(): ReadonlySet<string>;
2234
+ /**
2235
+ * Выполняет запрос к API через собранный конвейер.
2236
+ *
2237
+ * @typeParam T ожидаемая форма ответа после снятия обёртки `{ data: … }`
2238
+ * @throws {ItdApiError} если сервер ответил статусом ≥ 400
2239
+ * @throws {ItdTimeoutError} если истёк таймаут
2240
+ * @throws {ItdAbortError} если запрос отменён через `signal`
2241
+ * @throws {ItdNetworkError} если запрос не дошёл до сервера
2242
+ */
2243
+ request<T = unknown>(options: RawRequestOptions): Promise<T>;
2244
+ }
2245
+
2218
2246
  /**
2219
2247
  * Страница списка — единая форма для всех трёх схем пагинации API.
2220
2248
  *
@@ -2337,17 +2365,50 @@ declare class Paginator<T> implements AsyncIterable<T> {
2337
2365
  collect(max?: number): Promise<T[]>;
2338
2366
  }
2339
2367
 
2368
+ /** Параметры перебираемого списка: опции запроса плюс предел числа страниц. */
2369
+ interface ListParams extends RequestOptions {
2370
+ /** Ограничение числа страниц при переборе. */
2371
+ maxPages?: number | undefined;
2372
+ }
2373
+ /**
2374
+ * Описание перебираемого эндпоинта.
2375
+ *
2376
+ * Одно место, где заданы путь, параметры запроса, чтение страницы и схема пагинации.
2377
+ * {@link BaseResource.paginated} строит из него и разовую загрузку, и перебор.
2378
+ *
2379
+ * @typeParam T тип элемента списка
2380
+ * @typeParam P тип параметров метода
2381
+ */
2382
+ interface ListingSpec<T, P extends ListParams> {
2383
+ /** Путь эндпоинта. */
2384
+ path: (params: P) => string;
2385
+ /** Параметры запроса без полей пагинации — их добавит перебор. */
2386
+ query: (params: P) => QueryParams;
2387
+ /** Читает страницу из ответа. Получает позицию — она нужна схеме со смещением. */
2388
+ read: (body: unknown, state: PageState) => Page<T>;
2389
+ /** Схема пагинации эндпоинта. */
2390
+ mode: PaginationMode;
2391
+ /** Начальная позиция, вычисленная из параметров (курсор, номер или смещение). */
2392
+ start: (params: P) => PageState;
2393
+ }
2394
+ /** Пара методов, собранная из {@link ListingSpec}: разовая загрузка и перебор. */
2395
+ interface Listing<T, P extends ListParams> {
2396
+ /** Загружает одну страницу с позиции, заданной параметрами. */
2397
+ list(params: P): Promise<Page<T>>;
2398
+ /** Перебирает страницы, сама подставляя позиции. */
2399
+ iterate(params: P): Paginator<T>;
2400
+ }
2340
2401
  /** Общая основа всех групп методов клиента. */
2341
2402
  declare class BaseResource {
2342
2403
  /** @internal */
2343
2404
  protected readonly http: HttpClient;
2344
2405
  constructor(http: HttpClient);
2345
2406
  /**
2346
- * Переносит общие поля опций запроса в параметры транспорта.
2407
+ * Переносит опции запроса в описание транспорта.
2347
2408
  *
2348
- * Поля перечислены поимённо, а не скопированы целиком: параметры методов наследуют
2349
- * {@link RequestOptions} и приносят с собой `limit`, `cursor` и прочее, чему в описании
2350
- * запроса делать нечего. Исключение опции, заявленные плагинами: их библиотека
2409
+ * Копируются только поля {@link REQUEST_OPTION_KEYS} и опции, заявленные плагинами:
2410
+ * параметры методов наследуют {@link RequestOptions} и приносят с собой `limit`, `cursor`
2411
+ * и прочее, чему в описании запроса делать нечего. Чужие опции плагинов библиотека
2351
2412
  * не понимает, но обязана донести до обёрток нетронутыми.
2352
2413
  */
2353
2414
  protected requestOptions(options: RequestOptions | undefined): Partial<RequestOptions>;
@@ -2362,6 +2423,24 @@ declare class BaseResource {
2362
2423
  maxPages?: number;
2363
2424
  start?: PageState;
2364
2425
  }): Paginator<T>;
2426
+ /**
2427
+ * Собирает пару «загрузка страницы + перебор» из одного описания.
2428
+ *
2429
+ * Путь, параметры запроса и разбор ответа задаются один раз; `list` и `iterate`
2430
+ * строятся из них.
2431
+ *
2432
+ * @example
2433
+ * ```ts
2434
+ * #feed = this.paginated<Post, FeedParams>({
2435
+ * path: () => '/api/posts',
2436
+ * query: (p) => ({ tab: p.tab, limit: p.limit }),
2437
+ * start: (p) => (p.cursor ? { cursor: p.cursor } : {}),
2438
+ * read: (body) => readCursorPage<Post>(body, 'posts'),
2439
+ * mode: PaginationMode.Cursor,
2440
+ * });
2441
+ * ```
2442
+ */
2443
+ protected paginated<T, P extends ListParams>(spec: ListingSpec<T, P>): Listing<T, P>;
2365
2444
  }
2366
2445
 
2367
2446
  /** Учётные данные для входа. */
@@ -2662,16 +2741,13 @@ type FileReader = (path: string) => Promise<{
2662
2741
  */
2663
2742
  declare class FilesResource extends BaseResource {
2664
2743
  #private;
2744
+ /**
2745
+ * @param deps.readFile чтение файлов с диска. Передаёт точка входа `itd-api/node`;
2746
+ * в основном бандле его нет, чтобы браузерные сборщики не пытались разрешить `node:fs`.
2747
+ */
2665
2748
  constructor(http: HttpClient, deps?: {
2666
2749
  readFile?: FileReader;
2667
2750
  });
2668
- /**
2669
- * Подключает чтение файлов с диска.
2670
- *
2671
- * Вызывается точкой входа `itd-api/node`; в основном бандле работы с файловой
2672
- * системой нет, чтобы браузерные сборщики не пытались разрешить `node:fs`.
2673
- */
2674
- setFileReader(readFile: FileReader): void;
2675
2751
  /**
2676
2752
  * Загружает файл и возвращает его идентификатор.
2677
2753
  *
@@ -2715,17 +2791,13 @@ interface HashtagPostsParams extends RequestOptions {
2715
2791
  cursor?: string;
2716
2792
  maxPages?: number;
2717
2793
  }
2718
- /** Результат глобального поиска. */
2719
- interface SearchResult {
2720
- users: UserSummary[];
2721
- hashtags: Hashtag[];
2722
- }
2723
2794
  /**
2724
2795
  * Хэштеги.
2725
2796
  *
2726
2797
  * Доступна как `itd.hashtags`.
2727
2798
  */
2728
2799
  declare class HashtagsResource extends BaseResource {
2800
+ #private;
2729
2801
  /**
2730
2802
  * Ищет хэштеги.
2731
2803
  *
@@ -2748,139 +2820,6 @@ declare class HashtagsResource extends BaseResource {
2748
2820
  /** Перебирает посты по хэштегу. */
2749
2821
  iteratePosts(tag: string, params?: HashtagPostsParams): Paginator<Post>;
2750
2822
  }
2751
- /**
2752
- * Глобальный поиск.
2753
- *
2754
- * Доступна как `itd.search`.
2755
- */
2756
- declare class SearchResource extends BaseResource {
2757
- /**
2758
- * Ищет пользователей и хэштеги одним запросом.
2759
- *
2760
- * @example
2761
- * ```ts
2762
- * const { users, hashtags } = await itd.search.all('арт');
2763
- * ```
2764
- */
2765
- all(query: string, options?: RequestOptions): Promise<SearchResult>;
2766
- }
2767
- /**
2768
- * Жалобы на контент и пользователей.
2769
- *
2770
- * Доступна как `itd.reports`.
2771
- */
2772
- declare class ReportsResource extends BaseResource {
2773
- /**
2774
- * Отправляет жалобу.
2775
- *
2776
- * Повторная жалоба на тот же объект отклоняется сервером с сообщением
2777
- * «Вы уже отправляли жалобу на этот контент».
2778
- *
2779
- * @example
2780
- * ```ts
2781
- * await itd.reports.create(report.post(postId).reason('spam'));
2782
- * await itd.reports.create({ targetType: 'user', targetId, reason: 'fraud' });
2783
- * ```
2784
- */
2785
- create(input: ReportInput, options?: RequestOptions): Promise<Report>;
2786
- }
2787
- /**
2788
- * Верификация профиля.
2789
- *
2790
- * Доступна как `itd.verification`.
2791
- */
2792
- declare class VerificationResource extends BaseResource {
2793
- /** Загружает статус заявки. Значение `none` означает, что заявка не подавалась. */
2794
- status(options?: RequestOptions): Promise<VerificationStatus>;
2795
- /** Подаёт заявку на верификацию с видео. */
2796
- submit(videoUrl: string, options?: RequestOptions): Promise<unknown>;
2797
- }
2798
- /**
2799
- * Подписка и способы оплаты.
2800
- *
2801
- * Доступна как `itd.subscription`.
2802
- */
2803
- declare class SubscriptionResource extends BaseResource {
2804
- /** Загружает состояние подписки и её цену. */
2805
- status(options?: RequestOptions): Promise<Subscription>;
2806
- /**
2807
- * Запускает оплату подписки.
2808
- *
2809
- * Форма ответа в документации API не описана, поэтому тип результата не уточняется.
2810
- */
2811
- pay(options?: RequestOptions): Promise<unknown>;
2812
- /** Включает или отключает автопродление. */
2813
- setAutoRenewal(enabled: boolean, options?: RequestOptions): Promise<unknown>;
2814
- /** Запускает привязку карты. */
2815
- bindCard(options?: RequestOptions): Promise<unknown>;
2816
- /** Загружает список способов оплаты. Пустой массив, если карт нет. */
2817
- methods(options?: RequestOptions): Promise<PaymentMethod[]>;
2818
- /** Делает способ оплаты основным. */
2819
- setDefaultMethod(methodId: string, options?: RequestOptions): Promise<unknown>;
2820
- /** Удаляет способ оплаты. */
2821
- removeMethod(methodId: string, options?: RequestOptions): Promise<void>;
2822
- }
2823
- /**
2824
- * Сведения о платформе: изменения, анонсы, баннер события.
2825
- *
2826
- * Доступна как `itd.platform`.
2827
- */
2828
- declare class PlatformResource extends BaseResource {
2829
- /** Загружает журнал изменений. */
2830
- changelog(options?: RequestOptions): Promise<ChangelogEntry[]>;
2831
- /** Загружает анонсы платформы. */
2832
- announcements(options?: RequestOptions): Promise<Announcement[]>;
2833
- /** Загружает баннер текущего события — виджет «портал». */
2834
- portal(options?: RequestOptions): Promise<Portal>;
2835
- }
2836
- /** Запись о времени просмотра поста. */
2837
- interface DwellEntry {
2838
- /** Идентификатор поста. */
2839
- postId: string;
2840
- /** Сколько миллисекунд пост был виден. */
2841
- duration: number;
2842
- /** Служебная метка показа из поля `vs` объекта поста. */
2843
- vs?: string;
2844
- }
2845
- /** Запись о взаимодействии с контентом. */
2846
- interface InteractionEntry {
2847
- /** Тип взаимодействия: `photo_open`, `video_progress` и подобные. */
2848
- type: string;
2849
- /** Значение, смысл которого зависит от типа: доля просмотра, номер кадра. */
2850
- value?: number;
2851
- /** Идентификатор поста. */
2852
- postId?: string;
2853
- /** Идентификатор вложения. */
2854
- attachmentId?: string;
2855
- /** Служебная метка показа. */
2856
- vs?: string;
2857
- }
2858
- /**
2859
- * Телеметрия просмотров.
2860
- *
2861
- * @experimental Эндпоинты `/api/v1/i` и `/api/v1/x` нигде не описаны, а схема их полей
2862
- * не проверена на реальных запросах и может измениться без предупреждения.
2863
- *
2864
- * **Библиотека никогда не отправляет телеметрию сама.** Эти методы нужны только тем,
2865
- * кто пишет собственный клиент платформы; всем остальным их вызывать не требуется.
2866
- *
2867
- * Доступна как `itd.telemetry`.
2868
- */
2869
- declare class TelemetryResource extends BaseResource {
2870
- /**
2871
- * Отправляет время просмотра постов.
2872
- *
2873
- * @experimental Имена полей на проводе сжаты (`ai`, `v`, `s`), и их соответствие
2874
- * смыслу **не проверено** на реальных запросах. Может измениться без предупреждения.
2875
- */
2876
- dwell(entries: DwellEntry[], options?: RequestOptions): Promise<unknown>;
2877
- /**
2878
- * Отправляет события взаимодействия с контентом.
2879
- *
2880
- * @experimental См. предупреждение у {@link TelemetryResource}.
2881
- */
2882
- interaction(entries: InteractionEntry[], options?: RequestOptions): Promise<unknown>;
2883
- }
2884
2823
 
2885
2824
  /** Параметры запроса списка уведомлений. */
2886
2825
  interface NotificationListParams extends RequestOptions {
@@ -2902,8 +2841,7 @@ declare class NotificationsResource extends BaseResource {
2902
2841
  /**
2903
2842
  * Загружает страницу уведомлений.
2904
2843
  *
2905
- * Пагинация здесь основана на смещении. Сайт итд.com оборачивает смещение в строку
2906
- * и притворяется, что это курсор; библиотека отдаёт честное число.
2844
+ * Пагинация здесь основана на смещении.
2907
2845
  *
2908
2846
  * @example
2909
2847
  * ```ts
@@ -2953,6 +2891,20 @@ declare class NotificationsResource extends BaseResource {
2953
2891
  updateSettings(input: UpdateNotificationSettingsInput, options?: RequestOptions): Promise<NotificationSettings>;
2954
2892
  }
2955
2893
 
2894
+ /**
2895
+ * Сведения о платформе: изменения, анонсы, баннер события.
2896
+ *
2897
+ * Доступна как `itd.platform`.
2898
+ */
2899
+ declare class PlatformResource extends BaseResource {
2900
+ /** Загружает журнал изменений. */
2901
+ changelog(options?: RequestOptions): Promise<ChangelogEntry[]>;
2902
+ /** Загружает анонсы платформы. */
2903
+ announcements(options?: RequestOptions): Promise<Announcement[]>;
2904
+ /** Загружает баннер текущего события — виджет «портал». */
2905
+ portal(options?: RequestOptions): Promise<Portal>;
2906
+ }
2907
+
2956
2908
  /** Параметры запроса ленты. */
2957
2909
  interface FeedParams extends RequestOptions {
2958
2910
  /** Вкладка ленты. По умолчанию сервер отдаёт популярное. */
@@ -3121,6 +3073,165 @@ declare class PostsResource extends BaseResource {
3121
3073
  voiceComment(postId: string, audio: FileInput, options?: RequestOptions): Promise<Comment>;
3122
3074
  }
3123
3075
 
3076
+ /**
3077
+ * Жалобы на контент и пользователей.
3078
+ *
3079
+ * Доступна как `itd.reports`.
3080
+ */
3081
+ declare class ReportsResource extends BaseResource {
3082
+ /**
3083
+ * Отправляет жалобу.
3084
+ *
3085
+ * Повторная жалоба на тот же объект отклоняется сервером с сообщением
3086
+ * «Вы уже отправляли жалобу на этот контент».
3087
+ *
3088
+ * @example
3089
+ * ```ts
3090
+ * await itd.reports.create(report.post(postId).reason('spam'));
3091
+ * await itd.reports.create({ targetType: 'user', targetId, reason: 'fraud' });
3092
+ * ```
3093
+ */
3094
+ create(input: ReportInput, options?: RequestOptions): Promise<Report>;
3095
+ }
3096
+
3097
+ /** Результат глобального поиска. */
3098
+ interface SearchResult {
3099
+ users: UserSummary[];
3100
+ hashtags: Hashtag[];
3101
+ }
3102
+ /**
3103
+ * Глобальный поиск.
3104
+ *
3105
+ * Доступна как `itd.search`.
3106
+ */
3107
+ declare class SearchResource extends BaseResource {
3108
+ /**
3109
+ * Ищет пользователей и хэштеги одним запросом.
3110
+ *
3111
+ * @example
3112
+ * ```ts
3113
+ * const { users, hashtags } = await itd.search.all('арт');
3114
+ * ```
3115
+ */
3116
+ all(query: string, options?: RequestOptions): Promise<SearchResult>;
3117
+ }
3118
+
3119
+ /**
3120
+ * Подписка и способы оплаты.
3121
+ *
3122
+ * Доступна как `itd.subscription`.
3123
+ */
3124
+ declare class SubscriptionResource extends BaseResource {
3125
+ /** Загружает состояние подписки и её цену. */
3126
+ status(options?: RequestOptions): Promise<Subscription>;
3127
+ /**
3128
+ * Запускает оплату подписки.
3129
+ *
3130
+ * Форма ответа в документации API не описана, поэтому тип результата не уточняется.
3131
+ */
3132
+ pay(options?: RequestOptions): Promise<unknown>;
3133
+ /** Включает или отключает автопродление. */
3134
+ setAutoRenewal(enabled: boolean, options?: RequestOptions): Promise<unknown>;
3135
+ /** Запускает привязку карты. */
3136
+ bindCard(options?: RequestOptions): Promise<unknown>;
3137
+ /** Загружает список способов оплаты. Пустой массив, если карт нет. */
3138
+ methods(options?: RequestOptions): Promise<PaymentMethod[]>;
3139
+ /** Делает способ оплаты основным. */
3140
+ setDefaultMethod(methodId: string, options?: RequestOptions): Promise<unknown>;
3141
+ /** Удаляет способ оплаты. */
3142
+ removeMethod(methodId: string, options?: RequestOptions): Promise<void>;
3143
+ }
3144
+
3145
+ /**
3146
+ * Общие опции запроса телеметрии.
3147
+ *
3148
+ * Помимо {@link RequestOptions} позволяет задать `sid` — идентификатор сессии телеметрии.
3149
+ * По умолчанию он заводится один на объект {@link TelemetryResource}.
3150
+ */
3151
+ interface TelemetryOptions extends RequestOptions {
3152
+ /** Переопределяет идентификатор сессии телеметрии (`sid`) для этого запроса. */
3153
+ sid?: string;
3154
+ }
3155
+ /**
3156
+ * Событие просмотра поста для {@link TelemetryResource.dwell}.
3157
+ *
3158
+ * Пост определяется меткой показа `vs` и, при наличии, контекстом источника `sc`; поля
3159
+ * `postId` эндпоинт `/api/v1/i` не принимает.
3160
+ */
3161
+ interface DwellEntry {
3162
+ /** Метка показа — поле `vs` объекта поста. Уходит в поле `v`. */
3163
+ vs: string;
3164
+ /** Время появления поста в зоне видимости, epoch-мс. Поле `et`. */
3165
+ enterAt: number;
3166
+ /** Время ухода из зоны видимости, epoch-мс. Поле `xt`. */
3167
+ exitAt: number;
3168
+ /** Причина завершения просмотра. Поле `r`. */
3169
+ reason: ViewReason;
3170
+ /**
3171
+ * Длительность просмотра в мс. Поле `md`.
3172
+ *
3173
+ * Если не задано, вычисляется как `exitAt − enterAt`.
3174
+ */
3175
+ durationMs?: number;
3176
+ /** Контекст источника показа. Поле `sc`. */
3177
+ sourceContext?: string;
3178
+ /** Источник показа. Применим к `PostPage`/`Link`. Поле `s`. */
3179
+ source?: ViewSource;
3180
+ /** Повторный просмотр: пост уже встречался в этой сессии. Уходит как `b: 1`. */
3181
+ repeat?: boolean;
3182
+ }
3183
+ /** Событие взаимодействия с контентом для {@link TelemetryResource.interaction}. */
3184
+ interface InteractionEntry {
3185
+ /** Тип взаимодействия. Поле `t`. */
3186
+ type: InteractionType;
3187
+ /** Метка показа — поле `vs` объекта поста. Поле `v`. */
3188
+ vs: string;
3189
+ /** Идентификатор поста. Поле `ai`. */
3190
+ postId: string;
3191
+ /** Индекс вложения (с нуля) — для {@link InteractionType.PhotoOpen}. Поле `mi`. */
3192
+ mediaIndex?: number;
3193
+ /** Источник показа. Поле `s`. */
3194
+ source?: ViewSource;
3195
+ /** Просмотрено мс — для {@link InteractionType.VideoProgress}. Поле `pm`. */
3196
+ positionMs?: number;
3197
+ /** Длительность видео в мс — для {@link InteractionType.VideoProgress}. Поле `dm`. */
3198
+ durationMs?: number;
3199
+ }
3200
+ /**
3201
+ * Телеметрия просмотров.
3202
+ *
3203
+ * @experimental Недокументированные эндпоинты `/api/v1/i` (просмотры) и `/api/v1/x`
3204
+ * (взаимодействия); формат полей может измениться без предупреждения.
3205
+ *
3206
+ * Методы не вызываются автоматически — телеметрия отправляется только явным вызовом.
3207
+ *
3208
+ * Оба эндпоинта принимают конверт `{ sid, e }`, где `sid` — идентификатор сессии
3209
+ * телеметрии: по умолчанию один на объект, переопределяется опцией `sid`.
3210
+ *
3211
+ * Доступна как `itd.telemetry`.
3212
+ */
3213
+ declare class TelemetryResource extends BaseResource {
3214
+ #private;
3215
+ /**
3216
+ * Идентификатор сессии телеметрии (`sid`).
3217
+ *
3218
+ * Создаётся лениво при первом обращении и далее неизменен.
3219
+ */
3220
+ get sessionId(): string;
3221
+ /**
3222
+ * Отправляет события просмотра постов (`POST /api/v1/i`).
3223
+ *
3224
+ * @experimental См. предупреждение у {@link TelemetryResource}.
3225
+ */
3226
+ dwell(entries: DwellEntry[], options?: TelemetryOptions): Promise<unknown>;
3227
+ /**
3228
+ * Отправляет события взаимодействия с контентом (`POST /api/v1/x`).
3229
+ *
3230
+ * @experimental См. предупреждение у {@link TelemetryResource}.
3231
+ */
3232
+ interaction(entries: InteractionEntry[], options?: TelemetryOptions): Promise<unknown>;
3233
+ }
3234
+
3124
3235
  /**
3125
3236
  * Параметры списков пользователей.
3126
3237
  *
@@ -3256,6 +3367,34 @@ declare class UsersResource extends BaseResource {
3256
3367
  removePin(options?: RequestOptions): Promise<void>;
3257
3368
  }
3258
3369
 
3370
+ /**
3371
+ * Верификация профиля.
3372
+ *
3373
+ * Доступна как `itd.verification`.
3374
+ */
3375
+ declare class VerificationResource extends BaseResource {
3376
+ /** Загружает статус заявки. Значение `none` означает, что заявка не подавалась. */
3377
+ status(options?: RequestOptions): Promise<VerificationStatus>;
3378
+ /** Подаёт заявку на верификацию с видео. */
3379
+ submit(videoUrl: string, options?: RequestOptions): Promise<unknown>;
3380
+ }
3381
+
3382
+ declare global {
3383
+ interface SymbolConstructor {
3384
+ readonly asyncDispose: unique symbol;
3385
+ }
3386
+ }
3387
+ /**
3388
+ * Скрытые параметры конструктора — не часть публичного API.
3389
+ *
3390
+ * Через них точка входа `itd-api/node` передаёт чтение файлов с диска, не мутируя уже
3391
+ * созданный объект.
3392
+ *
3393
+ * @internal
3394
+ */
3395
+ interface ItdClientInternals {
3396
+ fileReader?: FileReader | undefined;
3397
+ }
3259
3398
  /**
3260
3399
  * Клиент API итд.com.
3261
3400
  *
@@ -3319,7 +3458,7 @@ declare class ItdClient {
3319
3458
  * @experimental Недокументированные эндпоинты. Библиотека никогда не отправляет их сама.
3320
3459
  */
3321
3460
  readonly telemetry: TelemetryResource;
3322
- constructor(options?: ItdClientOptions);
3461
+ constructor(options?: ItdClientOptions, internals?: ItdClientInternals);
3323
3462
  /** Базовый URL, к которому обращается клиент. */
3324
3463
  get baseUrl(): string;
3325
3464
  /**
@@ -3386,18 +3525,27 @@ declare class ItdClient {
3386
3525
  * ```
3387
3526
  */
3388
3527
  realtime(options?: RealtimeOptions): ItdRealtime;
3389
- /** Текущая сессия целиком — чтобы сохранить её самостоятельно. */
3390
- getSession(): Promise<ItdSession | null>;
3391
- /** Восстанавливает сохранённую сессию, включая cookie. */
3392
- setSession(session: ItdSession): Promise<void>;
3393
3528
  /**
3394
- * Подключает чтение файлов с диска.
3529
+ * Освобождает ресурсы клиента: останавливает очередь запросов (снимает отложенные паузы)
3530
+ * и закрывает все потоки уведомлений, созданные через {@link realtime}.
3395
3531
  *
3396
- * Вызывается из `itd-api/node`; напрямую обычно не нужно.
3532
+ * После вызова клиентом можно пользоваться снова — новые запросы поднимут всё заново,
3533
+ * но уже созданные потоки останутся закрытыми.
3397
3534
  *
3398
- * @internal
3535
+ * @example
3536
+ * ```ts
3537
+ * await using itd = new ItdClient({ auth: token });
3538
+ * // …работа…
3539
+ * // close() вызовется сам на выходе из блока
3540
+ * ```
3399
3541
  */
3400
- setFileReader(readFile: FileReader): void;
3542
+ close(): Promise<void>;
3543
+ /** Позволяет использовать клиент с `await using`. */
3544
+ [Symbol.asyncDispose](): Promise<void>;
3545
+ /** Текущая сессия целиком — чтобы сохранить её самостоятельно. */
3546
+ getSession(): Promise<ItdSession | null>;
3547
+ /** Восстанавливает сохранённую сессию, включая cookie. */
3548
+ setSession(session: ItdSession): Promise<void>;
3401
3549
  }
3402
3550
  /**
3403
3551
  * Создаёт клиент API итд.com.
@@ -3782,4 +3930,4 @@ interface SseTransportOptions {
3782
3930
  idleTimeout?: number;
3783
3931
  }
3784
3932
 
3785
- export { IMAGE_MIME_TYPES as $, ALLOWED_MIME_TYPES as A, type BuilderInput as B, type CaptchaCredentials as C, type CreatePollInput as D, type CreatePostInput as E, type FileReader as F, type CreateReportInput as G, type Credentials as H, type ItdSession as I, type CredentialsAuth as J, DEFAULT_BASE_URL as K, DEFAULT_TIMEOUT as L, DEFAULT_USER_AGENT as M, DEVICE_ID_HEADER as N, DetectedRuntime as O, type DwellEntry as P, type ErrorContextHook as Q, type FeedParams as R, FeedTab as S, type TokenStorage as T, type FileInput as U, FilesResource as V, type FollowResult as W, type ForgotPasswordInput as X, type Hashtag as Y, type HashtagPostsParams as Z, HashtagsResource as _, ItdClient as a, PostsResource as a$, type ImageMimeType as a0, type InteractionEntry as a1, type IsoDate as a2, ItdAbortError as a3, ItdApiError as a4, type ItdApiErrorInit as a5, ItdApiErrorKind as a6, ItdAuthError as a7, type ItdBuilder as a8, ItdConfigError as a9, type Notification as aA, type NotificationEvent as aB, type NotificationListParams as aC, type NotificationSettings as aD, NotificationType as aE, NotificationsResource as aF, OAuthProvider as aG, type Page as aH, type PageState as aI, PaginationMode as aJ, Paginator as aK, type PaymentMethod as aL, type Pin as aM, type PinPostResult as aN, type PinsResult as aO, PlatformResource as aP, type PluginContext as aQ, type Poll as aR, PollBuilder as aS, type PollInput as aT, type PollOption as aU, type PollTransportOptions as aV, type Portal as aW, type Post as aX, PostBuilder as aY, type PostInput as aZ, type PostStats as a_, ItdConflictError as aa, ItdError as ab, ItdErrorCode as ac, ItdErrorKind as ad, type ItdFieldErrors as ae, ItdForbiddenError as af, ItdNetworkError as ag, ItdNotFoundError as ah, ItdPhoneVerificationError as ai, type ItdPlugin as aj, ItdRateLimitError as ak, ItdRealtime as al, ItdServerError as am, ItdTimeoutError as an, ItdValidationError as ao, LIBRARY_VERSION as ap, type LikeResult as aq, LikesVisibility as ar, type Listener as as, LocalStorageTokenStorage as at, type Logger as au, type Loose as av, MAX_RECONNECT_ATTEMPTS as aw, MemoryTokenStorage as ax, type MyProfile as ay, NOTIFICATION_TYPE_ALIASES as az, type ItdClientOptions as b, WallAccess as b$, type PrivacySettings as b0, type Profile as b1, type PublicProfile as b2, RECONNECT_BACKOFF as b3, RECONNECT_JITTER as b4, REFRESH_COOKIE as b5, REFRESH_COOKIE_PATH as b6, type RateLimitOptions as b7, type RawRequestOptions as b8, type RealtimeEvents as b9, SpanType as bA, type SseTransportOptions as bB, type Subscription as bC, SubscriptionResource as bD, type SubscriptionState as bE, TURNSTILE_SITE_KEY as bF, TelemetryResource as bG, type Transformer as bH, type TransportContext as bI, type TransportEvent as bJ, UnauthorizedStreamError as bK, type Unsubscribe as bL, type UpdateNotificationSettingsInput as bM, type UpdatePrivacyInput as bN, type UpdateProfileInput as bO, type UploadOptions as bP, type UploadedFile as bQ, type UserId as bR, type UserListParams as bS, type UserPostsParams as bT, type UserRef as bU, type UserSummary as bV, UsersResource as bW, VIDEO_MIME_TYPES as bX, VerificationResource as bY, type VerificationStatus as bZ, type VideoMimeType as b_, type RealtimeOptions as ba, RealtimeStatus as bb, type RealtimeTransport as bc, RealtimeTransportKind as bd, type ReconnectOptions as be, type RepliesParams as bf, type Report as bg, ReportBuilder as bh, type ReportInput as bi, ReportReason as bj, ReportTargetType as bk, ReportsResource as bl, type RequestContext as bm, type RequestOptions as bn, type ResetPasswordInput as bo, type ResponseContext as bp, type RetryContext as bq, type RetryOptions as br, RuntimeMode as bs, STREAM_PATH as bt, SearchResource as bu, type SearchResult as bv, type Session as bw, type SignInResult as bx, SignInStatus as by, type Span as bz, AUDIO_MIME_TYPES as c, canonicalNotificationType as c0, comment as c1, createTokenStorage as c2, formatNotificationText as c3, isBuilder as c4, isItdApiError as c5, isItdAuthError as c6, isItdConflictError as c7, isItdError as c8, isItdForbiddenError as c9, isItdNotFoundError as ca, isItdPhoneVerificationError as cb, isItdRateLimitError as cc, isItdServerError as cd, isItdValidationError as ce, isKnownNotificationType as cf, isMyProfile as cg, normalizeNotification as ch, poll as ci, post as cj, readNotificationEvent as ck, readUnreadCountEvent as cl, report as cm, resolveNotificationUrl as cn, toDate as co, createClient as cp, AUTH_FLAG_COOKIE as d, AUTH_PATHS as e, type Actor as f, type AllowedMimeType as g, type Announcement as h, type AnnouncementButton as i, type Attachment as j, AttachmentType as k, type AudioMimeType as l, type AuthInput as m, AuthResource as n, type Author as o, type ChangelogEntry as p, type Clan as q, type ClientHooks as r, type Comment as s, CommentBuilder as t, type CommentInput as u, type CommentReplyTo as v, CommentSort as w, type CommentsParams as x, CommentsResource as y, type CreateCommentInput as z };
3933
+ export { HashtagsResource as $, ALLOWED_MIME_TYPES as A, type BuilderInput as B, type CaptchaCredentials as C, type CreateCommentInput as D, type CreatePollInput as E, type FileReader as F, type CreatePostInput as G, type CreateReportInput as H, type ItdSession as I, type Credentials as J, type CredentialsAuth as K, DEFAULT_BASE_URL as L, DEFAULT_TIMEOUT as M, DEFAULT_USER_AGENT as N, DEVICE_ID_HEADER as O, DetectedRuntime as P, type DwellEntry as Q, type ErrorContextHook as R, type FeedParams as S, type TokenStorage as T, FeedTab as U, type FileInput as V, FilesResource as W, type FollowResult as X, type ForgotPasswordInput as Y, type Hashtag as Z, type HashtagPostsParams as _, ItdClient as a, type PostInput as a$, IMAGE_MIME_TYPES as a0, type ImageMimeType as a1, type InteractionEntry as a2, InteractionType as a3, type IsoDate as a4, ItdAbortError as a5, ItdApiError as a6, type ItdApiErrorInit as a7, ItdApiErrorKind as a8, ItdAuthError as a9, type MyProfile as aA, NOTIFICATION_TYPE_ALIASES as aB, type Notification as aC, type NotificationEvent as aD, type NotificationListParams as aE, type NotificationSettings as aF, NotificationType as aG, NotificationsResource as aH, OAuthProvider as aI, type Page as aJ, type PageState as aK, PaginationMode as aL, Paginator as aM, type PaymentMethod as aN, type Pin as aO, type PinPostResult as aP, type PinsResult as aQ, PlatformResource as aR, type PluginContext as aS, type Poll as aT, PollBuilder as aU, type PollInput as aV, type PollOption as aW, type PollTransportOptions as aX, type Portal as aY, type Post as aZ, PostBuilder as a_, type ItdBuilder as aa, ItdConfigError as ab, ItdConflictError as ac, ItdError as ad, ItdErrorCode as ae, ItdErrorKind as af, type ItdFieldErrors as ag, ItdForbiddenError as ah, ItdNetworkError as ai, ItdNotFoundError as aj, ItdPhoneVerificationError as ak, type ItdPlugin as al, ItdRateLimitError as am, ItdRealtime as an, ItdServerError as ao, ItdTimeoutError as ap, ItdValidationError as aq, LIBRARY_VERSION as ar, type LikeResult as as, LikesVisibility as at, type Listener as au, LocalStorageTokenStorage as av, type Logger as aw, type Loose as ax, MAX_RECONNECT_ATTEMPTS as ay, MemoryTokenStorage as az, type ItdClientOptions as b, VerificationResource as b$, type PostStats as b0, PostsResource as b1, type PrivacySettings as b2, type Profile as b3, type PublicProfile as b4, RECONNECT_BACKOFF as b5, RECONNECT_JITTER as b6, REFRESH_COOKIE as b7, REFRESH_COOKIE_PATH as b8, type RateLimitOptions as b9, SignInStatus as bA, type Span as bB, SpanType as bC, type SseTransportOptions as bD, type Subscription as bE, SubscriptionResource as bF, type SubscriptionState as bG, TURNSTILE_SITE_KEY as bH, type TelemetryOptions as bI, TelemetryResource as bJ, type Transformer as bK, type TransportContext as bL, type TransportEvent as bM, UnauthorizedStreamError as bN, type Unsubscribe as bO, type UpdateNotificationSettingsInput as bP, type UpdatePrivacyInput as bQ, type UpdateProfileInput as bR, type UploadOptions as bS, type UploadedFile as bT, type UserId as bU, type UserListParams as bV, type UserPostsParams as bW, type UserRef as bX, type UserSummary as bY, UsersResource as bZ, VIDEO_MIME_TYPES as b_, type RawRequestOptions as ba, type RealtimeEvents as bb, type RealtimeOptions as bc, RealtimeStatus as bd, type RealtimeTransport as be, RealtimeTransportKind as bf, type ReconnectOptions as bg, type RepliesParams as bh, type Report as bi, ReportBuilder as bj, type ReportInput as bk, ReportReason as bl, ReportTargetType as bm, ReportsResource as bn, type RequestContext as bo, type RequestOptions as bp, type ResetPasswordInput as bq, type ResponseContext as br, type RetryContext as bs, type RetryOptions as bt, RuntimeMode as bu, STREAM_PATH as bv, SearchResource as bw, type SearchResult as bx, type Session as by, type SignInResult as bz, AUDIO_MIME_TYPES as c, type VerificationStatus as c0, type VideoMimeType as c1, ViewReason as c2, ViewSource as c3, WallAccess as c4, canonicalNotificationType as c5, comment as c6, createTokenStorage as c7, formatNotificationText as c8, isBuilder as c9, isItdApiError as ca, isItdAuthError as cb, isItdConflictError as cc, isItdError as cd, isItdForbiddenError as ce, isItdNotFoundError as cf, isItdPhoneVerificationError as cg, isItdRateLimitError as ch, isItdServerError as ci, isItdValidationError as cj, isKnownNotificationType as ck, isMyProfile as cl, normalizeNotification as cm, poll as cn, post as co, readNotificationEvent as cp, readUnreadCountEvent as cq, report as cr, resolveNotificationUrl as cs, toDate as ct, createClient as cu, AUTH_FLAG_COOKIE as d, AUTH_PATHS as e, AccessType as f, type Actor as g, type AllowedMimeType as h, type Announcement as i, type AnnouncementButton as j, type Attachment as k, AttachmentType as l, type AudioMimeType as m, type AuthInput as n, AuthResource as o, type Author as p, type ChangelogEntry as q, type Clan as r, type ClientHooks as s, type Comment as t, CommentBuilder as u, type CommentInput as v, type CommentReplyTo as w, CommentSort as x, type CommentsParams as y, CommentsResource as z };