Skip to content

v0.5.0

Choose a tag to compare

@KiowDev KiowDev released this 04 Aug 01:10
· 22 commits to main since this release
Immutable release. Only release title and notes can be modified.

Новая модель плагинов, каталог операций и переработанный конвейер запросов

Конвейер запросов

  • Очередь применяется к каждой сетевой попытке, а не ко всему логическому запросу: ожидание повтора больше не занимает слот конкурентности, а ограничитель частоты считает реальные обращения к серверу.
  • Локальный результат не проходит очередь: ответ из кэша, мок или короткое замыкание плагина возвращаются сразу и не расходуют RPS.
  • Очередь выбирается по итоговому URL.origin, уже после разрешения service и разового baseUrl. Два имени одного хоста делят лимитер, разные хосты изолированы.
  • Авторизация разделена на три стадии: восстановление после 401 вокруг попытки, подготовка токена до очереди и подстановка свежих заголовков непосредственно перед отправкой.
  • Служебные auth.signIn и auth.refresh проходят общий конвейер вместе с плагинами и очередью; отдельный урезанный auth-конвейер удалён.
  • Номер попытки считает фактические входы в транспорт: повтор после обновления токена получает следующий номер, а auth.refresh ведёт собственный счёт.
  • Порядок стадий и их частота закреплены contract-тестами и описаны в новом справочнике «Request pipeline».

Каталог операций

  • Каждый метод SDK получил стабильный operationIdposts.create, users.me, auth.refresh и так далее. Идентификатор не меняется при переносе HTTP-пути.
  • Публичный OPERATIONS хранит HTTP-метод и семантику повтора каждой встроенной операции; доступны operationMethod(), operationRetrySafety() и isBuiltInOperationId().
  • Плагины распознают операции по идентификатору, а не по регулярным выражениям над URL: перенос эндпоинта больше не ломает правила расширений молча.
  • Низкоуровневый itd.request() по умолчанию выполняется как операция raw; для собственных вызовов доступно пространство custom:*.

Плагины

  • Два явных уровня расширения. operations.use() вызывается один раз на логическую операцию и работает с разобранным результатом, attempts.use() оборачивает каждую сетевую попытку и видит итоговый URL, заголовки и сырой Response.
  • ClientPlugin заменил ItdPlugin: install(api) регистрирует преобразователи и перехватчики, а teardown дожидается запросов, уже вошедших в обёртку плагина.
  • Перехватчик попытки не может незаметно породить вторую отправку: повторный вызов next() запрещён, короткое замыкание возможно только явным возвратом Response.
  • Настройки плагинов передаются через extensions.<namespace> — регистрация ключей во время выполнения больше не нужна.

Повторы

  • Повтор опирается на семантику операции, а не на HTTP-метод. RetrySafety различает safe, idempotent и unsafe: читающий POST вроде posts.stats повторяется, а posts.create — нет.
  • Небезопасная операция повторяется автоматически только после ответа, который гарантирует, что запрос не был обработан.
  • Отдельно проверяется возможность заново собрать тело: одноразовый поток не делает операцию повторяемой.
  • Обычные повторы и лестница пауз после 429 считаются раздельно, поэтому последовательность 500 → 429 начинает лестницу с первой ступени.
  • Точечное переопределение доступно через RequestOptions.retrySafety, а shouldRetry получает RetryDecisionContext с семантикой операции.

Параметры запросов

  • Параметры эндпоинта и настройки выполнения разделены: itd.posts.list({ limit }, { signal, retry }).
  • Для итераторов добавлен PaginationOptions: maxPages управляет перебором и не попадает в запрос к эндпоинту.
  • Настройки загрузки файлов и телеметрии вынесены в собственные аргументы.

Realtime

  • Новый транспорт WebSocketTransport для сред с WebSocket: путь /api/ws, собственная реализация сокета, заголовки апгрейда и распознавание отказа по недействительному токену. Подключается явно через transport; выбор auto по-прежнему использует поток событий или опрос.
  • RealtimeComposer собирает feature-модуль без доступа к живому потоку: use(), filter() с type guard, route() поверх RealtimeRouter и errorBoundary() для защищённой ветки обработчиков.
  • Движок потока отделён от публичного объекта: переподключение, снимки цепочек и конкурентность живут в собственном слое.

