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
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
# Разметка текста
|
|
2
|
+
|
|
3
|
+
ИТД хранит форматирование отдельным массивом `spans`. Каждый span задаёт тип, смещение и
|
|
4
|
+
длину фрагмента:
|
|
5
|
+
|
|
6
|
+
```ts
|
|
7
|
+
{
|
|
8
|
+
type: 'bold',
|
|
9
|
+
offset: 0,
|
|
10
|
+
length: 5,
|
|
11
|
+
}
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
Смещения измеряются в UTF-16 code units — тех же единицах, которые используют
|
|
15
|
+
`String#slice`, `substring` и DOM Selection. Поэтому эмодзи вне BMP обычно занимает две
|
|
16
|
+
единицы.
|
|
17
|
+
|
|
18
|
+
## Создание поста
|
|
19
|
+
|
|
20
|
+
`markup()` собирает текст и вычисляет смещения одновременно:
|
|
21
|
+
|
|
22
|
+
```ts
|
|
23
|
+
import { post } from 'itd-api';
|
|
24
|
+
|
|
25
|
+
await itd.posts.create(
|
|
26
|
+
post().markup((m) =>
|
|
27
|
+
m
|
|
28
|
+
.text('смотрите ')
|
|
29
|
+
.hashtag('котики')
|
|
30
|
+
.text(' от ')
|
|
31
|
+
.mention('durov')
|
|
32
|
+
.newline()
|
|
33
|
+
.bold('важно')
|
|
34
|
+
.text(': ')
|
|
35
|
+
.link('документация', 'https://example.com/docs'),
|
|
36
|
+
),
|
|
37
|
+
);
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Доступны:
|
|
41
|
+
|
|
42
|
+
- `bold`, `italic`, `underline`, `strike`;
|
|
43
|
+
- `spoiler`, `monospace`, `quote`;
|
|
44
|
+
- `link`, `hashtag`, `mention`;
|
|
45
|
+
- произвольный `span()`;
|
|
46
|
+
- несколько стилей сразу через `styled()`.
|
|
47
|
+
|
|
48
|
+
Билдер неизменяемый: каждый вызов возвращает новый экземпляр.
|
|
49
|
+
|
|
50
|
+
## Несколько стилей и пересечения
|
|
51
|
+
|
|
52
|
+
API хранит каждый стиль отдельным span, поэтому один диапазон может быть одновременно
|
|
53
|
+
жирным и подчёркнутым:
|
|
54
|
+
|
|
55
|
+
```ts
|
|
56
|
+
import { SpanType, markup } from 'itd-api';
|
|
57
|
+
|
|
58
|
+
const sameRange = markup()
|
|
59
|
+
.styled('жирный и подчёркнутый', SpanType.Bold, SpanType.Underline)
|
|
60
|
+
.build();
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Вложенность выражает частичное пересечение без ручных offsets:
|
|
64
|
+
|
|
65
|
+
```ts
|
|
66
|
+
const nested = markup()
|
|
67
|
+
.bold((m) => m.text('весь жирный, ').underline('а это ещё и подчёркнуто'))
|
|
68
|
+
.build();
|
|
69
|
+
|
|
70
|
+
const linked = markup()
|
|
71
|
+
.link((m) => m.bold('документация'), 'https://example.com')
|
|
72
|
+
.build();
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
При сборке spans стабильно сортируются по `offset`, а при одинаковом начале — от длинного
|
|
76
|
+
к короткому.
|
|
77
|
+
|
|
78
|
+
## Автоматическая разметка
|
|
79
|
+
|
|
80
|
+
Для готового текста `autoSpans()` находит HTTP(S)-ссылки, хэштеги и упоминания:
|
|
81
|
+
|
|
82
|
+
```ts
|
|
83
|
+
await itd.posts.create(
|
|
84
|
+
post('#котики от @durov: https://example.com').autoSpans(),
|
|
85
|
+
);
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Метод сохраняет ручные стили и не создаёт дубли при повторном вызове. Отдельная функция
|
|
89
|
+
возвращает только найденный массив:
|
|
90
|
+
|
|
91
|
+
```ts
|
|
92
|
+
import { autoSpans } from 'itd-api';
|
|
93
|
+
|
|
94
|
+
const spans = autoSpans('спасибо @durov. #котики', {
|
|
95
|
+
links: true,
|
|
96
|
+
mentions: true,
|
|
97
|
+
hashtags: true,
|
|
98
|
+
});
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
Сущности внутри URL не размечаются, даже если `{ links: false }`: ссылки всё равно
|
|
102
|
+
распознаются как защищённые диапазоны, но не попадают в результат.
|
|
103
|
+
|
|
104
|
+
## Замена текста
|
|
105
|
+
|
|
106
|
+
Spans рассчитаны для конкретной строки. Поэтому `.content()` заменяет текст и сбрасывает
|
|
107
|
+
старую разметку:
|
|
108
|
+
|
|
109
|
+
```ts
|
|
110
|
+
post('#старый')
|
|
111
|
+
.autoSpans()
|
|
112
|
+
.content('новый текст')
|
|
113
|
+
.build();
|
|
114
|
+
|
|
115
|
+
// { content: 'новый текст' }
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
После `.content()` вызовите `.spans()`, `.markup()` или `.autoSpans()` заново. Метод
|
|
119
|
+
`.append()` сохраняет существующие spans: старые offsets при дописывании текста не меняются.
|
|
120
|
+
|
|
121
|
+
## Сырые spans
|
|
122
|
+
|
|
123
|
+
Готовый массив можно передать объектом или через билдер:
|
|
124
|
+
|
|
125
|
+
```ts
|
|
126
|
+
import { SpanType } from 'itd-api';
|
|
127
|
+
|
|
128
|
+
await itd.posts.create({
|
|
129
|
+
content: 'важно',
|
|
130
|
+
spans: [{ type: SpanType.Bold, offset: 0, length: 5 }],
|
|
131
|
+
});
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
Перед запросом библиотека проверяет, что каждый диапазон непустой и целиком лежит внутри
|
|
135
|
+
`content`. Spans без текста также отклоняются. Семантику типа проверить невозможно:
|
|
136
|
+
формально валидный диапазон остаётся ответственностью вызывающего кода.
|
|
137
|
+
|
|
138
|
+
У `link` адрес лежит в `url`, у `hashtag` имя — в `tag`, у `mention` — в `username`.
|
|
139
|
+
Старые ответы сервера могут хранить username упоминания в `tag`.
|
|
140
|
+
|
|
141
|
+
## Обновление поста
|
|
142
|
+
|
|
143
|
+
`posts.update()` принимает объект, билдер или функцию-настройщик:
|
|
144
|
+
|
|
145
|
+
```ts
|
|
146
|
+
await itd.posts.update(postId, post().markup((m) => m.bold('новый текст')));
|
|
147
|
+
await itd.posts.update(postId, (p) => p.content('#новый текст').autoSpans());
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
Update endpoint меняет только `content` и `spans`. Вложения, опрос и чужая стена
|
|
151
|
+
отклоняются до запроса. `content` требуется задать явно, чтобы `{}` или обновление только
|
|
152
|
+
spans не стёрло текущий текст.
|
|
153
|
+
|
|
154
|
+
Явный пустой текст разрешён одинаково во всех формах:
|
|
155
|
+
|
|
156
|
+
```ts
|
|
157
|
+
await itd.posts.update(postId, { content: '' });
|
|
158
|
+
await itd.posts.update(postId, post(''));
|
|
159
|
+
await itd.posts.update(postId, (p) => p.content(''));
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
## Отображение
|
|
163
|
+
|
|
164
|
+
`renderSpans()` поддерживает HTML, Markdown и ANSI:
|
|
165
|
+
|
|
166
|
+
```ts
|
|
167
|
+
import { renderSpans } from 'itd-api';
|
|
168
|
+
|
|
169
|
+
renderSpans(post.content, post.spans); // безопасный HTML по умолчанию
|
|
170
|
+
renderSpans(post.content, post.spans, { format: 'markdown' });
|
|
171
|
+
renderSpans(post.content, post.spans, { format: 'ansi' });
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
HTML экранируется, опасные схемы ссылок не превращаются в `<a>`. Для собственного
|
|
175
|
+
приложения можно заменить маршруты и CSS-префикс:
|
|
176
|
+
|
|
177
|
+
```ts
|
|
178
|
+
renderSpans(post.content, post.spans, {
|
|
179
|
+
mentionUrl: (username) => `/users/${username}`,
|
|
180
|
+
hashtagUrl: (tag) => `/topics/${tag}`,
|
|
181
|
+
classPrefix: 'feed',
|
|
182
|
+
});
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
Возврат `null` из `mentionUrl` или `hashtagUrl` отключает соответствующую ссылку,
|
|
186
|
+
`classPrefix: null` отключает классы. По умолчанию используются `/@username`,
|
|
187
|
+
`/hashtag/name` и классы `itd-*`.
|
|
188
|
+
|
|
189
|
+
Пересекающиеся spans разбиваются на корректно вложенные сегменты. В Markdown цитаты
|
|
190
|
+
применяются после сборки сегментов, а code spans выбирают забор длиннее внутренних
|
|
191
|
+
последовательностей обратных апострофов.
|
|
192
|
+
|
|
193
|
+
## Комментарии
|
|
194
|
+
|
|
195
|
+
Сервер может вернуть `comment.spans`; поле необязательно, поэтому оба вызова безопасны:
|
|
196
|
+
|
|
197
|
+
```ts
|
|
198
|
+
renderSpans(comment.content, comment.spans);
|
|
199
|
+
renderSpans(comment.content);
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
Скачанный клиент сайта и документированный API комментариев отправляют при создании и
|
|
203
|
+
редактировании только текст и вложения. Поэтому библиотека читает разметку комментариев,
|
|
204
|
+
но не обещает неподтверждённую сервером запись ручных spans.
|
|
205
|
+
|
|
206
|
+
## Запускаемый пример
|
|
207
|
+
|
|
208
|
+
Пример создаёт один настоящий пост и показывает авторазметку, пересечения и рендер:
|
|
209
|
+
|
|
210
|
+
```bash
|
|
211
|
+
ITD_TOKEN=<accessToken> node guides/text-markup/examples/create-post.mjs
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
Исходник: [`examples/create-post.mjs`](./examples/create-post.mjs).
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Создание и отображение поста с разметкой текста.
|
|
3
|
+
*
|
|
4
|
+
* Запуск:
|
|
5
|
+
* ITD_TOKEN=<ваш accessToken> node guides/text-markup/examples/create-post.mjs
|
|
6
|
+
*
|
|
7
|
+
* Скрипт создаёт один настоящий пост в аккаунте из ITD_TOKEN.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { ItdClient, SpanType, markup, post, renderSpans } from 'itd-api';
|
|
11
|
+
|
|
12
|
+
if (!process.env.ITD_TOKEN) {
|
|
13
|
+
throw new Error('Передайте access token в переменной окружения ITD_TOKEN');
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const itd = new ItdClient({ auth: process.env.ITD_TOKEN });
|
|
17
|
+
|
|
18
|
+
// Текст и offsets собираются одновременно — вручную считать индексы не нужно.
|
|
19
|
+
const created = await itd.posts.create(
|
|
20
|
+
post().markup((m) =>
|
|
21
|
+
m
|
|
22
|
+
.text('Смотрите ')
|
|
23
|
+
.hashtag('котики')
|
|
24
|
+
.text(' от ')
|
|
25
|
+
.mention('durov')
|
|
26
|
+
.newline()
|
|
27
|
+
.bold('Важно')
|
|
28
|
+
.text(': ')
|
|
29
|
+
.link('документация', 'https://example.com/docs'),
|
|
30
|
+
),
|
|
31
|
+
);
|
|
32
|
+
|
|
33
|
+
console.log(`Создан пост ${created.id}`);
|
|
34
|
+
console.log('HTML:', renderSpans(created.content, created.spans));
|
|
35
|
+
console.log(
|
|
36
|
+
'Markdown:',
|
|
37
|
+
renderSpans(created.content, created.spans, { format: 'markdown' }),
|
|
38
|
+
);
|
|
39
|
+
|
|
40
|
+
// Для готового обычного текста можно найти ссылки, хэштеги и упоминания автоматически.
|
|
41
|
+
const detected = post('#котики от @durov: https://example.com').autoSpans().build();
|
|
42
|
+
console.log('\nautoSpans():', detected);
|
|
43
|
+
|
|
44
|
+
// Один фрагмент может иметь несколько стилей; вложенность задаёт пересечения.
|
|
45
|
+
const layered = markup()
|
|
46
|
+
.styled('жирный и подчёркнутый', SpanType.Bold, SpanType.Underline)
|
|
47
|
+
.newline()
|
|
48
|
+
.bold((m) => m.text('жирный, ').italic('а здесь ещё курсив'))
|
|
49
|
+
.build();
|
|
50
|
+
console.log('\nПересекающиеся spans:', layered);
|
|
51
|
+
|
|
52
|
+
// Важно: новый content сбрасывает spans, рассчитанные для прежнего текста.
|
|
53
|
+
const replaced = post('#старый').autoSpans().content('новый текст').build();
|
|
54
|
+
console.log('\nПосле content():', replaced);
|
|
55
|
+
|
|
56
|
+
// Для своих маршрутов и CSS можно настроить HTML-рендер.
|
|
57
|
+
console.log(
|
|
58
|
+
'\nНастроенный HTML:',
|
|
59
|
+
renderSpans(created.content, created.spans, {
|
|
60
|
+
mentionUrl: (username) => `/users/${username}`,
|
|
61
|
+
hashtagUrl: (tag) => `/topics/${tag}`,
|
|
62
|
+
classPrefix: 'feed',
|
|
63
|
+
}),
|
|
64
|
+
);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "itd-api",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.11",
|
|
4
4
|
"description": "Клиент REST и realtime API социальной сети итд.com для JavaScript и TypeScript",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -27,6 +27,7 @@
|
|
|
27
27
|
},
|
|
28
28
|
"files": [
|
|
29
29
|
"dist",
|
|
30
|
+
"guides",
|
|
30
31
|
"NOTICE",
|
|
31
32
|
"LICENSE",
|
|
32
33
|
"README.md"
|
|
@@ -37,7 +38,8 @@
|
|
|
37
38
|
"workspaces": [
|
|
38
39
|
"turnstile",
|
|
39
40
|
"crypto",
|
|
40
|
-
"proxy"
|
|
41
|
+
"proxy",
|
|
42
|
+
"cache"
|
|
41
43
|
],
|
|
42
44
|
"main": "./dist/index.cjs",
|
|
43
45
|
"module": "./dist/index.js",
|
|
@@ -82,8 +84,8 @@
|
|
|
82
84
|
"test:watch": "vitest",
|
|
83
85
|
"test:coverage": "vitest run --coverage",
|
|
84
86
|
"typecheck": "tsc --noEmit",
|
|
85
|
-
"lint": "biome check src test turnstile/src turnstile/test crypto/src crypto/test proxy/src proxy/test",
|
|
86
|
-
"lint:fix": "biome check --write src test turnstile/src turnstile/test crypto/src crypto/test proxy/src proxy/test",
|
|
87
|
+
"lint": "biome check src test turnstile/src turnstile/test crypto/src crypto/test proxy/src proxy/test cache/src cache/test",
|
|
88
|
+
"lint:fix": "biome check --write src test turnstile/src turnstile/test crypto/src crypto/test proxy/src proxy/test cache/src cache/test",
|
|
87
89
|
"docs": "typedoc",
|
|
88
90
|
"check:pack": "publint && attw --pack .",
|
|
89
91
|
"version": "npm run sync-version && git add src/core/version.ts",
|