itd-api 0.6.0 → 0.7.1

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.
Files changed (90) hide show
  1. package/README.md +6 -6
  2. package/dist/index.cjs +473 -9378
  3. package/dist/index.cjs.map +1 -1
  4. package/dist/index.d.cts +300 -4830
  5. package/dist/index.d.ts +300 -4830
  6. package/dist/index.js +350 -9259
  7. package/dist/index.js.map +1 -1
  8. package/dist/{node.cjs → node/index.cjs} +16 -14
  9. package/dist/node/index.cjs.map +1 -0
  10. package/dist/{node.d.cts → node/index.d.cts} +4 -3
  11. package/dist/{node.d.ts → node/index.d.ts} +4 -3
  12. package/dist/{node.js → node/index.js} +5 -3
  13. package/dist/node/index.js.map +1 -0
  14. package/dist/realtime/index.cjs +165 -0
  15. package/dist/realtime/index.cjs.map +1 -0
  16. package/dist/realtime/index.d.cts +51 -0
  17. package/dist/realtime/index.d.ts +51 -0
  18. package/dist/realtime/index.js +120 -0
  19. package/dist/realtime/index.js.map +1 -0
  20. package/dist/rest/index.cjs +334 -0
  21. package/dist/rest/index.cjs.map +1 -0
  22. package/dist/rest/index.d.cts +138 -0
  23. package/dist/rest/index.d.ts +138 -0
  24. package/dist/rest/index.js +238 -0
  25. package/dist/rest/index.js.map +1 -0
  26. package/dist/shared/auth-provider-BfogACAb.js +91 -0
  27. package/dist/shared/auth-provider-BfogACAb.js.map +1 -0
  28. package/dist/shared/auth-provider-CTJkKfgy.cjs +108 -0
  29. package/dist/shared/auth-provider-CTJkKfgy.cjs.map +1 -0
  30. package/dist/shared/contracts-BoT7msmq.d.cts +84 -0
  31. package/dist/shared/contracts-BoT7msmq.d.ts +84 -0
  32. package/dist/{multi-storage-Bf84xiO8.cjs → shared/cookies-DZwFq6kr.cjs} +98 -429
  33. package/dist/shared/cookies-DZwFq6kr.cjs.map +1 -0
  34. package/dist/{multi-storage-BUZaLAPO.js → shared/cookies-tX2sNwxb.js} +99 -352
  35. package/dist/shared/cookies-tX2sNwxb.js.map +1 -0
  36. package/dist/{storage-IHdXw52v.js → shared/errors-Bhrd2fJd.js} +2 -229
  37. package/dist/shared/errors-Bhrd2fJd.js.map +1 -0
  38. package/dist/{storage-DnzZPS_9.cjs → shared/errors-DfU8M5eS.cjs} +1 -288
  39. package/dist/shared/errors-DfU8M5eS.cjs.map +1 -0
  40. package/dist/shared/multi-storage--yTEqiod.cjs +150 -0
  41. package/dist/shared/multi-storage--yTEqiod.cjs.map +1 -0
  42. package/dist/shared/multi-storage-CjAPB5Kq.d.cts +72 -0
  43. package/dist/shared/multi-storage-CkvTUC5m.js +121 -0
  44. package/dist/shared/multi-storage-CkvTUC5m.js.map +1 -0
  45. package/dist/shared/multi-storage-DccjD7Ww.d.ts +72 -0
  46. package/dist/shared/options-Dg5N3r1V.cjs +189 -0
  47. package/dist/shared/options-Dg5N3r1V.cjs.map +1 -0
  48. package/dist/shared/options-DtATYdLr.js +142 -0
  49. package/dist/shared/options-DtATYdLr.js.map +1 -0
  50. package/dist/shared/render-DMp_3Nzk.d.cts +2250 -0
  51. package/dist/shared/render-DZrxhC5_.d.ts +2250 -0
  52. package/dist/shared/render-DyeHJNBw.cjs +4147 -0
  53. package/dist/shared/render-DyeHJNBw.cjs.map +1 -0
  54. package/dist/shared/render-vtLixIiU.js +3992 -0
  55. package/dist/shared/render-vtLixIiU.js.map +1 -0
  56. package/dist/shared/storage-BPJR_k4-.cjs +290 -0
  57. package/dist/shared/storage-BPJR_k4-.cjs.map +1 -0
  58. package/dist/{storage-BqMxs76Y.d.ts → shared/storage-C_eICCep.d.cts} +2 -2
  59. package/dist/{storage-BqMxs76Y.d.cts → shared/storage-C_eICCep.d.ts} +2 -2
  60. package/dist/shared/storage-D86edNCB.js +231 -0
  61. package/dist/shared/storage-D86edNCB.js.map +1 -0
  62. package/dist/shared/url-B6-bXHKt.d.cts +2083 -0
  63. package/dist/shared/url-B6-bXHKt.d.ts +2083 -0
  64. package/dist/shared/url-CYXgxqGx.js +3673 -0
  65. package/dist/shared/url-CYXgxqGx.js.map +1 -0
  66. package/dist/shared/url-yjl2c8Ie.cjs +4032 -0
  67. package/dist/shared/url-yjl2c8Ie.cjs.map +1 -0
  68. package/dist/shared/websocket-BMtihD56.d.ts +562 -0
  69. package/dist/shared/websocket-CbzB1Leq.js +1874 -0
  70. package/dist/shared/websocket-CbzB1Leq.js.map +1 -0
  71. package/dist/shared/websocket-D1p32SB2.d.cts +562 -0
  72. package/dist/shared/websocket-sYlynrr0.cjs +1945 -0
  73. package/dist/shared/websocket-sYlynrr0.cjs.map +1 -0
  74. package/dist/{web.cjs → web/index.cjs} +4 -3
  75. package/dist/web/index.cjs.map +1 -0
  76. package/dist/{web.d.cts → web/index.d.cts} +2 -2
  77. package/dist/{web.d.ts → web/index.d.ts} +2 -2
  78. package/dist/{web.js → web/index.js} +3 -2
  79. package/dist/web/index.js.map +1 -0
  80. package/package.json +40 -12
  81. package/dist/multi-storage-BUZaLAPO.js.map +0 -1
  82. package/dist/multi-storage-BUoEoW8f.d.cts +0 -154
  83. package/dist/multi-storage-Bf84xiO8.cjs.map +0 -1
  84. package/dist/multi-storage-CQSlI_kn.d.ts +0 -154
  85. package/dist/node.cjs.map +0 -1
  86. package/dist/node.js.map +0 -1
  87. package/dist/storage-DnzZPS_9.cjs.map +0 -1
  88. package/dist/storage-IHdXw52v.js.map +0 -1
  89. package/dist/web.cjs.map +0 -1
  90. package/dist/web.js.map +0 -1