Хранилища

  • Общий backend KeyValueStore под памятью, файлом, localStorage и sessionStorage. TokenStorage и MultiTokenStorage остались доменными фасадами поверх него.
  • Добавлены декораторы withNamespace() и withCodec(), фабрики createKeyValueStore() и createRecordKeyValueStore().
  • В itd-api/web появились SessionStorageTokenStorage, LocalStorageKeyValueStore и SessionStorageKeyValueStore.
  • Файловый backend использует версионированный конверт, а повреждённый JSON больше не выглядит как пустое хранилище: и файл, и Web Storage сообщают об ошибке явно, вместо молчаливого выхода пользователя из сессии.
  • MultiTokenStorage выводит список аккаунтов из ключей и не хранит отдельный индекс.

Жизненный цикл клиента

  • dispose() стал терминальным: после него новые запросы, use(), defineService(), realtime() и повторный connect() завершаются ItdStateError. Повторный вызов возвращает тот же результат очистки, await using вызывает именно его.
  • close() остаётся перезапускаемой остановкой: закрывает потоки, отправляет накопители телеметрии и гасит очередь.
  • Накопленная телеметрия отправляется и при dispose() — до teardown плагинов и не открывая доступ новым пользовательским вызовам.
  • ItdAccounts получил такой же терминальный dispose(): контейнер отзывает storage-срезы и подписки.

Пакеты

  • @itd-api/cache: правила задаются полем operations вместо routes, каталог доступен как CACHE_OPERATIONS. Кэш и граф инвалидации опираются на operationId, поэтому совпадение URL у itd.request() больше не включает кэш случайно.
  • @itd-api/testing: добавлен createMockOperations() — подмена логической операции по operationId с последовательностями ответов, историей вызовов, passthrough и проверкой неиспользованных сценариев. createMockFetch() остаётся для проверки HTTP-деталей, повторов и ошибок транспорта.
  • @itd-api/crypto: набор шифруемых полей сопоставляется с operationId, собственное распознавание маршрутов удалено.
  • @itd-api/hydrate: переведён на новые контракты расширения.

Технические улучшения

  • Сборка клиента вынесена во внутреннюю фабрику runtime: конфигурация, транспорт, авторизация, очереди и единственный конвейер собираются в одном месте, а ItdClient остаётся фасадом.
  • Ресурсы клиента создаются лениво, при первом обращении.
  • Пользовательское определение сервиса накладывается на встроенное: auth и заголовки наследуются, пока ключ не задан явно.
  • Каталоги операций и мутаций заморожены целиком, включая вложенные описания.
  • Добавлен справочник «Request pipeline» с инвариантами конвейера и таблицей точек расширения.

Несовместимые изменения

  • ItdPlugin, PluginContext и Transformer заменены на ClientPlugin, PluginApi, OperationTransformer и AttemptInterceptor; плоские use() и useHooks() внутри плагина удалены.
  • Смешанные параметры и настройки запроса разделены во всех методах ресурсов; optionKeys и REQUEST_OPTION_KEYS удалены вместе с извлечением полей в базовом ресурсе.
  • retryWrites и внутренний повтор сетевых записей удалены — их заменяет RetrySafety.
  • createRecordMultiStorage() заменён на createRecordKeyValueStore().
  • dispose() больше не оставляет клиент пригодным для запросов.
  • cache({ routes }) и CACHE_ROUTES переименованы в cache({ operations }) и CACHE_OPERATIONS без переходных псевдонимов.
  • Совместимые перегрузки намеренно не добавлялись: 0.5.0 меняет публичные контракты один раз, вместо того чтобы надолго оставить два протокола.

Совместимость

  • @itd-api/cache@0.1.0, @itd-api/crypto@0.1.0, @itd-api/hydrate@0.1.0 и @itd-api/testing@0.1.0 требуют itd-api@>=0.5.0 <1.0.0.
  • @itd-api/proxy и @itd-api/turnstile не зависят от контракта ядра и не менялись.

Full Changelog: v0.4.0...v0.5.0