itd-api 0.1.0 → 0.2.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 +114 -489
- package/dist/index.cjs +8781 -415
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +4990 -1
- package/dist/index.d.ts +4990 -1
- package/dist/index.js +8688 -2
- package/dist/index.js.map +1 -1
- package/dist/multi-storage-BhcA2Izn.d.ts +198 -0
- package/dist/multi-storage-CyMe404l.js +805 -0
- package/dist/multi-storage-CyMe404l.js.map +1 -0
- package/dist/multi-storage-D1keK2Op.cjs +930 -0
- package/dist/multi-storage-D1keK2Op.cjs.map +1 -0
- package/dist/multi-storage-NDqzRQcD.d.cts +198 -0
- package/dist/node.cjs +225 -548
- package/dist/node.cjs.map +1 -1
- package/dist/node.d.cts +46 -59
- package/dist/node.d.ts +46 -59
- package/dist/node.js +223 -126
- package/dist/node.js.map +1 -1
- package/dist/runtime-CFEsf-jD.cjs +185 -0
- package/dist/runtime-CFEsf-jD.cjs.map +1 -0
- package/dist/runtime-DHxDn8gf.js +126 -0
- package/dist/runtime-DHxDn8gf.js.map +1 -0
- package/dist/storage-BjNRlkbE.d.cts +82 -0
- package/dist/storage-BjNRlkbE.d.ts +82 -0
- package/dist/storage-D9tfHx7Z.js +424 -0
- package/dist/storage-D9tfHx7Z.js.map +1 -0
- package/dist/storage-ycBqLBRB.cjs +615 -0
- package/dist/storage-ycBqLBRB.cjs.map +1 -0
- package/dist/web.cjs +87 -0
- package/dist/web.cjs.map +1 -0
- package/dist/web.d.cts +27 -0
- package/dist/web.d.ts +27 -0
- package/dist/web.js +86 -0
- package/dist/web.js.map +1 -0
- package/package.json +34 -14
- package/dist/chunk-6FB4HTKH.js +0 -7763
- package/dist/chunk-6FB4HTKH.js.map +0 -1
- package/dist/chunk-73CISRBG.cjs +0 -7873
- package/dist/chunk-73CISRBG.cjs.map +0 -1
- package/dist/index-BZF4K90s.d.cts +0 -4961
- package/dist/index-BZF4K90s.d.ts +0 -4961
- package/guides/README.md +0 -24
- package/guides/authentication/README.md +0 -176
- package/guides/authentication/examples/bot-with-session.mjs +0 -98
- package/guides/authentication/examples/turnstile-login.mjs +0 -56
- package/guides/integrations/README.md +0 -62
- package/guides/integrations/examples/proxy.mjs +0 -26
- package/guides/multi-accounts/README.md +0 -143
- package/guides/multi-accounts/examples/multi-accounts.mjs +0 -71
- package/guides/plugins/README.md +0 -253
- package/guides/plugins/examples/cache.mjs +0 -33
- package/guides/plugins/examples/crypto.mjs +0 -54
- package/guides/quickstart/README.md +0 -124
- package/guides/quickstart/examples/quick-start.mjs +0 -44
- package/guides/quickstart/examples/typescript.ts +0 -90
- package/guides/realtime/README.md +0 -109
- package/guides/realtime/examples/notifications.mjs +0 -62
- package/guides/reference/README.md +0 -67
- package/guides/reference/accounts.md +0 -101
- package/guides/reference/auth.md +0 -141
- package/guides/reference/builders.md +0 -135
- package/guides/reference/client.md +0 -184
- package/guides/reference/comments.md +0 -58
- package/guides/reference/discovery.md +0 -81
- package/guides/reference/enums.md +0 -103
- package/guides/reference/errors.md +0 -107
- package/guides/reference/files.md +0 -73
- package/guides/reference/models.md +0 -448
- package/guides/reference/notifications.md +0 -77
- package/guides/reference/pagination.md +0 -82
- package/guides/reference/platform.md +0 -47
- package/guides/reference/posts.md +0 -157
- package/guides/reference/realtime.md +0 -78
- package/guides/reference/reports.md +0 -28
- package/guides/reference/subscription.md +0 -41
- package/guides/reference/users.md +0 -146
- package/guides/reference/verification.md +0 -24
- package/guides/text-markup/README.md +0 -214
- package/guides/text-markup/examples/create-post.mjs +0 -64
package/guides/plugins/README.md
DELETED
|
@@ -1,253 +0,0 @@
|
|
|
1
|
-
# Плагины
|
|
2
|
-
|
|
3
|
-
Плагин расширяет клиент обёртками вокруг запросов и ответов. Одна установка действует на
|
|
4
|
-
все ресурсы:
|
|
5
|
-
|
|
6
|
-
```ts
|
|
7
|
-
import { ItdClient } from 'itd-api';
|
|
8
|
-
import { crypt } from '@itd-api/crypto';
|
|
9
|
-
|
|
10
|
-
const itd = new ItdClient({ auth: token });
|
|
11
|
-
itd.use(crypt());
|
|
12
|
-
```
|
|
13
|
-
|
|
14
|
-
## Cache
|
|
15
|
-
|
|
16
|
-
```bash
|
|
17
|
-
npm install @itd-api/cache
|
|
18
|
-
```
|
|
19
|
-
|
|
20
|
-
```ts
|
|
21
|
-
import { cache } from '@itd-api/cache';
|
|
22
|
-
|
|
23
|
-
const cached = cache({
|
|
24
|
-
ttl: 60_000,
|
|
25
|
-
routes: ['users.get', 'posts.get', 'posts.list'],
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
itd.use(cached);
|
|
29
|
-
```
|
|
30
|
-
|
|
31
|
-
Плагин хранит успешные ответы в LRU-кэше и объединяет одновременные одинаковые запросы.
|
|
32
|
-
Маршруты выбираются явно; после мутаций связанные данные инвалидируются автоматически.
|
|
33
|
-
У каждого клиента и аккаунта свой раздел кэша, а изменения общих сущностей сбрасывают
|
|
34
|
-
соответствующие маршруты во всех разделах.
|
|
35
|
-
|
|
36
|
-
```ts
|
|
37
|
-
await itd.posts.get(postId, { cache: 'reload' });
|
|
38
|
-
cached.invalidate('posts.get');
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
Полный каталог маршрутов, подключение к нескольким клиентам и привязка к realtime описаны в
|
|
42
|
-
[README пакета](../../cache/README.md).
|
|
43
|
-
|
|
44
|
-
Запускаемый пример:
|
|
45
|
-
|
|
46
|
-
```bash
|
|
47
|
-
ITD_TOKEN=<accessToken> ITD_POST_ID=<postId> \
|
|
48
|
-
node guides/plugins/examples/cache.mjs
|
|
49
|
-
```
|
|
50
|
-
|
|
51
|
-
## Crypto
|
|
52
|
-
|
|
53
|
-
```bash
|
|
54
|
-
npm install @itd-api/crypto
|
|
55
|
-
```
|
|
56
|
-
|
|
57
|
-
```ts
|
|
58
|
-
import { crypt } from '@itd-api/crypto';
|
|
59
|
-
|
|
60
|
-
itd.use(crypt());
|
|
61
|
-
|
|
62
|
-
const created = await itd.posts.create(
|
|
63
|
-
{ content: 'секретный текст' },
|
|
64
|
-
{ encrypt: { cipher: 'invisible', cover: 'обычный пост' } },
|
|
65
|
-
);
|
|
66
|
-
|
|
67
|
-
const post = await itd.posts.get(created.id);
|
|
68
|
-
console.log(post.content); // обложка
|
|
69
|
-
console.log(post.secret?.text); // секретный текст
|
|
70
|
-
```
|
|
71
|
-
|
|
72
|
-
Плагин обрабатывает посты, комментарии, ответы и текстовые поля профиля. Доступны
|
|
73
|
-
`invisible` и `beecrypt`; подробные ограничения описаны в README пакета.
|
|
74
|
-
|
|
75
|
-
Запускаемый пример:
|
|
76
|
-
|
|
77
|
-
```bash
|
|
78
|
-
ITD_TOKEN=<accessToken> node guides/plugins/examples/crypto.mjs
|
|
79
|
-
```
|
|
80
|
-
|
|
81
|
-
## Собственный плагин
|
|
82
|
-
|
|
83
|
-
```ts
|
|
84
|
-
import type { ItdPlugin } from 'itd-api';
|
|
85
|
-
|
|
86
|
-
const timing: ItdPlugin = {
|
|
87
|
-
name: 'timing',
|
|
88
|
-
install({ use, logger }) {
|
|
89
|
-
use(async (request, next) => {
|
|
90
|
-
const started = Date.now();
|
|
91
|
-
try {
|
|
92
|
-
return await next(request);
|
|
93
|
-
} finally {
|
|
94
|
-
logger?.info(`${request.method} ${request.path}: ${Date.now() - started} мс`);
|
|
95
|
-
}
|
|
96
|
-
});
|
|
97
|
-
},
|
|
98
|
-
};
|
|
99
|
-
|
|
100
|
-
itd.use(timing);
|
|
101
|
-
```
|
|
102
|
-
|
|
103
|
-
Обёртка может:
|
|
104
|
-
|
|
105
|
-
- передать в `next()` изменённую копию запроса;
|
|
106
|
-
- изменить полученный ответ;
|
|
107
|
-
- вернуть результат без обращения к сети;
|
|
108
|
-
- выбросить собственную ошибку.
|
|
109
|
-
|
|
110
|
-
Без явных правил подключённая раньше обёртка оказывается снаружи. Она выполняется один раз
|
|
111
|
-
на логический запрос, независимо от внутренних повторов транспорта.
|
|
112
|
-
|
|
113
|
-
## Порядок и зависимости
|
|
114
|
-
|
|
115
|
-
Плагин может описать отношения с другими плагинами:
|
|
116
|
-
|
|
117
|
-
```ts
|
|
118
|
-
const tracing: ItdPlugin = {
|
|
119
|
-
name: 'tracing',
|
|
120
|
-
before: ['cache'], // обёртка tracing снаружи cache
|
|
121
|
-
requires: ['transport'], // без transport подключение завершится ошибкой
|
|
122
|
-
conflicts: ['legacy-tracing'],
|
|
123
|
-
install({ use }) {
|
|
124
|
-
use((request, next) => next(request));
|
|
125
|
-
},
|
|
126
|
-
};
|
|
127
|
-
```
|
|
128
|
-
|
|
129
|
-
- `before` ставит плагин снаружи названных;
|
|
130
|
-
- `after` — внутри названных;
|
|
131
|
-
- `requires` требует уже подключённый плагин и ставит его раньше зависимого;
|
|
132
|
-
- `conflicts` запрещает совместное подключение, даже если конфликт объявлен только одной
|
|
133
|
-
стороной.
|
|
134
|
-
|
|
135
|
-
Ссылки `before` и `after` на ещё не подключённый плагин допустимы: порядок перестроится,
|
|
136
|
-
когда тот появится. Цикл отклоняется до вызова `install()`.
|
|
137
|
-
|
|
138
|
-
Фактический порядок можно проверить:
|
|
139
|
-
|
|
140
|
-
```ts
|
|
141
|
-
itd.pluginNames();
|
|
142
|
-
itd.hasPlugin('cache');
|
|
143
|
-
```
|
|
144
|
-
|
|
145
|
-
## Хуки отдельных попыток
|
|
146
|
-
|
|
147
|
-
`use()` видит логический запрос один раз. Для метрик и трассировки есть `useHooks()`:
|
|
148
|
-
|
|
149
|
-
```ts
|
|
150
|
-
const telemetry: ItdPlugin = {
|
|
151
|
-
name: 'telemetry',
|
|
152
|
-
install({ useHooks }) {
|
|
153
|
-
useHooks({
|
|
154
|
-
onRequest({ method, path, attempt }) {
|
|
155
|
-
console.log(`попытка ${attempt}: ${method} ${path}`);
|
|
156
|
-
},
|
|
157
|
-
onResponse({ status, duration }) {
|
|
158
|
-
console.log(status, duration);
|
|
159
|
-
},
|
|
160
|
-
onError({ error, duration }) {
|
|
161
|
-
console.error(error, duration);
|
|
162
|
-
},
|
|
163
|
-
onRetry({ attempt, delay }) {
|
|
164
|
-
console.log(`после попытки ${attempt} ждём ${delay} мс`);
|
|
165
|
-
},
|
|
166
|
-
});
|
|
167
|
-
},
|
|
168
|
-
};
|
|
169
|
-
```
|
|
170
|
-
|
|
171
|
-
Хуки, заданные в конструкторе `ItdClient`, вызываются раньше хуков плагинов. Исключение
|
|
172
|
-
из хука прерывает запрос — плагину наблюдаемости лучше обрабатывать собственные ошибки
|
|
173
|
-
внутри.
|
|
174
|
-
|
|
175
|
-
## Отключение и очистка
|
|
176
|
-
|
|
177
|
-
`install()` может вернуть синхронную или асинхронную функцию очистки:
|
|
178
|
-
|
|
179
|
-
```ts
|
|
180
|
-
const plugin: ItdPlugin = {
|
|
181
|
-
name: 'connection',
|
|
182
|
-
install({ use }) {
|
|
183
|
-
const connection = openConnection();
|
|
184
|
-
use((request, next) => next(request));
|
|
185
|
-
|
|
186
|
-
return () => connection.close();
|
|
187
|
-
},
|
|
188
|
-
};
|
|
189
|
-
|
|
190
|
-
itd.use(plugin);
|
|
191
|
-
await itd.unuse('connection');
|
|
192
|
-
```
|
|
193
|
-
|
|
194
|
-
Новые запросы перестают видеть плагин сразу, а teardown ждёт завершения запроса, который
|
|
195
|
-
уже проходит через его обёртку. Обязательную зависимость нельзя отключить раньше зависящего
|
|
196
|
-
от неё плагина.
|
|
197
|
-
|
|
198
|
-
`close()` по-прежнему временно останавливает очередь и realtime, не отключая плагины.
|
|
199
|
-
`dispose()` делает окончательную очистку и вызывает teardown всех плагинов изнутри наружу.
|
|
200
|
-
`await using` вызывает `dispose()` автоматически.
|
|
201
|
-
|
|
202
|
-
## Собственные опции метода
|
|
203
|
-
|
|
204
|
-
Плагин объявляет разрешённые ключи:
|
|
205
|
-
|
|
206
|
-
```ts
|
|
207
|
-
const plugin: ItdPlugin = {
|
|
208
|
-
name: 'мой',
|
|
209
|
-
optionKeys: ['мояОпция'],
|
|
210
|
-
install({ use }) {
|
|
211
|
-
use(async (request, next) => {
|
|
212
|
-
console.log(request.мояОпция);
|
|
213
|
-
return next(request);
|
|
214
|
-
});
|
|
215
|
-
},
|
|
216
|
-
};
|
|
217
|
-
|
|
218
|
-
declare module 'itd-api' {
|
|
219
|
-
interface RequestOptions {
|
|
220
|
-
мояОпция?: string | undefined;
|
|
221
|
-
}
|
|
222
|
-
}
|
|
223
|
-
```
|
|
224
|
-
|
|
225
|
-
Ключи самого запроса — `path`, `body`, `headers`, `signal` и другие системные поля —
|
|
226
|
-
зарезервированы. Плагин с конфликтующим `optionKeys` отклоняется при подключении.
|
|
227
|
-
|
|
228
|
-
## Несколько аккаунтов
|
|
229
|
-
|
|
230
|
-
```ts
|
|
231
|
-
accounts.use(plugin);
|
|
232
|
-
await accounts.unuse(plugin.name);
|
|
233
|
-
```
|
|
234
|
-
|
|
235
|
-
Плагин установится всем существующим аккаунтам и будет автоматически применяться к новым.
|
|
236
|
-
`accounts.pluginNames()` и `accounts.hasPlugin()` описывают общий набор.
|
|
237
|
-
|
|
238
|
-
## Структура нового плагина
|
|
239
|
-
|
|
240
|
-
Структура пакета плагина:
|
|
241
|
-
|
|
242
|
-
```text
|
|
243
|
-
my-plugin/
|
|
244
|
-
├── package.json
|
|
245
|
-
├── README.md
|
|
246
|
-
├── src/
|
|
247
|
-
│ └── index.ts
|
|
248
|
-
└── test/
|
|
249
|
-
└── plugin.test.ts
|
|
250
|
-
```
|
|
251
|
-
|
|
252
|
-
Пакет должен иметь собственные тесты, сборку и экспортировать фабрику либо объект,
|
|
253
|
-
совместимый с `ItdPlugin`.
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Запуск:
|
|
3
|
-
* ITD_TOKEN=<accessToken> ITD_POST_ID=<postId> \
|
|
4
|
-
* node guides/plugins/examples/cache.mjs
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import { cache } from '@itd-api/cache';
|
|
8
|
-
import { ItdClient } from 'itd-api';
|
|
9
|
-
|
|
10
|
-
const token = process.env.ITD_TOKEN;
|
|
11
|
-
const postId = process.env.ITD_POST_ID;
|
|
12
|
-
|
|
13
|
-
if (!token || !postId) {
|
|
14
|
-
throw new Error('Передайте ITD_TOKEN и ITD_POST_ID');
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
const itd = new ItdClient({ auth: token });
|
|
18
|
-
const cached = cache({
|
|
19
|
-
ttl: 60_000,
|
|
20
|
-
routes: ['posts.get', 'users.get'],
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
itd.use(cached);
|
|
24
|
-
|
|
25
|
-
try {
|
|
26
|
-
const first = await itd.posts.get(postId);
|
|
27
|
-
const second = await itd.posts.get(postId);
|
|
28
|
-
|
|
29
|
-
console.log(first.content);
|
|
30
|
-
console.log(`Повторный ответ получен из кэша: ${first.id === second.id}`);
|
|
31
|
-
} finally {
|
|
32
|
-
await itd.close();
|
|
33
|
-
}
|
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Скрытое сообщение в обычном посте.
|
|
3
|
-
*
|
|
4
|
-
* Запуск:
|
|
5
|
-
* ITD_TOKEN=<accessToken> node guides/plugins/examples/crypto.mjs
|
|
6
|
-
*
|
|
7
|
-
* Плагин лежит в отдельном пакете — основному он не нужен:
|
|
8
|
-
*
|
|
9
|
-
* npm i @itd-api/crypto
|
|
10
|
-
*
|
|
11
|
-
* Пример публикует пост, читает его обратно **с сервера** и сравнивает результат.
|
|
12
|
-
* Смысл именно в обратном чтении: сервер итд.com нормализует текст поста при сохранении,
|
|
13
|
-
* и проверить, что нагрузка это пережила, можно только на живом API.
|
|
14
|
-
*/
|
|
15
|
-
|
|
16
|
-
import { ItdClient, isItdApiError } from 'itd-api';
|
|
17
|
-
import { crypt, stripInvisible } from '@itd-api/crypto';
|
|
18
|
-
|
|
19
|
-
const COVER = 'обычный пост, ничего необычного';
|
|
20
|
-
const SECRET = 'секретный текст: 🦎 привет из @itd-api/crypto';
|
|
21
|
-
|
|
22
|
-
const itd = new ItdClient({ auth: process.env.ITD_TOKEN });
|
|
23
|
-
|
|
24
|
-
// Одна строка — и шифрование доступно во всех методах, принимающих текст.
|
|
25
|
-
itd.use(crypt());
|
|
26
|
-
|
|
27
|
-
try {
|
|
28
|
-
const created = await itd.posts.create(
|
|
29
|
-
{ content: SECRET },
|
|
30
|
-
{ encrypt: { cipher: 'invisible', cover: COVER } },
|
|
31
|
-
);
|
|
32
|
-
console.log(`Опубликован пост ${created.id}`);
|
|
33
|
-
|
|
34
|
-
// Читаем с сервера, а не берём ответ на публикацию: интересно именно то,
|
|
35
|
-
// что сохранилось после нормализации.
|
|
36
|
-
const post = await itd.posts.get(created.id);
|
|
37
|
-
|
|
38
|
-
console.log(`Видят все: ${stripInvisible(post.content)}`);
|
|
39
|
-
console.log(`Спрятано: ${post.secret?.text ?? '— ничего не нашлось —'}`);
|
|
40
|
-
console.log(`Длина: ${post.content.length} символов вместо ${COVER.length}`);
|
|
41
|
-
|
|
42
|
-
console.log(
|
|
43
|
-
post.secret?.text === SECRET
|
|
44
|
-
? '✔ сообщение пережило сохранение на сервере'
|
|
45
|
-
: '✘ сообщение потерялось — формат разошёлся с тем, что делает сервер',
|
|
46
|
-
);
|
|
47
|
-
|
|
48
|
-
// Прибираем за собой: пост нужен был только для проверки.
|
|
49
|
-
await itd.posts.remove(created.id);
|
|
50
|
-
console.log('Пост удалён');
|
|
51
|
-
} catch (error) {
|
|
52
|
-
console.error(isItdApiError(error) ? `${error.code}: ${error.message}` : error);
|
|
53
|
-
process.exitCode = 1;
|
|
54
|
-
}
|
|
@@ -1,124 +0,0 @@
|
|
|
1
|
-
# Быстрый старт
|
|
2
|
-
|
|
3
|
-
## Установка
|
|
4
|
-
|
|
5
|
-
```bash
|
|
6
|
-
npm install itd-api
|
|
7
|
-
```
|
|
8
|
-
|
|
9
|
-
Пакет поддерживает ESM и CommonJS, Node 18+, браузер, Bun, Deno и React Native.
|
|
10
|
-
|
|
11
|
-
## Создание клиента
|
|
12
|
-
|
|
13
|
-
```ts
|
|
14
|
-
import { FeedTab, ItdClient } from 'itd-api';
|
|
15
|
-
|
|
16
|
-
const itd = new ItdClient({
|
|
17
|
-
auth: process.env.ITD_TOKEN,
|
|
18
|
-
});
|
|
19
|
-
|
|
20
|
-
const me = await itd.users.me();
|
|
21
|
-
console.log(`@${me.username}, подписчиков: ${me.followersCount}`);
|
|
22
|
-
|
|
23
|
-
for await (const post of itd.posts.iterate({ tab: FeedTab.Following })) {
|
|
24
|
-
console.log(post.author.username, post.content);
|
|
25
|
-
if (!post.isLiked) await itd.posts.like(post.id);
|
|
26
|
-
}
|
|
27
|
-
```
|
|
28
|
-
|
|
29
|
-
Для загрузки файлов по пути и файлового хранилища сессии используйте Node-вход:
|
|
30
|
-
|
|
31
|
-
```ts
|
|
32
|
-
import { FileTokenStorage, ItdClient } from 'itd-api/node';
|
|
33
|
-
|
|
34
|
-
const itd = new ItdClient({
|
|
35
|
-
storage: new FileTokenStorage('./.itd-session.json'),
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
await itd.posts.create((p) =>
|
|
39
|
-
p.content('привет').attach('./photo.jpg'),
|
|
40
|
-
);
|
|
41
|
-
```
|
|
42
|
-
|
|
43
|
-
## Публикация
|
|
44
|
-
|
|
45
|
-
Методы принимают обычный объект, готовый билдер или функцию-настройщик:
|
|
46
|
-
|
|
47
|
-
```ts
|
|
48
|
-
import { post } from 'itd-api';
|
|
49
|
-
|
|
50
|
-
await itd.posts.create({ content: 'привет' });
|
|
51
|
-
|
|
52
|
-
await itd.posts.create((p) =>
|
|
53
|
-
p
|
|
54
|
-
.content('смотрите')
|
|
55
|
-
.attach('./photo.jpg')
|
|
56
|
-
.poll((q) => q.question('нравится?').options('да', 'нет')),
|
|
57
|
-
);
|
|
58
|
-
|
|
59
|
-
const draft = post().onWall(userId);
|
|
60
|
-
await itd.posts.create(draft.content('первый'));
|
|
61
|
-
await itd.posts.create(draft.content('второй'));
|
|
62
|
-
```
|
|
63
|
-
|
|
64
|
-
Билдеры неизменяемые, а `build()` проверяет данные до обращения к сети.
|
|
65
|
-
|
|
66
|
-
## Пагинация
|
|
67
|
-
|
|
68
|
-
```ts
|
|
69
|
-
for await (const post of itd.posts.iterate({ tab: 'popular' })) {
|
|
70
|
-
console.log(post.id);
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
const page = await itd.posts.list({ tab: 'popular', limit: 20 });
|
|
74
|
-
const next = await itd.posts.list({
|
|
75
|
-
tab: 'popular',
|
|
76
|
-
cursor: page.nextCursor ?? undefined,
|
|
77
|
-
});
|
|
78
|
-
```
|
|
79
|
-
|
|
80
|
-
Курсор непрозрачен — передавайте его обратно без разбора. Итератор одноразовый; для второго
|
|
81
|
-
прохода создайте новый.
|
|
82
|
-
|
|
83
|
-
## Ошибки
|
|
84
|
-
|
|
85
|
-
```ts
|
|
86
|
-
import {
|
|
87
|
-
ItdRateLimitError,
|
|
88
|
-
ItdValidationError,
|
|
89
|
-
isItdApiError,
|
|
90
|
-
} from 'itd-api';
|
|
91
|
-
|
|
92
|
-
try {
|
|
93
|
-
await itd.users.updateMe({ username: 'занятое_имя' });
|
|
94
|
-
} catch (error) {
|
|
95
|
-
if (error instanceof ItdValidationError) {
|
|
96
|
-
console.error(error.fieldErrors);
|
|
97
|
-
} else if (error instanceof ItdRateLimitError) {
|
|
98
|
-
console.error(error.retryAfter);
|
|
99
|
-
} else if (isItdApiError(error)) {
|
|
100
|
-
console.error(error.status, error.code, error.message);
|
|
101
|
-
} else {
|
|
102
|
-
throw error;
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
```
|
|
106
|
-
|
|
107
|
-
## Куда дальше
|
|
108
|
-
|
|
109
|
-
- [Авторизация и сессии](../authentication/README.md)
|
|
110
|
-
- [Разметка текста](../text-markup/README.md)
|
|
111
|
-
- [Realtime](../realtime/README.md)
|
|
112
|
-
- [Несколько аккаунтов](../multi-accounts/README.md)
|
|
113
|
-
- [Интеграции](../integrations/README.md)
|
|
114
|
-
- [Плагины](../plugins/README.md)
|
|
115
|
-
|
|
116
|
-
## Примеры
|
|
117
|
-
|
|
118
|
-
```bash
|
|
119
|
-
ITD_TOKEN=<accessToken> node guides/quickstart/examples/quick-start.mjs
|
|
120
|
-
npx tsx guides/quickstart/examples/typescript.ts
|
|
121
|
-
```
|
|
122
|
-
|
|
123
|
-
- [`examples/quick-start.mjs`](./examples/quick-start.mjs) — профиль и чтение ленты.
|
|
124
|
-
- [`examples/typescript.ts`](./examples/typescript.ts) — типы, билдеры, пагинация и ошибки.
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Быстрый старт: чтение ленты и реакция на пост.
|
|
3
|
-
*
|
|
4
|
-
* Запуск:
|
|
5
|
-
* ITD_TOKEN=<ваш accessToken> node guides/quickstart/examples/quick-start.mjs
|
|
6
|
-
*
|
|
7
|
-
* Где взять токен: откройте итд.com, войдите, затем в консоли браузера выполните
|
|
8
|
-
* запрос к /api/v1/auth/refresh — либо воспользуйтесь руководством по авторизации.
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
import { FeedTab, ItdClient, isItdApiError } from 'itd-api';
|
|
12
|
-
|
|
13
|
-
const itd = new ItdClient({
|
|
14
|
-
// Опции допускают undefined, поэтому переменную окружения можно передавать напрямую.
|
|
15
|
-
auth: process.env.ITD_TOKEN,
|
|
16
|
-
});
|
|
17
|
-
|
|
18
|
-
try {
|
|
19
|
-
const me = await itd.users.me();
|
|
20
|
-
console.log(`Вы вошли как ${me.displayName} (@${me.username})`);
|
|
21
|
-
console.log(`Подписчиков: ${me.followersCount}, записей: ${me.postsCount}\n`);
|
|
22
|
-
|
|
23
|
-
// Одна страница ленты.
|
|
24
|
-
const page = await itd.posts.list({ tab: FeedTab.Popular, limit: 5 });
|
|
25
|
-
|
|
26
|
-
for (const post of page.items) {
|
|
27
|
-
const text = post.content.slice(0, 60).replace(/\n/g, ' ');
|
|
28
|
-
console.log(`${post.author.avatar} @${post.author.username}: ${text}`);
|
|
29
|
-
console.log(` ❤ ${post.likesCount} 💬 ${post.commentsCount} 🔁 ${post.repostsCount}`);
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
// Перебор нескольких страниц: курсоры подставляются сами.
|
|
33
|
-
console.log('\nПервые 12 записей из подписок:');
|
|
34
|
-
|
|
35
|
-
const posts = await itd.posts.iterate({ tab: FeedTab.Following }).collect(12);
|
|
36
|
-
console.log(`получено ${posts.length}`);
|
|
37
|
-
} catch (error) {
|
|
38
|
-
if (isItdApiError(error)) {
|
|
39
|
-
console.error(`Ошибка API [${error.code}] ${error.status}: ${error.message}`);
|
|
40
|
-
if (Object.keys(error.fieldErrors).length > 0) console.error(error.fieldErrors);
|
|
41
|
-
} else {
|
|
42
|
-
throw error;
|
|
43
|
-
}
|
|
44
|
-
}
|
|
@@ -1,90 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* TypeScript: типы, билдеры и разбор ошибок.
|
|
3
|
-
*
|
|
4
|
-
* Запуск:
|
|
5
|
-
* npx tsx guides/quickstart/examples/typescript.ts
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import {
|
|
9
|
-
FeedTab,
|
|
10
|
-
ItdClient,
|
|
11
|
-
ItdValidationError,
|
|
12
|
-
type Notification,
|
|
13
|
-
type Post,
|
|
14
|
-
ReportReason,
|
|
15
|
-
isItdApiError,
|
|
16
|
-
ItdErrorCode,
|
|
17
|
-
ItdRateLimitError,
|
|
18
|
-
poll,
|
|
19
|
-
post,
|
|
20
|
-
report,
|
|
21
|
-
} from 'itd-api';
|
|
22
|
-
|
|
23
|
-
const itd = new ItdClient({ auth: process.env.ITD_TOKEN });
|
|
24
|
-
|
|
25
|
-
// ── Перечисления вместо магических строк ────────────────────────────────────────
|
|
26
|
-
// Работают обе формы: константа и обычная строка.
|
|
27
|
-
await itd.posts.list({ tab: FeedTab.Popular });
|
|
28
|
-
await itd.posts.list({ tab: 'following' });
|
|
29
|
-
|
|
30
|
-
// ── Заготовки билдеров переиспользуются ─────────────────────────────────────────
|
|
31
|
-
// Билдер неизменяемый, поэтому заготовку не испортить.
|
|
32
|
-
const draft = post().content('черновик');
|
|
33
|
-
|
|
34
|
-
const first: Post = await itd.posts.create(draft.append('первая версия'));
|
|
35
|
-
const second: Post = await itd.posts.create(draft.append('вторая версия'));
|
|
36
|
-
console.log(first.id, second.id);
|
|
37
|
-
|
|
38
|
-
// Опрос можно собрать заранее и передать в несколько записей.
|
|
39
|
-
const survey = poll('Какой язык удобнее?').options('TypeScript', 'JavaScript').multipleChoice();
|
|
40
|
-
await itd.posts.create({ content: 'голосуем', poll: survey });
|
|
41
|
-
|
|
42
|
-
// ── Пагинация: три способа ──────────────────────────────────────────────────────
|
|
43
|
-
// По элементам.
|
|
44
|
-
for await (const item of itd.posts.iterate({ tab: FeedTab.Popular })) {
|
|
45
|
-
console.log(item.content);
|
|
46
|
-
break;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
// По страницам — когда нужны сведения о самой странице.
|
|
50
|
-
for await (const page of itd.users.iterateFollowers('durov').pages()) {
|
|
51
|
-
console.log(`${page.items.length} из ${page.total ?? '?'}`);
|
|
52
|
-
break;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
// Собрать нужное количество и остановиться.
|
|
56
|
-
const top: Post[] = await itd.posts.iterate({ tab: FeedTab.Popular }).collect(50);
|
|
57
|
-
console.log(`собрано ${top.length}`);
|
|
58
|
-
|
|
59
|
-
// ── Разбор ошибок ───────────────────────────────────────────────────────────────
|
|
60
|
-
try {
|
|
61
|
-
await itd.users.updateMe({ username: 'занятое_имя' });
|
|
62
|
-
} catch (error) {
|
|
63
|
-
if (error instanceof ItdValidationError) {
|
|
64
|
-
// Обе формы ошибок API сведены к одной структуре.
|
|
65
|
-
for (const [field, messages] of Object.entries(error.fieldErrors)) {
|
|
66
|
-
console.error(`${field}: ${messages.join(', ')}`);
|
|
67
|
-
}
|
|
68
|
-
} else if (error instanceof ItdRateLimitError) {
|
|
69
|
-
console.error(`Лимит запросов, повтор через ${error.retryAfter ?? '?'} мс`);
|
|
70
|
-
} else if (isItdApiError(error) && error.hasCode(ItdErrorCode.PROFILE_USERNAME_TAKEN)) {
|
|
71
|
-
console.error('Имя уже занято');
|
|
72
|
-
} else {
|
|
73
|
-
throw error;
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
// ── Стена другого пользователя требует UUID ─────────────────────────────────────
|
|
78
|
-
// Проверка сработает до обращения к сети и подскажет, где взять идентификатор.
|
|
79
|
-
const target = await itd.users.get('durov');
|
|
80
|
-
await itd.posts.create((p) => p.content('привет!').onWall(target.id));
|
|
81
|
-
|
|
82
|
-
// ── Жалоба: тип объекта и его идентификатор нельзя рассогласовать ───────────────
|
|
83
|
-
await itd.reports.create(report.post(first.id).reason(ReportReason.Spam));
|
|
84
|
-
|
|
85
|
-
// ── Уведомления из REST и из потока имеют одну форму ────────────────────────────
|
|
86
|
-
const feed: Notification[] = (await itd.notifications.list({ limit: 10 })).items;
|
|
87
|
-
|
|
88
|
-
const stream = itd.realtime();
|
|
89
|
-
stream.on('notification', ({ notification }) => feed.unshift(notification));
|
|
90
|
-
await stream.connect();
|