itd-api 0.7.2 → 0.9.0
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 +72 -27
- package/dist/events/index.cjs +53 -0
- package/dist/events/index.d.cts +3 -0
- package/dist/events/index.d.ts +3 -0
- package/dist/events/index.js +5 -0
- package/dist/index.cjs +234 -200
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +70 -64
- package/dist/index.d.ts +70 -64
- package/dist/index.js +202 -179
- package/dist/index.js.map +1 -1
- package/dist/node/index.cjs +6 -5
- package/dist/node/index.cjs.map +1 -1
- package/dist/node/index.d.cts +2 -2
- package/dist/node/index.d.ts +2 -2
- package/dist/node/index.js +5 -4
- package/dist/node/index.js.map +1 -1
- package/dist/rest/index.cjs +32 -26
- package/dist/rest/index.cjs.map +1 -1
- package/dist/rest/index.d.cts +9 -7
- package/dist/rest/index.d.ts +9 -7
- package/dist/rest/index.js +19 -21
- package/dist/rest/index.js.map +1 -1
- package/dist/shared/{errors-DfU8M5eS.cjs → errors-BmP3TKoW.cjs} +3 -3
- package/dist/shared/{errors-DfU8M5eS.cjs.map → errors-BmP3TKoW.cjs.map} +1 -1
- package/dist/shared/{errors-Bhrd2fJd.js → errors-GI10kZxk.js} +3 -3
- package/dist/shared/{errors-Bhrd2fJd.js.map → errors-GI10kZxk.js.map} +1 -1
- package/dist/shared/{websocket-BLR8eVJV.js → events-C5wnTXPT.js} +770 -490
- package/dist/shared/events-C5wnTXPT.js.map +1 -0
- package/dist/shared/events-CqtkP65d.d.ts +698 -0
- package/dist/shared/events-DGAWlCaI.d.cts +698 -0
- package/dist/shared/{websocket-C_eI4H2o.cjs → events-FZfnEez0.cjs} +834 -518
- package/dist/shared/events-FZfnEez0.cjs.map +1 -0
- package/dist/shared/{storage-BPJR_k4-.cjs → key-value-store-B5GYVEYZ.cjs} +2 -86
- package/dist/shared/key-value-store-B5GYVEYZ.cjs.map +1 -0
- package/dist/shared/{storage-D86edNCB.js → key-value-store-Bt2PSMxY.js} +3 -69
- package/dist/shared/key-value-store-Bt2PSMxY.js.map +1 -0
- package/dist/shared/key-value-store-COZaNHZS.d.cts +69 -0
- package/dist/shared/key-value-store-COZaNHZS.d.ts +69 -0
- package/dist/shared/{multi-storage-DccjD7Ww.d.ts → multi-storage-BEL7tcKn.d.cts} +3 -2
- package/dist/shared/{multi-storage--yTEqiod.cjs → multi-storage-CDKLa956.cjs} +11 -10
- package/dist/shared/{multi-storage--yTEqiod.cjs.map → multi-storage-CDKLa956.cjs.map} +1 -1
- package/dist/shared/{multi-storage-CjAPB5Kq.d.cts → multi-storage-LkljOSzA.d.ts} +3 -2
- package/dist/shared/{multi-storage-CkvTUC5m.js → multi-storage-SoW05uzO.js} +5 -4
- package/dist/shared/{multi-storage-CkvTUC5m.js.map → multi-storage-SoW05uzO.js.map} +1 -1
- package/dist/shared/{options-Dg5N3r1V.cjs → options-DOJYtoti.cjs} +8 -6
- package/dist/shared/options-DOJYtoti.cjs.map +1 -0
- package/dist/shared/{options-DtATYdLr.js → options-DhgGg7Ms.js} +8 -6
- package/dist/shared/options-DhgGg7Ms.js.map +1 -0
- package/dist/shared/{cookies-DZwFq6kr.cjs → redact-BP00URmQ.cjs} +312 -2
- package/dist/shared/redact-BP00URmQ.cjs.map +1 -0
- package/dist/shared/{cookies-tX2sNwxb.js → redact-Ba5iSVYZ.js} +235 -3
- package/dist/shared/redact-Ba5iSVYZ.js.map +1 -0
- package/dist/shared/{render-CgwKdOzu.d.ts → render-B4qis7Sb.d.ts} +775 -313
- package/dist/shared/{render-DO0F5YSm.d.cts → render-DDwy2Ame.d.cts} +775 -313
- package/dist/shared/{render-mcuELiYi.cjs → render-Dqi8Owqk.cjs} +1464 -662
- package/dist/shared/render-Dqi8Owqk.cjs.map +1 -0
- package/dist/shared/{render-C6HRPs10.js → render-hiWFh2s4.js} +1366 -618
- package/dist/shared/render-hiWFh2s4.js.map +1 -0
- package/dist/shared/storage-BQrtKon9.d.cts +86 -0
- package/dist/shared/storage-CTRGT5wF.d.ts +86 -0
- package/dist/shared/storage-CfHKzVHf.js +71 -0
- package/dist/shared/storage-CfHKzVHf.js.map +1 -0
- package/dist/shared/storage-QNVxzpDB.cjs +88 -0
- package/dist/shared/storage-QNVxzpDB.cjs.map +1 -0
- package/dist/shared/{url-BaMCQpYH.cjs → url-Bsb3xE5U.cjs} +577 -466
- package/dist/shared/url-Bsb3xE5U.cjs.map +1 -0
- package/dist/shared/{url-IU0xN9wX.js → url-DP33mp3s.js} +508 -409
- package/dist/shared/url-DP33mp3s.js.map +1 -0
- package/dist/shared/{url-DTfZ2toq.d.ts → url-XBsMdAcv.d.cts} +1313 -1200
- package/dist/shared/{url-DTfZ2toq.d.cts → url-XBsMdAcv.d.ts} +1313 -1200
- package/dist/web/index.cjs +5 -4
- package/dist/web/index.cjs.map +1 -1
- package/dist/web/index.d.cts +1 -1
- package/dist/web/index.d.ts +1 -1
- package/dist/web/index.js +3 -2
- package/dist/web/index.js.map +1 -1
- package/package.json +16 -15
- package/dist/realtime/index.cjs +0 -165
- package/dist/realtime/index.cjs.map +0 -1
- package/dist/realtime/index.d.cts +0 -51
- package/dist/realtime/index.d.ts +0 -51
- package/dist/realtime/index.js +0 -120
- package/dist/realtime/index.js.map +0 -1
- package/dist/shared/auth-provider-CG8oCQ9F.cjs +0 -108
- package/dist/shared/auth-provider-CG8oCQ9F.cjs.map +0 -1
- package/dist/shared/auth-provider-mYqxsSVa.js +0 -91
- package/dist/shared/auth-provider-mYqxsSVa.js.map +0 -1
- package/dist/shared/cookies-DZwFq6kr.cjs.map +0 -1
- package/dist/shared/cookies-tX2sNwxb.js.map +0 -1
- package/dist/shared/options-Dg5N3r1V.cjs.map +0 -1
- package/dist/shared/options-DtATYdLr.js.map +0 -1
- package/dist/shared/render-C6HRPs10.js.map +0 -1
- package/dist/shared/render-mcuELiYi.cjs.map +0 -1
- package/dist/shared/storage-BPJR_k4-.cjs.map +0 -1
- package/dist/shared/storage-C_eICCep.d.cts +0 -152
- package/dist/shared/storage-C_eICCep.d.ts +0 -152
- package/dist/shared/storage-D86edNCB.js.map +0 -1
- package/dist/shared/url-BaMCQpYH.cjs.map +0 -1
- package/dist/shared/url-IU0xN9wX.js.map +0 -1
- package/dist/shared/websocket-BLR8eVJV.js.map +0 -1
- package/dist/shared/websocket-C_eI4H2o.cjs.map +0 -1
- package/dist/shared/websocket-DF7XIMiX.d.cts +0 -562
- package/dist/shared/websocket-DYKBr8HF.d.ts +0 -562
|
@@ -1,97 +1,447 @@
|
|
|
1
|
-
//#region src/
|
|
2
|
-
/**
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
1
|
+
//#region src/types/enums.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Enum API итд.com.
|
|
4
|
+
*
|
|
5
|
+
* Здесь намеренно не используется `enum` из TypeScript. Вместо него — пара «замороженный
|
|
6
|
+
* объект + одноимённый тип». Такой приём даёт всё, ради чего берут `enum`
|
|
7
|
+
* (`FeedTab.Popular`, перебор значений в рантайме), и при этом:
|
|
8
|
+
*
|
|
9
|
+
* - **стирается без остатка** — `enum` порождает рантайм-код и отвергается средами,
|
|
10
|
+
* которые просто срезают типы (`node --experimental-strip-types`);
|
|
11
|
+
* - **не запрещает обычные строки** — `itd.posts.list({ tab: 'popular' })` остаётся валидным,
|
|
12
|
+
* тогда как строковый `enum` считает это ошибкой типа и вынуждает всех импортировать себя;
|
|
13
|
+
* - **позволяет открытые множества** — там, где документация перечисляет значения не полностью,
|
|
14
|
+
* тип расширяется через {@link Loose}, а объект остаётся справочником известных значений.
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```ts
|
|
18
|
+
* import { FeedTab } from 'itd-api';
|
|
19
|
+
*
|
|
20
|
+
* await itd.posts.list({ tab: FeedTab.Popular }); // без магических строк
|
|
21
|
+
* await itd.posts.list({ tab: 'popular' }); // и так тоже можно
|
|
22
|
+
*
|
|
23
|
+
* Object.values(FeedTab); // ['popular', 'following', 'clan']
|
|
24
|
+
* ```
|
|
25
|
+
*
|
|
26
|
+
* @packageDocumentation
|
|
27
|
+
*/
|
|
28
|
+
/**
|
|
29
|
+
* Открытый строковый enum.
|
|
30
|
+
*
|
|
31
|
+
* Даёт автодополнение известных значений, но не ломается, если сервер пришлёт новое.
|
|
32
|
+
* Используется там, где документация API перечисляет значения не полностью («`everyone` и др.»).
|
|
33
|
+
*/
|
|
34
|
+
type Loose<T extends string> = T | (string & {});
|
|
35
|
+
/**
|
|
36
|
+
* Вкладка ленты `GET /api/posts`.
|
|
37
|
+
*
|
|
38
|
+
* Множество закрытое: неизвестное значение сервер отвергнет.
|
|
39
|
+
*/
|
|
40
|
+
declare const FeedTab: Readonly<{
|
|
41
|
+
/** Популярное. Курсор здесь — номер страницы в виде строки (`"2"`, `"6"`…). */
|
|
42
|
+
readonly Popular: "popular";
|
|
43
|
+
/** Записи тех, на кого вы подписаны. Курсор — отметка времени последнего поста. */
|
|
44
|
+
readonly Following: "following";
|
|
45
|
+
/** Лента клана. Курсор, как и в подписках, — отметка времени. */
|
|
46
|
+
readonly Clan: "clan";
|
|
14
47
|
}>;
|
|
15
|
-
type
|
|
48
|
+
type FeedTab = (typeof FeedTab)[keyof typeof FeedTab];
|
|
49
|
+
/** Порядок комментариев к посту. */
|
|
50
|
+
declare const CommentSort: Readonly<{
|
|
51
|
+
/** Сначала новые. */
|
|
52
|
+
readonly Newest: "newest";
|
|
53
|
+
/** Сначала старые. */
|
|
54
|
+
readonly Oldest: "oldest";
|
|
55
|
+
/** Сначала популярные. */
|
|
56
|
+
readonly Popular: "popular";
|
|
57
|
+
}>;
|
|
58
|
+
type CommentSort = (typeof CommentSort)[keyof typeof CommentSort];
|
|
59
|
+
/** Тип вложения. */
|
|
60
|
+
declare const AttachmentType: Readonly<{
|
|
61
|
+
readonly Image: "image";
|
|
62
|
+
readonly Video: "video";
|
|
63
|
+
/** Голосовые комментарии: `audio/ogg`, с полем `duration`. */
|
|
64
|
+
readonly Audio: "audio";
|
|
65
|
+
}>;
|
|
66
|
+
type AttachmentType = (typeof AttachmentType)[keyof typeof AttachmentType];
|
|
16
67
|
/**
|
|
17
|
-
*
|
|
68
|
+
* Тип фрагмента разметки в тексте поста или комментария.
|
|
18
69
|
*
|
|
19
|
-
*
|
|
70
|
+
* Первые два сервер расставляет сам при разборе текста, остальные приходят от редактора.
|
|
71
|
+
* Тип открытый: набор может пополниться.
|
|
72
|
+
*
|
|
73
|
+
* @example
|
|
74
|
+
* ```ts
|
|
75
|
+
* await itd.posts.update(postId, {
|
|
76
|
+
* content: 'жирное слово',
|
|
77
|
+
* spans: [{ type: SpanType.Bold, offset: 0, length: 6 }],
|
|
78
|
+
* });
|
|
79
|
+
* ```
|
|
20
80
|
*/
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
readonly
|
|
24
|
-
/**
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
readonly
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
81
|
+
declare const SpanType: Readonly<{
|
|
82
|
+
/** Хэштег. Название без решётки лежит в `tag`. */
|
|
83
|
+
readonly Hashtag: "hashtag";
|
|
84
|
+
/** Упоминание. Имя пользователя лежит в `tag`. */
|
|
85
|
+
readonly Mention: "mention";
|
|
86
|
+
/** Ссылка. Адрес лежит в `url`, а не в `tag`. */
|
|
87
|
+
readonly Link: "link";
|
|
88
|
+
readonly Bold: "bold";
|
|
89
|
+
readonly Italic: "italic";
|
|
90
|
+
readonly Underline: "underline";
|
|
91
|
+
/** Зачёркнутый. */
|
|
92
|
+
readonly Strike: "strike";
|
|
93
|
+
/** Спойлер: текст скрыт до нажатия. */
|
|
94
|
+
readonly Spoiler: "spoiler";
|
|
95
|
+
/** Моноширинный. */
|
|
96
|
+
readonly Monospace: "monospace";
|
|
97
|
+
readonly Quote: "quote";
|
|
98
|
+
}>;
|
|
99
|
+
type SpanType = Loose<(typeof SpanType)[keyof typeof SpanType]>;
|
|
100
|
+
/** На что подаётся жалоба. */
|
|
101
|
+
declare const ReportTargetType: Readonly<{
|
|
102
|
+
readonly Post: "post";
|
|
103
|
+
readonly Comment: "comment";
|
|
104
|
+
readonly User: "user";
|
|
105
|
+
}>;
|
|
106
|
+
type ReportTargetType = (typeof ReportTargetType)[keyof typeof ReportTargetType];
|
|
107
|
+
/** Причина жалобы. Множество закрытое. */
|
|
108
|
+
declare const ReportReason: Readonly<{
|
|
109
|
+
readonly Spam: "spam";
|
|
110
|
+
readonly Violence: "violence";
|
|
111
|
+
readonly Hate: "hate";
|
|
112
|
+
readonly Adult: "adult";
|
|
113
|
+
readonly Fraud: "fraud";
|
|
114
|
+
readonly Other: "other";
|
|
115
|
+
}>;
|
|
116
|
+
type ReportReason = (typeof ReportReason)[keyof typeof ReportReason];
|
|
117
|
+
/** Состояние соединения событийного канала. */
|
|
118
|
+
declare const EventChannelStatus: Readonly<{
|
|
119
|
+
readonly Connecting: "connecting";
|
|
120
|
+
readonly Connected: "connected";
|
|
121
|
+
readonly Error: "error";
|
|
122
|
+
readonly Disconnected: "disconnected";
|
|
123
|
+
}>;
|
|
124
|
+
type EventChannelStatus = (typeof EventChannelStatus)[keyof typeof EventChannelStatus];
|
|
125
|
+
/** Состояние сервиса платформы. Тип открытый. */
|
|
126
|
+
declare const ServiceState: Readonly<{
|
|
127
|
+
/** Работает штатно. */
|
|
128
|
+
readonly Operational: "operational";
|
|
129
|
+
/** Работает с деградацией. */
|
|
130
|
+
readonly Degraded: "degraded";
|
|
131
|
+
/** Недоступен. */
|
|
132
|
+
readonly Downtime: "downtime";
|
|
133
|
+
}>;
|
|
134
|
+
type ServiceState = Loose<(typeof ServiceState)[keyof typeof ServiceState]>;
|
|
135
|
+
/** Вид происшествия в истории сервиса. Тип открытый. */
|
|
136
|
+
declare const IncidentKind: Readonly<{
|
|
137
|
+
/** Недоступен. */
|
|
138
|
+
readonly Down: "down";
|
|
139
|
+
/** Деградация. */
|
|
140
|
+
readonly Degraded: "deg";
|
|
141
|
+
}>;
|
|
142
|
+
type IncidentKind = Loose<(typeof IncidentKind)[keyof typeof IncidentKind]>;
|
|
34
143
|
/**
|
|
35
|
-
*
|
|
144
|
+
* Уровень доступа к разделу профиля.
|
|
36
145
|
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
* собственного правила на сервере.
|
|
146
|
+
* Общий набор значений для полей `wallAccess` и `likesVisibility` настроек приватности.
|
|
147
|
+
* Тип открытый: сервер может прислать значение вне этого перечня.
|
|
40
148
|
*/
|
|
41
|
-
declare const
|
|
42
|
-
|
|
43
|
-
readonly
|
|
44
|
-
|
|
45
|
-
readonly
|
|
46
|
-
|
|
47
|
-
readonly
|
|
48
|
-
|
|
49
|
-
readonly
|
|
50
|
-
readonly 'files.get': 40;
|
|
51
|
-
readonly auth: 35;
|
|
52
|
-
readonly 'auth.refresh': 25;
|
|
53
|
-
readonly search: 25;
|
|
54
|
-
readonly 'comments.like': 22;
|
|
55
|
-
readonly 'files.upload': 15;
|
|
56
|
-
readonly 'files.remove': 15;
|
|
57
|
-
readonly 'posts.comment': 14;
|
|
58
|
-
readonly 'hashtags.trending': 13;
|
|
59
|
-
readonly 'posts.repost': 7;
|
|
60
|
-
readonly 'users.follow': 7;
|
|
61
|
-
readonly 'verification.status': 6;
|
|
62
|
-
readonly 'posts.create': 5;
|
|
63
|
-
readonly 'users.updateMe': 3;
|
|
64
|
-
readonly 'reports.create': 3;
|
|
65
|
-
readonly 'verification.submit': 3;
|
|
149
|
+
declare const AccessType: Readonly<{
|
|
150
|
+
/** Никто. */
|
|
151
|
+
readonly Nobody: "nobody";
|
|
152
|
+
/** Только взаимные подписки. */
|
|
153
|
+
readonly Mutual: "mutual";
|
|
154
|
+
/** Подписчики. */
|
|
155
|
+
readonly Followers: "followers";
|
|
156
|
+
/** Все. */
|
|
157
|
+
readonly Everyone: "everyone";
|
|
66
158
|
}>;
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
readonly
|
|
76
|
-
|
|
159
|
+
type AccessType = Loose<(typeof AccessType)[keyof typeof AccessType]>;
|
|
160
|
+
/** Кто может писать на стену профиля. Псевдоним {@link AccessType}. */
|
|
161
|
+
declare const WallAccess: Readonly<{
|
|
162
|
+
/** Никто. */
|
|
163
|
+
readonly Nobody: "nobody";
|
|
164
|
+
/** Только взаимные подписки. */
|
|
165
|
+
readonly Mutual: "mutual";
|
|
166
|
+
/** Подписчики. */
|
|
167
|
+
readonly Followers: "followers";
|
|
168
|
+
/** Все. */
|
|
169
|
+
readonly Everyone: "everyone";
|
|
170
|
+
}>;
|
|
171
|
+
type WallAccess = AccessType;
|
|
172
|
+
/** Кто видит реакции пользователя. Псевдоним {@link AccessType}. */
|
|
173
|
+
declare const LikesVisibility: Readonly<{
|
|
174
|
+
/** Никто. */
|
|
175
|
+
readonly Nobody: "nobody";
|
|
176
|
+
/** Только взаимные подписки. */
|
|
177
|
+
readonly Mutual: "mutual";
|
|
178
|
+
/** Подписчики. */
|
|
179
|
+
readonly Followers: "followers";
|
|
180
|
+
/** Все. */
|
|
181
|
+
readonly Everyone: "everyone";
|
|
182
|
+
}>;
|
|
183
|
+
type LikesVisibility = AccessType;
|
|
77
184
|
/**
|
|
78
|
-
*
|
|
185
|
+
* Канонический тип уведомления (новое поколение имён).
|
|
79
186
|
*
|
|
80
|
-
*
|
|
81
|
-
*
|
|
187
|
+
* REST-эндпоинт `/api/notifications/` отдаёт старые имена (`like`, `comment`, `reply`,
|
|
188
|
+
* `repost`, `mention`), SSE-поток — новые. Библиотека приводит их к этому набору,
|
|
189
|
+
* сохраняя исходное значение в поле `rawType`.
|
|
82
190
|
*/
|
|
83
|
-
declare const
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
readonly
|
|
94
|
-
|
|
191
|
+
declare const NotificationType: Readonly<{
|
|
192
|
+
/** Реакция на пост. Старое имя — `like`. */
|
|
193
|
+
readonly PostReaction: "post_reaction";
|
|
194
|
+
/** Комментарий к посту. Старое имя — `comment`. */
|
|
195
|
+
readonly PostComment: "post_comment";
|
|
196
|
+
/** Ответ на комментарий. Старое имя — `reply`. */
|
|
197
|
+
readonly CommentReply: "comment_reply";
|
|
198
|
+
/** Репост. Старое имя — `repost`. */
|
|
199
|
+
readonly PostRepost: "post_repost";
|
|
200
|
+
/** Упоминание в посте. Старое имя — `mention`. */
|
|
201
|
+
readonly PostMention: "post_mention";
|
|
202
|
+
/** Реакция на комментарий. */
|
|
203
|
+
readonly CommentReaction: "comment_reaction";
|
|
204
|
+
/** Упоминание в комментарии. */
|
|
205
|
+
readonly CommentMention: "comment_mention";
|
|
206
|
+
/** Запись на вашей стене. */
|
|
207
|
+
readonly WallPost: "wall_post";
|
|
208
|
+
/** На вас подписались. */
|
|
209
|
+
readonly Follow: "follow";
|
|
210
|
+
/** Заявка на подписку (закрытый профиль). */
|
|
211
|
+
readonly FollowRequest: "follow_request";
|
|
212
|
+
/** Заявка на подписку принята. */
|
|
213
|
+
readonly FollowAccepted: "follow_accepted";
|
|
214
|
+
/** Верификация одобрена. Приходит только по REST. */
|
|
215
|
+
readonly VerificationApproved: "verification_approved";
|
|
216
|
+
/** Верификация отклонена. Приходит только по REST. */
|
|
217
|
+
readonly VerificationRejected: "verification_rejected";
|
|
218
|
+
}>;
|
|
219
|
+
type NotificationType = Loose<(typeof NotificationType)[keyof typeof NotificationType]>;
|
|
220
|
+
/**
|
|
221
|
+
* Тип взаимодействия с контентом в телеметрии (`POST /api/v1/x`, поле `t`).
|
|
222
|
+
*
|
|
223
|
+
* Кодируется числом.
|
|
224
|
+
*/
|
|
225
|
+
declare const InteractionType: Readonly<{
|
|
226
|
+
/** Открытие фотографии. */
|
|
227
|
+
readonly PhotoOpen: 1;
|
|
228
|
+
/** Прогресс просмотра видео. Несёт поля `pm`/`dm`. */
|
|
229
|
+
readonly VideoProgress: 2;
|
|
230
|
+
}>;
|
|
231
|
+
type InteractionType = (typeof InteractionType)[keyof typeof InteractionType];
|
|
232
|
+
/**
|
|
233
|
+
* Источник показа поста в телеметрии (поле `s`).
|
|
234
|
+
*
|
|
235
|
+
* Кодируется числом. Поле применимо к источникам `PostPage` и `Link`; для лент источник
|
|
236
|
+
* передаётся контекстом `sc`.
|
|
237
|
+
*/
|
|
238
|
+
declare const ViewSource: Readonly<{
|
|
239
|
+
readonly FeedGlobal: 1;
|
|
240
|
+
readonly FeedFollowing: 2;
|
|
241
|
+
readonly FeedClan: 3;
|
|
242
|
+
readonly Profile: 4;
|
|
243
|
+
readonly Hashtag: 5;
|
|
244
|
+
readonly PostPage: 6;
|
|
245
|
+
readonly Link: 7;
|
|
246
|
+
readonly Search: 8;
|
|
247
|
+
}>;
|
|
248
|
+
type ViewSource = (typeof ViewSource)[keyof typeof ViewSource];
|
|
249
|
+
/**
|
|
250
|
+
* Причина завершения просмотра поста в телеметрии (`POST /api/v1/i`, поле `r`).
|
|
251
|
+
*
|
|
252
|
+
* Кодируется числом.
|
|
253
|
+
*/
|
|
254
|
+
declare const ViewReason: Readonly<{
|
|
255
|
+
/** Пост ушёл из зоны видимости при обычной прокрутке. */
|
|
256
|
+
readonly Normal: 0;
|
|
257
|
+
/** Потеря фокуса окна. */
|
|
258
|
+
readonly Blur: 1;
|
|
259
|
+
/** Вкладка скрыта. */
|
|
260
|
+
readonly Hidden: 2;
|
|
261
|
+
/** Уход со страницы (`pagehide`). */
|
|
262
|
+
readonly PageHide: 3;
|
|
263
|
+
/** Элемент перестал наблюдаться. */
|
|
264
|
+
readonly Unobserve: 4;
|
|
265
|
+
/** Достигнут порог времени просмотра. */
|
|
266
|
+
readonly ThresholdMet: 5;
|
|
267
|
+
}>;
|
|
268
|
+
type ViewReason = (typeof ViewReason)[keyof typeof ViewReason];
|
|
269
|
+
/**
|
|
270
|
+
* Строковые коды ошибок из поля `code`.
|
|
271
|
+
*
|
|
272
|
+
* Ключи намеренно повторяют написание сервера: код из ответа API можно найти здесь
|
|
273
|
+
* поиском один в один, без мысленного перевода регистра.
|
|
274
|
+
*
|
|
275
|
+
* Список открыт — сервер может добавить новый код, и это не должно ломать типизацию.
|
|
276
|
+
*
|
|
277
|
+
* @example
|
|
278
|
+
* ```ts
|
|
279
|
+
* if (err.hasCode(ItdErrorCode.OTP_INVALID)) await restartOtpFlow();
|
|
280
|
+
* ```
|
|
281
|
+
*/
|
|
282
|
+
declare const ItdErrorCode: Readonly<{
|
|
283
|
+
readonly BAD_REQUEST: "BAD_REQUEST";
|
|
284
|
+
readonly UNAUTHORIZED: "UNAUTHORIZED";
|
|
285
|
+
readonly ACCESS_DENIED: "ACCESS_DENIED";
|
|
286
|
+
readonly ENTITY_NOT_FOUND: "ENTITY_NOT_FOUND";
|
|
287
|
+
readonly ENTITY_ALREADY_EXISTS: "ENTITY_ALREADY_EXISTS";
|
|
288
|
+
readonly VALIDATION_ERROR: "VALIDATION_ERROR";
|
|
289
|
+
readonly BUSINESS_RULE_VIOLATION: "BUSINESS_RULE_VIOLATION";
|
|
290
|
+
readonly RATE_LIMIT_EXCEEDED: "RATE_LIMIT_EXCEEDED";
|
|
291
|
+
readonly UNKNOWN_ERROR: "UNKNOWN_ERROR";
|
|
292
|
+
/** Сервер отвечает так на `404`, `ENTITY_NOT_FOUND` в этом случае не приходит. */
|
|
293
|
+
readonly NOT_FOUND: "NOT_FOUND";
|
|
294
|
+
/** На практике не приходит: вместо него сервер шлёт `TURNSTILE_VERIFICATION_FAILED`. */
|
|
295
|
+
readonly CAPTCHA_FAILED: "CAPTCHA_FAILED";
|
|
296
|
+
/** Капча не пройдена: токен Turnstile недействителен, просрочен или уже использован. */
|
|
297
|
+
readonly TURNSTILE_VERIFICATION_FAILED: "TURNSTILE_VERIFICATION_FAILED";
|
|
298
|
+
readonly OTP_INVALID: "OTP_INVALID";
|
|
299
|
+
/** `flowToken` неизвестен или просрочен — поток подтверждения нужно начинать заново. */
|
|
300
|
+
readonly INVALID_FLOW_TOKEN: "INVALID_FLOW_TOKEN";
|
|
301
|
+
readonly ACCOUNT_DEACTIVATED: "ACCOUNT_DEACTIVATED";
|
|
302
|
+
readonly ACCOUNT_EMAIL_DOMAIN_NOT_ALLOWED: "ACCOUNT_EMAIL_DOMAIN_NOT_ALLOWED";
|
|
303
|
+
readonly ACCOUNT_INVALID_CREDENTIALS: "ACCOUNT_INVALID_CREDENTIALS";
|
|
304
|
+
readonly ACCOUNT_TEMPORARILY_LOCKED: "ACCOUNT_TEMPORARILY_LOCKED";
|
|
305
|
+
readonly ACCOUNT_CURRENT_PASSWORD_INCORRECT: "ACCOUNT_CURRENT_PASSWORD_INCORRECT";
|
|
306
|
+
readonly SESSION_EXPIRED: "SESSION_EXPIRED";
|
|
307
|
+
readonly SESSION_REVOKED: "SESSION_REVOKED";
|
|
308
|
+
readonly SESSION_INVALID_REFRESH_TOKEN: "SESSION_INVALID_REFRESH_TOKEN";
|
|
309
|
+
/** Запрос обновления пришёл без cookie `refresh_token` — продлевать нечего. */
|
|
310
|
+
readonly REFRESH_TOKEN_MISSING: "REFRESH_TOKEN_MISSING";
|
|
311
|
+
/** Cookie `refresh_token` есть, но сессии за ней уже нет: отозвана или истекла. */
|
|
312
|
+
readonly SESSION_NOT_FOUND: "SESSION_NOT_FOUND";
|
|
313
|
+
readonly MISSING_FLOW_TOKEN: "MISSING_FLOW_TOKEN";
|
|
314
|
+
readonly PROFILE_USERNAME_TAKEN: "PROFILE_USERNAME_TAKEN";
|
|
315
|
+
readonly PROFILE_USERNAME_RESERVED: "PROFILE_USERNAME_RESERVED";
|
|
316
|
+
readonly PROFILE_RESTRICTION_ACTIVE: "PROFILE_RESTRICTION_ACTIVE";
|
|
317
|
+
readonly PROFILE_MODIFICATION_RESTRICTED: "PROFILE_MODIFICATION_RESTRICTED";
|
|
318
|
+
readonly CONTENT_MODERATION_FAILED: "CONTENT_MODERATION_FAILED";
|
|
319
|
+
readonly FILE_TOO_LARGE: "FILE_TOO_LARGE";
|
|
320
|
+
readonly UNSUPPORTED_FILE_TYPE: "UNSUPPORTED_FILE_TYPE";
|
|
321
|
+
readonly UPLOAD_FAILED: "UPLOAD_FAILED";
|
|
322
|
+
readonly VIDEO_REQUIRES_VERIFICATION: "VIDEO_REQUIRES_VERIFICATION";
|
|
323
|
+
readonly PHONE_VERIFICATION_REQUIRED: "PHONE_VERIFICATION_REQUIRED";
|
|
324
|
+
readonly WRITE_ACCESS_RESTRICTED: "WRITE_ACCESS_RESTRICTED";
|
|
325
|
+
}>;
|
|
326
|
+
type ItdErrorCode = Loose<(typeof ItdErrorCode)[keyof typeof ItdErrorCode]>;
|
|
327
|
+
//#endregion
|
|
328
|
+
//#region src/models/common.d.ts
|
|
329
|
+
/**
|
|
330
|
+
* Дата и время в формате ISO-8601, например `2026-07-21T14:30:00.000Z`.
|
|
331
|
+
*
|
|
332
|
+
* Библиотека не превращает такие поля в `Date`: строку проще сравнивать, логировать
|
|
333
|
+
* и передавать дальше без потерь. Для разбора есть `toDate()`.
|
|
334
|
+
*/
|
|
335
|
+
type IsoDate = string;
|
|
336
|
+
/**
|
|
337
|
+
* Идентификатор пользователя — **строго UUID**.
|
|
338
|
+
*
|
|
339
|
+
* Отличается от {@link UserRef} тем, что имя пользователя здесь не подойдёт. Так помечены
|
|
340
|
+
* места, где API принимает только UUID: например `wallRecipientId` при постинге на чужую стену.
|
|
341
|
+
*/
|
|
342
|
+
type UserId = string;
|
|
343
|
+
/**
|
|
344
|
+
* Ссылка на пользователя: **UUID либо имя пользователя**.
|
|
345
|
+
*
|
|
346
|
+
* Пути вида `/api/users/{id}` принимают оба варианта, поэтому `itd.users.get('nowkie')`
|
|
347
|
+
* работает так же, как `itd.users.get('9f1c…')`.
|
|
348
|
+
*/
|
|
349
|
+
type UserRef = string;
|
|
350
|
+
/**
|
|
351
|
+
* Разметка в тексте поста или комментария.
|
|
352
|
+
*
|
|
353
|
+
* `offset` и `length` измеряются в UTF-16 code units: это те же индексы, которые используют
|
|
354
|
+
* `String#slice`, `substring` и DOM Selection в JavaScript. Эмодзи вне BMP обычно занимают
|
|
355
|
+
* две единицы.
|
|
356
|
+
*/
|
|
357
|
+
interface Span {
|
|
358
|
+
/** Тип фрагмента — см. {@link SpanType}. */
|
|
359
|
+
type: SpanType;
|
|
360
|
+
/** Смещение от начала текста. */
|
|
361
|
+
offset: number;
|
|
362
|
+
/** Длина фрагмента. */
|
|
363
|
+
length: number;
|
|
364
|
+
/** Имя хэштега без решётки. У старых mention-объектов может содержать username. */
|
|
365
|
+
tag?: string;
|
|
366
|
+
/** Адрес ссылки. Только у `link`: у него вместо `tag` отдельное поле. */
|
|
367
|
+
url?: string;
|
|
368
|
+
/** Имя пользователя у `mention`. */
|
|
369
|
+
username?: string;
|
|
370
|
+
/** Идентификатор пользователя у некоторых ответов API с `mention`. */
|
|
371
|
+
id?: string;
|
|
372
|
+
}
|
|
373
|
+
//#endregion
|
|
374
|
+
//#region src/domain/buckets.d.ts
|
|
375
|
+
/**
|
|
376
|
+
* Ёмкость серверных счётчиков частоты, запросов в минуту.
|
|
377
|
+
*
|
|
378
|
+
* Таблица действует до первого ответа бакета; дальше ёмкость берётся из заголовка
|
|
379
|
+
* `x-ratelimit-limit` и заменяет табличную. `default` — счётчик любого пути без
|
|
380
|
+
* собственного правила на сервере.
|
|
381
|
+
*/
|
|
382
|
+
declare const BUCKET_LIMITS: Readonly<{
|
|
383
|
+
readonly 'posts.stats': 180;
|
|
384
|
+
readonly default: 150;
|
|
385
|
+
readonly feed: 90;
|
|
386
|
+
readonly 'posts.like': 85;
|
|
387
|
+
readonly 'posts.comments': 80;
|
|
388
|
+
readonly hashtags: 50;
|
|
389
|
+
readonly users: 40;
|
|
390
|
+
readonly notifications: 40;
|
|
391
|
+
readonly 'files.get': 40;
|
|
392
|
+
readonly auth: 35;
|
|
393
|
+
readonly 'auth.refresh': 25;
|
|
394
|
+
readonly search: 25;
|
|
395
|
+
readonly 'comments.like': 22;
|
|
396
|
+
readonly 'files.upload': 15;
|
|
397
|
+
readonly 'files.remove': 15;
|
|
398
|
+
readonly 'posts.comment': 14;
|
|
399
|
+
readonly 'hashtags.trending': 13;
|
|
400
|
+
readonly 'posts.repost': 7;
|
|
401
|
+
readonly 'users.follow': 7;
|
|
402
|
+
readonly 'verification.status': 6;
|
|
403
|
+
readonly 'posts.create': 5;
|
|
404
|
+
readonly 'users.updateMe': 3;
|
|
405
|
+
readonly 'reports.create': 3;
|
|
406
|
+
readonly 'verification.submit': 3;
|
|
407
|
+
readonly shop: 150;
|
|
408
|
+
readonly 'shop.delivery.cities': 60;
|
|
409
|
+
readonly 'shop.delivery.calculate': 45;
|
|
410
|
+
readonly 'shop.delivery.points': 30;
|
|
411
|
+
readonly 'shop.consents.record': 15;
|
|
412
|
+
readonly 'shop.orders.pay': 13;
|
|
413
|
+
readonly 'shop.orders.verifyAccessCode': 13;
|
|
414
|
+
readonly 'shop.orders.create': 12;
|
|
415
|
+
readonly 'shop.orders.requestAccessCode': 4;
|
|
416
|
+
}>;
|
|
417
|
+
/** Имя встроенного бакета. */
|
|
418
|
+
type RateLimitBucket = keyof typeof BUCKET_LIMITS;
|
|
419
|
+
/** Счётчик, из которого списывается путь без собственного правила на сервере. */
|
|
420
|
+
declare const DEFAULT_RATE_LIMIT_BUCKET: RateLimitBucket;
|
|
421
|
+
//#endregion
|
|
422
|
+
//#region src/domain/operations.d.ts
|
|
423
|
+
/** Описание встроенной операции: та же форма, что знает ядро, но с именем известного бакета. */
|
|
424
|
+
interface ItdOperationDefinition extends OperationDefinition {
|
|
425
|
+
readonly bucket?: RateLimitBucket;
|
|
426
|
+
}
|
|
427
|
+
/**
|
|
428
|
+
* Каталог встроенных операций.
|
|
429
|
+
*
|
|
430
|
+
* ID описывает смысл вызова и не меняется при переносе HTTP-пути. Method и retrySafety
|
|
431
|
+
* хранятся здесь, чтобы resources, retry и плагины не вели независимые таблицы операций.
|
|
432
|
+
*/
|
|
433
|
+
declare const OPERATIONS: Readonly<{
|
|
434
|
+
readonly 'auth.check': Readonly<{
|
|
435
|
+
readonly method: "GET";
|
|
436
|
+
readonly retrySafety: "safe";
|
|
437
|
+
}>;
|
|
438
|
+
readonly 'auth.signUp': Readonly<{
|
|
439
|
+
readonly method: "POST";
|
|
440
|
+
readonly retrySafety: "unsafe";
|
|
441
|
+
readonly bucket: "auth";
|
|
442
|
+
}>;
|
|
443
|
+
readonly 'auth.signIn': Readonly<{
|
|
444
|
+
readonly method: "POST";
|
|
95
445
|
readonly retrySafety: "safe";
|
|
96
446
|
readonly bucket: "auth";
|
|
97
447
|
}>;
|
|
@@ -408,12 +758,12 @@ declare const OPERATIONS: Readonly<{
|
|
|
408
758
|
readonly method: "PUT";
|
|
409
759
|
readonly retrySafety: "idempotent";
|
|
410
760
|
}>;
|
|
411
|
-
readonly '
|
|
761
|
+
readonly 'events.notifications.poll.updates': Readonly<{
|
|
412
762
|
readonly method: "GET";
|
|
413
763
|
readonly retrySafety: "safe";
|
|
414
764
|
readonly bucket: "notifications";
|
|
415
765
|
}>;
|
|
416
|
-
readonly '
|
|
766
|
+
readonly 'events.notifications.poll.unread': Readonly<{
|
|
417
767
|
readonly method: "GET";
|
|
418
768
|
readonly retrySafety: "safe";
|
|
419
769
|
readonly bucket: "notifications";
|
|
@@ -505,18 +855,81 @@ declare const OPERATIONS: Readonly<{
|
|
|
505
855
|
readonly method: "POST";
|
|
506
856
|
readonly retrySafety: "unsafe";
|
|
507
857
|
}>;
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
858
|
+
readonly 'shop.products.list': Readonly<{
|
|
859
|
+
readonly method: "GET";
|
|
860
|
+
readonly retrySafety: "safe";
|
|
861
|
+
readonly bucket: "shop";
|
|
862
|
+
}>;
|
|
863
|
+
readonly 'shop.products.get': Readonly<{
|
|
864
|
+
readonly method: "GET";
|
|
865
|
+
readonly retrySafety: "safe";
|
|
866
|
+
readonly bucket: "shop";
|
|
867
|
+
}>;
|
|
868
|
+
readonly 'shop.delivery.countries': Readonly<{
|
|
869
|
+
readonly method: "GET";
|
|
870
|
+
readonly retrySafety: "safe";
|
|
871
|
+
readonly bucket: "shop";
|
|
872
|
+
}>;
|
|
873
|
+
readonly 'shop.delivery.cities': Readonly<{
|
|
874
|
+
readonly method: "GET";
|
|
875
|
+
readonly retrySafety: "safe";
|
|
876
|
+
readonly bucket: "shop.delivery.cities";
|
|
877
|
+
}>;
|
|
878
|
+
readonly 'shop.delivery.points': Readonly<{
|
|
879
|
+
readonly method: "GET";
|
|
880
|
+
readonly retrySafety: "safe";
|
|
881
|
+
readonly bucket: "shop.delivery.points";
|
|
882
|
+
}>;
|
|
883
|
+
readonly 'shop.delivery.calculate': Readonly<{
|
|
884
|
+
readonly method: "POST";
|
|
885
|
+
readonly retrySafety: "safe";
|
|
886
|
+
readonly bucket: "shop.delivery.calculate";
|
|
887
|
+
}>;
|
|
888
|
+
readonly 'shop.orders.create': Readonly<{
|
|
889
|
+
readonly method: "POST";
|
|
890
|
+
readonly retrySafety: "idempotent";
|
|
891
|
+
readonly bucket: "shop.orders.create";
|
|
892
|
+
}>;
|
|
893
|
+
readonly 'shop.orders.list': Readonly<{
|
|
894
|
+
readonly method: "GET";
|
|
895
|
+
readonly retrySafety: "safe";
|
|
896
|
+
}>;
|
|
897
|
+
readonly 'shop.orders.get': Readonly<{
|
|
898
|
+
readonly method: "GET";
|
|
899
|
+
readonly retrySafety: "safe";
|
|
900
|
+
}>;
|
|
901
|
+
readonly 'shop.orders.pay': Readonly<{
|
|
902
|
+
readonly method: "POST";
|
|
903
|
+
readonly retrySafety: "unsafe";
|
|
904
|
+
readonly bucket: "shop.orders.pay";
|
|
905
|
+
}>;
|
|
906
|
+
readonly 'shop.orders.requestAccessCode': Readonly<{
|
|
907
|
+
readonly method: "POST";
|
|
908
|
+
readonly retrySafety: "unsafe";
|
|
909
|
+
readonly bucket: "shop.orders.requestAccessCode";
|
|
910
|
+
}>;
|
|
911
|
+
readonly 'shop.orders.verifyAccessCode': Readonly<{
|
|
912
|
+
readonly method: "POST";
|
|
913
|
+
readonly retrySafety: "unsafe";
|
|
914
|
+
readonly bucket: "shop.orders.verifyAccessCode";
|
|
915
|
+
}>;
|
|
916
|
+
readonly 'shop.consents.record': Readonly<{
|
|
917
|
+
readonly method: "POST";
|
|
918
|
+
readonly retrySafety: "unsafe";
|
|
919
|
+
readonly bucket: "shop.consents.record";
|
|
920
|
+
}>;
|
|
921
|
+
}>;
|
|
922
|
+
/** Стабильный ID встроенной операции. */
|
|
923
|
+
type BuiltInOperationId = keyof typeof OPERATIONS;
|
|
924
|
+
/** Пользовательская семантическая операция низкоуровневого запроса. */
|
|
925
|
+
type CustomOperationId = `custom:${string}`;
|
|
926
|
+
/** ID любого запроса, видимый transformers и hooks. */
|
|
927
|
+
type OperationId = BuiltInOperationId | FeatureOperationId | CustomOperationId | 'raw';
|
|
928
|
+
/** Проверяет принадлежность ID встроенному каталогу. */
|
|
929
|
+
declare function isBuiltInOperationId(value: string): value is BuiltInOperationId;
|
|
930
|
+
/** HTTP-метод встроенной операции. */
|
|
931
|
+
declare function operationMethod(id: BuiltInOperationId): OperationMethod;
|
|
932
|
+
/** Политика автоматического повтора встроенной операции. */
|
|
520
933
|
declare function operationRetrySafety(id: BuiltInOperationId): RetrySafety;
|
|
521
934
|
/**
|
|
522
935
|
* Бакет операции.
|
|
@@ -597,7 +1010,7 @@ type QueryValue = string | number | boolean | null | undefined | readonly (strin
|
|
|
597
1010
|
type QueryParams = Record<string, QueryValue>;
|
|
598
1011
|
//#endregion
|
|
599
1012
|
//#region src/core/options.d.ts
|
|
600
|
-
/**
|
|
1013
|
+
/** Логгер библиотеки. Совместим с `console`. */
|
|
601
1014
|
interface Logger {
|
|
602
1015
|
debug(message: string, ...args: unknown[]): void;
|
|
603
1016
|
info(message: string, ...args: unknown[]): void;
|
|
@@ -629,6 +1042,8 @@ interface RetryDecisionContext {
|
|
|
629
1042
|
interface RateLimitBucketOverride {
|
|
630
1043
|
/** Одновременных запросов внутри бакета. */
|
|
631
1044
|
concurrency?: number | undefined;
|
|
1045
|
+
/** Верхняя граница стартов внутри бакета в секунду. */
|
|
1046
|
+
rps?: number | undefined;
|
|
632
1047
|
/** Ёмкость бакета до первого ответа, запросов в минуту. */
|
|
633
1048
|
limit?: number | undefined;
|
|
634
1049
|
}
|
|
@@ -649,8 +1064,8 @@ interface RateLimitOptions {
|
|
|
649
1064
|
*
|
|
650
1065
|
* `false` — одна очередь на направление: её пауза придерживает все запросы разом.
|
|
651
1066
|
* В этом режиме ёмкость отдельного счётчика неизвестна, поэтому `bucketConcurrency`,
|
|
652
|
-
* `bucketOverrides` и режим `pacing: 'smooth'` не действуют, а исчерпанный
|
|
653
|
-
* встречается первой ступенью `retryDelays`.
|
|
1067
|
+
* все поля `bucketOverrides` и режим `pacing: 'smooth'` не действуют, а исчерпанный
|
|
1068
|
+
* остаток встречается первой ступенью `retryDelays`. Общий `rps` продолжает действовать.
|
|
654
1069
|
*/
|
|
655
1070
|
buckets?: boolean | undefined;
|
|
656
1071
|
/**
|
|
@@ -664,7 +1079,7 @@ interface RateLimitOptions {
|
|
|
664
1079
|
*
|
|
665
1080
|
* @example
|
|
666
1081
|
* ```ts
|
|
667
|
-
* rateLimit: { bucketOverrides: { 'posts.create': {
|
|
1082
|
+
* rateLimit: { bucketOverrides: { 'posts.create': { rps: 2 }, feed: { concurrency: 2 } } }
|
|
668
1083
|
* ```
|
|
669
1084
|
*/
|
|
670
1085
|
bucketOverrides?: Record<string, RateLimitBucketOverride> | undefined;
|
|
@@ -718,7 +1133,7 @@ interface RetryContext extends RequestContext {
|
|
|
718
1133
|
delay: number;
|
|
719
1134
|
}
|
|
720
1135
|
/**
|
|
721
|
-
*
|
|
1136
|
+
* Хуки запроса.
|
|
722
1137
|
*
|
|
723
1138
|
* Вызываются последовательно; исключение внутри хука прервёт запрос, поэтому свою логику
|
|
724
1139
|
* лучше оборачивать в `try`.
|
|
@@ -736,8 +1151,8 @@ interface ClientHooks {
|
|
|
736
1151
|
/**
|
|
737
1152
|
* Настройки исполнения запросов: куда ходить, как долго ждать и чем представляться.
|
|
738
1153
|
*
|
|
739
|
-
* Всё, что нужно generic-ядру и ничего сверх того. Авторизация и сессия описаны
|
|
740
|
-
*
|
|
1154
|
+
* Всё, что нужно generic-ядру и ничего сверх того. Авторизация и сессия описаны отдельно,
|
|
1155
|
+
* а полный набор опций клиента их объединяет.
|
|
741
1156
|
*
|
|
742
1157
|
* Все поля допускают явный `undefined`, чтобы можно было передавать значения, которых
|
|
743
1158
|
* может не быть, — например `new ItdClient({ timeout: process.env.TIMEOUT })`.
|
|
@@ -775,919 +1190,336 @@ interface RuntimeOptions {
|
|
|
775
1190
|
/**
|
|
776
1191
|
* Сколько `close()` и `dispose()` ждут чужой код, мс. По умолчанию 10000.
|
|
777
1192
|
*
|
|
778
|
-
* Ждут обработчиков
|
|
779
|
-
* срока ресурсы всё равно освобождаются, а метод отклоняется `ItdStateError` с указанием
|
|
780
|
-
* того, что удерживало остановку. `0` снимает ограничение.
|
|
781
|
-
*/
|
|
782
|
-
shutdownTimeout?: number | undefined;
|
|
783
|
-
/** Повторные попытки. `false` отключает их полностью. */
|
|
784
|
-
retry?: RetryOptions | false | undefined;
|
|
785
|
-
/** Ограничение нагрузки. `false` отключает очередь. */
|
|
786
|
-
rateLimit?: RateLimitOptions | false | undefined;
|
|
787
|
-
/** Своя реализация `fetch`: для Deno, React Native, тестов или прокси. */
|
|
788
|
-
fetch?: typeof fetch | undefined;
|
|
789
|
-
/** Часы для тайм-аутов, повторов и очередей. Обычно подменяются только в тестах. */
|
|
790
|
-
clock?: ItdClock | undefined;
|
|
791
|
-
/** Как обращаться с cookie. По умолчанию определяется по среде исполнения. */
|
|
792
|
-
mode?: RuntimeMode | undefined;
|
|
793
|
-
/** Заголовки, добавляемые ко всем запросам, — например `User-Agent` для бота. */
|
|
794
|
-
headers?: Record<string, string> | undefined;
|
|
795
|
-
/**
|
|
796
|
-
* Значение заголовка `User-Agent`. `false` — не отправлять его вовсе.
|
|
797
|
-
*
|
|
798
|
-
* По умолчанию `Mozilla/5.0 (compatible; itd-api/<версия>; …)`: `fetch` в Node не шлёт
|
|
799
|
-
* `User-Agent` сам, а сайт стоит за DDoS-Guard, который такие запросы может не пропустить.
|
|
800
|
-
* В браузере опция не действует — там заголовок менять запрещено.
|
|
801
|
-
*/
|
|
802
|
-
userAgent?: string | false | undefined;
|
|
803
|
-
/**
|
|
804
|
-
hooks?: ClientHooks | undefined;
|
|
805
|
-
/**
|
|
806
|
-
logger?: Logger | boolean | undefined;
|
|
807
|
-
}
|
|
808
|
-
/**
|
|
809
|
-
* Namespaces расширений отдельной операции.
|
|
810
|
-
*
|
|
811
|
-
* Пакеты дополняют интерфейс через declaration merging и владеют только своим полем.
|
|
812
|
-
* Core передаёт объект operation transformers без знания его содержимого.
|
|
813
|
-
*/
|
|
814
|
-
interface RequestExtensions {}
|
|
815
|
-
/** Опции выполнения отдельного запроса. Передаются последним аргументом методов ресурсов. */
|
|
816
|
-
interface RequestOptions {
|
|
817
|
-
/** Отмена запроса извне. */
|
|
818
|
-
signal?: AbortSignal | undefined;
|
|
819
|
-
/** Таймаут только для этого запроса, мс. */
|
|
820
|
-
timeout?: number | undefined;
|
|
821
|
-
/** Дополнительные заголовки. */
|
|
822
|
-
headers?: Record<string, string> | undefined;
|
|
823
|
-
/** Повторы только для этого запроса. Переопределяют глобальную настройку `retry`. */
|
|
824
|
-
retry?: RetryOptions | false | undefined;
|
|
825
|
-
/**
|
|
826
|
-
* Явно переопределяет безопасность повтора операции.
|
|
827
|
-
*
|
|
828
|
-
* Встроенные resources получают значение из каталога. Опция нужна прежде всего custom/raw
|
|
829
|
-
* интеграциям и осознанному переопределению серверного контракта.
|
|
830
|
-
*/
|
|
831
|
-
retrySafety?: RetrySafety | undefined;
|
|
832
|
-
/**
|
|
833
|
-
* Имя бакета, из которого списывается запрос.
|
|
834
|
-
*
|
|
835
|
-
* Встроенные resources берут его из каталога операций; низкоуровневый вызов без этой
|
|
836
|
-
* опции попадает в `default`.
|
|
837
|
-
*
|
|
838
|
-
* Имя сверяется со встроенной картой — незнакомое отвергается {@link ItdConfigError}
|
|
839
|
-
* до отправки, независимо от того, включена ли очередь. Своё правило `rateLimit.bucket`
|
|
840
|
-
* заводит собственное пространство имён и проверку снимает.
|
|
841
|
-
*/
|
|
842
|
-
rateLimitBucket?: string | undefined;
|
|
843
|
-
/** Настройки подключённых operation extensions, сгруппированные по владельцу. */
|
|
844
|
-
extensions?: RequestExtensions | undefined;
|
|
845
|
-
}
|
|
846
|
-
/** Опции перебора страниц, не являющиеся параметрами endpoint. */
|
|
847
|
-
interface PaginationOptions extends RequestOptions {
|
|
848
|
-
/** Максимальное число страниц; без значения перебор продолжается до конца списка. */
|
|
849
|
-
maxPages?: number | undefined;
|
|
850
|
-
}
|
|
851
|
-
/** Полное описание запроса для низкоуровневого `itd.request()`. */
|
|
852
|
-
interface RawRequestOptions extends RequestOptions {
|
|
853
|
-
/**
|
|
854
|
-
* Семантическое имя низкоуровневого запроса. Встроенные resources выставляют его сами.
|
|
855
|
-
* Пользовательские значения следует помещать в namespace `custom:`.
|
|
856
|
-
*/
|
|
857
|
-
operationId?: OperationId | undefined;
|
|
858
|
-
method: string;
|
|
859
|
-
/** Путь с ведущим слэшем, например `/api/posts`. Завершающий слэш значим. */
|
|
860
|
-
path: string;
|
|
861
|
-
/**
|
|
862
|
-
* Имя сервиса, на хост которого уйдёт запрос. Без него запрос идёт на основной `baseUrl`
|
|
863
|
-
* клиента. Сервисы задаются опцией {@link RuntimeOptions.services}.
|
|
864
|
-
*/
|
|
865
|
-
service?: string | undefined;
|
|
866
|
-
/**
|
|
867
|
-
* Хост этого запроса. Важнее, чем {@link RawRequestOptions.service}.
|
|
868
|
-
*
|
|
869
|
-
* На посторонний основному API хост Bearer-токен по умолчанию не отправляется.
|
|
870
|
-
* Для осознанного разрешения укажите `skipAuth: false`.
|
|
871
|
-
*/
|
|
872
|
-
baseUrl?: string | undefined;
|
|
873
|
-
query?: QueryParams | undefined;
|
|
874
|
-
/** Тело: будет отправлено как JSON. Для загрузки файлов передайте `FormData`. */
|
|
875
|
-
body?: unknown;
|
|
876
|
-
/**
|
|
877
|
-
* Не подставлять заголовок авторизации.
|
|
878
|
-
*
|
|
879
|
-
* Явное `false` разрешает авторизацию и для разового внешнего `baseUrl`; без него
|
|
880
|
-
* токен автоматически отправляется только основному хосту и его поддоменам.
|
|
881
|
-
*/
|
|
882
|
-
skipAuth?: boolean | undefined;
|
|
883
|
-
/** Не пытаться обновить токен при `401` — используется самими эндпоинтами авторизации. */
|
|
884
|
-
skipAuthRefresh?: boolean | undefined;
|
|
885
|
-
/**
|
|
886
|
-
* Выполнить запрос мимо очереди.
|
|
887
|
-
*
|
|
888
|
-
* Продвинутый escape hatch для служебных интеграций. Встроенные refresh и sign-in проходят
|
|
889
|
-
* обычную очередь: она охватывает только одну сетевую попытку и не создаёт deadlock.
|
|
890
|
-
*/
|
|
891
|
-
skipQueue?: boolean | undefined;
|
|
892
|
-
/** Вернуть тело ответа без снятия обёртки `{ data: … }`. */
|
|
893
|
-
raw?: boolean | undefined;
|
|
894
|
-
}
|
|
895
|
-
/** Запрос внутри pipeline: в отличие от raw input всегда имеет семантический ID. */
|
|
896
|
-
interface OperationRequestOptions extends RawRequestOptions {
|
|
897
|
-
operationId: OperationId;
|
|
898
|
-
}
|
|
899
|
-
//#endregion
|
|
900
|
-
//#region src/core/emitter.d.ts
|
|
901
|
-
/** Обработчик события. */
|
|
902
|
-
type Listener<T> = (payload: T) => void;
|
|
903
|
-
/** Функция отписки, которую возвращает подписка на событие. */
|
|
904
|
-
type Unsubscribe = () => void;
|
|
905
|
-
/**
|
|
906
|
-
* Минимальный типизированный источник событий.
|
|
907
|
-
*
|
|
908
|
-
* Своя реализация вместо `EventTarget` и `EventEmitter`: первый есть не везде и требует
|
|
909
|
-
* обёрток `CustomEvent`, второй существует только в Node. Нужны ровно подписка и рассылка.
|
|
910
|
-
*
|
|
911
|
-
* Исключение в обработчике не прерывает рассылку остальным и не роняет библиотеку.
|
|
912
|
-
*
|
|
913
|
-
* @typeParam Events карта «имя события → тип полезной нагрузки». Задаётся интерфейсом,
|
|
914
|
-
* поэтому ограничение на индексную сигнатуру намеренно не накладывается.
|
|
915
|
-
*/
|
|
916
|
-
declare class Emitter<Events> {
|
|
917
|
-
#private;
|
|
918
|
-
constructor(onListenerError?: (error: unknown) => void);
|
|
919
|
-
/**
|
|
920
|
-
* Подписывается на событие.
|
|
921
|
-
*
|
|
922
|
-
* @returns функция отписки
|
|
923
|
-
*
|
|
924
|
-
* @example
|
|
925
|
-
* ```ts
|
|
926
|
-
* const off = realtime.on('notification', (event) => console.log(event));
|
|
927
|
-
* off();
|
|
928
|
-
* ```
|
|
929
|
-
*/
|
|
930
|
-
on<K extends keyof Events>(event: K, listener: Listener<Events[K]>): Unsubscribe;
|
|
931
|
-
/** Подписывается на одно срабатывание. */
|
|
932
|
-
once<K extends keyof Events>(event: K, listener: Listener<Events[K]>): Unsubscribe;
|
|
933
|
-
/** Отписывается от события. */
|
|
934
|
-
off<K extends keyof Events>(event: K, listener: Listener<Events[K]>): void;
|
|
935
|
-
/** Рассылает событие подписчикам. */
|
|
936
|
-
emit<K extends keyof Events>(event: K, payload: Events[K]): void;
|
|
937
|
-
/** Сколько подписчиков у события. */
|
|
938
|
-
listenerCount(event: keyof Events): number;
|
|
939
|
-
/** Снимает все подписки. */
|
|
940
|
-
removeAllListeners(): void;
|
|
941
|
-
}
|
|
942
|
-
//#endregion
|
|
943
|
-
//#region src/types/enums.d.ts
|
|
944
|
-
/**
|
|
945
|
-
* Перечисления API итд.com.
|
|
946
|
-
*
|
|
947
|
-
* Здесь намеренно не используется `enum` из TypeScript. Вместо него — пара «замороженный
|
|
948
|
-
* объект + одноимённый тип». Такой приём даёт всё, ради чего берут `enum`
|
|
949
|
-
* (`FeedTab.Popular`, перебор значений в рантайме), и при этом:
|
|
950
|
-
*
|
|
951
|
-
* - **стирается без остатка** — `enum` порождает рантайм-код и отвергается средами,
|
|
952
|
-
* которые просто срезают типы (`node --experimental-strip-types`);
|
|
953
|
-
* - **не запрещает обычные строки** — `itd.posts.list({ tab: 'popular' })` остаётся валидным,
|
|
954
|
-
* тогда как строковый `enum` считает это ошибкой типа и вынуждает всех импортировать себя;
|
|
955
|
-
* - **позволяет открытые множества** — там, где документация перечисляет значения не полностью,
|
|
956
|
-
* тип расширяется через {@link Loose}, а объект остаётся справочником известных значений.
|
|
957
|
-
*
|
|
958
|
-
* @example
|
|
959
|
-
* ```ts
|
|
960
|
-
* import { FeedTab } from 'itd-api';
|
|
961
|
-
*
|
|
962
|
-
* await itd.posts.list({ tab: FeedTab.Popular }); // без магических строк
|
|
963
|
-
* await itd.posts.list({ tab: 'popular' }); // и так тоже можно
|
|
964
|
-
*
|
|
965
|
-
* Object.values(FeedTab); // ['popular', 'following', 'clan']
|
|
966
|
-
* ```
|
|
967
|
-
*
|
|
968
|
-
* @packageDocumentation
|
|
969
|
-
*/
|
|
970
|
-
/**
|
|
971
|
-
* Открытое строковое перечисление.
|
|
972
|
-
*
|
|
973
|
-
* Даёт автодополнение известных значений, но не ломается, если сервер пришлёт новое.
|
|
974
|
-
* Используется там, где документация API перечисляет значения не полностью («`everyone` и др.»).
|
|
975
|
-
*/
|
|
976
|
-
type Loose<T extends string> = T | (string & {});
|
|
977
|
-
/**
|
|
978
|
-
* Вкладка ленты `GET /api/posts`.
|
|
979
|
-
*
|
|
980
|
-
* Множество закрытое: неизвестное значение сервер отвергнет.
|
|
981
|
-
*/
|
|
982
|
-
declare const FeedTab: Readonly<{
|
|
983
|
-
/** Популярное. Курсор здесь — номер страницы в виде строки (`"2"`, `"6"`…). */
|
|
984
|
-
readonly Popular: "popular";
|
|
985
|
-
/** Записи тех, на кого вы подписаны. Курсор — отметка времени последнего поста. */
|
|
986
|
-
readonly Following: "following";
|
|
987
|
-
/** Лента клана. Курсор, как и в подписках, — отметка времени. */
|
|
988
|
-
readonly Clan: "clan";
|
|
989
|
-
}>;
|
|
990
|
-
type FeedTab = (typeof FeedTab)[keyof typeof FeedTab];
|
|
991
|
-
/** Порядок комментариев к посту. */
|
|
992
|
-
declare const CommentSort: Readonly<{
|
|
993
|
-
/** Сначала новые. */
|
|
994
|
-
readonly Newest: "newest";
|
|
995
|
-
/** Сначала старые. */
|
|
996
|
-
readonly Oldest: "oldest";
|
|
997
|
-
/** Сначала популярные. */
|
|
998
|
-
readonly Popular: "popular";
|
|
999
|
-
}>;
|
|
1000
|
-
type CommentSort = (typeof CommentSort)[keyof typeof CommentSort];
|
|
1001
|
-
/** Тип вложения. */
|
|
1002
|
-
declare const AttachmentType: Readonly<{
|
|
1003
|
-
readonly Image: "image";
|
|
1004
|
-
readonly Video: "video";
|
|
1005
|
-
/** Голосовые комментарии: `audio/ogg`, с полем `duration`. */
|
|
1006
|
-
readonly Audio: "audio";
|
|
1007
|
-
}>;
|
|
1008
|
-
type AttachmentType = (typeof AttachmentType)[keyof typeof AttachmentType];
|
|
1009
|
-
/**
|
|
1010
|
-
* Тип фрагмента разметки в тексте поста или комментария.
|
|
1011
|
-
*
|
|
1012
|
-
* Первые два сервер расставляет сам при разборе текста, остальные приходят от редактора.
|
|
1013
|
-
* Тип открытый: набор может пополниться.
|
|
1014
|
-
*
|
|
1015
|
-
* @example
|
|
1016
|
-
* ```ts
|
|
1017
|
-
* await itd.posts.update(postId, {
|
|
1018
|
-
* content: 'жирное слово',
|
|
1019
|
-
* spans: [{ type: SpanType.Bold, offset: 0, length: 6 }],
|
|
1020
|
-
* });
|
|
1021
|
-
* ```
|
|
1022
|
-
*/
|
|
1023
|
-
declare const SpanType: Readonly<{
|
|
1024
|
-
/** Хэштег. Название без решётки лежит в `tag`. */
|
|
1025
|
-
readonly Hashtag: "hashtag";
|
|
1026
|
-
/** Упоминание. Имя пользователя лежит в `tag`. */
|
|
1027
|
-
readonly Mention: "mention";
|
|
1028
|
-
/** Ссылка. Адрес лежит в `url`, а не в `tag`. */
|
|
1029
|
-
readonly Link: "link";
|
|
1030
|
-
readonly Bold: "bold";
|
|
1031
|
-
readonly Italic: "italic";
|
|
1032
|
-
readonly Underline: "underline";
|
|
1033
|
-
/** Зачёркнутый. */
|
|
1034
|
-
readonly Strike: "strike";
|
|
1035
|
-
/** Спойлер: текст скрыт до нажатия. */
|
|
1036
|
-
readonly Spoiler: "spoiler";
|
|
1037
|
-
/** Моноширинный. */
|
|
1038
|
-
readonly Monospace: "monospace";
|
|
1039
|
-
readonly Quote: "quote";
|
|
1040
|
-
}>;
|
|
1041
|
-
type SpanType = Loose<(typeof SpanType)[keyof typeof SpanType]>;
|
|
1042
|
-
/** На что подаётся жалоба. */
|
|
1043
|
-
declare const ReportTargetType: Readonly<{
|
|
1044
|
-
readonly Post: "post";
|
|
1045
|
-
readonly Comment: "comment";
|
|
1046
|
-
readonly User: "user";
|
|
1047
|
-
}>;
|
|
1048
|
-
type ReportTargetType = (typeof ReportTargetType)[keyof typeof ReportTargetType];
|
|
1049
|
-
/** Причина жалобы. Множество закрытое. */
|
|
1050
|
-
declare const ReportReason: Readonly<{
|
|
1051
|
-
readonly Spam: "spam";
|
|
1052
|
-
readonly Violence: "violence";
|
|
1053
|
-
readonly Hate: "hate";
|
|
1054
|
-
readonly Adult: "adult";
|
|
1055
|
-
readonly Fraud: "fraud";
|
|
1056
|
-
readonly Other: "other";
|
|
1057
|
-
}>;
|
|
1058
|
-
type ReportReason = (typeof ReportReason)[keyof typeof ReportReason];
|
|
1059
|
-
/** Состояние realtime-соединения. */
|
|
1060
|
-
declare const RealtimeStatus: Readonly<{
|
|
1061
|
-
readonly Connecting: "connecting";
|
|
1062
|
-
readonly Connected: "connected";
|
|
1063
|
-
readonly Error: "error";
|
|
1064
|
-
readonly Disconnected: "disconnected";
|
|
1065
|
-
}>;
|
|
1066
|
-
type RealtimeStatus = (typeof RealtimeStatus)[keyof typeof RealtimeStatus];
|
|
1067
|
-
/** Состояние сервиса платформы. Тип открытый. */
|
|
1068
|
-
declare const ServiceState: Readonly<{
|
|
1069
|
-
/** Работает штатно. */
|
|
1070
|
-
readonly Operational: "operational";
|
|
1071
|
-
/** Работает с деградацией. */
|
|
1072
|
-
readonly Degraded: "degraded";
|
|
1073
|
-
/** Недоступен. */
|
|
1074
|
-
readonly Downtime: "downtime";
|
|
1075
|
-
}>;
|
|
1076
|
-
type ServiceState = Loose<(typeof ServiceState)[keyof typeof ServiceState]>;
|
|
1077
|
-
/** Вид происшествия в истории сервиса. Тип открытый. */
|
|
1078
|
-
declare const IncidentKind: Readonly<{
|
|
1079
|
-
/** Недоступен. */
|
|
1080
|
-
readonly Down: "down";
|
|
1081
|
-
/** Деградация. */
|
|
1082
|
-
readonly Degraded: "deg";
|
|
1083
|
-
}>;
|
|
1084
|
-
type IncidentKind = Loose<(typeof IncidentKind)[keyof typeof IncidentKind]>;
|
|
1085
|
-
/**
|
|
1086
|
-
* Уровень доступа к разделу профиля.
|
|
1087
|
-
*
|
|
1088
|
-
* Общий набор значений для полей `wallAccess` и `likesVisibility` настроек приватности.
|
|
1089
|
-
* Тип открытый: сервер может прислать значение вне этого перечня.
|
|
1090
|
-
*/
|
|
1091
|
-
declare const AccessType: Readonly<{
|
|
1092
|
-
/** Никто. */
|
|
1093
|
-
readonly Nobody: "nobody";
|
|
1094
|
-
/** Только взаимные подписки. */
|
|
1095
|
-
readonly Mutual: "mutual";
|
|
1096
|
-
/** Подписчики. */
|
|
1097
|
-
readonly Followers: "followers";
|
|
1098
|
-
/** Все. */
|
|
1099
|
-
readonly Everyone: "everyone";
|
|
1100
|
-
}>;
|
|
1101
|
-
type AccessType = Loose<(typeof AccessType)[keyof typeof AccessType]>;
|
|
1102
|
-
/** Кто может писать на стену профиля. Псевдоним {@link AccessType}. */
|
|
1103
|
-
declare const WallAccess: Readonly<{
|
|
1104
|
-
/** Никто. */
|
|
1105
|
-
readonly Nobody: "nobody";
|
|
1106
|
-
/** Только взаимные подписки. */
|
|
1107
|
-
readonly Mutual: "mutual";
|
|
1108
|
-
/** Подписчики. */
|
|
1109
|
-
readonly Followers: "followers";
|
|
1110
|
-
/** Все. */
|
|
1111
|
-
readonly Everyone: "everyone";
|
|
1112
|
-
}>;
|
|
1113
|
-
type WallAccess = AccessType;
|
|
1114
|
-
/** Кто видит реакции пользователя. Псевдоним {@link AccessType}. */
|
|
1115
|
-
declare const LikesVisibility: Readonly<{
|
|
1116
|
-
/** Никто. */
|
|
1117
|
-
readonly Nobody: "nobody";
|
|
1118
|
-
/** Только взаимные подписки. */
|
|
1119
|
-
readonly Mutual: "mutual";
|
|
1120
|
-
/** Подписчики. */
|
|
1121
|
-
readonly Followers: "followers";
|
|
1122
|
-
/** Все. */
|
|
1123
|
-
readonly Everyone: "everyone";
|
|
1124
|
-
}>;
|
|
1125
|
-
type LikesVisibility = AccessType;
|
|
1126
|
-
/**
|
|
1127
|
-
* Канонический тип уведомления (новое поколение имён).
|
|
1128
|
-
*
|
|
1129
|
-
* REST-эндпоинт `/api/notifications/` отдаёт старые имена (`like`, `comment`, `reply`,
|
|
1130
|
-
* `repost`, `mention`), SSE-поток — новые. Библиотека приводит их к этому набору,
|
|
1131
|
-
* сохраняя исходное значение в поле `rawType`.
|
|
1132
|
-
*/
|
|
1133
|
-
declare const NotificationType: Readonly<{
|
|
1134
|
-
/** Реакция на пост. Старое имя — `like`. */
|
|
1135
|
-
readonly PostReaction: "post_reaction";
|
|
1136
|
-
/** Комментарий к посту. Старое имя — `comment`. */
|
|
1137
|
-
readonly PostComment: "post_comment";
|
|
1138
|
-
/** Ответ на комментарий. Старое имя — `reply`. */
|
|
1139
|
-
readonly CommentReply: "comment_reply";
|
|
1140
|
-
/** Репост. Старое имя — `repost`. */
|
|
1141
|
-
readonly PostRepost: "post_repost";
|
|
1142
|
-
/** Упоминание в посте. Старое имя — `mention`. */
|
|
1143
|
-
readonly PostMention: "post_mention";
|
|
1144
|
-
/** Реакция на комментарий. */
|
|
1145
|
-
readonly CommentReaction: "comment_reaction";
|
|
1146
|
-
/** Упоминание в комментарии. */
|
|
1147
|
-
readonly CommentMention: "comment_mention";
|
|
1148
|
-
/** Запись на вашей стене. */
|
|
1149
|
-
readonly WallPost: "wall_post";
|
|
1150
|
-
/** На вас подписались. */
|
|
1151
|
-
readonly Follow: "follow";
|
|
1152
|
-
/** Заявка на подписку (закрытый профиль). */
|
|
1153
|
-
readonly FollowRequest: "follow_request";
|
|
1154
|
-
/** Заявка на подписку принята. */
|
|
1155
|
-
readonly FollowAccepted: "follow_accepted";
|
|
1156
|
-
/** Верификация одобрена. Приходит только по REST. */
|
|
1157
|
-
readonly VerificationApproved: "verification_approved";
|
|
1158
|
-
/** Верификация отклонена. Приходит только по REST. */
|
|
1159
|
-
readonly VerificationRejected: "verification_rejected";
|
|
1160
|
-
}>;
|
|
1161
|
-
type NotificationType = Loose<(typeof NotificationType)[keyof typeof NotificationType]>;
|
|
1162
|
-
/**
|
|
1163
|
-
* Тип взаимодействия с контентом в телеметрии (`POST /api/v1/x`, поле `t`).
|
|
1164
|
-
*
|
|
1165
|
-
* Кодируется числом.
|
|
1166
|
-
*/
|
|
1167
|
-
declare const InteractionType: Readonly<{
|
|
1168
|
-
/** Открытие фотографии. */
|
|
1169
|
-
readonly PhotoOpen: 1;
|
|
1170
|
-
/** Прогресс просмотра видео. Несёт поля `pm`/`dm`. */
|
|
1171
|
-
readonly VideoProgress: 2;
|
|
1172
|
-
}>;
|
|
1173
|
-
type InteractionType = (typeof InteractionType)[keyof typeof InteractionType];
|
|
1174
|
-
/**
|
|
1175
|
-
* Источник показа поста в телеметрии (поле `s`).
|
|
1176
|
-
*
|
|
1177
|
-
* Кодируется числом. Поле применимо к источникам `PostPage` и `Link`; для лент источник
|
|
1178
|
-
* передаётся контекстом `sc`.
|
|
1179
|
-
*/
|
|
1180
|
-
declare const ViewSource: Readonly<{
|
|
1181
|
-
readonly FeedGlobal: 1;
|
|
1182
|
-
readonly FeedFollowing: 2;
|
|
1183
|
-
readonly FeedClan: 3;
|
|
1184
|
-
readonly Profile: 4;
|
|
1185
|
-
readonly Hashtag: 5;
|
|
1186
|
-
readonly PostPage: 6;
|
|
1187
|
-
readonly Link: 7;
|
|
1188
|
-
readonly Search: 8;
|
|
1189
|
-
}>;
|
|
1190
|
-
type ViewSource = (typeof ViewSource)[keyof typeof ViewSource];
|
|
1191
|
-
/**
|
|
1192
|
-
* Причина завершения просмотра поста в телеметрии (`POST /api/v1/i`, поле `r`).
|
|
1193
|
-
*
|
|
1194
|
-
* Кодируется числом.
|
|
1195
|
-
*/
|
|
1196
|
-
declare const ViewReason: Readonly<{
|
|
1197
|
-
/** Пост ушёл из зоны видимости при обычной прокрутке. */
|
|
1198
|
-
readonly Normal: 0;
|
|
1199
|
-
/** Потеря фокуса окна. */
|
|
1200
|
-
readonly Blur: 1;
|
|
1201
|
-
/** Вкладка скрыта. */
|
|
1202
|
-
readonly Hidden: 2;
|
|
1203
|
-
/** Уход со страницы (`pagehide`). */
|
|
1204
|
-
readonly PageHide: 3;
|
|
1205
|
-
/** Элемент перестал наблюдаться. */
|
|
1206
|
-
readonly Unobserve: 4;
|
|
1207
|
-
/** Достигнут порог времени просмотра. */
|
|
1208
|
-
readonly ThresholdMet: 5;
|
|
1209
|
-
}>;
|
|
1210
|
-
type ViewReason = (typeof ViewReason)[keyof typeof ViewReason];
|
|
1211
|
-
/**
|
|
1212
|
-
* Строковые коды ошибок из поля `code`.
|
|
1213
|
-
*
|
|
1214
|
-
* Ключи намеренно повторяют написание сервера: код из ответа API можно найти здесь
|
|
1215
|
-
* поиском один в один, без мысленного перевода регистра.
|
|
1216
|
-
*
|
|
1217
|
-
* Список открыт — сервер может добавить новый код, и это не должно ломать типизацию.
|
|
1218
|
-
*
|
|
1219
|
-
* @example
|
|
1220
|
-
* ```ts
|
|
1221
|
-
* if (err.hasCode(ItdErrorCode.OTP_INVALID)) await restartOtpFlow();
|
|
1222
|
-
* ```
|
|
1223
|
-
*/
|
|
1224
|
-
declare const ItdErrorCode: Readonly<{
|
|
1225
|
-
readonly BAD_REQUEST: "BAD_REQUEST";
|
|
1226
|
-
readonly UNAUTHORIZED: "UNAUTHORIZED";
|
|
1227
|
-
readonly ACCESS_DENIED: "ACCESS_DENIED";
|
|
1228
|
-
readonly ENTITY_NOT_FOUND: "ENTITY_NOT_FOUND";
|
|
1229
|
-
readonly ENTITY_ALREADY_EXISTS: "ENTITY_ALREADY_EXISTS";
|
|
1230
|
-
readonly VALIDATION_ERROR: "VALIDATION_ERROR";
|
|
1231
|
-
readonly BUSINESS_RULE_VIOLATION: "BUSINESS_RULE_VIOLATION";
|
|
1232
|
-
readonly RATE_LIMIT_EXCEEDED: "RATE_LIMIT_EXCEEDED";
|
|
1233
|
-
readonly UNKNOWN_ERROR: "UNKNOWN_ERROR";
|
|
1234
|
-
/** Сервер отвечает так на `404`, `ENTITY_NOT_FOUND` в этом случае не приходит. */
|
|
1235
|
-
readonly NOT_FOUND: "NOT_FOUND";
|
|
1236
|
-
/** На практике не приходит: вместо него сервер шлёт `TURNSTILE_VERIFICATION_FAILED`. */
|
|
1237
|
-
readonly CAPTCHA_FAILED: "CAPTCHA_FAILED";
|
|
1238
|
-
/** Капча не пройдена: токен Turnstile недействителен, просрочен или уже использован. */
|
|
1239
|
-
readonly TURNSTILE_VERIFICATION_FAILED: "TURNSTILE_VERIFICATION_FAILED";
|
|
1240
|
-
readonly OTP_INVALID: "OTP_INVALID";
|
|
1241
|
-
/** `flowToken` неизвестен или просрочен — поток подтверждения нужно начинать заново. */
|
|
1242
|
-
readonly INVALID_FLOW_TOKEN: "INVALID_FLOW_TOKEN";
|
|
1243
|
-
readonly ACCOUNT_DEACTIVATED: "ACCOUNT_DEACTIVATED";
|
|
1244
|
-
readonly ACCOUNT_EMAIL_DOMAIN_NOT_ALLOWED: "ACCOUNT_EMAIL_DOMAIN_NOT_ALLOWED";
|
|
1245
|
-
readonly ACCOUNT_INVALID_CREDENTIALS: "ACCOUNT_INVALID_CREDENTIALS";
|
|
1246
|
-
readonly ACCOUNT_TEMPORARILY_LOCKED: "ACCOUNT_TEMPORARILY_LOCKED";
|
|
1247
|
-
readonly ACCOUNT_CURRENT_PASSWORD_INCORRECT: "ACCOUNT_CURRENT_PASSWORD_INCORRECT";
|
|
1248
|
-
readonly SESSION_EXPIRED: "SESSION_EXPIRED";
|
|
1249
|
-
readonly SESSION_REVOKED: "SESSION_REVOKED";
|
|
1250
|
-
readonly SESSION_INVALID_REFRESH_TOKEN: "SESSION_INVALID_REFRESH_TOKEN";
|
|
1251
|
-
/** Запрос обновления пришёл без cookie `refresh_token` — продлевать нечего. */
|
|
1252
|
-
readonly REFRESH_TOKEN_MISSING: "REFRESH_TOKEN_MISSING";
|
|
1253
|
-
/** Cookie `refresh_token` есть, но сессии за ней уже нет: отозвана или истекла. */
|
|
1254
|
-
readonly SESSION_NOT_FOUND: "SESSION_NOT_FOUND";
|
|
1255
|
-
readonly MISSING_FLOW_TOKEN: "MISSING_FLOW_TOKEN";
|
|
1256
|
-
readonly PROFILE_USERNAME_TAKEN: "PROFILE_USERNAME_TAKEN";
|
|
1257
|
-
readonly PROFILE_RESTRICTION_ACTIVE: "PROFILE_RESTRICTION_ACTIVE";
|
|
1258
|
-
readonly PROFILE_MODIFICATION_RESTRICTED: "PROFILE_MODIFICATION_RESTRICTED";
|
|
1259
|
-
readonly CONTENT_MODERATION_FAILED: "CONTENT_MODERATION_FAILED";
|
|
1260
|
-
readonly FILE_TOO_LARGE: "FILE_TOO_LARGE";
|
|
1261
|
-
readonly UNSUPPORTED_FILE_TYPE: "UNSUPPORTED_FILE_TYPE";
|
|
1262
|
-
readonly UPLOAD_FAILED: "UPLOAD_FAILED";
|
|
1263
|
-
readonly VIDEO_REQUIRES_VERIFICATION: "VIDEO_REQUIRES_VERIFICATION";
|
|
1264
|
-
readonly PHONE_VERIFICATION_REQUIRED: "PHONE_VERIFICATION_REQUIRED";
|
|
1265
|
-
readonly WRITE_ACCESS_RESTRICTED: "WRITE_ACCESS_RESTRICTED";
|
|
1266
|
-
}>;
|
|
1267
|
-
type ItdErrorCode = Loose<(typeof ItdErrorCode)[keyof typeof ItdErrorCode]>;
|
|
1268
|
-
//#endregion
|
|
1269
|
-
//#region src/models/common.d.ts
|
|
1270
|
-
/**
|
|
1271
|
-
* Дата и время в формате ISO-8601, например `2026-07-21T14:30:00.000Z`.
|
|
1272
|
-
*
|
|
1273
|
-
* Библиотека не превращает такие поля в `Date`: строку проще сравнивать, логировать
|
|
1274
|
-
* и передавать дальше без потерь. Для разбора есть `toDate()`.
|
|
1275
|
-
*/
|
|
1276
|
-
type IsoDate = string;
|
|
1277
|
-
/**
|
|
1278
|
-
* Идентификатор пользователя — **строго UUID**.
|
|
1279
|
-
*
|
|
1280
|
-
* Отличается от {@link UserRef} тем, что имя пользователя здесь не подойдёт. Так помечены
|
|
1281
|
-
* места, где API принимает только UUID: например `wallRecipientId` при постинге на чужую стену.
|
|
1282
|
-
*/
|
|
1283
|
-
type UserId = string;
|
|
1284
|
-
/**
|
|
1285
|
-
* Ссылка на пользователя: **UUID либо имя пользователя**.
|
|
1286
|
-
*
|
|
1287
|
-
* Пути вида `/api/users/{id}` принимают оба варианта, поэтому `itd.users.get('nowkie')`
|
|
1288
|
-
* работает так же, как `itd.users.get('9f1c…')`.
|
|
1289
|
-
*/
|
|
1290
|
-
type UserRef = string;
|
|
1291
|
-
/**
|
|
1292
|
-
* Разметка в тексте поста или комментария.
|
|
1293
|
-
*
|
|
1294
|
-
* `offset` и `length` измеряются в UTF-16 code units: это те же индексы, которые используют
|
|
1295
|
-
* `String#slice`, `substring` и DOM Selection в JavaScript. Эмодзи вне BMP обычно занимают
|
|
1296
|
-
* две единицы.
|
|
1297
|
-
*/
|
|
1298
|
-
interface Span {
|
|
1299
|
-
/** Тип фрагмента — см. {@link SpanType}. */
|
|
1300
|
-
type: SpanType;
|
|
1301
|
-
/** Смещение от начала текста. */
|
|
1302
|
-
offset: number;
|
|
1303
|
-
/** Длина фрагмента. */
|
|
1304
|
-
length: number;
|
|
1305
|
-
/** Имя хэштега без решётки. У старых mention-объектов может содержать username. */
|
|
1306
|
-
tag?: string;
|
|
1307
|
-
/** Адрес ссылки. Только у `link`: у него вместо `tag` отдельное поле. */
|
|
1308
|
-
url?: string;
|
|
1309
|
-
/** Имя пользователя у `mention`. */
|
|
1310
|
-
username?: string;
|
|
1311
|
-
/** Идентификатор пользователя у некоторых ответов API с `mention`. */
|
|
1312
|
-
id?: string;
|
|
1313
|
-
}
|
|
1314
|
-
//#endregion
|
|
1315
|
-
//#region src/core/version.d.ts
|
|
1316
|
-
/** Версия библиотеки. Попадает в `User-Agent`. */
|
|
1317
|
-
declare const LIBRARY_VERSION = "0.7.2";
|
|
1318
|
-
//#endregion
|
|
1319
|
-
//#region src/core/config.d.ts
|
|
1320
|
-
/** Базовый URL API итд.com. Домен записан в punycode: `итд.com`. */
|
|
1321
|
-
declare const DEFAULT_BASE_URL = "https://xn--d1ah4a.com";
|
|
1322
|
-
/** Имя встроенного сервиса статуса. */
|
|
1323
|
-
declare const STATUS_SERVICE = "status";
|
|
1324
|
-
//#endregion
|
|
1325
|
-
//#region src/core/auth-provider.d.ts
|
|
1326
|
-
/** Области аккаунта и конкретной сессии для локального состояния плагинов. */
|
|
1327
|
-
interface AuthIdentity {
|
|
1328
|
-
/** Идентификатор пользователя; отсутствует у непрозрачного или повреждённого токена. */
|
|
1329
|
-
userId?: UserId | undefined;
|
|
1330
|
-
/** Идентификатор серверной сессии; отсутствует у непрозрачного или повреждённого токена. */
|
|
1331
|
-
sessionId?: string | undefined;
|
|
1193
|
+
* Ждут обработчиков событийного канала и операций, вошедших в обёртки плагинов. По истечении
|
|
1194
|
+
* срока ресурсы всё равно освобождаются, а метод отклоняется `ItdStateError` с указанием
|
|
1195
|
+
* того, что удерживало остановку. `0` снимает ограничение.
|
|
1196
|
+
*/
|
|
1197
|
+
shutdownTimeout?: number | undefined;
|
|
1198
|
+
/** Повторные попытки. `false` отключает их полностью. */
|
|
1199
|
+
retry?: RetryOptions | false | undefined;
|
|
1200
|
+
/** Ограничение нагрузки. `false` отключает очередь. */
|
|
1201
|
+
rateLimit?: RateLimitOptions | false | undefined;
|
|
1202
|
+
/** Своя реализация `fetch`: для Deno, React Native, тестов или прокси. */
|
|
1203
|
+
fetch?: typeof fetch | undefined;
|
|
1204
|
+
/** Часы для тайм-аутов, повторов и очередей. Обычно подменяются только в тестах. */
|
|
1205
|
+
clock?: ItdClock | undefined;
|
|
1206
|
+
/** Как обращаться с cookie. По умолчанию определяется по среде исполнения. */
|
|
1207
|
+
mode?: RuntimeMode | undefined;
|
|
1208
|
+
/** Заголовки, добавляемые ко всем запросам, — например `User-Agent` для бота. */
|
|
1209
|
+
headers?: Record<string, string> | undefined;
|
|
1210
|
+
/**
|
|
1211
|
+
* Значение заголовка `User-Agent`. `false` — не отправлять его вовсе.
|
|
1212
|
+
*
|
|
1213
|
+
* По умолчанию `Mozilla/5.0 (compatible; itd-api/<версия>; …)`: `fetch` в Node не шлёт
|
|
1214
|
+
* `User-Agent` сам, а сайт стоит за DDoS-Guard, который такие запросы может не пропустить.
|
|
1215
|
+
* В браузере опция не действует — там заголовок менять запрещено.
|
|
1216
|
+
*/
|
|
1217
|
+
userAgent?: string | false | undefined;
|
|
1218
|
+
/** Хуки запросов. */
|
|
1219
|
+
hooks?: ClientHooks | undefined;
|
|
1220
|
+
/** Логгер. `true` — использовать `console`. */
|
|
1221
|
+
logger?: Logger | boolean | undefined;
|
|
1332
1222
|
}
|
|
1333
1223
|
/**
|
|
1334
|
-
*
|
|
1335
|
-
*
|
|
1336
|
-
* Узкий контракт вместо полноценного менеджера сессии: pipeline не должен знать ни про
|
|
1337
|
-
* refresh-токены, ни про хранилище, ни про вход по паролю. Благодаря этому клиент с готовым
|
|
1338
|
-
* токеном не тянет за собой сессионную машинерию — она подставляется вызывающим кодом.
|
|
1224
|
+
* Настройки плагинов для отдельной операции.
|
|
1339
1225
|
*
|
|
1340
|
-
*
|
|
1341
|
-
* {@link bearerToken}, {@link tokenProvider} и {@link anonymousAuth}.
|
|
1226
|
+
* Пакеты дополняют интерфейс и используют отдельные именованные поля.
|
|
1342
1227
|
*/
|
|
1343
|
-
interface
|
|
1228
|
+
interface RequestExtensions {}
|
|
1229
|
+
/** Опции выполнения отдельного запроса. Передаются последним аргументом методов ресурсов. */
|
|
1230
|
+
interface RequestOptions {
|
|
1231
|
+
/** Отмена запроса извне. */
|
|
1232
|
+
signal?: AbortSignal | undefined;
|
|
1233
|
+
/** Таймаут только для этого запроса, мс. */
|
|
1234
|
+
timeout?: number | undefined;
|
|
1235
|
+
/** Дополнительные заголовки. */
|
|
1236
|
+
headers?: Record<string, string> | undefined;
|
|
1237
|
+
/** Повторы только для этого запроса. Переопределяют глобальную настройку `retry`. */
|
|
1238
|
+
retry?: RetryOptions | false | undefined;
|
|
1344
1239
|
/**
|
|
1345
|
-
*
|
|
1240
|
+
* Явно переопределяет безопасность повтора операции.
|
|
1346
1241
|
*
|
|
1347
|
-
*
|
|
1348
|
-
*
|
|
1242
|
+
* Встроенные ресурсы получают значение из каталога. Опция предназначена для произвольных
|
|
1243
|
+
* запросов.
|
|
1349
1244
|
*/
|
|
1350
|
-
|
|
1245
|
+
retrySafety?: RetrySafety | undefined;
|
|
1351
1246
|
/**
|
|
1352
|
-
*
|
|
1247
|
+
* Имя бакета, из которого списывается запрос.
|
|
1353
1248
|
*
|
|
1354
|
-
*
|
|
1355
|
-
*
|
|
1249
|
+
* Встроенные ресурсы берут его из каталога операций; низкоуровневый вызов без этой
|
|
1250
|
+
* опции попадает в `default`.
|
|
1251
|
+
*
|
|
1252
|
+
* Имя сверяется со встроенной картой — незнакомое отвергается {@link ItdConfigError}
|
|
1253
|
+
* до отправки, независимо от того, включена ли очередь. Своё правило `rateLimit.bucket`
|
|
1254
|
+
* заводит собственное пространство имён и проверку снимает.
|
|
1356
1255
|
*/
|
|
1357
|
-
|
|
1256
|
+
rateLimitBucket?: string | undefined;
|
|
1257
|
+
/** Настройки подключённых плагинов. */
|
|
1258
|
+
extensions?: RequestExtensions | undefined;
|
|
1259
|
+
}
|
|
1260
|
+
/** Опции перебора страниц, не являющиеся параметрами метода API. */
|
|
1261
|
+
interface PaginationOptions extends RequestOptions {
|
|
1262
|
+
/** Максимальное число страниц; без значения перебор продолжается до конца списка. */
|
|
1263
|
+
maxPages?: number | undefined;
|
|
1264
|
+
}
|
|
1265
|
+
/** Полное описание запроса для низкоуровневого `itd.request()`. */
|
|
1266
|
+
interface RawRequestOptions extends RequestOptions {
|
|
1358
1267
|
/**
|
|
1359
|
-
*
|
|
1268
|
+
* Имя низкоуровневого запроса. Встроенные ресурсы задают его сами.
|
|
1269
|
+
* Пользовательские значения должны начинаться с `custom:`.
|
|
1270
|
+
*/
|
|
1271
|
+
operationId?: OperationId | undefined;
|
|
1272
|
+
method: string;
|
|
1273
|
+
/** Путь с ведущим слэшем, например `/api/posts`. Завершающий слэш значим. */
|
|
1274
|
+
path: string;
|
|
1275
|
+
/**
|
|
1276
|
+
* Имя сервиса, на хост которого уйдёт запрос. Без него запрос идёт на основной `baseUrl`
|
|
1277
|
+
* клиента. Сервисы задаются опцией {@link RuntimeOptions.services}.
|
|
1278
|
+
*/
|
|
1279
|
+
service?: string | undefined;
|
|
1280
|
+
/**
|
|
1281
|
+
* Хост этого запроса. Важнее, чем {@link RawRequestOptions.service}.
|
|
1360
1282
|
*
|
|
1361
|
-
*
|
|
1362
|
-
*
|
|
1283
|
+
* На посторонний основному API хост Bearer-токен по умолчанию не отправляется.
|
|
1284
|
+
* Для осознанного разрешения укажите `skipAuth: false`.
|
|
1363
1285
|
*/
|
|
1364
|
-
|
|
1286
|
+
baseUrl?: string | undefined;
|
|
1287
|
+
query?: QueryParams | undefined;
|
|
1288
|
+
/** Тело: будет отправлено как JSON. Для загрузки файлов передайте `FormData`. */
|
|
1289
|
+
body?: unknown;
|
|
1365
1290
|
/**
|
|
1366
|
-
*
|
|
1291
|
+
* Не подставлять заголовок авторизации.
|
|
1367
1292
|
*
|
|
1368
|
-
*
|
|
1293
|
+
* Явное `false` разрешает авторизацию и для разового внешнего `baseUrl`; без него
|
|
1294
|
+
* токен автоматически отправляется только основному хосту и его поддоменам.
|
|
1369
1295
|
*/
|
|
1370
|
-
|
|
1371
|
-
/**
|
|
1372
|
-
|
|
1373
|
-
/** Снимает подписки при терминальном освобождении владельца. */
|
|
1374
|
-
dispose(): void;
|
|
1375
|
-
}
|
|
1376
|
-
/**
|
|
1377
|
-
* Авторизации нет: заголовок не подставляется, ответ `401` не восстанавливается.
|
|
1378
|
-
*
|
|
1379
|
-
* @example
|
|
1380
|
-
* ```ts
|
|
1381
|
-
* const api = createRestClient(); // публичные эндпоинты доступны и без токена
|
|
1382
|
-
* ```
|
|
1383
|
-
*/
|
|
1384
|
-
declare function anonymousAuth(): AuthProvider;
|
|
1385
|
-
/**
|
|
1386
|
-
* Готовый Bearer-токен: ни хранилища, ни продления.
|
|
1387
|
-
*
|
|
1388
|
-
* Ответ `401` уходит вызывающему коду как есть — обновить токен провайдеру нечем.
|
|
1389
|
-
* Для сессии, которая продлевает себя сама, нужен полный клиент.
|
|
1390
|
-
*
|
|
1391
|
-
* @example
|
|
1392
|
-
* ```ts
|
|
1393
|
-
* const api = createRestClient({ auth: bearerToken(process.env.ITD_TOKEN) });
|
|
1394
|
-
* ```
|
|
1395
|
-
*/
|
|
1396
|
-
declare function bearerToken(accessToken: string): AuthProvider;
|
|
1397
|
-
/**
|
|
1398
|
-
* Токен из внешнего источника — хранилища секретов, кэша, соседнего сервиса.
|
|
1399
|
-
*
|
|
1400
|
-
* Источник спрашивается на стадии подготовки, до входа в очередь: там ожидание безопасно,
|
|
1401
|
-
* а слот транспорта ещё не занят. Значение держится до следующей подготовки, потому что
|
|
1402
|
-
* подстановка заголовков обязана быть синхронной.
|
|
1403
|
-
*
|
|
1404
|
-
* @example
|
|
1405
|
-
* ```ts
|
|
1406
|
-
* const api = createRestClient({ auth: tokenProvider(() => vault.read('itd')) });
|
|
1407
|
-
* ```
|
|
1408
|
-
*/
|
|
1409
|
-
declare function tokenProvider(getToken: () => string | null | Promise<string | null>): AuthProvider;
|
|
1410
|
-
//#endregion
|
|
1411
|
-
//#region src/models/users.d.ts
|
|
1412
|
-
/** Значок-«пин» в профиле — награда или отметка платформы. */
|
|
1413
|
-
interface Pin {
|
|
1414
|
-
/** Постоянный идентификатор, например `epepuy_202605_59`. */
|
|
1415
|
-
slug: string;
|
|
1416
|
-
/** Отображаемое название. */
|
|
1417
|
-
name: string;
|
|
1418
|
-
/** Описание, за что выдан. */
|
|
1419
|
-
description: string;
|
|
1420
|
-
/** Адрес изображения. */
|
|
1421
|
-
url: string;
|
|
1422
|
-
/** Когда выдан. Приходит только в списке своих пинов. */
|
|
1423
|
-
grantedAt?: IsoDate;
|
|
1424
|
-
}
|
|
1425
|
-
/**
|
|
1426
|
-
* Автор поста или комментария.
|
|
1427
|
-
*
|
|
1428
|
-
* Встречается внутри `post.author` и `comment.author`.
|
|
1429
|
-
*/
|
|
1430
|
-
interface Author {
|
|
1431
|
-
id: UserId;
|
|
1432
|
-
username: string;
|
|
1433
|
-
displayName: string;
|
|
1296
|
+
skipAuth?: boolean | undefined;
|
|
1297
|
+
/** Не пытаться обновить токен при `401` — используется самими эндпоинтами авторизации. */
|
|
1298
|
+
skipAuthRefresh?: boolean | undefined;
|
|
1434
1299
|
/**
|
|
1435
|
-
*
|
|
1300
|
+
* Выполнить запрос мимо очереди.
|
|
1436
1301
|
*
|
|
1437
|
-
*
|
|
1438
|
-
* Отрисовывать его нужно как текст.
|
|
1302
|
+
* Служебная настройка для интеграций. Встроенные вход и обновление токена проходят очередь.
|
|
1439
1303
|
*/
|
|
1440
|
-
|
|
1441
|
-
/**
|
|
1442
|
-
|
|
1443
|
-
/** Активный значок профиля. Может отсутствовать. */
|
|
1444
|
-
pin?: Pin | null;
|
|
1445
|
-
/** Есть ли премиум-подписка (значок NUKSTA). */
|
|
1446
|
-
hasNuksta?: boolean;
|
|
1447
|
-
}
|
|
1448
|
-
/**
|
|
1449
|
-
* Участник события в уведомлении.
|
|
1450
|
-
*
|
|
1451
|
-
* Отличается от {@link Author} набором полей: вместо значков приходит связь с вами.
|
|
1452
|
-
*/
|
|
1453
|
-
interface Actor {
|
|
1454
|
-
id: UserId;
|
|
1455
|
-
username: string;
|
|
1456
|
-
displayName: string;
|
|
1457
|
-
/** Эмодзи-аватар, см. {@link Author.avatar}. */
|
|
1458
|
-
avatar: string;
|
|
1459
|
-
/** Подписаны ли вы на этого пользователя. */
|
|
1460
|
-
isFollowing?: boolean;
|
|
1461
|
-
/** Подписан ли он на вас. */
|
|
1462
|
-
isFollowedBy?: boolean;
|
|
1463
|
-
}
|
|
1464
|
-
/**
|
|
1465
|
-
* Пользователь в списках.
|
|
1466
|
-
*
|
|
1467
|
-
* Набор полей зависит от эндпоинта: подписчики и подписки приносят `isFollowing`,
|
|
1468
|
-
* поиск и рекомендации — `followersCount` и `hasNuksta`. Необязательные поля отражают
|
|
1469
|
-
* это различие.
|
|
1470
|
-
*/
|
|
1471
|
-
interface UserSummary {
|
|
1472
|
-
id: UserId;
|
|
1473
|
-
username: string;
|
|
1474
|
-
displayName: string;
|
|
1475
|
-
/** Эмодзи-аватар, см. {@link Author.avatar}. */
|
|
1476
|
-
avatar: string;
|
|
1477
|
-
verified: boolean;
|
|
1478
|
-
/** Подписаны ли вы. Приходит в списках подписчиков и подписок. */
|
|
1479
|
-
isFollowing?: boolean;
|
|
1480
|
-
/** Есть ли премиум. Приходит в поиске и рекомендациях. */
|
|
1481
|
-
hasNuksta?: boolean;
|
|
1482
|
-
/** Число подписчиков. Приходит в поиске и рекомендациях. */
|
|
1483
|
-
followersCount?: number;
|
|
1484
|
-
}
|
|
1485
|
-
/** Поля профиля, общие для своего и чужого. */
|
|
1486
|
-
interface ProfileBase {
|
|
1487
|
-
id: UserId;
|
|
1488
|
-
username: string;
|
|
1489
|
-
displayName: string;
|
|
1490
|
-
/** Эмодзи-аватар, см. {@link Author.avatar}. */
|
|
1491
|
-
avatar: string;
|
|
1492
|
-
/** URL изображения баннера либо `null`. */
|
|
1493
|
-
banner: string | null;
|
|
1494
|
-
/** Описание профиля. */
|
|
1495
|
-
bio: string;
|
|
1496
|
-
verified: boolean;
|
|
1497
|
-
pin?: Pin | null;
|
|
1498
|
-
/** Кто может писать на стену. */
|
|
1499
|
-
wallAccess: WallAccess;
|
|
1500
|
-
/** Кто видит реакции. */
|
|
1501
|
-
likesVisibility: LikesVisibility;
|
|
1502
|
-
followersCount: number;
|
|
1503
|
-
followingCount: number;
|
|
1504
|
-
postsCount: number;
|
|
1505
|
-
createdAt: IsoDate;
|
|
1506
|
-
}
|
|
1507
|
-
/** Состояние подписки на премиум. */
|
|
1508
|
-
interface SubscriptionState {
|
|
1509
|
-
isActive: boolean;
|
|
1510
|
-
expiresAt: IsoDate | null;
|
|
1511
|
-
autoRenewal: boolean;
|
|
1512
|
-
}
|
|
1513
|
-
/**
|
|
1514
|
-
* Свой профиль — ответ `GET /api/users/me`.
|
|
1515
|
-
*
|
|
1516
|
-
* Отличается от чужого наличием {@link subscription} и {@link isPhoneVerified}
|
|
1517
|
-
* и отсутствием полей связи (`isFollowing`, `online`).
|
|
1518
|
-
*/
|
|
1519
|
-
interface MyProfile extends ProfileBase {
|
|
1520
|
-
/** Закрыт ли профиль. */
|
|
1521
|
-
isPrivate: boolean;
|
|
1522
|
-
/** Подтверждён ли телефон. Без него часть действий недоступна. */
|
|
1523
|
-
isPhoneVerified: boolean;
|
|
1524
|
-
/** Своя премиум-подписка. */
|
|
1525
|
-
subscription: SubscriptionState;
|
|
1304
|
+
skipQueue?: boolean | undefined;
|
|
1305
|
+
/** Вернуть тело ответа без снятия обёртки `{ data: … }`. */
|
|
1306
|
+
raw?: boolean | undefined;
|
|
1526
1307
|
}
|
|
1527
|
-
/**
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1308
|
+
/** Подготовленный запрос с обязательным идентификатором операции. */
|
|
1309
|
+
interface OperationRequestOptions extends RawRequestOptions {
|
|
1310
|
+
operationId: OperationId;
|
|
1311
|
+
}
|
|
1312
|
+
//#endregion
|
|
1313
|
+
//#region src/core/operation.d.ts
|
|
1314
|
+
/** HTTP-метод операции. */
|
|
1315
|
+
type OperationMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
|
|
1316
|
+
/** ID операции подключаемого модуля: `<featureName>.<operationName>`. */
|
|
1317
|
+
type FeatureOperationId<TFeatureName extends string = string, TOperationName extends string = string> = `${TFeatureName}.${TOperationName}`;
|
|
1318
|
+
/** Семантическая безопасность автоматического повтора операции. */
|
|
1319
|
+
declare const RetrySafety: Readonly<{
|
|
1320
|
+
/** Автоматический повтор не создаёт неприемлемого эффекта; обычно это чтение. */
|
|
1321
|
+
readonly Safe: "safe";
|
|
1322
|
+
/** Повтор операции приводит к тому же состоянию, что и один вызов. */
|
|
1323
|
+
readonly Idempotent: "idempotent";
|
|
1324
|
+
/** Повтор может создать ещё один побочный эффект. */
|
|
1325
|
+
readonly Unsafe: "unsafe";
|
|
1326
|
+
}>;
|
|
1327
|
+
type RetrySafety = (typeof RetrySafety)[keyof typeof RetrySafety];
|
|
1328
|
+
/** Расширяемые метаданные операции. Плагины добавляют собственные поля. */
|
|
1329
|
+
interface OperationAnnotations {}
|
|
1330
|
+
/** Публичные неизменяемые метаданные семантической операции. */
|
|
1331
|
+
interface OperationMetadata {
|
|
1332
|
+
readonly method: OperationMethod;
|
|
1333
|
+
readonly retrySafety: RetrySafety;
|
|
1334
|
+
readonly bucket?: string;
|
|
1335
|
+
readonly annotations?: Readonly<OperationAnnotations>;
|
|
1540
1336
|
}
|
|
1541
1337
|
/**
|
|
1542
|
-
*
|
|
1338
|
+
* Контракт результата одного HTTP-запроса.
|
|
1543
1339
|
*
|
|
1544
|
-
*
|
|
1340
|
+
* Функция чтения принадлежит исполнителю и не входит в API плагинов. Все вызовы одного `id`
|
|
1341
|
+
* используют один контракт, поэтому форма результата не зависит от места вызова.
|
|
1545
1342
|
*/
|
|
1546
|
-
interface
|
|
1547
|
-
|
|
1548
|
-
/**
|
|
1549
|
-
|
|
1550
|
-
/** Подписаны ли вы на него. */
|
|
1551
|
-
isFollowing: boolean;
|
|
1552
|
-
/** Подписан ли он на вас. */
|
|
1553
|
-
isFollowedBy: boolean;
|
|
1554
|
-
/** Сейчас ли пользователь в сети. */
|
|
1555
|
-
online: boolean;
|
|
1556
|
-
/** Когда был в сети. `null`, если скрыто настройками приватности. */
|
|
1557
|
-
lastSeen: IsoDate | null;
|
|
1558
|
-
}
|
|
1559
|
-
/** Профиль: свой либо чужой. Различаются функцией `isMyProfile()`. */
|
|
1560
|
-
type Profile = MyProfile | PublicProfile;
|
|
1561
|
-
/** Настройки приватности профиля. */
|
|
1562
|
-
interface PrivacySettings {
|
|
1563
|
-
/** Закрыт ли профиль: подписка требует одобрения. */
|
|
1564
|
-
isPrivate: boolean;
|
|
1565
|
-
wallAccess: WallAccess;
|
|
1566
|
-
likesVisibility: LikesVisibility;
|
|
1567
|
-
/** Показывать ли время последнего посещения. */
|
|
1568
|
-
showLastSeen: boolean;
|
|
1343
|
+
interface OperationContract<T = unknown, TId extends string = string> extends OperationMetadata {
|
|
1344
|
+
readonly id: TId;
|
|
1345
|
+
/** Преобразует разобранное тело HTTP-ответа в результат операции. @internal */
|
|
1346
|
+
readonly read: (body: unknown, request: Readonly<OperationRequestOptions>) => T;
|
|
1569
1347
|
}
|
|
1570
1348
|
/**
|
|
1571
|
-
*
|
|
1349
|
+
* Минимальное стабильное описание операции, доступное core и плагинам.
|
|
1572
1350
|
*
|
|
1573
|
-
*
|
|
1574
|
-
* ```ts
|
|
1575
|
-
* const result = await itd.users.follow('nowkie');
|
|
1576
|
-
* // { following: true, followersCount: 11 }
|
|
1577
|
-
* ```
|
|
1351
|
+
* Форма описания принадлежит ядру; заполненный ими каталог — доменному слою.
|
|
1578
1352
|
*/
|
|
1579
|
-
interface
|
|
1580
|
-
/**
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
/** Закреплённые значки профиля и выбранный из них. */
|
|
1588
|
-
interface PinsResult {
|
|
1589
|
-
pins: Pin[];
|
|
1590
|
-
/** Идентификатор активного значка — строка, а не объект. */
|
|
1591
|
-
activePin: string | null;
|
|
1353
|
+
interface OperationDefinition extends OperationMetadata {
|
|
1354
|
+
/**
|
|
1355
|
+
* Бакет операции. Опущено — операция списывает из бакета по умолчанию.
|
|
1356
|
+
*
|
|
1357
|
+
* Счётчик определяется парой «путь + метод»: `GET /api/users/me` — 40 запросов
|
|
1358
|
+
* в минуту, `PUT` того же пути — 3, `DELETE` — 150.
|
|
1359
|
+
*/
|
|
1360
|
+
readonly bucket?: string;
|
|
1592
1361
|
}
|
|
1593
1362
|
//#endregion
|
|
1594
|
-
//#region src/
|
|
1363
|
+
//#region src/core/version.d.ts
|
|
1364
|
+
/** Версия библиотеки. Попадает в `User-Agent`. */
|
|
1365
|
+
declare const LIBRARY_VERSION = "0.9.0";
|
|
1366
|
+
//#endregion
|
|
1367
|
+
//#region src/core/config.d.ts
|
|
1368
|
+
/** Базовый URL API итд.com. Домен записан в punycode: `итд.com`. */
|
|
1369
|
+
declare const DEFAULT_BASE_URL = "https://xn--d1ah4a.com";
|
|
1370
|
+
/** Имя встроенного сервиса статуса. */
|
|
1371
|
+
declare const STATUS_SERVICE = "status";
|
|
1372
|
+
//#endregion
|
|
1373
|
+
//#region src/core/emitter.d.ts
|
|
1374
|
+
/** Обработчик события. */
|
|
1375
|
+
type Listener<T> = (payload: T) => void;
|
|
1376
|
+
/** Функция отписки, которую возвращает подписка на событие. */
|
|
1377
|
+
type Unsubscribe = () => void;
|
|
1595
1378
|
/**
|
|
1596
|
-
*
|
|
1379
|
+
* Минимальный типизированный источник событий.
|
|
1597
1380
|
*
|
|
1598
|
-
*
|
|
1599
|
-
*
|
|
1600
|
-
* поэтому объекты из `itd.notifications.list()` и из потока можно складывать в один список.
|
|
1381
|
+
* Своя реализация вместо `EventTarget` и `EventEmitter`: первый есть не везде и требует
|
|
1382
|
+
* обёрток `CustomEvent`, второй существует только в Node. Нужны ровно подписка и рассылка.
|
|
1601
1383
|
*
|
|
1602
|
-
*
|
|
1603
|
-
*
|
|
1384
|
+
* Исключение в обработчике не прерывает рассылку остальным и не роняет библиотеку.
|
|
1385
|
+
*
|
|
1386
|
+
* @typeParam Events карта «имя события → тип полезной нагрузки». Задаётся интерфейсом,
|
|
1387
|
+
* поэтому ограничение на индексную сигнатуру намеренно не накладывается.
|
|
1604
1388
|
*/
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
/**
|
|
1627
|
-
|
|
1628
|
-
/**
|
|
1629
|
-
|
|
1389
|
+
declare class Emitter<Events> {
|
|
1390
|
+
#private;
|
|
1391
|
+
constructor(onListenerError?: (error: unknown) => void);
|
|
1392
|
+
/**
|
|
1393
|
+
* Подписывается на событие.
|
|
1394
|
+
*
|
|
1395
|
+
* @returns функция отписки
|
|
1396
|
+
*
|
|
1397
|
+
* @example
|
|
1398
|
+
* ```ts
|
|
1399
|
+
* const off = events.on('notification', (event) => console.log(event));
|
|
1400
|
+
* off();
|
|
1401
|
+
* ```
|
|
1402
|
+
*/
|
|
1403
|
+
on<K extends keyof Events>(event: K, listener: Listener<Events[K]>): Unsubscribe;
|
|
1404
|
+
/** Подписывается на одно срабатывание. */
|
|
1405
|
+
once<K extends keyof Events>(event: K, listener: Listener<Events[K]>): Unsubscribe;
|
|
1406
|
+
/** Отписывается от события. */
|
|
1407
|
+
off<K extends keyof Events>(event: K, listener: Listener<Events[K]>): void;
|
|
1408
|
+
/** Рассылает событие подписчикам. */
|
|
1409
|
+
emit<K extends keyof Events>(event: K, payload: Events[K]): void;
|
|
1410
|
+
/** Сколько подписчиков у события. */
|
|
1411
|
+
listenerCount(event: keyof Events): number;
|
|
1412
|
+
/** Снимает все подписки. */
|
|
1413
|
+
removeAllListeners(): void;
|
|
1414
|
+
}
|
|
1415
|
+
//#endregion
|
|
1416
|
+
//#region src/core/auth-provider.d.ts
|
|
1417
|
+
/** Области аккаунта и конкретной сессии для локального состояния плагинов. */
|
|
1418
|
+
interface AuthIdentity {
|
|
1419
|
+
/** Идентификатор пользователя; отсутствует у непрозрачного или повреждённого токена. */
|
|
1420
|
+
userId?: UserId | undefined;
|
|
1421
|
+
/** Идентификатор серверной сессии; отсутствует у непрозрачного или повреждённого токена. */
|
|
1422
|
+
sessionId?: string | undefined;
|
|
1630
1423
|
}
|
|
1631
1424
|
/**
|
|
1632
|
-
*
|
|
1425
|
+
* Что конвейер запросов спрашивает у авторизации.
|
|
1633
1426
|
*
|
|
1634
|
-
*
|
|
1635
|
-
*
|
|
1636
|
-
*
|
|
1427
|
+
* Узкий контракт вместо полноценного менеджера сессии: pipeline не должен знать ни про
|
|
1428
|
+
* refresh-токены, ни про хранилище, ни про вход по паролю. Благодаря этому клиент с готовым
|
|
1429
|
+
* токеном не тянет за собой сессионную машинерию — она подставляется вызывающим кодом.
|
|
1430
|
+
*
|
|
1431
|
+
* Каждый метод соответствует ровно одной стадии конвейера. Готовые реализации —
|
|
1432
|
+
* `bearerToken()`, `tokenProvider()` и `anonymousAuth()`.
|
|
1637
1433
|
*/
|
|
1638
|
-
interface
|
|
1639
|
-
/** Общий выключатель доставки. */
|
|
1640
|
-
enabled: boolean;
|
|
1641
|
-
/** Звук уведомления. */
|
|
1642
|
-
sound: boolean;
|
|
1643
|
-
/** Новые подписчики. */
|
|
1644
|
-
follows: boolean;
|
|
1645
|
-
/** Записи на вашей стене. */
|
|
1646
|
-
wallPosts: boolean;
|
|
1647
|
-
/** Реакции на ваши записи. */
|
|
1648
|
-
likes: boolean;
|
|
1649
|
-
/** Комментарии и ответы. */
|
|
1650
|
-
comments: boolean;
|
|
1651
|
-
/** Упоминания. */
|
|
1652
|
-
mentions: boolean;
|
|
1653
|
-
}
|
|
1654
|
-
//#endregion
|
|
1655
|
-
//#region src/notifications/normalize.d.ts
|
|
1656
|
-
/** Событие потока уведомлений после разбора. */
|
|
1657
|
-
interface NotificationEvent {
|
|
1658
|
-
/** Само уведомление в единой форме. */
|
|
1659
|
-
notification: Notification;
|
|
1434
|
+
interface AuthProvider {
|
|
1660
1435
|
/**
|
|
1661
|
-
*
|
|
1436
|
+
* Текущий токен доступа.
|
|
1662
1437
|
*
|
|
1663
|
-
*
|
|
1438
|
+
* Нужен там, где заголовок не поставить: SSE в браузере и WebSocket передают токен
|
|
1439
|
+
* параметром адреса. Конвейеру запросов достаточно {@link currentHeaders}.
|
|
1664
1440
|
*/
|
|
1665
|
-
|
|
1666
|
-
/**
|
|
1667
|
-
|
|
1441
|
+
token(): Promise<string | null>;
|
|
1442
|
+
/**
|
|
1443
|
+
* Готовит состояние авторизации до входа транспортной попытки в очередь.
|
|
1444
|
+
*
|
|
1445
|
+
* Чтение хранилища, обращение к внешнему источнику токена и отложенный вход асинхронны,
|
|
1446
|
+
* поэтому обязаны завершиться до захвата слота очереди.
|
|
1447
|
+
*/
|
|
1448
|
+
prepare(): Promise<void>;
|
|
1449
|
+
/**
|
|
1450
|
+
* Заголовки уже подготовленной авторизации.
|
|
1451
|
+
*
|
|
1452
|
+
* Синхронность существенна: слой стоит внутри очереди, непосредственно перед транспортом,
|
|
1453
|
+
* и не должен запускать I/O. Зато запрос, отстоявший в очереди, получает самый свежий токен.
|
|
1454
|
+
*/
|
|
1455
|
+
currentHeaders(): Record<string, string>;
|
|
1456
|
+
/**
|
|
1457
|
+
* Реакция на ответ `401`.
|
|
1458
|
+
*
|
|
1459
|
+
* @returns `true`, если токен обновлён и повторять попытку имеет смысл
|
|
1460
|
+
*/
|
|
1461
|
+
recover(): Promise<boolean>;
|
|
1462
|
+
/** Значение заголовка `X-Device-Id`. Отправляется и с анонимными запросами. */
|
|
1463
|
+
deviceId(): Promise<string>;
|
|
1464
|
+
/** Снимает подписки при терминальном освобождении владельца. */
|
|
1465
|
+
dispose(): void;
|
|
1668
1466
|
}
|
|
1669
1467
|
/**
|
|
1670
|
-
*
|
|
1468
|
+
* Авторизации нет: заголовок не подставляется, ответ `401` не восстанавливается.
|
|
1671
1469
|
*
|
|
1672
|
-
*
|
|
1673
|
-
*
|
|
1674
|
-
*
|
|
1675
|
-
*
|
|
1676
|
-
|
|
1470
|
+
* @example
|
|
1471
|
+
* ```ts
|
|
1472
|
+
* const api = createRestClient(); // публичные эндпоинты доступны и без токена
|
|
1473
|
+
* ```
|
|
1474
|
+
*/
|
|
1475
|
+
declare function anonymousAuth(): AuthProvider;
|
|
1476
|
+
/**
|
|
1477
|
+
* Готовый Bearer-токен: ни хранилища, ни продления.
|
|
1478
|
+
*
|
|
1479
|
+
* Ответ `401` уходит вызывающему коду как есть — обновить токен провайдеру нечем.
|
|
1480
|
+
* Для сессии, которая продлевает себя сама, нужен полный клиент.
|
|
1677
1481
|
*
|
|
1678
|
-
*
|
|
1679
|
-
*
|
|
1482
|
+
* @example
|
|
1483
|
+
* ```ts
|
|
1484
|
+
* const api = createRestClient({ auth: bearerToken(process.env.ITD_TOKEN) });
|
|
1485
|
+
* ```
|
|
1486
|
+
*/
|
|
1487
|
+
declare function bearerToken(accessToken: string): AuthProvider;
|
|
1488
|
+
/**
|
|
1489
|
+
* Токен из внешнего источника — хранилища секретов, кэша, соседнего сервиса.
|
|
1680
1490
|
*
|
|
1681
|
-
*
|
|
1491
|
+
* Источник спрашивается на стадии подготовки, до входа в очередь: там ожидание безопасно,
|
|
1492
|
+
* а слот транспорта ещё не занят. Значение держится до следующей подготовки, потому что
|
|
1493
|
+
* подстановка заголовков обязана быть синхронной.
|
|
1682
1494
|
*
|
|
1683
1495
|
* @example
|
|
1684
1496
|
* ```ts
|
|
1685
|
-
* const
|
|
1686
|
-
* const fromStream = normalizeNotification(event.payload);
|
|
1687
|
-
* // одинаковая форма — можно объединять
|
|
1497
|
+
* const api = createRestClient({ auth: tokenProvider(() => vault.read('itd')) });
|
|
1688
1498
|
* ```
|
|
1689
1499
|
*/
|
|
1690
|
-
declare function
|
|
1500
|
+
declare function tokenProvider(getToken: () => string | null | Promise<string | null>): AuthProvider;
|
|
1501
|
+
//#endregion
|
|
1502
|
+
//#region src/core/connection.d.ts
|
|
1503
|
+
/**
|
|
1504
|
+
* Разрешённое окружение одного долговременного соединения клиента.
|
|
1505
|
+
*
|
|
1506
|
+
* Синхронизационные запросы выполняются через адаптер предметного модуля.
|
|
1507
|
+
*/
|
|
1508
|
+
interface ClientConnection {
|
|
1509
|
+
/** Фактический HTTP(S)-адрес сервиса с учётом настроек клиента. */
|
|
1510
|
+
readonly baseUrl: string;
|
|
1511
|
+
/** Разрешено ли соединению передавать Bearer-токен этому сервису. */
|
|
1512
|
+
readonly authorize: boolean;
|
|
1513
|
+
readonly fetch: typeof fetch;
|
|
1514
|
+
readonly clock: ItdClock;
|
|
1515
|
+
readonly logger: Logger | undefined;
|
|
1516
|
+
/** Заголовки платформы и сервиса без Bearer-токена. */
|
|
1517
|
+
baseHeaders(url: string): Promise<Headers>;
|
|
1518
|
+
/** Текущий токен; способ его передачи выбирает транспорт. */
|
|
1519
|
+
getToken(): Promise<string | null>;
|
|
1520
|
+
/** Пытается восстановить авторизацию после отказа транспорта. */
|
|
1521
|
+
refreshAuth(): Promise<boolean>;
|
|
1522
|
+
}
|
|
1691
1523
|
//#endregion
|
|
1692
1524
|
//#region src/core/errors.d.ts
|
|
1693
1525
|
/** Бренд, по которому ошибки библиотеки распознаются надёжнее, чем через `instanceof`. */
|
|
@@ -1761,268 +1593,549 @@ declare class ItdError extends Error {
|
|
|
1761
1593
|
cause?: unknown;
|
|
1762
1594
|
});
|
|
1763
1595
|
}
|
|
1764
|
-
/** Параметры конструктора {@link ItdApiError}. */
|
|
1765
|
-
interface ItdApiErrorInit {
|
|
1766
|
-
/** HTTP-статус ответа. */
|
|
1767
|
-
status: number;
|
|
1768
|
-
/** Строковый код ошибки из тела ответа. */
|
|
1769
|
-
code: ItdErrorCode;
|
|
1770
|
-
/** Человекочитаемое сообщение. */
|
|
1771
|
-
message: string;
|
|
1772
|
-
/** Расширенное описание, если сервер его прислал. */
|
|
1773
|
-
detail?: string | undefined;
|
|
1774
|
-
/** Заголовок ошибки, если сервер его прислал. */
|
|
1775
|
-
title?: string | undefined;
|
|
1776
|
-
/** Ошибки по конкретным полям (сведены из `errors` и `violations`). */
|
|
1777
|
-
fieldErrors?: ItdFieldErrors | undefined;
|
|
1778
|
-
/** Идентификатор запроса из заголовков ответа, если есть. */
|
|
1779
|
-
requestId?: string | undefined;
|
|
1780
|
-
/** HTTP-метод запроса. */
|
|
1781
|
-
method: string;
|
|
1782
|
-
/** Путь запроса без базового URL. */
|
|
1783
|
-
path: string;
|
|
1784
|
-
/** Тело ответа как оно пришло — на случай, если документация разошлась с реальностью. */
|
|
1785
|
-
raw: unknown;
|
|
1786
|
-
/** Сам объект ответа. Тело уже прочитано. */
|
|
1787
|
-
response?: Response | undefined;
|
|
1788
|
-
/** Значение `Retry-After` в миллисекундах, если заголовок был. */
|
|
1789
|
-
retryAfter?: number | undefined;
|
|
1790
|
-
/** Сколько запросов разрешено в окне (`x-ratelimit-limit`). */
|
|
1791
|
-
rateLimit?: number | undefined;
|
|
1792
|
-
/** Сколько запросов осталось в окне (`x-ratelimit-remaining`). */
|
|
1793
|
-
rateLimitRemaining?: number | undefined;
|
|
1596
|
+
/** Параметры конструктора {@link ItdApiError}. */
|
|
1597
|
+
interface ItdApiErrorInit {
|
|
1598
|
+
/** HTTP-статус ответа. */
|
|
1599
|
+
status: number;
|
|
1600
|
+
/** Строковый код ошибки из тела ответа. */
|
|
1601
|
+
code: ItdErrorCode;
|
|
1602
|
+
/** Человекочитаемое сообщение. */
|
|
1603
|
+
message: string;
|
|
1604
|
+
/** Расширенное описание, если сервер его прислал. */
|
|
1605
|
+
detail?: string | undefined;
|
|
1606
|
+
/** Заголовок ошибки, если сервер его прислал. */
|
|
1607
|
+
title?: string | undefined;
|
|
1608
|
+
/** Ошибки по конкретным полям (сведены из `errors` и `violations`). */
|
|
1609
|
+
fieldErrors?: ItdFieldErrors | undefined;
|
|
1610
|
+
/** Идентификатор запроса из заголовков ответа, если есть. */
|
|
1611
|
+
requestId?: string | undefined;
|
|
1612
|
+
/** HTTP-метод запроса. */
|
|
1613
|
+
method: string;
|
|
1614
|
+
/** Путь запроса без базового URL. */
|
|
1615
|
+
path: string;
|
|
1616
|
+
/** Тело ответа как оно пришло — на случай, если документация разошлась с реальностью. */
|
|
1617
|
+
raw: unknown;
|
|
1618
|
+
/** Сам объект ответа. Тело уже прочитано. */
|
|
1619
|
+
response?: Response | undefined;
|
|
1620
|
+
/** Значение `Retry-After` в миллисекундах, если заголовок был. */
|
|
1621
|
+
retryAfter?: number | undefined;
|
|
1622
|
+
/** Сколько запросов разрешено в окне (`x-ratelimit-limit`). */
|
|
1623
|
+
rateLimit?: number | undefined;
|
|
1624
|
+
/** Сколько запросов осталось в окне (`x-ratelimit-remaining`). */
|
|
1625
|
+
rateLimitRemaining?: number | undefined;
|
|
1626
|
+
}
|
|
1627
|
+
/**
|
|
1628
|
+
* Ошибка, возвращённая сервером итд.com (HTTP-статус ≥ 400).
|
|
1629
|
+
*
|
|
1630
|
+
* API отдаёт ошибки в двух разных формах — `{ error: { … } }` и `{ code, message, violations }`.
|
|
1631
|
+
* Библиотека сводит обе к этому классу, поэтому разбирать форму ответа вручную не нужно.
|
|
1632
|
+
*
|
|
1633
|
+
* @example
|
|
1634
|
+
* ```ts
|
|
1635
|
+
* try {
|
|
1636
|
+
* await itd.users.updateMe({ username: 'занятое_имя' });
|
|
1637
|
+
* } catch (e) {
|
|
1638
|
+
* if (e instanceof ItdValidationError) {
|
|
1639
|
+
* console.log(e.fieldErrors.username); // ['Имя уже занято']
|
|
1640
|
+
* }
|
|
1641
|
+
* }
|
|
1642
|
+
* ```
|
|
1643
|
+
*/
|
|
1644
|
+
declare class ItdApiError extends ItdError {
|
|
1645
|
+
/**
|
|
1646
|
+
* Разновидность ошибки: та же информация, что и класс, но пригодная для сравнения.
|
|
1647
|
+
*
|
|
1648
|
+
* Позволяет разбирать ошибку через `switch`, а проверкам вроде {@link isItdAuthError} —
|
|
1649
|
+
* работать даже когда в проекте оказались две копии библиотеки.
|
|
1650
|
+
*/
|
|
1651
|
+
readonly apiKind: ItdApiErrorKind;
|
|
1652
|
+
/** HTTP-статус ответа. */
|
|
1653
|
+
readonly status: number;
|
|
1654
|
+
/** Строковый код ошибки, например `VALIDATION_ERROR`. */
|
|
1655
|
+
readonly code: ItdErrorCode;
|
|
1656
|
+
/** Расширенное описание, если сервер его прислал. */
|
|
1657
|
+
readonly detail: string | undefined;
|
|
1658
|
+
/** Заголовок ошибки, если сервер его прислал. */
|
|
1659
|
+
readonly title: string | undefined;
|
|
1660
|
+
/** Ошибки по полям. Пустой объект, если сервер их не прислал. */
|
|
1661
|
+
readonly fieldErrors: ItdFieldErrors;
|
|
1662
|
+
/** Идентификатор запроса из заголовков ответа. */
|
|
1663
|
+
readonly requestId: string | undefined;
|
|
1664
|
+
/** HTTP-метод запроса. */
|
|
1665
|
+
readonly method: string;
|
|
1666
|
+
/** Путь запроса без базового URL. */
|
|
1667
|
+
readonly path: string;
|
|
1668
|
+
/** Тело ответа как оно пришло. */
|
|
1669
|
+
readonly raw: unknown;
|
|
1670
|
+
/** Объект ответа. Тело уже прочитано и повторно прочитано быть не может. */
|
|
1671
|
+
readonly response: Response | undefined;
|
|
1672
|
+
/** Пауза из заголовка `Retry-After` в миллисекундах. Сервер итд.com его не присылает. */
|
|
1673
|
+
readonly retryAfter: number | undefined;
|
|
1674
|
+
/**
|
|
1675
|
+
* Сколько запросов разрешено в окне — заголовок `x-ratelimit-limit`.
|
|
1676
|
+
*
|
|
1677
|
+
* Времени сброса окна сервер не сообщает, поэтому точный момент повтора неизвестен.
|
|
1678
|
+
*/
|
|
1679
|
+
readonly rateLimit: number | undefined;
|
|
1680
|
+
/** Сколько запросов осталось в окне — заголовок `x-ratelimit-remaining`. */
|
|
1681
|
+
readonly rateLimitRemaining: number | undefined;
|
|
1682
|
+
/**
|
|
1683
|
+
* @param apiKind разновидность; подставляется подклассами, снаружи задавать не нужно
|
|
1684
|
+
*/
|
|
1685
|
+
constructor(init: ItdApiErrorInit, apiKind?: ItdApiErrorKind);
|
|
1686
|
+
/**
|
|
1687
|
+
* Проверяет код ошибки. Удобнее, чем сравнивать строки вручную.
|
|
1688
|
+
*
|
|
1689
|
+
* @example
|
|
1690
|
+
* ```ts
|
|
1691
|
+
* if (err.hasCode('OTP_INVALID', 'MISSING_FLOW_TOKEN')) await restartOtpFlow();
|
|
1692
|
+
* ```
|
|
1693
|
+
*/
|
|
1694
|
+
hasCode(...codes: ItdErrorCode[]): boolean;
|
|
1695
|
+
/** Имеет ли смысл повторить запрос: `429` и серверные ошибки `5xx`. */
|
|
1696
|
+
get isRetryable(): boolean;
|
|
1697
|
+
}
|
|
1698
|
+
/** `400` / `422` — данные не прошли валидацию. Подробности в {@link ItdApiError.fieldErrors}. */
|
|
1699
|
+
declare class ItdValidationError extends ItdApiError {
|
|
1700
|
+
constructor(init: ItdApiErrorInit);
|
|
1701
|
+
}
|
|
1702
|
+
/** `401` — токен отсутствует, истёк или отозван. */
|
|
1703
|
+
declare class ItdAuthError extends ItdApiError {
|
|
1704
|
+
constructor(init: ItdApiErrorInit);
|
|
1705
|
+
}
|
|
1706
|
+
/** `403` — доступ запрещён либо действие ограничено настройками приватности. */
|
|
1707
|
+
declare class ItdForbiddenError extends ItdApiError {
|
|
1708
|
+
constructor(init: ItdApiErrorInit);
|
|
1709
|
+
}
|
|
1710
|
+
/** `404` — сущность не найдена. */
|
|
1711
|
+
declare class ItdNotFoundError extends ItdApiError {
|
|
1712
|
+
constructor(init: ItdApiErrorInit);
|
|
1713
|
+
}
|
|
1714
|
+
/** `409` — сущность уже существует. */
|
|
1715
|
+
declare class ItdConflictError extends ItdApiError {
|
|
1716
|
+
constructor(init: ItdApiErrorInit);
|
|
1717
|
+
}
|
|
1718
|
+
/**
|
|
1719
|
+
* `429` — превышен лимит запросов.
|
|
1720
|
+
*
|
|
1721
|
+
* Если сервер прислал `Retry-After`, пауза доступна в {@link ItdApiError.retryAfter}
|
|
1722
|
+
* (в миллисекундах). При включённых ретраях библиотека выдерживает её автоматически.
|
|
1723
|
+
*/
|
|
1724
|
+
declare class ItdRateLimitError extends ItdApiError {
|
|
1725
|
+
constructor(init: ItdApiErrorInit);
|
|
1726
|
+
}
|
|
1727
|
+
/**
|
|
1728
|
+
* Действие требует подтверждённого телефона (`PHONE_VERIFICATION_REQUIRED`).
|
|
1729
|
+
*
|
|
1730
|
+
* Подтверждение проходит через Telegram-бота: ссылка лежит в {@link verificationUrl}.
|
|
1731
|
+
*/
|
|
1732
|
+
declare class ItdPhoneVerificationError extends ItdApiError {
|
|
1733
|
+
/** Ссылка на бота подтверждения, если удалось определить идентификатор пользователя. */
|
|
1734
|
+
readonly verificationUrl: string | undefined;
|
|
1735
|
+
constructor(init: ItdApiErrorInit & {
|
|
1736
|
+
userId?: string | undefined;
|
|
1737
|
+
});
|
|
1738
|
+
}
|
|
1739
|
+
/** `5xx` — ошибка на стороне сервера. */
|
|
1740
|
+
declare class ItdServerError extends ItdApiError {
|
|
1741
|
+
constructor(init: ItdApiErrorInit);
|
|
1742
|
+
}
|
|
1743
|
+
/** Причина ошибки получения вложения. */
|
|
1744
|
+
declare const ItdFileErrorReason: Readonly<{
|
|
1745
|
+
/** Сетевой сбой при получении источника. */
|
|
1746
|
+
readonly Network: "network";
|
|
1747
|
+
/** Источник ответил ошибочным HTTP-статусом. */
|
|
1748
|
+
readonly Http: "http";
|
|
1749
|
+
/** Источник превысил разрешённый размер. */
|
|
1750
|
+
readonly TooLarge: "too_large";
|
|
1751
|
+
/** Среда или источник не предоставили поток. */
|
|
1752
|
+
readonly StreamUnavailable: "stream_unavailable";
|
|
1753
|
+
/** Поток источника завершился ошибкой. */
|
|
1754
|
+
readonly Read: "read";
|
|
1755
|
+
}>;
|
|
1756
|
+
type ItdFileErrorReason = (typeof ItdFileErrorReason)[keyof typeof ItdFileErrorReason];
|
|
1757
|
+
/** Не удалось получить или прочитать содержимое вложения. */
|
|
1758
|
+
declare class ItdFileError extends ItdError {
|
|
1759
|
+
readonly reason: ItdFileErrorReason;
|
|
1760
|
+
/** Адрес источника без секретных параметров запроса, если файл получался по сети. */
|
|
1761
|
+
readonly url: string | undefined;
|
|
1762
|
+
/** HTTP-статус источника. */
|
|
1763
|
+
readonly status: number | undefined;
|
|
1764
|
+
/** Разрешённый размер в байтах. */
|
|
1765
|
+
readonly limit: number | undefined;
|
|
1766
|
+
/** Обнаруженный размер в байтах. */
|
|
1767
|
+
readonly actual: number | undefined;
|
|
1768
|
+
/** Имеет ли смысл повторить получение источника. */
|
|
1769
|
+
readonly retryable: boolean;
|
|
1770
|
+
constructor(message: string, init: {
|
|
1771
|
+
reason: ItdFileErrorReason;
|
|
1772
|
+
url?: string | undefined;
|
|
1773
|
+
status?: number | undefined;
|
|
1774
|
+
limit?: number | undefined;
|
|
1775
|
+
actual?: number | undefined;
|
|
1776
|
+
retryable?: boolean | undefined;
|
|
1777
|
+
cause?: unknown;
|
|
1778
|
+
});
|
|
1779
|
+
}
|
|
1780
|
+
/** Запрос не дошёл до сервера: DNS, обрыв соединения, отсутствие сети. */
|
|
1781
|
+
declare class ItdNetworkError extends ItdError {
|
|
1782
|
+
/** HTTP-метод запроса. */
|
|
1783
|
+
readonly method: string;
|
|
1784
|
+
/** Путь запроса без базового URL. */
|
|
1785
|
+
readonly path: string;
|
|
1786
|
+
constructor(message: string, init: {
|
|
1787
|
+
method: string;
|
|
1788
|
+
path: string;
|
|
1789
|
+
cause?: unknown;
|
|
1790
|
+
});
|
|
1791
|
+
}
|
|
1792
|
+
/** Истёк таймаут запроса, заданный опцией `timeout`. */
|
|
1793
|
+
declare class ItdTimeoutError extends ItdError {
|
|
1794
|
+
/** Значение таймаута в миллисекундах. */
|
|
1795
|
+
readonly timeout: number;
|
|
1796
|
+
/** HTTP-метод запроса. */
|
|
1797
|
+
readonly method: string;
|
|
1798
|
+
/** Путь запроса без базового URL. */
|
|
1799
|
+
readonly path: string;
|
|
1800
|
+
constructor(init: {
|
|
1801
|
+
timeout: number;
|
|
1802
|
+
method: string;
|
|
1803
|
+
path: string;
|
|
1804
|
+
});
|
|
1805
|
+
}
|
|
1806
|
+
/** Запрос отменён через переданный `AbortSignal`. */
|
|
1807
|
+
declare class ItdAbortError extends ItdError {
|
|
1808
|
+
constructor(message?: string, options?: {
|
|
1809
|
+
cause?: unknown;
|
|
1810
|
+
});
|
|
1811
|
+
}
|
|
1812
|
+
/**
|
|
1813
|
+
* Операция невозможна в текущем состоянии объекта.
|
|
1814
|
+
*
|
|
1815
|
+
* Например, клиент уже окончательно освобождён через `dispose()` и не может выполнять
|
|
1816
|
+
* новые запросы или создавать событийные соединения.
|
|
1817
|
+
*/
|
|
1818
|
+
declare class ItdStateError extends ItdError {
|
|
1819
|
+
constructor(message: string, options?: {
|
|
1820
|
+
cause?: unknown;
|
|
1821
|
+
});
|
|
1822
|
+
}
|
|
1823
|
+
/**
|
|
1824
|
+
* Некорректная конфигурация или аргументы — обнаружено до обращения к сети.
|
|
1825
|
+
*
|
|
1826
|
+
* Этим же классом сообщают о нарушенных инвариантах билдеры: например, опрос
|
|
1827
|
+
* с одним вариантом ответа.
|
|
1828
|
+
*/
|
|
1829
|
+
declare class ItdConfigError extends ItdError {
|
|
1830
|
+
constructor(message: string, options?: {
|
|
1831
|
+
cause?: unknown;
|
|
1832
|
+
});
|
|
1833
|
+
}
|
|
1834
|
+
/** Любая ошибка, порождённая этой библиотекой. */
|
|
1835
|
+
declare function isItdError(value: unknown): value is ItdError;
|
|
1836
|
+
/** Ошибка, пришедшая от сервера итд.com (статус ≥ 400). */
|
|
1837
|
+
declare function isItdApiError(value: unknown): value is ItdApiError;
|
|
1838
|
+
/** Ошибка получения или чтения вложения. */
|
|
1839
|
+
declare function isItdFileError(value: unknown): value is ItdFileError;
|
|
1840
|
+
/** Операция невозможна в текущем состоянии объекта. */
|
|
1841
|
+
declare function isItdStateError(value: unknown): value is ItdStateError;
|
|
1842
|
+
/** Ошибка валидации: `VALIDATION_ERROR` либо статус `400`/`422`. */
|
|
1843
|
+
declare function isItdValidationError(value: unknown): value is ItdValidationError;
|
|
1844
|
+
/** Ошибка авторизации: истёкший или отозванный токен. */
|
|
1845
|
+
declare function isItdAuthError(value: unknown): value is ItdAuthError;
|
|
1846
|
+
/** Доступ запрещён либо действие ограничено настройками приватности. */
|
|
1847
|
+
declare function isItdForbiddenError(value: unknown): value is ItdForbiddenError;
|
|
1848
|
+
/** Сущность не найдена. */
|
|
1849
|
+
declare function isItdNotFoundError(value: unknown): value is ItdNotFoundError;
|
|
1850
|
+
/** Сущность уже существует. */
|
|
1851
|
+
declare function isItdConflictError(value: unknown): value is ItdConflictError;
|
|
1852
|
+
/** Превышен лимит запросов. */
|
|
1853
|
+
declare function isItdRateLimitError(value: unknown): value is ItdRateLimitError;
|
|
1854
|
+
/** Действие требует подтверждённого телефона. Ссылка — в `verificationUrl`. */
|
|
1855
|
+
declare function isItdPhoneVerificationError(value: unknown): value is ItdPhoneVerificationError;
|
|
1856
|
+
/** Ошибка на стороне сервера (`5xx`). */
|
|
1857
|
+
declare function isItdServerError(value: unknown): value is ItdServerError;
|
|
1858
|
+
//#endregion
|
|
1859
|
+
//#region src/models/users.d.ts
|
|
1860
|
+
/** Значок-«пин» в профиле — награда или отметка платформы. */
|
|
1861
|
+
interface Pin {
|
|
1862
|
+
/** Постоянный идентификатор, например `epepuy_202605_59`. */
|
|
1863
|
+
slug: string;
|
|
1864
|
+
/** Отображаемое название. */
|
|
1865
|
+
name: string;
|
|
1866
|
+
/** Описание, за что выдан. */
|
|
1867
|
+
description: string;
|
|
1868
|
+
/** Адрес изображения. */
|
|
1869
|
+
url: string;
|
|
1870
|
+
/** Когда выдан. Приходит только в списке своих пинов. */
|
|
1871
|
+
grantedAt?: IsoDate;
|
|
1794
1872
|
}
|
|
1795
1873
|
/**
|
|
1796
|
-
*
|
|
1797
|
-
*
|
|
1798
|
-
* API отдаёт ошибки в двух разных формах — `{ error: { … } }` и `{ code, message, violations }`.
|
|
1799
|
-
* Библиотека сводит обе к этому классу, поэтому разбирать форму ответа вручную не нужно.
|
|
1874
|
+
* Автор поста или комментария.
|
|
1800
1875
|
*
|
|
1801
|
-
*
|
|
1802
|
-
* ```ts
|
|
1803
|
-
* try {
|
|
1804
|
-
* await itd.users.updateMe({ username: 'занятое_имя' });
|
|
1805
|
-
* } catch (e) {
|
|
1806
|
-
* if (e instanceof ItdValidationError) {
|
|
1807
|
-
* console.log(e.fieldErrors.username); // ['Имя уже занято']
|
|
1808
|
-
* }
|
|
1809
|
-
* }
|
|
1810
|
-
* ```
|
|
1876
|
+
* Встречается внутри `post.author` и `comment.author`.
|
|
1811
1877
|
*/
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
* Позволяет разбирать ошибку через `switch`, а проверкам вроде {@link isItdAuthError} —
|
|
1817
|
-
* работать даже когда в проекте оказались две копии библиотеки.
|
|
1818
|
-
*/
|
|
1819
|
-
readonly apiKind: ItdApiErrorKind;
|
|
1820
|
-
/** HTTP-статус ответа. */
|
|
1821
|
-
readonly status: number;
|
|
1822
|
-
/** Строковый код ошибки, например `VALIDATION_ERROR`. */
|
|
1823
|
-
readonly code: ItdErrorCode;
|
|
1824
|
-
/** Расширенное описание, если сервер его прислал. */
|
|
1825
|
-
readonly detail: string | undefined;
|
|
1826
|
-
/** Заголовок ошибки, если сервер его прислал. */
|
|
1827
|
-
readonly title: string | undefined;
|
|
1828
|
-
/** Ошибки по полям. Пустой объект, если сервер их не прислал. */
|
|
1829
|
-
readonly fieldErrors: ItdFieldErrors;
|
|
1830
|
-
/** Идентификатор запроса из заголовков ответа. */
|
|
1831
|
-
readonly requestId: string | undefined;
|
|
1832
|
-
/** HTTP-метод запроса. */
|
|
1833
|
-
readonly method: string;
|
|
1834
|
-
/** Путь запроса без базового URL. */
|
|
1835
|
-
readonly path: string;
|
|
1836
|
-
/** Тело ответа как оно пришло. */
|
|
1837
|
-
readonly raw: unknown;
|
|
1838
|
-
/** Объект ответа. Тело уже прочитано и повторно прочитано быть не может. */
|
|
1839
|
-
readonly response: Response | undefined;
|
|
1840
|
-
/** Пауза из заголовка `Retry-After` в миллисекундах. Сервер итд.com его не присылает. */
|
|
1841
|
-
readonly retryAfter: number | undefined;
|
|
1842
|
-
/**
|
|
1843
|
-
* Сколько запросов разрешено в окне — заголовок `x-ratelimit-limit`.
|
|
1844
|
-
*
|
|
1845
|
-
* Времени сброса окна сервер не сообщает, поэтому точный момент повтора неизвестен.
|
|
1846
|
-
*/
|
|
1847
|
-
readonly rateLimit: number | undefined;
|
|
1848
|
-
/** Сколько запросов осталось в окне — заголовок `x-ratelimit-remaining`. */
|
|
1849
|
-
readonly rateLimitRemaining: number | undefined;
|
|
1850
|
-
/**
|
|
1851
|
-
* @param apiKind разновидность; подставляется подклассами, снаружи задавать не нужно
|
|
1852
|
-
*/
|
|
1853
|
-
constructor(init: ItdApiErrorInit, apiKind?: ItdApiErrorKind);
|
|
1878
|
+
interface Author {
|
|
1879
|
+
id: UserId;
|
|
1880
|
+
username: string;
|
|
1881
|
+
displayName: string;
|
|
1854
1882
|
/**
|
|
1855
|
-
*
|
|
1883
|
+
* **Эмодзи, а не картинка.**
|
|
1856
1884
|
*
|
|
1857
|
-
*
|
|
1858
|
-
*
|
|
1859
|
-
* if (err.hasCode('OTP_INVALID', 'MISSING_FLOW_TOKEN')) await restartOtpFlow();
|
|
1860
|
-
* ```
|
|
1885
|
+
* На итд.com аватар — это символ клана (`🩵`, `🦎`), а не адрес изображения.
|
|
1886
|
+
* Отрисовывать его нужно как текст.
|
|
1861
1887
|
*/
|
|
1862
|
-
|
|
1863
|
-
/**
|
|
1864
|
-
|
|
1888
|
+
avatar: string;
|
|
1889
|
+
/** Пройдена ли верификация. */
|
|
1890
|
+
verified: boolean;
|
|
1891
|
+
/** Активный значок профиля. Может отсутствовать. */
|
|
1892
|
+
pin?: Pin | null;
|
|
1893
|
+
/** Есть ли премиум-подписка (значок NUKSTA). */
|
|
1894
|
+
hasNuksta?: boolean;
|
|
1865
1895
|
}
|
|
1866
|
-
/**
|
|
1867
|
-
|
|
1868
|
-
|
|
1896
|
+
/**
|
|
1897
|
+
* Участник события в уведомлении.
|
|
1898
|
+
*
|
|
1899
|
+
* Отличается от {@link Author} набором полей: вместо значков приходит связь с вами.
|
|
1900
|
+
*/
|
|
1901
|
+
interface Actor {
|
|
1902
|
+
id: UserId;
|
|
1903
|
+
username: string;
|
|
1904
|
+
displayName: string;
|
|
1905
|
+
/** Эмодзи-аватар, см. {@link Author.avatar}. */
|
|
1906
|
+
avatar: string;
|
|
1907
|
+
/** Подписаны ли вы на этого пользователя. */
|
|
1908
|
+
isFollowing?: boolean;
|
|
1909
|
+
/** Подписан ли он на вас. */
|
|
1910
|
+
isFollowedBy?: boolean;
|
|
1869
1911
|
}
|
|
1870
|
-
/**
|
|
1871
|
-
|
|
1872
|
-
|
|
1912
|
+
/**
|
|
1913
|
+
* Пользователь в списках.
|
|
1914
|
+
*
|
|
1915
|
+
* Набор полей зависит от эндпоинта: подписчики и подписки приносят `isFollowing`,
|
|
1916
|
+
* поиск и рекомендации — `followersCount` и `hasNuksta`. Необязательные поля отражают
|
|
1917
|
+
* это различие.
|
|
1918
|
+
*/
|
|
1919
|
+
interface UserSummary {
|
|
1920
|
+
id: UserId;
|
|
1921
|
+
username: string;
|
|
1922
|
+
displayName: string;
|
|
1923
|
+
/** Эмодзи-аватар, см. {@link Author.avatar}. */
|
|
1924
|
+
avatar: string;
|
|
1925
|
+
verified: boolean;
|
|
1926
|
+
/** Подписаны ли вы. Приходит в списках подписчиков и подписок. */
|
|
1927
|
+
isFollowing?: boolean;
|
|
1928
|
+
/** Есть ли премиум. Приходит в поиске и рекомендациях. */
|
|
1929
|
+
hasNuksta?: boolean;
|
|
1930
|
+
/** Число подписчиков. Приходит в поиске и рекомендациях. */
|
|
1931
|
+
followersCount?: number;
|
|
1873
1932
|
}
|
|
1874
|
-
/**
|
|
1875
|
-
|
|
1876
|
-
|
|
1933
|
+
/** Поля профиля, общие для своего и чужого. */
|
|
1934
|
+
interface ProfileBase {
|
|
1935
|
+
id: UserId;
|
|
1936
|
+
username: string;
|
|
1937
|
+
displayName: string;
|
|
1938
|
+
/** Эмодзи-аватар, см. {@link Author.avatar}. */
|
|
1939
|
+
avatar: string;
|
|
1940
|
+
/** URL изображения баннера либо `null`. */
|
|
1941
|
+
banner: string | null;
|
|
1942
|
+
/** Описание профиля. */
|
|
1943
|
+
bio: string;
|
|
1944
|
+
verified: boolean;
|
|
1945
|
+
pin?: Pin | null;
|
|
1946
|
+
/** Кто может писать на стену. */
|
|
1947
|
+
wallAccess: WallAccess;
|
|
1948
|
+
/** Кто видит реакции. */
|
|
1949
|
+
likesVisibility: LikesVisibility;
|
|
1950
|
+
followersCount: number;
|
|
1951
|
+
followingCount: number;
|
|
1952
|
+
postsCount: number;
|
|
1953
|
+
createdAt: IsoDate;
|
|
1877
1954
|
}
|
|
1878
|
-
/**
|
|
1879
|
-
|
|
1880
|
-
|
|
1955
|
+
/** Состояние подписки на премиум. */
|
|
1956
|
+
interface SubscriptionState {
|
|
1957
|
+
isActive: boolean;
|
|
1958
|
+
expiresAt: IsoDate | null;
|
|
1959
|
+
autoRenewal: boolean;
|
|
1881
1960
|
}
|
|
1882
|
-
/**
|
|
1883
|
-
|
|
1884
|
-
|
|
1961
|
+
/**
|
|
1962
|
+
* Свой профиль — ответ `GET /api/users/me`.
|
|
1963
|
+
*
|
|
1964
|
+
* Отличается от чужого наличием {@link subscription} и {@link isPhoneVerified}
|
|
1965
|
+
* и отсутствием полей связи (`isFollowing`, `online`).
|
|
1966
|
+
*/
|
|
1967
|
+
interface MyProfile extends ProfileBase {
|
|
1968
|
+
/** Закрыт ли профиль. */
|
|
1969
|
+
isPrivate: boolean;
|
|
1970
|
+
/** Подтверждён ли телефон. Без него часть действий недоступна. */
|
|
1971
|
+
isPhoneVerified: boolean;
|
|
1972
|
+
/** Своя премиум-подписка. */
|
|
1973
|
+
subscription: SubscriptionState;
|
|
1974
|
+
}
|
|
1975
|
+
/**
|
|
1976
|
+
* Состояние авторизации — ответ `GET /api/profile`.
|
|
1977
|
+
*
|
|
1978
|
+
* Endpoint доступен без сессии: в этом случае `authenticated` равен `false`,
|
|
1979
|
+
* а `user` — `null`.
|
|
1980
|
+
*/
|
|
1981
|
+
interface AuthState {
|
|
1982
|
+
/** Есть ли действующая сессия. */
|
|
1983
|
+
authenticated: boolean;
|
|
1984
|
+
/** Заблокирован ли текущий аккаунт. */
|
|
1985
|
+
banned: boolean;
|
|
1986
|
+
/** Текущий пользователь либо `null` без действующей сессии. */
|
|
1987
|
+
user: MyProfile | null;
|
|
1885
1988
|
}
|
|
1886
1989
|
/**
|
|
1887
|
-
*
|
|
1990
|
+
* Чужой профиль — ответ `GET /api/users/{id|username}`.
|
|
1888
1991
|
*
|
|
1889
|
-
*
|
|
1890
|
-
* (в миллисекундах). При включённых ретраях библиотека выдерживает её автоматически.
|
|
1992
|
+
* Вместо своей подписки содержит связь с вами и присутствие.
|
|
1891
1993
|
*/
|
|
1892
|
-
|
|
1893
|
-
|
|
1994
|
+
interface PublicProfile extends ProfileBase {
|
|
1995
|
+
hasNuksta?: boolean;
|
|
1996
|
+
/** Закреплённый пост, если он есть. */
|
|
1997
|
+
pinnedPostId: string | null;
|
|
1998
|
+
/** Подписаны ли вы на него. */
|
|
1999
|
+
isFollowing: boolean;
|
|
2000
|
+
/** Подписан ли он на вас. */
|
|
2001
|
+
isFollowedBy: boolean;
|
|
2002
|
+
/** Сейчас ли пользователь в сети. */
|
|
2003
|
+
online: boolean;
|
|
2004
|
+
/** Когда был в сети. `null`, если скрыто настройками приватности. */
|
|
2005
|
+
lastSeen: IsoDate | null;
|
|
2006
|
+
}
|
|
2007
|
+
/** Профиль: свой либо чужой. Различаются функцией `isMyProfile()`. */
|
|
2008
|
+
type Profile = MyProfile | PublicProfile;
|
|
2009
|
+
/** Настройки приватности профиля. */
|
|
2010
|
+
interface PrivacySettings {
|
|
2011
|
+
/** Закрыт ли профиль: подписка требует одобрения. */
|
|
2012
|
+
isPrivate: boolean;
|
|
2013
|
+
wallAccess: WallAccess;
|
|
2014
|
+
likesVisibility: LikesVisibility;
|
|
2015
|
+
/** Показывать ли время последнего посещения. */
|
|
2016
|
+
showLastSeen: boolean;
|
|
1894
2017
|
}
|
|
1895
2018
|
/**
|
|
1896
|
-
*
|
|
2019
|
+
* Результат подписки на пользователя.
|
|
1897
2020
|
*
|
|
1898
|
-
*
|
|
2021
|
+
* @example
|
|
2022
|
+
* ```ts
|
|
2023
|
+
* const result = await itd.users.follow('nowkie');
|
|
2024
|
+
* // { following: true, followersCount: 11 }
|
|
2025
|
+
* ```
|
|
1899
2026
|
*/
|
|
1900
|
-
|
|
1901
|
-
/**
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
/** `5xx` — ошибка на стороне сервера. */
|
|
1908
|
-
declare class ItdServerError extends ItdApiError {
|
|
1909
|
-
constructor(init: ItdApiErrorInit);
|
|
1910
|
-
}
|
|
1911
|
-
/** Причина ошибки получения вложения. */
|
|
1912
|
-
declare const ItdFileErrorReason: Readonly<{
|
|
1913
|
-
/** Сетевой сбой при получении источника. */
|
|
1914
|
-
readonly Network: "network";
|
|
1915
|
-
/** Источник ответил ошибочным HTTP-статусом. */
|
|
1916
|
-
readonly Http: "http";
|
|
1917
|
-
/** Источник превысил разрешённый размер. */
|
|
1918
|
-
readonly TooLarge: "too_large";
|
|
1919
|
-
/** Среда или источник не предоставили поток. */
|
|
1920
|
-
readonly StreamUnavailable: "stream_unavailable";
|
|
1921
|
-
/** Поток источника завершился ошибкой. */
|
|
1922
|
-
readonly Read: "read";
|
|
1923
|
-
}>;
|
|
1924
|
-
type ItdFileErrorReason = (typeof ItdFileErrorReason)[keyof typeof ItdFileErrorReason];
|
|
1925
|
-
/** Не удалось получить или прочитать содержимое вложения. */
|
|
1926
|
-
declare class ItdFileError extends ItdError {
|
|
1927
|
-
readonly reason: ItdFileErrorReason;
|
|
1928
|
-
/** Адрес источника, если файл получался по сети. */
|
|
1929
|
-
readonly url: string | undefined;
|
|
1930
|
-
/** HTTP-статус источника. */
|
|
1931
|
-
readonly status: number | undefined;
|
|
1932
|
-
/** Разрешённый размер в байтах. */
|
|
1933
|
-
readonly limit: number | undefined;
|
|
1934
|
-
/** Обнаруженный размер в байтах. */
|
|
1935
|
-
readonly actual: number | undefined;
|
|
1936
|
-
/** Имеет ли смысл повторить получение источника. */
|
|
1937
|
-
readonly retryable: boolean;
|
|
1938
|
-
constructor(message: string, init: {
|
|
1939
|
-
reason: ItdFileErrorReason;
|
|
1940
|
-
url?: string | undefined;
|
|
1941
|
-
status?: number | undefined;
|
|
1942
|
-
limit?: number | undefined;
|
|
1943
|
-
actual?: number | undefined;
|
|
1944
|
-
retryable?: boolean | undefined;
|
|
1945
|
-
cause?: unknown;
|
|
1946
|
-
});
|
|
1947
|
-
}
|
|
1948
|
-
/** Запрос не дошёл до сервера: DNS, обрыв соединения, отсутствие сети. */
|
|
1949
|
-
declare class ItdNetworkError extends ItdError {
|
|
1950
|
-
/** HTTP-метод запроса. */
|
|
1951
|
-
readonly method: string;
|
|
1952
|
-
/** Путь запроса без базового URL. */
|
|
1953
|
-
readonly path: string;
|
|
1954
|
-
constructor(message: string, init: {
|
|
1955
|
-
method: string;
|
|
1956
|
-
path: string;
|
|
1957
|
-
cause?: unknown;
|
|
1958
|
-
});
|
|
1959
|
-
}
|
|
1960
|
-
/** Истёк таймаут запроса, заданный опцией `timeout`. */
|
|
1961
|
-
declare class ItdTimeoutError extends ItdError {
|
|
1962
|
-
/** Значение таймаута в миллисекундах. */
|
|
1963
|
-
readonly timeout: number;
|
|
1964
|
-
/** HTTP-метод запроса. */
|
|
1965
|
-
readonly method: string;
|
|
1966
|
-
/** Путь запроса без базового URL. */
|
|
1967
|
-
readonly path: string;
|
|
1968
|
-
constructor(init: {
|
|
1969
|
-
timeout: number;
|
|
1970
|
-
method: string;
|
|
1971
|
-
path: string;
|
|
1972
|
-
});
|
|
2027
|
+
interface FollowResult {
|
|
2028
|
+
/** Подписка оформлена. У закрытого профиля отправляется заявка, и здесь будет `false`. */
|
|
2029
|
+
following: boolean;
|
|
2030
|
+
/** Сколько подписчиков стало у пользователя после действия. */
|
|
2031
|
+
followersCount?: number;
|
|
2032
|
+
/** Статус заявки, если профиль закрыт. */
|
|
2033
|
+
status?: Loose<'following' | 'requested'>;
|
|
1973
2034
|
}
|
|
1974
|
-
/**
|
|
1975
|
-
|
|
1976
|
-
|
|
1977
|
-
|
|
1978
|
-
|
|
2035
|
+
/** Закреплённые значки профиля и выбранный из них. */
|
|
2036
|
+
interface PinsResult {
|
|
2037
|
+
pins: Pin[];
|
|
2038
|
+
/** Идентификатор активного значка — строка, а не объект. */
|
|
2039
|
+
activePin: string | null;
|
|
1979
2040
|
}
|
|
2041
|
+
//#endregion
|
|
2042
|
+
//#region src/models/notifications.d.ts
|
|
1980
2043
|
/**
|
|
1981
|
-
*
|
|
2044
|
+
* Уведомление в единой форме.
|
|
1982
2045
|
*
|
|
1983
|
-
*
|
|
1984
|
-
*
|
|
2046
|
+
* REST-список и SSE-поток отдают уведомления по-разному — разные имена типов, разные имена
|
|
2047
|
+
* полей, один участник против массива. Библиотека приводит оба вида к этой структуре,
|
|
2048
|
+
* поэтому объекты из `itd.notifications.list()` и из потока можно складывать в один список.
|
|
2049
|
+
*
|
|
2050
|
+
* Исходные данные не теряются: серверное имя типа остаётся в {@link rawType},
|
|
2051
|
+
* а весь необработанный объект — в {@link raw}.
|
|
1985
2052
|
*/
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
|
|
2053
|
+
interface Notification {
|
|
2054
|
+
id: string;
|
|
2055
|
+
/** Канонический тип. Старые имена (`like`, `comment`) приведены к новым. */
|
|
2056
|
+
type: NotificationType;
|
|
2057
|
+
/** Имя типа в том виде, в каком его прислал сервер. */
|
|
2058
|
+
rawType: string;
|
|
2059
|
+
/** Объект события: пост, комментарий, пользователь. */
|
|
2060
|
+
entityId: string | null;
|
|
2061
|
+
/** Пост, которому принадлежит комментарий, если событие о комментарии. */
|
|
2062
|
+
parentEntityId: string | null;
|
|
2063
|
+
/** Прочитано ли уведомление. */
|
|
2064
|
+
isRead: boolean;
|
|
2065
|
+
/** Кто совершил действие. Для схлопнутых уведомлений — несколько человек. */
|
|
2066
|
+
actors: Actor[];
|
|
2067
|
+
/** Сколько участников схлопнуто в одно уведомление. Минимум 1. */
|
|
2068
|
+
count: number;
|
|
2069
|
+
/** Текст или заголовок объекта события. */
|
|
2070
|
+
preview: string | null;
|
|
2071
|
+
/** Ссылка перехода, предложенная сервером. Обычно точнее её `resolveNotificationUrl()`. */
|
|
2072
|
+
clickUrl?: string;
|
|
2073
|
+
createdAt: IsoDate;
|
|
2074
|
+
/** Когда уведомление изменилось — например было прочитано. */
|
|
2075
|
+
updatedAt: IsoDate;
|
|
2076
|
+
/** Исходный объект как он пришёл от сервера. */
|
|
2077
|
+
raw: unknown;
|
|
1990
2078
|
}
|
|
1991
2079
|
/**
|
|
1992
|
-
*
|
|
2080
|
+
* Настройки уведомлений.
|
|
1993
2081
|
*
|
|
1994
|
-
*
|
|
1995
|
-
*
|
|
2082
|
+
* Сервер отдаёт плоский объект, но исторически знает два набора имён для одних и тех же
|
|
2083
|
+
* настроек (`likes` и `reactions`, `comments` и `replies`). При сохранении библиотека
|
|
2084
|
+
* отправляет оба, при чтении принимает любой.
|
|
1996
2085
|
*/
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
|
|
2086
|
+
interface NotificationSettings {
|
|
2087
|
+
/** Общий выключатель доставки. */
|
|
2088
|
+
enabled: boolean;
|
|
2089
|
+
/** Звук уведомления. */
|
|
2090
|
+
sound: boolean;
|
|
2091
|
+
/** Новые подписчики. */
|
|
2092
|
+
follows: boolean;
|
|
2093
|
+
/** Записи на вашей стене. */
|
|
2094
|
+
wallPosts: boolean;
|
|
2095
|
+
/** Реакции на ваши записи. */
|
|
2096
|
+
likes: boolean;
|
|
2097
|
+
/** Комментарии и ответы. */
|
|
2098
|
+
comments: boolean;
|
|
2099
|
+
/** Упоминания. */
|
|
2100
|
+
mentions: boolean;
|
|
2001
2101
|
}
|
|
2002
|
-
|
|
2003
|
-
|
|
2004
|
-
/**
|
|
2005
|
-
|
|
2006
|
-
/**
|
|
2007
|
-
|
|
2008
|
-
/**
|
|
2009
|
-
|
|
2010
|
-
|
|
2011
|
-
|
|
2012
|
-
|
|
2013
|
-
|
|
2014
|
-
/**
|
|
2015
|
-
|
|
2016
|
-
|
|
2017
|
-
|
|
2018
|
-
|
|
2019
|
-
|
|
2020
|
-
|
|
2021
|
-
|
|
2022
|
-
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
|
|
2102
|
+
//#endregion
|
|
2103
|
+
//#region src/notifications/normalize.d.ts
|
|
2104
|
+
/** Событие потока уведомлений после разбора. */
|
|
2105
|
+
interface NotificationEvent {
|
|
2106
|
+
/** Само уведомление в единой форме. */
|
|
2107
|
+
notification: Notification;
|
|
2108
|
+
/**
|
|
2109
|
+
* Актуальное число непрочитанных, если сервер его сообщил.
|
|
2110
|
+
*
|
|
2111
|
+
* Клиент не увеличивает счётчик сам: значение приходит с сервера.
|
|
2112
|
+
*/
|
|
2113
|
+
unreadCount: number | undefined;
|
|
2114
|
+
/** Нужно ли проиграть звук. */
|
|
2115
|
+
sound: boolean;
|
|
2116
|
+
}
|
|
2117
|
+
/**
|
|
2118
|
+
* Приводит уведомление к единой форме.
|
|
2119
|
+
*
|
|
2120
|
+
* Нужна потому, что REST-список и поток событий описывают одно и то же событие по-разному:
|
|
2121
|
+
* различаются имена типов (`like` против `post_reaction`), имена полей
|
|
2122
|
+
* (`targetId`/`entityId`, `read`/`isRead`, `preview`/`entityPreview`) и число участников
|
|
2123
|
+
* (`actor` против массива `actors`). После приведения объекты из обоих источников
|
|
2124
|
+
* можно складывать в один список.
|
|
2125
|
+
*
|
|
2126
|
+
* Исходные данные не теряются: имя типа с сервера остаётся в `rawType`,
|
|
2127
|
+
* весь объект целиком — в `raw`.
|
|
2128
|
+
*
|
|
2129
|
+
* @param input уведомление из REST-ответа либо полезная нагрузка события потока
|
|
2130
|
+
*
|
|
2131
|
+
* @example
|
|
2132
|
+
* ```ts
|
|
2133
|
+
* const fromRest = normalizeNotification(restItem);
|
|
2134
|
+
* const fromStream = normalizeNotification(event.payload);
|
|
2135
|
+
* // одинаковая форма — можно объединять
|
|
2136
|
+
* ```
|
|
2137
|
+
*/
|
|
2138
|
+
declare function normalizeNotification(input: unknown): Notification;
|
|
2026
2139
|
//#endregion
|
|
2027
2140
|
//#region src/notifications/text.d.ts
|
|
2028
2141
|
/**
|
|
@@ -2077,5 +2190,5 @@ declare function isKnownNotificationType(type: string): boolean;
|
|
|
2077
2190
|
*/
|
|
2078
2191
|
declare function resolveNotificationUrl(notification: Notification): string;
|
|
2079
2192
|
//#endregion
|
|
2080
|
-
export {
|
|
2081
|
-
//# sourceMappingURL=url-
|
|
2193
|
+
export { isItdValidationError as $, RateLimitBucket as $t, ItdFieldErrors as A, ResponseContext as At, ItdTimeoutError as B, ItdClock as Bt, ItdApiErrorInit as C, RateLimitBucketContext as Ct, ItdConflictError as D, RequestContext as Dt, ItdConfigError as E, RawRequestOptions as Et, ItdNotFoundError as F, QueryParams as Ft, isItdError as G, OPERATIONS as Gt, isItdApiError as H, BuiltInOperationId as Ht, ItdPhoneVerificationError as I, QueryValue as It, isItdNotFoundError as J, operationBucket as Jt, isItdFileError as K, OperationId as Kt, ItdRateLimitError as L, ServiceDefinition as Lt, ItdFileErrorReason as M, RetryDecisionContext as Mt, ItdForbiddenError as N, RetryOptions as Nt, ItdError as O, RequestExtensions as Ot, ItdNetworkError as P, RuntimeOptions as Pt, isItdStateError as Q, DEFAULT_RATE_LIMIT_BUCKET as Qt, ItdServerError as R, RateLimitPacing as Rt, ItdApiError as S, PaginationOptions as St, ItdAuthError as T, RateLimitOptions as Tt, isItdAuthError as U, CustomOperationId as Ut, ItdValidationError as V, systemClock as Vt, isItdConflictError as W, ItdOperationDefinition as Wt, isItdRateLimitError as X, operationRetrySafety as Xt, isItdPhoneVerificationError as Y, operationMethod as Yt, isItdServerError as Z, BUCKET_LIMITS as Zt, Profile as _, ServiceState as _n, RetrySafety as _t, NotificationEvent as a, AttachmentType as an, tokenProvider as at, UserSummary as b, ViewSource as bn, Logger as bt, NotificationSettings as c, FeedTab as cn, Unsubscribe as ct, Author as d, ItdErrorCode as dn, LIBRARY_VERSION as dt, IsoDate as en, ClientConnection as et, FollowResult as f, LikesVisibility as fn, FeatureOperationId as ft, PrivacySettings as g, ReportTargetType as gn, OperationMethod as gt, PinsResult as h, ReportReason as hn, OperationMetadata as ht, formatNotificationText as i, AccessType as in, bearerToken as it, ItdFileError as j, RetryContext as jt, ItdErrorKind as k, RequestOptions as kt, Actor as l, IncidentKind as ln, DEFAULT_BASE_URL as lt, Pin as m, NotificationType as mn, OperationContract as mt, canonicalNotificationType as n, UserId as nn, AuthProvider as nt, normalizeNotification as o, CommentSort as on, Emitter as ot, MyProfile as p, Loose as pn, OperationAnnotations as pt, isItdForbiddenError as q, isBuiltInOperationId as qt, isKnownNotificationType as r, UserRef as rn, anonymousAuth as rt, Notification as s, EventChannelStatus as sn, Listener as st, resolveNotificationUrl as t, Span as tn, AuthIdentity as tt, AuthState as u, InteractionType as un, STATUS_SERVICE as ut, PublicProfile as v, SpanType as vn, ClientHooks as vt, ItdApiErrorKind as w, RateLimitBucketOverride as wt, ItdAbortError as x, WallAccess as xn, OperationRequestOptions as xt, SubscriptionState as y, ViewReason as yn, ErrorContextHook as yt, ItdStateError as z, RuntimeMode as zt };
|
|
2194
|
+
//# sourceMappingURL=url-XBsMdAcv.d.cts.map
|