itd-api 0.0.11 → 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 -485
- 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-QD4UHJFF.cjs +0 -7387
- package/dist/chunk-QD4UHJFF.cjs.map +0 -1
- package/dist/chunk-TB7HW3VX.js +0 -7277
- package/dist/chunk-TB7HW3VX.js.map +0 -1
- package/dist/index-CrlTO7sR.d.cts +0 -4858
- package/dist/index-CrlTO7sR.d.ts +0 -4858
- package/guides/README.md +0 -22
- 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 -142
- package/guides/multi-accounts/examples/multi-accounts.mjs +0 -71
- package/guides/plugins/README.md +0 -162
- 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/text-markup/README.md +0 -214
- package/guides/text-markup/examples/create-post.mjs +0 -64
package/guides/README.md
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
# Руководства
|
|
2
|
-
|
|
3
|
-
| Руководство | О чём |
|
|
4
|
-
|---|---|
|
|
5
|
-
| [Быстрый старт](./quickstart/README.md) | установка, клиент, публикация, пагинация и ошибки |
|
|
6
|
-
| [Разметка текста](./text-markup/README.md) | spans, `markup()`, `autoSpans()`, пересечения и `renderSpans()` |
|
|
7
|
-
| [Авторизация](./authentication/README.md) | токены, Turnstile, OTP, продление и хранение сессии |
|
|
8
|
-
| [Realtime](./realtime/README.md) | уведомления, SSE, переподключение и fallback на polling |
|
|
9
|
-
| [Несколько аккаунтов](./multi-accounts/README.md) | `ItdAccounts`, общее хранилище, очереди и личные настройки |
|
|
10
|
-
| [Интеграции](./integrations/README.md) | proxy, Turnstile и точки подключения внешних возможностей |
|
|
11
|
-
| [Плагины](./plugins/README.md) | Cache, Crypto, `ItdPlugin` и создание нового плагина |
|
|
12
|
-
|
|
13
|
-
## Запуск примеров
|
|
14
|
-
|
|
15
|
-
Установите зависимости и соберите библиотеку:
|
|
16
|
-
|
|
17
|
-
```bash
|
|
18
|
-
npm install
|
|
19
|
-
npm run build
|
|
20
|
-
```
|
|
21
|
-
|
|
22
|
-
Команды запуска и переменные окружения указаны в каждом руководстве.
|
|
@@ -1,176 +0,0 @@
|
|
|
1
|
-
# Авторизация и сессии
|
|
2
|
-
|
|
3
|
-
Клиент может получить доступ к API из `auth`, сохранённой сессии или явного вызова
|
|
4
|
-
`itd.auth`. Обязательного способа нет:
|
|
5
|
-
|
|
6
|
-
```ts
|
|
7
|
-
new ItdClient({ auth: '<accessToken>' });
|
|
8
|
-
new ItdClient({ auth: { accessToken, refreshToken } });
|
|
9
|
-
new ItdClient({ auth: { email, password, getTurnstileToken } });
|
|
10
|
-
new ItdClient({ auth: { getToken: () => vault.read() } });
|
|
11
|
-
new ItdClient({ storage: new FileTokenStorage('./.itd-session.json') });
|
|
12
|
-
new ItdClient();
|
|
13
|
-
```
|
|
14
|
-
|
|
15
|
-
`storage` отражает текущее состояние сессии и имеет приоритет, а отсутствующие поля
|
|
16
|
-
дополняются из `auth`.
|
|
17
|
-
|
|
18
|
-
## Сохранённая сессия
|
|
19
|
-
|
|
20
|
-
В Node, Bun и Deno:
|
|
21
|
-
|
|
22
|
-
```ts
|
|
23
|
-
import { FileTokenStorage, ItdClient } from 'itd-api/node';
|
|
24
|
-
|
|
25
|
-
const itd = new ItdClient({
|
|
26
|
-
storage: new FileTokenStorage('./.itd-session.json'),
|
|
27
|
-
});
|
|
28
|
-
|
|
29
|
-
const me = await itd.users.me();
|
|
30
|
-
```
|
|
31
|
-
|
|
32
|
-
Если access token истёк, клиент использует refresh-сессию, повторяет исходный запрос и
|
|
33
|
-
сохраняет обновлённые данные. Параллельные `401` ждут одного refresh.
|
|
34
|
-
|
|
35
|
-
Refresh-токен обновляется при каждом продлении. Штатные хранилища записывают его
|
|
36
|
-
автоматически. При собственном хранении сохраняйте сессию после каждого события `tokens`:
|
|
37
|
-
|
|
38
|
-
```ts
|
|
39
|
-
itd.on('tokens', async () => saveSomewhere(await itd.getSession()));
|
|
40
|
-
|
|
41
|
-
await itd.setSession(await loadFromSomewhere());
|
|
42
|
-
```
|
|
43
|
-
|
|
44
|
-
Проверить возможность продления заранее:
|
|
45
|
-
|
|
46
|
-
```ts
|
|
47
|
-
if (await itd.auth.hasRefreshSession()) await itd.auth.refresh();
|
|
48
|
-
else redirectToLogin();
|
|
49
|
-
```
|
|
50
|
-
|
|
51
|
-
Автоматическое продление отключается через `autoRefresh: false`.
|
|
52
|
-
|
|
53
|
-
## Что хранится
|
|
54
|
-
|
|
55
|
-
Полная сессия включает:
|
|
56
|
-
|
|
57
|
-
- access и refresh tokens;
|
|
58
|
-
- cookie;
|
|
59
|
-
- `deviceId`.
|
|
60
|
-
|
|
61
|
-
Вне браузера `fetch` не ведёт cookie сам, поэтому библиотека хранит их вместе с сессией.
|
|
62
|
-
`deviceId` должен переживать перезапуски, иначе сервер будет видеть каждый запуск как новое
|
|
63
|
-
устройство.
|
|
64
|
-
|
|
65
|
-
Доступные хранилища:
|
|
66
|
-
|
|
67
|
-
| Хранилище | Импорт | Среда |
|
|
68
|
-
|---|---|---|
|
|
69
|
-
| `MemoryTokenStorage` | `itd-api` | везде |
|
|
70
|
-
| `LocalStorageTokenStorage` | `itd-api` | браузер |
|
|
71
|
-
| `FileTokenStorage` | `itd-api/node` | Node, Bun, Deno |
|
|
72
|
-
| `createTokenStorage()` | `itd-api` | Redis, БД, AsyncStorage и другие |
|
|
73
|
-
|
|
74
|
-
`getUserId()` читает идентификатор из JWT без запроса, но не проверяет подпись:
|
|
75
|
-
|
|
76
|
-
```ts
|
|
77
|
-
const cachedId = await itd.getUserId();
|
|
78
|
-
const actualProfile = await itd.users.me();
|
|
79
|
-
```
|
|
80
|
-
|
|
81
|
-
## Turnstile
|
|
82
|
-
|
|
83
|
-
`signIn`, `signUp` и `forgotPassword` требуют одноразовый токен Cloudflare Turnstile.
|
|
84
|
-
В браузере используйте виджет с экспортируемым ключом:
|
|
85
|
-
|
|
86
|
-
```ts
|
|
87
|
-
import { TURNSTILE_SITE_KEY } from 'itd-api';
|
|
88
|
-
|
|
89
|
-
turnstile.render('#captcha', {
|
|
90
|
-
sitekey: TURNSTILE_SITE_KEY,
|
|
91
|
-
callback: (turnstileToken) =>
|
|
92
|
-
itd.auth.signIn({ email, password, turnstileToken }),
|
|
93
|
-
});
|
|
94
|
-
```
|
|
95
|
-
|
|
96
|
-
Долгоживущему процессу передавайте функцию получения свежего токена:
|
|
97
|
-
|
|
98
|
-
```ts
|
|
99
|
-
new ItdClient({
|
|
100
|
-
auth: {
|
|
101
|
-
email,
|
|
102
|
-
password,
|
|
103
|
-
getTurnstileToken: () => captchaSolver.solve(),
|
|
104
|
-
},
|
|
105
|
-
});
|
|
106
|
-
```
|
|
107
|
-
|
|
108
|
-
Для Node доступен пакет `@itd-api/turnstile`:
|
|
109
|
-
|
|
110
|
-
```bash
|
|
111
|
-
npm i @itd-api/turnstile playwright
|
|
112
|
-
npx playwright install chromium
|
|
113
|
-
```
|
|
114
|
-
|
|
115
|
-
```ts
|
|
116
|
-
import { createTurnstileSolver } from '@itd-api/turnstile';
|
|
117
|
-
|
|
118
|
-
const itd = new ItdClient({
|
|
119
|
-
storage: new FileTokenStorage('./.itd-session.json'),
|
|
120
|
-
auth: {
|
|
121
|
-
email,
|
|
122
|
-
password,
|
|
123
|
-
getTurnstileToken: createTurnstileSolver(),
|
|
124
|
-
},
|
|
125
|
-
});
|
|
126
|
-
```
|
|
127
|
-
|
|
128
|
-
## Вход и восстановление через OTP
|
|
129
|
-
|
|
130
|
-
```ts
|
|
131
|
-
await itd.auth.signInWithOtp({
|
|
132
|
-
email,
|
|
133
|
-
password,
|
|
134
|
-
turnstileToken,
|
|
135
|
-
getOtp: () => rl.question('Код из письма: '),
|
|
136
|
-
});
|
|
137
|
-
|
|
138
|
-
await itd.auth.resetPasswordWithOtp({
|
|
139
|
-
email,
|
|
140
|
-
turnstileToken,
|
|
141
|
-
newPassword,
|
|
142
|
-
getOtp: () => rl.question('Код из письма: '),
|
|
143
|
-
});
|
|
144
|
-
```
|
|
145
|
-
|
|
146
|
-
## Потеря сессии
|
|
147
|
-
|
|
148
|
-
Если refresh не удался, серверная ошибка приходит вызывающему коду и в событии
|
|
149
|
-
`authError`:
|
|
150
|
-
|
|
151
|
-
```ts
|
|
152
|
-
itd.on('authError', ({ error }) => {
|
|
153
|
-
if (isItdApiError(error)) {
|
|
154
|
-
console.error(error.code);
|
|
155
|
-
}
|
|
156
|
-
});
|
|
157
|
-
```
|
|
158
|
-
|
|
159
|
-
Полезные коды: `SESSION_NOT_FOUND`, `SESSION_REVOKED`, `REFRESH_TOKEN_MISSING`.
|
|
160
|
-
|
|
161
|
-
## Примеры
|
|
162
|
-
|
|
163
|
-
- [`examples/bot-with-session.mjs`](./examples/bot-with-session.mjs) — ручной токен
|
|
164
|
-
Turnstile при первом входе и сохранение сессии.
|
|
165
|
-
- [`examples/turnstile-login.mjs`](./examples/turnstile-login.mjs) — автоматическое
|
|
166
|
-
получение Turnstile через браузер.
|
|
167
|
-
|
|
168
|
-
Запуск из корня:
|
|
169
|
-
|
|
170
|
-
```bash
|
|
171
|
-
ITD_EMAIL=you@example.com ITD_PASSWORD=secret ITD_TURNSTILE=... \
|
|
172
|
-
node guides/authentication/examples/bot-with-session.mjs
|
|
173
|
-
|
|
174
|
-
ITD_EMAIL=you@example.com ITD_PASSWORD=secret \
|
|
175
|
-
node guides/authentication/examples/turnstile-login.mjs
|
|
176
|
-
```
|
|
@@ -1,98 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Бот на Node: вход по логину и паролю, сохранение сессии, публикация с опросом.
|
|
3
|
-
*
|
|
4
|
-
* Запуск:
|
|
5
|
-
* ITD_EMAIL=you@example.com ITD_PASSWORD=secret ITD_TURNSTILE=... \
|
|
6
|
-
* node guides/authentication/examples/bot-with-session.mjs
|
|
7
|
-
*
|
|
8
|
-
* Вход требует токен капчи Cloudflare Turnstile: получите его в браузере на странице входа
|
|
9
|
-
* (ключ виджета — TURNSTILE_SITE_KEY) и передайте в ITD_TURNSTILE. Токен одноразовый
|
|
10
|
-
* и живёт несколько минут, поэтому нужен только при первом запуске.
|
|
11
|
-
*
|
|
12
|
-
* Дальше сессия сохраняется в `.itd-session.json`, и повторный вход не понадобится:
|
|
13
|
-
* библиотека продлевает её сама. Добавьте этот файл в .gitignore — в нём лежат токены.
|
|
14
|
-
*/
|
|
15
|
-
|
|
16
|
-
import { createInterface } from 'node:readline/promises';
|
|
17
|
-
import { FileTokenStorage, ItdClient, isItdApiError } from 'itd-api/node';
|
|
18
|
-
|
|
19
|
-
const itd = new ItdClient({
|
|
20
|
-
// auth здесь не задаём: вход по паролю требует свежей капчи, поэтому он делается
|
|
21
|
-
// явно и только когда сохранённая сессия не подошла — см. ensureSignedIn().
|
|
22
|
-
|
|
23
|
-
// Без хранилища бот входил бы заново при каждом запуске, а серия входов подряд
|
|
24
|
-
// может привести к временной блокировке аккаунта.
|
|
25
|
-
storage: new FileTokenStorage('./.itd-session.json'),
|
|
26
|
-
|
|
27
|
-
// Ограничение нагрузки: запросы уходят не залпом, а ровным потоком.
|
|
28
|
-
rateLimit: { concurrency: 4, rps: 8 },
|
|
29
|
-
|
|
30
|
-
// logger: true, // раскомментируйте, чтобы видеть каждый запрос (токены маскируются)
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
// Сессия истекла и продлить её не удалось — здесь стоит уведомить владельца бота.
|
|
34
|
-
// В error лежит ответ сервера: по error.code видно, отозвана сессия или просто истекла.
|
|
35
|
-
itd.on('authError', ({ error }) =>
|
|
36
|
-
console.error('Сессия потеряна:', isItdApiError(error) ? error.code : error),
|
|
37
|
-
);
|
|
38
|
-
|
|
39
|
-
/**
|
|
40
|
-
* Работает с сохранённой сессией, а входит заново, только если та не подошла.
|
|
41
|
-
*
|
|
42
|
-
* Отдельная проверка `hasRefreshSession()` не нужна: продление происходит само при 401.
|
|
43
|
-
* Достаточно поймать 401, который пережил и продление тоже.
|
|
44
|
-
*/
|
|
45
|
-
async function ensureSignedIn() {
|
|
46
|
-
try {
|
|
47
|
-
return await itd.users.me();
|
|
48
|
-
} catch (error) {
|
|
49
|
-
if (!isItdApiError(error) || error.status !== 401) throw error;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
if (!process.env.ITD_TURNSTILE) {
|
|
53
|
-
throw new Error('Сохранённая сессия не подошла — нужен новый токен капчи в ITD_TURNSTILE');
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
57
|
-
try {
|
|
58
|
-
await itd.auth.signInWithOtp({
|
|
59
|
-
email: process.env.ITD_EMAIL,
|
|
60
|
-
password: process.env.ITD_PASSWORD,
|
|
61
|
-
turnstileToken: process.env.ITD_TURNSTILE,
|
|
62
|
-
getOtp: () => rl.question('Код из письма: '),
|
|
63
|
-
});
|
|
64
|
-
} finally {
|
|
65
|
-
rl.close();
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
return itd.users.me();
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
const me = await ensureSignedIn();
|
|
72
|
-
console.log(`Вошли как @${me.username}\n`);
|
|
73
|
-
|
|
74
|
-
// Публикация с опросом. Файл загрузится сам, порядок вложений сохранится.
|
|
75
|
-
const post = await itd.posts.create((p) =>
|
|
76
|
-
p
|
|
77
|
-
.content('Собираю мнения')
|
|
78
|
-
.poll((q) => q.question('Какой язык удобнее?').options('TypeScript', 'JavaScript')),
|
|
79
|
-
);
|
|
80
|
-
|
|
81
|
-
console.log(`Опубликовано: ${post.id}`);
|
|
82
|
-
|
|
83
|
-
// Пример с картинкой — раскомментируйте, подставив существующий путь:
|
|
84
|
-
// await itd.posts.create((p) => p.content('смотрите').attach('./photo.jpg'));
|
|
85
|
-
|
|
86
|
-
// Обход подписок и реакция на непонравившиеся записи.
|
|
87
|
-
let liked = 0;
|
|
88
|
-
|
|
89
|
-
for await (const item of itd.posts.iterate({ tab: 'following' })) {
|
|
90
|
-
if (liked >= 5) break;
|
|
91
|
-
if (item.isLiked || item.isOwner) continue;
|
|
92
|
-
|
|
93
|
-
await itd.posts.like(item.id);
|
|
94
|
-
liked += 1;
|
|
95
|
-
console.log(`❤ @${item.author.username}: ${item.content.slice(0, 40)}`);
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
console.log(`\nПоставлено реакций: ${liked}`);
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Полностью автоматический вход: токен капчи добывается сам.
|
|
3
|
-
*
|
|
4
|
-
* Запуск:
|
|
5
|
-
* ITD_EMAIL=you@example.com ITD_PASSWORD=secret \
|
|
6
|
-
* node guides/authentication/examples/turnstile-login.mjs
|
|
7
|
-
*
|
|
8
|
-
* В соседнем `bot-with-session.mjs` токен капчи приходится добывать руками и передавать
|
|
9
|
-
* в ITD_TURNSTILE. Здесь его берёт `@itd-api/turnstile`: поднимает браузер, забирает токен
|
|
10
|
-
* и закрывается. Установите отдельно, основному пакету он не нужен:
|
|
11
|
-
*
|
|
12
|
-
* npm i @itd-api/turnstile playwright
|
|
13
|
-
* npx playwright install chromium
|
|
14
|
-
*
|
|
15
|
-
* Браузер открывается с окном — так виджет проходится надёжнее. На сервере без графической
|
|
16
|
-
* оболочки запускайте через
|
|
17
|
-
* `xvfb-run -a node guides/authentication/examples/turnstile-login.mjs`.
|
|
18
|
-
*/
|
|
19
|
-
|
|
20
|
-
import { FileTokenStorage, ItdClient, isItdApiError } from 'itd-api/node';
|
|
21
|
-
import { createTurnstileSolver } from '@itd-api/turnstile';
|
|
22
|
-
|
|
23
|
-
const itd = new ItdClient({
|
|
24
|
-
// Сессия переживает перезапуск, поэтому браузер поднимется только в первый раз —
|
|
25
|
-
// дальше клиент продлевает токен сам и до входа по паролю дело не доходит.
|
|
26
|
-
storage: new FileTokenStorage('./.itd-session.json'),
|
|
27
|
-
|
|
28
|
-
auth: {
|
|
29
|
-
email: process.env.ITD_EMAIL,
|
|
30
|
-
password: process.env.ITD_PASSWORD,
|
|
31
|
-
|
|
32
|
-
// Функция, а не готовая строка: токен одноразовый и живёт несколько минут, поэтому
|
|
33
|
-
// клиент спрашивает свежий перед каждой попыткой входа — в том числе через сутки,
|
|
34
|
-
// когда сессия истечёт и понадобится войти заново.
|
|
35
|
-
getTurnstileToken: createTurnstileSolver({
|
|
36
|
-
logger: (message) => console.log(`[turnstile] ${message}`),
|
|
37
|
-
}),
|
|
38
|
-
},
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
itd.on('signIn', () => console.log('Вход выполнен, сессия сохранена'));
|
|
42
|
-
|
|
43
|
-
try {
|
|
44
|
-
const me = await itd.users.me();
|
|
45
|
-
console.log(`Вошли как @${me.username}`);
|
|
46
|
-
|
|
47
|
-
for await (const item of itd.posts.iterate({ tab: 'following' })) {
|
|
48
|
-
console.log(`@${item.author.username}: ${item.content.slice(0, 60)}`);
|
|
49
|
-
break;
|
|
50
|
-
}
|
|
51
|
-
} catch (error) {
|
|
52
|
-
// Если аккаунт требует подтверждения кодом из письма, автоматический вход невозможен —
|
|
53
|
-
// клиент скажет об этом отдельно и предложит itd.auth.signInWithOtp().
|
|
54
|
-
console.error(isItdApiError(error) ? `${error.code}: ${error.message}` : error);
|
|
55
|
-
process.exitCode = 1;
|
|
56
|
-
}
|
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
# Интеграции
|
|
2
|
-
|
|
3
|
-
Готовые интеграции добавляют поддержку прокси-серверов и автоматическое получение
|
|
4
|
-
Turnstile-токенов.
|
|
5
|
-
|
|
6
|
-
| Пакет | Точка подключения |
|
|
7
|
-
|---|---|
|
|
8
|
-
| [`@itd-api/proxy`](../../proxy/README.md) | `ItdClientOptions.fetch` |
|
|
9
|
-
| [`@itd-api/turnstile`](../../turnstile/README.md) | `auth.getTurnstileToken` |
|
|
10
|
-
|
|
11
|
-
## Proxy
|
|
12
|
-
|
|
13
|
-
Пакет создаёт совместимый `fetch`, который направляет HTTP/HTTPS-запросы через HTTP,
|
|
14
|
-
HTTPS или SOCKS5-прокси:
|
|
15
|
-
|
|
16
|
-
```bash
|
|
17
|
-
npm install @itd-api/proxy
|
|
18
|
-
```
|
|
19
|
-
|
|
20
|
-
```ts
|
|
21
|
-
import { ItdClient } from 'itd-api';
|
|
22
|
-
import { proxyFetch } from '@itd-api/proxy';
|
|
23
|
-
|
|
24
|
-
const fetch = proxyFetch('socks5://user:password@127.0.0.1:1080');
|
|
25
|
-
const itd = new ItdClient({ auth: token, fetch });
|
|
26
|
-
|
|
27
|
-
try {
|
|
28
|
-
console.log(await itd.users.me());
|
|
29
|
-
} finally {
|
|
30
|
-
await itd.close();
|
|
31
|
-
await fetch.close();
|
|
32
|
-
}
|
|
33
|
-
```
|
|
34
|
-
|
|
35
|
-
Через этот транспорт идут API-запросы, авторизация, повторы и realtime. Пакет работает
|
|
36
|
-
в Node, Bun и Deno. В браузере исходящий SOCKS/HTTP-прокси таким способом настроить нельзя.
|
|
37
|
-
|
|
38
|
-
Запускаемый пример:
|
|
39
|
-
|
|
40
|
-
```bash
|
|
41
|
-
ITD_TOKEN=<accessToken> ITD_PROXY=socks5://127.0.0.1:1080 \
|
|
42
|
-
node guides/integrations/examples/proxy.mjs
|
|
43
|
-
```
|
|
44
|
-
|
|
45
|
-
## Turnstile
|
|
46
|
-
|
|
47
|
-
`@itd-api/turnstile` получает одноразовый токен капчи и передаёт его механизму входа:
|
|
48
|
-
|
|
49
|
-
```ts
|
|
50
|
-
import { createTurnstileSolver } from '@itd-api/turnstile';
|
|
51
|
-
|
|
52
|
-
const itd = new ItdClient({
|
|
53
|
-
auth: {
|
|
54
|
-
email,
|
|
55
|
-
password,
|
|
56
|
-
getTurnstileToken: createTurnstileSolver(),
|
|
57
|
-
},
|
|
58
|
-
});
|
|
59
|
-
```
|
|
60
|
-
|
|
61
|
-
Установка Playwright, сохранение сессии и запускаемые примеры описаны в
|
|
62
|
-
[руководстве по авторизации](../authentication/README.md).
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Запуск:
|
|
3
|
-
* ITD_TOKEN=<accessToken> ITD_PROXY=socks5://127.0.0.1:1080 \
|
|
4
|
-
* node guides/integrations/examples/proxy.mjs
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import { proxyFetch } from '@itd-api/proxy';
|
|
8
|
-
import { ItdClient } from 'itd-api';
|
|
9
|
-
|
|
10
|
-
const token = process.env.ITD_TOKEN;
|
|
11
|
-
const proxy = process.env.ITD_PROXY;
|
|
12
|
-
|
|
13
|
-
if (!token || !proxy) {
|
|
14
|
-
throw new Error('Передайте ITD_TOKEN и ITD_PROXY');
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
const fetch = proxyFetch(proxy);
|
|
18
|
-
const itd = new ItdClient({ auth: token, fetch });
|
|
19
|
-
|
|
20
|
-
try {
|
|
21
|
-
const me = await itd.users.me();
|
|
22
|
-
console.log(`Прокси работает: @${me.username}`);
|
|
23
|
-
} finally {
|
|
24
|
-
await itd.close();
|
|
25
|
-
await fetch.close();
|
|
26
|
-
}
|
|
@@ -1,142 +0,0 @@
|
|
|
1
|
-
# Несколько аккаунтов
|
|
2
|
-
|
|
3
|
-
`ItdAccounts` управляет именованными клиентами. У каждого аккаунта отдельные tokens, cookie
|
|
4
|
-
и `deviceId`, но сессии складываются в одно `MultiTokenStorage`.
|
|
5
|
-
|
|
6
|
-
```ts
|
|
7
|
-
import { FileMultiTokenStorage, ItdAccounts } from 'itd-api/node';
|
|
8
|
-
|
|
9
|
-
const accounts = new ItdAccounts({
|
|
10
|
-
storage: new FileMultiTokenStorage('./.itd-sessions.json'),
|
|
11
|
-
rateLimit: { concurrency: 4 },
|
|
12
|
-
});
|
|
13
|
-
|
|
14
|
-
await accounts.restore();
|
|
15
|
-
|
|
16
|
-
if (!accounts.has('kiow')) {
|
|
17
|
-
accounts.addAccount('kiow', {
|
|
18
|
-
auth: { email, password, getTurnstileToken },
|
|
19
|
-
});
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
const itd = accounts.account('kiow');
|
|
23
|
-
await itd.posts.create({ content: 'привет' });
|
|
24
|
-
await accounts.close();
|
|
25
|
-
```
|
|
26
|
-
|
|
27
|
-
Имя аккаунта локальное: сервер его не знает и библиотека не нормализует.
|
|
28
|
-
|
|
29
|
-
## Основные операции
|
|
30
|
-
|
|
31
|
-
| Метод | Назначение |
|
|
32
|
-
|---|---|
|
|
33
|
-
| `addAccount(name, options?)` | добавить аккаунт |
|
|
34
|
-
| `account(name)` | получить обычный `ItdClient` |
|
|
35
|
-
| `restore()` | восстановить аккаунты из хранилища |
|
|
36
|
-
| `removeAccount(name, { forget })` | убрать аккаунт и при необходимости забыть сессию |
|
|
37
|
-
| `has(name)`, `names()`, `size` | проверить состав |
|
|
38
|
-
| `use(plugin)` | подключить плагин существующим и будущим клиентам |
|
|
39
|
-
| `on(event, listener)` | слушать события всех аккаунтов |
|
|
40
|
-
| `close()` | закрыть все клиенты |
|
|
41
|
-
|
|
42
|
-
Идентификатор профиля можно прочитать из JWT без запроса:
|
|
43
|
-
|
|
44
|
-
```ts
|
|
45
|
-
for (const [name, itd] of accounts) {
|
|
46
|
-
console.log(name, await itd.getUserId());
|
|
47
|
-
}
|
|
48
|
-
```
|
|
49
|
-
|
|
50
|
-
## Общие и личные настройки
|
|
51
|
-
|
|
52
|
-
Общие опции задаются контейнеру, личные — в `addAccount()`. `headers` и `services`
|
|
53
|
-
объединяются по ключам.
|
|
54
|
-
|
|
55
|
-
```ts
|
|
56
|
-
accounts.addAccount('первый', {
|
|
57
|
-
auth: token1,
|
|
58
|
-
fetch: proxyFetch('socks5://127.0.0.1:1080'),
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
accounts.addAccount('второй', {
|
|
62
|
-
auth: token2,
|
|
63
|
-
fetch: proxyFetch('socks5://127.0.0.1:1081'),
|
|
64
|
-
});
|
|
65
|
-
```
|
|
66
|
-
|
|
67
|
-
`auth` и `deviceId` нельзя задавать контейнеру: они принадлежат конкретному аккаунту.
|
|
68
|
-
Обычный `TokenStorage` здесь заменён общим `MultiTokenStorage`, поэтому личный `storage`
|
|
69
|
-
в `addAccount()` также запрещён.
|
|
70
|
-
|
|
71
|
-
## Очереди запросов
|
|
72
|
-
|
|
73
|
-
По умолчанию у каждого аккаунта отдельная очередь. Это соответствует лимитам по аккаунту
|
|
74
|
-
и не связывает клиентов, работающих через разные прокси.
|
|
75
|
-
|
|
76
|
-
Если общий IP сам становится ограничением, включите одну очередь:
|
|
77
|
-
|
|
78
|
-
```ts
|
|
79
|
-
const accounts = new ItdAccounts({
|
|
80
|
-
storage,
|
|
81
|
-
rateLimit: { concurrency: 4, rps: 8 },
|
|
82
|
-
rateLimitScope: 'shared',
|
|
83
|
-
});
|
|
84
|
-
```
|
|
85
|
-
|
|
86
|
-
В shared-режиме параметры очереди берутся из контейнера. Личный `rateLimit` у аккаунта
|
|
87
|
-
запрещён, но `rateLimit: false` полностью выводит конкретный клиент из общей очереди.
|
|
88
|
-
|
|
89
|
-
## Собственное хранилище
|
|
90
|
-
|
|
91
|
-
Методы `MultiTokenStorage` получают имя аккаунта:
|
|
92
|
-
|
|
93
|
-
```ts
|
|
94
|
-
import { createMultiTokenStorage } from 'itd-api';
|
|
95
|
-
|
|
96
|
-
const storage = createMultiTokenStorage({
|
|
97
|
-
get: async (account) =>
|
|
98
|
-
JSON.parse((await redis.get(`itd:session:${account}`)) ?? 'null'),
|
|
99
|
-
|
|
100
|
-
set: async (account, session) => {
|
|
101
|
-
await redis.set(`itd:session:${account}`, JSON.stringify(session));
|
|
102
|
-
await redis.sadd('itd:accounts', account);
|
|
103
|
-
},
|
|
104
|
-
|
|
105
|
-
clear: async (account) => {
|
|
106
|
-
await redis.del(`itd:session:${account}`);
|
|
107
|
-
await redis.srem('itd:accounts', account);
|
|
108
|
-
},
|
|
109
|
-
|
|
110
|
-
accounts: () => redis.smembers('itd:accounts'),
|
|
111
|
-
});
|
|
112
|
-
```
|
|
113
|
-
|
|
114
|
-
Список `accounts()` ведёт сам адаптер. По нему `restore()` узнаёт, какие аккаунты нужно
|
|
115
|
-
поднять после перезапуска.
|
|
116
|
-
|
|
117
|
-
## События
|
|
118
|
-
|
|
119
|
-
Контейнер добавляет имя аккаунта в полезную нагрузку:
|
|
120
|
-
|
|
121
|
-
```ts
|
|
122
|
-
accounts.on('authError', ({ account, error }) => {
|
|
123
|
-
console.error(`[${account}]`, error);
|
|
124
|
-
});
|
|
125
|
-
```
|
|
126
|
-
|
|
127
|
-
Плагины, подключённые через `accounts.use(plugin)`, применяются ко всем существующим и
|
|
128
|
-
будущим клиентам.
|
|
129
|
-
|
|
130
|
-
## Realtime
|
|
131
|
-
|
|
132
|
-
Каждый аккаунт держит своё SSE-соединение. Не открывайте поток автоматически всем, если
|
|
133
|
-
уведомления нужны только части аккаунтов.
|
|
134
|
-
|
|
135
|
-
## Запускаемый пример
|
|
136
|
-
|
|
137
|
-
```bash
|
|
138
|
-
ITD_TOKENS='бот-1=<accessToken>,бот-2=<accessToken>' \
|
|
139
|
-
node guides/multi-accounts/examples/multi-accounts.mjs
|
|
140
|
-
```
|
|
141
|
-
|
|
142
|
-
Исходник: [`examples/multi-accounts.mjs`](./examples/multi-accounts.mjs).
|
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Несколько аккаунтов в одном процессе: общее хранилище сессий, свой токен у каждого.
|
|
3
|
-
*
|
|
4
|
-
* Запуск:
|
|
5
|
-
* ITD_TOKENS='бот-1=<accessToken>,бот-2=<accessToken>' \
|
|
6
|
-
* node guides/multi-accounts/examples/multi-accounts.mjs
|
|
7
|
-
*
|
|
8
|
-
* Первый запуск заводит аккаунты по токенам и складывает их сессии в `.itd-sessions.json`.
|
|
9
|
-
* При следующих ITD_TOKENS уже не нужен: restore() поднимет всех из файла, а истёкшие
|
|
10
|
-
* токены библиотека продлит сама. Файл в .gitignore — в нём лежат токены доступа.
|
|
11
|
-
*/
|
|
12
|
-
|
|
13
|
-
import { FileMultiTokenStorage, ItdAccounts, isItdApiError } from 'itd-api/node';
|
|
14
|
-
|
|
15
|
-
const accounts = new ItdAccounts({
|
|
16
|
-
storage: new FileMultiTokenStorage('./.itd-sessions.json'),
|
|
17
|
-
|
|
18
|
-
// Ограничение нагрузки. Лимиты итд.com считаются по аккаунту, поэтому очередь
|
|
19
|
-
// по умолчанию у каждого своя. Если все аккаунты ходят с одного IP и упираются
|
|
20
|
-
// в ограничение по адресу — добавьте rateLimitScope: 'shared'.
|
|
21
|
-
rateLimit: { concurrency: 4, rps: 8 },
|
|
22
|
-
|
|
23
|
-
// logger: true, // раскомментируйте, чтобы видеть каждый запрос (токены маскируются)
|
|
24
|
-
});
|
|
25
|
-
|
|
26
|
-
try {
|
|
27
|
-
// Обработчик один на всех: в полезной нагрузке приходит имя аккаунта.
|
|
28
|
-
accounts.on('authError', ({ account, error }) =>
|
|
29
|
-
console.error(`[${account}] сессия потеряна:`, isItdApiError(error) ? error.code : error),
|
|
30
|
-
);
|
|
31
|
-
|
|
32
|
-
// Поднимаем тех, кто уже входил раньше, — ни токена, ни капчи для этого не нужно.
|
|
33
|
-
const restored = await accounts.restore();
|
|
34
|
-
if (restored.length > 0) console.log(`Из хранилища: ${restored.join(', ')}`);
|
|
35
|
-
|
|
36
|
-
// Новые аккаунты — из переменной окружения вида «имя=токен,имя=токен».
|
|
37
|
-
for (const pair of (process.env.ITD_TOKENS ?? '').split(',').filter(Boolean)) {
|
|
38
|
-
const [name, token] = pair.split('=');
|
|
39
|
-
if (!name || !token || accounts.has(name)) continue;
|
|
40
|
-
|
|
41
|
-
accounts.addAccount(name, { auth: token });
|
|
42
|
-
console.log(`Добавлен: ${name}`);
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
if (accounts.size === 0) {
|
|
46
|
-
throw new Error('Ни одного аккаунта: передайте ITD_TOKENS при первом запуске');
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
// Клиент аккаунта — обычный ItdClient со всеми разделами.
|
|
50
|
-
for (const [name, itd] of accounts) {
|
|
51
|
-
// getUserId() читает идентификатор из самого токена и не стоит ни одного запроса.
|
|
52
|
-
const id = await itd.getUserId();
|
|
53
|
-
|
|
54
|
-
try {
|
|
55
|
-
const me = await itd.users.me();
|
|
56
|
-
console.log(`${name} → @${me.username} (${id ?? 'id неизвестен'})`);
|
|
57
|
-
} catch (error) {
|
|
58
|
-
console.error(`${name} → не отвечает:`, isItdApiError(error) ? error.code : error);
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
// Действие одним аккаунтом.
|
|
63
|
-
const [first] = accounts.names();
|
|
64
|
-
const posts = await accounts.account(first).posts.iterate({ tab: 'popular' }).collect(3);
|
|
65
|
-
console.log(`\n${first} видит ${posts.length} популярных записей`);
|
|
66
|
-
|
|
67
|
-
// Убрать аккаунт вместе с сохранённой сессией:
|
|
68
|
-
// await accounts.removeAccount('бот-2', { forget: true });
|
|
69
|
-
} finally {
|
|
70
|
-
await accounts.close();
|
|
71
|
-
}
|