synapse-storage 3.0.3 → 3.0.5

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.
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/utils/index.ts","../src/core/selector/selector.module.ts","../src/reactive/dispatcher/dispatcher.module.ts","../src/reactive/effects/effects.module.ts","../src/reactive/effects/utils/chunkRequestConsistent.ts","../src/reactive/effects/utils/chunkRequestParallel.ts","../src/utils/createSynapse.ts"],"sourcesContent":["export { type AnySynapseStore, createSynapse, type SynapseStoreBasic, type SynapseStoreWithDispatcher, type SynapseStoreWithEffects } from './createSynapse'\n","import { ILogger, IStorage } from '../storage'\nimport { ISelectorModule, Selector, SelectorAPI, SelectorOptions, Subscriber } from './selector.interface'\n\n// Отладка: управление через параметр DEBUG\nconst DEBUG = false\n\n// Глобальный кеш селекторов (используем имя селектора как ключ)\nconst GLOBAL_SELECTOR_CACHE = new Map<\n string,\n {\n api: SelectorAPI<any>\n refCount: number\n unsubscribeFunctions: VoidFunction[]\n }\n>()\n\n/**\n * Получает короткий хеш строки для добавления уникальности к имени селектора\n * @param str Строка для хеширования\n * @returns Короткий хеш\n */\nfunction getStringHash(str: string): string {\n let hash = 0\n if (str.length === 0) return hash.toString(36)\n\n for (let i = 0; i < str.length; i++) {\n const char = str.charCodeAt(i)\n hash = (hash << 5) - hash + char\n hash = hash & hash\n }\n\n // Преобразуем в короткую строку в формате base36\n return Math.abs(hash).toString(36).substring(0, 6)\n}\n\n/**\n * Интеллектуальное сравнение объектов по структуре\n * Сравнивает примитивы через ===, объекты - рекурсивно по структуре\n */\nfunction defaultEquals<T>(a: T, b: T): boolean {\n // Проверяем, одинаковые ли объекты по ссылке\n if (a === b) return true\n\n // Если один из объектов null или undefined, но не оба одновременно\n if (a == null || b == null) return false\n\n // Если это не объекты или функции, значит это примитивы\n if (typeof a !== 'object' && typeof a !== 'function' && typeof b !== 'object' && typeof b !== 'function') {\n return a === b\n }\n\n // Если это разные типы\n if (typeof a !== typeof b) return false\n\n // Если это даты\n if (a instanceof Date && b instanceof Date) {\n return a.getTime() === b.getTime()\n }\n\n // Если это массивы\n if (Array.isArray(a) && Array.isArray(b)) {\n if (a.length !== b.length) return false\n for (let i = 0; i < a.length; i++) {\n if (!defaultEquals(a[i], b[i])) return false\n }\n return true\n }\n\n // Обычные объекты\n if (typeof a === 'object' && typeof b === 'object') {\n const keysA = Object.keys(a as object)\n const keysB = Object.keys(b as object)\n\n if (keysA.length !== keysB.length) return false\n\n // Проверяем все ключи в a\n return keysA.every((key) => {\n if (!Object.prototype.hasOwnProperty.call(b, key)) return false\n return defaultEquals((a as any)[key], (b as any)[key])\n })\n }\n\n // По умолчанию считаем объекты разными\n return false\n}\n\n// Мемоизирует функцию селектора для оптимизации\nfunction memoizeSelector<S, R>(selectorFn: (state: S) => R, equals: (a: R, b: R) => boolean = defaultEquals): (state: S) => R {\n let lastState: S | undefined\n let lastResult: R | undefined\n let hasResult = false\n\n return function memoized(state: S): R {\n // Если это первый вызов или состояние изменилось\n if (!hasResult || lastState !== state) {\n const newResult = selectorFn(state)\n\n // Проверяем, изменился ли результат\n if (!hasResult || !equals(newResult, lastResult as R)) {\n lastResult = newResult\n }\n\n lastState = state\n hasResult = true\n }\n\n return lastResult as R\n }\n}\n\nclass SelectorSubscription<T> {\n private readonly id: string\n readonly subscribers = new Set<Subscriber<T>>()\n private lastValue?: T\n private readonly memoizedGetState: () => Promise<T>\n\n constructor(\n private readonly name: string,\n getState: () => Promise<T>,\n private readonly equals: (a: T, b: T) => boolean = defaultEquals,\n private readonly logger?: ILogger,\n ) {\n this.id = name\n\n // Создаем мемоизированную версию getState\n this.memoizedGetState = this.createMemoizedGetState(getState)\n\n if (DEBUG) {\n console.log(`[${this.id}] Создан new SelectorSubscription`)\n }\n }\n\n // Создает мемоизированную версию getState с кешированием результата\n private createMemoizedGetState(getState: () => Promise<T>): () => Promise<T> {\n let lastPromise: Promise<T> | null = null\n let isExecuting = false\n\n return async () => {\n // Если уже выполняется запрос, возвращаем его\n if (isExecuting && lastPromise) {\n return lastPromise\n }\n\n isExecuting = true\n\n try {\n lastPromise = getState()\n return await lastPromise\n } finally {\n isExecuting = false\n }\n }\n }\n\n async notify(): Promise<void> {\n try {\n const newValue = await this.memoizedGetState()\n\n // Проверка на изменение значения с использованием функции сравнения\n if (this.lastValue === undefined || !this.equals(newValue, this.lastValue)) {\n if (DEBUG) {\n console.log(`[${this.id}] Значение изменилось, notify()`, {\n old: this.lastValue,\n new: newValue,\n })\n }\n\n this.lastValue = newValue\n\n const promises = Array.from(this.subscribers).map(async (subscriber) => {\n try {\n await subscriber.notify(newValue)\n } catch (error) {\n this.logger?.error(`[${this.id}] Ошибка в уведомлении подписчика`, { error })\n }\n })\n\n await Promise.all(promises)\n } else if (DEBUG) {\n console.log(`[${this.id}] Значение не изменилось in notify(), пропуск уведомления`)\n }\n } catch (error: any) {\n this.logger?.error(`[${this.id}] Ошибка в notify()`, { error })\n throw error\n }\n }\n\n subscribe(subscriber: Subscriber<T>): () => void {\n if (DEBUG) {\n console.log(`[${this.id}] Добавлено новый подписчик, всего: ${this.subscribers.size + 1}`)\n }\n\n this.subscribers.add(subscriber)\n\n // Отправляем текущее значение, если оно есть\n if (this.lastValue !== undefined) {\n // Используем микротаск для асинхронности\n Promise.resolve().then(() => {\n try {\n subscriber.notify(this.lastValue as T)\n } catch (error) {\n this.logger?.error(`[${this.id}] Ошибка в первоначальном уведомлении`, { error })\n }\n })\n } else {\n // Если значения нет - запрашиваем его\n this.notify().catch((error) => {\n this.logger?.error(`[${this.id}] Ошибка в первоначальном уведомлении`, { error })\n })\n }\n\n return () => {\n if (DEBUG) {\n console.log(`[${this.id}] Подписчик удален, осталось: ${this.subscribers.size - 1}`)\n }\n this.subscribers.delete(subscriber)\n }\n }\n\n cleanup(): void {\n if (DEBUG) {\n console.log(`[${this.id}] Очистка подписки, было ${this.subscribers.size} подписчиков`)\n }\n this.subscribers.clear()\n this.lastValue = undefined\n }\n\n getId(): string {\n return this.id\n }\n}\n\nexport class SelectorModule<S extends Record<string, any>> implements ISelectorModule<S> {\n storageName: string\n\n private subscriptions = new Map<string, SelectorSubscription<any>>()\n private cachedState?: S\n\n private localSelectorCache = new Map<\n string,\n {\n api: SelectorAPI<any>\n dependencies?: SelectorAPI<any>[]\n unsubscribeFunctions: Array<() => void>\n }\n >()\n\n // Флаг для батчинга обновлений\n private batchUpdateInProgress = false\n private pendingUpdates = new Set<string>()\n\n constructor(\n private readonly source: IStorage<S>,\n private readonly logger?: ILogger,\n ) {\n this.storageName = source.name\n\n if (DEBUG) {\n console.log(`Создан SelectorModule для хранилища: ${this.storageName}`)\n }\n\n // Сразу получаем начальное состояние для кеширования\n this.source.getState().then((state) => {\n this.cachedState = state\n if (DEBUG) {\n console.log(`Кэшированное начальное состояние для ${this.storageName}`)\n }\n })\n }\n\n /**\n * Генерирует имя для селектора на основе его типа и функции\n */\n private generateName(isSimpleSelector: boolean, selectorOrDeps: any, resultFnOrOptions?: any): string {\n const type = isSimpleSelector ? 'simple' : 'combined'\n let hash = ''\n\n if (isSimpleSelector) {\n // Для простого селектора генерируем хеш на основе функции селектора\n const selectorStr = selectorOrDeps.toString()\n hash = getStringHash(selectorStr)\n } else {\n // Для комбинированного селектора генерируем хеш на основе ID зависимостей и функции результата\n const depsIds = (selectorOrDeps as SelectorAPI<any>[]).map((s) => s.getId()).join('_')\n const resultFnStr = resultFnOrOptions.toString()\n hash = getStringHash(depsIds + resultFnStr)\n }\n\n return `${this.storageName}_${type}_${hash}`\n }\n\n /**\n * Обрабатывает отложенные обновления, чтобы избежать каскадных уведомлений\n */\n private processPendingUpdates(): void {\n if (this.pendingUpdates.size === 0 || this.batchUpdateInProgress) return\n\n this.batchUpdateInProgress = true\n\n // Используем setTimeout для обеспечения асинхронности и батчинга обновлений\n setTimeout(async () => {\n try {\n // Копируем список селекторов для обновления\n const subscriptionsToUpdate = Array.from(this.pendingUpdates)\n this.pendingUpdates.clear()\n\n // Обновляем состояние один раз\n this.cachedState = await this.source.getState()\n\n // Обновляем все ожидающие селекторы\n const updatePromises = subscriptionsToUpdate.map(async (id) => {\n const subscription = this.subscriptions.get(id)\n if (subscription) {\n try {\n return await subscription.notify()\n } catch (error) {\n this.logger?.error(`Ошибка уведомления подписчика ${id}`, { error })\n }\n }\n return Promise.resolve()\n })\n\n await Promise.all(updatePromises)\n } catch (error) {\n this.logger?.error('Ошибка обработки ожидающих обновлений', { error })\n } finally {\n this.batchUpdateInProgress = false\n\n // Если появились новые обновления во время обработки, запускаем процесс снова\n if (this.pendingUpdates.size > 0) {\n this.processPendingUpdates()\n }\n }\n }, 0)\n }\n\n createSelector<T>(selector: Selector<S, T>, options?: SelectorOptions<T>): SelectorAPI<T>\n createSelector<Deps extends unknown[], T>(dependencies: { [K in keyof Deps]: SelectorAPI<Deps[K]> }, resultFn: (...args: Deps) => T, options?: SelectorOptions<T>): SelectorAPI<T>\n\n createSelector<T>(\n selectorOrDeps: Selector<S, T> | SelectorAPI<any>[],\n resultFnOrOptions?: ((...args: any[]) => T) | SelectorOptions<T>,\n optionsArg?: SelectorOptions<T>,\n ): SelectorAPI<T> {\n // Определяем, какую перегрузку используем\n const isSimpleSelector = !Array.isArray(selectorOrDeps)\n\n // Извлекаем options\n const options = isSimpleSelector ? (resultFnOrOptions as SelectorOptions<T>) || {} : optionsArg || {}\n\n // Используем предоставленное имя или генерируем новое\n const selectorId = options.name || this.generateName(isSimpleSelector, selectorOrDeps, isSimpleSelector ? undefined : resultFnOrOptions)\n\n // Проверяем локальный кеш\n if (this.localSelectorCache.has(selectorId)) {\n if (DEBUG) {\n console.log(`[${this.storageName}] Reusing cached selector: ${selectorId}`)\n }\n return this.localSelectorCache.get(selectorId)!.api\n }\n\n // Проверяем глобальный кеш\n if (GLOBAL_SELECTOR_CACHE.has(selectorId)) {\n const cached = GLOBAL_SELECTOR_CACHE.get(selectorId)!\n cached.refCount++\n if (DEBUG) {\n console.log(`[${this.storageName}] Повторное использование глобального кэшированного селектора: ${selectorId}, refCount: ${cached.refCount}`)\n }\n return cached.api\n }\n\n // Создаем новый селектор\n let result: SelectorAPI<T>\n let dependencies: SelectorAPI<any>[] | undefined\n let unsubscribeFunctions: VoidFunction[] = []\n\n if (isSimpleSelector) {\n // Простой селектор с мемоизацией\n const memoized = memoizeSelector(selectorOrDeps as Selector<S, T>, options.equals || defaultEquals)\n\n const created = this.createSimpleSelector(memoized, { ...options, name: selectorId, equals: options.equals || defaultEquals })\n\n result = created.api\n unsubscribeFunctions = created.unsubscribeFunctions\n } else {\n // Комбинированный селектор\n dependencies = selectorOrDeps as SelectorAPI<any>[]\n\n const created = this.createCombinedSelector(dependencies, resultFnOrOptions as (...args: any[]) => T, {\n ...options,\n name: selectorId,\n equals: options.equals || defaultEquals,\n })\n\n result = created.api\n unsubscribeFunctions = created.unsubscribeFunctions\n }\n\n // Сохраняем в кеши\n this.localSelectorCache.set(selectorId, {\n api: result,\n dependencies,\n unsubscribeFunctions,\n })\n\n GLOBAL_SELECTOR_CACHE.set(selectorId, {\n api: result,\n refCount: 1,\n unsubscribeFunctions,\n })\n\n if (DEBUG) {\n console.log(`[${this.storageName}] Создан новый селектор: ${selectorId}`)\n }\n\n return result\n }\n\n private createSimpleSelector<T>(\n selector: Selector<S, T>,\n options: SelectorOptions<T> & { name: string },\n ): {\n api: SelectorAPI<T>\n unsubscribeFunctions: VoidFunction[]\n } {\n if (DEBUG) {\n console.log(`[${this.storageName}] Создан простой селектор: ${options.name}`)\n }\n\n // Функция для получения данных\n const getState = async (): Promise<T> => {\n // Используем кешированное состояние, если оно доступно\n if (this.cachedState) {\n return selector(this.cachedState as S)\n }\n\n // Иначе получаем его из хранилища\n const state = await this.source.getState()\n this.cachedState = state // Обновляем кеш\n return selector(state as S)\n }\n\n const subscription = new SelectorSubscription(options.name, getState, options.equals || defaultEquals, this.logger)\n\n const id = subscription.getId()\n this.subscriptions.set(id, subscription)\n\n // Подписка на обновления хранилища с батчингом\n const unsubscribeFromStorage = this.source.subscribeToAll(async (event: any) => {\n if (event?.type === 'storage:update') {\n if (DEBUG) {\n console.log(`[${id}] Получено событие обновления хранилища`)\n }\n\n // Добавляем селектор в список ожидающих обновления\n this.pendingUpdates.add(id)\n this.processPendingUpdates()\n }\n })\n\n const unsubscribeFunctions = [unsubscribeFromStorage]\n\n return {\n api: {\n select: () => getState(),\n subscribe: (subscriber) => {\n return subscription.subscribe(subscriber)\n },\n getId: () => id,\n },\n unsubscribeFunctions,\n }\n }\n\n private createCombinedSelector<Deps extends unknown[], T>(\n selectors: { [K in keyof Deps]: SelectorAPI<Deps[K]> },\n resultFn: (...args: Deps) => T,\n options: SelectorOptions<T> & { name: string },\n ): {\n api: SelectorAPI<T>\n unsubscribeFunctions: Array<() => void>\n } {\n // Мемоизируем функцию для более эффективного вычисления\n const memoizedResultFn = memoizeSelector((args: Deps) => resultFn(...args), options.equals || defaultEquals)\n\n const getState = async () => {\n const values = await Promise.all(selectors.map((s) => s.select()))\n return memoizedResultFn(values as Deps)\n }\n\n const subscription = new SelectorSubscription(options.name, getState, options.equals || defaultEquals, this.logger)\n\n const id = subscription.getId()\n this.subscriptions.set(id, subscription)\n\n // Создаем подписки на зависимости с дебаунсингом\n let debounceTimer: any = null\n\n const triggerUpdate = () => {\n // Очищаем предыдущий таймер\n if (debounceTimer !== null) {\n clearTimeout(debounceTimer)\n }\n\n // Устанавливаем новый таймер для дебаунсинга\n debounceTimer = setTimeout(() => {\n debounceTimer = null\n\n // Вызываем уведомление только после завершения дебаунса\n subscription.notify().catch((error) => this.logger?.error(`[${id}] Ошибка в объединенном уведомлении:`, { error }))\n }, 10) // Короткая задержка для дебаунсинга\n }\n\n const unsubscribeFunctions = selectors.map((selector) =>\n selector.subscribe({\n notify: () => {\n triggerUpdate()\n },\n }),\n )\n\n return {\n api: {\n select: () => getState(),\n subscribe: (subscriber) => {\n return subscription.subscribe(subscriber)\n },\n getId: () => id,\n },\n unsubscribeFunctions,\n }\n }\n\n destroy(): void {\n if (DEBUG) {\n console.log(`[${this.storageName}] Началось уничтожение SelectorModule`)\n }\n\n // Очищаем все подписки\n this.subscriptions.forEach((sub) => sub.cleanup())\n this.subscriptions.clear()\n\n // Очищаем кеш состояния\n this.cachedState = undefined\n\n // Очищаем список ожидающих обновлений\n this.pendingUpdates.clear()\n\n // Очищаем подписки из локального кеша\n this.localSelectorCache.forEach((cached) => {\n cached.unsubscribeFunctions.forEach((unsub) => unsub())\n })\n\n // Собираем ключи для глобального кеша\n const keysToCheck = new Set<string>()\n this.localSelectorCache.forEach((_, key) => {\n keysToCheck.add(key)\n })\n this.localSelectorCache.clear()\n\n // Уменьшаем счетчики ссылок в глобальном кеше\n keysToCheck.forEach((key) => {\n const globalCached = GLOBAL_SELECTOR_CACHE.get(key)\n if (globalCached) {\n globalCached.refCount--\n if (globalCached.refCount <= 0) {\n globalCached.unsubscribeFunctions.forEach((unsub) => unsub())\n GLOBAL_SELECTOR_CACHE.delete(key)\n\n if (DEBUG) {\n console.log(`[${this.storageName}] Удален селектор из глобального кэша: ${key}`)\n }\n }\n }\n })\n if (DEBUG) {\n console.log(`[${this.storageName}] Уничтожен`)\n }\n }\n}\n","import { Observable, Subject } from 'rxjs'\n\nimport type { IStorage } from '../../core'\nimport { TypedAction } from '../effects'\n\n/**\n * Расширенное API для middleware\n */\nexport interface EnhancedMiddlewareAPI<T extends Record<string, any>> {\n // Базовые возможности\n getState: () => Promise<T>\n dispatch: (action: Action) => Promise<any>\n\n // Доступ к хранилищу напрямую\n storage: IStorage<T>\n\n // Доступ к потоку действий\n actions$: Observable<Action>\n\n // Доступ к зарегистрированным действиям\n actions: Record<string, DispatchFunction<any, any>>\n\n // Доступ к зарегистрированным наблюдателям\n watchers: Record<string, WatcherFunction<any>>\n\n // Вспомогательные методы\n findActionByType: (actionType: string) => DispatchFunction<any, any> | undefined\n findWatcherByType: (actionType: string) => WatcherFunction<any> | undefined\n}\n\n/**\n * Расширенное определение middleware\n */\nexport interface EnhancedMiddleware<T extends Record<string, any> = any> {\n (api: EnhancedMiddlewareAPI<T>): (next: (action: Action) => Promise<any>) => (action: Action) => Promise<any>\n}\n\n/**\n * Базовая структура действия\n */\nexport interface Action<T = unknown> {\n type: string\n payload?: T\n meta?: Record<string, any>\n}\n\n// Параметры исполнения функции действия\ninterface ActionExecutionOptions {\n // Веб-воркер для выполнения действия\n worker?: Worker\n // Функция мемоизации\n memoize?: (currentArgs: any[], previousArgs: any[], previousResult: any) => boolean\n}\n\n/**\n * Параметры для создания действия\n */\nexport interface ActionDefinition<TParams, TResult> {\n /** Тип действия для идентификации в потоке и эффектах */\n type: string\n /** Функция, выполняющая действие и возвращающая результат (payload) */\n action: (params: TParams) => Promise<TResult> | TResult\n /** Дополнительные метаданные (опционально) */\n meta?: Record<string, any>\n}\n\n/**\n * Определение типа для watcher'а\n */\ninterface WatcherDefinition<T, R> {\n type: string\n selector: (state: T) => R\n meta?: Record<string, any>\n // Опционально - функция для определения, изменилось ли значение\n shouldTrigger?: (prev: R | undefined, current: R) => boolean\n}\n\n/**\n * Тип для функции watcher\n */\nexport interface WatcherFunction<R> {\n (): Observable<TypedAction<R>>\n actionType: string\n meta?: Record<string, any>\n unsubscribe: VoidFunction\n}\n\n/**\n * Расширенный тип для функции настройки действий с поддержкой дополнительных утилит\n */\nexport type ActionsSetupWithUtils<T extends Record<string, unknown>> = (\n storage: IStorage<T>,\n utils: {\n createAction: ActionCreatorFactory\n createWatcher: <R>(config: WatcherDefinition<T, R>) => WatcherFunction<R>\n },\n) => Record<string, DispatchFunction<any, any> | WatcherFunction<any>>\n\n/**\n * Расширенная функция диспетчеризации\n */\nexport interface DispatchFunction<TParams, TResult> {\n /** Функция для вызова действия с параметрами */\n (params: TParams): Promise<TResult>\n /** Тип действия для использования в эффектах */\n actionType: string\n /** Метаданные действия */\n meta?: Record<string, any>\n /** Внутренний тип для идентификации */\n _type?: 'dispatch' | 'watchers'\n}\n\n/**\n * Тип для фабрики создателей действий\n */\ntype ActionCreatorFactory = <TParams, TResult>(config: ActionDefinition<TParams, TResult>, executionOptions?: ActionExecutionOptions) => DispatchFunction<TParams, TResult>\n\n/**\n * Тип для функции настройки действий\n */\nexport type ActionsSetup<T extends Record<string, unknown>> = (create: ActionCreatorFactory, storage: IStorage<T>) => Record<string, DispatchFunction<any, any>>\n\n/**\n * Извлекает тип результата из функции диспетчера\n */\nexport type ExtractResultType<T> = T extends DispatchFunction<any, infer R> ? R : never\n\n/**\n * Извлекает типы из функции настройки действий\n */\nexport type ActionsResult<F> = F extends (create: ActionCreatorFactory, storage: any, ...args: any[]) => infer R ? R : Record<string, DispatchFunction<any, any>>\n\n/**\n * Типизированный объект действий\n */\nexport type DispatchActions<T> = {\n [K in keyof T]: T[K] extends DispatchFunction<any, any> ? T[K] : never\n}\n\n/**\n * Типизированный объект watchers\n */\nexport type WatcherActions<T> = {\n [K in keyof T]: T[K] extends WatcherFunction<any> ? T[K] : never\n}\n\n/**\n * Параметры для Dispatcher\n */\ninterface DispatcherOptions<T extends Record<string, any>> {\n // Хранилище - обязательный параметр\n storage: IStorage<T>\n // Опциональные параметры\n worker?: Worker\n // DispatcherMiddleware для обработки действий\n middlewares?: EnhancedMiddleware<T>[]\n}\n\n/**\n * Интерфейс для API middleware\n */\nexport interface DispatcherMiddlewareAPI<T extends Record<string, any>> {\n getState: () => Promise<T>\n dispatch: (action: Action) => Promise<any>\n}\n\n/**\n * Интерфейс для middleware\n */\nexport interface DispatcherMiddleware<T extends Record<string, any> = any> {\n (api: DispatcherMiddlewareAPI<T>): (next: (action: Action) => Promise<any>) => (action: Action) => Promise<any>\n}\n\n/**\n * Класс Dispatcher для интеграции хранилищ с реактивной системой\n */\nexport class Dispatcher<T extends Record<string, any>, TActionsFn extends ActionsSetupWithUtils<T> = ActionsSetupWithUtils<T>> {\n // Поток действий\n private actions$ = new Subject<Action>()\n\n // Публичный Observable для действий\n public readonly actions: Observable<Action> = this.actions$.asObservable()\n\n // Методы диспетчеризации действий с типизацией\n public dispatch: Record<string, DispatchFunction<any, any>> = {}\n\n // Watcher'ы для реактивной подписки на изменения\n public watchers: Record<string, WatcherFunction<any>> = {}\n\n // Ссылка на хранилище\n private storage: IStorage<T>\n\n // Только один массив для хранения инициализированных middleware\n private middlewareFunctions: Array<(next: (action: Action) => Promise<any>) => (action: Action) => Promise<any>> = []\n\n // API для инициализации middleware\n private middlewareAPI: EnhancedMiddlewareAPI<T>\n\n /**\n * Создает новый экземпляр Dispatcher\n */\n constructor(private options: DispatcherOptions<T>) {\n this.storage = options.storage\n\n // Создаем API для middleware сразу\n this.middlewareAPI = {\n getState: () => this.storage.getState(),\n dispatch: async (action: Action) => {\n this.actions$.next(action)\n return action.payload\n },\n storage: this.storage,\n actions$: this.actions,\n actions: this.dispatch,\n watchers: this.watchers,\n findActionByType: (type) => this.findActionByType(type),\n findWatcherByType: (type) => this.findWatcherByType(type),\n }\n\n // Если есть middleware в options, добавляем их\n if (options.middlewares && options.middlewares.length > 0) {\n this.use(...options.middlewares)\n }\n }\n\n /**\n * Добавляет middleware в цепочку обработки\n */\n public use(...middlewares: EnhancedMiddleware<T>[]): this {\n // Инициализируем каждый middleware и добавляем только инициализированную версию\n for (let i = 0; i < middlewares.length; i++) {\n try {\n // Инициализируем middleware с API\n const initializedMiddleware = middlewares[i](this.middlewareAPI)\n this.middlewareFunctions.push(initializedMiddleware)\n } catch (error) {\n console.error(`Error initializing middleware [${i}]:`, error)\n }\n }\n return this\n }\n\n /**\n * Получает все действия с улучшенной типизацией\n */\n public getActions(): ActionsResult<TActionsFn> {\n return this.dispatch as ActionsResult<TActionsFn>\n }\n\n /**\n * Получает типизированные действия диспетчера\n */\n public getTypedDispatch<A extends Record<string, any>>(): DispatchActions<A> {\n return this.dispatch as DispatchActions<A>\n }\n\n /**\n * Получает типизированные watcher'ы\n */\n public getTypedWatchers<A extends Record<string, any>>(): WatcherActions<A> {\n return this.watchers as WatcherActions<A>\n }\n\n /**\n * Находит действие по типу\n */\n public findActionByType(actionType: string): DispatchFunction<any, any> | undefined {\n return Object.values(this.dispatch).find((action) => {\n return action.actionType.split(`[${this.storage.name}]`)[1] === actionType\n })\n }\n\n /**\n * Находит наблюдатель по типу\n */\n public findWatcherByType(actionType: string): WatcherFunction<any> | undefined {\n return Object.values(this.watchers).find((watcher) => watcher.actionType === actionType)\n }\n\n /**\n * Создает действие\n */\n public createAction<TParams, TResult>(actionConfig: ActionDefinition<TParams, TResult>, executionOptions?: ActionExecutionOptions): DispatchFunction<TParams, TResult> {\n const actionType = `[${this.storage.name}]${actionConfig.type}`\n\n // Для мемоизации храним последние аргументы и результат\n let lastArgs: TParams[] | null = null\n let lastResult: TResult | null = null\n\n // Создаем функцию диспетчеризации\n const dispatchFn = async (params: TParams): Promise<TResult> => {\n const args = [params] as TParams[]\n\n // Проверяем мемоизацию\n if (executionOptions?.memoize && lastArgs && lastResult) {\n if (executionOptions.memoize(args, lastArgs, lastResult)) {\n return lastResult\n }\n }\n\n // Создаем объект действия\n const actionObject: Action<TResult> = {\n type: actionType,\n meta: actionConfig.meta,\n }\n\n // Применяем middleware цепочку\n let result: TResult\n\n if (this.middlewareFunctions.length > 0) {\n // Базовая функция выполнения действия\n // Строим цепочку middleware в обратном порядке\n let chain = async (action: Action): Promise<TResult> => {\n if (executionOptions?.worker) {\n return this.executeInWorker(executionOptions.worker, actionType, args, actionConfig.action)\n } else {\n return Promise.resolve(actionConfig.action(params))\n }\n }\n\n // Проходим по middleware в обратном порядке\n // Важно: сначала создаем всю цепочку, затем выполняем\n for (let i = this.middlewareFunctions.length - 1; i >= 0; i--) {\n const currentMiddleware = this.middlewareFunctions[i]\n const nextChain = chain // Сохраняем предыдущую цепочку\n\n // Создаем новую цепочку, которая вызывает текущий middleware,\n // передавая предыдущую цепочку как функцию next\n chain = async (action: Action) => {\n // Создаем функцию next для передачи в middleware\n const next = async (nextAction: Action) => nextChain(nextAction)\n\n // Получаем обработчик действия и сразу вызываем его\n return currentMiddleware(next)(action)\n }\n }\n\n // Выполняем действие через цепочку middleware\n result = await chain(actionObject)\n } else {\n // Выполняем действие напрямую без middleware\n if (executionOptions?.worker) {\n result = await this.executeInWorker(executionOptions.worker, actionType, args, actionConfig.action)\n } else {\n result = await actionConfig.action(params)\n }\n }\n\n // Обновляем объект действия результатом\n actionObject.payload = result\n\n // Сохраняем аргументы и результат для мемоизации\n lastArgs = [...args]\n lastResult = result\n\n // Отправляем информацию о действии в поток\n this.actions$.next(actionObject)\n\n return result\n }\n\n dispatchFn._type = 'dispatch'\n // Добавляем тип действия как свойство функции\n Object.defineProperty(dispatchFn, 'actionType', {\n value: actionType,\n writable: false,\n enumerable: true,\n })\n\n // Добавляем метаданные, если они есть\n if (actionConfig.meta) {\n Object.defineProperty(dispatchFn, 'meta', {\n value: actionConfig.meta,\n writable: false,\n enumerable: true,\n })\n }\n\n return dispatchFn as DispatchFunction<TParams, TResult>\n }\n /**\n * Создает watcher для отслеживания изменений в хранилище\n */\n public createWatcher<R>(config: WatcherDefinition<T, R>): WatcherFunction<R> {\n // Логика остается без изменений\n const actionType = `[${this.storage.name}]${config.type}`\n\n // Создаем Subject для этого watcher'а\n const subject = new Subject<TypedAction<R>>()\n\n // Предыдущее значение для сравнения\n let prevValue: R | undefined\n\n // Подписываемся на изменения состояния\n const unsubscribe = this.storage.subscribe(config.selector, (value: R) => {\n // Проверяем, нужно ли генерировать событие\n if (!config.shouldTrigger || config.shouldTrigger(prevValue, value)) {\n // Создаем действие\n const action: TypedAction<R> = {\n type: actionType,\n payload: value,\n meta: config.meta,\n }\n\n // Отправляем в основной поток действий\n this.actions$.next(action)\n\n // Отправляем в поток этого watcher'а\n subject.next(action)\n\n // Обновляем предыдущее значение\n prevValue = value\n }\n })\n\n // Создаем функцию watcher'а\n const watcherFn = () => subject.asObservable()\n watcherFn._type = 'watchers'\n // Добавляем свойства\n Object.defineProperty(watcherFn, 'actionType', {\n value: actionType,\n writable: false,\n enumerable: true,\n })\n\n if (config.meta) {\n Object.defineProperty(watcherFn, 'meta', {\n value: config.meta,\n writable: false,\n enumerable: true,\n })\n }\n\n // Добавляем метод для отписки\n Object.defineProperty(watcherFn, 'unsubscribe', {\n value: unsubscribe,\n writable: false,\n enumerable: true,\n })\n\n //@ts-ignore\n return watcherFn as WatcherFunction<R>\n }\n\n /**\n * Выполняет действие в worker\n */\n private async executeInWorker<TParams, TResult>(\n worker: Worker,\n actionType: string,\n args: TParams[],\n fallbackAction?: (params: TParams) => Promise<TResult> | TResult,\n ): Promise<TResult> {\n // Логика остается без изменений\n return new Promise((resolve, reject) => {\n const requestId = `${actionType}_${Date.now()}_${Math.random()}`\n\n const handleMessage = (event: MessageEvent) => {\n if (event.data.requestId === requestId) {\n worker.removeEventListener('message', handleMessage)\n\n if (event.data.error) {\n reject(new Error(event.data.error))\n } else {\n resolve(event.data.result)\n }\n }\n }\n\n worker.addEventListener('message', handleMessage)\n\n worker.postMessage({\n type: actionType,\n args,\n requestId,\n })\n\n // Опционально: таймаут\n setTimeout(() => {\n worker.removeEventListener('message', handleMessage)\n reject(new Error(`Worker execution timeout for action: ${actionType}`))\n }, 30000) // 30 секунд таймаут\n })\n }\n}\n\n/**\n * Функция для создания типизированного диспетчера\n */\nexport function createDispatcher<TState extends Record<string, any>, TActions extends ActionsSetupWithUtils<TState>>(\n options: DispatcherOptions<TState>,\n actionsSetup: TActions,\n): Dispatcher<TState, TActions> & {\n dispatch: DispatchActions<ReturnType<TActions>>\n watchers: WatcherActions<ReturnType<TActions>>\n} {\n // Создаем экземпляр диспетчера\n const dispatcher = new Dispatcher<TState, TActions>(options)\n\n // Вызываем функцию настройки действий с обновленной структурой аргументов\n const actions = actionsSetup(options.storage, {\n createAction: (actionConfig, executionOptions) => dispatcher.createAction(actionConfig, executionOptions),\n createWatcher: (config) => dispatcher.createWatcher(config),\n })\n\n // Регистрируем все созданные объекты в соответствующих коллекциях\n for (const [key, fn] of Object.entries(actions)) {\n if (typeof fn === 'function') {\n const type = (fn as any)._type\n // @ts-ignore\n dispatcher[type][key] = fn\n }\n }\n\n return dispatcher as Dispatcher<TState, TActions> & {\n dispatch: DispatchActions<ReturnType<TActions>>\n watchers: WatcherActions<ReturnType<TActions>>\n }\n}\nexport type CreateDispatcherType = ReturnType<typeof createDispatcher>\n","import { combineLatest, merge, Observable, of, OperatorFunction, pipe, Subject } from 'rxjs'\nimport { catchError, filter, map, share, switchMap, take, withLatestFrom } from 'rxjs/operators'\n\nimport { IStorage } from '../../core'\nimport { Action, ActionsResult, Dispatcher, DispatchFunction, ExtractResultType, WatcherFunction } from '../dispatcher'\nimport { ChunkRequestConsistent, chunkRequestConsistent, ChunkRequestParallel, chunkRequestParallel } from './utils'\n\n/**\n * Тип действия с типизированным payload\n */\nexport interface TypedAction<P> extends Action<P> {\n type: string\n payload: P\n}\n\n/**\n * Тип для внешних состояний\n */\nexport type ExternalStates = Record<string, Observable<any>>\n\n/**\n * Тип для базового эффекта без доступа к состоянию\n */\nexport type EffectBase<TDispatchers extends Record<string, Dispatcher<any, any>> = Record<string, never>, TServices extends Record<string, any> = Record<string, never>> = (\n action$: Observable<Action>,\n dispatchers: TDispatchers,\n services: TServices,\n) => Observable<unknown>\n\n/**\n * Тип для эффекта с доступом к состоянию и конфигурации - это основной тип, который используется по умолчанию\n */\nexport type Effect<\n TState extends Record<string, any> = any,\n TDispatchers extends Record<string, Dispatcher<any, any>> = Record<string, never>,\n TServices extends Record<string, any> = Record<string, never>,\n TConfig extends Record<string, any> = Record<string, never>,\n TExternalStates extends ExternalStates = Record<string, never>,\n> = (\n action$: Observable<Action>,\n state$: Observable<TState>,\n externalStates: TExternalStates,\n dispatchers: TDispatchers,\n services: TServices,\n config: TConfig,\n) => Observable<unknown>\n\n/**\n * Тип для получения типов действий диспетчера\n */\nexport type DispatcherActions<T> = T extends Dispatcher<any, infer A> ? ActionsResult<A> : Record<string, DispatchFunction<any, any>>\n\n/**\n * Конфигурация для валидации в validateMap\n */\nexport interface ValidateConfig {\n conditions: boolean[]\n skipAction: (() => any) | any | ((() => any) | any)[]\n}\n\n/**\n * Утилиты для запросов в validateMap\n */\nexport interface ValidateMapRequestUtils {\n chunkRequest: ChunkRequestParallel\n chunkRequestConsistent: ChunkRequestConsistent\n}\n\n/**\n * Оператор для фильтрации действий по типу с сохранением типа payload\n */\nexport function ofType<T extends DispatchFunction<any, any> | WatcherFunction<any>>(\n actionFn: T,\n): OperatorFunction<Action, TypedAction<T extends WatcherFunction<infer R> ? R : ExtractResultType<T>>> {\n const { actionType } = actionFn\n\n if (!actionType) {\n console.warn('ofType: Action function does not have actionType property', actionFn)\n return filter(() => false) as any\n }\n\n // Определяем тип payload в зависимости от типа функции\n type PayloadType = T extends WatcherFunction<infer R> ? R : ExtractResultType<T>\n\n // Улучшенная реализация с явными типами\n return (source$: Observable<Action>): Observable<TypedAction<PayloadType>> => {\n return source$.pipe(filter((action): action is TypedAction<PayloadType> => action !== undefined && action.type === actionType))\n }\n}\n\n/**\n * Оператор для фильтрации действий по нескольким типам с объединением типов payload\n * @param actionFns Массив функций действий\n */\nexport function ofTypes<T extends DispatchFunction<any, any>[]>(actionFns: [...T]): OperatorFunction<Action, TypedAction<ExtractResultType<T[number]>>> {\n // Получаем типы действий\n const actionTypes = actionFns.map((fn) => fn.actionType).filter(Boolean)\n\n if (actionTypes.length === 0) {\n console.warn('ofTypes: No valid action types found in array', actionFns)\n return filter(() => false) as OperatorFunction<Action, TypedAction<ExtractResultType<T[number]>>>\n }\n\n // Union тип для payload из всех действий\n type CombinedPayloadType = ExtractResultType<T[number]>\n\n // Улучшенная реализация с явными типами\n return (source$: Observable<Action>): Observable<TypedAction<CombinedPayloadType>> => {\n return source$.pipe(filter((action): action is TypedAction<CombinedPayloadType> => action !== undefined && actionTypes.includes(action.type)))\n }\n}\n\n/**\n * Оператор для ожидания выполнения всех указанных действий\n * @param actionFns Массив функций действий\n */\nexport function ofTypesWaitAll<T extends DispatchFunction<any, any>[]>(actionFns: [...T]) {\n return (source$: Observable<Action>): Observable<{ [K in keyof T]: TypedAction<ExtractResultType<T[K]>> }> => {\n // Создаем потоки для каждого типа действия\n const actionTypes = actionFns.map((fn) => fn.actionType).filter(Boolean)\n\n if (actionTypes.length === 0) {\n console.warn('ofTypesWaitAll: No valid action types found in array', actionFns)\n return of([]) as any\n }\n\n // Для каждого типа действия создаем поток,\n // который берет первое срабатывание\n const actionStreams = actionTypes.map((type, index) =>\n source$.pipe(\n filter((action) => action.type === type),\n take(1),\n map((action) =>\n // Сохраняем ассоциацию с индексом, чтобы соответствовать\n // порядку в исходном массиве actionFns\n ({ index, action }),\n ),\n ),\n )\n\n // Ждем, пока все потоки выдадут значения, и сортируем результаты\n // по индексу для сохранения порядка\n return combineLatest(actionStreams).pipe(\n map((results) => {\n // Сортируем по индексу\n results.sort((a, b) => a.index - b.index)\n // Убираем индекс и возвращаем только действия\n return results.map((r) => r.action) as any\n }),\n )\n }\n}\n\n/**\n * Создает Observable с выбранными данными из состояния\n * @param state$ Поток состояния\n * @param selectors Селекторы для выбора частей состояния\n * @returns Observable с массивом выбранных значений\n */\nexport function selectorMap<TState, TResults extends any[]>(\n state$: Observable<TState>,\n ...selectors: { [K in keyof TResults]: (state: TState) => TResults[K] }\n): Observable<TResults> {\n return state$.pipe(\n map((state) => {\n return selectors.map((selector) => selector(state)) as TResults\n }),\n )\n}\n\n/**\n * Создает именованный объект вместо массива\n * @param state$ Поток состояния\n * @param selectors Объект с селекторами\n * @returns Observable с объектом выбранных значений\n */\nexport function selectorObject<TState, TResult extends Record<string, any>>(\n state$: Observable<TState>,\n selectors: { [K in keyof TResult]: (state: TState) => TResult[K] },\n): Observable<TResult> {\n return state$.pipe(\n map((state) => {\n const result = {} as TResult\n for (const [key, selector] of Object.entries(selectors)) {\n result[key as keyof TResult] = selector(state)\n }\n return result\n }),\n )\n}\n\n/**\n * Оператор validateMap для валидации данных и условного вызова API\n */\nexport function validateMap<T, TResult = any>({\n validator,\n apiCall,\n}: {\n validator?: (value: T) => ValidateConfig\n apiCall: (value: T, utils: ValidateMapRequestUtils) => Observable<TResult>\n}): OperatorFunction<T, any> {\n return pipe(\n switchMap((pipeData) => {\n /**\n * Функция вызова API-метода\n */\n const callApi = () =>\n apiCall(pipeData, {\n chunkRequest: chunkRequestParallel,\n chunkRequestConsistent: chunkRequestConsistent,\n })\n\n /**\n * Если валидацию не используем - сразу вызываем запрос\n */\n if (!validator) return callApi()\n\n const validateConfig = validator(pipeData)\n const { conditions, skipAction } = validateConfig\n const conditionMet = conditions.every(Boolean)\n\n /**\n * Если валидация не пройдена - вызываем экшн сброса\n */\n if (!conditionMet) {\n if (Array.isArray(skipAction)) {\n // eslint-disable-next-line no-unsafe-optional-chaining\n return of(...skipAction?.filter(Boolean).map((action) => (typeof action === 'function' ? action() : action)))\n }\n return of(typeof skipAction === 'function' ? skipAction() : skipAction)\n }\n\n return callApi()\n }),\n )\n}\n\n/**\n * Класс для управления эффектами с поддержкой доступа к состоянию и конфигурации\n * Основной класс, который следует использовать\n */\nexport class EffectsModule<\n TState extends Record<string, any> = any,\n TDispatchers extends Record<string, Dispatcher<any, any>> = Record<string, never>,\n TServices extends Record<string, any> = Record<string, never>,\n TConfig extends Record<string, any> = Record<string, never>,\n TExternalStates extends ExternalStates = Record<string, never>,\n> {\n private effects: Effect<TState, TDispatchers, TServices, TConfig, TExternalStates>[] = []\n private subscriptions: Array<{ unsubscribe: VoidFunction }> = []\n private running = false\n private action$ = new Subject<Action>()\n\n /**\n * Поток состояния\n */\n public readonly state$: Observable<TState>\n\n /**\n * Создает модуль эффектов с доступом к состоянию, внешним состояниям и конфигурации\n * @param storage Хранилище состояния\n * @param externalStates Внешние состояния\n * @param dispatchers Объект с диспетчерами\n * @param services Объект с сервисами\n * @param config Глобальная конфигурация для всех эффектов\n */\n constructor(\n private storage: IStorage<TState>,\n private externalStates: TExternalStates = {} as TExternalStates,\n private dispatchers: TDispatchers,\n private services: TServices = {} as TServices,\n private config: TConfig = {} as TConfig,\n ) {\n this.subscribeToDispatchers()\n\n // Создаем поток состояния\n this.state$ = new Observable<TState>((observer) => {\n // Отправляем начальное состояние\n this.storage.getState().then((state) => observer.next(state))\n\n // Подписываемся на все изменения\n const unsubscribe = this.storage.subscribeToAll(() => {\n this.storage.getState().then((state) => observer.next(state))\n })\n\n // Отписываемся при завершении\n return () => unsubscribe()\n }).pipe(share())\n }\n\n /**\n * Подписывается на действия от всех диспетчеров\n */\n private subscribeToDispatchers() {\n for (const [_, dispatcher] of Object.entries(this.dispatchers)) {\n const subscription = dispatcher.actions.subscribe((action) => {\n this.action$.next(action)\n })\n\n this.subscriptions.push(subscription)\n }\n }\n\n add(effect: Effect<TState, TDispatchers, TServices, TConfig, TExternalStates>): this {\n this.effects.push(effect)\n\n if (this.running) {\n this.subscribeToEffect(effect)\n }\n\n return this\n }\n\n /**\n * Добавляет несколько эффектов\n * @param effects Эффекты для добавления\n * @returns Текущий модуль\n */\n addEffects(effects: Effect<TState, TDispatchers, TServices, TConfig, TExternalStates>[]): this {\n effects.forEach((effect) => this.add(effect))\n return this\n }\n\n /**\n * Запускает все эффекты\n * @returns Текущий модуль\n */\n start(): this {\n if (this.running) {\n return this\n }\n\n this.effects.forEach((effect) => this.subscribeToEffect(effect))\n this.running = true\n\n return this\n }\n\n /**\n * Останавливает все эффекты\n * @returns Текущий модуль\n */\n stop(): this {\n this.subscriptions.forEach((sub) => sub.unsubscribe())\n this.subscriptions = []\n this.running = false\n\n return this\n }\n\n /**\n * Подписывается на конкретный эффект\n * @param effect Эффект для подписки\n */\n private subscribeToEffect(effect: Effect<TState, TDispatchers, TServices, TConfig, TExternalStates>): void {\n try {\n const output$ = effect(this.action$.asObservable(), this.state$, this.externalStates, this.dispatchers, this.services, this.config).pipe(\n catchError((err) => {\n console.error('Error in effect:', err)\n return of(null)\n }),\n )\n\n const subscription = output$.subscribe((result) => {\n if (result === null || result === undefined) {\n return\n }\n\n if (typeof result === 'function') {\n try {\n result()\n } catch (callError) {\n console.error('Error calling effect result function:', callError)\n }\n }\n })\n\n this.subscriptions.push(subscription)\n } catch (setupError) {\n console.error('Error setting up effect:', setupError)\n }\n }\n}\n\n/**\n * Вспомогательная функция для создания типизированного эффекта без состояния\n * @deprecated Используйте createEffect вместо этого\n */\nexport function createEffectBase<TDispatchers extends Record<string, Dispatcher<any, any>>, TServices extends Record<string, any>>(\n effect: EffectBase<TDispatchers, TServices>,\n): EffectBase<TDispatchers, TServices> {\n return effect\n}\n\n/**\n * Вспомогательная функция для создания типизированного эффекта с состоянием и конфигурацией\n */\nexport function createEffect<\n TState extends Record<string, any>,\n TDispatchers extends Record<string, Dispatcher<any, any>>,\n TServices extends Record<string, any>,\n TConfig extends Record<string, any> = Record<string, never>,\n TExternalStates extends ExternalStates = Record<string, never>,\n>(effect: Effect<TState, TDispatchers, TServices, TConfig, TExternalStates>): Effect<TState, TDispatchers, TServices, TConfig, TExternalStates> {\n return effect\n}\n\n/**\n * Объединяет несколько эффектов в один\n * @param effects Эффекты для объединения\n * @returns Объединенный эффект\n */\nexport function combineEffects<\n TState extends Record<string, any>,\n TDispatchers extends Record<string, Dispatcher<any, any>>,\n TServices extends Record<string, any>,\n TConfig extends Record<string, any> = Record<string, never>,\n TExternalStates extends ExternalStates = Record<string, never>,\n>(...effects: Effect<TState, TDispatchers, TServices, TConfig, TExternalStates>[]): Effect<TState, TDispatchers, TServices, TConfig, TExternalStates> {\n return (action$, state$, externalStates, dispatchers, services, config) => {\n const outputs = effects.map((effect) => {\n try {\n return effect(action$, state$, externalStates, dispatchers, services, config)\n } catch (error) {\n console.error('Error in one of combined effects:', error)\n return of(null)\n }\n })\n return merge(...outputs)\n }\n}\n","import { Observable, of } from 'rxjs'\nimport { concatAll, delay, mergeMap, toArray } from 'rxjs/operators'\n\nimport { chunk } from '../../../_utils'\n\n/**\n * Разбиение запроса на порции\n * Отправляется ПОСЛЕДОВАТЕЛЬНО n-запросов и дожидается ответа от каждого\n * @param fn - функция в которую передается chunk и возвращается функция api\n * @param arr - массив который нужно поделить\n * @param size - размер порции\n * @param delayMs - задержка между запросами в миллисекундах\n */\nexport const chunkRequestConsistent = <T, R>(fn: (chunk: T[]) => Observable<R>, arr: T[], size: number, delayMs = 0): Observable<R[]> => {\n const chunks = chunk(arr, size).map((chunkItem) => of(chunkItem).pipe(delay(delayMs), mergeMap(fn)))\n return of(...chunks).pipe(concatAll(), toArray())\n}\nexport type ChunkRequestConsistent = typeof chunkRequestConsistent\n","import { forkJoin, Observable, timer } from 'rxjs'\nimport { mergeMap } from 'rxjs/operators'\n\nimport { chunk } from '../../../_utils'\n\n/**\n * Разбиение запроса на порции\n * Отправляется ПАРАЛЛЕЛЬНО n-запросов и дожидается ответа от каждого\n * @param fn - функция в которую передается chunk и возвращается функция api\n * @param arr - массив который нужно поделить\n * @param size - размер порции\n * @param delayMs - задержка между запросами в миллисекундах\n */\nexport const chunkRequestParallel = <T, R>(fn: (chunk: T[]) => Observable<R>, arr: T[], size: number, delayMs = 0): Observable<R[]> =>\n forkJoin(chunk(arr, size).map((chunkItem, index) => timer(index * delayMs).pipe(mergeMap(() => fn(chunkItem)))))\nexport type ChunkRequestParallel = typeof chunkRequestParallel\n","import { Observable } from 'rxjs'\n\nimport { ISelectorModule, IStorage, SelectorModule } from '../core'\nimport { Effect, EffectsModule, ExternalStates } from '../reactive'\n\n// Вспомогательные типы для извлечения типов из других типов\nexport type ExtractPromiseType<T> = T extends Promise<infer U> ? U : T\nexport type ExtractStorageType<T> = T extends IStorage<infer U> ? U : never\nexport type ExtractDispatchType<T> = T extends { dispatch: infer D } ? D : never\n\nexport type StorageCreatorFunction<T extends Record<string, any>> = () => Promise<IStorage<T>>\n\n/**\n * Базовая конфигурация хранилища\n */\ntype BaseSynapseConfig<TStore extends Record<string, any>, TSelectors = any, TExternalSelectors extends Record<string, any> = Record<string, any>> = (\n | { storage: IStorage<TStore>; createStorageFn?: undefined }\n | { storage?: undefined; createStorageFn: StorageCreatorFunction<TStore> }\n) & {\n // Внешние селекторы\n externalSelectors?: TExternalSelectors\n // Функция создания селекторов\n createSelectorsFn?: (selectorModule: ISelectorModule<TStore>, externalSelectors: TExternalSelectors) => TSelectors\n}\n\n/**\n * Конфигурация с dispatcher и effects\n */\nexport type CreateSynapseConfigWithEffects<\n TStore extends Record<string, any>,\n TSelectors = any,\n TDispatcher = any,\n TApi extends Record<string, any> = Record<string, never>,\n TConfig extends Record<string, any> = Record<string, never>,\n TExternalSelectors extends Record<string, any> = Record<string, any>,\n> = BaseSynapseConfig<TStore, TSelectors, TExternalSelectors> & {\n // Функция создания диспетчера (обязательная)\n createDispatcherFn: (storage: IStorage<TStore>) => TDispatcher\n // Функция создания конфигурации для эффектов (обязательная)\n createEffectConfig: (dispatcher: TDispatcher) => {\n dispatchers: Record<string, any>\n api?: TApi\n config?: TConfig\n externalStates?: ExternalStates\n }\n // Эффекты\n effects?: Effect<TStore, any, TApi, TConfig, any>[]\n}\n\n/**\n * Конфигурация только с dispatcher\n */\nexport type CreateSynapseConfigWithDispatcher<\n TStore extends Record<string, any>,\n TSelectors = any,\n TDispatcher = any,\n TExternalSelectors extends Record<string, any> = Record<string, any>,\n> = BaseSynapseConfig<TStore, TSelectors, TExternalSelectors> & {\n // Функция создания диспетчера (обязательная)\n createDispatcherFn: (storage: IStorage<TStore>) => TDispatcher\n // Эффекты отсутствуют\n createEffectConfig?: never\n effects?: never\n}\n\n/**\n * Конфигурация без dispatcher\n */\nexport type CreateSynapseConfigBasic<\n TStore extends Record<string, any>,\n TSelectors = any,\n TExternalSelectors extends Record<string, any> = Record<string, any>,\n> = BaseSynapseConfig<TStore, TSelectors, TExternalSelectors> & {\n // Dispatcher отсутствует\n createDispatcherFn?: never\n createEffectConfig?: never\n effects?: never\n}\n\n/**\n * Результат с dispatcher и effects\n */\nexport interface SynapseStoreWithEffects<TStore extends Record<string, any>, TStorage extends IStorage<TStore>, TSelectors, TActions> {\n storage: TStorage\n selectors: TSelectors\n actions: TActions\n state$: Observable<TStore>\n dispatcher: any\n destroy: () => Promise<void>\n}\n\n/**\n * Результат только с dispatcher\n */\nexport interface SynapseStoreWithDispatcher<TStore extends Record<string, any>, TStorage extends IStorage<TStore>, TSelectors, TActions> {\n storage: TStorage\n selectors: TSelectors\n actions: TActions\n dispatcher: any\n destroy: () => Promise<void>\n}\n\n/**\n * Результат без dispatcher\n */\nexport interface SynapseStoreBasic<TStore extends Record<string, any>, TStorage extends IStorage<TStore>, TSelectors> {\n storage: TStorage\n selectors: TSelectors\n destroy: () => Promise<void>\n}\n\n/**\n * Union-тип для всех возможных результатов createSynapse\n */\nexport type AnySynapseStore<TStore extends Record<string, any> = any, TStorage extends IStorage<TStore> = IStorage<any>, TSelectors = any, TActions = any> =\n | SynapseStoreWithEffects<TStore, TStorage, TSelectors, TActions>\n | SynapseStoreWithDispatcher<TStore, TStorage, TSelectors, TActions>\n | SynapseStoreBasic<TStore, TStorage, TSelectors>\n\n/**\n * Перегрузки функции createSynapse\n */\n\n// Случай 1: С dispatcher и effects\nexport function createSynapse<\n TStore extends Record<string, any>,\n TSelectors = any,\n TDispatcher = any,\n TApi extends Record<string, any> = Record<string, never>,\n TConfig extends Record<string, any> = Record<string, never>,\n TExternalSelectors extends Record<string, any> = Record<string, any>,\n TStorage extends IStorage<TStore> = IStorage<TStore>,\n>(\n config: CreateSynapseConfigWithEffects<TStore, TSelectors, TDispatcher, TApi, TConfig, TExternalSelectors>,\n): Promise<SynapseStoreWithEffects<TStore, TStorage, TSelectors, ExtractDispatchType<TDispatcher>>>\n\n// Случай 2: Только с dispatcher\nexport function createSynapse<\n TStore extends Record<string, any>,\n TSelectors = any,\n TDispatcher = any,\n TExternalSelectors extends Record<string, any> = Record<string, any>,\n TStorage extends IStorage<TStore> = IStorage<TStore>,\n>(\n config: CreateSynapseConfigWithDispatcher<TStore, TSelectors, TDispatcher, TExternalSelectors>,\n): Promise<SynapseStoreWithDispatcher<TStore, TStorage, TSelectors, ExtractDispatchType<TDispatcher>>>\n\n// Случай 3: Без dispatcher\nexport function createSynapse<\n TStore extends Record<string, any>,\n TSelectors = any,\n TExternalSelectors extends Record<string, any> = Record<string, any>,\n TStorage extends IStorage<TStore> = IStorage<TStore>,\n>(config: CreateSynapseConfigBasic<TStore, TSelectors, TExternalSelectors>): Promise<SynapseStoreBasic<TStore, TStorage, TSelectors>>\n\n// Основная реализация\nexport async function createSynapse<\n TStore extends Record<string, any>,\n TSelectors = any,\n TDispatcher = any,\n TApi extends Record<string, any> = Record<string, never>,\n TConfig extends Record<string, any> = Record<string, never>,\n TExternalSelectors extends Record<string, any> = Record<string, any>,\n TStorage extends IStorage<TStore> = IStorage<TStore>,\n>(config: any): Promise<any> {\n // Создаем и инициализируем хранилище\n const storageInstance = (config.createStorageFn ? await config.createStorageFn() : config.storage!) as TStorage\n\n // Создаем сборщики для последующей очистки\n const cleanupCallbacks: Array<() => Promise<void> | void> = []\n\n const result: any = {\n storage: storageInstance,\n selectors: {} as TSelectors,\n destroy: async () => {\n for (const callback of cleanupCallbacks) {\n await callback()\n }\n },\n }\n\n cleanupCallbacks.push(() => storageInstance.destroy())\n\n let dispatcher: TDispatcher | undefined\n let selectorModule: ISelectorModule<TStore>\n let effectsModule: any\n\n // Создаем модуль селекторов\n if (config.createSelectorsFn) {\n try {\n selectorModule = new SelectorModule(storageInstance)\n\n const externalSelectors = config.externalSelectors || ({} as TExternalSelectors)\n\n result.selectors = config.createSelectorsFn(selectorModule, externalSelectors)\n\n if (typeof (selectorModule as any).destroy === 'function') {\n cleanupCallbacks.push(() => selectorModule.destroy())\n }\n } catch (error) {\n console.error('Ошибка создания selectors:', error)\n }\n }\n\n // Создаем диспетчер\n if (config.createDispatcherFn) {\n dispatcher = config.createDispatcherFn(storageInstance)\n result.dispatcher = dispatcher\n\n // @ts-ignore\n if (dispatcher && 'dispatch' in dispatcher) {\n result.actions = (dispatcher as any).dispatch\n\n if (typeof (dispatcher as any).destroy === 'function') {\n cleanupCallbacks.push(() => (dispatcher as any).destroy())\n }\n }\n }\n\n // Создаем и настраиваем модуль эффектов\n if (config.createEffectConfig && dispatcher) {\n try {\n const { dispatchers, api, config: effectConfig, externalStates } = config.createEffectConfig(dispatcher)\n\n // Получаем внешние состояния из конфигурации эффектов\n const effectExternalStates = externalStates || {}\n\n // Создаем модуль эффектов с внешними состояниями\n effectsModule = new EffectsModule(storageInstance, effectExternalStates, dispatchers, api, effectConfig)\n\n // Добавляем эффекты\n if (Array.isArray(config.effects)) {\n // @ts-ignore\n config.effects.forEach((effect) => {\n if (effectsModule) effectsModule.add(effect)\n })\n }\n\n // Запускаем модуль эффектов\n effectsModule.start()\n result.state$ = effectsModule.state$\n\n // Добавляем очистку эффектов\n cleanupCallbacks.push(() => {\n if (effectsModule) effectsModule.stop()\n })\n } catch (error) {\n console.error('Ошибка создания модуля эффектов:', error)\n }\n }\n\n return result\n}\n"],"mappings":"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","names":["import_rxjs","import_operators","import_rxjs","import_rxjs","import_operators"]}
package/dist/utils.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/core/selector/selector.module.ts","../src/reactive/dispatcher/dispatcher.module.ts","../src/reactive/effects/effects.module.ts","../src/reactive/effects/utils/chunkRequestConsistent.ts","../src/reactive/effects/utils/chunkRequestParallel.ts","../src/utils/createSynapse.ts"],"sourcesContent":["import { ILogger, IStorage } from '../storage'\nimport { ISelectorModule, Selector, SelectorAPI, SelectorOptions, Subscriber } from './selector.interface'\n\n// Отладка: управление через параметр DEBUG\nconst DEBUG = false\n\n// Глобальный кеш селекторов (используем имя селектора как ключ)\nconst GLOBAL_SELECTOR_CACHE = new Map<\n string,\n {\n api: SelectorAPI<any>\n refCount: number\n unsubscribeFunctions: VoidFunction[]\n }\n>()\n\n/**\n * Получает короткий хеш строки для добавления уникальности к имени селектора\n * @param str Строка для хеширования\n * @returns Короткий хеш\n */\nfunction getStringHash(str: string): string {\n let hash = 0\n if (str.length === 0) return hash.toString(36)\n\n for (let i = 0; i < str.length; i++) {\n const char = str.charCodeAt(i)\n hash = (hash << 5) - hash + char\n hash = hash & hash\n }\n\n // Преобразуем в короткую строку в формате base36\n return Math.abs(hash).toString(36).substring(0, 6)\n}\n\n/**\n * Интеллектуальное сравнение объектов по структуре\n * Сравнивает примитивы через ===, объекты - рекурсивно по структуре\n */\nfunction defaultEquals<T>(a: T, b: T): boolean {\n // Проверяем, одинаковые ли объекты по ссылке\n if (a === b) return true\n\n // Если один из объектов null или undefined, но не оба одновременно\n if (a == null || b == null) return false\n\n // Если это не объекты или функции, значит это примитивы\n if (typeof a !== 'object' && typeof a !== 'function' && typeof b !== 'object' && typeof b !== 'function') {\n return a === b\n }\n\n // Если это разные типы\n if (typeof a !== typeof b) return false\n\n // Если это даты\n if (a instanceof Date && b instanceof Date) {\n return a.getTime() === b.getTime()\n }\n\n // Если это массивы\n if (Array.isArray(a) && Array.isArray(b)) {\n if (a.length !== b.length) return false\n for (let i = 0; i < a.length; i++) {\n if (!defaultEquals(a[i], b[i])) return false\n }\n return true\n }\n\n // Обычные объекты\n if (typeof a === 'object' && typeof b === 'object') {\n const keysA = Object.keys(a as object)\n const keysB = Object.keys(b as object)\n\n if (keysA.length !== keysB.length) return false\n\n // Проверяем все ключи в a\n return keysA.every((key) => {\n if (!Object.prototype.hasOwnProperty.call(b, key)) return false\n return defaultEquals((a as any)[key], (b as any)[key])\n })\n }\n\n // По умолчанию считаем объекты разными\n return false\n}\n\n// Мемоизирует функцию селектора для оптимизации\nfunction memoizeSelector<S, R>(selectorFn: (state: S) => R, equals: (a: R, b: R) => boolean = defaultEquals): (state: S) => R {\n let lastState: S | undefined\n let lastResult: R | undefined\n let hasResult = false\n\n return function memoized(state: S): R {\n // Если это первый вызов или состояние изменилось\n if (!hasResult || lastState !== state) {\n const newResult = selectorFn(state)\n\n // Проверяем, изменился ли результат\n if (!hasResult || !equals(newResult, lastResult as R)) {\n lastResult = newResult\n }\n\n lastState = state\n hasResult = true\n }\n\n return lastResult as R\n }\n}\n\nclass SelectorSubscription<T> {\n private readonly id: string\n readonly subscribers = new Set<Subscriber<T>>()\n private lastValue?: T\n private readonly memoizedGetState: () => Promise<T>\n\n constructor(\n private readonly name: string,\n getState: () => Promise<T>,\n private readonly equals: (a: T, b: T) => boolean = defaultEquals,\n private readonly logger?: ILogger,\n ) {\n this.id = name\n\n // Создаем мемоизированную версию getState\n this.memoizedGetState = this.createMemoizedGetState(getState)\n\n if (DEBUG) {\n console.log(`[${this.id}] Создан new SelectorSubscription`)\n }\n }\n\n // Создает мемоизированную версию getState с кешированием результата\n private createMemoizedGetState(getState: () => Promise<T>): () => Promise<T> {\n let lastPromise: Promise<T> | null = null\n let isExecuting = false\n\n return async () => {\n // Если уже выполняется запрос, возвращаем его\n if (isExecuting && lastPromise) {\n return lastPromise\n }\n\n isExecuting = true\n\n try {\n lastPromise = getState()\n return await lastPromise\n } finally {\n isExecuting = false\n }\n }\n }\n\n async notify(): Promise<void> {\n try {\n const newValue = await this.memoizedGetState()\n\n // Проверка на изменение значения с использованием функции сравнения\n if (this.lastValue === undefined || !this.equals(newValue, this.lastValue)) {\n if (DEBUG) {\n console.log(`[${this.id}] Значение изменилось, notify()`, {\n old: this.lastValue,\n new: newValue,\n })\n }\n\n this.lastValue = newValue\n\n const promises = Array.from(this.subscribers).map(async (subscriber) => {\n try {\n await subscriber.notify(newValue)\n } catch (error) {\n this.logger?.error(`[${this.id}] Ошибка в уведомлении подписчика`, { error })\n }\n })\n\n await Promise.all(promises)\n } else if (DEBUG) {\n console.log(`[${this.id}] Значение не изменилось in notify(), пропуск уведомления`)\n }\n } catch (error: any) {\n this.logger?.error(`[${this.id}] Ошибка в notify()`, { error })\n throw error\n }\n }\n\n subscribe(subscriber: Subscriber<T>): () => void {\n if (DEBUG) {\n console.log(`[${this.id}] Добавлено новый подписчик, всего: ${this.subscribers.size + 1}`)\n }\n\n this.subscribers.add(subscriber)\n\n // Отправляем текущее значение, если оно есть\n if (this.lastValue !== undefined) {\n // Используем микротаск для асинхронности\n Promise.resolve().then(() => {\n try {\n subscriber.notify(this.lastValue as T)\n } catch (error) {\n this.logger?.error(`[${this.id}] Ошибка в первоначальном уведомлении`, { error })\n }\n })\n } else {\n // Если значения нет - запрашиваем его\n this.notify().catch((error) => {\n this.logger?.error(`[${this.id}] Ошибка в первоначальном уведомлении`, { error })\n })\n }\n\n return () => {\n if (DEBUG) {\n console.log(`[${this.id}] Подписчик удален, осталось: ${this.subscribers.size - 1}`)\n }\n this.subscribers.delete(subscriber)\n }\n }\n\n cleanup(): void {\n if (DEBUG) {\n console.log(`[${this.id}] Очистка подписки, было ${this.subscribers.size} подписчиков`)\n }\n this.subscribers.clear()\n this.lastValue = undefined\n }\n\n getId(): string {\n return this.id\n }\n}\n\nexport class SelectorModule<S extends Record<string, any>> implements ISelectorModule<S> {\n storageName: string\n\n private subscriptions = new Map<string, SelectorSubscription<any>>()\n private cachedState?: S\n\n private localSelectorCache = new Map<\n string,\n {\n api: SelectorAPI<any>\n dependencies?: SelectorAPI<any>[]\n unsubscribeFunctions: Array<() => void>\n }\n >()\n\n // Флаг для батчинга обновлений\n private batchUpdateInProgress = false\n private pendingUpdates = new Set<string>()\n\n constructor(\n private readonly source: IStorage<S>,\n private readonly logger?: ILogger,\n ) {\n this.storageName = source.name\n\n if (DEBUG) {\n console.log(`Создан SelectorModule для хранилища: ${this.storageName}`)\n }\n\n // Сразу получаем начальное состояние для кеширования\n this.source.getState().then((state) => {\n this.cachedState = state\n if (DEBUG) {\n console.log(`Кэшированное начальное состояние для ${this.storageName}`)\n }\n })\n }\n\n /**\n * Генерирует имя для селектора на основе его типа и функции\n */\n private generateName(isSimpleSelector: boolean, selectorOrDeps: any, resultFnOrOptions?: any): string {\n const type = isSimpleSelector ? 'simple' : 'combined'\n let hash = ''\n\n if (isSimpleSelector) {\n // Для простого селектора генерируем хеш на основе функции селектора\n const selectorStr = selectorOrDeps.toString()\n hash = getStringHash(selectorStr)\n } else {\n // Для комбинированного селектора генерируем хеш на основе ID зависимостей и функции результата\n const depsIds = (selectorOrDeps as SelectorAPI<any>[]).map((s) => s.getId()).join('_')\n const resultFnStr = resultFnOrOptions.toString()\n hash = getStringHash(depsIds + resultFnStr)\n }\n\n return `${this.storageName}_${type}_${hash}`\n }\n\n /**\n * Обрабатывает отложенные обновления, чтобы избежать каскадных уведомлений\n */\n private processPendingUpdates(): void {\n if (this.pendingUpdates.size === 0 || this.batchUpdateInProgress) return\n\n this.batchUpdateInProgress = true\n\n // Используем setTimeout для обеспечения асинхронности и батчинга обновлений\n setTimeout(async () => {\n try {\n // Копируем список селекторов для обновления\n const subscriptionsToUpdate = Array.from(this.pendingUpdates)\n this.pendingUpdates.clear()\n\n // Обновляем состояние один раз\n this.cachedState = await this.source.getState()\n\n // Обновляем все ожидающие селекторы\n const updatePromises = subscriptionsToUpdate.map(async (id) => {\n const subscription = this.subscriptions.get(id)\n if (subscription) {\n try {\n return await subscription.notify()\n } catch (error) {\n this.logger?.error(`Ошибка уведомления подписчика ${id}`, { error })\n }\n }\n return Promise.resolve()\n })\n\n await Promise.all(updatePromises)\n } catch (error) {\n this.logger?.error('Ошибка обработки ожидающих обновлений', { error })\n } finally {\n this.batchUpdateInProgress = false\n\n // Если появились новые обновления во время обработки, запускаем процесс снова\n if (this.pendingUpdates.size > 0) {\n this.processPendingUpdates()\n }\n }\n }, 0)\n }\n\n createSelector<T>(selector: Selector<S, T>, options?: SelectorOptions<T>): SelectorAPI<T>\n createSelector<Deps extends unknown[], T>(dependencies: { [K in keyof Deps]: SelectorAPI<Deps[K]> }, resultFn: (...args: Deps) => T, options?: SelectorOptions<T>): SelectorAPI<T>\n\n createSelector<T>(\n selectorOrDeps: Selector<S, T> | SelectorAPI<any>[],\n resultFnOrOptions?: ((...args: any[]) => T) | SelectorOptions<T>,\n optionsArg?: SelectorOptions<T>,\n ): SelectorAPI<T> {\n // Определяем, какую перегрузку используем\n const isSimpleSelector = !Array.isArray(selectorOrDeps)\n\n // Извлекаем options\n const options = isSimpleSelector ? (resultFnOrOptions as SelectorOptions<T>) || {} : optionsArg || {}\n\n // Используем предоставленное имя или генерируем новое\n const selectorId = options.name || this.generateName(isSimpleSelector, selectorOrDeps, isSimpleSelector ? undefined : resultFnOrOptions)\n\n // Проверяем локальный кеш\n if (this.localSelectorCache.has(selectorId)) {\n if (DEBUG) {\n console.log(`[${this.storageName}] Reusing cached selector: ${selectorId}`)\n }\n return this.localSelectorCache.get(selectorId)!.api\n }\n\n // Проверяем глобальный кеш\n if (GLOBAL_SELECTOR_CACHE.has(selectorId)) {\n const cached = GLOBAL_SELECTOR_CACHE.get(selectorId)!\n cached.refCount++\n if (DEBUG) {\n console.log(`[${this.storageName}] Повторное использование глобального кэшированного селектора: ${selectorId}, refCount: ${cached.refCount}`)\n }\n return cached.api\n }\n\n // Создаем новый селектор\n let result: SelectorAPI<T>\n let dependencies: SelectorAPI<any>[] | undefined\n let unsubscribeFunctions: VoidFunction[] = []\n\n if (isSimpleSelector) {\n // Простой селектор с мемоизацией\n const memoized = memoizeSelector(selectorOrDeps as Selector<S, T>, options.equals || defaultEquals)\n\n const created = this.createSimpleSelector(memoized, { ...options, name: selectorId, equals: options.equals || defaultEquals })\n\n result = created.api\n unsubscribeFunctions = created.unsubscribeFunctions\n } else {\n // Комбинированный селектор\n dependencies = selectorOrDeps as SelectorAPI<any>[]\n\n const created = this.createCombinedSelector(dependencies, resultFnOrOptions as (...args: any[]) => T, {\n ...options,\n name: selectorId,\n equals: options.equals || defaultEquals,\n })\n\n result = created.api\n unsubscribeFunctions = created.unsubscribeFunctions\n }\n\n // Сохраняем в кеши\n this.localSelectorCache.set(selectorId, {\n api: result,\n dependencies,\n unsubscribeFunctions,\n })\n\n GLOBAL_SELECTOR_CACHE.set(selectorId, {\n api: result,\n refCount: 1,\n unsubscribeFunctions,\n })\n\n if (DEBUG) {\n console.log(`[${this.storageName}] Создан новый селектор: ${selectorId}`)\n }\n\n return result\n }\n\n private createSimpleSelector<T>(\n selector: Selector<S, T>,\n options: SelectorOptions<T> & { name: string },\n ): {\n api: SelectorAPI<T>\n unsubscribeFunctions: VoidFunction[]\n } {\n if (DEBUG) {\n console.log(`[${this.storageName}] Создан простой селектор: ${options.name}`)\n }\n\n // Функция для получения данных\n const getState = async (): Promise<T> => {\n // Используем кешированное состояние, если оно доступно\n if (this.cachedState) {\n return selector(this.cachedState as S)\n }\n\n // Иначе получаем его из хранилища\n const state = await this.source.getState()\n this.cachedState = state // Обновляем кеш\n return selector(state as S)\n }\n\n const subscription = new SelectorSubscription(options.name, getState, options.equals || defaultEquals, this.logger)\n\n const id = subscription.getId()\n this.subscriptions.set(id, subscription)\n\n // Подписка на обновления хранилища с батчингом\n const unsubscribeFromStorage = this.source.subscribeToAll(async (event: any) => {\n if (event?.type === 'storage:update') {\n if (DEBUG) {\n console.log(`[${id}] Получено событие обновления хранилища`)\n }\n\n // Добавляем селектор в список ожидающих обновления\n this.pendingUpdates.add(id)\n this.processPendingUpdates()\n }\n })\n\n const unsubscribeFunctions = [unsubscribeFromStorage]\n\n return {\n api: {\n select: () => getState(),\n subscribe: (subscriber) => {\n return subscription.subscribe(subscriber)\n },\n getId: () => id,\n },\n unsubscribeFunctions,\n }\n }\n\n private createCombinedSelector<Deps extends unknown[], T>(\n selectors: { [K in keyof Deps]: SelectorAPI<Deps[K]> },\n resultFn: (...args: Deps) => T,\n options: SelectorOptions<T> & { name: string },\n ): {\n api: SelectorAPI<T>\n unsubscribeFunctions: Array<() => void>\n } {\n // Мемоизируем функцию для более эффективного вычисления\n const memoizedResultFn = memoizeSelector((args: Deps) => resultFn(...args), options.equals || defaultEquals)\n\n const getState = async () => {\n const values = await Promise.all(selectors.map((s) => s.select()))\n return memoizedResultFn(values as Deps)\n }\n\n const subscription = new SelectorSubscription(options.name, getState, options.equals || defaultEquals, this.logger)\n\n const id = subscription.getId()\n this.subscriptions.set(id, subscription)\n\n // Создаем подписки на зависимости с дебаунсингом\n let debounceTimer: any = null\n\n const triggerUpdate = () => {\n // Очищаем предыдущий таймер\n if (debounceTimer !== null) {\n clearTimeout(debounceTimer)\n }\n\n // Устанавливаем новый таймер для дебаунсинга\n debounceTimer = setTimeout(() => {\n debounceTimer = null\n\n // Вызываем уведомление только после завершения дебаунса\n subscription.notify().catch((error) => this.logger?.error(`[${id}] Ошибка в объединенном уведомлении:`, { error }))\n }, 10) // Короткая задержка для дебаунсинга\n }\n\n const unsubscribeFunctions = selectors.map((selector) =>\n selector.subscribe({\n notify: () => {\n triggerUpdate()\n },\n }),\n )\n\n return {\n api: {\n select: () => getState(),\n subscribe: (subscriber) => {\n return subscription.subscribe(subscriber)\n },\n getId: () => id,\n },\n unsubscribeFunctions,\n }\n }\n\n destroy(): void {\n if (DEBUG) {\n console.log(`[${this.storageName}] Началось уничтожение SelectorModule`)\n }\n\n // Очищаем все подписки\n this.subscriptions.forEach((sub) => sub.cleanup())\n this.subscriptions.clear()\n\n // Очищаем кеш состояния\n this.cachedState = undefined\n\n // Очищаем список ожидающих обновлений\n this.pendingUpdates.clear()\n\n // Очищаем подписки из локального кеша\n this.localSelectorCache.forEach((cached) => {\n cached.unsubscribeFunctions.forEach((unsub) => unsub())\n })\n\n // Собираем ключи для глобального кеша\n const keysToCheck = new Set<string>()\n this.localSelectorCache.forEach((_, key) => {\n keysToCheck.add(key)\n })\n this.localSelectorCache.clear()\n\n // Уменьшаем счетчики ссылок в глобальном кеше\n keysToCheck.forEach((key) => {\n const globalCached = GLOBAL_SELECTOR_CACHE.get(key)\n if (globalCached) {\n globalCached.refCount--\n if (globalCached.refCount <= 0) {\n globalCached.unsubscribeFunctions.forEach((unsub) => unsub())\n GLOBAL_SELECTOR_CACHE.delete(key)\n\n if (DEBUG) {\n console.log(`[${this.storageName}] Удален селектор из глобального кэша: ${key}`)\n }\n }\n }\n })\n if (DEBUG) {\n console.log(`[${this.storageName}] Уничтожен`)\n }\n }\n}\n","import { Observable, Subject } from 'rxjs'\n\nimport type { IStorage } from '../../core'\nimport { TypedAction } from '../effects'\n\n/**\n * Расширенное API для middleware\n */\nexport interface EnhancedMiddlewareAPI<T extends Record<string, any>> {\n // Базовые возможности\n getState: () => Promise<T>\n dispatch: (action: Action) => Promise<any>\n\n // Доступ к хранилищу напрямую\n storage: IStorage<T>\n\n // Доступ к потоку действий\n actions$: Observable<Action>\n\n // Доступ к зарегистрированным действиям\n actions: Record<string, DispatchFunction<any, any>>\n\n // Доступ к зарегистрированным наблюдателям\n watchers: Record<string, WatcherFunction<any>>\n\n // Вспомогательные методы\n findActionByType: (actionType: string) => DispatchFunction<any, any> | undefined\n findWatcherByType: (actionType: string) => WatcherFunction<any> | undefined\n}\n\n/**\n * Расширенное определение middleware\n */\nexport interface EnhancedMiddleware<T extends Record<string, any> = any> {\n (api: EnhancedMiddlewareAPI<T>): (next: (action: Action) => Promise<any>) => (action: Action) => Promise<any>\n}\n\n/**\n * Базовая структура действия\n */\nexport interface Action<T = unknown> {\n type: string\n payload?: T\n meta?: Record<string, any>\n}\n\n// Параметры исполнения функции действия\ninterface ActionExecutionOptions {\n // Веб-воркер для выполнения действия\n worker?: Worker\n // Функция мемоизации\n memoize?: (currentArgs: any[], previousArgs: any[], previousResult: any) => boolean\n}\n\n/**\n * Параметры для создания действия\n */\nexport interface ActionDefinition<TParams, TResult> {\n /** Тип действия для идентификации в потоке и эффектах */\n type: string\n /** Функция, выполняющая действие и возвращающая результат (payload) */\n action: (params: TParams) => Promise<TResult> | TResult\n /** Дополнительные метаданные (опционально) */\n meta?: Record<string, any>\n}\n\n/**\n * Определение типа для watcher'а\n */\ninterface WatcherDefinition<T, R> {\n type: string\n selector: (state: T) => R\n meta?: Record<string, any>\n // Опционально - функция для определения, изменилось ли значение\n shouldTrigger?: (prev: R | undefined, current: R) => boolean\n}\n\n/**\n * Тип для функции watcher\n */\nexport interface WatcherFunction<R> {\n (): Observable<TypedAction<R>>\n actionType: string\n meta?: Record<string, any>\n unsubscribe: VoidFunction\n}\n\n/**\n * Расширенный тип для функции настройки действий с поддержкой дополнительных утилит\n */\nexport type ActionsSetupWithUtils<T extends Record<string, unknown>> = (\n storage: IStorage<T>,\n utils: {\n createAction: ActionCreatorFactory\n createWatcher: <R>(config: WatcherDefinition<T, R>) => WatcherFunction<R>\n },\n) => Record<string, DispatchFunction<any, any> | WatcherFunction<any>>\n\n/**\n * Расширенная функция диспетчеризации\n */\nexport interface DispatchFunction<TParams, TResult> {\n /** Функция для вызова действия с параметрами */\n (params: TParams): Promise<TResult>\n /** Тип действия для использования в эффектах */\n actionType: string\n /** Метаданные действия */\n meta?: Record<string, any>\n /** Внутренний тип для идентификации */\n _type?: 'dispatch' | 'watchers'\n}\n\n/**\n * Тип для фабрики создателей действий\n */\ntype ActionCreatorFactory = <TParams, TResult>(config: ActionDefinition<TParams, TResult>, executionOptions?: ActionExecutionOptions) => DispatchFunction<TParams, TResult>\n\n/**\n * Тип для функции настройки действий\n */\nexport type ActionsSetup<T extends Record<string, unknown>> = (create: ActionCreatorFactory, storage: IStorage<T>) => Record<string, DispatchFunction<any, any>>\n\n/**\n * Извлекает тип результата из функции диспетчера\n */\nexport type ExtractResultType<T> = T extends DispatchFunction<any, infer R> ? R : never\n\n/**\n * Извлекает типы из функции настройки действий\n */\nexport type ActionsResult<F> = F extends (create: ActionCreatorFactory, storage: any, ...args: any[]) => infer R ? R : Record<string, DispatchFunction<any, any>>\n\n/**\n * Типизированный объект действий\n */\nexport type DispatchActions<T> = {\n [K in keyof T]: T[K] extends DispatchFunction<any, any> ? T[K] : never\n}\n\n/**\n * Типизированный объект watchers\n */\nexport type WatcherActions<T> = {\n [K in keyof T]: T[K] extends WatcherFunction<any> ? T[K] : never\n}\n\n/**\n * Параметры для Dispatcher\n */\ninterface DispatcherOptions<T extends Record<string, any>> {\n // Хранилище - обязательный параметр\n storage: IStorage<T>\n // Опциональные параметры\n worker?: Worker\n // DispatcherMiddleware для обработки действий\n middlewares?: EnhancedMiddleware<T>[]\n}\n\n/**\n * Интерфейс для API middleware\n */\nexport interface DispatcherMiddlewareAPI<T extends Record<string, any>> {\n getState: () => Promise<T>\n dispatch: (action: Action) => Promise<any>\n}\n\n/**\n * Интерфейс для middleware\n */\nexport interface DispatcherMiddleware<T extends Record<string, any> = any> {\n (api: DispatcherMiddlewareAPI<T>): (next: (action: Action) => Promise<any>) => (action: Action) => Promise<any>\n}\n\n/**\n * Класс Dispatcher для интеграции хранилищ с реактивной системой\n */\nexport class Dispatcher<T extends Record<string, any>, TActionsFn extends ActionsSetupWithUtils<T> = ActionsSetupWithUtils<T>> {\n // Поток действий\n private actions$ = new Subject<Action>()\n\n // Публичный Observable для действий\n public readonly actions: Observable<Action> = this.actions$.asObservable()\n\n // Методы диспетчеризации действий с типизацией\n public dispatch: Record<string, DispatchFunction<any, any>> = {}\n\n // Watcher'ы для реактивной подписки на изменения\n public watchers: Record<string, WatcherFunction<any>> = {}\n\n // Ссылка на хранилище\n private storage: IStorage<T>\n\n // Только один массив для хранения инициализированных middleware\n private middlewareFunctions: Array<(next: (action: Action) => Promise<any>) => (action: Action) => Promise<any>> = []\n\n // API для инициализации middleware\n private middlewareAPI: EnhancedMiddlewareAPI<T>\n\n /**\n * Создает новый экземпляр Dispatcher\n */\n constructor(private options: DispatcherOptions<T>) {\n this.storage = options.storage\n\n // Создаем API для middleware сразу\n this.middlewareAPI = {\n getState: () => this.storage.getState(),\n dispatch: async (action: Action) => {\n this.actions$.next(action)\n return action.payload\n },\n storage: this.storage,\n actions$: this.actions,\n actions: this.dispatch,\n watchers: this.watchers,\n findActionByType: (type) => this.findActionByType(type),\n findWatcherByType: (type) => this.findWatcherByType(type),\n }\n\n // Если есть middleware в options, добавляем их\n if (options.middlewares && options.middlewares.length > 0) {\n this.use(...options.middlewares)\n }\n }\n\n /**\n * Добавляет middleware в цепочку обработки\n */\n public use(...middlewares: EnhancedMiddleware<T>[]): this {\n // Инициализируем каждый middleware и добавляем только инициализированную версию\n for (let i = 0; i < middlewares.length; i++) {\n try {\n // Инициализируем middleware с API\n const initializedMiddleware = middlewares[i](this.middlewareAPI)\n this.middlewareFunctions.push(initializedMiddleware)\n } catch (error) {\n console.error(`Error initializing middleware [${i}]:`, error)\n }\n }\n return this\n }\n\n /**\n * Получает все действия с улучшенной типизацией\n */\n public getActions(): ActionsResult<TActionsFn> {\n return this.dispatch as ActionsResult<TActionsFn>\n }\n\n /**\n * Получает типизированные действия диспетчера\n */\n public getTypedDispatch<A extends Record<string, any>>(): DispatchActions<A> {\n return this.dispatch as DispatchActions<A>\n }\n\n /**\n * Получает типизированные watcher'ы\n */\n public getTypedWatchers<A extends Record<string, any>>(): WatcherActions<A> {\n return this.watchers as WatcherActions<A>\n }\n\n /**\n * Находит действие по типу\n */\n public findActionByType(actionType: string): DispatchFunction<any, any> | undefined {\n return Object.values(this.dispatch).find((action) => {\n return action.actionType.split(`[${this.storage.name}]`)[1] === actionType\n })\n }\n\n /**\n * Находит наблюдатель по типу\n */\n public findWatcherByType(actionType: string): WatcherFunction<any> | undefined {\n return Object.values(this.watchers).find((watcher) => watcher.actionType === actionType)\n }\n\n /**\n * Создает действие\n */\n public createAction<TParams, TResult>(actionConfig: ActionDefinition<TParams, TResult>, executionOptions?: ActionExecutionOptions): DispatchFunction<TParams, TResult> {\n const actionType = `[${this.storage.name}]${actionConfig.type}`\n\n // Для мемоизации храним последние аргументы и результат\n let lastArgs: TParams[] | null = null\n let lastResult: TResult | null = null\n\n // Создаем функцию диспетчеризации\n const dispatchFn = async (params: TParams): Promise<TResult> => {\n const args = [params] as TParams[]\n\n // Проверяем мемоизацию\n if (executionOptions?.memoize && lastArgs && lastResult) {\n if (executionOptions.memoize(args, lastArgs, lastResult)) {\n return lastResult\n }\n }\n\n // Создаем объект действия\n const actionObject: Action<TResult> = {\n type: actionType,\n meta: actionConfig.meta,\n }\n\n // Применяем middleware цепочку\n let result: TResult\n\n if (this.middlewareFunctions.length > 0) {\n // Базовая функция выполнения действия\n // Строим цепочку middleware в обратном порядке\n let chain = async (action: Action): Promise<TResult> => {\n if (executionOptions?.worker) {\n return this.executeInWorker(executionOptions.worker, actionType, args, actionConfig.action)\n } else {\n return Promise.resolve(actionConfig.action(params))\n }\n }\n\n // Проходим по middleware в обратном порядке\n // Важно: сначала создаем всю цепочку, затем выполняем\n for (let i = this.middlewareFunctions.length - 1; i >= 0; i--) {\n const currentMiddleware = this.middlewareFunctions[i]\n const nextChain = chain // Сохраняем предыдущую цепочку\n\n // Создаем новую цепочку, которая вызывает текущий middleware,\n // передавая предыдущую цепочку как функцию next\n chain = async (action: Action) => {\n // Создаем функцию next для передачи в middleware\n const next = async (nextAction: Action) => nextChain(nextAction)\n\n // Получаем обработчик действия и сразу вызываем его\n return currentMiddleware(next)(action)\n }\n }\n\n // Выполняем действие через цепочку middleware\n result = await chain(actionObject)\n } else {\n // Выполняем действие напрямую без middleware\n if (executionOptions?.worker) {\n result = await this.executeInWorker(executionOptions.worker, actionType, args, actionConfig.action)\n } else {\n result = await actionConfig.action(params)\n }\n }\n\n // Обновляем объект действия результатом\n actionObject.payload = result\n\n // Сохраняем аргументы и результат для мемоизации\n lastArgs = [...args]\n lastResult = result\n\n // Отправляем информацию о действии в поток\n this.actions$.next(actionObject)\n\n return result\n }\n\n dispatchFn._type = 'dispatch'\n // Добавляем тип действия как свойство функции\n Object.defineProperty(dispatchFn, 'actionType', {\n value: actionType,\n writable: false,\n enumerable: true,\n })\n\n // Добавляем метаданные, если они есть\n if (actionConfig.meta) {\n Object.defineProperty(dispatchFn, 'meta', {\n value: actionConfig.meta,\n writable: false,\n enumerable: true,\n })\n }\n\n return dispatchFn as DispatchFunction<TParams, TResult>\n }\n /**\n * Создает watcher для отслеживания изменений в хранилище\n */\n public createWatcher<R>(config: WatcherDefinition<T, R>): WatcherFunction<R> {\n // Логика остается без изменений\n const actionType = `[${this.storage.name}]${config.type}`\n\n // Создаем Subject для этого watcher'а\n const subject = new Subject<TypedAction<R>>()\n\n // Предыдущее значение для сравнения\n let prevValue: R | undefined\n\n // Подписываемся на изменения состояния\n const unsubscribe = this.storage.subscribe(config.selector, (value: R) => {\n // Проверяем, нужно ли генерировать событие\n if (!config.shouldTrigger || config.shouldTrigger(prevValue, value)) {\n // Создаем действие\n const action: TypedAction<R> = {\n type: actionType,\n payload: value,\n meta: config.meta,\n }\n\n // Отправляем в основной поток действий\n this.actions$.next(action)\n\n // Отправляем в поток этого watcher'а\n subject.next(action)\n\n // Обновляем предыдущее значение\n prevValue = value\n }\n })\n\n // Создаем функцию watcher'а\n const watcherFn = () => subject.asObservable()\n watcherFn._type = 'watchers'\n // Добавляем свойства\n Object.defineProperty(watcherFn, 'actionType', {\n value: actionType,\n writable: false,\n enumerable: true,\n })\n\n if (config.meta) {\n Object.defineProperty(watcherFn, 'meta', {\n value: config.meta,\n writable: false,\n enumerable: true,\n })\n }\n\n // Добавляем метод для отписки\n Object.defineProperty(watcherFn, 'unsubscribe', {\n value: unsubscribe,\n writable: false,\n enumerable: true,\n })\n\n //@ts-ignore\n return watcherFn as WatcherFunction<R>\n }\n\n /**\n * Выполняет действие в worker\n */\n private async executeInWorker<TParams, TResult>(\n worker: Worker,\n actionType: string,\n args: TParams[],\n fallbackAction?: (params: TParams) => Promise<TResult> | TResult,\n ): Promise<TResult> {\n // Логика остается без изменений\n return new Promise((resolve, reject) => {\n const requestId = `${actionType}_${Date.now()}_${Math.random()}`\n\n const handleMessage = (event: MessageEvent) => {\n if (event.data.requestId === requestId) {\n worker.removeEventListener('message', handleMessage)\n\n if (event.data.error) {\n reject(new Error(event.data.error))\n } else {\n resolve(event.data.result)\n }\n }\n }\n\n worker.addEventListener('message', handleMessage)\n\n worker.postMessage({\n type: actionType,\n args,\n requestId,\n })\n\n // Опционально: таймаут\n setTimeout(() => {\n worker.removeEventListener('message', handleMessage)\n reject(new Error(`Worker execution timeout for action: ${actionType}`))\n }, 30000) // 30 секунд таймаут\n })\n }\n}\n\n/**\n * Функция для создания типизированного диспетчера\n */\nexport function createDispatcher<TState extends Record<string, any>, TActions extends ActionsSetupWithUtils<TState>>(\n options: DispatcherOptions<TState>,\n actionsSetup: TActions,\n): Dispatcher<TState, TActions> & {\n dispatch: DispatchActions<ReturnType<TActions>>\n watchers: WatcherActions<ReturnType<TActions>>\n} {\n // Создаем экземпляр диспетчера\n const dispatcher = new Dispatcher<TState, TActions>(options)\n\n // Вызываем функцию настройки действий с обновленной структурой аргументов\n const actions = actionsSetup(options.storage, {\n createAction: (actionConfig, executionOptions) => dispatcher.createAction(actionConfig, executionOptions),\n createWatcher: (config) => dispatcher.createWatcher(config),\n })\n\n // Регистрируем все созданные объекты в соответствующих коллекциях\n for (const [key, fn] of Object.entries(actions)) {\n if (typeof fn === 'function') {\n const type = (fn as any)._type\n // @ts-ignore\n dispatcher[type][key] = fn\n }\n }\n\n return dispatcher as Dispatcher<TState, TActions> & {\n dispatch: DispatchActions<ReturnType<TActions>>\n watchers: WatcherActions<ReturnType<TActions>>\n }\n}\nexport type CreateDispatcherType = ReturnType<typeof createDispatcher>\n","import { combineLatest, merge, Observable, of, OperatorFunction, pipe, Subject } from 'rxjs'\nimport { catchError, filter, map, share, switchMap, take, withLatestFrom } from 'rxjs/operators'\n\nimport { IStorage } from '../../core'\nimport { Action, ActionsResult, Dispatcher, DispatchFunction, ExtractResultType, WatcherFunction } from '../dispatcher'\nimport { ChunkRequestConsistent, chunkRequestConsistent, ChunkRequestParallel, chunkRequestParallel } from './utils'\n\n/**\n * Тип действия с типизированным payload\n */\nexport interface TypedAction<P> extends Action<P> {\n type: string\n payload: P\n}\n\n/**\n * Тип для внешних состояний\n */\nexport type ExternalStates = Record<string, Observable<any>>\n\n/**\n * Тип для базового эффекта без доступа к состоянию\n */\nexport type EffectBase<TDispatchers extends Record<string, Dispatcher<any, any>> = Record<string, never>, TServices extends Record<string, any> = Record<string, never>> = (\n action$: Observable<Action>,\n dispatchers: TDispatchers,\n services: TServices,\n) => Observable<unknown>\n\n/**\n * Тип для эффекта с доступом к состоянию и конфигурации - это основной тип, который используется по умолчанию\n */\nexport type Effect<\n TState extends Record<string, any> = any,\n TDispatchers extends Record<string, Dispatcher<any, any>> = Record<string, never>,\n TServices extends Record<string, any> = Record<string, never>,\n TConfig extends Record<string, any> = Record<string, never>,\n TExternalStates extends ExternalStates = Record<string, never>,\n> = (\n action$: Observable<Action>,\n state$: Observable<TState>,\n externalStates: TExternalStates,\n dispatchers: TDispatchers,\n services: TServices,\n config: TConfig,\n) => Observable<unknown>\n\n/**\n * Тип для получения типов действий диспетчера\n */\nexport type DispatcherActions<T> = T extends Dispatcher<any, infer A> ? ActionsResult<A> : Record<string, DispatchFunction<any, any>>\n\n/**\n * Конфигурация для валидации в validateMap\n */\nexport interface ValidateConfig {\n conditions: boolean[]\n skipAction: (() => any) | any | ((() => any) | any)[]\n}\n\n/**\n * Утилиты для запросов в validateMap\n */\nexport interface ValidateMapRequestUtils {\n chunkRequest: ChunkRequestParallel\n chunkRequestConsistent: ChunkRequestConsistent\n}\n\n/**\n * Оператор для фильтрации действий по типу с сохранением типа payload\n */\nexport function ofType<T extends DispatchFunction<any, any> | WatcherFunction<any>>(\n actionFn: T,\n): OperatorFunction<Action, TypedAction<T extends WatcherFunction<infer R> ? R : ExtractResultType<T>>> {\n const { actionType } = actionFn\n\n if (!actionType) {\n console.warn('ofType: Action function does not have actionType property', actionFn)\n return filter(() => false) as any\n }\n\n // Определяем тип payload в зависимости от типа функции\n type PayloadType = T extends WatcherFunction<infer R> ? R : ExtractResultType<T>\n\n // Улучшенная реализация с явными типами\n return (source$: Observable<Action>): Observable<TypedAction<PayloadType>> => {\n return source$.pipe(filter((action): action is TypedAction<PayloadType> => action !== undefined && action.type === actionType))\n }\n}\n\n/**\n * Оператор для фильтрации действий по нескольким типам с объединением типов payload\n * @param actionFns Массив функций действий\n */\nexport function ofTypes<T extends DispatchFunction<any, any>[]>(actionFns: [...T]): OperatorFunction<Action, TypedAction<ExtractResultType<T[number]>>> {\n // Получаем типы действий\n const actionTypes = actionFns.map((fn) => fn.actionType).filter(Boolean)\n\n if (actionTypes.length === 0) {\n console.warn('ofTypes: No valid action types found in array', actionFns)\n return filter(() => false) as OperatorFunction<Action, TypedAction<ExtractResultType<T[number]>>>\n }\n\n // Union тип для payload из всех действий\n type CombinedPayloadType = ExtractResultType<T[number]>\n\n // Улучшенная реализация с явными типами\n return (source$: Observable<Action>): Observable<TypedAction<CombinedPayloadType>> => {\n return source$.pipe(filter((action): action is TypedAction<CombinedPayloadType> => action !== undefined && actionTypes.includes(action.type)))\n }\n}\n\n/**\n * Оператор для ожидания выполнения всех указанных действий\n * @param actionFns Массив функций действий\n */\nexport function ofTypesWaitAll<T extends DispatchFunction<any, any>[]>(actionFns: [...T]) {\n return (source$: Observable<Action>): Observable<{ [K in keyof T]: TypedAction<ExtractResultType<T[K]>> }> => {\n // Создаем потоки для каждого типа действия\n const actionTypes = actionFns.map((fn) => fn.actionType).filter(Boolean)\n\n if (actionTypes.length === 0) {\n console.warn('ofTypesWaitAll: No valid action types found in array', actionFns)\n return of([]) as any\n }\n\n // Для каждого типа действия создаем поток,\n // который берет первое срабатывание\n const actionStreams = actionTypes.map((type, index) =>\n source$.pipe(\n filter((action) => action.type === type),\n take(1),\n map((action) =>\n // Сохраняем ассоциацию с индексом, чтобы соответствовать\n // порядку в исходном массиве actionFns\n ({ index, action }),\n ),\n ),\n )\n\n // Ждем, пока все потоки выдадут значения, и сортируем результаты\n // по индексу для сохранения порядка\n return combineLatest(actionStreams).pipe(\n map((results) => {\n // Сортируем по индексу\n results.sort((a, b) => a.index - b.index)\n // Убираем индекс и возвращаем только действия\n return results.map((r) => r.action) as any\n }),\n )\n }\n}\n\n/**\n * Создает Observable с выбранными данными из состояния\n * @param state$ Поток состояния\n * @param selectors Селекторы для выбора частей состояния\n * @returns Observable с массивом выбранных значений\n */\nexport function selectorMap<TState, TResults extends any[]>(\n state$: Observable<TState>,\n ...selectors: { [K in keyof TResults]: (state: TState) => TResults[K] }\n): Observable<TResults> {\n return state$.pipe(\n map((state) => {\n return selectors.map((selector) => selector(state)) as TResults\n }),\n )\n}\n\n/**\n * Создает именованный объект вместо массива\n * @param state$ Поток состояния\n * @param selectors Объект с селекторами\n * @returns Observable с объектом выбранных значений\n */\nexport function selectorObject<TState, TResult extends Record<string, any>>(\n state$: Observable<TState>,\n selectors: { [K in keyof TResult]: (state: TState) => TResult[K] },\n): Observable<TResult> {\n return state$.pipe(\n map((state) => {\n const result = {} as TResult\n for (const [key, selector] of Object.entries(selectors)) {\n result[key as keyof TResult] = selector(state)\n }\n return result\n }),\n )\n}\n\n/**\n * Оператор validateMap для валидации данных и условного вызова API\n */\nexport function validateMap<T, TResult = any>({\n validator,\n apiCall,\n}: {\n validator?: (value: T) => ValidateConfig\n apiCall: (value: T, utils: ValidateMapRequestUtils) => Observable<TResult>\n}): OperatorFunction<T, any> {\n return pipe(\n switchMap((pipeData) => {\n /**\n * Функция вызова API-метода\n */\n const callApi = () =>\n apiCall(pipeData, {\n chunkRequest: chunkRequestParallel,\n chunkRequestConsistent: chunkRequestConsistent,\n })\n\n /**\n * Если валидацию не используем - сразу вызываем запрос\n */\n if (!validator) return callApi()\n\n const validateConfig = validator(pipeData)\n const { conditions, skipAction } = validateConfig\n const conditionMet = conditions.every(Boolean)\n\n /**\n * Если валидация не пройдена - вызываем экшн сброса\n */\n if (!conditionMet) {\n if (Array.isArray(skipAction)) {\n // eslint-disable-next-line no-unsafe-optional-chaining\n return of(...skipAction?.filter(Boolean).map((action) => (typeof action === 'function' ? action() : action)))\n }\n return of(typeof skipAction === 'function' ? skipAction() : skipAction)\n }\n\n return callApi()\n }),\n )\n}\n\n/**\n * Класс для управления эффектами с поддержкой доступа к состоянию и конфигурации\n * Основной класс, который следует использовать\n */\nexport class EffectsModule<\n TState extends Record<string, any> = any,\n TDispatchers extends Record<string, Dispatcher<any, any>> = Record<string, never>,\n TServices extends Record<string, any> = Record<string, never>,\n TConfig extends Record<string, any> = Record<string, never>,\n TExternalStates extends ExternalStates = Record<string, never>,\n> {\n private effects: Effect<TState, TDispatchers, TServices, TConfig, TExternalStates>[] = []\n private subscriptions: Array<{ unsubscribe: VoidFunction }> = []\n private running = false\n private action$ = new Subject<Action>()\n\n /**\n * Поток состояния\n */\n public readonly state$: Observable<TState>\n\n /**\n * Создает модуль эффектов с доступом к состоянию, внешним состояниям и конфигурации\n * @param storage Хранилище состояния\n * @param externalStates Внешние состояния\n * @param dispatchers Объект с диспетчерами\n * @param services Объект с сервисами\n * @param config Глобальная конфигурация для всех эффектов\n */\n constructor(\n private storage: IStorage<TState>,\n private externalStates: TExternalStates = {} as TExternalStates,\n private dispatchers: TDispatchers,\n private services: TServices = {} as TServices,\n private config: TConfig = {} as TConfig,\n ) {\n this.subscribeToDispatchers()\n\n // Создаем поток состояния\n this.state$ = new Observable<TState>((observer) => {\n // Отправляем начальное состояние\n this.storage.getState().then((state) => observer.next(state))\n\n // Подписываемся на все изменения\n const unsubscribe = this.storage.subscribeToAll(() => {\n this.storage.getState().then((state) => observer.next(state))\n })\n\n // Отписываемся при завершении\n return () => unsubscribe()\n }).pipe(share())\n }\n\n /**\n * Подписывается на действия от всех диспетчеров\n */\n private subscribeToDispatchers() {\n for (const [_, dispatcher] of Object.entries(this.dispatchers)) {\n const subscription = dispatcher.actions.subscribe((action) => {\n this.action$.next(action)\n })\n\n this.subscriptions.push(subscription)\n }\n }\n\n add(effect: Effect<TState, TDispatchers, TServices, TConfig, TExternalStates>): this {\n this.effects.push(effect)\n\n if (this.running) {\n this.subscribeToEffect(effect)\n }\n\n return this\n }\n\n /**\n * Добавляет несколько эффектов\n * @param effects Эффекты для добавления\n * @returns Текущий модуль\n */\n addEffects(effects: Effect<TState, TDispatchers, TServices, TConfig, TExternalStates>[]): this {\n effects.forEach((effect) => this.add(effect))\n return this\n }\n\n /**\n * Запускает все эффекты\n * @returns Текущий модуль\n */\n start(): this {\n if (this.running) {\n return this\n }\n\n this.effects.forEach((effect) => this.subscribeToEffect(effect))\n this.running = true\n\n return this\n }\n\n /**\n * Останавливает все эффекты\n * @returns Текущий модуль\n */\n stop(): this {\n this.subscriptions.forEach((sub) => sub.unsubscribe())\n this.subscriptions = []\n this.running = false\n\n return this\n }\n\n /**\n * Подписывается на конкретный эффект\n * @param effect Эффект для подписки\n */\n private subscribeToEffect(effect: Effect<TState, TDispatchers, TServices, TConfig, TExternalStates>): void {\n try {\n const output$ = effect(this.action$.asObservable(), this.state$, this.externalStates, this.dispatchers, this.services, this.config).pipe(\n catchError((err) => {\n console.error('Error in effect:', err)\n return of(null)\n }),\n )\n\n const subscription = output$.subscribe((result) => {\n if (result === null || result === undefined) {\n return\n }\n\n if (typeof result === 'function') {\n try {\n result()\n } catch (callError) {\n console.error('Error calling effect result function:', callError)\n }\n }\n })\n\n this.subscriptions.push(subscription)\n } catch (setupError) {\n console.error('Error setting up effect:', setupError)\n }\n }\n}\n\n/**\n * Вспомогательная функция для создания типизированного эффекта без состояния\n * @deprecated Используйте createEffect вместо этого\n */\nexport function createEffectBase<TDispatchers extends Record<string, Dispatcher<any, any>>, TServices extends Record<string, any>>(\n effect: EffectBase<TDispatchers, TServices>,\n): EffectBase<TDispatchers, TServices> {\n return effect\n}\n\n/**\n * Вспомогательная функция для создания типизированного эффекта с состоянием и конфигурацией\n */\nexport function createEffect<\n TState extends Record<string, any>,\n TDispatchers extends Record<string, Dispatcher<any, any>>,\n TServices extends Record<string, any>,\n TConfig extends Record<string, any> = Record<string, never>,\n TExternalStates extends ExternalStates = Record<string, never>,\n>(effect: Effect<TState, TDispatchers, TServices, TConfig, TExternalStates>): Effect<TState, TDispatchers, TServices, TConfig, TExternalStates> {\n return effect\n}\n\n/**\n * Объединяет несколько эффектов в один\n * @param effects Эффекты для объединения\n * @returns Объединенный эффект\n */\nexport function combineEffects<\n TState extends Record<string, any>,\n TDispatchers extends Record<string, Dispatcher<any, any>>,\n TServices extends Record<string, any>,\n TConfig extends Record<string, any> = Record<string, never>,\n TExternalStates extends ExternalStates = Record<string, never>,\n>(...effects: Effect<TState, TDispatchers, TServices, TConfig, TExternalStates>[]): Effect<TState, TDispatchers, TServices, TConfig, TExternalStates> {\n return (action$, state$, externalStates, dispatchers, services, config) => {\n const outputs = effects.map((effect) => {\n try {\n return effect(action$, state$, externalStates, dispatchers, services, config)\n } catch (error) {\n console.error('Error in one of combined effects:', error)\n return of(null)\n }\n })\n return merge(...outputs)\n }\n}\n","import { Observable, of } from 'rxjs'\nimport { concatAll, delay, mergeMap, toArray } from 'rxjs/operators'\n\nimport { chunk } from '../../../_utils'\n\n/**\n * Разбиение запроса на порции\n * Отправляется ПОСЛЕДОВАТЕЛЬНО n-запросов и дожидается ответа от каждого\n * @param fn - функция в которую передается chunk и возвращается функция api\n * @param arr - массив который нужно поделить\n * @param size - размер порции\n * @param delayMs - задержка между запросами в миллисекундах\n */\nexport const chunkRequestConsistent = <T, R>(fn: (chunk: T[]) => Observable<R>, arr: T[], size: number, delayMs = 0): Observable<R[]> => {\n const chunks = chunk(arr, size).map((chunkItem) => of(chunkItem).pipe(delay(delayMs), mergeMap(fn)))\n return of(...chunks).pipe(concatAll(), toArray())\n}\nexport type ChunkRequestConsistent = typeof chunkRequestConsistent\n","import { forkJoin, Observable, timer } from 'rxjs'\nimport { mergeMap } from 'rxjs/operators'\n\nimport { chunk } from '../../../_utils'\n\n/**\n * Разбиение запроса на порции\n * Отправляется ПАРАЛЛЕЛЬНО n-запросов и дожидается ответа от каждого\n * @param fn - функция в которую передается chunk и возвращается функция api\n * @param arr - массив который нужно поделить\n * @param size - размер порции\n * @param delayMs - задержка между запросами в миллисекундах\n */\nexport const chunkRequestParallel = <T, R>(fn: (chunk: T[]) => Observable<R>, arr: T[], size: number, delayMs = 0): Observable<R[]> =>\n forkJoin(chunk(arr, size).map((chunkItem, index) => timer(index * delayMs).pipe(mergeMap(() => fn(chunkItem)))))\nexport type ChunkRequestParallel = typeof chunkRequestParallel\n","import { Observable } from 'rxjs'\n\nimport { ISelectorModule, IStorage, SelectorModule } from '../core'\nimport { Effect, EffectsModule, ExternalStates } from '../reactive'\n\n// Вспомогательные типы для извлечения типов из других типов\nexport type ExtractPromiseType<T> = T extends Promise<infer U> ? U : T\nexport type ExtractStorageType<T> = T extends IStorage<infer U> ? U : never\nexport type ExtractDispatchType<T> = T extends { dispatch: infer D } ? D : never\n\nexport type StorageCreatorFunction<T extends Record<string, any>> = () => Promise<IStorage<T>>\n\n/**\n * Базовая конфигурация хранилища\n */\ntype BaseSynapseConfig<TStore extends Record<string, any>, TSelectors = any, TExternalSelectors extends Record<string, any> = Record<string, any>> = (\n | { storage: IStorage<TStore>; createStorageFn?: undefined }\n | { storage?: undefined; createStorageFn: StorageCreatorFunction<TStore> }\n) & {\n // Внешние селекторы\n externalSelectors?: TExternalSelectors\n // Функция создания селекторов\n createSelectorsFn?: (selectorModule: ISelectorModule<TStore>, externalSelectors: TExternalSelectors) => TSelectors\n}\n\n/**\n * Конфигурация с dispatcher и effects\n */\nexport type CreateSynapseConfigWithEffects<\n TStore extends Record<string, any>,\n TSelectors = any,\n TDispatcher = any,\n TApi extends Record<string, any> = Record<string, never>,\n TConfig extends Record<string, any> = Record<string, never>,\n TExternalSelectors extends Record<string, any> = Record<string, any>,\n> = BaseSynapseConfig<TStore, TSelectors, TExternalSelectors> & {\n // Функция создания диспетчера (обязательная)\n createDispatcherFn: (storage: IStorage<TStore>) => TDispatcher\n // Функция создания конфигурации для эффектов (обязательная)\n createEffectConfig: (dispatcher: TDispatcher) => {\n dispatchers: Record<string, any>\n api?: TApi\n config?: TConfig\n externalStates?: ExternalStates\n }\n // Эффекты\n effects?: Effect<TStore, any, TApi, TConfig, any>[]\n}\n\n/**\n * Конфигурация только с dispatcher\n */\nexport type CreateSynapseConfigWithDispatcher<\n TStore extends Record<string, any>,\n TSelectors = any,\n TDispatcher = any,\n TExternalSelectors extends Record<string, any> = Record<string, any>,\n> = BaseSynapseConfig<TStore, TSelectors, TExternalSelectors> & {\n // Функция создания диспетчера (обязательная)\n createDispatcherFn: (storage: IStorage<TStore>) => TDispatcher\n // Эффекты отсутствуют\n createEffectConfig?: never\n effects?: never\n}\n\n/**\n * Конфигурация без dispatcher\n */\nexport type CreateSynapseConfigBasic<\n TStore extends Record<string, any>,\n TSelectors = any,\n TExternalSelectors extends Record<string, any> = Record<string, any>,\n> = BaseSynapseConfig<TStore, TSelectors, TExternalSelectors> & {\n // Dispatcher отсутствует\n createDispatcherFn?: never\n createEffectConfig?: never\n effects?: never\n}\n\n/**\n * Результат с dispatcher и effects\n */\nexport interface SynapseStoreWithEffects<TStore extends Record<string, any>, TStorage extends IStorage<TStore>, TSelectors, TActions> {\n storage: TStorage\n selectors: TSelectors\n actions: TActions\n state$: Observable<TStore>\n dispatcher: any\n destroy: () => Promise<void>\n}\n\n/**\n * Результат только с dispatcher\n */\nexport interface SynapseStoreWithDispatcher<TStore extends Record<string, any>, TStorage extends IStorage<TStore>, TSelectors, TActions> {\n storage: TStorage\n selectors: TSelectors\n actions: TActions\n dispatcher: any\n destroy: () => Promise<void>\n}\n\n/**\n * Результат без dispatcher\n */\nexport interface SynapseStoreBasic<TStore extends Record<string, any>, TStorage extends IStorage<TStore>, TSelectors> {\n storage: TStorage\n selectors: TSelectors\n destroy: () => Promise<void>\n}\n\n/**\n * Union-тип для всех возможных результатов createSynapse\n */\nexport type AnySynapseStore<TStore extends Record<string, any> = any, TStorage extends IStorage<TStore> = IStorage<any>, TSelectors = any, TActions = any> =\n | SynapseStoreWithEffects<TStore, TStorage, TSelectors, TActions>\n | SynapseStoreWithDispatcher<TStore, TStorage, TSelectors, TActions>\n | SynapseStoreBasic<TStore, TStorage, TSelectors>\n\n/**\n * Перегрузки функции createSynapse\n */\n\n// Случай 1: С dispatcher и effects\nexport function createSynapse<\n TStore extends Record<string, any>,\n TSelectors = any,\n TDispatcher = any,\n TApi extends Record<string, any> = Record<string, never>,\n TConfig extends Record<string, any> = Record<string, never>,\n TExternalSelectors extends Record<string, any> = Record<string, any>,\n TStorage extends IStorage<TStore> = IStorage<TStore>,\n>(\n config: CreateSynapseConfigWithEffects<TStore, TSelectors, TDispatcher, TApi, TConfig, TExternalSelectors>,\n): Promise<SynapseStoreWithEffects<TStore, TStorage, TSelectors, ExtractDispatchType<TDispatcher>>>\n\n// Случай 2: Только с dispatcher\nexport function createSynapse<\n TStore extends Record<string, any>,\n TSelectors = any,\n TDispatcher = any,\n TExternalSelectors extends Record<string, any> = Record<string, any>,\n TStorage extends IStorage<TStore> = IStorage<TStore>,\n>(\n config: CreateSynapseConfigWithDispatcher<TStore, TSelectors, TDispatcher, TExternalSelectors>,\n): Promise<SynapseStoreWithDispatcher<TStore, TStorage, TSelectors, ExtractDispatchType<TDispatcher>>>\n\n// Случай 3: Без dispatcher\nexport function createSynapse<\n TStore extends Record<string, any>,\n TSelectors = any,\n TExternalSelectors extends Record<string, any> = Record<string, any>,\n TStorage extends IStorage<TStore> = IStorage<TStore>,\n>(config: CreateSynapseConfigBasic<TStore, TSelectors, TExternalSelectors>): Promise<SynapseStoreBasic<TStore, TStorage, TSelectors>>\n\n// Основная реализация\nexport async function createSynapse<\n TStore extends Record<string, any>,\n TSelectors = any,\n TDispatcher = any,\n TApi extends Record<string, any> = Record<string, never>,\n TConfig extends Record<string, any> = Record<string, never>,\n TExternalSelectors extends Record<string, any> = Record<string, any>,\n TStorage extends IStorage<TStore> = IStorage<TStore>,\n>(config: any): Promise<any> {\n // Создаем и инициализируем хранилище\n const storageInstance = (config.createStorageFn ? await config.createStorageFn() : config.storage!) as TStorage\n\n // Создаем сборщики для последующей очистки\n const cleanupCallbacks: Array<() => Promise<void> | void> = []\n\n const result: any = {\n storage: storageInstance,\n selectors: {} as TSelectors,\n destroy: async () => {\n for (const callback of cleanupCallbacks) {\n await callback()\n }\n },\n }\n\n cleanupCallbacks.push(() => storageInstance.destroy())\n\n let dispatcher: TDispatcher | undefined\n let selectorModule: ISelectorModule<TStore>\n let effectsModule: any\n\n // Создаем модуль селекторов\n if (config.createSelectorsFn) {\n try {\n selectorModule = new SelectorModule(storageInstance)\n\n const externalSelectors = config.externalSelectors || ({} as TExternalSelectors)\n\n result.selectors = config.createSelectorsFn(selectorModule, externalSelectors)\n\n if (typeof (selectorModule as any).destroy === 'function') {\n cleanupCallbacks.push(() => selectorModule.destroy())\n }\n } catch (error) {\n console.error('Ошибка создания selectors:', error)\n }\n }\n\n // Создаем диспетчер\n if (config.createDispatcherFn) {\n dispatcher = config.createDispatcherFn(storageInstance)\n result.dispatcher = dispatcher\n\n // @ts-ignore\n if (dispatcher && 'dispatch' in dispatcher) {\n result.actions = (dispatcher as any).dispatch\n\n if (typeof (dispatcher as any).destroy === 'function') {\n cleanupCallbacks.push(() => (dispatcher as any).destroy())\n }\n }\n }\n\n // Создаем и настраиваем модуль эффектов\n if (config.createEffectConfig && dispatcher) {\n try {\n const { dispatchers, api, config: effectConfig, externalStates } = config.createEffectConfig(dispatcher)\n\n // Получаем внешние состояния из конфигурации эффектов\n const effectExternalStates = externalStates || {}\n\n // Создаем модуль эффектов с внешними состояниями\n effectsModule = new EffectsModule(storageInstance, effectExternalStates, dispatchers, api, effectConfig)\n\n // Добавляем эффекты\n if (Array.isArray(config.effects)) {\n // @ts-ignore\n config.effects.forEach((effect) => {\n if (effectsModule) effectsModule.add(effect)\n })\n }\n\n // Запускаем модуль эффектов\n effectsModule.start()\n result.state$ = effectsModule.state$\n\n // Добавляем очистку эффектов\n cleanupCallbacks.push(() => {\n if (effectsModule) effectsModule.stop()\n })\n } catch (error) {\n console.error('Ошибка создания модуля эффектов:', error)\n }\n }\n\n return result\n}\n"],"mappings":"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","names":["Observable","of","Subject","mergeMap","Observable","Subject","of"]}