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