itd-api 0.0.9 → 0.0.11
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 +90 -252
- package/dist/{chunk-HTF2MOM4.cjs → chunk-QD4UHJFF.cjs} +4106 -2730
- package/dist/chunk-QD4UHJFF.cjs.map +1 -0
- package/dist/{chunk-MYAU2WJU.js → chunk-TB7HW3VX.js} +4097 -2731
- package/dist/chunk-TB7HW3VX.js.map +1 -0
- package/dist/index-CrlTO7sR.d.cts +4858 -0
- package/dist/index-CrlTO7sR.d.ts +4858 -0
- package/dist/index.cjs +136 -100
- package/dist/index.d.cts +1 -4206
- package/dist/index.d.ts +1 -4206
- package/dist/index.js +1 -1
- package/dist/node.cjs +226 -132
- package/dist/node.cjs.map +1 -1
- package/dist/node.d.cts +42 -4
- package/dist/node.d.ts +42 -4
- package/dist/node.js +99 -36
- package/dist/node.js.map +1 -1
- package/guides/README.md +22 -0
- package/guides/authentication/README.md +176 -0
- package/guides/authentication/examples/bot-with-session.mjs +98 -0
- package/guides/authentication/examples/turnstile-login.mjs +56 -0
- package/guides/integrations/README.md +62 -0
- package/guides/integrations/examples/proxy.mjs +26 -0
- package/guides/multi-accounts/README.md +142 -0
- package/guides/multi-accounts/examples/multi-accounts.mjs +71 -0
- package/guides/plugins/README.md +162 -0
- package/guides/plugins/examples/cache.mjs +33 -0
- package/guides/plugins/examples/crypto.mjs +54 -0
- package/guides/quickstart/README.md +124 -0
- package/guides/quickstart/examples/quick-start.mjs +44 -0
- package/guides/quickstart/examples/typescript.ts +90 -0
- package/guides/realtime/README.md +109 -0
- package/guides/realtime/examples/notifications.mjs +62 -0
- package/guides/text-markup/README.md +214 -0
- package/guides/text-markup/examples/create-post.mjs +64 -0
- package/package.json +6 -4
- package/dist/chunk-HTF2MOM4.cjs.map +0 -1
- package/dist/chunk-MYAU2WJU.js.map +0 -1
package/README.md
CHANGED
|
@@ -43,65 +43,24 @@ const itd = new ItdClient({ storage: new FileTokenStorage('./.itd-session.json')
|
|
|
43
43
|
await itd.posts.create((p) => p.content('привет').attach('./photo.jpg'));
|
|
44
44
|
```
|
|
45
45
|
|
|
46
|
-
|
|
46
|
+
Продолжение с запускаемыми примерами — в [руководстве по быстрому старту](./guides/quickstart/README.md).
|
|
47
|
+
Все тематические материалы собраны в [`guides/`](./guides/README.md).
|
|
47
48
|
|
|
48
49
|
---
|
|
49
50
|
|
|
50
51
|
## Авторизация
|
|
51
52
|
|
|
52
|
-
|
|
53
|
-
из явного вызова входа. Всё это взаимозаменяемо, и **обязательного варианта нет**.
|
|
53
|
+
Клиент может взять доступ из `auth`, сохранённой сессии или явного вызова `itd.auth`:
|
|
54
54
|
|
|
55
55
|
```ts
|
|
56
|
-
new ItdClient({ auth: '<accessToken>' });
|
|
57
|
-
new ItdClient({ auth: { accessToken, refreshToken } });
|
|
58
|
-
new ItdClient({ auth: { email, password, getTurnstileToken } });
|
|
59
|
-
new ItdClient({
|
|
60
|
-
|
|
61
|
-
new ItdClient({ storage: new FileTokenStorage('./.itd-session.json') }); // сессия с прошлого раза
|
|
62
|
-
new ItdClient(); // войти позже, через itd.auth
|
|
63
|
-
```
|
|
64
|
-
|
|
65
|
-
`auth` и `storage` не конкурируют, а дополняют друг друга: **хранилище главнее** — оно
|
|
66
|
-
отражает текущее состояние сессии, — а недостающие поля берутся из `auth`. Типичный случай:
|
|
67
|
-
в хранилище лежит только `accessToken`, а `refreshToken` приходит из настроек приложения.
|
|
68
|
-
|
|
69
|
-
### Сессия из хранилища — `auth` не нужен
|
|
70
|
-
|
|
71
|
-
Если предыдущий запуск сохранил сессию, для работы достаточно одного `storage`:
|
|
72
|
-
|
|
73
|
-
```ts
|
|
74
|
-
import { ItdClient, FileTokenStorage } from 'itd-api/node';
|
|
75
|
-
|
|
76
|
-
const itd = new ItdClient({ storage: new FileTokenStorage('./.itd-session.json') });
|
|
77
|
-
|
|
78
|
-
const me = await itd.users.me(); // токен подставится сам
|
|
79
|
-
```
|
|
80
|
-
|
|
81
|
-
Более того, сохранённого `accessToken` не требуется вовсе. Хватает cookie: первый запрос
|
|
82
|
-
получит `401`, библиотека продлит сессию и повторит его — вызывающий код ничего не заметит.
|
|
83
|
-
|
|
84
|
-
Refresh-токен живёт 30 суток и обновляется при каждом продлении, поэтому регулярно
|
|
85
|
-
работающему боту капчу достаточно решить один раз, при первом запуске.
|
|
86
|
-
|
|
87
|
-
Проверить, есть ли что продлевать, можно заранее:
|
|
88
|
-
|
|
89
|
-
```ts
|
|
90
|
-
if (await itd.auth.hasRefreshSession()) await itd.auth.refresh();
|
|
91
|
-
else redirectToLogin();
|
|
56
|
+
new ItdClient({ auth: '<accessToken>' });
|
|
57
|
+
new ItdClient({ auth: { accessToken, refreshToken } });
|
|
58
|
+
new ItdClient({ auth: { email, password, getTurnstileToken } });
|
|
59
|
+
new ItdClient({ storage: new FileTokenStorage('./.itd-session.json') });
|
|
92
60
|
```
|
|
93
61
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
При ответе `401` библиотека продлевает сессию и повторяет запрос. Параллельные запросы,
|
|
97
|
-
одновременно получившие `401`, ждут **одного** обновления, а не запускают своё — иначе сервер
|
|
98
|
-
увидел бы десяток одновременных `refresh` и отверг бы все, кроме первого.
|
|
99
|
-
|
|
100
|
-
Отключить автоматику: `autoRefresh: false`, дальше `await itd.auth.refresh()` вручную.
|
|
101
|
-
|
|
102
|
-
Когда продлить не удалось, `refresh()` бросает ошибку **сервера** — по её коду видно, что
|
|
103
|
-
именно случилось: `SESSION_NOT_FOUND` (сессия отозвана или истекла), `SESSION_REVOKED`,
|
|
104
|
-
`REFRESH_TOKEN_MISSING` (продлевать нечем). Та же ошибка приходит в событии `authError`:
|
|
62
|
+
При `401` сессия продлевается, исходный запрос повторяется, а новое состояние сохраняется.
|
|
63
|
+
Параллельные запросы ждут одного refresh. Потерю сессии можно отследить:
|
|
105
64
|
|
|
106
65
|
```ts
|
|
107
66
|
itd.on('authError', ({ error }) => {
|
|
@@ -109,108 +68,39 @@ itd.on('authError', ({ error }) => {
|
|
|
109
68
|
});
|
|
110
69
|
```
|
|
111
70
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
не решает — он принимает готовый токен, а решает его кто-то снаружи.
|
|
116
|
-
|
|
117
|
-
```ts
|
|
118
|
-
import { TURNSTILE_SITE_KEY } from 'itd-api';
|
|
119
|
-
|
|
120
|
-
// в браузере — виджет Turnstile с этим ключом
|
|
121
|
-
turnstile.render('#captcha', {
|
|
122
|
-
sitekey: TURNSTILE_SITE_KEY,
|
|
123
|
-
callback: (turnstileToken) => itd.auth.signIn({ email, password, turnstileToken }),
|
|
124
|
-
});
|
|
125
|
-
```
|
|
126
|
-
|
|
127
|
-
Токен одноразовый и живёт несколько минут. Долгоживущему боту передавайте не строку,
|
|
128
|
-
а источник — он спрашивается заново перед каждой попыткой входа:
|
|
129
|
-
|
|
130
|
-
```ts
|
|
131
|
-
new ItdClient({
|
|
132
|
-
auth: { email, password, getTurnstileToken: () => captchaSolver.solve() },
|
|
133
|
-
});
|
|
134
|
-
```
|
|
135
|
-
|
|
136
|
-
В Node таким источником может быть [`@itd-api/turnstile`](./turnstile/README.md) — отдельный пакет,
|
|
137
|
-
который поднимает браузер и приносит токен. Отдельный он намеренно: тянет за собой Playwright
|
|
138
|
-
и требует графической оболочки, а нужен далеко не всем — с сохранённой сессией до входа
|
|
139
|
-
по паролю дело обычно вообще не доходит.
|
|
140
|
-
|
|
141
|
-
```sh
|
|
142
|
-
npm i @itd-api/turnstile playwright
|
|
143
|
-
```
|
|
71
|
+
Вход, регистрация и восстановление пароля требуют одноразовый Turnstile token. Подробности
|
|
72
|
+
о cookie, `deviceId`, OTP, собственном storage и автоматическом решателе:
|
|
73
|
+
[руководство по авторизации](./guides/authentication/README.md).
|
|
144
74
|
|
|
145
|
-
|
|
146
|
-
import { createTurnstileSolver } from '@itd-api/turnstile';
|
|
75
|
+
---
|
|
147
76
|
|
|
148
|
-
|
|
149
|
-
storage: new FileTokenStorage('./.itd-session.json'),
|
|
150
|
-
auth: { email, password, getTurnstileToken: createTurnstileSolver() },
|
|
151
|
-
});
|
|
152
|
-
```
|
|
77
|
+
## Несколько аккаунтов
|
|
153
78
|
|
|
154
|
-
|
|
79
|
+
`ItdAccounts` хранит именованные клиенты с отдельными tokens, cookie и `deviceId`, но одним
|
|
80
|
+
`MultiTokenStorage`:
|
|
155
81
|
|
|
156
82
|
```ts
|
|
157
|
-
import {
|
|
158
|
-
|
|
159
|
-
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
83
|
+
import { ItdAccounts, FileMultiTokenStorage } from 'itd-api/node';
|
|
160
84
|
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
85
|
+
const accounts = new ItdAccounts({
|
|
86
|
+
storage: new FileMultiTokenStorage('./.itd-sessions.json'),
|
|
87
|
+
rateLimit: { concurrency: 4 },
|
|
164
88
|
});
|
|
165
|
-
```
|
|
166
89
|
|
|
167
|
-
|
|
90
|
+
// Поднимаем тех, кто уже входил раньше: ни auth, ни капча не нужны.
|
|
91
|
+
await accounts.restore();
|
|
168
92
|
|
|
169
|
-
|
|
93
|
+
if (!accounts.has('kiow')) {
|
|
94
|
+
accounts.addAccount('kiow', { auth: { email, password, getTurnstileToken } });
|
|
95
|
+
}
|
|
170
96
|
|
|
171
|
-
|
|
172
|
-
await itd.
|
|
173
|
-
|
|
174
|
-
getOtp: () => rl.question('Код из письма: '),
|
|
175
|
-
});
|
|
97
|
+
const itd = accounts.account('kiow'); // обычный ItdClient со всеми разделами
|
|
98
|
+
await itd.posts.create({ content: 'привет' });
|
|
99
|
+
await accounts.close();
|
|
176
100
|
```
|
|
177
101
|
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
| Хранилище | Откуда | Среда |
|
|
181
|
-
|---|---|---|
|
|
182
|
-
| `MemoryTokenStorage` (по умолчанию) | `itd-api` | везде |
|
|
183
|
-
| `LocalStorageTokenStorage` | `itd-api` | браузер |
|
|
184
|
-
| `FileTokenStorage` | `itd-api/node` | Node, Bun, Deno |
|
|
185
|
-
| `createTokenStorage({ get, set, clear })` | `itd-api` | своё: Redis, БД, AsyncStorage |
|
|
186
|
-
|
|
187
|
-
По умолчанию сессия живёт в памяти процесса и теряется при перезапуске. Укажите `storage` —
|
|
188
|
-
и библиотека сама запишет туда всё нужное после входа и после каждого продления; отдельно
|
|
189
|
-
сохранять ничего не надо.
|
|
190
|
-
|
|
191
|
-
В сессию попадают `accessToken`, `refreshToken`, cookie и `deviceId`. Сохранять её целиком
|
|
192
|
-
важно: refresh-токен приходит в cookie `refresh_token`, а `fetch` вне браузера их не хранит,
|
|
193
|
-
поэтому библиотека ведёт собственный cookie-jar. В браузере используется
|
|
194
|
-
`credentials: 'include'`, в React Native cookie ведёт нативный слой.
|
|
195
|
-
|
|
196
|
-
`deviceId` — идентификатор устройства из заголовка `X-Device-Id`. Сервер различает по нему
|
|
197
|
-
записи в списке сессий (`itd.auth.sessions()`), поэтому при постоянном хранилище он переживает
|
|
198
|
-
перезапуск и бот не плодит по новой сессии на каждый старт. Своё значение — опцией `deviceId`.
|
|
199
|
-
|
|
200
|
-
Refresh-токен можно передать и строкой (`auth: { accessToken, refreshToken }`) — вне браузера
|
|
201
|
-
библиотека сама подставит его нужной cookie. В браузере так не выйдет: cookie помечена
|
|
202
|
-
`HttpOnly`, и из JS её не выставить.
|
|
203
|
-
|
|
204
|
-
**Сервер выдаёт при каждом продлении новый refresh-токен взамен прежнего.** Со штатным
|
|
205
|
-
`storage` это происходит само. Если же вы храните сессию сами, снимайте её после каждого
|
|
206
|
-
обновления, а не один раз при входе, — иначе сохранённое значение протухнет:
|
|
207
|
-
|
|
208
|
-
```ts
|
|
209
|
-
itd.on('tokens', async () => saveSomewhere(await itd.getSession()));
|
|
210
|
-
|
|
211
|
-
// при следующем запуске
|
|
212
|
-
await itd.setSession(await loadFromSomewhere());
|
|
213
|
-
```
|
|
102
|
+
Личные прокси, общая или раздельные очереди, собственное хранилище и события контейнера
|
|
103
|
+
описаны в [руководстве по нескольким аккаунтам](./guides/multi-accounts/README.md).
|
|
214
104
|
|
|
215
105
|
---
|
|
216
106
|
|
|
@@ -287,25 +177,48 @@ await itd.posts.create(draft.content('второй')); // заготовка
|
|
|
287
177
|
Файлы из `attach()` загружаются автоматически, порядок вложений сохраняется, MIME-тип
|
|
288
178
|
проверяется до отправки.
|
|
289
179
|
|
|
290
|
-
Разметка текста
|
|
291
|
-
|
|
292
|
-
|
|
180
|
+
### Разметка текста
|
|
181
|
+
|
|
182
|
+
Билдер собирает текст и сам считает смещения:
|
|
293
183
|
|
|
294
184
|
```ts
|
|
295
|
-
import {
|
|
296
|
-
|
|
297
|
-
await itd.posts.create(
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
185
|
+
import { post, renderSpans } from 'itd-api';
|
|
186
|
+
|
|
187
|
+
const created = await itd.posts.create(
|
|
188
|
+
post().markup((m) =>
|
|
189
|
+
m
|
|
190
|
+
.text('смотрите ')
|
|
191
|
+
.hashtag('котики')
|
|
192
|
+
.text(' от ')
|
|
193
|
+
.mention('durov')
|
|
194
|
+
.text(': ')
|
|
195
|
+
.bold('важно'),
|
|
196
|
+
),
|
|
197
|
+
);
|
|
198
|
+
|
|
199
|
+
renderSpans(created.content, created.spans); // безопасный HTML по умолчанию
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
Доступны `bold`, `italic`, `underline`, `strike`, `spoiler`, `monospace`, `quote`, `link`,
|
|
203
|
+
`hashtag`, `mention`, `span()` и несколько стилей сразу через `styled()`. Вложенные и
|
|
204
|
+
пересекающиеся spans поддерживаются. Смещения измеряются в единицах UTF-16, как индексы
|
|
205
|
+
строк и DOM Selection в JavaScript.
|
|
206
|
+
|
|
207
|
+
Для обычного текста есть автоматическое обнаружение ссылок, хэштегов и упоминаний:
|
|
208
|
+
|
|
209
|
+
```ts
|
|
210
|
+
await itd.posts.create(post('#котики от @durov: https://example.com').autoSpans());
|
|
304
211
|
```
|
|
305
212
|
|
|
306
|
-
|
|
213
|
+
`renderSpans()` также выводит Markdown и ANSI и позволяет настроить маршруты упоминаний,
|
|
214
|
+
хэштегов и префикс CSS-классов. Вызов `postBuilder.content(newText)` сбрасывает прежние
|
|
215
|
+
spans, поскольку они рассчитаны для другого текста. `posts.update()` принимает тот же билдер,
|
|
216
|
+
но требует явно заданный `content`.
|
|
217
|
+
|
|
218
|
+
Авторазметка, пересекающиеся стили, обновление и настройка рендера подробно разобраны
|
|
219
|
+
в [руководстве по разметке](./guides/text-markup/README.md).
|
|
307
220
|
|
|
308
|
-
Билдеры есть у поста, комментария, опроса и жалобы. Все они неизменяемые, а `build()`
|
|
221
|
+
Билдеры есть у разметки, поста, комментария, опроса и жалобы. Все они неизменяемые, а `build()`
|
|
309
222
|
проверяет данные и бросает `ItdConfigError` **до** обращения к сети:
|
|
310
223
|
|
|
311
224
|
```ts
|
|
@@ -328,33 +241,13 @@ stream.on('notification', ({ notification }) => {
|
|
|
328
241
|
console.log(formatNotificationText(notification)); // «Аня и ещё 2 оценили ваш пост»
|
|
329
242
|
console.log(resolveNotificationUrl(notification)); // '/@anya/post/9f1c…'
|
|
330
243
|
});
|
|
331
|
-
stream.on('unreadCount', (count) => setBadge(count));
|
|
332
244
|
|
|
333
245
|
await stream.connect();
|
|
334
246
|
```
|
|
335
247
|
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
Уведомления из потока и из `itd.notifications.list()` приведены к общей форме, поэтому
|
|
340
|
-
складываются в один список. Сервер называет типы коротко (`like`, `comment`, `repost`),
|
|
341
|
-
библиотека приводит их к однозначным (`post_reaction`, `post_comment`, `post_repost`),
|
|
342
|
-
а пришедшее значение оставляет в `rawType`; весь исходный объект — в `raw`.
|
|
343
|
-
|
|
344
|
-
`resolveNotificationUrl()` учитывает, что смысл полей зависит от типа: у комментария
|
|
345
|
-
цель — пост, а предмет — сам комментарий; у репоста наоборот, цель — репост, а предмет —
|
|
346
|
-
исходная запись. Поэтому ссылка на комментарий ведёт на пост с якорем, а на репост —
|
|
347
|
-
на сам репост.
|
|
348
|
-
|
|
349
|
-
Соединение держится само: обрывы, продление токена и повторные попытки
|
|
350
|
-
(`[1, 2, 4, 8, 16, 30] с`, джиттер ±30%, 15 попыток подряд) обрабатываются внутри.
|
|
351
|
-
Сервер шлёт keep-alive `: ping` каждые 15 секунд; если тишина длится дольше `idleTimeout`
|
|
352
|
-
(90 секунд по умолчанию), соединение считается мёртвым и поднимается заново.
|
|
353
|
-
В браузере поток дополнительно переподключается при возврате вкладки из фона
|
|
354
|
-
и восстановлении сети.
|
|
355
|
-
|
|
356
|
-
> Счётчик непрочитанных сервер по потоку **не присылает** — событие `unreadCount`
|
|
357
|
-
> на практике не срабатывает. Считайте сами либо запрашивайте `itd.notifications.count()`.
|
|
248
|
+
REST и поток используют одну форму уведомления. Переподключение, refresh token, keep-alive
|
|
249
|
+
и fallback на polling обрабатываются внутри. Эксплуатационные настройки и счётчик
|
|
250
|
+
непрочитанных разобраны в [руководстве по realtime](./guides/realtime/README.md).
|
|
358
251
|
|
|
359
252
|
---
|
|
360
253
|
|
|
@@ -407,6 +300,11 @@ await itd.request({ method: 'GET', service: 'pb', path: '/api/pixel-info', query
|
|
|
407
300
|
То же самое после создания клиента — `itd.defineService({ name, baseUrl, headers, auth })`;
|
|
408
301
|
базовый URL сервиса отдаёт `itd.serviceBaseUrl(name)`.
|
|
409
302
|
|
|
303
|
+
Bearer-токен по умолчанию отправляется только основному хосту и его поддоменам.
|
|
304
|
+
Публичный или сторонний сервис его не получает. То же правило действует для разового
|
|
305
|
+
`itd.request({ baseUrl })`; если внешнему хосту действительно нужна авторизация,
|
|
306
|
+
разрешите её явно через `skipAuth: false`.
|
|
307
|
+
|
|
410
308
|
У каждого сервиса своя очередь `rateLimit`: лимит частоты сервер считает по хосту, поэтому
|
|
411
309
|
`429` от статуса не тормозит основной API и наоборот.
|
|
412
310
|
|
|
@@ -538,93 +436,32 @@ await fetch.close(); // закрывает пул соединений
|
|
|
538
436
|
```
|
|
539
437
|
|
|
540
438
|
Через тот же `fetch` пойдут авторизация, cookie, очередь, повторы и поток уведомлений.
|
|
541
|
-
Только для Node/Bun/Deno.
|
|
439
|
+
Только для Node/Bun/Deno. Подключение proxy и Turnstile разобрано в
|
|
440
|
+
[руководстве по интеграциям](./guides/integrations/README.md), параметры транспорта — в
|
|
441
|
+
[README пакета](./proxy/README.md).
|
|
542
442
|
|
|
543
443
|
---
|
|
544
444
|
|
|
545
445
|
## Плагины
|
|
546
446
|
|
|
547
|
-
Плагин
|
|
548
|
-
одна обёртка охватывает сразу все методы клиента. Подключается через `itd.use()`:
|
|
447
|
+
Плагин оборачивает запросы и ответы сразу всех ресурсов:
|
|
549
448
|
|
|
550
449
|
```ts
|
|
551
450
|
import { ItdClient } from 'itd-api';
|
|
552
|
-
import {
|
|
451
|
+
import { cache } from '@itd-api/cache';
|
|
553
452
|
|
|
554
453
|
const itd = new ItdClient({ auth: token });
|
|
555
|
-
itd.use(
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
[Отдельный пакет](./crypto/README.md): прячет текст в невидимых символах внутри обычного поста.
|
|
561
|
-
Читатель видит обложку, а тот, у кого подключён плагин, получает спрятанное отдельным полем.
|
|
562
|
-
|
|
563
|
-
```sh
|
|
564
|
-
npm i @itd-api/crypto
|
|
565
|
-
```
|
|
566
|
-
|
|
567
|
-
```ts
|
|
568
|
-
// отправка: текст прогоняется через шифр, обложка остаётся видимой
|
|
569
|
-
const created = await itd.posts.create(
|
|
570
|
-
{ content: 'секретный текст' },
|
|
571
|
-
{ encrypt: { cipher: 'invisible', cover: 'обычный пост' } },
|
|
454
|
+
itd.use(
|
|
455
|
+
cache({
|
|
456
|
+
ttl: 60_000,
|
|
457
|
+
routes: ['users.get', 'posts.get', 'posts.list'],
|
|
458
|
+
}),
|
|
572
459
|
);
|
|
573
|
-
|
|
574
|
-
// чтение: content не меняется, расшифровка приезжает рядом
|
|
575
|
-
const post = await itd.posts.get(created.id);
|
|
576
|
-
post.secret?.text; // 'секретный текст'
|
|
577
|
-
```
|
|
578
|
-
|
|
579
|
-
Работает для постов, комментариев, ответов, имени и подписи профиля. Расшифровка идёт сама
|
|
580
|
-
и вглубь: находки появляются и у постов ленты, и у исходного поста репоста, и у авторов.
|
|
581
|
-
|
|
582
|
-
Шифра два: `invisible` — невидимые символы с обложкой, `beecrypt` — видимый текст из букв
|
|
583
|
-
`жъЖЪ`. Подробности, ограничения и то, как подключить свой шифр, — в
|
|
584
|
-
[README пакета](./crypto/README.md).
|
|
585
|
-
|
|
586
|
-
### Свой плагин
|
|
587
|
-
|
|
588
|
-
```ts
|
|
589
|
-
import type { ItdPlugin } from 'itd-api';
|
|
590
|
-
|
|
591
|
-
const timing: ItdPlugin = {
|
|
592
|
-
name: 'timing',
|
|
593
|
-
install({ use, logger }) {
|
|
594
|
-
use(async (request, next) => {
|
|
595
|
-
const started = Date.now();
|
|
596
|
-
try {
|
|
597
|
-
return await next(request);
|
|
598
|
-
} finally {
|
|
599
|
-
logger?.info(`${request.method} ${request.path}: ${Date.now() - started} мс`);
|
|
600
|
-
}
|
|
601
|
-
});
|
|
602
|
-
},
|
|
603
|
-
};
|
|
604
|
-
```
|
|
605
|
-
|
|
606
|
-
Обёртка может изменить запрос (передайте в `next` копию), подменить ответ или вернуть своё,
|
|
607
|
-
не обращаясь к сети. Подключённая раньше оказывается снаружи. Выполняется она один раз
|
|
608
|
-
на запрос, независимо от числа повторов.
|
|
609
|
-
|
|
610
|
-
Свои опции запроса плагин объявляет сам — библиотека их не понимает, но доносит до обёртки
|
|
611
|
-
нетронутыми:
|
|
612
|
-
|
|
613
|
-
```ts
|
|
614
|
-
const plugin: ItdPlugin = {
|
|
615
|
-
name: 'мой',
|
|
616
|
-
optionKeys: ['мояОпция'],
|
|
617
|
-
install({ use }) { /* … */ },
|
|
618
|
-
};
|
|
619
|
-
|
|
620
|
-
declare module 'itd-api' {
|
|
621
|
-
interface RequestOptions { мояОпция?: string | undefined }
|
|
622
|
-
}
|
|
623
460
|
```
|
|
624
461
|
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
462
|
+
Официальные плагины Cache и Crypto, полный контракт `ItdPlugin`, собственные опции и
|
|
463
|
+
структура пакета описаны в
|
|
464
|
+
[руководстве по плагинам](./guides/plugins/README.md).
|
|
628
465
|
|
|
629
466
|
---
|
|
630
467
|
|
|
@@ -644,6 +481,7 @@ declare module 'itd-api' {
|
|
|
644
481
|
| `itd.realtime()` | поток уведомлений |
|
|
645
482
|
| `itd.use()` | плагины: обёртки вокруг запроса и ответа |
|
|
646
483
|
| `itd.request()` | произвольный запрос, если метода ещё нет |
|
|
484
|
+
| `ItdAccounts` | несколько аккаунтов с общим хранилищем сессий |
|
|
647
485
|
|
|
648
486
|
Метода не хватает или ответ разошёлся с документацией — есть запасной путь:
|
|
649
487
|
|
|
@@ -671,7 +509,7 @@ TypeScript 5.0+. Пакет собран в ESM и CommonJS, типы корре
|
|
|
671
509
|
|
|
672
510
|
```bash
|
|
673
511
|
npm install
|
|
674
|
-
npm test #
|
|
512
|
+
npm test # 611 тестов
|
|
675
513
|
npm run test:all # вместе с пакетами workspace
|
|
676
514
|
npm run typecheck
|
|
677
515
|
npm run lint
|