@@ -0,0 +1,2250 @@
1
+ import { $ as UserSummary, B as Notification, Ct as ReportReason, Dt as ViewReason, Ft as Logger, G as FollowResult, It as OperationRequestOptions, J as PinsResult, K as MyProfile, Lt as PaginationOptions, Mt as Unsubscribe, Ot as ViewSource, Tt as ServiceState, V as NotificationSettings, W as Author, Wt as RequestOptions, X as Profile, Xt as QueryParams, Y as PrivacySettings, Z as PublicProfile, _t as InteractionType, bt as Loose, ct as IsoDate, dt as UserRef, et as AuthIdentity, gn as RetrySafety, gt as IncidentKind, hn as OperationMethod, ht as FeedTab, lt as Span, mt as CommentSort, pt as AttachmentType, rn as BuiltInOperationId, sn as OperationId, ut as UserId, wt as ReportTargetType, zt as RateLimitBucketOverride } from "./url-B6-bXHKt.js";
2
+ import { c as LazyFile, d as UrlFileOptions, i as FileStreamContent, l as StreamFile, n as FileContext, o as FileTransferMode, r as FileInput, s as FromStreamOptions } from "./contracts-BoT7msmq.js";
3
+ //#region src/core/catalog.d.ts
4
+ /**
5
+ * Всё, что ядро знает о предметной области.
6
+ *
7
+ * Ядро исполняет операцию, не зная, что такое пост, комментарий или профиль: оно спрашивает
8
+ * каталог о повторяемости, методе и счётчике частоты, а таблицы конкретного API живут
9
+ * в доменном слое. Именно эта граница позволяет позже вынести retry и планировщик очереди
10
+ * в отдельные слоты executor, не таща за ними каталог эндпоинтов.
11
+ *
12
+ * @internal
13
+ */
14
+ interface OperationCatalog {
15
+ /** Безопасность повтора операции. `undefined` — операция каталогу неизвестна. */
16
+ retrySafetyOf(id: string): RetrySafety | undefined;
17
+ /** HTTP-метод операции. `undefined` — операция каталогу неизвестна. */
18
+ methodOf(id: string): OperationMethod | undefined;
19
+ /** Счётчик частоты операции. Для неизвестной возвращает {@link defaultBucket}. */
20
+ bucketOf(id: string): string;
21
+ /** Известно ли каталогу имя бакета. */
22
+ isKnownBucket(name: string): boolean;
23
+ /** Ёмкость бакетов до первого ответа сервера, запросов в минуту. */
24
+ readonly bucketLimits: Readonly<Record<string, number>>;
25
+ /** Встроенные поправки бакетов, например предел одновременности загрузки файлов. */
26
+ readonly bucketOverrides: Readonly<Record<string, RateLimitBucketOverride>>;
27
+ /** Счётчик, из которого списывается путь без собственного правила на сервере. */
28
+ readonly defaultBucket: string;
29
+ }
30
+ //#endregion
31
+ //#region src/core/execution/pipeline.d.ts
32
+ /** Тело, заново подготовленное для одной транспортной попытки. */
33
+ interface PreparedRequestBody {
34
+ body: BodyInit;
35
+ /** Заголовки тела, например multipart boundary. Пользовательские заголовки важнее. */
36
+ headers?: Record<string, string> | undefined;
37
+ /** Освобождает открытый файл или входящий HTTP-поток. */
38
+ cleanup?: (() => void | Promise<void>) | undefined;
39
+ }
40
+ /** Контекст подготовки повторяемого тела. */
41
+ interface RequestBodyContext {
42
+ signal: AbortSignal;
43
+ attempt: number;
44
+ }
45
+ /** Создаёт новое тело для каждой транспортной попытки. */
46
+ type RequestBodyFactory = (context: RequestBodyContext) => PreparedRequestBody | Promise<PreparedRequestBody>;
47
+ /**
48
+ * Описание запроса внутри конвейера.
49
+ *
50
+ * Отличается от публичного {@link RawRequestOptions} одним служебным полем: слои конвейера
51
+ * должны уметь дописать заголовки так, чтобы пользовательские `headers` всё равно остались
52
+ * важнее. Смешивать их в одном объекте нельзя — тогда слой авторизации перебивал бы
53
+ * `Authorization`, заданный вызывающим кодом вручную.
54
+ */
55
+ interface PipelineRequest extends OperationRequestOptions {
56
+ /** Повторяемое тело. Используется внутренними ресурсами вместо `body`. @internal */
57
+ bodyFactory?: RequestBodyFactory | undefined;
58
+ /**
59
+ * Заголовки, добавленные слоями конвейера.
60
+ *
61
+ * Ставятся до пользовательских `headers` и потому могут быть ими переопределены.
62
+ *
63
+ * @internal
64
+ */
65
+ layerHeaders?: Record<string, string> | undefined;
66
+ /**
67
+ * Номер фактически начатой транспортной попытки, начиная с 1. Проставляет attempt layer.
68
+ *
69
+ * @internal
70
+ */
71
+ attempt?: number | undefined;
72
+ }
73
+ /** Запрос на внешней границе pipeline. Низкоуровневый вызов без ID считается `raw`. */
74
+ type PipelineRequestInput = Omit<PipelineRequest, 'operationId'> & {
75
+ operationId?: OperationId | undefined;
76
+ };
77
+ /** Обработчик запроса. Самый внутренний в цепочке — транспорт. */
78
+ type RequestHandler = (request: PipelineRequest) => Promise<unknown>;
79
+ //#endregion
80
+ //#region src/core/plugins/contracts.d.ts
81
+ /**
82
+ * Обёртка одной логической операции.
83
+ *
84
+ * Вызывается ровно один раз независимо от retry и auth recovery. Может изменить
85
+ * семантический запрос, обработать разобранный результат или завершить операцию локально.
86
+ *
87
+ * @param request описание логической операции; не изменяйте сам объект — передайте копию в `next`
88
+ * @param next следующая обёртка либо выполнение операции
89
+ * @returns разобранный результат в том виде, в котором его получит вызывающий код
90
+ *
91
+ * @example Дописать заголовок ко всем операциям
92
+ * ```ts
93
+ * const transformer: OperationTransformer = (request, next) =>
94
+ * next({ ...request, headers: { ...request.headers, 'X-Trace': trace() } });
95
+ * ```
96
+ */
97
+ type OperationTransformer = (request: OperationRequestOptions, next: (request: OperationRequestOptions) => Promise<unknown>) => Promise<unknown>;
98
+ /** Финальные данные одной транспортной попытки. */
99
+ interface AttemptContext {
100
+ /** Стабильная семантическая операция. */
101
+ readonly operationId: OperationId;
102
+ /** Нормализованный HTTP-метод. */
103
+ readonly method: string;
104
+ /** Исходный путь операции до разрешения service/base URL. */
105
+ readonly path: string;
106
+ /** Полностью разрешённый URL со строкой query. */
107
+ readonly url: string;
108
+ /** Итоговые заголовки. Сам объект mutable для подписи и diagnostic headers. */
109
+ readonly headers: Headers;
110
+ /** Номер transport attempt, начиная с 1. */
111
+ readonly attempt: number;
112
+ /** Тело после сериализации либо подготовки body factory. Поток нельзя читать заранее. */
113
+ readonly body: BodyInit | undefined;
114
+ /** Общий сигнал отмены и таймаута этой попытки. */
115
+ readonly signal: AbortSignal;
116
+ }
117
+ /**
118
+ * Продолжение attempt chain.
119
+ *
120
+ * В рамках одного interceptor его можно вызвать только один раз. Возвращает сырой ответ:
121
+ * transport ещё не проверял status и не читал body.
122
+ */
123
+ type AttemptNext = () => Promise<Response>;
124
+ /**
125
+ * Обёртка одной транспортной попытки.
126
+ *
127
+ * Получает уже разрешённый URL, итоговые заголовки, подготовленное тело и номер попытки.
128
+ * Может дописать заголовки, измерить wire latency, обработать сырой `Response` или вернуть
129
+ * синтетический `Response`. Семантический input здесь намеренно недоступен для изменения.
130
+ *
131
+ * Вызывается заново для каждого retry и auth recovery. `next()` разрешено вызвать один раз.
132
+ * Если interceptor читает тело ответа, читать нужно `response.clone()`: исходный body после
133
+ * цепочки разбирает transport. Исключение interceptor остаётся пользовательской ошибкой и не
134
+ * классифицируется как сетевой сбой для автоматического retry.
135
+ *
136
+ * @param context окончательные данные текущей транспортной попытки
137
+ * @param next следующий interceptor либо вызов `fetch`
138
+ * @returns исходный или синтетический сырой `Response`
139
+ */
140
+ type AttemptInterceptor = (context: AttemptContext, next: AttemptNext) => Promise<Response>;
141
+ /** Регистрация расширений логической операции. */
142
+ interface OperationExtensions {
143
+ /**
144
+ * Подключает transformer.
145
+ *
146
+ * Зарегистрированные раньше оборачивают зарегистрированные позже. Возвращённая функция
147
+ * идемпотентна и снимает только эту регистрацию.
148
+ */
149
+ use(transformer: OperationTransformer): Unsubscribe;
150
+ }
151
+ /** Регистрация расширений транспортной попытки. */
152
+ interface AttemptExtensions {
153
+ /**
154
+ * Подключает interceptor.
155
+ *
156
+ * Зарегистрированные раньше оборачивают зарегистрированные позже. Возвращённая функция
157
+ * идемпотентна и снимает только эту регистрацию.
158
+ */
159
+ use(interceptor: AttemptInterceptor): Unsubscribe;
160
+ }
161
+ /**
162
+ * Освобождение ресурсов, заведённых плагином при установке.
163
+ *
164
+ * Вызывается после завершения логических операций, уже вошедших в расширения плагина,
165
+ * поэтому может безопасно закрывать используемые ими соединения и хранилища.
166
+ */
167
+ type PluginTeardown = () => void | Promise<void>;
168
+ /** API, доступный плагину при подключении. */
169
+ interface PluginApi {
170
+ /** Базовый URL клиента — например чтобы разобрать абсолютные ссылки из ответа. */
171
+ baseUrl: string;
172
+ /** Отладочный вывод клиента, если он включён. */
173
+ logger: Logger | undefined;
174
+ /** Расширения логической операции: выполняются один раз и могут short-circuit сеть. */
175
+ operations: OperationExtensions;
176
+ /** Расширения wire attempt: выполняются заново после каждого retry/auth recovery. */
177
+ attempts: AttemptExtensions;
178
+ /**
179
+ * Непрозрачная fallback-область текущей авторизации.
180
+ *
181
+ * Нужна плагинам, которые обязаны безопасно изолировать непрозрачный токен. Для объединения
182
+ * состояния копий одного аккаунта используйте {@link getAuthIdentity}.
183
+ */
184
+ getAuthScope?: (() => string) | undefined;
185
+ /**
186
+ * Загружает сессию и возвращает идентификаторы аккаунта и конкретной сессии из JWT.
187
+ *
188
+ * Предпочтительнее {@link getAuthScope} для состояния, которое должно объединяться между
189
+ * несколькими экземплярами клиента одного аккаунта.
190
+ */
191
+ getAuthIdentity?: (() => Promise<AuthIdentity>) | undefined;
192
+ }
193
+ /**
194
+ * Плагин клиента.
195
+ *
196
+ * Подключается через `itd.use(plugin)` и регистрирует расширения одного или обоих уровней:
197
+ * {@link OperationTransformer} для логической операции и {@link AttemptInterceptor} для
198
+ * отдельной транспортной попытки. Core взаимодействует с плагином только через эти контракты
199
+ * и его lifecycle, не зная деталей реализации.
200
+ *
201
+ * Настройки отдельного вызова плагин объявляет своим полем в `RequestExtensions` через
202
+ * declaration merging. Пользователь передаёт их в `RequestOptions.extensions`, а operation
203
+ * transformer читает только принадлежащий плагину namespace.
204
+ *
205
+ * @example Логирование логических операций
206
+ * ```ts
207
+ * const logging: ClientPlugin = {
208
+ * name: 'logging',
209
+ * install({ operations, logger }) {
210
+ * operations.use(async (request, next) => {
211
+ * logger?.info(`${request.method} ${request.path}`);
212
+ * return next(request);
213
+ * });
214
+ * },
215
+ * };
216
+ *
217
+ * itd.use(logging);
218
+ * ```
219
+ */
220
+ interface ClientPlugin {
221
+ /** Имя плагина. Должно быть уникальным: повторное подключение — ошибка. */
222
+ name: string;
223
+ /** Плагины, которые обязаны быть подключены раньше этого. */
224
+ requires?: readonly string[];
225
+ /** Несовместимые плагины. Достаточно объявить конфликт с одной стороны. */
226
+ conflicts?: readonly string[];
227
+ /** Имена плагинов, снаружи которых должны стоять оба вида расширений этого плагина. */
228
+ before?: readonly string[];
229
+ /** Имена плагинов, внутри которых должны стоять оба вида расширений этого плагина. */
230
+ after?: readonly string[];
231
+ /**
232
+ * Устанавливает плагин.
233
+ *
234
+ * Может вернуть функцию освобождения ресурсов. Она вызывается при `unuse()` или
235
+ * окончательном `dispose()` клиента и может быть асинхронной. Сам `install()` синхронный:
236
+ * регистрация расширений завершается до того, как `use()` вернёт управление.
237
+ */
238
+ install(api: PluginApi): void | PluginTeardown;
239
+ }
240
+ //#endregion
241
+ //#region src/core/scheduling/rate-limit.d.ts
242
+ /** Снимок одного бакета. */
243
+ interface RateLimitBucketState {
244
+ /** Origin, на котором ведётся счётчик. `undefined` — очередь без известного направления. */
245
+ destination: string | undefined;
246
+ bucket: string;
247
+ /** Ёмкость из последнего ответа; `undefined`, пока ответов не было. */
248
+ limit: number | undefined;
249
+ /** Остаток из последнего ответа. */
250
+ remaining: number | undefined;
251
+ /** Запросов бакета прошло в общую очередь и ещё не завершилось. */
252
+ active: number;
253
+ /** Запросов бакета ждёт своей очереди — из-за паузы или предела одновременности. */
254
+ pending: number;
255
+ }
256
+ //#endregion
257
+ //#region src/core/execution/http.d.ts
258
+ /** Что нужно фасаду для работы. */
259
+ interface HttpClientDeps {
260
+ /** Готовый обработчик — вся цепочка слоёв поверх транспорта. */
261
+ handler: RequestHandler;
262
+ baseUrl: string;
263
+ /** Каталог, из которого берётся HTTP-метод семантической операции. */
264
+ catalog: OperationCatalog;
265
+ }
266
+ /**
267
+ * Точка входа ресурсов в конвейер запросов.
268
+ *
269
+ * Принимает готовый обработчик — цепочку слоёв поверх транспорта, собранную
270
+ * во внутреннем runtime клиента, — и отдаёт ресурсам методы `request`/`operation`.
271
+ * О слоях и их порядке ресурсы не знают.
272
+ */
273
+ declare class HttpClient {
274
+ #private;
275
+ constructor(deps: HttpClientDeps);
276
+ /** Базовый URL, к которому обращается клиент. */
277
+ get baseUrl(): string;
278
+ /**
279
+ * Выполняет запрос к API через собранный конвейер.
280
+ *
281
+ * @typeParam T ожидаемая форма ответа после снятия обёртки `{ data: … }`
282
+ * @throws {ItdApiError} если сервер ответил статусом ≥ 400
283
+ * @throws {ItdTimeoutError} если истёк таймаут
284
+ * @throws {ItdAbortError} если запрос отменён через `signal`
285
+ * @throws {ItdNetworkError} если запрос не дошёл до сервера
286
+ */
287
+ request<T = unknown>(options: PipelineRequestInput): Promise<T>;
288
+ /** Выполняет встроенную семантическую операцию, подставляя её HTTP-метод из каталога. */
289
+ operation<T = unknown>(operationId: BuiltInOperationId, options: Omit<PipelineRequest, 'operationId' | 'method'>): Promise<T>;
290
+ /** Выполняет внутреннюю операцию финализации после начала `ItdClient.dispose()`. @internal */
291
+ cleanupOperation<T = unknown>(operationId: BuiltInOperationId, options: Omit<PipelineRequest, 'operationId' | 'method'>): Promise<T>;
292
+ }
293
+ //#endregion
294
+ //#region src/models/account.d.ts
295
+ /** Активная сессия входа. */
296
+ interface Session {
297
+ id: string;
298
+ /** Та ли это сессия, из которой выполнен запрос. */
299
+ isCurrent: boolean;
300
+ createdAt: IsoDate;
301
+ lastUsedAt: IsoDate;
302
+ expiresAt: IsoDate;
303
+ ipAddress: string;
304
+ /** Код страны по IP, например `RU`. */
305
+ ipCountry: string | null;
306
+ ipCity: string | null;
307
+ deviceType: Loose<'desktop' | 'mobile'>;
308
+ osName: string | null;
309
+ osVersion: string | null;
310
+ /** Название браузера или приложения. */
311
+ clientName: string | null;
312
+ clientVersion: string | null;
313
+ deviceModel: string | null;
314
+ }
315
+ /** Состояние платной подписки и её цена. */
316
+ interface Subscription {
317
+ /** Активна ли подписка сейчас. */
318
+ active: boolean;
319
+ /** Включено ли автопродление. */
320
+ recurringEnabled: boolean;
321
+ /** Цена в рублях. */
322
+ price: number;
323
+ }
324
+ /** Сохранённый способ оплаты. */
325
+ interface PaymentMethod {
326
+ id: string;
327
+ /** Последние четыре цифры карты. */
328
+ last4?: string;
329
+ /** Платёжная система: `visa`, `mastercard`, `mir`. */
330
+ brand?: string;
331
+ /** Основной ли это способ оплаты. */
332
+ isDefault?: boolean;
333
+ expiresAt?: IsoDate | null;
334
+ }
335
+ //#endregion
336
+ //#region src/resources/pagination.d.ts
337
+ /**
338
+ * Страница списка — единая форма для всех трёх схем пагинации API.
339
+ *
340
+ * Какие необязательные поля заполнены, зависит от эндпоинта: у ленты это `nextCursor`,
341
+ * у подписчиков — `page` и `total`, у уведомлений — `nextOffset`. Обычно они не нужны:
342
+ * перебор берёт на себя {@link Paginator}.
343
+ */
344
+ interface Page<T> {
345
+ /** Элементы страницы. */
346
+ items: T[];
347
+ /** Есть ли следующая страница. */
348
+ hasMore: boolean;
349
+ /**
350
+ * Курсор следующей страницы.
351
+ *
352
+ * Непрозрачен: у вкладки `popular` это номер страницы, у `following` — отметка времени.
353
+ * Передавайте его обратно как есть и не пытайтесь разобрать.
354
+ */
355
+ nextCursor?: string | null | undefined;
356
+ /** Номер текущей страницы при постраничной схеме. */
357
+ page?: number | undefined;
358
+ /** Запрошенный размер страницы. */
359
+ limit?: number | undefined;
360
+ /** Общее число элементов, если сервер его сообщил. */
361
+ total?: number | undefined;
362
+ /** Смещение для следующего запроса при схеме со смещением. */
363
+ nextOffset?: number | undefined;
364
+ /** Исходный ответ — на случай, если документация разошлась с реальностью. */
365
+ raw: unknown;
366
+ }
367
+ /** Схема пагинации эндпоинта. */
368
+ declare const PaginationMode: Readonly<{
369
+ /** Следующая страница запрашивается непрозрачным курсором. */
370
+ readonly Cursor: "cursor";
371
+ /** Следующая страница запрашивается номером. */
372
+ readonly Page: "page";
373
+ /** Следующая страница запрашивается смещением от начала списка. */
374
+ readonly Offset: "offset";
375
+ }>;
376
+ type PaginationMode = (typeof PaginationMode)[keyof typeof PaginationMode];
377
+ /** Применяет преобразование к элементам страницы, сохраняя сведения о пагинации. */
378
+ declare function mapPage<T, R>(page: Page<T>, map: (item: T) => R): Page<R>;
379
+ /** Позиция, с которой запрашивается очередная страница. */
380
+ interface PageState {
381
+ cursor?: string | undefined;
382
+ page?: number | undefined;
383
+ offset?: number | undefined;
384
+ }
385
+ /** Настройки перебора страниц. */
386
+ interface PaginatorOptions<T> {
387
+ mode: PaginationMode;
388
+ /** Загружает одну страницу для указанной позиции. */
389
+ load: (state: PageState) => Promise<Page<T>>;
390
+ /**
391
+ * С какой позиции начать. По умолчанию с начала списка.
392
+ *
393
+ * Нужно, чтобы перебор можно было продолжить с сохранённого курсора, а не только
394
+ * начать заново.
395
+ */
396
+ start?: PageState | undefined;
397
+ /**
398
+ * Предохранитель от бесконечного перебора. По умолчанию 1000.
399
+ *
400
+ * Сработает, только если сервер бесконечно сообщает `hasMore` — при нормальной работе
401
+ * перебор останавливается сам.
402
+ */
403
+ maxPages?: number | undefined;
404
+ /** Отмена перебора. */
405
+ signal?: AbortSignal | undefined;
406
+ }
407
+ /**
408
+ * Перебор страниц списка.
409
+ *
410
+ * Скрывает различия трёх схем пагинации: перебор элементов, страниц и сбор в массив
411
+ * выглядят одинаково независимо от эндпоинта.
412
+ *
413
+ * **Одноразовый.** Позиция хранится внутри, поэтому повторный перебор того же объекта
414
+ * ничего не вернёт: он продолжится с места, где закончился прошлый. Нужен второй проход —
415
+ * возьмите новый перебор у того же метода ресурса.
416
+ *
417
+ * @example Перебор элементов
418
+ * ```ts
419
+ * for await (const post of itd.posts.iterate({ tab: 'following' })) {
420
+ * console.log(post.content);
421
+ * }
422
+ * ```
423
+ *
424
+ * @example Первые сто элементов
425
+ * ```ts
426
+ * const posts = await itd.posts.iterate({ tab: 'popular' }).collect(100);
427
+ * ```
428
+ *
429
+ * @example Постранично
430
+ * ```ts
431
+ * for await (const page of itd.users.followers('nowkie').pages()) {
432
+ * console.log(page.items.length, 'из', page.total);
433
+ * }
434
+ * ```
435
+ */
436
+ declare class Paginator<T> implements AsyncIterable<T> {
437
+ #private;
438
+ constructor(options: PaginatorOptions<T>);
439
+ /**
440
+ * Загружает следующую страницу.
441
+ *
442
+ * @returns страница либо `null`, если перебор закончен
443
+ */
444
+ next(): Promise<Page<T> | null>;
445
+ /**
446
+ * Перебирает страницы целиком.
447
+ *
448
+ * Полезно, когда нужны сведения о самой странице — например `total`.
449
+ */
450
+ pages(): AsyncGenerator<Page<T>, void, undefined>;
451
+ /** Перебирает элементы всех страниц подряд. */
452
+ [Symbol.asyncIterator](): AsyncGenerator<T, void, undefined>;
453
+ /**
454
+ * Собирает элементы в массив.
455
+ *
456
+ * @param max сколько элементов достаточно; без него перебираются все страницы
457
+ */
458
+ collect(max?: number): Promise<T[]>;
459
+ }
460
+ //#endregion
461
+ //#region src/resources/base.d.ts
462
+ /**
463
+ * Описание перебираемого эндпоинта.
464
+ *
465
+ * Одно место, где заданы путь, параметры запроса, чтение страницы и схема пагинации.
466
+ * {@link BaseResource.paginated} строит из него и разовую загрузку, и перебор.
467
+ *
468
+ * @typeParam T тип элемента списка
469
+ * @typeParam P тип параметров метода
470
+ */
471
+ interface ListingSpec<T, P extends object> {
472
+ /** Стабильная семантическая операция списка. */
473
+ operationId: BuiltInOperationId | ((params: P) => BuiltInOperationId);
474
+ /** Путь эндпоинта. */
475
+ path: (params: P) => string;
476
+ /** Параметры запроса без полей пагинации — их добавит перебор. */
477
+ query: (params: P) => QueryParams;
478
+ /** Читает страницу из ответа. Получает позицию — она нужна схеме со смещением. */
479
+ read: (body: unknown, state: PageState) => Page<T>;
480
+ /** Схема пагинации эндпоинта. */
481
+ mode: PaginationMode;
482
+ /** Начальная позиция, вычисленная из параметров (курсор, номер или смещение). */
483
+ start: (params: P) => PageState;
484
+ }
485
+ /** Пара методов, собранная из {@link ListingSpec}: разовая загрузка и перебор. */
486
+ interface Listing<T, P extends object> {
487
+ /** Загружает одну страницу с позиции, заданной параметрами. */
488
+ list(params: P, options?: RequestOptions): Promise<Page<T>>;
489
+ /** Перебирает страницы, сама подставляя позиции. */
490
+ iterate(params: P, options?: PaginationOptions): Paginator<T>;
491
+ }
492
+ /** Общая основа всех групп методов клиента. */
493
+ declare class BaseResource {
494
+ /** @internal */
495
+ protected readonly http: HttpClient;
496
+ constructor(http: HttpClient);
497
+ /**
498
+ * Собирает перебор страниц.
499
+ *
500
+ * @param mode схема пагинации эндпоинта
501
+ * @param load загружает одну страницу для указанной позиции
502
+ * @param options только управление самим перебором: предел, отмена и начальная позиция
503
+ */
504
+ protected paginate<T>(mode: PaginationMode, load: (state: PageState) => Promise<Page<T>>, options?: PaginationOptions & {
505
+ start?: PageState;
506
+ }): Paginator<T>;
507
+ /**
508
+ * Собирает пару «загрузка страницы + перебор» из одного описания.
509
+ *
510
+ * Путь, параметры запроса и разбор ответа задаются один раз; `list` и `iterate`
511
+ * строятся из них.
512
+ *
513
+ * @example
514
+ * ```ts
515
+ * #feed = this.paginated<Post, FeedParams>({
516
+ * operationId: 'posts.list',
517
+ * path: () => '/api/posts',
518
+ * query: (p) => ({ tab: p.tab, limit: p.limit }),
519
+ * start: (p) => (p.cursor ? { cursor: p.cursor } : {}),
520
+ * read: (body) => readCursorPage<Post>(body, 'posts'),
521
+ * mode: PaginationMode.Cursor,
522
+ * });
523
+ * ```
524
+ */
525
+ protected paginated<T, P extends object>(spec: ListingSpec<T, P>): Listing<T, P>;
526
+ }
527
+ //#endregion
528
+ //#region src/domain/params.d.ts
529
+ /** Данные для создания опроса. */
530
+ interface CreatePollInput {
531
+ /** Вопрос. Не может быть пустым. */
532
+ question: string;
533
+ /** Варианты ответа. Требуется минимум два. */
534
+ options: {
535
+ text: string;
536
+ }[];
537
+ /** Разрешить выбор нескольких вариантов. По умолчанию `false`. */
538
+ multipleChoice?: boolean;
539
+ }
540
+ /**
541
+ * Нормализованные данные для создания поста.
542
+ *
543
+ * Это форма, которую возвращают `PostBuilder.build()` и `resolvePost()` после
544
+ * преобразования вложенных builders. Для входа `itd.posts.create()` см. {@link CreatePostInput}.
545
+ */
546
+ interface CreatePostData {
547
+ /** Текст поста. */
548
+ content?: string;
549
+ /**
550
+ * Разметка текста. Сырые spans проверяются относительно `content`;
551
+ * для автоматического построения доступны `post().markup()` и `post().autoSpans()`.
552
+ */
553
+ spans?: Span[];
554
+ /**
555
+ * Чья стена, если пост публикуется не у себя.
556
+ *
557
+ * Требуется **UUID**: имя пользователя здесь не работает, его можно получить
558
+ * из профиля через `itd.users.get(username)`.
559
+ */
560
+ wallRecipientId?: UserId | null;
561
+ /** Идентификаторы заранее загруженных вложений. */
562
+ attachmentIds?: string[];
563
+ /** Файлы, которые нужно загрузить перед публикацией. Порядок сохраняется. */
564
+ files?: FileInput[];
565
+ /** Готовые данные опроса. */
566
+ poll?: CreatePollInput;
567
+ }
568
+ /** Поля поста, которые принимает `itd.posts.update()`. */
569
+ interface UpdatePostInput {
570
+ /** Новый текст поста. Обязателен, чтобы обновление одних spans не стёрло текущий текст. */
571
+ content: string;
572
+ /** Разметка нового текста. */
573
+ spans?: Span[];
574
+ }
575
+ /** Данные для создания комментария или ответа. */
576
+ interface CreateCommentInput {
577
+ /** Текст. У голосового комментария должен быть пустым. */
578
+ content?: string;
579
+ /** Идентификаторы заранее загруженных вложений. */
580
+ attachmentIds?: string[];
581
+ /** Файлы, которые нужно загрузить перед отправкой. */
582
+ files?: FileInput[];
583
+ /**
584
+ * Кому адресован ответ.
585
+ *
586
+ * Применимо только в `itd.comments.reply()`; в комментарии к посту поле не имеет смысла.
587
+ */
588
+ replyToUserId?: UserId;
589
+ }
590
+ /** Данные для создания жалобы. */
591
+ interface CreateReportInput {
592
+ /** На что жалоба. */
593
+ targetType: ReportTargetType;
594
+ /** Идентификатор объекта жалобы. */
595
+ targetId: string;
596
+ /** Причина. */
597
+ reason: ReportReason;
598
+ /** Пояснение в свободной форме. */
599
+ description?: string;
600
+ }
601
+ //#endregion
602
+ //#region src/builders/base.d.ts
603
+ /** Метка билдера. Через `Symbol.for` — чтобы распознавание переживало смешивание ESM и CJS. */
604
+ declare const BUILDER: unique symbol;
605
+ /**
606
+ * Билдер входных данных.
607
+ *
608
+ * Билдеры необязательны: любой метод, принимающий билдер, принимает и обычный объект.
609
+ * Проверки одинаковы в обоих случаях.
610
+ */
611
+ interface ItdBuilder<T> {
612
+ /** @internal */
613
+ readonly [BUILDER]: true;
614
+ /**
615
+ * Собирает и проверяет результат.
616
+ *
617
+ * @throws {ItdConfigError} если нарушены требования к данным
618
+ */
619
+ build(): T;
620
+ /** Чтобы билдер корректно вёл себя внутри `JSON.stringify`. */
621
+ toJSON(): T;
622
+ }
623
+ /**
624
+ * Три равноправные формы входа: обычный объект, готовый билдер или функция-настройщик.
625
+ *
626
+ * @example
627
+ * ```ts
628
+ * itd.posts.create({ content: 'привет' }); // объект
629
+ * itd.posts.create(post().content('привет')); // билдер
630
+ * itd.posts.create((p) => p.content('привет')); // функция
631
+ * ```
632
+ */
633
+ type BuilderInput<T, B extends ItdBuilder<T>> = T | B | ((builder: B) => B | T);
634
+ /** Является ли значение билдером. */
635
+ declare function isBuilder<T>(value: unknown): value is ItdBuilder<T>;
636
+ //#endregion
637
+ //#region src/builders/comment.d.ts
638
+ /** Внутреннее состояние {@link CommentBuilder}. */
639
+ interface CommentState extends CreateCommentInput {
640
+ content: string;
641
+ attachmentIds: string[];
642
+ files: FileInput[];
643
+ /** Голосовой комментарий: текста быть не должно, вложение ровно одно. */
644
+ voice: boolean;
645
+ }
646
+ /**
647
+ * Билдер комментария и ответа на комментарий.
648
+ *
649
+ * Неизменяемый: каждый вызов возвращает новый экземпляр. Создаётся функцией {@link comment}.
650
+ */
651
+ declare class CommentBuilder implements ItdBuilder<CreateCommentInput> {
652
+ #private;
653
+ /** @internal */
654
+ readonly [BUILDER]: true;
655
+ /** @internal Создавайте билдер функцией {@link comment}. */
656
+ constructor(state: CommentState);
657
+ /** Задаёт текст комментария. */
658
+ content(text: string): CommentBuilder;
659
+ /** Прикладывает файл — он будет загружен перед отправкой. */
660
+ attach(file: FileInput): CommentBuilder;
661
+ /** Прикладывает уже загруженное вложение. */
662
+ attachId(attachmentId: string): CommentBuilder;
663
+ /**
664
+ * Делает комментарий голосовым.
665
+ *
666
+ * Текста у такого комментария быть не должно, а вложение ровно одно — аудио в формате
667
+ * `audio/ogg`. Так его принимает API.
668
+ *
669
+ * @example
670
+ * ```ts
671
+ * import { fromPath } from 'itd-api/node';
672
+ *
673
+ * await itd.posts.comment(postId, (c) => c.voice(fromPath('./answer.ogg')));
674
+ * ```
675
+ */
676
+ voice(audio: FileInput): CommentBuilder;
677
+ /**
678
+ * Кому адресован ответ.
679
+ *
680
+ * Имеет смысл только в `itd.comments.reply()`; при отправке комментария к посту
681
+ * это поле вызовет ошибку.
682
+ */
683
+ replyTo(userId: UserId): CommentBuilder;
684
+ build(): CreateCommentInput;
685
+ toJSON(): CreateCommentInput;
686
+ }
687
+ /**
688
+ * Начинает сборку комментария.
689
+ *
690
+ * @param content текст; можно задать позже методом {@link CommentBuilder.content}
691
+ *
692
+ * @example
693
+ * ```ts
694
+ * import { comment } from 'itd-api';
695
+ *
696
+ * await itd.posts.comment(postId, comment('согласен').attach({ url: memeUrl }));
697
+ * ```
698
+ */
699
+ declare function comment(content?: string): CommentBuilder;
700
+ /** Что принимает параметр комментария: объект, билдер или функция-настройщик. */
701
+ type CommentInput = BuilderInput<CreateCommentInput, CommentBuilder>;
702
+ //#endregion
703
+ //#region src/models/content.d.ts
704
+ /** Вложение поста или комментария. */
705
+ interface Attachment {
706
+ id: string;
707
+ type: AttachmentType;
708
+ /** Адрес файла на CDN. */
709
+ url: string;
710
+ /** Ширина изображения или видео в пикселях. */
711
+ width?: number;
712
+ /** Высота изображения или видео в пикселях. */
713
+ height?: number;
714
+ mimeType: string;
715
+ /** Исходное имя файла. Приходит не всегда. */
716
+ filename?: string;
717
+ /** Размер в байтах. Приходит не всегда. */
718
+ size?: number;
719
+ /** Длительность аудио или видео в секундах. */
720
+ duration?: number | null;
721
+ /** Порядковый номер во вложениях поста. */
722
+ order?: number;
723
+ }
724
+ /** Вариант ответа в опросе. */
725
+ interface PollOption {
726
+ id: string;
727
+ text: string;
728
+ /** Сколько голосов отдано за этот вариант. */
729
+ votesCount: number;
730
+ /** Порядковый номер варианта, начиная с нуля. */
731
+ position: number;
732
+ }
733
+ /** Опрос внутри поста. */
734
+ interface Poll {
735
+ id: string;
736
+ /** Пост, которому принадлежит опрос. */
737
+ postId: string;
738
+ question: string;
739
+ /** Можно ли выбрать несколько вариантов. */
740
+ multipleChoice: boolean;
741
+ options: PollOption[];
742
+ totalVotes: number;
743
+ /** Голосовали ли вы. */
744
+ hasVoted: boolean;
745
+ /** За что проголосовали вы. Пустой массив, если голоса не было. */
746
+ votedOptionIds: string[];
747
+ createdAt: IsoDate;
748
+ }
749
+ /** Пост ленты, стены или профиля. */
750
+ interface Post {
751
+ id: string;
752
+ content: string;
753
+ /** Разметка текста. Передаётся без изменений, см. {@link Span}. */
754
+ spans: Span[];
755
+ author: Author;
756
+ attachments: Attachment[];
757
+ likesCount: number;
758
+ commentsCount: number;
759
+ repostsCount: number;
760
+ viewsCount: number;
761
+ /** Чья это стена, если пост опубликован не у себя. */
762
+ wallRecipientId: UserId | null;
763
+ /** Владелец стены. Приходит не во всех ответах. */
764
+ wallRecipient?: Author | null;
765
+ /** Поставили ли вы реакцию. */
766
+ isLiked: boolean;
767
+ /** Делали ли вы репост. */
768
+ isReposted: boolean;
769
+ /** Засчитан ли просмотр. */
770
+ isViewed: boolean;
771
+ /** Ваш ли это пост. */
772
+ isOwner: boolean;
773
+ /** Исходный пост, если это репост. */
774
+ originalPost?: Post | null;
775
+ poll?: Poll | null;
776
+ /** Преобладающая реакция — эмодзи либо `null`. */
777
+ dominantEmoji?: string | null;
778
+ /** Когда пост отредактировали. `null`, если не редактировали. */
779
+ editedAt: IsoDate | null;
780
+ createdAt: IsoDate;
781
+ /**
782
+ * Служебная метка показа для телеметрии.
783
+ *
784
+ * Нужна только эндпоинтам `itd.telemetry.*`. В остальных случаях игнорируйте.
785
+ */
786
+ vs?: string;
787
+ /**
788
+ * Топовые комментарии. Приходят только в ответе `GET /api/posts/{id}`.
789
+ *
790
+ * В списках постов поле отсутствует.
791
+ */
792
+ comments?: Comment[];
793
+ }
794
+ /** На чей комментарий дан ответ. */
795
+ interface CommentReplyTo {
796
+ id: string;
797
+ username: string;
798
+ displayName: string;
799
+ }
800
+ /** Комментарий к посту или ответ на комментарий. */
801
+ interface Comment {
802
+ id: string;
803
+ /** Текст. У голосового комментария пустой. */
804
+ content: string;
805
+ /**
806
+ * Разметка текста, включая автоматически найденные сервером хэштеги и упоминания.
807
+ *
808
+ * Методы создания и редактирования комментария принимают только `content`, поэтому
809
+ * библиотека не отправляет ручные spans в этих операциях.
810
+ * Поле необязательно: отдельные ответы сервера могут его не содержать.
811
+ */
812
+ spans?: Span[];
813
+ author: Author;
814
+ likesCount: number;
815
+ repliesCount: number;
816
+ isLiked: boolean;
817
+ createdAt: IsoDate;
818
+ /** Вложения. У голосового — одно аудио с `mimeType: 'audio/ogg'`. */
819
+ attachments?: Attachment[];
820
+ /** Вложенные ответы. В списках приходит превью, полный список — через `itd.comments.replies()`. */
821
+ replies?: Comment[];
822
+ /** Заполнено только у ответов. */
823
+ replyTo?: CommentReplyTo;
824
+ }
825
+ /** Хэштег. */
826
+ interface Hashtag {
827
+ id: string;
828
+ /** Название без решётки. */
829
+ name: string;
830
+ /** Сколько постов с этим хэштегом. */
831
+ postsCount: number;
832
+ }
833
+ /** Счётчики поста из `itd.posts.stats()`. */
834
+ interface PostStats {
835
+ id: string;
836
+ likesCount: number;
837
+ commentsCount: number;
838
+ repostsCount: number;
839
+ viewsCount: number;
840
+ /** Преобладающая реакция — эмодзи либо `null`. */
841
+ dominantEmoji: string | null;
842
+ }
843
+ /** Результат реакции на пост. */
844
+ interface LikeResult {
845
+ liked: boolean;
846
+ likesCount: number;
847
+ }
848
+ /** Результат закрепления поста в профиле. */
849
+ interface PinPostResult {
850
+ success: boolean;
851
+ pinnedPostId: string | null;
852
+ }
853
+ //#endregion
854
+ //#region src/resources/comments.d.ts
855
+ /** Параметры запроса ответов на комментарий. */
856
+ interface RepliesParams {
857
+ limit?: number;
858
+ page?: number;
859
+ }
860
+ /**
861
+ * Комментарии и ответы на них.
862
+ *
863
+ * Доступна как `itd.comments`. Комментарии **к посту** живут в `itd.posts`:
864
+ * `itd.posts.comments()` и `itd.posts.comment()`.
865
+ */
866
+ declare class CommentsResource extends BaseResource {
867
+ #private;
868
+ constructor(http: HttpClient, deps: {
869
+ uploadFiles: (files: FileInput[], options?: RequestOptions) => Promise<string[]>;
870
+ });
871
+ /**
872
+ * Загружает страницу ответов на комментарий.
873
+ *
874
+ * Здесь пагинация **постраничная**, в отличие от комментариев к посту, где курсорная.
875
+ */
876
+ replies(commentId: string, params?: RepliesParams, options?: RequestOptions): Promise<Page<Comment>>;
877
+ /** Перебирает ответы на комментарий. */
878
+ iterateReplies(commentId: string, params?: RepliesParams, options?: PaginationOptions): Paginator<Comment>;
879
+ /**
880
+ * Отвечает на комментарий.
881
+ *
882
+ * @example
883
+ * ```ts
884
+ * await itd.comments.reply(commentId, 'согласен');
885
+ * await itd.comments.reply(commentId, (c) => c.content('и вот почему').replyTo(userId));
886
+ * ```
887
+ */
888
+ reply(commentId: string, input: CommentInput | string, options?: RequestOptions): Promise<Comment>;
889
+ /** Редактирует текст комментария. */
890
+ update(commentId: string, content: string, options?: RequestOptions): Promise<Comment>;
891
+ /** Удаляет комментарий. Восстановить его можно через {@link restore}. */
892
+ remove(commentId: string, options?: RequestOptions): Promise<void>;
893
+ /** Восстанавливает удалённый комментарий. */
894
+ restore(commentId: string, options?: RequestOptions): Promise<Comment>;
895
+ /** Ставит реакцию на комментарий. */
896
+ like(commentId: string, options?: RequestOptions): Promise<LikeResult>;
897
+ /** Убирает реакцию с комментария. */
898
+ unlike(commentId: string, options?: RequestOptions): Promise<LikeResult>;
899
+ }
900
+ //#endregion
901
+ //#region src/resources/files.d.ts
902
+ /** Ответ загрузки файла. */
903
+ interface UploadedFile {
904
+ /** Идентификатор вложения — его передают в `attachmentIds`. */
905
+ id: string;
906
+ /** Адрес файла на CDN. */
907
+ url: string;
908
+ }
909
+ /** Настройки загрузки. */
910
+ interface UploadOptions {
911
+ /** Имя файла. Используется для определения MIME, если тип не задан. */
912
+ filename?: string;
913
+ /** MIME-тип. По умолчанию определяется по имени или `Blob`. */
914
+ contentType?: string;
915
+ /** Проверять тип до отправки. По умолчанию `true`. */
916
+ validateMime?: boolean;
917
+ /** Дополнительный предел размера для любого вида источника. */
918
+ maxBytes?: number | undefined;
919
+ /** Размер очереди библиотеки при потоковой передаче. */
920
+ streamBufferBytes?: number | undefined;
921
+ }
922
+ /** Файлы и медиа. */
923
+ declare class FilesResource extends BaseResource {
924
+ #private;
925
+ constructor(http: HttpClient, deps: {
926
+ fetch: typeof fetch;
927
+ });
928
+ /**
929
+ * Загружает файл и возвращает его идентификатор.
930
+ *
931
+ * Потоковый источник открывается заново при каждой повторной попытке. Буферный источник
932
+ * после успешного чтения переиспользуется.
933
+ */
934
+ upload(input: FileInput, uploadOptions?: UploadOptions, requestOptions?: RequestOptions): Promise<UploadedFile>;
935
+ /** Загружает несколько файлов последовательно, сохраняя порядок. */
936
+ uploadMany(files: FileInput[], uploadOptions?: UploadOptions, requestOptions?: RequestOptions): Promise<string[]>;
937
+ /**
938
+ * Загружает сведения о файле.
939
+ *
940
+ * Для ещё не прикреплённого файла сервер может ответить `404`.
941
+ */
942
+ get(fileId: string, options?: RequestOptions): Promise<unknown>;
943
+ /** Удаляет загруженный файл. */
944
+ remove(fileId: string, options?: RequestOptions): Promise<void>;
945
+ }
946
+ //#endregion
947
+ //#region src/resources/hashtags.d.ts
948
+ /** Параметры запроса постов по хэштегу. */
949
+ interface HashtagPostsParams {
950
+ limit?: number;
951
+ cursor?: string;
952
+ }
953
+ /**
954
+ * Хэштеги.
955
+ *
956
+ * Доступна как `itd.hashtags`.
957
+ */
958
+ declare class HashtagsResource extends BaseResource {
959
+ #private;
960
+ /**
961
+ * Ищет хэштеги.
962
+ *
963
+ * Без строки запроса возвращает общий список.
964
+ */
965
+ search(query?: string, params?: {
966
+ limit?: number;
967
+ }, options?: RequestOptions): Promise<Hashtag[]>;
968
+ /** Загружает трендовые хэштеги. */
969
+ trending(params?: {
970
+ limit?: number;
971
+ }, options?: RequestOptions): Promise<Hashtag[]>;
972
+ /**
973
+ * Загружает страницу постов по хэштегу.
974
+ *
975
+ * @param tag название без решётки; кодируется автоматически, поэтому кириллица
976
+ * и пробелы допустимы
977
+ */
978
+ posts(tag: string, params?: HashtagPostsParams, options?: RequestOptions): Promise<Page<Post>>;
979
+ /** Перебирает посты по хэштегу. */
980
+ iteratePosts(tag: string, params?: HashtagPostsParams, options?: PaginationOptions): Paginator<Post>;
981
+ }
982
+ //#endregion
983
+ //#region src/resources/notifications.d.ts
984
+ /** Параметры запроса списка уведомлений. */
985
+ interface NotificationListParams {
986
+ limit?: number;
987
+ /** Смещение от начала списка. */
988
+ offset?: number;
989
+ }
990
+ /** Изменяемые настройки уведомлений. */
991
+ type UpdateNotificationSettingsInput = Partial<NotificationSettings>;
992
+ /**
993
+ * Уведомления: список, счётчик, отметки о прочтении, настройки.
994
+ *
995
+ * Доступна как `itd.notifications`. Все уведомления приведены к единой форме, поэтому
996
+ * объекты отсюда и из потока событий можно складывать в один список.
997
+ */
998
+ declare class NotificationsResource extends BaseResource {
999
+ #private;
1000
+ /**
1001
+ * Загружает страницу уведомлений.
1002
+ *
1003
+ * Пагинация здесь основана на смещении.
1004
+ *
1005
+ * @example
1006
+ * ```ts
1007
+ * const page = await itd.notifications.list({ limit: 20 });
1008
+ * const next = await itd.notifications.list({ limit: 20, offset: page.nextOffset });
1009
+ * ```
1010
+ */
1011
+ list(params?: NotificationListParams, options?: RequestOptions): Promise<Page<Notification>>;
1012
+ /**
1013
+ * Перебирает уведомления.
1014
+ *
1015
+ * @example
1016
+ * ```ts
1017
+ * for await (const notification of itd.notifications.iterate()) {
1018
+ * console.log(formatNotificationText(notification));
1019
+ * }
1020
+ * ```
1021
+ */
1022
+ iterate(params?: NotificationListParams, options?: PaginationOptions): Paginator<Notification>;
1023
+ /** Загружает число непрочитанных уведомлений. */
1024
+ count(options?: RequestOptions): Promise<number>;
1025
+ /**
1026
+ * Отмечает уведомление прочитанным.
1027
+ *
1028
+ * @returns сколько записей отметил сервер
1029
+ */
1030
+ markRead(notificationId: string, options?: RequestOptions): Promise<number>;
1031
+ /**
1032
+ * Отмечает прочитанными сразу несколько уведомлений.
1033
+ *
1034
+ * Список автоматически режется на части по 20 идентификаторов — столько же отправляет
1035
+ * сайт итд.com, поэтому на сервере вероятен предел. Части уходят последовательно,
1036
+ * результат суммируется.
1037
+ *
1038
+ * @returns сколько записей отметил сервер суммарно
1039
+ */
1040
+ markReadBatch(ids: string[], options?: RequestOptions): Promise<number>;
1041
+ /** Отмечает прочитанными все уведомления. */
1042
+ markAllRead(options?: RequestOptions): Promise<number>;
1043
+ /** Загружает настройки уведомлений. */
1044
+ getSettings(options?: RequestOptions): Promise<NotificationSettings>;
1045
+ /**
1046
+ * Обновляет настройки уведомлений.
1047
+ *
1048
+ * Отправляются только изменяемые поля, в том же виде, в каком сервер их возвращает.
1049
+ */
1050
+ updateSettings(input: UpdateNotificationSettingsInput, options?: RequestOptions): Promise<NotificationSettings>;
1051
+ }
1052
+ //#endregion
1053
+ //#region src/models/platform.d.ts
1054
+ /** Клан в рейтинге. */
1055
+ interface Clan {
1056
+ /** Эмодзи клана — оно же аватар его участников. */
1057
+ avatar: string;
1058
+ memberCount: number;
1059
+ }
1060
+ /** Запись журнала изменений платформы. */
1061
+ interface ChangelogEntry {
1062
+ version: string;
1063
+ date: string;
1064
+ changes: string[];
1065
+ }
1066
+ /** Кнопка в анонсе платформы. */
1067
+ interface AnnouncementButton {
1068
+ title: string;
1069
+ /** Оформление: `primary`, `secondary` и другие. */
1070
+ style: string;
1071
+ action: {
1072
+ type: string;
1073
+ [key: string]: unknown;
1074
+ };
1075
+ }
1076
+ /** Анонс на главной странице платформы. */
1077
+ interface Announcement {
1078
+ id: string;
1079
+ image: {
1080
+ url: string;
1081
+ width: number;
1082
+ height: number;
1083
+ };
1084
+ title: string;
1085
+ description: string;
1086
+ /** Дополнительный текст мелким шрифтом. */
1087
+ additional_text?: string;
1088
+ buttons: AnnouncementButton[];
1089
+ }
1090
+ /** Баннер текущего события — виджет «портал». */
1091
+ interface Portal {
1092
+ active: boolean;
1093
+ title: string;
1094
+ url: string;
1095
+ }
1096
+ /** Статус заявки на верификацию. `none` означает, что заявка не подавалась. */
1097
+ interface VerificationStatus {
1098
+ status: Loose<'none' | 'pending' | 'approved' | 'rejected'>;
1099
+ }
1100
+ /** Созданная жалоба. */
1101
+ interface Report {
1102
+ id: string;
1103
+ createdAt: IsoDate;
1104
+ }
1105
+ //#endregion
1106
+ //#region src/models/status.d.ts
1107
+ /** Происшествие в истории сервиса. */
1108
+ interface StatusIncidentLine {
1109
+ /** Вид происшествия. */
1110
+ t: IncidentKind;
1111
+ /**
1112
+ * Готовая строка для показа: `недоступен 6 мин (12:00–12:06)`. Время московское.
1113
+ * Длительность и границы интервала отдельными полями не приходят.
1114
+ */
1115
+ text: string;
1116
+ }
1117
+ /** Одни сутки в истории сервиса. */
1118
+ interface StatusDay {
1119
+ /** Худшее состояние за сутки. */
1120
+ type: ServiceState;
1121
+ /** Дата суток, `YYYY-MM-DD`. Сутки нарезаны по UTC. */
1122
+ date_key: string;
1123
+ /** Доступность за сутки в процентах. */
1124
+ uptime: number;
1125
+ /** Происшествия за сутки. */
1126
+ lines: StatusIncidentLine[];
1127
+ }
1128
+ /** Сервис платформы и его история доступности. */
1129
+ interface ServiceStatus {
1130
+ /** Идентификатор: `auth`, `main`, `media` и прочие. */
1131
+ id: string;
1132
+ /** Отображаемое название. */
1133
+ name: string;
1134
+ current_status: ServiceState;
1135
+ /** Пояснение к текущему состоянию, например `No downtime`. */
1136
+ current_message: string;
1137
+ /** Задержка последней проверки в миллисекундах. */
1138
+ latency_ms: number;
1139
+ /**
1140
+ * Момент последней проверки. Сервер отдаёт `YYYY-MM-DD HH:mm:ss` в UTC, библиотека
1141
+ * приводит значение к ISO.
1142
+ */
1143
+ last_checked: IsoDate;
1144
+ /** Доступность за 90 суток в процентах. */
1145
+ uptime_90d: number;
1146
+ /**
1147
+ * История по суткам. Ключ — сколько суток назад, `'0'` — сегодня.
1148
+ *
1149
+ * Объект разреженный: сутки без данных сервер пропускает. Ровный массив даёт
1150
+ * `statusDays()`.
1151
+ */
1152
+ days: Record<string, StatusDay | undefined>;
1153
+ }
1154
+ /** Состояние платформы — ответ `itd.platform.status()`. */
1155
+ interface PlatformStatus {
1156
+ /** Худшее состояние среди сервисов. */
1157
+ overall_status: ServiceState;
1158
+ /** Когда данные последний раз пересчитаны. */
1159
+ updated_at: IsoDate;
1160
+ services: ServiceStatus[];
1161
+ }
1162
+ //#endregion
1163
+ //#region src/resources/platform.d.ts
1164
+ /** Требования к версии одного приложения платформы. */
1165
+ interface PlatformClientVersion {
1166
+ /** Минимальная поддерживаемая версия приложения. */
1167
+ minVersion: string;
1168
+ /** Последняя доступная версия приложения. */
1169
+ latestVersion: string;
1170
+ /** Адрес страницы обновления приложения. */
1171
+ updateUrl: string;
1172
+ }
1173
+ /** Версии клиентских приложений платформы. */
1174
+ interface PlatformVersions {
1175
+ android: PlatformClientVersion;
1176
+ ios: PlatformClientVersion;
1177
+ [client: string]: PlatformClientVersion;
1178
+ }
1179
+ /**
1180
+ * Сведения о платформе: версии приложений, изменения, анонсы, баннер события.
1181
+ *
1182
+ * Доступна как `itd.platform`.
1183
+ */
1184
+ declare class PlatformResource extends BaseResource {
1185
+ /**
1186
+ * Загружает минимальные и актуальные версии клиентских приложений.
1187
+ *
1188
+ * Endpoint публичный: автоматическая авторизация в запрос не добавляется.
1189
+ *
1190
+ * @example
1191
+ * ```ts
1192
+ * const versions = await itd.platform.version();
1193
+ * console.log(versions.android.latestVersion);
1194
+ * ```
1195
+ */
1196
+ version(options?: RequestOptions): Promise<PlatformVersions>;
1197
+ /** Загружает журнал изменений. */
1198
+ changelog(options?: RequestOptions): Promise<ChangelogEntry[]>;
1199
+ /** Загружает анонсы платформы. */
1200
+ announcements(options?: RequestOptions): Promise<Announcement[]>;
1201
+ /** Загружает баннер текущего события — виджет «портал». */
1202
+ portal(options?: RequestOptions): Promise<Portal>;
1203
+ /**
1204
+ * Загружает состояние сервисов платформы за последние 90 суток.
1205
+ *
1206
+ * Идёт на хост `статус.итд.com` без авторизации. Ответ кэшируется сервером на минуту.
1207
+ * История по суткам приходит разреженной, ровный массив даёт `statusDays`.
1208
+ *
1209
+ * @example
1210
+ * ```ts
1211
+ * const status = await itd.platform.status();
1212
+ *
1213
+ * if (status.overall_status !== 'operational') {
1214
+ * const broken = status.services.filter((s) => s.current_status !== 'operational');
1215
+ * console.log('лежит:', broken.map((s) => s.name).join(', '));
1216
+ * }
1217
+ * ```
1218
+ */
1219
+ status(options?: RequestOptions): Promise<PlatformStatus>;
1220
+ }
1221
+ //#endregion
1222
+ //#region src/builders/markup.d.ts
1223
+ /** Текст вместе с рассчитанной разметкой. */
1224
+ interface TextMarkup {
1225
+ content: string;
1226
+ spans: Span[];
1227
+ }
1228
+ /** Описание фрагмента без смещения: его вычисляет {@link MarkupBuilder}. */
1229
+ type MarkupSpan = Omit<Span, 'offset' | 'length'>;
1230
+ /** Что принимает метод разметки: результат, билдер или функция-настройщик. */
1231
+ type MarkupInput = BuilderInput<TextMarkup, MarkupBuilder>;
1232
+ /**
1233
+ * Содержимое форматированного фрагмента.
1234
+ *
1235
+ * Строка создаёт простой фрагмент. Билдер, готовая разметка или функция позволяют вложить
1236
+ * одни spans в другие, как при последовательном форматировании выделения в редакторе сайта.
1237
+ */
1238
+ type MarkupContent = string | MarkupInput;
1239
+ /** Какие сущности искать в {@link autoSpans}. */
1240
+ interface AutoSpansOptions {
1241
+ /** Находить `#хэштеги`. По умолчанию `true`. */
1242
+ hashtags?: boolean;
1243
+ /** Находить `@упоминания`. По умолчанию `true`. */
1244
+ mentions?: boolean;
1245
+ /** Находить абсолютные HTTP(S)-ссылки. По умолчанию `true`. */
1246
+ links?: boolean;
1247
+ }
1248
+ /**
1249
+ * Неизменяемый билдер текста с разметкой.
1250
+ *
1251
+ * Каждый метод дописывает фрагмент и сам считает `offset` и `length` в единицах UTF-16 —
1252
+ * именно такие индексы использует JavaScript-редактор сайта.
1253
+ */
1254
+ declare class MarkupBuilder implements ItdBuilder<TextMarkup> {
1255
+ #private;
1256
+ /** @internal */
1257
+ readonly [BUILDER]: true;
1258
+ /** @internal Создавайте билдер функцией {@link markup}. */
1259
+ constructor(content: string, spans: Span[]);
1260
+ /** Дописывает обычный текст без разметки. */
1261
+ text(value: string): MarkupBuilder;
1262
+ /** Дописывает переводы строк. */
1263
+ newline(count?: number): MarkupBuilder;
1264
+ /**
1265
+ * Дописывает фрагмент с произвольным типом разметки.
1266
+ *
1267
+ * Вложенный билдер позволяет форматировать часть фрагмента дополнительным стилем.
1268
+ * Для нескольких стилей на всём фрагменте используйте {@link styled}.
1269
+ */
1270
+ span(value: MarkupContent, span: MarkupSpan): MarkupBuilder;
1271
+ /**
1272
+ * Дописывает фрагмент с несколькими стилями на одном диапазоне.
1273
+ *
1274
+ * Для `link`, которому нужен `url`, используйте {@link link}; произвольные spans с
1275
+ * метаданными можно объединять через вложенные вызовы {@link span}.
1276
+ */
1277
+ styled(value: MarkupContent, ...types: Span['type'][]): MarkupBuilder;
1278
+ /** Дописывает `#хэштег` и сохраняет имя без решётки в `tag`. */
1279
+ hashtag(tag: string): MarkupBuilder;
1280
+ /** Дописывает `@username` и сохраняет имя пользователя в `username`. */
1281
+ mention(username: string): MarkupBuilder;
1282
+ /**
1283
+ * Дописывает ссылку.
1284
+ *
1285
+ * Для строки адрес по умолчанию становится и текстом ссылки. Вложенному форматированному
1286
+ * фрагменту URL нужно передать явно.
1287
+ */
1288
+ link(content: MarkupContent, url?: string): MarkupBuilder;
1289
+ bold(content: MarkupContent): MarkupBuilder;
1290
+ italic(content: MarkupContent): MarkupBuilder;
1291
+ underline(content: MarkupContent): MarkupBuilder;
1292
+ strike(content: MarkupContent): MarkupBuilder;
1293
+ spoiler(content: MarkupContent): MarkupBuilder;
1294
+ monospace(content: MarkupContent): MarkupBuilder;
1295
+ quote(content: MarkupContent): MarkupBuilder;
1296
+ build(): TextMarkup;
1297
+ toJSON(): TextMarkup;
1298
+ }
1299
+ /** Начинает сборку текста с автоматически вычисляемыми смещениями. */
1300
+ declare function markup(content?: string): MarkupBuilder;
1301
+ /**
1302
+ * Находит в тексте те сущности, которые сайт получает после серверного разбора:
1303
+ * HTTP(S)-ссылки, `#хэштеги` и `@упоминания`.
1304
+ *
1305
+ * Смещения выражены в UTF-16 code units, поэтому совпадают с `String#slice`,
1306
+ * `substring`, DOM Selection и wire-форматом сайта даже при наличии эмодзи.
1307
+ */
1308
+ declare function autoSpans(text: string, options?: AutoSpansOptions): Span[];
1309
+ //#endregion
1310
+ //#region src/spans/parse.d.ts
1311
+ /** Настройки безопасного импорта разметки. */
1312
+ interface ParseMarkupOptions {
1313
+ /**
1314
+ * Разрешённые схемы ссылок без завершающего двоеточия.
1315
+ *
1316
+ * По умолчанию разрешены только `http` и `https`. Относительные ссылки не превращаются
1317
+ * в spans: wire-формату нужен самостоятельный адрес.
1318
+ */
1319
+ allowedLinkProtocols?: readonly string[];
1320
+ }
1321
+ /**
1322
+ * Преобразует безопасное подмножество Markdown в текст и wire-spans.
1323
+ *
1324
+ * Поддерживаются bold, italic, strike, spoiler, inline/fenced code, ссылки, underline
1325
+ * через `<u>` и цитаты `>`. Неподдерживаемая и незакрытая разметка остаётся текстом.
1326
+ * У изображений сохраняется alt-текст без URL.
1327
+ */
1328
+ declare function parseMarkdown(source: string, options?: ParseMarkupOptions): TextMarkup;
1329
+ /**
1330
+ * Преобразует ограниченный HTML в обычный текст и wire-spans.
1331
+ *
1332
+ * Разрешены только семантические теги форматирования. Атрибуты событий игнорируются,
1333
+ * содержимое `script`, `style`, `iframe`, `object`, SVG и подобных активных элементов
1334
+ * удаляется. Опасный `href` сохраняет текст ссылки, но не создаёт span.
1335
+ */
1336
+ declare function parseHtml(source: string, options?: ParseMarkupOptions): TextMarkup;
1337
+ //#endregion
1338
+ //#region src/builders/poll.d.ts
1339
+ /**
1340
+ * Билдер опроса.
1341
+ *
1342
+ * Неизменяемый: каждый вызов возвращает новый экземпляр, поэтому заготовку можно
1343
+ * переиспользовать, не боясь её испортить. Создаётся функцией {@link poll}.
1344
+ */
1345
+ declare class PollBuilder implements ItdBuilder<CreatePollInput> {
1346
+ #private;
1347
+ /** @internal */
1348
+ readonly [BUILDER]: true;
1349
+ /** @internal Создавайте билдер функцией {@link poll}. */
1350
+ constructor(state: CreatePollInput);
1351
+ /** Задаёт вопрос. */
1352
+ question(text: string): PollBuilder;
1353
+ /** Добавляет один вариант ответа. */
1354
+ option(text: string): PollBuilder;
1355
+ /**
1356
+ * Добавляет несколько вариантов сразу.
1357
+ *
1358
+ * @example
1359
+ * ```ts
1360
+ * poll('ну как?').options('да', 'нет', 'не знаю');
1361
+ * ```
1362
+ */
1363
+ options(...texts: string[]): PollBuilder;
1364
+ /** Разрешает выбор нескольких вариантов. */
1365
+ multipleChoice(enabled?: boolean): PollBuilder;
1366
+ build(): CreatePollInput;
1367
+ toJSON(): CreatePollInput;
1368
+ }
1369
+ /**
1370
+ * Начинает сборку опроса.
1371
+ *
1372
+ * @param question вопрос; можно задать позже методом {@link PollBuilder.question}
1373
+ *
1374
+ * @example
1375
+ * ```ts
1376
+ * import { poll } from 'itd-api';
1377
+ *
1378
+ * const q = poll('Какой язык лучше?')
1379
+ * .options('TypeScript', 'JavaScript')
1380
+ * .multipleChoice();
1381
+ *
1382
+ * await itd.posts.create({ content: 'голосуем', poll: q });
1383
+ * ```
1384
+ */
1385
+ declare function poll(question?: string): PollBuilder;
1386
+ /** Что принимает параметр опроса: объект, билдер или функция-настройщик. */
1387
+ type PollInput = BuilderInput<CreatePollInput, PollBuilder>;
1388
+ //#endregion
1389
+ //#region src/builders/post.d.ts
1390
+ declare const BUILD_UPDATE: unique symbol;
1391
+ /** Данные для создания поста, включая поддерживаемые builder-формы вложенного опроса. */
1392
+ interface CreatePostInput extends Omit<CreatePostData, 'poll'> {
1393
+ /** Опрос: обычный объект, {@link PollBuilder} или функция-настройщик. */
1394
+ poll?: PollInput;
1395
+ }
1396
+ /** Внутреннее состояние {@link PostBuilder}. */
1397
+ interface PostState extends CreatePostInput {
1398
+ content: string;
1399
+ contentSet: boolean;
1400
+ attachmentIds: string[];
1401
+ files: FileInput[];
1402
+ }
1403
+ /**
1404
+ * Билдер поста.
1405
+ *
1406
+ * Неизменяемый: каждый вызов возвращает новый экземпляр, поэтому заготовку можно
1407
+ * переиспользовать. Создаётся функцией {@link post}.
1408
+ *
1409
+ * @example Заготовка для нескольких постов
1410
+ * ```ts
1411
+ * const onWall = post().onWall(userId);
1412
+ *
1413
+ * await itd.posts.create(onWall.content('первый'));
1414
+ * await itd.posts.create(onWall.content('второй')); // заготовка не испорчена
1415
+ * ```
1416
+ */
1417
+ declare class PostBuilder implements ItdBuilder<CreatePostData> {
1418
+ #private;
1419
+ /** @internal */
1420
+ readonly [BUILDER]: true;
1421
+ /** @internal Создавайте билдер функцией {@link post}. */
1422
+ constructor(state: PostState);
1423
+ /**
1424
+ * Задаёт текст поста, заменяя прежний вместе с его разметкой.
1425
+ *
1426
+ * Spans привязаны к конкретному тексту, поэтому после замены их нужно задать заново
1427
+ * через {@link spans}, {@link markup} или {@link autoSpans}.
1428
+ */
1429
+ content(text: string): PostBuilder;
1430
+ /** Дописывает текст к уже заданному. */
1431
+ append(text: string): PostBuilder;
1432
+ /**
1433
+ * Задаёт готовую разметку текста. Смещения проверяются при {@link build}.
1434
+ *
1435
+ * Для автоматического поиска сущностей есть {@link autoSpans}, а для вычисления смещений
1436
+ * при сборке текста — {@link markup}.
1437
+ */
1438
+ spans(spans: Span[]): PostBuilder;
1439
+ /**
1440
+ * Заменяет текст и разметку результатом {@link MarkupBuilder}.
1441
+ *
1442
+ * @example
1443
+ * ```ts
1444
+ * post().markup((m) => m.text('смотрите ').hashtag('котики').text(' от ').mention('nowkie'));
1445
+ * ```
1446
+ */
1447
+ markup(input: MarkupInput): PostBuilder;
1448
+ /** Заменяет текст и spans результатом безопасного разбора Markdown. */
1449
+ markdown(source: string, options?: ParseMarkupOptions): PostBuilder;
1450
+ /** Заменяет текст и spans результатом безопасного разбора ограниченного HTML. */
1451
+ html(source: string, options?: ParseMarkupOptions): PostBuilder;
1452
+ /**
1453
+ * Находит HTTP(S)-ссылки, хэштеги и упоминания в уже заданном тексте.
1454
+ *
1455
+ * Ручные стили сохраняются. Повторный вызов не дублирует уже найденные сущности.
1456
+ */
1457
+ autoSpans(options?: AutoSpansOptions): PostBuilder;
1458
+ /**
1459
+ * Публикует пост на стене другого пользователя.
1460
+ *
1461
+ * @param userId **UUID** пользователя; имя пользователя не подойдёт
1462
+ */
1463
+ onWall(userId: UserId): PostBuilder;
1464
+ /**
1465
+ * Прикладывает файл — он будет загружен перед публикацией.
1466
+ *
1467
+ * Порядок вызовов сохраняется в порядке вложений.
1468
+ */
1469
+ attach(file: FileInput): PostBuilder;
1470
+ /** Прикладывает уже загруженное вложение по его идентификатору. */
1471
+ attachId(attachmentId: string): PostBuilder;
1472
+ /**
1473
+ * Добавляет опрос.
1474
+ *
1475
+ * Принимает объект, {@link PollBuilder} или функцию-настройщик.
1476
+ *
1477
+ * @example
1478
+ * ```ts
1479
+ * post('голосуем').poll((q) => q.question('ну как?').options('да', 'нет'));
1480
+ * ```
1481
+ */
1482
+ poll(input: PollInput): PostBuilder;
1483
+ build(): CreatePostData;
1484
+ /** @internal Собирает данные по правилам `posts.update`, не применяя правила создания. */
1485
+ [BUILD_UPDATE](): UpdatePostInput;
1486
+ toJSON(): CreatePostData;
1487
+ }
1488
+ /**
1489
+ * Начинает сборку поста.
1490
+ *
1491
+ * @param content текст; можно задать позже методом {@link PostBuilder.content}
1492
+ *
1493
+ * @example
1494
+ * ```ts
1495
+ * import { post } from 'itd-api';
1496
+ *
1497
+ * await itd.posts.create(
1498
+ * post('смотрите что нашёл')
1499
+ * .attach({ url: 'https://example.com/photo.jpg' })
1500
+ * .poll((q) => q.question('нравится?').options('да', 'нет')),
1501
+ * );
1502
+ * ```
1503
+ */
1504
+ declare function post(content?: string): PostBuilder;
1505
+ /** Что принимает параметр поста: объект, билдер или функция-настройщик. */
1506
+ type PostInput = BuilderInput<CreatePostInput, PostBuilder>;
1507
+ /** Что принимает `posts.update`: объект, билдер поста или функция-настройщик. */
1508
+ type PostUpdateInput = UpdatePostInput | PostBuilder | ((builder: PostBuilder) => PostBuilder | UpdatePostInput);
1509
+ //#endregion
1510
+ //#region src/resources/posts.d.ts
1511
+ /** Параметры запроса ленты. */
1512
+ interface FeedParams {
1513
+ /** Вкладка ленты. По умолчанию сервер отдаёт популярное. */
1514
+ tab?: FeedTab;
1515
+ /** Сколько постов на страницу. */
1516
+ limit?: number;
1517
+ /**
1518
+ * Курсор следующей страницы из предыдущего ответа.
1519
+ *
1520
+ * Передавайте значение как есть: его формат зависит от вкладки и может измениться.
1521
+ */
1522
+ cursor?: string;
1523
+ }
1524
+ /** Параметры запроса постов пользователя. */
1525
+ interface UserPostsParams {
1526
+ limit?: number;
1527
+ cursor?: string;
1528
+ /** Порядок сортировки. */
1529
+ sort?: string;
1530
+ /** Закреплённый пост, чтобы сервер поднял его наверх. */
1531
+ pinnedPostId?: string;
1532
+ }
1533
+ /** Параметры запроса комментариев к посту. */
1534
+ interface CommentsParams {
1535
+ limit?: number;
1536
+ /**
1537
+ * Курсор следующей страницы: идентификатор последнего полученного комментария.
1538
+ *
1539
+ * Передавайте значение из `nextCursor` предыдущего ответа как есть.
1540
+ */
1541
+ cursor?: string;
1542
+ sort?: CommentSort;
1543
+ }
1544
+ /**
1545
+ * Посты: лента, публикация, реакции, репосты, комментарии.
1546
+ *
1547
+ * Доступна как `itd.posts`.
1548
+ */
1549
+ declare class PostsResource extends BaseResource {
1550
+ #private;
1551
+ constructor(http: HttpClient, deps: {
1552
+ uploadFiles: (files: FileInput[], options?: RequestOptions) => Promise<string[]>;
1553
+ });
1554
+ /**
1555
+ * Загружает страницу ленты.
1556
+ *
1557
+ * @example
1558
+ * ```ts
1559
+ * const page = await itd.posts.list({ tab: FeedTab.Following, limit: 20 });
1560
+ * const next = await itd.posts.list({ tab: FeedTab.Following, cursor: page.nextCursor ?? undefined });
1561
+ * ```
1562
+ */
1563
+ list(params?: FeedParams, options?: RequestOptions): Promise<Page<Post>>;
1564
+ /**
1565
+ * Перебирает ленту, сама подставляя курсоры.
1566
+ *
1567
+ * @example
1568
+ * ```ts
1569
+ * for await (const post of itd.posts.iterate({ tab: 'following' })) {
1570
+ * console.log(post.author.username, post.content);
1571
+ * }
1572
+ * ```
1573
+ */
1574
+ iterate(params?: FeedParams, options?: PaginationOptions): Paginator<Post>;
1575
+ /**
1576
+ * Публикует пост.
1577
+ *
1578
+ * Принимает обычный объект, {@link PostBuilder} или функцию-настройщик. Файлы из поля
1579
+ * `files` загружаются автоматически, порядок вложений сохраняется.
1580
+ *
1581
+ * @example
1582
+ * ```ts
1583
+ * await itd.posts.create({ content: 'привет' });
1584
+ * await itd.posts.create((p) => p.content('привет').attach({ url: 'https://example.com/photo.jpg' }));
1585
+ * ```
1586
+ */
1587
+ create(input: PostInput, options?: RequestOptions): Promise<Post>;
1588
+ /**
1589
+ * Загружает один пост вместе с топовыми комментариями.
1590
+ *
1591
+ * В отличие от списков, здесь у поста заполнено поле `comments`.
1592
+ */
1593
+ get(postId: string, options?: RequestOptions): Promise<Post>;
1594
+ /**
1595
+ * Редактирует текст и разметку поста.
1596
+ *
1597
+ * Как и {@link create}, принимает объект, готовый {@link PostBuilder} или
1598
+ * функцию-настройщик. Поля создания поста, которые update endpoint не поддерживает
1599
+ * (вложения, опрос и стена), отвергаются до запроса.
1600
+ */
1601
+ update(postId: string, input: PostUpdateInput, options?: RequestOptions): Promise<Post>;
1602
+ /** Удаляет пост. Восстановить его можно через {@link restore}. */
1603
+ remove(postId: string, options?: RequestOptions): Promise<void>;
1604
+ /** Восстанавливает удалённый пост. */
1605
+ restore(postId: string, options?: RequestOptions): Promise<Post>;
1606
+ /** Ставит реакцию на пост. */
1607
+ like(postId: string, options?: RequestOptions): Promise<LikeResult>;
1608
+ /** Убирает реакцию с поста. */
1609
+ unlike(postId: string, options?: RequestOptions): Promise<LikeResult>;
1610
+ /**
1611
+ * Делает репост с необязательным комментарием.
1612
+ *
1613
+ * Вложения к репосту не поддерживаются: сервер их игнорирует, поэтому параметров
1614
+ * для файлов здесь нет.
1615
+ */
1616
+ repost(postId: string, content?: string, options?: RequestOptions): Promise<Post>;
1617
+ /** Отменяет репост. */
1618
+ unrepost(postId: string, options?: RequestOptions): Promise<void>;
1619
+ /** Закрепляет пост в профиле. */
1620
+ pin(postId: string, options?: RequestOptions): Promise<PinPostResult>;
1621
+ /** Открепляет пост. */
1622
+ unpin(postId: string, options?: RequestOptions): Promise<PinPostResult>;
1623
+ /**
1624
+ * Голосует в опросе.
1625
+ *
1626
+ * @param optionIds выбранные варианты; несколько допустимы только при `multipleChoice`
1627
+ */
1628
+ vote(postId: string, optionIds: string[], options?: RequestOptions): Promise<Poll>;
1629
+ /** Запрашивает счётчики сразу для нескольких постов. */
1630
+ stats(ids: string[], options?: RequestOptions): Promise<PostStats[]>;
1631
+ /**
1632
+ * Загружает страницу стены пользователя.
1633
+ *
1634
+ * Это **не только его собственные посты**: сюда попадают и записи, которые другие
1635
+ * оставили на его стене — у них `author` чужой, а `wallRecipient` указывает на владельца
1636
+ * стены. Поэтому число записей обычно больше, чем `postsCount` из профиля; чтобы
1637
+ * получить только авторские посты, отфильтруйте по `post.author.id`.
1638
+ *
1639
+ * Принимает и UUID, и имя пользователя.
1640
+ */
1641
+ byUser(user: UserRef, params?: UserPostsParams, options?: RequestOptions): Promise<Page<Post>>;
1642
+ /** Перебирает стену пользователя. Что именно в неё входит — см. {@link byUser}. */
1643
+ iterateByUser(user: UserRef, params?: UserPostsParams, options?: PaginationOptions): Paginator<Post>;
1644
+ /** Загружает страницу постов, которые пользователь отметил реакцией. */
1645
+ likedByUser(user: UserRef, params?: UserPostsParams, options?: RequestOptions): Promise<Page<Post>>;
1646
+ /** Перебирает посты, которые пользователь отметил реакцией. */
1647
+ iterateLikedByUser(user: UserRef, params?: UserPostsParams, options?: PaginationOptions): Paginator<Post>;
1648
+ /**
1649
+ * Загружает страницу комментариев к посту.
1650
+ *
1651
+ * У этого эндпоинта курсор и признак продолжения лежат рядом со списком, а не внутри
1652
+ * объекта `pagination`, как у остальных, — разница скрыта внутри.
1653
+ */
1654
+ comments(postId: string, params?: CommentsParams, options?: RequestOptions): Promise<Page<Comment>>;
1655
+ /** Перебирает комментарии к посту. */
1656
+ iterateComments(postId: string, params?: CommentsParams, options?: PaginationOptions): Paginator<Comment>;
1657
+ /**
1658
+ * Комментирует пост.
1659
+ *
1660
+ * @example
1661
+ * ```ts
1662
+ * await itd.posts.comment(postId, 'согласен');
1663
+ * await itd.posts.comment(postId, (c) => c.content('смотри').attach(blob));
1664
+ * ```
1665
+ */
1666
+ comment(postId: string, input: CommentInput | string, options?: RequestOptions): Promise<Comment>;
1667
+ /**
1668
+ * Отправляет голосовой комментарий.
1669
+ *
1670
+ * Текста у такого комментария нет: сервер ждёт пустой `content` и одно аудиовложение
1671
+ * в формате `audio/ogg`.
1672
+ *
1673
+ * @example
1674
+ * ```ts
1675
+ * import { fromPath } from 'itd-api/node';
1676
+ *
1677
+ * await itd.posts.voiceComment(postId, fromPath('./answer.ogg'));
1678
+ * ```
1679
+ */
1680
+ voiceComment(postId: string, audio: FileInput, options?: RequestOptions): Promise<Comment>;
1681
+ }
1682
+ //#endregion
1683
+ //#region src/builders/report.d.ts
1684
+ /**
1685
+ * Билдер жалобы.
1686
+ *
1687
+ * Точка входа задаёт объект жалобы и его тип одновременно, поэтому рассогласовать
1688
+ * `targetType` и `targetId` невозможно. Создаётся объектом {@link report}.
1689
+ */
1690
+ declare class ReportBuilder implements ItdBuilder<CreateReportInput> {
1691
+ #private;
1692
+ /** @internal */
1693
+ readonly [BUILDER]: true;
1694
+ /** @internal Создавайте билдер через {@link report}. */
1695
+ constructor(state: Partial<CreateReportInput>);
1696
+ /** Указывает причину жалобы. */
1697
+ reason(reason: ReportReason): ReportBuilder;
1698
+ /** Добавляет пояснение в свободной форме. */
1699
+ description(text: string): ReportBuilder;
1700
+ build(): CreateReportInput;
1701
+ toJSON(): CreateReportInput;
1702
+ }
1703
+ /**
1704
+ * Начинает сборку жалобы.
1705
+ *
1706
+ * Тип объекта выбирается точкой входа, так что указать идентификатор комментария
1707
+ * с типом «пост» нельзя в принципе.
1708
+ *
1709
+ * @example
1710
+ * ```ts
1711
+ * import { report, ReportReason } from 'itd-api';
1712
+ *
1713
+ * await itd.reports.create(report.post(postId).reason(ReportReason.Spam));
1714
+ * await itd.reports.create(report.user(userId).reason('fraud').description('пишет в личку'));
1715
+ * ```
1716
+ */
1717
+ declare const report: Readonly<{
1718
+ /** Жалоба на пост. */
1719
+ post: (postId: string) => ReportBuilder;
1720
+ /** Жалоба на комментарий. */
1721
+ comment: (commentId: string) => ReportBuilder;
1722
+ /** Жалоба на пользователя. */
1723
+ user: (userId: string) => ReportBuilder;
1724
+ }>;
1725
+ /** Что принимает параметр жалобы: объект, билдер или функция-настройщик. */
1726
+ type ReportInput = BuilderInput<CreateReportInput, ReportBuilder>;
1727
+ //#endregion
1728
+ //#region src/resources/reports.d.ts
1729
+ /**
1730
+ * Жалобы на контент и пользователей.
1731
+ *
1732
+ * Доступна как `itd.reports`.
1733
+ */
1734
+ declare class ReportsResource extends BaseResource {
1735
+ /**
1736
+ * Отправляет жалобу.
1737
+ *
1738
+ * Повторная жалоба на тот же объект отклоняется сервером с сообщением
1739
+ * «Вы уже отправляли жалобу на этот контент».
1740
+ *
1741
+ * @example
1742
+ * ```ts
1743
+ * await itd.reports.create(report.post(postId).reason('spam'));
1744
+ * await itd.reports.create({ targetType: 'user', targetId, reason: 'fraud' });
1745
+ * ```
1746
+ */
1747
+ create(input: ReportInput, options?: RequestOptions): Promise<Report>;
1748
+ }
1749
+ //#endregion
1750
+ //#region src/resources/search.d.ts
1751
+ /** Результат глобального поиска. */
1752
+ interface SearchResult {
1753
+ users: UserSummary[];
1754
+ hashtags: Hashtag[];
1755
+ }
1756
+ /**
1757
+ * Глобальный поиск.
1758
+ *
1759
+ * Доступна как `itd.search`.
1760
+ */
1761
+ declare class SearchResource extends BaseResource {
1762
+ /**
1763
+ * Ищет пользователей и хэштеги одним запросом.
1764
+ *
1765
+ * @example
1766
+ * ```ts
1767
+ * const { users, hashtags } = await itd.search.all('арт');
1768
+ * ```
1769
+ */
1770
+ all(query: string, options?: RequestOptions): Promise<SearchResult>;
1771
+ }
1772
+ //#endregion
1773
+ //#region src/resources/subscription.d.ts
1774
+ /**
1775
+ * Подписка и способы оплаты.
1776
+ *
1777
+ * Доступна как `itd.subscription`.
1778
+ */
1779
+ declare class SubscriptionResource extends BaseResource {
1780
+ /** Загружает состояние подписки и её цену. */
1781
+ status(options?: RequestOptions): Promise<Subscription>;
1782
+ /**
1783
+ * Запускает оплату подписки.
1784
+ *
1785
+ * Форма ответа в документации API не описана, поэтому тип результата не уточняется.
1786
+ */
1787
+ pay(options?: RequestOptions): Promise<unknown>;
1788
+ /** Включает или отключает автопродление. */
1789
+ setAutoRenewal(enabled: boolean, options?: RequestOptions): Promise<unknown>;
1790
+ /** Запускает привязку карты. */
1791
+ bindCard(options?: RequestOptions): Promise<unknown>;
1792
+ /** Загружает список способов оплаты. Пустой массив, если карт нет. */
1793
+ methods(options?: RequestOptions): Promise<PaymentMethod[]>;
1794
+ /** Делает способ оплаты основным. */
1795
+ setDefaultMethod(methodId: string, options?: RequestOptions): Promise<unknown>;
1796
+ /** Удаляет способ оплаты. */
1797
+ removeMethod(methodId: string, options?: RequestOptions): Promise<void>;
1798
+ }
1799
+ //#endregion
1800
+ //#region src/resources/telemetry.d.ts
1801
+ /** Параметры событий телеметрии. */
1802
+ interface TelemetryOptions {
1803
+ /** Переопределяет идентификатор сессии телеметрии (`sid`) для этого запроса. */
1804
+ sid?: string;
1805
+ }
1806
+ /** Часы, используемые tracker-ом для измерения времени просмотра. */
1807
+ interface TelemetryClock {
1808
+ /** Возвращает текущее время в миллисекундах. */
1809
+ now(): number;
1810
+ }
1811
+ /** Опции tracker-а просмотра. */
1812
+ interface ViewTrackerOptions extends TelemetryOptions {
1813
+ /** Часы для измерения времени. По умолчанию используется `Date.now()`. */
1814
+ clock?: TelemetryClock;
1815
+ }
1816
+ /** Опции накопителя телеметрии. */
1817
+ interface TelemetryBatchOptions extends TelemetryOptions {
1818
+ /**
1819
+ * Максимальное число событий в одном запросе.
1820
+ *
1821
+ * Значение по умолчанию — 50. Это размер клиентской пачки, а не заявленный лимит API.
1822
+ */
1823
+ maxBatchSize?: number;
1824
+ /** Часы для tracker-ов, созданных через накопитель. */
1825
+ clock?: TelemetryClock;
1826
+ }
1827
+ /** Событие просмотра поста для {@link TelemetryResource.dwell}. */
1828
+ interface DwellEntry {
1829
+ /** Метка показа — поле `vs` объекта поста. */
1830
+ vs: string;
1831
+ /** Время появления поста в зоне видимости, epoch-мс. */
1832
+ enterAt: number;
1833
+ /** Время ухода из зоны видимости, epoch-мс. */
1834
+ exitAt: number;
1835
+ /** Причина завершения просмотра. */
1836
+ reason: ViewReason;
1837
+ /** Длительность просмотра в мс. По умолчанию `exitAt - enterAt`. */
1838
+ durationMs?: number;
1839
+ /** Контекст источника показа. */
1840
+ sourceContext?: string;
1841
+ /** Источник показа. */
1842
+ source?: ViewSource;
1843
+ /** Пост уже встречался в этой сессии. */
1844
+ repeat?: boolean;
1845
+ }
1846
+ /** Событие взаимодействия с контентом для {@link TelemetryResource.interaction}. */
1847
+ interface InteractionEntry {
1848
+ /** Тип взаимодействия. */
1849
+ type: InteractionType;
1850
+ /** Метка показа — поле `vs` объекта поста. */
1851
+ vs: string;
1852
+ /** Идентификатор поста. */
1853
+ postId: string;
1854
+ /** Индекс вложения, начиная с нуля. */
1855
+ mediaIndex?: number;
1856
+ /** Источник показа. */
1857
+ source?: ViewSource;
1858
+ /** Просмотренная позиция видео в мс. */
1859
+ positionMs?: number;
1860
+ /** Длительность видео в мс. */
1861
+ durationMs?: number;
1862
+ }
1863
+ /** Данные для {@link TelemetryResource.startView}. */
1864
+ interface ViewTrackerInput {
1865
+ /** Метка показа — поле `vs` объекта поста. */
1866
+ vs: string;
1867
+ /** Контекст источника показа. */
1868
+ sourceContext?: string;
1869
+ /** Источник показа. */
1870
+ source?: ViewSource;
1871
+ /** Пост уже встречался в этой сессии. */
1872
+ repeat?: boolean;
1873
+ }
1874
+ /** Данные открытия фотографии. */
1875
+ interface PhotoOpenInput {
1876
+ /** Метка показа — поле `vs` объекта поста. */
1877
+ vs: string;
1878
+ /** Идентификатор поста. */
1879
+ postId: string;
1880
+ /** Индекс открытого вложения, начиная с нуля. */
1881
+ mediaIndex: number;
1882
+ /** Источник показа. */
1883
+ source?: ViewSource;
1884
+ }
1885
+ /** Данные о прогрессе просмотра видео. */
1886
+ interface VideoProgressInput {
1887
+ /** Метка показа — поле `vs` объекта поста. */
1888
+ vs: string;
1889
+ /** Идентификатор поста. */
1890
+ postId: string;
1891
+ /** Просмотренная позиция видео в мс. */
1892
+ positionMs: number;
1893
+ /** Длительность видео в мс. */
1894
+ durationMs: number;
1895
+ /** Источник показа. */
1896
+ source?: ViewSource;
1897
+ }
1898
+ /** Активное измерение времени просмотра. */
1899
+ interface ViewTracker {
1900
+ /** Время начала измерения в миллисекундах. */
1901
+ readonly enteredAt: number;
1902
+ /** Был ли уже вызван {@link finish}. */
1903
+ readonly finished: boolean;
1904
+ /**
1905
+ * Завершает измерение и передаёт событие.
1906
+ *
1907
+ * Повторный вызов возвращает тот же Promise и не создаёт второе событие.
1908
+ */
1909
+ finish(reason: ViewReason): Promise<void>;
1910
+ }
1911
+ /** Явно управляемый накопитель событий телеметрии. */
1912
+ interface TelemetryBatch {
1913
+ /** Число ожидающих событий просмотра. */
1914
+ readonly pendingDwell: number;
1915
+ /** Число ожидающих событий взаимодействия. */
1916
+ readonly pendingInteractions: number;
1917
+ /** Закрыт ли накопитель. */
1918
+ readonly closed: boolean;
1919
+ /** Добавляет одно или несколько событий просмотра. */
1920
+ dwell(entry: DwellEntry | readonly DwellEntry[]): this;
1921
+ /** Добавляет одно или несколько событий взаимодействия. */
1922
+ interaction(entry: InteractionEntry | readonly InteractionEntry[]): this;
1923
+ /** Добавляет событие открытия фотографии. */
1924
+ photoOpen(input: PhotoOpenInput): this;
1925
+ /** Добавляет событие прогресса просмотра видео. */
1926
+ videoProgress(input: VideoProgressInput): this;
1927
+ /** Начинает измерение просмотра, которое после `finish()` попадёт в этот накопитель. */
1928
+ startView(input: ViewTrackerInput): ViewTracker;
1929
+ /**
1930
+ * Отправляет накопленные события.
1931
+ *
1932
+ * Опции позволяют заменить, например, отменённый `signal` при повторной попытке.
1933
+ */
1934
+ flush(options?: RequestOptions): Promise<void>;
1935
+ /** Отправляет накопленные события и закрывает накопитель. */
1936
+ close(): Promise<void>;
1937
+ }
1938
+ /**
1939
+ * Телеметрия просмотров и взаимодействий.
1940
+ *
1941
+ * Ничего не отправляет автоматически: каждый запрос, tracker или накопитель создаётся
1942
+ * явным вызовом пользователя. Доступна как `itd.telemetry`.
1943
+ */
1944
+ declare class TelemetryResource extends BaseResource {
1945
+ #private;
1946
+ constructor(http: HttpClient);
1947
+ /** Идентификатор сессии телеметрии, общий для всех событий этого ресурса. */
1948
+ get sessionId(): string;
1949
+ /** Отправляет события просмотра постов (`POST /api/v1/i`). */
1950
+ dwell(entries: readonly DwellEntry[], telemetryOptions?: TelemetryOptions, requestOptions?: RequestOptions): Promise<unknown>;
1951
+ /** Отправляет события взаимодействия с контентом (`POST /api/v1/x`). */
1952
+ interaction(entries: readonly InteractionEntry[], telemetryOptions?: TelemetryOptions, requestOptions?: RequestOptions): Promise<unknown>;
1953
+ /** Начинает измерять время просмотра и отправляет результат после `finish()`. */
1954
+ startView(input: ViewTrackerInput, options?: ViewTrackerOptions, requestOptions?: RequestOptions): ViewTracker;
1955
+ /** Отправляет событие открытия фотографии. */
1956
+ photoOpen(input: PhotoOpenInput, telemetryOptions?: TelemetryOptions, requestOptions?: RequestOptions): Promise<unknown>;
1957
+ /** Отправляет событие прогресса просмотра видео. */
1958
+ videoProgress(input: VideoProgressInput, telemetryOptions?: TelemetryOptions, requestOptions?: RequestOptions): Promise<unknown>;
1959
+ /**
1960
+ * Создаёт накопитель с явными `flush()` и `close()`.
1961
+ *
1962
+ * Создание и добавление записей не выполняют сетевых запросов.
1963
+ */
1964
+ batch(options?: TelemetryBatchOptions, requestOptions?: RequestOptions): TelemetryBatch;
1965
+ /** Закрывает все созданные накопители, отправляя оставшиеся записи. */
1966
+ close(): Promise<void>;
1967
+ }
1968
+ //#endregion
1969
+ //#region src/resources/users.d.ts
1970
+ /**
1971
+ * Параметры списков пользователей.
1972
+ *
1973
+ * ⚠️ Списки подписчиков, подписок и заблокированных на сервере **не листаются**:
1974
+ * `page` он игнорирует, а `limit` зажимает на 20. Подробности — в {@link UsersResource.followers}.
1975
+ */
1976
+ interface UserListParams {
1977
+ /** Сколько записей вернуть. Значения больше 20 сервер молча уменьшает до 20. */
1978
+ limit?: number;
1979
+ /** Номер страницы. Сервер его игнорирует — оставлен на случай, если пагинацию починят. */
1980
+ page?: number;
1981
+ }
1982
+ /** Изменяемые поля своего профиля. */
1983
+ interface UpdateProfileInput {
1984
+ displayName?: string;
1985
+ username?: string;
1986
+ /** Эмодзи-аватар: символ клана, а не адрес картинки. */
1987
+ avatar?: string;
1988
+ bio?: string;
1989
+ /** Идентификатор загруженного файла баннера. `null` удаляет текущий баннер. */
1990
+ bannerId?: string | null;
1991
+ }
1992
+ /** Изменяемые настройки приватности. */
1993
+ type UpdatePrivacyInput = Partial<PrivacySettings>;
1994
+ /**
1995
+ * Пользователи: профили, подписки, блокировки, приватность.
1996
+ *
1997
+ * Доступна как `itd.users`.
1998
+ */
1999
+ declare class UsersResource extends BaseResource {
2000
+ #private;
2001
+ constructor(http: HttpClient, deps: {
2002
+ uploadFile: (file: FileInput, uploadOptions?: UploadOptions, requestOptions?: RequestOptions) => Promise<UploadedFile>;
2003
+ });
2004
+ /** Загружает свой профиль — с подпиской и признаком подтверждённого телефона. */
2005
+ me(options?: RequestOptions): Promise<MyProfile>;
2006
+ /** Обновляет свой профиль. Передавайте только изменяемые поля. */
2007
+ updateMe(input: UpdateProfileInput, options?: RequestOptions): Promise<MyProfile>;
2008
+ /**
2009
+ * Загружает изображение и устанавливает его баннером профиля.
2010
+ *
2011
+ * Для установки используется идентификатор, полученный от `/api/files/upload`.
2012
+ * Если файл уже загружен, используйте {@link updateMe}: `{ bannerId: file.id }`.
2013
+ *
2014
+ * @example
2015
+ * ```ts
2016
+ * await itd.users.setBanner(file, { filename: 'banner.webp' });
2017
+ * ```
2018
+ */
2019
+ setBanner(file: FileInput, uploadOptions?: UploadOptions, requestOptions?: RequestOptions): Promise<MyProfile>;
2020
+ /** Удаляет баннер профиля, устанавливая `bannerId` в `null`. */
2021
+ removeBanner(options?: RequestOptions): Promise<MyProfile>;
2022
+ /** Деактивирует аккаунт. Вернуть его можно через {@link restore}. */
2023
+ deactivate(options?: RequestOptions): Promise<void>;
2024
+ /** Восстанавливает деактивированный аккаунт. */
2025
+ restore(options?: RequestOptions): Promise<void>;
2026
+ /** Создаёт профиль после регистрации. */
2027
+ createProfile(input: {
2028
+ username: string;
2029
+ displayName: string;
2030
+ avatar?: string;
2031
+ }, options?: RequestOptions): Promise<MyProfile>;
2032
+ /**
2033
+ * Загружает профиль пользователя.
2034
+ *
2035
+ * @param user UUID **или** имя пользователя — подходит и то, и другое
2036
+ *
2037
+ * @example
2038
+ * ```ts
2039
+ * const profile = await itd.users.get('nowkie');
2040
+ * await itd.posts.create({ content: 'привет', wallRecipientId: profile.id });
2041
+ * ```
2042
+ */
2043
+ get(user: UserRef, options?: RequestOptions): Promise<PublicProfile>;
2044
+ /** Проверяет, свободно ли имя пользователя. */
2045
+ checkUsername(username: string, options?: RequestOptions): Promise<boolean>;
2046
+ /** Ищет пользователей по строке запроса. */
2047
+ search(query: string, params?: {
2048
+ limit?: number;
2049
+ }, options?: RequestOptions): Promise<UserSummary[]>;
2050
+ /** Загружает рекомендации, на кого подписаться. */
2051
+ whoToFollow(options?: RequestOptions): Promise<UserSummary[]>;
2052
+ /** Загружает рейтинг кланов. */
2053
+ topClans(options?: RequestOptions): Promise<Clan[]>;
2054
+ /**
2055
+ * Подписывается на пользователя.
2056
+ *
2057
+ * У закрытого профиля вместо подписки отправляется заявка — это видно по полю `status`.
2058
+ */
2059
+ follow(user: UserRef, options?: RequestOptions): Promise<FollowResult>;
2060
+ /** Отписывается от пользователя. */
2061
+ unfollow(user: UserRef, options?: RequestOptions): Promise<void>;
2062
+ /**
2063
+ * Загружает подписчиков пользователя.
2064
+ *
2065
+ * ⚠️ **Сервер этот список не листает.** Возвращаются первые 20 записей и только они:
2066
+ * параметр `page` игнорируется (любая страница отдаёт те же записи и `pagination.page: 1`),
2067
+ * `limit` больше 20 молча уменьшается, а `hasMore` всегда `false`. Последнее честно —
2068
+ * получить продолжение нечем.
2069
+ *
2070
+ * Числу `total` доверять тоже не стоит: оно расходится с `followersCount` из профиля —
2071
+ * на проверенных аккаунтах занижено примерно на 1–4%.
2072
+ */
2073
+ followers(user: UserRef, params?: UserListParams, options?: RequestOptions): Promise<Page<UserSummary>>;
2074
+ /**
2075
+ * Перебирает подписчиков.
2076
+ *
2077
+ * ⚠️ Перебор закончится после первых 20 записей: сервер список не листает —
2078
+ * см. {@link followers}. Метод оставлен на случай, если пагинацию починят.
2079
+ */
2080
+ iterateFollowers(user: UserRef, params?: UserListParams, options?: PaginationOptions): Paginator<UserSummary>;
2081
+ /** Загружает подписки пользователя. Ограничения те же, что у {@link followers}. */
2082
+ following(user: UserRef, params?: UserListParams, options?: RequestOptions): Promise<Page<UserSummary>>;
2083
+ /** Перебирает подписки. Закончится после первых 20 записей — см. {@link followers}. */
2084
+ iterateFollowing(user: UserRef, params?: UserListParams, options?: PaginationOptions): Paginator<UserSummary>;
2085
+ /**
2086
+ * Проверяет, подписаны ли вы, сразу для нескольких пользователей.
2087
+ *
2088
+ * @returns объект «идентификатор пользователя → подписаны ли вы»
2089
+ *
2090
+ * @example
2091
+ * ```ts
2092
+ * const statuses = await itd.users.followStatus([userA, userB]);
2093
+ * // { 'b89dee4f-…': true, '35ea3059-…': false }
2094
+ * ```
2095
+ */
2096
+ followStatus(userIds: UserId[], options?: RequestOptions): Promise<Record<string, boolean>>;
2097
+ /** Блокирует пользователя. */
2098
+ block(user: UserRef, options?: RequestOptions): Promise<void>;
2099
+ /** Снимает блокировку. */
2100
+ unblock(user: UserRef, options?: RequestOptions): Promise<void>;
2101
+ /** Загружает заблокированных пользователей. Ограничения те же, что у {@link followers}. */
2102
+ blocked(params?: UserListParams, options?: RequestOptions): Promise<Page<UserSummary>>;
2103
+ /** Перебирает заблокированных. Закончится после первых 20 записей — см. {@link followers}. */
2104
+ iterateBlocked(params?: UserListParams, options?: PaginationOptions): Paginator<UserSummary>;
2105
+ /** Загружает настройки приватности. */
2106
+ getPrivacy(options?: RequestOptions): Promise<PrivacySettings>;
2107
+ /** Обновляет настройки приватности. Передавайте только изменяемые поля. */
2108
+ updatePrivacy(input: UpdatePrivacyInput, options?: RequestOptions): Promise<PrivacySettings>;
2109
+ /**
2110
+ * Загружает значки профиля и выбранный из них.
2111
+ *
2112
+ * `activePin` — строка-идентификатор, а не объект.
2113
+ */
2114
+ pins(options?: RequestOptions): Promise<PinsResult>;
2115
+ /** Выбирает активный значок профиля. */
2116
+ setPin(slug: string, options?: RequestOptions): Promise<void>;
2117
+ /** Снимает активный значок. */
2118
+ removePin(options?: RequestOptions): Promise<void>;
2119
+ }
2120
+ //#endregion
2121
+ //#region src/resources/verification.d.ts
2122
+ /**
2123
+ * Верификация профиля.
2124
+ *
2125
+ * Доступна как `itd.verification`.
2126
+ */
2127
+ declare class VerificationResource extends BaseResource {
2128
+ /** Загружает статус заявки. Значение `none` означает, что заявка не подавалась. */
2129
+ status(options?: RequestOptions): Promise<VerificationStatus>;
2130
+ /** Подаёт заявку на верификацию с видео. */
2131
+ submit(videoUrl: string, options?: RequestOptions): Promise<unknown>;
2132
+ }
2133
+ //#endregion
2134
+ //#region src/core/attachments/factories.d.ts
2135
+ /** Создаёт URL-источник в выбранном режиме. */
2136
+ declare function fromUrl(url: string, options: UrlFileOptions & {
2137
+ mode: typeof FileTransferMode.Stream;
2138
+ }): StreamFile;
2139
+ declare function fromUrl(url: string, options?: UrlFileOptions & {
2140
+ mode?: typeof FileTransferMode.Buffer;
2141
+ }): LazyFile;
2142
+ declare function fromUrl(url: string, options: UrlFileOptions): LazyFile | StreamFile;
2143
+ /**
2144
+ * Создаёт повторяемый пользовательский поток.
2145
+ *
2146
+ * Фабрика вызывается заново для каждой попытки; возвращать один и тот же поток нельзя.
2147
+ */
2148
+ declare function fromStream(factory: (context: FileContext) => ReadableStream<Uint8Array> | FileStreamContent | Promise<ReadableStream<Uint8Array> | FileStreamContent>, options?: FromStreamOptions): StreamFile;
2149
+ //#endregion
2150
+ //#region src/domain/mime.d.ts
2151
+ /** Изображения, которые принимает `POST /api/files/upload`. */
2152
+ declare const IMAGE_MIME_TYPES: readonly ["image/jpeg", "image/png", "image/gif", "image/webp", "image/avif", "image/heic", "image/heif"];
2153
+ type ImageMimeType = (typeof IMAGE_MIME_TYPES)[number];
2154
+ /** Видео, которые принимает `POST /api/files/upload`. */
2155
+ declare const VIDEO_MIME_TYPES: readonly ["video/mp4", "video/webm", "video/quicktime"];
2156
+ type VideoMimeType = (typeof VIDEO_MIME_TYPES)[number];
2157
+ /** Аудио для голосовых комментариев. */
2158
+ declare const AUDIO_MIME_TYPES: readonly ["audio/ogg"];
2159
+ type AudioMimeType = (typeof AUDIO_MIME_TYPES)[number];
2160
+ /** Все типы, которые принимает загрузка. */
2161
+ declare const ALLOWED_MIME_TYPES: readonly ["image/jpeg", "image/png", "image/gif", "image/webp", "image/avif", "image/heic", "image/heif", "video/mp4", "video/webm", "video/quicktime", "audio/ogg"];
2162
+ type AllowedMimeType = (typeof ALLOWED_MIME_TYPES)[number];
2163
+ //#endregion
2164
+ //#region src/domain/time.d.ts
2165
+ /**
2166
+ * Приводит отметку времени без часового пояса к ISO-8601, считая её временем UTC.
2167
+ *
2168
+ * Строку другого вида возвращает нетронутой.
2169
+ *
2170
+ * @example
2171
+ * ```ts
2172
+ * utcStampToIso('2026-07-23 23:14:25'); // '2026-07-23T23:14:25Z'
2173
+ * utcStampToIso('2026-07-23T23:14:25Z'); // без изменений
2174
+ * ```
2175
+ */
2176
+ declare function utcStampToIso(value: string): string;
2177
+ /**
2178
+ * Разбирает дату API в объект `Date`.
2179
+ *
2180
+ * @returns `null`, если строки нет или она не разбирается
2181
+ *
2182
+ * @example
2183
+ * ```ts
2184
+ * const created = toDate(post.createdAt);
2185
+ * ```
2186
+ */
2187
+ declare function toDate(value: IsoDate | null | undefined): Date | null;
2188
+ //#endregion
2189
+ //#region src/models/guards.d.ts
2190
+ /**
2191
+ * Свой ли это профиль.
2192
+ *
2193
+ * @example
2194
+ * ```ts
2195
+ * if (isMyProfile(profile)) console.log(profile.subscription.isActive);
2196
+ * ```
2197
+ */
2198
+ declare function isMyProfile(profile: Profile): profile is MyProfile;
2199
+ //#endregion
2200
+ //#region src/models/status-helpers.d.ts
2201
+ /**
2202
+ * Разворачивает историю сервиса в массив на 90 суток.
2203
+ * Сутки без данных становятся `null`.
2204
+ *
2205
+ * @returns массив, где индекс — сколько суток назад: `[0]` — сегодня
2206
+ *
2207
+ * @example
2208
+ * ```ts
2209
+ * const status = await itd.platform.status();
2210
+ * const days = statusDays(status.services[0]);
2211
+ *
2212
+ * days[0]?.uptime; // доступность за сегодня
2213
+ * days.filter((day) => day === null).length; // за сколько суток данных нет
2214
+ * ```
2215
+ */
2216
+ declare function statusDays(service: ServiceStatus): (StatusDay | null)[];
2217
+ //#endregion
2218
+ //#region src/spans/render.d.ts
2219
+ /** Формат результата {@link renderSpans}. */
2220
+ declare const SpanRenderFormat: Readonly<{
2221
+ readonly Html: "html";
2222
+ readonly Markdown: "markdown";
2223
+ readonly Ansi: "ansi";
2224
+ }>;
2225
+ type SpanRenderFormat = (typeof SpanRenderFormat)[keyof typeof SpanRenderFormat];
2226
+ interface RenderSpansOptions {
2227
+ /** Формат результата. По умолчанию `html`. */
2228
+ format?: SpanRenderFormat;
2229
+ /** Строит адрес упоминания. `null` или `undefined` отключает ссылку. */
2230
+ mentionUrl?: (username: string) => string | null | undefined;
2231
+ /** Строит адрес хэштега. `null` или `undefined` отключает ссылку. */
2232
+ hashtagUrl?: (tag: string) => string | null | undefined;
2233
+ /**
2234
+ * Префикс HTML-классов. По умолчанию `itd`; пустая строка или `null` отключает классы.
2235
+ *
2236
+ * Например, `app` создаёт `app-mention`, `app-hashtag`, `app-quote` и `app-spoiler`.
2237
+ */
2238
+ classPrefix?: string | null;
2239
+ }
2240
+ /**
2241
+ * Преобразует текст и wire-разметку API в безопасный HTML, Markdown или ANSI.
2242
+ *
2243
+ * Некорректные серверные spans игнорируются либо обрезаются по границам строки. Пересекающиеся
2244
+ * spans разбиваются на независимые сегменты, поэтому HTML остаётся корректно вложенным.
2245
+ * Отсутствующий массив считается пустым; формат по умолчанию — HTML.
2246
+ */
2247
+ declare function renderSpans(content: string, spans?: readonly Span[] | null | undefined, options?: RenderSpansOptions): string;
2248
+ //#endregion
2249
+ export { poll as $, CreatePostData as $t, TelemetryResource as A, FilesResource as At, ReportInput as B, PinPostResult as Bt, DwellEntry as C, RequestHandler as Cn, Report as Ct, TelemetryBatchOptions as D, UpdateNotificationSettingsInput as Dt, TelemetryBatch as E, NotificationsResource as Et, SubscriptionResource as F, Attachment as Ft, UserPostsParams as G, CommentBuilder as Gt, CommentsParams as H, PollOption as Ht, SearchResource as I, Comment as It, PostInput as J, BuilderInput as Jt, CreatePostInput as K, CommentInput as Kt, SearchResult as L, CommentReplyTo as Lt, ViewTracker as M, UploadedFile as Mt, ViewTrackerInput as N, CommentsResource as Nt, TelemetryClock as O, HashtagPostsParams as Ot, ViewTrackerOptions as P, RepliesParams as Pt, PollInput as Q, CreatePollInput as Qt, ReportsResource as R, Hashtag as Rt, UsersResource as S, PluginTeardown as Sn, Portal as St, PhotoOpenInput as T, NotificationListParams as Tt, FeedParams as U, Post as Ut, report as V, Poll as Vt, PostsResource as W, PostStats as Wt, post as X, isBuilder as Xt, PostUpdateInput as Y, ItdBuilder as Yt, PollBuilder as Z, CreateCommentInput as Zt, fromUrl as _, AttemptNext as _n, StatusIncidentLine as _t, isMyProfile as a, PaginationMode as an, MarkupContent as at, UpdateProfileInput as b, OperationTransformer as bn, ChangelogEntry as bt, ALLOWED_MIME_TYPES as c, mapPage as cn, TextMarkup as ct, AudioMimeType as d, Subscription as dn, PlatformClientVersion as dt, CreateReportInput as en, ParseMarkupOptions as et, IMAGE_MIME_TYPES as f, HttpClient as fn, PlatformResource as ft, fromStream as g, AttemptInterceptor as gn, StatusDay as gt, VideoMimeType as h, AttemptExtensions as hn, ServiceStatus as ht, statusDays as i, PageState as in, MarkupBuilder as it, VideoProgressInput as j, UploadOptions as jt, TelemetryOptions as k, HashtagsResource as kt, AUDIO_MIME_TYPES as l, PaymentMethod as ln, autoSpans as lt, VIDEO_MIME_TYPES as m, AttemptContext as mn, PlatformStatus as mt, SpanRenderFormat as n, BaseResource as nn, parseMarkdown as nt, toDate as o, Paginator as on, MarkupInput as ot, ImageMimeType as p, RateLimitBucketState as pn, PlatformVersions as pt, PostBuilder as q, comment as qt, renderSpans as r, Page as rn, AutoSpansOptions as rt, utcStampToIso as s, PaginatorOptions as sn, MarkupSpan as st, RenderSpansOptions as t, UpdatePostInput as tn, parseHtml as tt, AllowedMimeType as u, Session as un, markup as ut, VerificationResource as v, ClientPlugin as vn, Announcement as vt, InteractionEntry as w, VerificationStatus as wt, UserListParams as x, PluginApi as xn, Clan as xt, UpdatePrivacyInput as y, OperationExtensions as yn, AnnouncementButton as yt, ReportBuilder as z, LikeResult as zt };
2250
+ //# sourceMappingURL=render-DZrxhC5_.d.ts.map