v0.5.0
·
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 получил стабильный
operationId—posts.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