UNPKG

synapse-storage

Version:

Набор инструментов для управления состоянием и апи-запросами

130 lines (129 loc) 7.21 kB
import { ApiContext, CacheConfig, RequestDefinition, RetryConfig } from './api.interface'; import { QueryOptions, QueryResult, Unsubscribe } from './query.interface'; /** * Конфигурация эндпоинта */ export interface EndpointConfig<RequestParams extends Record<string, any> = any, RequestResult = any> { /** Функция для создания определения запроса из параметров */ request: (params: RequestParams, context?: Record<string, any>) => RequestDefinition<RequestParams>; /** Настройки кэша для эндпоинта */ cache?: CacheConfig; /** Теги эндпоинта для группировки в кэше */ tags?: string[]; /** Теги, которые инвалидируются при успешном запросе */ invalidatesTags?: string[]; /** Функция для подготовки заголовков (дополняет глобальную) */ prepareHeaders?: (headers: Headers, context: ApiContext<RequestParams>) => Promise<Headers>; /** Добавить ключи заголовков, влияющие на кэш (Дополняет глобавльные ключи) */ includeCacheableHeaderKeys?: string[]; /** Исключить ключи заголовков, влияющие на кэш (Дополняет глобавльные ключи) */ excludeCacheableHeaderKeys?: string[]; /** Конфигурация retry для этого эндпоинта (переопределяет глобальную) */ retry?: RetryConfig; } /** * Состояние эндпоинта * Содержит информацию о текущем состоянии запроса и данные */ export interface EndpointState { /** Статус запроса */ status: 'idle' | 'loading' | 'success' | 'error'; /** Ошибка (при неуспешном запросе) */ error?: Error; /** Количество вызовов */ fetchCounts: number; /** Метаданные эндпоинта */ meta: Endpoint['meta']; /** Какие заголовки участвовали в формировании ключа кэша (итоговые) */ cacheableHeaders: string[]; } /** * Статус выполнения запроса */ export type RequestStatus = 'idle' | 'loading' | 'success' | 'error'; /** * Состояние самого запроса */ export interface RequestState<ResponseData = any, RequestParams extends Record<string, any> = any, E = Error> { status: RequestStatus; data?: ResponseData; error?: E; headers: Record<string, any> | Headers; requestParams: RequestParams; fromCache: boolean; } export interface SubscribeOptions { /** Автоматически отписаться после завершения запроса */ autoUnsubscribe?: boolean; } /** * Дополнительные методы для request */ export interface RequestResponseModify<T, P extends Record<string, any> = any> { id: string; /** * Подписка на изменения состояния запроса */ subscribe: (listener: (state: RequestState<T, P>) => void, options?: SubscribeOptions) => VoidFunction; /** * Ожидание завершения запроса * @returns Promise с результатом запроса */ wait: () => Promise<QueryResult<T, Error>>; waitWithCallbacks: (handlers: { idle?: (request: RequestState<T, P>) => void; loading?: (request: RequestState<T, P>) => void; success?: (data: T | undefined, request: RequestState<T, P>) => void; error?: (error: Error | undefined, request: RequestState<T, P>) => void; }) => Promise<QueryResult<T, Error>>; /** * Отменить запрос */ abort: VoidFunction; then<TResult1 = QueryResult<T, Error>, TResult2 = never>(onfulfilled?: ((value: QueryResult<T, Error>) => TResult1 | PromiseLike<TResult1>) | undefined | null, onrejected?: ((reason: Error) => TResult2 | PromiseLike<TResult2>) | undefined | null): Promise<TResult1 | TResult2>; catch<TResult = never>(onrejected?: ((reason: Error) => TResult | PromiseLike<TResult>) | undefined | null): Promise<QueryResult<T, Error> | TResult>; finally(onfinally?: VoidFunction | undefined | null): Promise<QueryResult<T, Error>>; } /** * Структура эндпоинта * * Эндпоинт - это всего лишь определение того6 как будет вызван метод * Эндпоинт может быть вызван в разных частях приложения с разными параметрами * По этому нет смысла хранить ответы так как они будут перезаписываться * метод subscribe больше нужен для мониторинга * meta - метаинформация по эндпоинту (то как он сконфигурирован) */ export interface Endpoint<RequestParams extends Record<string, any> = any, ResponseData = any> { /** Счетчик вызова конкретного эндпоинта в проекте */ fetchCounts: number; /** Выполнить запрос с параметрами */ request: (params: RequestParams, options?: QueryOptions) => RequestResponseModify<ResponseData>; /** Подписаться на изменения состояния эндпоинта (в основном для сбора статистики) */ subscribe: (callback: (state: EndpointState) => void) => Unsubscribe; /** * Синхронно прочитать результат из кэша без сетевого запроса (fast-path для SSR). * Возвращает `undefined`, если кэш недоступен синхронно (async-хранилище, * заголовки в ключе кэша, отключённый кэш или протухшая запись). */ getCachedSync: (params: RequestParams) => QueryResult<ResponseData, Error> | undefined; /** Подписка на инвалидацию кэша по тегам эндпоинта (для авто-рефетча хуков) */ onCacheInvalidate: (listener: VoidFunction) => Unsubscribe; /** Сбросить состояние */ reset: () => Promise<void>; /** Метаданные эндпоинта */ meta: { /** Имя эндпоинта */ name: string; /** Теги эндпоинта */ tags: string[]; /** Теги, которые инвалидируются */ invalidatesTags: string[]; /** Настройки кэша */ cache: CacheConfig; }; destroy: VoidFunction; } /** * Функция для создания типизированных эндпоинтов */ export type CreateEndpoint = <RequestParams extends Record<string, any>, RequestResult>(config: EndpointConfig<RequestParams, RequestResult>) => EndpointConfig<RequestParams, RequestResult>;