Skip to content

Repository files navigation

Пример приложения на itd-api

Рабочий клиент социальной сети итд.com на itd-api: лента, профили, посты с комментариями, реакции, репосты, опросы, уведомления, поиск и хэштеги. Рядом с интерфейсом — панель «под капотом» с журналом вызовов библиотеки.

Проект не является официальным и не аффилирован с итд.com.

Запуск

npm install
npm run dev

Откроется http://localhost:3000. Токен не нужен: без него сайт работает на песочнице — сервере API в памяти из @itd-api/testing.

Для продакшена задайте пароль сессии:

cp .env.example .env   # и впишите NUXT_SESSION_PASSWORD (32+ символа)
npm run build && node .output/server/index.mjs

Два режима

Режим Данные Когда
Песочница createMockServer() в памяти, своя у каждого посетителя пока не введён токен
Живой настоящий API итд.com после ввода своего access token на /token

Код серверных роутов у обоих режимов один и тот же — меняется только клиент, который им отдаёт useItd(). Песочница живёт полчаса после последнего действия, ограничена пятьюдесятью записями, двумястами комментариями, одним мегабайтом состояния и двумя тысячами символов в тексте; вложений не поддерживает.

Свежую запись посетителя её жители встречают парой реакций и коротким комментарием — обычными вызовами SDK от своего имени. Это единственное место, где роут делает больше одного вызова, и в журнале видна вся цепочка.

Почему клиент SDK живёт на сервере

итд.com отвечает на preflight без Access-Control-Allow-Origin, поэтому браузер запрос отвергает. Вдобавок refresh-токен лежит в HttpOnly-cookie, выставить которую из JS нельзя. Поэтому ItdClient работает только в Nitro (server/), в режиме RuntimeMode.Server, — cookie ведёт встроенный jar библиотеки, а браузер ходит в свои роуты /api/*.

Где лежат токены

accessToken, refreshToken, cookie API и deviceId не покидают сервер: они лежат в хранилище Nitro (useStorage('itd-sessions')), а браузер получает лишь непрозрачный идентификатор в запечатанной httpOnly-cookie itd_example. Запись живёт сутки с последнего обращения; кнопка «Забыть токен» удаляет её сразу. Сессию на итд.com это не закрывает — токен остаётся действительным.

Хранилище выбирается по окружению: upstash при заданных NUXT_REDIS_KV_REST_API_URL и NUXT_REDIS_KV_REST_API_TOKEN, redis при REDIS_URL, иначе память процесса. На serverless память не годится — инстансы поднимаются и гаснут, посетителя выбрасывало бы произвольно.

NUXT_SESSION_PASSWORD обязателен. Значение по умолчанию лежит в репозитории, поэтому вне режима разработки приложение с ним падает: иначе cookie любого посетителя подделал бы кто угодно.

Входа по паролю здесь нет

Публичный сайт не должен принимать чужие учётные данные, а капча при входе требует поднять браузер на сервере — на serverless это невозможно. Поэтому в примере остался единственный способ: вставить собственный access token. Вход по email и паролю, код из письма и QR в самом SDK есть — см. руководство по авторизации.

Ответ роута — ответ библиотеки

Своего DTO-слоя в примере нет: роут возвращает ровно то, что вернул метод SDK, а страницы типизируются моделями itd-api (Post, Profile, Page<T>). Снимается единственное поле — raw с копией исходного ответа: с ней каждый список ехал бы в браузер дважды.

Расшифровку скрытого текста делает сам плагин @itd-api/crypto: он кладёт готовое представление в decoded, а компоненты читают его через app/utils/decoded.ts. Тексты и ссылки уведомлений тоже считает библиотека — formatNotificationText и resolveNotificationUrl.

Панель «под капотом»

Каждый роут отдаёт конверт { response, meta }, где meta — журнал вызовов SDK: имя операции, аргументы, длительность, число попыток, флаг «из кэша» и ошибка. Собирает его плагин server/utils/inspector.ts на двух уровнях расширений — обёртке логической операции и перехватчике сетевой попытки. На сервере журнал не хранится: он живёт ровно столько, сколько выполняется запрос, а дальше — в памяти вкладки, последние 50 записей.

Заголовки для этого не годились: в них нельзя положить не-ASCII, а аргументы бывают русскими.

Вложения идут потоком

Файл уходит на сервер сырым телом запроса (имя и тип — заголовками), а оттуда сразу в itd.files.upload() источником fromStream(): целиком в памяти он не собирается. Предел размера сторожит сама библиотека через maxBytes, поэтому враньё в Content-Length ничего не даёт.

Повторы для загрузки отключены ({ retry: false }) осознанно: потоковый источник открывается заново на каждую попытку, а тело HTTP-запроса читается ровно один раз. При обрыве или 429 ошибка сразу приходит в интерфейс, и файл выбирают заново.

На Vercel предел свой: тело запроса к функции там не больше 4.5 МБ, и файл крупнее отвергает платформа.

Уведомления

NUXT_REALTIME Что происходит
poll (по умолчанию) браузер раз в 30 секунд спрашивает счётчик и подтягивает новое
sse библиотека держит поток на сервере, браузер читает свой text/event-stream
off блок уведомлений скрыт

Опрос выбран по умолчанию не от бедности: на serverless открытое соединение оплачивается как выполнение и всё равно рвётся по лимиту длительности.

Ограничение частоты

Лимиты итд.com считаются по IP, а все посетители демо приходят с одного адреса. Поэтому клиенты собраны в ItdAccounts с rateLimitScope: 'shared' — библиотека разводит их запросы одной очередью, — а ответы читающих операций кэшируются на 30 секунд (@itd-api/cache). Поймав 429, библиотека сама выждет по лестнице пауз; после неё ошибка придёт в интерфейс с понятным текстом.

Как устроено

Файл Что делает
server/utils/itd.ts клиенты посетителей: ItdAccounts для живого режима, песочница для остальных
server/utils/session.ts cookie с идентификатором и хранилище токенов
server/utils/sandbox.ts сервер API в памяти на сессию: TTL, квоты, вытеснение
server/utils/inspector.ts плагин, собирающий журнал вызовов
server/utils/handler.ts defineItdHandler() — конверт { response, meta } и перевод ошибок
server/api/upload.post.ts потоковая загрузка вложения через fromStream()
app/composables/useItdFetch.ts разворачивает конверт и кормит панель
app/composables/useCursorList.ts бесконечный список: курсор, смещение или номер страницы — одинаково
app/components/ItdInspector.vue сама панель

Переменные окружения

Переменная Назначение
NUXT_SESSION_PASSWORD шифрование cookie сессии, 32+ символа. Обязательна вне dev
NUXT_REDIS_KV_REST_API_URL, NUXT_REDIS_KV_REST_API_TOKEN хранилище токенов на serverless
REDIS_URL локальный Redis вместо Upstash
NUXT_REALTIME poll, sse или off
NUXT_PUBLIC_SANDBOX пускать ли без токена
NUXT_PUBLIC_INSPECTOR собирать ли журнал вызовов
NUXT_ITD_BASE_URL свой базовый URL API
NUXT_PROXY_URL прокси для локального запуска
NUXT_STORAGE_DRIVER upstash, redis или memory — если не задана, выбирается по остальным переменным

Лицензия

MIT.

About

Пример использования библиотеки itd-api

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Used by

Contributors

Languages