@pravosleva/reactive-engine 1.7.0-beta → 1.8.0-beta
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.
- package/dist/angular/ReactiveEngine4Angular.cjs +1 -1
- package/dist/angular/ReactiveEngine4Angular.cjs.map +1 -1
- package/dist/angular/ReactiveEngine4Angular.d.ts +16 -7
- package/dist/angular/ReactiveEngine4Angular.d.ts.map +1 -1
- package/dist/angular/ReactiveEngine4Angular.mjs +4 -4
- package/dist/angular/ReactiveEngine4Angular.mjs.map +1 -1
- package/dist/angular/core.angular.auto.test.d.ts +2 -0
- package/dist/angular/core.angular.auto.test.d.ts.map +1 -0
- package/dist/angular/core.angular.test.d.ts +2 -0
- package/dist/angular/core.angular.test.d.ts.map +1 -0
- package/dist/angular/index.cjs +1 -1
- package/dist/angular/index.d.ts +2 -2
- package/dist/angular/index.d.ts.map +1 -1
- package/dist/angular/index.mjs +1 -1
- package/dist/angular/rxjs-interop.d.ts +1 -1
- package/dist/angular/rxjs-interop.d.ts.map +1 -1
- package/dist/core/AbstractService.d.ts +3 -3
- package/dist/core/core.auto.test.d.ts +2 -0
- package/dist/core/core.auto.test.d.ts.map +1 -0
- package/dist/core/core.d.ts +105 -366
- package/dist/core/core.d.ts.map +1 -1
- package/dist/core/types.d.ts +102 -72
- package/dist/core/types.d.ts.map +1 -1
- package/dist/core.cjs +1 -1
- package/dist/core.cjs.map +1 -1
- package/dist/core.mjs +497 -414
- package/dist/core.mjs.map +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.mjs +11 -11
- package/dist/react/ReactiveEngine4React.cjs +1 -1
- package/dist/react/ReactiveEngine4React.cjs.map +1 -1
- package/dist/react/ReactiveEngine4React.d.ts +16 -8
- package/dist/react/ReactiveEngine4React.d.ts.map +1 -1
- package/dist/react/ReactiveEngine4React.mjs +5 -5
- package/dist/react/ReactiveEngine4React.mjs.map +1 -1
- package/dist/react/core.react.auto.test.d.ts +2 -0
- package/dist/react/core.react.auto.test.d.ts.map +1 -0
- package/dist/react/hooks/FilteredCatalog.auto.test.d.ts +2 -0
- package/dist/react/hooks/FilteredCatalog.auto.test.d.ts.map +1 -0
- package/dist/react/hooks/useReactiveSubscription/useReactiveSubscription.auto.test.d.ts +2 -0
- package/dist/react/hooks/useReactiveSubscription/useReactiveSubscription.auto.test.d.ts.map +1 -0
- package/dist/react/hooks/useReactiveValue/useReactiveValue.auto.test.d.ts +2 -0
- package/dist/react/hooks/useReactiveValue/useReactiveValue.auto.test.d.ts.map +1 -0
- package/dist/react/index.cjs +1 -1
- package/dist/react/index.d.ts +2 -2
- package/dist/react/index.d.ts.map +1 -1
- package/dist/react/index.mjs +1 -1
- package/dist/reactive-engine.umd.js +2 -2
- package/dist/reactive-engine.umd.js.map +1 -1
- package/dist/vue/ReactiveEngine4Vue.cjs +1 -1
- package/dist/vue/ReactiveEngine4Vue.cjs.map +1 -1
- package/dist/vue/ReactiveEngine4Vue.d.ts +21 -13
- package/dist/vue/ReactiveEngine4Vue.d.ts.map +1 -1
- package/dist/vue/ReactiveEngine4Vue.mjs +27 -17
- package/dist/vue/ReactiveEngine4Vue.mjs.map +1 -1
- package/dist/vue/composables/useReactiveValue.auto.test.d.ts +2 -0
- package/dist/vue/composables/useReactiveValue.auto.test.d.ts.map +1 -0
- package/dist/vue/core.vue.auto.test.d.ts +2 -0
- package/dist/vue/core.vue.auto.test.d.ts.map +1 -0
- package/dist/vue/core.vue.test.d.ts +2 -0
- package/dist/vue/core.vue.test.d.ts.map +1 -0
- package/dist/vue/index.cjs +1 -1
- package/dist/vue/index.d.ts +1 -1
- package/dist/vue/index.d.ts.map +1 -1
- package/dist/vue/index.mjs +1 -1
- package/package.json +1 -1
- package/dist/angular/ReactiveEngine4Angular.test.d.ts +0 -2
- package/dist/angular/ReactiveEngine4Angular.test.d.ts.map +0 -1
- package/dist/decorators/withThrottleComputed/_withThrottleComputed.d.ts +0 -22
- package/dist/decorators/withThrottleComputed/_withThrottleComputed.d.ts.map +0 -1
- package/dist/utils/getExtractedValues.cjs +0 -2
- package/dist/utils/getExtractedValues.cjs.map +0 -1
- package/dist/utils/getExtractedValues.mjs +0 -24
- package/dist/utils/getExtractedValues.mjs.map +0 -1
- package/dist/vue/ReactiveEngine4Vue.test.d.ts +0 -2
- package/dist/vue/ReactiveEngine4Vue.test.d.ts.map +0 -1
package/dist/core.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"core.mjs","names":[],"sources":["../src/core/core.ts"],"sourcesContent":["import { ResourceOptions, ResourceState, SignalOptions } from './types'\nimport { getExtractedValues } from '../utils'\n\n/**\n * Интерфейс для сигнала.\n * @template T\n * @interface Signal<T>\n */\nexport interface Signal<T> {\n /**\n * Значение сигнала.\n * @type {T}\n */\n value: T;\n\n /**\n * Подписка на изменение значения сигнала.\n * @function subscribe\n * @param {Function} cb - Коллбек функция для обработки изменения.\n * @returns {CleanupFn} - Функция для очистки подписки.\n */\n subscribe: (cb: (val: T) => void) => CleanupFn;\n}\n\nexport type CleanupFn = () => void;\nexport type EffectFn = () => CleanupFn | void;\nexport type Token<T> = string | symbol | { new(engine: ReactiveEngine, ...args: any[]): T };\nexport type Factory<T> = (engine: ReactiveEngine) => T;\n\n/**\n * Интерфейс для вычисляемого значения.\n * @template T\n * @interface Computed<T>\n */\nexport interface Computed<T> {\n /**\n * Только читаемое значение вычисляемого значения.\n * @type {T}\n */\n readonly value: T;\n\n /**\n * Подписка на изменение вычисляемого значения.\n * @function subscribe\n * @param {Function} cb - Коллбек функция для обработки изменения.\n * @returns {CleanupFn} - Функция для очистки подписки.\n */\n subscribe: (cb: (val: T) => void) => CleanupFn;\n\n /**\n * Принудительное уничтожение вычисляемого значения и его эффекта для предотвращения утечек памяти.\n */\n destroy: () => void;\n}\n\n/**\n * Интерфейс для эффекта.\n * @interface IEffect\n */\nexport interface IEffect {\n run: () => void;\n label?: string;\n cleanups: Set<CleanupFn>;\n}\n\n/**\n * Интерфейс для ресурса.\n * @template T\n * @interface Resource<T>\n */\nexport interface Resource<T> extends ResourceState<T> {\n /**\n * Перезагрузка ресурса.\n * @function refetch\n * @returns {void}\n */\n refetch: () => void;\n\n /**\n * Подписка на изменение состояния ресурса.\n * @function subscribe\n * @param {Function} cb - Коллбек функция для обработки изменения.\n * @returns {CleanupFn} - Функция для очистки подписки.\n */\n subscribe: (cb: (val: ResourceState<T>) => void) => CleanupFn;\n\n /**\n * Только читаемое состояние ресурса.\n * @type {ResourceState<T>}\n */\n readonly value: ResourceState<T>;\n}\n\nexport interface EngineLoggerOptions {\n /** Наименование инстанса движка */\n instanceName?: string;\n /** Включить детальное логгирование в консоль */\n isEnabled: boolean;\n /** Выводить время выполнения с точностью до микросекунд (performance.now) */\n traceTime?: boolean;\n /** Фильтровать логи по имени сигнала (поддерживает RegExp или строку) */\n filter?: RegExp | string;\n /** Показывать внутренние системные логи ядра (сигналы кэша, эффекты computed) */\n isCoreOptimizationDebugEnabled?: boolean;\n}\n\nexport interface ReactiveEngineOptions {\n logger?: EngineLoggerOptions;\n}\n// Конкретные и строгие структуры для деталей каждого типа лога\nexport interface SignalLogDetail {\n from: unknown;\n to: unknown;\n subscribersCount: number;\n subscribers: string[];\n}\n\nexport interface ComputedLogDetail {\n value: unknown;\n duration: string;\n}\n\nexport interface EffectLogDetail {\n triggeredBy: string;\n executionTime?: string;\n}\n\nexport interface BatchLogDetail {\n transactionSize: number;\n totalEffectsRun: number;\n}\nexport interface ResourceLogDetail {\n /** Текущий статус загрузки */\n loading: boolean;\n /** Данные ответа (если есть) */\n data: unknown;\n /** Объект ошибки (если запрос упал) */\n error: Error | null;\n /** Была ли это повторная попытка (Retry) */\n isRetrying?: boolean;\n}\nexport interface ReactiveDetail {}\n\n// Маппинг: связываем строковый литерал типа лога с его интерфейсом деталей\nexport interface LogDetailMap {\n signal: SignalLogDetail;\n computed: ComputedLogDetail;\n effect: EffectLogDetail;\n batch: BatchLogDetail;\n resource: ResourceLogDetail;\n reactive: ReactiveDetail;\n}\n\n\n// --- ЯДРО ---\n/**\n * Класс `ReactiveEngine` представляет собой реактивную систему, которая позволяет создавать и управлять реактивными объектами,\n * сигналами, эффектами, асинхронными ресурсами и другими реактивными примитивами. Реактивные механизмы облегчают разработку\n * сложных пользовательских интерфейсов и приложений, автоматически отслеживая зависимости между данными и реактивно обновляя UI.\n *\n * Основные возможности `ReactiveEngine` включают:\n * - **Сигналы (Signals)**: Реактивные переменные с поддержкой подписки на изменения.\n * - **Эффекты (Effects)**: Автоматические функции, которые выполняются при изменении зависимых сигналов.\n * - **Ресурсы (Resources)**: Асинхронные ресурсы с поддержкой повторных попыток и валидации.\n * - **Прокси-объекты (Proxy Objects)**: Реактивное обертывание объектов для отслеживания изменений свойств.\n * - **Интеграция с React**: Удобные методы для интеграции реактивного ядра с компонентами React.\n *\n * Пример использования:\n *\n * ```javascript\n * const engine = new ReactiveEngine();\n * const count = engine.signal(0);\n *\n * engine.effect(() => {\n * console.log(`Count is ${count.value}`);\n * });\n *\n * count.value++; // Выведет: Count is 1\n * ```\n *\n * @class\n */\nexport class ReactiveEngine {\n protected frameworkPrefix = 'core'\n private activeEffect: IEffect | null = null\n private isBatching = false\n private pendingEffects = new Set<IEffect>()\n\n // В контейнерах DI вместо any используем unknown. Это заставит методы inject/provide\n // явно приводить типы через дженерики <T>, защищая от рантайм-ошибок.\n private services = new Map<Token<unknown>, unknown>()\n private factories = new Map<Token<unknown>, Factory<unknown>>()\n\n // Объект-ключ мапится на объект-прокси. Здесь идеально подходит тип object.\n private proxyCache = new WeakMap<object, object>()\n private allEffects = new Set<IEffect>()\n\n // Logger\n private loggerOptions?: EngineLoggerOptions\n private pendingLogQueue: Array<{\n [K in keyof LogDetailMap]: {\n type: K;\n name: string;\n detail: LogDetailMap[K];\n }\n }[keyof LogDetailMap]> = []\n private lastTransactionDuration: number | null = null\n // Хранилища точечной аналитки:\n private signalMutationCounts = new Map<string, number>() // Имя сигнала -> Кол-во мутаций\n private lastComputedDurations = new Map<string, number>() // Имя computed -> Время прошлого расчета\n private effectExecutionCounts = new Map<string, number>() // Имя эффекта -> Кол-во запусков\n private batchTickCounts = 0 // Глобальный счетчик транзакций ядра\n\n constructor(options?: ReactiveEngineOptions) {\n this.loggerOptions = options?.logger\n }\n\n /**\n * Системный метод вывода форматированных логов в консоль.\n * Автоматически подстраивает тип входящего аргумента `detail` под выбранный литерал `type`.\n *\n * Дополнительно агрегирует рантйам-статистику по всей стейт-машине приложения:\n * - **`signal`:** Отслеживает счетчик частоты изменений (шума) для детекции паразитных циклов мутаций.\n * - **`computed`:** Сравнивает текущую длительность ленивого вычисления с прошлым, подсвечивая тренд производительности.\n * - **`effect`:** Подсчитывает общее количество ререндеров/вызовов побочных эффектов.\n * - **`batch`:** Фиксирует порядковый номер выполненного шедулером пакета микрозадач.\n *\n * @template K - Литеральный тип лога из карты `LogDetailMap`\n * @param {K} type - Категория логгируемого события ('signal' | 'computed' | 'effect' | 'batch')\n * @param {string} name - Уникальное имя реактивного элемента (или label эффекта)\n * @param {LogDetailMap[K]} detail - Строго типизированный объект с контекстными данными события\n * @returns {void}\n */\n public log<K extends keyof LogDetailMap>(\n type: K,\n name: string,\n detail: LogDetailMap[K]\n ): void {\n if (!this.loggerOptions?.isEnabled) return\n\n if (!this.loggerOptions?.isCoreOptimizationDebugEnabled) {\n // Детектим внутренний сигнал кэша\n const isInternalSignal = getExtractedValues({\n expectedKey: 'CORE_INTERNAL_SIGNAL', tested: [name], valueType: 'number'\n })?.[0] === '1'\n // Детектим внутренний эффект оптимизации компута по маркеру в имени\n const isInternalEffect = getExtractedValues({\n expectedKey: 'CORE_INTERNAL_EFFECT', tested: [name], valueType: 'number'\n })?.[0] === '1'\n // Если это сервисный лог, а отладка оптимизации выключена — тихо выходим!\n if (isInternalSignal || isInternalEffect) return\n }\n\n // Фильтрацию производим уже по очищенному имени\n if (this.loggerOptions.filter) {\n const regex = this.loggerOptions.filter instanceof RegExp\n ? this.loggerOptions.filter\n : new RegExp(this.loggerOptions.filter.replace(/^\\/|\\/$/g, ''))\n if (!regex.test(name)) return\n }\n\n const badgeColors: Record<keyof LogDetailMap, string> = {\n signal: 'background: #007acc; color: #fff; padding: 2px 6px; border-radius: 4px; font-weight: bold;',\n computed: 'background: #42b883; color: #fff; padding: 2px 6px; border-radius: 4px; font-weight: bold;',\n effect: 'background: #e01e5a; color: #fff; padding: 2px 6px; border-radius: 4px; font-weight: bold;',\n batch: 'background: #7952b3; color: #fff; padding: 2px 6px; border-radius: 4px; font-weight: bold;',\n resource: 'background: #d97706; color: #fff; padding: 2px 6px; border-radius: 4px; font-weight: bold;',\n reactive: 'background: #007acc; color: #fff; padding: 2px 6px; border-radius: 4px; font-weight: bold;',\n }\n\n let subBadgeText = ''\n let subBadgeStyle = 'color: #aaa; font-weight: normal;'\n\n switch (type) {\n case 'signal': {\n // Проверяем, является ли сигнал внутренним служебным сигналом ядра\n const isInternal = getExtractedValues({\n tested: [name],\n expectedKey: 'CORE_INTERNAL_SIGNAL',\n valueType: 'number'\n })?.[0] === '1'\n\n // (?) Чистим имя от метаданных для красивого вывода в консоль\n const displayName = name // name.replace(/\\[CORE_INTERNAL_SIGNAL=1\\]:/g, '');\n\n const currentCount = (this.signalMutationCounts.get(displayName) || 0) + 1\n this.signalMutationCounts.set(displayName, currentCount)\n\n const signalDetail = detail as SignalLogDetail\n const isFullyOptimized = signalDetail.subscribers && signalDetail.subscribers.length > 0\n ? signalDetail.subscribers.every((sub) => {\n if (!sub) return false\n return getExtractedValues({\n tested: [sub],\n expectedKey: 'IS_OPTIMIZED',\n valueType: 'number',\n })?.[0] === '1'\n })\n : false\n\n const isNoisy = currentCount > 50\n\n // Переключаем текст под-бэджа, если это внутренний сигнал computed\n const typeLabel = isInternal ? 'COMPUTED_INTERNAL' : 'SIGNAL'\n\n subBadgeText = ` 🔄 Изменений ${isInternal ? 'кэша' : 'сигнала'}: ${currentCount}${isNoisy ? ' ⚠️ (high noise — обнаружен дребезг/спам значений!)' : ''}`\n\n if (isNoisy) {\n subBadgeStyle = 'color: orange; font-weight: bold;'\n if (!isFullyOptimized) {\n (detail as any).__performance_advice__ = {\n issue: `Сигнал [${displayName}] обновляется слишком часто (${currentCount} раз за такт). Это приводит к избыточным ререндерам UI.`,\n solution: `Оберните чтение этого сигнала в декоратор сжатия потока данных 'withThrottleComputed'`,\n example: `public throttled = withThrottleComputed(this.engine, () => this.yourSignalName.value, { limit: 300 });`\n }\n }\n }\n\n // Переопределяем параметры вывода console.groupCollapsed локально\n console.groupCollapsed(\n `%c${typeLabel}%c [${displayName}]%c${subBadgeText}`,\n isInternal ? 'background: #42b883; color: #fff; padding: 2px 6px; border-radius: 4px; font-weight: bold;' : badgeColors[type],\n 'color: #aaa; font-weight: bold;',\n subBadgeStyle\n )\n console.log('Данные (Payload):', detail)\n if (this.loggerOptions.traceTime && typeof performance !== 'undefined') {\n console.log('Тайминг рантайма:', `${performance.now().toFixed(2)} ms`)\n }\n console.groupEnd()\n\n return // Прерываем дефолтный вывод, так как мы отрендерили сигнал со специальным бэджем!\n }\n case 'computed': {\n // Даже если это был сигнал, мы берем детали вычислений\n const currentDetail = detail as any\n\n // Безопасно извлекаем значение для заголовка бэджа.\n // Читаем .to только если это простой примитив (не объект), чтобы не триггерить геттеры ядра!\n if (currentDetail && 'to' in currentDetail) {\n const rawValue = currentDetail.to\n const displayValue = typeof rawValue === 'object' && rawValue !== null\n ? '{...}' // Для объектов выводим заглушку, защищая геттеры от JSON.stringify\n : String(rawValue)\n\n subBadgeText = ` 🧮 Значение: ${displayValue}`\n } else if (currentDetail && 'duration' in currentDetail) {\n // Ваша стандартная рабочая логика тренда для оригинального события computed\n const currentDuration = parseFloat(currentDetail.duration)\n if (!isNaN(currentDuration)) {\n const lastDuration = this.lastComputedDurations.get(name)\n if (lastDuration !== undefined && lastDuration > 0) {\n const diff = currentDuration - lastDuration\n const percentChange = (diff / lastDuration) * 100\n if (percentChange > 5) {\n subBadgeText = ` 🔴 Замедление: +${percentChange.toFixed(1)}% (${currentDetail.duration})`\n subBadgeStyle = 'color: #e01e5a; font-weight: bold;'\n } else if (percentChange < -5) {\n subBadgeText = ` 🟢 Ускорение: ${percentChange.toFixed(1)}% (${currentDetail.duration})`\n subBadgeStyle = 'color: #42b883; font-weight: bold;'\n } else {\n subBadgeText = ` 🟢 Стабильно (${currentDetail.duration})`\n subBadgeStyle = 'color: #42b883; font-weight: bold;'\n }\n } else {\n subBadgeText = ` ⚪ Первый расчет (${currentDetail.duration})`\n }\n this.lastComputedDurations.set(name, currentDuration)\n }\n }\n break\n }\n case 'effect': {\n const currentCount = (this.effectExecutionCounts.get(name) || 0) + 1\n this.effectExecutionCounts.set(name, currentCount)\n\n const isOverTriggered = currentCount > 30\n const currentDetail = detail as any\n const durationStr = currentDetail && 'duration' in currentDetail ? ` (${currentDetail.duration})` : ''\n\n // Выводим статус стабильности и длительность в заголовок бэджа по аналогии с computed\n subBadgeText = ` 🟢 Стабильно${durationStr} | 🚀 Вызовов: ${currentCount}${isOverTriggered ? ' ⚠️ (heavy re-renders)' : ''}`\n subBadgeStyle = 'color: #42b883; font-weight: bold;'\n\n if (isOverTriggered) subBadgeStyle = 'color: #ff4a4a; font-weight: bold;'\n break\n }\n case 'batch': {\n this.batchTickCounts += 1\n subBadgeText = ` 📦 Номер транзакции: #${this.batchTickCounts}`\n break\n }\n case 'resource': {\n const resourceDetail = detail as ResourceLogDetail\n\n // Формируем динамический статус-маркер для заголовка\n if (resourceDetail.loading) {\n subBadgeText = ' ⏳ ЗАГРУЗКА (fetching...)'\n subBadgeStyle = 'color: #d97706; font-weight: bold;' // Оранжевый\n } else if (resourceDetail.error) {\n subBadgeText = ` 🔴 ОШИБКА: ${resourceDetail.error.message || 'Unknown Error'}`\n subBadgeStyle = 'color: #ff4a4a; font-weight: bold;' // Красный\n } else {\n // Данные успешно загружены\n const rawData = resourceDetail.data\n const displayData = typeof rawData === 'object' && rawData !== null\n ? '{...}'\n : String(rawData)\n\n subBadgeText = ` 🟢 УСПЕХ (data: ${displayData})`\n subBadgeStyle = 'color: #42b883; font-weight: bold;' // Зеленый\n }\n break\n }\n default:\n break\n }\n\n // Выводим красивый свернутый заголовок под-элемента с аналитикой\n console.groupCollapsed(\n `%c${type.toUpperCase()}%c [${name}]%c${subBadgeText}`,\n badgeColors[type],\n 'color: #aaa; font-weight: bold;',\n subBadgeStyle\n )\n console.log('Данные (Payload):', detail)\n if (this.loggerOptions.traceTime && typeof performance !== 'undefined') {\n console.log('Тайминг рантайма:', `${performance.now().toFixed(2)} ms`)\n }\n console.groupEnd()\n }\n\n /**\n * Коллбек для уведомления об изменении сигнала.\n * Использование unknown вместо any гарантирует безопасную работу с типами prev/next.\n */\n public onSignalChange?: (name: string, next: unknown, prev: unknown) => void\n\n /**\n * DI: Регистрация зависимости.\n * @template T\n * @function provide\n * @param {Token<T>} token - Токен для зависимости.\n * @param {T | Factory<T>} valueOrFactory - Значение или фабрика для создания сервиса.\n * @returns {void}\n * @source\n */\n public provide<T>(token: Token<T>, valueOrFactory: T | Factory<T>): void {\n if (typeof valueOrFactory === 'function' && !valueOrFactory.prototype)\n this.factories.set(token, valueOrFactory as Factory<T>)\n else\n this.services.set(token, valueOrFactory)\n }\n\n /**\n * DI: Инъекция; Получение сервиса по токену.\n * @template T\n * @function inject\n * @param {Token<T>} token - Токен для зависимости.\n * @returns {T} - Сервис.\n * @source\n */\n public inject<T>(token: Token<T>): T {\n if (!token) {\n throw new Error(`[DI Error]: Вы пытаетесь внедрить пустой токен (undefined/null). Проверьте импорты.`)\n }\n\n // Приводим токен к базовому типу Token<unknown> для совместимости с Map\n const targetToken = token as Token<unknown>\n\n if (this.services.has(targetToken)) {\n return this.services.get(targetToken) as T\n }\n\n try {\n const factory = this.factories.get(targetToken)\n if (factory) {\n const instance = factory(this) as T\n this.services.set(targetToken, instance)\n return instance\n }\n if (typeof token === 'function' && token.prototype) {\n const instance = new (token as { new(eng: ReactiveEngine): T })(this)\n this.services.set(targetToken, instance)\n return instance\n }\n throw new Error(`Service not found: ${String(token)}`)\n } catch (e) {\n throw new Error(`[DI Error]: Не удалось создать сервис ${String(token)}. Ошибка: ${(e as Error)?.message || 'No e?.message'}`)\n }\n }\n\n /**\n * Накапливает логи об изменениях в буфер текущей микрозадачи\n */\n public queueLog(type: keyof LogDetailMap, name: string, detail: any): void {\n if (!this.loggerOptions?.isEnabled) return\n this.pendingLogQueue.push({ type, name, detail })\n }\n\n /**\n * Синхронно обрабатывает и выводит в консоль накопленный буфер логов\n * для текущего тика микрозадачи (реактивной транзакции).\n *\n * Метод автоматически вызывается планировщиком ядра (`queueMicrotask`) непосредственно\n * перед запуском каскада отложенных эффектов фреймворков и ререндеров интерфейса.\n *\n * ### Особенности рантайм-логики:\n * 1. **Атомарный батчинг:** Предотвращает лавинообразный спам в консоли разработчика при\n * множественных синхронных мутациях сигналов. Все тики склеиваются в единую мастер-группу.\n * 2. **Безопасная фильтрация:** Изолирует логи по маске, переданной в `loggerOptions.filter`.\n * Если после фильтрации очередь оказывается пустой, метод бережно зачищает буфер и\n * возвращает управление шедулеру ядра, не блокируя выполнение `pendingEffects`.\n * 3. **Профайлинг производительности (Pull Duration):** При включенном `traceTime` рассчитывает\n * чистую длительность калькуляции и фильтрации транзакции графа в миллисекундах\n * с точностью до микросекунд (`performance.now`), помогая находить узкие места.\n *\n * @function flushLogs\n * @returns {void} Метод не возвращает значения, а только очищает внутренний буфер `pendingLogQueue`.\n */\n public flushLogs(): void {\n if (!this.loggerOptions?.isEnabled || this.pendingLogQueue.length === 0) return\n\n const startTime = typeof performance !== 'undefined' ? performance.now() : 0\n let logsToRender = this.pendingLogQueue\n\n if (this.loggerOptions.filter) {\n try {\n let regex: RegExp\n if (this.loggerOptions.filter instanceof RegExp) {\n regex = this.loggerOptions.filter\n } else {\n const cleanStr = this.loggerOptions.filter.replace(/^\\/|\\/$/g, '')\n regex = new RegExp(cleanStr)\n }\n logsToRender = logsToRender.filter(item => regex.test(item.name))\n } catch (e) {\n console.warn('[Logger Error]: Некорректный паттерн фильтрации логов', e)\n }\n }\n\n if (logsToRender.length === 0) {\n this.pendingLogQueue = []\n return\n }\n\n // ШАГ 1: Переносим замер времени ВВЕРХ, чтобы знать длительность ДО рендеринга заголовка\n let durationText = ''\n let trendText = ''\n let trendStyle = 'color: #aaa; font-weight: normal;' // Дефолтный серый стиль для тренда в заголовке\n\n if (this.loggerOptions.traceTime && startTime) {\n const endTime = performance.now()\n const duration = endTime - startTime\n\n durationText = ` | Duration: ${duration.toFixed(3)} ms`\n\n // Расчет дельты тренда\n if (this.lastTransactionDuration !== null && this.lastTransactionDuration > 0) {\n const diff = duration - this.lastTransactionDuration\n const percentChange = (diff / this.lastTransactionDuration) * 100\n\n if (percentChange > 0.1) {\n // Просадка производительности (время выросло) -> КРАСНЫЙ\n trendText = ` 🔴 +${percentChange.toFixed(1)}%`\n trendStyle = 'color: #e01e5a; font-weight: bold;'\n } else if (percentChange < -0.1) {\n // Ускорение графа (время уменьшилось) -> ЗЕЛЕНЫЙ\n trendText = ` 🟢 ${percentChange.toFixed(1)}%`\n trendStyle = 'color: #42b883; font-weight: bold;'\n } else {\n // Изменения в пределах погрешности -> СТАБИЛЬНО (ЗЕЛЕНЫЙ)\n trendText = ' 🟢 stable'\n trendStyle = 'color: #42b883; font-weight: bold;'\n }\n } else {\n trendText = ' ⚪ first'\n }\n\n // Сохраняем значение для следующего тика микрозадачи\n this.lastTransactionDuration = duration\n }\n\n // ШАГ 2: ВЫВОДИМ ВСЁ В ОДИН ЗАГОЛOВОК ГРУППЫ\n // %c №1 - Стильный фиолетовый бэдж TRANSACTION\n // %c №2 - Серый текст с размером батча и чистым временем выполнения (ms)\n // %c №3 - Динамический цветной индикатор тренда (Красный/Зеленый) с процентами\n console.groupCollapsed(\n `%cREACTIVE TRANSACTION${!!this.loggerOptions.instanceName ? ` ${this.loggerOptions.instanceName}` : ''}%c Microtask Tick (Size: ${logsToRender.length}${durationText})%c${trendText}`,\n 'background: #7952b3; color: #fff; padding: 2px 6px; border-radius: 4px; font-weight: bold;',\n 'color: #aaa; font-weight: normal;',\n trendStyle\n )\n\n // Рендерим вложенные детальные логи сигналов и computed\n logsToRender.forEach(item => {\n this.log(item.type as any, item.name, item.detail as any)\n })\n\n if (this.loggerOptions.traceTime && typeof performance !== 'undefined') {\n console.log(`%c[Execution Timestamp]: ${performance.now().toFixed(2)} ms`, 'color: #7952b3; font-weight: bold;')\n }\n\n console.groupEnd()\n this.pendingLogQueue = []\n }\n\n /**\n * Создание сигнала.\n * @template T\n * @function signal\n * @param {T} initialValue - Начальное значение сигнала.\n * @param {string | SignalOptions<T>} [optionsOrName] - Имя или опции сигнала.\n * @returns {Signal<T>} - Сигнал.\n * @source\n */\n public signal<T>(initialValue: T, optionsOrName?: string | SignalOptions<T>): Signal<T> {\n const engine = this\n let val = initialValue\n const subscribers = new Set<IEffect>()\n const options = typeof optionsOrName === 'string'\n ? { name: optionsOrName }\n : optionsOrName || {}\n const name = options.name || 'unnamed_signal'\n\n return {\n get value(): T {\n if (engine.activeEffect) {\n const currentEffect = engine.activeEffect\n\n // Защита от раздувания памяти!\n // Добавляем функцию очистки в cleanups СТРОГО один раз — при первой регистрации эффекта.\n if (!subscribers.has(currentEffect)) {\n subscribers.add(currentEffect)\n\n currentEffect.cleanups.add(() => {\n subscribers.delete(currentEffect) // При уничтожении эффекта сигнал забудет его\n })\n }\n }\n\n return val\n },\n set value(newValue: T) {\n // ШАГ 1: Проверяем валидатор. Валидация считается успешной ТОЛЬКО если\n // метод вернул строго true. Если вернулась строка ошибки или false — блокируем запись.\n if (options?.validate && options.validate(newValue) !== true) {\n // Вытаскиваем строку ошибки, если валидатор её вернул\n const validationResult = options.validate(newValue)\n const errorReason = typeof validationResult === 'string' ? validationResult : 'Unknown reason'\n\n console.error(`[ReactiveEngine] Validation failed for signal \"${name}\": ${errorReason}`, { value: newValue })\n return // Мгновенный выход, val остается равен 10!\n }\n\n // ШАГ 2: Патч для мутабельности объектов/массивов\n const isPrimitive = newValue === null || (typeof newValue !== 'object' && typeof newValue !== 'function')\n if (isPrimitive && val === newValue) return\n\n // ШАГ 3: Запись значения\n const old = val\n val = newValue\n engine.onSignalChange?.(name, newValue, old)\n\n // ШАГ 4: Оповещение подписчиков без само-циклирования\n subscribers.forEach(e => {\n if (e === engine.activeEffect) return\n\n if (engine.isBatching) {\n engine.pendingEffects.add(e)\n } else {\n engine.pendingEffects.add(e)\n\n if (!engine.isBatching) {\n engine.isBatching = true\n queueMicrotask(() => {\n for (const effectObj of engine.pendingEffects) {\n engine.pendingEffects.delete(effectObj)\n effectObj.run()\n }\n engine.isBatching = false\n engine.flushLogs?.()\n })\n }\n }\n })\n },\n subscribe(cb: (val: T) => void) {\n // Чистая и безопасная подписка для React/Vue/Angular адаптеров\n return engine.effect(\n () => {\n cb(this.value)\n },\n `${engine.frameworkPrefix}:use:${name}`\n )\n }\n }\n }\n\n /**\n * Создание эффекта.\n * @function effect\n * @param {EffectFn} fn - Функция эффекта.\n * @param {string} [label] - Необязательная метка для логирования и отладки.\n * @returns {CleanupFn} - Функция для очистки эффекта.\n * @source\n */\n public effect(fn: EffectFn, label?: string): CleanupFn {\n const engine = this\n // Теперь он жестко изолирован в памяти для данного инстанса эффекта,\n // никогда не потеряет контекст и гарантированно станет false после первого тика!\n // Эта переменная она полностью блокирует ложные «холостые» логи при инициализации (монтировании) эффекта\n let isFirstRun = true\n const effectObj: IEffect = {\n label, // Запоминаем имя эффекта для профайлера/логов\n cleanups: new Set(),\n run() {\n // 1. Создаем моментальный снимок (копию) функций очистки.\n // Итерация по копии гарантирует, что даже если внутри колбэков очистки\n // или последующего safeRun в Set прилетят новые элементы,\n // текущий цикл .forEach завершится строго по старой длине и НЕ зациклится!\n const cleanupsToRun = Array.from(this.cleanups)\n this.cleanups.clear()\n\n cleanupsToRun.forEach(c => c())\n\n const prev = engine.activeEffect\n engine.activeEffect = this\n\n const startTime = performance.now()\n engine.safeRun(this, () => {\n const cleanup = fn()\n if (typeof cleanup === 'function') this.cleanups.add(cleanup)\n })\n\n engine.activeEffect = prev\n\n // Logger integretion (Читаем флаг из замыкания):\n // Логируем только если это боевой перезапуск (isFirstRun === false)\n const duration = performance.now() - startTime\n if (!isFirstRun && engine.loggerOptions?.isEnabled) {\n const filter = engine.loggerOptions.filter\n\n if (!filter || (filter instanceof RegExp && !!this.label && filter.test(this.label))) {\n if (typeof engine.queueLog === 'function') {\n engine.queueLog('effect', this.label || 'unnamed-efect-0', {\n name: this.label || 'unnamed-efect-0', // Ключ для фильтрации во flushLogs\n type: 'effect', // Ключ для switch/case в методе log()\n detail: {\n status: 'stable',\n duration: `${duration.toFixed(3)}ms`,\n timestamp: startTime\n }\n })\n }\n }\n }\n // После первого прохода снимаем флаг\n isFirstRun = false\n }\n }\n this.allEffects.add(effectObj)\n effectObj.run()\n\n return () => {\n effectObj.cleanups.forEach(c => c())\n engine.pendingEffects.delete(effectObj)\n engine.allEffects.delete(effectObj) // Всегда чистим за собой\n }\n }\n\n // Кэш для вычисляемых свойств: Вместо Map<Function, any> используем строгий интерфейс с unknown дженериком\n private computedCache = new Map<Function, WeakRef<Computed<unknown>>>()\n\n // 1. Создаем реестр финализации под капотом движка.\n // В качестве токена очистки передаем функцию, которую нужно выполнить.\n private cleanupRegistry = new FinalizationRegistry<() => void>(\n (cleanupFn) => {\n cleanupFn() // Вызовется автоматически, когда сборщик мусора удалит computedInstance\n }\n )\n\n /**\n * Создание вычисляемого значения.\n * @template T\n * @function computed\n * @param {Function} fn - Функция для вычисления значения.\n * @param {string} [signalName] - Имя сигнала.\n * @returns {Computed<T>} - Вычисляемое значение с методом destroy.\n * @source\n */\n public computed<T>(fn: () => T, signalName?: string): Computed<T> {\n if (this.computedCache.has(fn)) {\n const cachedRef = this.computedCache.get(fn)\n const cachedInstance = cachedRef?.deref()\n if (cachedInstance) {\n return cachedInstance as Computed<T>\n }\n }\n\n const engine = this\n const name = signalName || 'unnamed_computed'\n\n // Маркируем внутренний сигнал ядра метаданными для утилиты getExtractedValues\n const sig = this.signal<T>(undefined as unknown as T, `[CORE_INTERNAL_SIGNAL=1]:${name}`)\n\n let isDirty = true\n let cachedValue: T\n\n // Core effect:\n // Переносим логику логгера и замер таймингов прямо сюда — в единственное место,\n // где реально выполняется функция fn() при изменении зависимостей!\n const unsubscribeEffect = this.effect(() => {\n // СЕКРЕТ PUSH-КАСКАДА:\n // Мы принудительно вычисляем fn() на каждый тик зависимостей.\n // Благодаря этому, когда меняется count -> step-A синхронно просыпается в микрозадаче,\n // меняет свой sig.value -> этот сигнал мгновенно будит step-B, который уже добавлен\n // в pendingEffects текущей транзакции!\n cachedValue = fn()\n isDirty = false\n\n const startTime = typeof performance !== 'undefined' ? performance.now() : 0\n const durationStr = startTime ? `0.010ms` : 'N/A' // Пассивный замер для логгера\n\n if (typeof engine.queueLog === 'function') {\n engine.queueLog('computed', name, {\n value: cachedValue,\n duration: durationStr\n })\n }\n\n // Пушим значение. Сеттер сигнала подхватит следующий шаг,\n // так как флаг isBatching удерживается шедулером!\n (sig as any).value = cachedValue\n }, `[CORE_INTERNAL_EFFECT=1]:${name}`)\n\n const effectObj = Array.from(this.allEffects)[this.allEffects.size - 1]\n\n const performCleanup = () => {\n unsubscribeEffect()\n if (effectObj) {\n engine.allEffects.delete(effectObj)\n }\n engine.computedCache.delete(fn)\n }\n\n const computedInstance: Computed<T> = {\n get value() {\n // Если кто-то читает .value вручную вне эффектов фреймворка,\n // и флаг грязен — производим ленивый Pull-расчет\n if (isDirty) {\n cachedValue = fn()\n isDirty = false;\n (sig as any).value = cachedValue\n }\n return sig.value\n },\n subscribe: (cb: (val: T) => void) => sig.subscribe(cb),\n destroy() {\n unsubscribeEffect()\n performCleanup()\n engine.computedCache.delete(fn)\n }\n }\n\n this.cleanupRegistry.register(computedInstance, performCleanup)\n this.computedCache.set(fn, new WeakRef(computedInstance as Computed<unknown>))\n\n return computedInstance\n }\n\n /**\n * Создает глубокий реактивный объект (Proxy) на основе переданного целевого объекта или массива.\n *\n * В отличие от атомарных сигналов (`signal`), требующих ручного обращения через `.value`,\n * метод `reactive` позволяет работать со сложными разветвленными структурами данных нативно,\n * используя стандартный синтаксис JavaScript для чтения и прямой мутации свойств.\n *\n * ### Архитектурные особенности рантайма:\n * 1. **Гранулярность подписок (Property-level Subscriptions):** Зависимости графа ядра трекаются\n * не для всего объекта целиком, а строго для конкретных ключей (`prop`). Если эффект или\n * компонент читает свойство `user.name`, он подписывается исключительно на этот ключ.\n * Изменение свойства `user.age` не вызовет его повторного выполнения.\n * 2. **Глубокое проксирование (Deep Reactivity):** При обращении к вложенным объектам или массивам,\n * метод динамически и лениво оборачивает их в Proxy-структуры, автоматически формируя\n * понятные строковые пути для подсистемы логирования (например, `user.meta.role`).\n * 3. **Иммунизация кэша (Proxy Mirroring Cache):** Все созданные Proxy зеркалируются во внутреннем\n * реестре `proxyCache`. Повторный вызов метода для одного и того же объекта вернет\n * уже существующий Proxy, предотвращая утечки памяти и дублирование подписок.\n *\n * ### Применение в оптимизации больших форм:\n * Идеально подходит для тяжелых интерфейсов (динамические таблицы, анкеты из сотен полей),\n * так как прямая мутация конкретного инпута изолирует поток изменений и избавляет от необходимости\n * иммутабельного копирования всего стейта формы через оператор расширения (`...spread`).\n *\n * @template T - Тип целевого объекта, расширяющий базовый интерфейс `object`.\n * @function reactive\n * @param {T} target - Исходный объект или массив JavaScript для проксирования.\n * @param {string} [name='reactive'] - Уникальное базовое имя объекта для трассировки и фильтрации в логгере.\n * @returns {T} Глубоко проксированный реактивный объект типа `T`.\n *\n * @example\n * ```typescript\n * // 1. Инициализация в сервисе бизнес-логики:\n * public form = this.engine.reactive({\n * user: { name: 'Иван', age: 25 }\n * }, 'profile-form');\n *\n * // 2. Прямая мутация в экшене (Proxy перехватит тик и запустит атомарный батчинг):\n * public updateAge() {\n * this.form.user.age += 1; // Автоматический лог: SIGNAL [profile-form.user.age]\n * }\n *\n * // 3. Мост подписки для UI-компонентов:\n * public uiBridge = this.engine.computed(() => ({\n * name: this.form.user.name,\n * age: this.form.user.age\n * }));\n * ```\n */\n public reactive<T extends object>(target: T, name: string = 'reactive'): T {\n if (this.proxyCache.has(target)) {\n return this.proxyCache.get(target) as T\n }\n const engine = this\n const propsSubscribers = new Map<string | symbol, Set<IEffect>>()\n\n const proxy = new Proxy(target, {\n get(obj, prop, receiver) {\n if (engine.activeEffect) {\n const currentEffect = engine.activeEffect\n if (!propsSubscribers.has(prop)) propsSubscribers.set(prop, new Set())\n\n const subscribers = propsSubscribers.get(prop)!\n if (!subscribers.has(currentEffect)) {\n subscribers.add(currentEffect)\n\n const cleanupFn = () => {\n subscribers.delete(currentEffect)\n }\n currentEffect.cleanups.add(cleanupFn)\n }\n }\n\n // ====================================================\n // ИСПРАВЛЕННЫЙ ПЕРХВАТ МЕТОДОВ МАССИВОВ (АВТОБАТЧИНГ)\n // ====================================================\n if (Array.isArray(obj) && typeof prop === 'string') {\n const mutatingMethods = ['push', 'pop', 'shift', 'unshift', 'splice', 'sort', 'reverse']\n\n if (mutatingMethods.includes(prop)) {\n const originalMethod = (obj as any)[prop]\n\n return function (...args: any[]) {\n // Перед мутацией принудительно замораживаем граф (включаем батчинг),\n // чтобы внутренние мутации индексов нативного JavaScript не вызывали e.run()\n const WAS_BATCHING = engine.isBatching\n engine.isBatching = true\n\n const result = originalMethod.apply(obj, args)\n\n // Аккумулируем ВСЕХ подписчиков текущего массива в очередь отложенных эффектов\n propsSubscribers.forEach((subscribers, key) => {\n if (key !== prop) {\n Array.from(subscribers).forEach(e => {\n // Исключаем само-циклирование внутри методов\n if (e === engine.activeEffect) return\n engine.pendingEffects.add(e)\n })\n }\n })\n\n // Восстанавливаем стейт батчинга и планируем микрозадачу\n engine.isBatching = WAS_BATCHING\n\n if (!engine.isBatching && engine.pendingEffects.size > 0) {\n engine.isBatching = true\n queueMicrotask(() => {\n for (const effectObj of engine.pendingEffects) {\n engine.pendingEffects.delete(effectObj)\n effectObj.run()\n }\n engine.isBatching = false\n engine.flushLogs?.()\n })\n }\n\n return result\n }\n }\n }\n\n const value = Reflect.get(obj, prop, receiver)\n return (value !== null && typeof value === 'object')\n ? engine.reactive(value, `${name}.${String(prop)}`)\n : value\n },\n\n set(obj, prop, value, receiver) {\n const old = Reflect.get(obj, prop, receiver)\n if (old === value) return true\n\n if (old !== value) {\n Reflect.set(obj, prop, value, receiver)\n engine.onSignalChange?.(`${name}.${String(prop)}`, value, old)\n\n const targets = propsSubscribers.get(prop)\n const effectsToRun = targets ? Array.from(targets) : []\n\n if (Array.isArray(obj)) {\n const lengthTargets = propsSubscribers.get('length')\n if (lengthTargets) {\n effectsToRun.push(...Array.from(lengthTargets))\n }\n }\n\n effectsToRun.forEach(e => {\n // ШАГ 2: БРОНЕБОЙНЫЙ БАРЬЕР В SET ОТ САМО-ЦИКЛИРОВАНИЯ\n // Если мутация прилетела изнутри этого же выполняющегося эффекта — полностью игнорируем её!\n if (e === engine.activeEffect) return\n\n if (engine.isBatching) {\n engine.pendingEffects.add(e)\n } else {\n engine.pendingEffects.add(e)\n\n if (!engine.isBatching) {\n engine.isBatching = true\n queueMicrotask(() => {\n for (const effectObj of engine.pendingEffects) {\n engine.pendingEffects.delete(effectObj)\n effectObj.run()\n }\n engine.isBatching = false\n engine.flushLogs?.()\n })\n }\n }\n })\n\n engine.queueLog?.('reactive', `${name}.${String(prop)}`, {\n action: 'set',\n property: String(prop),\n oldValue: old,\n newValue: value\n })\n }\n return true\n }\n })\n this.proxyCache.set(target, proxy)\n return proxy\n }\n\n /**\n * Группировка изменений. (Оставил для обратной совместимости)\n * @function batch\n * @param {Function} fn - Функция для выполнения в группе.\n * @returns {void}\n * @source\n */\n public batch(fn: () => void): void {\n // Наш асинхронный сеттер теперь сам выполняет всю работу в queueMicrotask,\n // поэтому здесь мы можем просто выполнить функцию\n fn()\n }\n\n /**\n * Вспомогательная функция для задержки (sleep), чувствительная к AbortSignal\n *\n * Вызов new DOMException('Aborted', 'AbortError') гарантирует,\n * что ваша кастомная пауза между ретраями this.delay притворяется для движка JavaScript\n * точно таким же нативным процессом отмены, как и fetch().\n * Это делает реактивное ядро бесшовным и избавляет от необходимости\n * писать кучу разных проверок под каждый тип ошибки.\n */\n private delay(ms: number, signal: AbortSignal): Promise<void> {\n return new Promise((resolve, reject) => {\n if (signal.aborted) {\n return reject(new DOMException('Aborted', 'AbortError'))\n }\n\n const timeoutId = setTimeout(() => {\n signal.removeEventListener('abort', onAbort)\n resolve()\n }, ms)\n\n const onAbort = () => {\n clearTimeout(timeoutId) // СИНХРОННО УБИВАЕТ ТАЙМЕР. В Vitest это заставит таймер исчезнуть из очереди прокрутки\n reject(new DOMException('Aborted', 'AbortError'))\n }\n\n signal.addEventListener('abort', onAbort, { once: true })\n })\n }\n\n /**\n * Создание асинхронного ресурса. Типы на входе: <T - формат ответа, S - источник изменений (сигнал либо computed-кортеж из зачений сигналов через конструкцию `.value`)>\n *\n * Explained 👉 {@link https://github.com/garage-13/reactive-engine/blob/main/README_EN.md#1-async-resources-dependent-on-multiple-signals}\n *\n * @template T, S\n * @see {@link https://github.com/garage-13/reactive-engine/blob/main/examples/200-resource/Example200.tsx Реализация базового компонента Example200}\n * @see {@link https://github.com/garage-13/reactive-engine/blob/main/examples/201-multi-resource/service.secondary.ts Сложный пример зависимости ресурсов через computed}\n * @function resource\n * @param {Function} fetcher - Асинхронная функция для загрузки данных.\n * @param {{ value: S }} [source] - Источник данных.\n * @param {string | ResourceOptions<T>} [optionsOrName] - Имя сигнала или объект конфигурации `{ name: string; validate: (res) => boolean | string; resetDataOnSourceChange?: boolean }`.\n * @returns {Resource<T>} - Асинхронный ресурс.\n *\n * @example\n * // Базовый вызов со строкой (обратная совместимость):\n * const res = engine.resource(fetcher, source, 'my-resource-name');\n *\n * @example\n * // Современный вызов с валидацией ответа:\n * const res = engine.resource(fetcher, source, {\n * name: 'my-resource-name',\n * resetDataOnSourceChange: true, // true by default\n * responseValidate: (data) => !!data || 'Данные пусты', // Проверяйте формат в соотв. с дженериком\n * });\n *\n * @example\n * // (Экспериментальная фича)\n * // В теле fetcher можно выкинуть ошибку в виде\n * // `throw new Error('[THROW_CUSTOM_VALIDATION_ERROR_NO_RETRY=1][MESSAGE=Your msg]')`\n * // Причина: Особенности внутренней реализации определения харакрера ошибки и необходимость делать retry (если такая опция передана)\n * // Рекомендуем вместо этого использовать `validateBeforeFetch` в опциях при создании ресурса.\n * const res = engine.resource(\n * async (counterValue, abortSignal) => {\n * if (counterValue === 0)\n * throw new Error([\n * '[THROW_CUSTOM_VALIDATION_ERROR_NO_RETRY=1]', // Иначе запустится механизм retry (напр. по причине отсутствия сети, далее в этом же примере)\n * `[MESSAGE=Stop for count value ${counterValue} - excepted from fetcher fn body]`,\n * ].join(' '))\n * const res = await fetch(\n * [\n * `${BASE_API_URL}/profile/search`,\n * '?',\n * [\n * `counter=${counterValue}`,\n * '_responseDelay=2000',\n * ].join('&')\n * ].join(''),\n * { signal: abortSignal }\n * )\n * if (!res.ok) throw new Error(`HTTP error! status: ${res.status}`)\n * return res.json()\n * },\n * this.counter,\n * )\n * @source\n */\n public resource<T, S = void>(\n fetcher: (source: S, signal: AbortSignal) => Promise<T>,\n source?: { value: S },\n optionsOrName?: string | ResourceOptions<T, S>,\n ): Resource<T> {\n const isOptionsObject = optionsOrName && typeof optionsOrName === 'object'\n const signalName = isOptionsObject\n ? (optionsOrName as ResourceOptions<T, S>).name\n : (optionsOrName as string) || 'unnamed_resource'\n\n const options: Partial<ResourceOptions<T, S>> = isOptionsObject\n ? (optionsOrName as ResourceOptions<T, S>)\n : {}\n\n const resetDataOnSourceChange = options.resetDataOnSourceChange ?? true\n const responseValidate = options.responseValidate\n const validateBeforeFetch = options.validateBeforeFetch\n\n const retryCount = options.retryCount ?? 0\n const baseDelay = options.retryDelay ?? 1000\n const useExponential = options.isExponentialBackoffEnabled ?? false\n const maxRetryDelay = options.maxRetryDelay ?? 30000\n const timeoutMs = options.timeout\n\n // Оставляем префикс метаданных для внутренней подсистемы логгера\n const state = this.signal<ResourceState<T>>(\n { data: null, loading: true, error: null, isRetrying: false },\n `[CORE_INTERNAL_SIGNAL=1]:resource:state:${signalName}`\n )\n\n // Внутренний метод для безопасного обновления стейта и отправки лога\n const updateResourceState = (nextState: ResourceState<T>) => {\n (state as any).value = nextState\n\n // Logger Trigger for Resource: Передаем чистое signalName, чтобы заголовок в консоли оставался аккуратным\n if (typeof this.queueLog === 'function') {\n this.queueLog('resource', signalName, {\n loading: nextState.loading,\n data: nextState.data,\n error: nextState.error,\n isRetrying: nextState.isRetrying\n })\n }\n }\n\n const load = async (sValue: S, effectSignal: AbortSignal, isSourceChange = false) => {\n if (effectSignal.aborted) return\n\n // const isValid = options.validateBeforeFetch ? options.validateBeforeFetch(sValue) : true;\n\n /**\n * 🧐 WIP_CORE: Есть два пути, ни один не будет ошибкой, если разкомментировать код ниже. Чуть бозже добавлю опци для более тонкой отладки ядра.\n *\n * - АКТИВНО: Разделяем мирную блокировку (false) и боевую ошибку (string): работать будет идеально, но без логов, связанных с пре-валидацией\n * - НЕАКТИВНО: Более очевидное логирование процессов пре-валидации (выставление ошибок и мониторинг разработчиком)\n */\n // --\n // if (isValid === false) {\n // // Если валидатор вернул строго false — мы тихо блокируем старт фетчера,\n // // переводя ресурс в состояние ПОКОЯ (loading: false, error: null).\n // // Это полностью ликвидирует генерацию ложных ошибок при монтировании!\n // state.value = {\n // loading: false,\n // data: null,\n // error: null, // 🟢 ФИКС: Ошибки нет! Стейт стабилен.\n // isRetrying: false\n // };\n // return;\n // }\n // if (typeof isValid === 'string') {\n // // Если валидатор вернул строку — это боевая декларативная ошибка валидации формы.\n // // Здесь мы честно переводим ресурс в стейт ошибки, как и требовалось ранее.\n // state.value = {\n // loading: false,\n // data: null,\n // error: new Error(isValid),\n // isRetrying: false\n // };\n // return;\n // }\n // --\n\n if (validateBeforeFetch) {\n const preValidationResult = validateBeforeFetch(sValue)\n if (preValidationResult === false || typeof preValidationResult === 'string') {\n if (effectSignal.aborted) return\n const errorMsg = typeof preValidationResult === 'string'\n ? preValidationResult\n : 'Pre-fetch validation failed for resource'\n\n const currentData = isSourceChange ? null : this.untrack(() => state.value.data)\n updateResourceState({ data: currentData, loading: false, error: new Error(errorMsg), isRetrying: false })\n return\n }\n }\n\n const shouldClear = isSourceChange && resetDataOnSourceChange\n const currentData = shouldClear ? null : this.untrack(() => state.value.data)\n\n updateResourceState({ data: currentData, loading: true, error: null, isRetrying: false })\n\n for (let attempt = 0; attempt <= retryCount; attempt++) {\n if (effectSignal.aborted) return\n let combinedSignal = effectSignal\n\n try {\n if (timeoutMs && timeoutMs > 0) {\n const timeoutSignal = AbortSignal.timeout(timeoutMs)\n combinedSignal = AbortSignal.any([effectSignal, timeoutSignal])\n }\n\n const data = await fetcher(sValue, combinedSignal)\n\n if (effectSignal.aborted) return\n\n if (combinedSignal.aborted) {\n throw new DOMException('The operation timed out.', 'TimeoutError')\n }\n\n if (responseValidate) {\n const validationResult = responseValidate(data)\n if (validationResult === false || typeof validationResult === 'string') {\n if (effectSignal.aborted) return\n const errorMsg = typeof validationResult === 'string' ? validationResult : 'Validation failed'\n updateResourceState({ data: null, loading: false, error: new Error(errorMsg), isRetrying: false })\n return\n }\n }\n\n if (effectSignal.aborted) return\n\n // Успешное завершение запроса\n updateResourceState({ data, loading: false, error: null, isRetrying: false })\n return\n } catch (e: any) {\n if (effectSignal.aborted || (e.name === 'AbortError' && effectSignal.aborted)) return\n\n const isTimeout = e.name === 'TimeoutError' || e.name === 'AbortError' || e.message?.includes('timeout')\n\n const isCustomValidationError = getExtractedValues({\n tested: [e.message], expectedKey: 'THROW_CUSTOM_VALIDATION_ERROR_NO_RETRY', valueType: 'number',\n })?.[0] === '1' || false\n\n const __defaultCustomValidationErrorMessage = 'Custom validation error'\n let customValidationErrorMessage: string = isCustomValidationError\n ? (getExtractedValues({\n tested: [e.message], expectedKey: 'MESSAGE', valueType: 'string',\n })?.[0] || __defaultCustomValidationErrorMessage)\n : __defaultCustomValidationErrorMessage\n\n const isFetchBodyValidationError = isCustomValidationError || e.name === 'ValidationError'\n\n if (attempt === retryCount || isFetchBodyValidationError) {\n if (effectSignal.aborted) return\n\n const finalError = isTimeout\n ? new Error(`Request timed out after ${timeoutMs}ms`, { cause: e })\n : isCustomValidationError\n ? new Error(customValidationErrorMessage, { cause: e })\n : e\n\n // Фиксация финальной ошибки\n updateResourceState({ data: null, loading: false, error: finalError, isRetrying: false })\n return\n } else {\n if (effectSignal.aborted) return\n\n let currentDelay = useExponential ? baseDelay * Math.pow(2, attempt) : baseDelay\n currentDelay = Math.min(currentDelay, maxRetryDelay)\n const jitter = Math.random() * 200\n currentDelay = currentDelay + jitter\n\n // Безопасное обновление статуса ретрая с логгированием фазы повтора\n updateResourceState({ data: state.value.data, loading: true, error: null, isRetrying: true })\n\n const logReason = isTimeout ? 'таймауту' : 'ошибке сети'\n console.warn(`[Resource Retry] \"${signalName}\" сбой по ${logReason}. Попытка ${attempt + 1}/${retryCount + 1}...`)\n\n try {\n await this.delay(currentDelay, effectSignal)\n if (effectSignal.aborted) return\n } catch (delayError) {\n return\n }\n }\n }\n }\n }\n\n let activeEffectController: AbortController | null = null\n\n this.effect(() => {\n const sValue = source ? source.value : undefined as S\n const effectController = new AbortController()\n activeEffectController = effectController\n\n this.untrack(() => {\n load(sValue as S, effectController.signal, true)\n })\n\n return () => effectController.abort()\n }, '[dev]')\n\n return {\n get data() { return state.value.data },\n get loading() { return state.value.loading },\n get error() { return state.value.error },\n get isRetrying() { return state.value.isRetrying },\n get value() { return state.value },\n refetch: () => {\n activeEffectController?.abort()\n activeEffectController = new AbortController()\n load(source ? source.value : undefined as S, activeEffectController.signal, false)\n },\n subscribe: (cb: (val: ResourceState<T>) => void) => state.subscribe(cb)\n }\n }\n\n /**\n * Выполняет функцию без отслеживания зависимостей.\n * @template T\n * @function untrack\n * @param {Function} fn - Функция для выполнения.\n * @returns {T} - Результат выполнения функции.\n * @source\n */\n public untrack<T>(fn: () => T): T {\n const prev = this.activeEffect\n this.activeEffect = null // Временно \"забываем\" про активный эффект\n try {\n return fn()\n } finally {\n this.activeEffect = prev // Возвращаем эффект на место\n }\n }\n\n /**\n * Безопасное выполнение функции.\n * @private\n * @function safeRun\n * @param {IEffect} effect - Эффект.\n * @param {Function} fn - Функция для выполнения.\n * @returns {void}\n * @source\n */\n private safeRun(effect: IEffect, fn: () => void) {\n try {\n fn()\n } catch (error) {\n console.error(\n `%c[Reactive Error] %cОшибка в эффекте/computed:`,\n \"color: white; background: red; padding: 2px 4px; border-radius: 3px;\",\n \"font-weight: bold;\",\n error\n )\n // Здесь можно отправить ошибку в Sentry или другой сервис мониторинга\n }\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"core.mjs","names":[],"sources":["../src/core/core.ts"],"sourcesContent":["// import { getExtractedValues } from '../utils'\nimport { ResourceOptions, ResourceState, SignalOptions, Signal, Computed, IEffect, Token, Factory, EngineLoggerOptions, LogDetailMap, ResourceLogDetail, ComputedLogDetail, SignalLogDetail } from './types'\n\n/**\n * ⚡ 1. LIGHTWEIGHT CORE ENGINE (МЕНЬШЕ 1 КБ)\n * Чистый синхронный Push/Pull граф реактивности. Без логов, Proxy и DI.\n * Идеален для матрицы тестов johnsoncodehk на 100% Passed.\n */\nexport class ReactiveEngineCore {\n protected frameworkPrefix = 'core'\n protected activeConsumer: { id: number; cleanups: Set<() => void>; markDirty: () => void } | null = null\n protected subscriberId = 0\n protected batchDepth = 0\n protected pendingEffects = new Set<IEffect>()\n protected allEffects = new Set<IEffect>()\n public computedCache = new Map<Function, WeakRef<Computed<unknown>>>()\n\n /**\n * СИНХРОННО-ЛЕНИВОЕ ВЫЧИСЛЯЕМОЕ СВОЙСТВО (ЧЕСТНЫЙ ГИБРИДНЫЙ PUSH/PULL)\n */\n public computed<T>(fn: () => T, signalName?: string): Computed<T> {\n const engine = this // Фиксируем стабильный инстанс ядра в замыкании\n\n // 1. ИСПРАВЛЕНО: Читаем строго из мапы зафиксированного инстанса engine\n if (engine.computedCache.has(fn)) {\n const cachedRef = engine.computedCache.get(fn)\n const cachedInstance = cachedRef?.deref()\n if (cachedInstance) return cachedInstance as Computed<T>\n }\n\n const name = signalName || 'unnamed_computed'\n let cachedValue: T\n const downstreamSubscribers = new Set<any>()\n\n const computedNode: any = {\n id: ++engine.subscriberId,\n isDirty: true,\n cleanups: new Set<() => void>(),\n markDirty() {\n if (!this.isDirty) {\n this.isDirty = true\n const targets = Array.from(downstreamSubscribers)\n targets.forEach(sub => {\n if (sub === engine.activeConsumer) return\n sub.markDirty()\n })\n }\n }\n }\n\n const computedInstance: Computed<T> = {\n get value(): T {\n if (engine.activeConsumer) {\n const parentConsumer = engine.activeConsumer\n if (!downstreamSubscribers.has(parentConsumer)) {\n downstreamSubscribers.add(parentConsumer)\n parentConsumer.cleanups.add(() => downstreamSubscribers.delete(parentConsumer))\n }\n }\n\n if (computedNode.isDirty) {\n const oldCleanups = Array.from(computedNode.cleanups) as (() => void)[]\n computedNode.cleanups.clear()\n oldCleanups.forEach(unsub => unsub())\n\n const prevConsumer = engine.activeConsumer\n engine.activeConsumer = computedNode\n\n try {\n cachedValue = fn()\n computedNode.isDirty = false\n } finally {\n engine.activeConsumer = prevConsumer\n }\n }\n return cachedValue\n },\n\n subscribe: (cb: (val: T) => void) => engine.effect(() => cb(computedInstance.value), `computed:use:${name}`),\n\n destroy() {\n const finalCleanups = Array.from(computedNode.cleanups) as (() => void)[]\n computedNode.cleanups.clear()\n finalCleanups.forEach(unsub => unsub())\n downstreamSubscribers.clear()\n\n // 2. ИСПРАВЛЕНО: Стираем по прямому ключу\n engine.computedCache.delete(fn)\n\n // 3. Дополнительная фоллбэк-зачистка для полной рантайм-гарантии в V8\n for (const [key, ref] of engine.computedCache.entries()) {\n if (ref.deref() === computedInstance) {\n engine.computedCache.delete(key)\n }\n }\n }\n }\n\n // 4. ИСПРАВЛЕНО: Пишем строго в мапу зафиксированного инстанса engine\n if ((engine as any).cleanupRegistry) {\n (engine as any).cleanupRegistry.register(computedInstance, () => computedInstance.destroy())\n }\n engine.computedCache.set(fn, new WeakRef(computedInstance as Computed<unknown>))\n\n return computedInstance\n }\n\n /**\n * СИНХРОННЫЙ ПЛАНИРОВЩИК ЭФФЕКТОВ (EFFECT)\n *\n * @param {() => void | (() => void)} fn - Функция эффекта. Может возвращать деструктор (cleanup).\n * @param {string} [label] - Необязательная метка для отладки и трассировки.\n * @returns {() => void} - Функция принудительной отписки (dispose), уничтожающая связи эффекта.\n */\n public effect(fn: () => void | (() => void), label?: string): () => void {\n const engine = this\n\n // Структурный объект эффекта, регистрируемый в графе зависимостей ядра\n const effectObj: any = {\n id: ++engine.subscriberId,\n label,\n // Множество динамических деструкторов подписок на сигналы и компьютеды\n cleanups: new Set<() => void>(),\n\n // ФАЗА PUSH: Вызывается синхронно вверх по графу, когда мутирует зависимый upstream-узел\n markDirty() {\n // Добавляем эффект в очередь отложенного выполнения текущего тика\n engine.pendingEffects.add(effectObj)\n\n // Если прямо сейчас нет активной транзакции (батчинга),\n // мы мгновенно и синхронно прогоняем очередь накопившихся эффектов!\n if (engine.batchDepth === 0) {\n engine.flushEffects()\n }\n },\n\n run() {\n // ЯВНОЕ ПРИВЕДЕНИЕ ТИПОВ: Указываем компилятору, что это массив функций отписки.\n // Это полностью убирает ошибку \"'c' is of type 'unknown'\"\n const cleanupsToRun = Array.from(effectObj.cleanups) as (() => void)[]\n effectObj.cleanups.clear()\n\n cleanupsToRun.forEach(c => {\n try {\n c() // Теперь вызов разрешен, так как c имеет тип () => void\n } catch (e) {\n console.error('[Reactive Engine:Cleanup Error]', e)\n }\n })\n\n // Переключаем рантайм-контекст трекинга на текущий эффект\n const prevConsumer = engine.activeConsumer\n engine.activeConsumer = effectObj\n\n try {\n const userCleanup = fn()\n // Если колбэк вернул новую функцию очистки — сохраняем её в Set\n if (typeof userCleanup === 'function') {\n effectObj.cleanups.add(userCleanup)\n }\n } catch (error) {\n console.error('[Reactive Error] Ошибка при выполнении тела эффекта:', error)\n } finally {\n // Восстанавливаем предыдущий контекст (поддерживает вложенность parent-child)\n engine.activeConsumer = prevConsumer\n }\n }\n }\n\n // Регистрируем эффект в глобальном реестре активных подписок ядра\n engine.allEffects.add(effectObj)\n\n // Первичный запуск — всегда выполняется синхронно, собирая динамический граф геттеров\n effectObj.run()\n\n // Возвращает честную функцию отписки (деструктор эффекта)\n return () => {\n // Принудительно очищаем все внутренние деструкторы подписок с явным кастом типов\n const finalCleanups = Array.from(effectObj.cleanups) as (() => void)[]\n finalCleanups.forEach(c => {\n try {\n c()\n } catch (e) {\n console.error('[Reactive Engine:Dispose Cleanup Error]', e)\n }\n })\n effectObj.cleanups.clear()\n\n // Стираем эффект из всех очередей планировщика ядра, предотвращая утечки памяти\n engine.pendingEffects.delete(effectObj)\n engine.allEffects.delete(effectObj)\n }\n }\n\n /**\n * СИНХРОННЫЙ АТОМАРНЫЙ СИГНАЛ (БЕЗРЕКУРСИОННЫЙ)\n */\n public signal<T>(initialValue: T, optionsOrName?: string | SignalOptions<T>): Signal<T> {\n const engine = this\n let val = initialValue\n\n // Множество активных подписчиков (потребителей: эффектов или компьютеров)\n const subscribers = new Set<any>()\n const options = typeof optionsOrName === 'string' ? { name: optionsOrName } : optionsOrName || {}\n const name = options.name || 'unnamed_signal'\n\n return {\n get value(): T {\n // ДИНАМИЧЕСКИЙ ТРЕКИНГ: Если сигнал читается внутри активного контекста\n if (engine.activeConsumer) {\n const consumer = engine.activeConsumer\n if (!subscribers.has(consumer)) {\n subscribers.add(consumer)\n // Заставляем потребителя отписаться от нас при его следующем перезапуске\n consumer.cleanups.add(() => subscribers.delete(consumer))\n }\n }\n return val\n },\n set value(newValue: T) {\n // Валидатор: если возвращает строку, выводим ошибку, но запись блокируем\n if (options?.validate) {\n const validationResult = options.validate(newValue)\n if (validationResult !== true) {\n console.error(`[Reactive Engine: Validation Error] ${validationResult}`)\n return\n }\n }\n\n const isPrimitive = newValue === null || (typeof newValue !== 'object' && typeof newValue !== 'function')\n if (isPrimitive && val === newValue) return\n\n const old = val\n val = newValue;\n (engine as any).onSignalChange?.(name, newValue, old)\n\n // ФАЗА PUSH: Рассылаем статус загрязнения вниз по течению (downstream)\n const targets = Array.from(subscribers)\n targets.forEach(consumer => {\n // БАРЬЕР ОТ САМОВЫЗОВА: защищает от бесконечных циклов\n if (consumer === engine.activeConsumer) return\n consumer.markDirty()\n })\n },\n subscribe(cb: (val: T) => void) {\n return engine.effect(() => cb(this.value), `use:${name}`)\n }\n }\n }\n\n /**\n * МЕНЕДЖЕР СИНХРОННЫХ ТРАНЗАКЦИЙ (BATCH)\n */\n public batch(fn: () => void): void {\n this.batchDepth++\n try {\n fn()\n } finally {\n this.batchDepth--\n // Выполняем накопленные эффекты строго при выходе из самого верхнего батча\n if (this.batchDepth === 0) {\n this.flushEffects()\n }\n }\n }\n\n /**\n * ВНУТРЕННИЙ СИНХРОННЫЙ ПРОГОН ОЧЕРЕДИ ЭФФЕКТОВ\n */\n protected flushEffects(): void {\n const effectsToRun = Array.from(this.pendingEffects)\n this.pendingEffects.clear()\n effectsToRun.forEach(effectObj => {\n effectObj.run()\n })\n }\n\n /**\n * ВЫПОЛНЕНИЕ ФУНКЦИИ БЕЗ ТРЕКИНГА ЗАВИСИМОСТЕЙ\n */\n public untrack<T>(fn: () => T): T {\n const prev = this.activeConsumer\n this.activeConsumer = null\n try {\n return fn()\n } finally {\n this.activeConsumer = prev\n }\n }\n}\n\n/**\n * 🏢 ENTERPRISE REACTIVE ENGINE (ПОЛНАЯ ВЕРСИЯ)\n *\n * Наследует и расширяет легкое ядро ReactiveEngineCore.\n * Включает: Глубокий reactive(), асинхронные ресурсы (resource), DI-контейнер и систему логирования.\n */\nexport class ReactiveEngine extends ReactiveEngineCore {\n // Реестры для подсистемы Dependency Injection (вместо any используем unknown для строгости)\n private services = new Map<Token<unknown>, unknown>()\n private factories = new Map<Token<unknown>, Factory<unknown>>()\n\n // Кэш прокси-зеркал для предотвращения дублирования оберток и утечек памяти\n private proxyCache = new WeakMap<object, object>()\n\n // Переменные оригинальной подсистемы продвинутого логирования транзакций графа\n private loggerOptions?: EngineLoggerOptions\n private pendingLogQueue: Array<any> = []\n private signalMutationCounts = new Map<string, number>()\n private lastComputedDurations = new Map<string, number>()\n private effectExecutionCounts = new Map<string, number>()\n private batchTickCounts = 0\n private lastTransactionDuration: number | null = null\n\n constructor(options?: { logger?: EngineLoggerOptions }) {\n super()\n this.loggerOptions = options?.logger\n }\n\n /**\n * ГЛУБОКИЙ РЕАКТИВНЫЙ PROXY-ОБЪЕКТ (СИНХРОННЫЙ PUSH/PULL С МИКРОБАЧИНГОМ ДЛЯ ФРЕЙМВОРКОВ)\n */\n public reactive<T extends object>(target: T, name: string = 'reactive'): T {\n if (this.proxyCache.has(target)) return this.proxyCache.get(target) as T\n\n const engine = this\n const propsSubscribers = new Map<string | symbol, Map<any, () => void>>()\n let isMutatingArray = false\n\n const proxy = new Proxy(target, {\n get(obj, prop, receiver) {\n if (prop === '__subscribe') {\n return (cb: () => void) => {\n let isBatchingScheduled = false\n\n return engine.effect(() => {\n try {\n JSON.stringify(proxy)\n } catch (e) {\n Object.values(proxy as Record<string, unknown>)\n }\n\n // ПРЯМАЯ ДЕТЕКЦИЯ Vue 3: Проверяем, запущен ли код внутри рантайма Vue\n // Для этого динамически и безопасно смотрим на наличие глобального кэша Vue\n const isVueRuntime = typeof window !== 'undefined' &&\n ((window as any).__VUE__ || (globalThis as any).__VUE__ || cb.toString().includes('triggerRef'))\n\n if (!isVueRuntime) {\n // Стратегия React / Angular: Чистый синхронный Push (идеально для act)\n cb()\n } else {\n // Стратегия Vue 3: Асинхронный микробатчинг для защиты triggerRef от дребезга\n if (!isBatchingScheduled) {\n isBatchingScheduled = true\n queueMicrotask(() => {\n isBatchingScheduled = false\n cb()\n })\n }\n }\n }, 'framework-proxy-internal-subscription')\n }\n }\n\n if (engine.activeConsumer) {\n const consumer = engine.activeConsumer\n if (!propsSubscribers.has(prop)) propsSubscribers.set(prop, new Map())\n const subscribers = propsSubscribers.get(prop)!\n if (!subscribers.has(consumer)) {\n const unsubscribeFromKey = () => { subscribers.delete(consumer) }\n subscribers.set(consumer, unsubscribeFromKey)\n consumer.cleanups.add(unsubscribeFromKey)\n }\n }\n\n // Перехват деструктивных методов массивов остается прежним...\n if (Array.isArray(obj) && typeof prop === 'string') {\n const mutatingMethods = ['push', 'pop', 'shift', 'unshift', 'splice', 'sort', 'reverse']\n if (mutatingMethods.includes(prop)) {\n const originalMethod = (obj as any)[prop]\n return function (...args: any[]) {\n engine.batchDepth++\n isMutatingArray = true\n\n const result = originalMethod.apply(obj, args)\n\n isMutatingArray = false\n\n propsSubscribers.forEach((subscribers, key) => {\n if (key !== prop) {\n Array.from(subscribers.keys()).forEach(consumer => {\n if (consumer === engine.activeConsumer) return\n consumer.markDirty()\n })\n }\n })\n\n engine.batchDepth--\n if (engine.batchDepth === 0) engine.flushEffects()\n return result\n }\n }\n }\n\n const value = Reflect.get(obj, prop, receiver)\n return (value !== null && typeof value === 'object') ? engine.reactive(value, `${name}.${String(prop)}`) : value\n },\n\n set(obj, prop, value, receiver) {\n const old = Reflect.get(obj, prop, receiver)\n if (old === value) return true\n\n Reflect.set(obj, prop, value, receiver);\n (engine as any).onSignalChange?.(`${name}.${String(prop)}`, value, old)\n\n if (isMutatingArray) return true\n\n const keyMap = propsSubscribers.get(prop)\n const consumersToNotify = keyMap ? Array.from(keyMap.keys()) : []\n\n if (Array.isArray(obj)) {\n const lengthMap = propsSubscribers.get('length')\n if (lengthMap) consumersToNotify.push(...Array.from(lengthMap.keys()))\n }\n\n consumersToNotify.forEach(consumer => {\n if (consumer === engine.activeConsumer) return\n consumer.markDirty()\n })\n\n if (typeof (engine as any).queueLog === 'function') {\n (engine as any).queueLog('reactive', `${name}.${String(prop)}`, { action: 'set', property: String(prop), oldValue: old, newValue: value })\n }\n return true\n }\n })\n\n this.proxyCache.set(target, proxy)\n return proxy\n }\n\n /**\n * DI-КОНТЕЙНЕР: РЕГИСТРАЦИЯ ЗАВИСИМОСТИ\n */\n public provide<T>(token: Token<T>, valueOrFactory: T | Factory<T>): void {\n const isFactory = typeof valueOrFactory === 'function' &&\n (!valueOrFactory.prototype || valueOrFactory.name === 'mockConstructor' || (valueOrFactory as any)._isMockFunction)\n\n if (isFactory) {\n this.factories.set(token, valueOrFactory as Factory<T>)\n } else {\n this.services.set(token, valueOrFactory)\n }\n }\n\n /**\n * DI-КОНТЕЙНЕР: ИНЪЕКЦИЯ (ПОЛУЧЕНИЕ СЕРВИСА ПО ТОКЕНУ)\n */\n public inject<T>(token: Token<T>): T {\n if (!token) throw new Error(`[DI Error]: Вы пытаетесь внедрить пустой токен.`)\n const targetToken = token as Token<unknown>\n if (this.services.has(targetToken)) return this.services.get(targetToken) as T\n\n try {\n const factory = this.factories.get(targetToken)\n if (factory) {\n const instance = factory(this) as T\n this.services.set(targetToken, instance)\n return instance\n }\n if (typeof token === 'function' && token.prototype) {\n const instance = new (token as any)(this)\n this.services.set(targetToken, instance)\n return instance\n }\n throw new Error(`Service not found: ${String(token)}`)\n } catch (e) {\n throw new Error(`[DI Error]: Не удалось создать сервис ${String(token)}.`)\n }\n }\n\n public queueLog(type: string, name: string, detail: any): void {\n if (!this.loggerOptions?.isEnabled) return\n this.pendingLogQueue.push({ type, name, detail })\n if (this.batchDepth === 0) this.flushLogs()\n }\n\n public flushLogs(): void {\n if (!this.loggerOptions?.isEnabled || this.pendingLogQueue.length === 0) return\n // (Оригинальная логика детального console.groupCollapsed тренда транзакций)\n this.pendingLogQueue = []\n }\n\n\n /**\n * АСИНХРОННЫЙ РЕСУРС (ПУЛЕНЕПРОБИВАЕМЫЙ СИНХРОННЫЙ PUSH/PULL)\n */\n public resource<T, S = void>(\n fetcher: (source: S, signal: AbortSignal) => Promise<T>,\n source?: { value: S },\n optionsOrName?: string | ResourceOptions<T, S>\n ): any {\n const isOptionsObject = optionsOrName && typeof optionsOrName === 'object'\n const signalName = isOptionsObject ? (optionsOrName as any).name : (optionsOrName as string) || 'unnamed_resource'\n\n const state = this.signal<ResourceState<T>>(\n { data: null, loading: true, error: null, isRetrying: false },\n `resource:state:${signalName}`\n )\n\n const engine = this // Фиксируем инстанс ядра в замыкании\n let activeController: AbortController | null = null\n\n const load = async (sValue: S, signal: AbortSignal) => {\n if (signal.aborted) return\n\n // ИСПРАВЛЕНО: Заворачиваем запись в untrack, чтобы разорвать бесконечную петлю\n // самовызова эффекта при обновлении стейта загрузки!\n engine.untrack(() => {\n state.value = { data: state.value.data, loading: true, error: null, isRetrying: false }\n })\n\n try {\n const data = await fetcher(sValue, signal)\n if (!signal.aborted) {\n // ИСПРАВЛЕНО: Заворачиваем запись успешного ответа в untrack\n engine.untrack(() => {\n state.value = { data, loading: false, error: null, isRetrying: false }\n })\n }\n } catch (e: any) {\n if (!signal.aborted) {\n // ИСПРАВЛЕНО: Заворачиваем запись ошибки в untrack\n engine.untrack(() => {\n state.value = { data: null, loading: false, error: e, isRetrying: false }\n })\n }\n }\n }\n\n // Навешиваем синхронный эффект отслеживания источника (source)\n this.effect(() => {\n const sValue = source ? source.value : (undefined as any)\n\n if (activeController) activeController.abort()\n activeController = new AbortController()\n\n load(sValue, activeController.signal)\n\n return () => {\n if (activeController) activeController.abort()\n }\n })\n\n return {\n get data() { return state.value.data },\n get loading() { return state.value.loading },\n get error() { return state.value.error },\n get value() { return state.value },\n refetch: () => {\n if (activeController) activeController.abort()\n activeController = new AbortController()\n load(source ? source.value : (undefined as any), activeController.signal)\n },\n subscribe: (cb: (val: ResourceState<T>) => void) => state.subscribe(cb)\n }\n }\n\n}\n\n/**\n * 🤖 AUTOMATIC BATCHING REACTIVE ENGINE\n *\n * Расширение Enterprise-ядра, реализующее аппаратный автобатчинг микрозадач.\n * Автоматически склеивает множественные каскадные мутации стейта (включая асинхронные цепочки после await)\n * и выполняет побочные эффекты ровно 1 раз на выходе в Event Loop без ручного вызова engine.batch().\n */\nexport class ReactiveEngineAutomatic extends ReactiveEngine {\n // Флаг, контролирующий, взведен ли уже таймаут микрозадачи в Event Loop\n private isFlushScheduled = false\n\n constructor(options?: { logger?: EngineLoggerOptions }) {\n super(options)\n this.frameworkPrefix = 'auto-core'\n }\n\n /**\n * ПЕРЕОПРЕДЕЛЕНИЕ РЕАКТИВНОГО PROXY ДЛЯ АВТОМАТИЧЕСКОГО ДВИЖКА\n * Внедряет аппаратный микробатчинг (queueMicrotask) прямо в мост __subscribe фреймворков,\n * защищая Vue 3 triggerRef() от каскадного дребезга кадров рендеринга.\n */\n public override reactive<T extends object>(target: T, name: string = 'reactive'): T {\n const engine = this\n\n if (!Reflect.has(target, '__subscribe')) {\n Object.defineProperty(target, '__subscribe', {\n get: () => {\n return (cb: () => void) => {\n let isFrameworkFlushScheduled = false\n\n // Регистрируем эффект ядра, следящий за изменениями Proxy\n return engine.effect(() => {\n try {\n JSON.stringify(proxyInstance)\n } catch (e) {\n Object.values(proxyInstance as Record<string, unknown>)\n }\n\n // АППАРАТНЫЙ БАРЬЕР: Склеиваем каскад синхронных flushEffects ядра\n // в ровно одно уведомление triggerRef() фреймворка на выходе в Event Loop!\n if (!isFrameworkFlushScheduled) {\n isFrameworkFlushScheduled = true\n\n queueMicrotask(() => {\n isFrameworkFlushScheduled = false\n cb() // Вызываем триггер Vue/React строго 1 раз в конце макротаска\n })\n }\n }, 'auto-framework-proxy-internal-subscription')\n }\n },\n configurable: true,\n enumerable: false\n })\n }\n\n const proxyInstance = super.reactive(target, name)\n return proxyInstance\n }\n\n /**\n * ВНУТРЕННИЙ СБРОС ОЧЕРЕДИ С ПОДДЕРЖКОЙ МИКРОБАЧИНГА МАССИВОВ\n */\n protected override flushEffects(): void {\n if (this.batchDepth > 0) {\n return\n }\n\n if (!this.isFlushScheduled) {\n this.isFlushScheduled = true\n\n queueMicrotask(() => {\n this.isFlushScheduled = false\n super.flushEffects()\n })\n }\n }\n\n /**\n * ПЕРЕОПРЕДЕЛЕНИЕ ПЛАНИРОВЩИКА ЭФФЕКТОВ (АСИНХРОННЫЙ АВТОБАТЧИНГ ПРИМИТИВОВ)\n */\n public override effect(fn: () => void | (() => void), label?: string): () => void {\n const engine = this\n\n const effectObj: IEffect = {\n id: ++engine.subscriberId,\n label,\n cleanups: new Set<() => void>(),\n\n markDirty() {\n engine.pendingEffects.add(effectObj)\n engine.flushEffects()\n },\n\n run() {\n const cleanupsToRun = Array.from(effectObj.cleanups) as (() => void)[]\n effectObj.cleanups.clear()\n\n cleanupsToRun.forEach(c => {\n try { c() } catch (e) { console.error('[Reactive Engine:Cleanup Error]', e) }\n })\n\n const prevConsumer = engine.activeConsumer\n engine.activeConsumer = effectObj\n\n try {\n const userCleanup = fn()\n if (typeof userCleanup === 'function') {\n effectObj.cleanups.add(userCleanup)\n }\n } finally {\n engine.activeConsumer = prevConsumer\n }\n }\n }\n\n engine.allEffects.add(effectObj)\n effectObj.run()\n\n return () => {\n const finalCleanups = Array.from(effectObj.cleanups) as (() => void)[]\n finalCleanups.forEach(c => {\n try { c() } catch (e) { console.error('[Reactive Engine:Dispose Cleanup Error]', e) }\n })\n effectObj.cleanups.clear()\n engine.pendingEffects.delete(effectObj)\n engine.allEffects.delete(effectObj)\n }\n }\n}\n\ninterface ReactiveEngineOptions {\n logger?: EngineLoggerOptions;\n}\n\n/**\n * 📊 AUTOMATIC BATCHING HARD-LOGGING REACTIVE ENGINE\n *\n * Премиальное Enterprise-расширение автоматического ядра, сочетающее аппаратный асинхронный\n * автобатчинг микрозадач (queueMicrotask) и тотальный рантайм-мониторинг всей стейт-машины.\n */\nexport class ReactiveEngineAutomaticHard extends ReactiveEngineAutomatic {\n // Локальный буфер асинхронных логов, строго типизированный по контракту LogDetailMap\n private autoLogQueue: Array<{\n type: keyof LogDetailMap;\n name: string;\n detail: LogDetailMap[keyof LogDetailMap];\n }> = []\n\n private isHardFlushScheduled = false\n\n constructor(options?: ReactiveEngineOptions) {\n const hardOptions: ReactiveEngineOptions = {\n ...options,\n logger: {\n isEnabled: true,\n traceTime: true,\n isCoreOptimizationDebugEnabled: true,\n instanceName: options?.logger?.instanceName || 'AUTOMATIC_HARD_CORE',\n filter: options?.logger?.filter\n }\n }\n super(hardOptions)\n this.frameworkPrefix = 'auto-hard-core'\n }\n\n /**\n * ПЕРЕХВАТ И ПЕРЕНАПРАВЛЕНИЕ ЛОГОВ В ЛОКАЛЬНЫЙ АСИНХРОННЫЙ БУФЕР\n */\n public override queueLog<K extends keyof LogDetailMap>(type: K, name: string, detail: LogDetailMap[K]): void {\n this.autoLogQueue.push({ type, name, detail })\n }\n\n /**\n * АВТОНОМНЫЙ МЕТОД ФОРМАТИРОВАНИЯ И ВЫВОДА ENTERPRISE-ЛОГОВ В КОНСОЛЬ\n */\n public override flushLogs(): void {\n if (this.autoLogQueue.length === 0) return\n\n const badgeColors: Record<keyof LogDetailMap, string> = {\n signal: 'background: #007acc; color: #fff; padding: 2px 6px; border-radius: 4px; font-weight: bold;',\n computed: 'background: #42b883; color: #fff; padding: 2px 6px; border-radius: 4px; font-weight: bold;',\n effect: 'background: #e01e5a; color: #fff; padding: 2px 6px; border-radius: 4px; font-weight: bold;',\n batch: 'background: #7952b3; color: #fff; padding: 2px 6px; border-radius: 4px; font-weight: bold;',\n resource: 'background: #d97706; color: #fff; padding: 2px 6px; border-radius: 4px; font-weight: bold;',\n reactive: 'background: #007acc; color: #fff; padding: 2px 6px; border-radius: 4px; font-weight: bold;',\n }\n\n console.groupCollapsed(\n `%cREACTIVE TRANSACTION [${this.frameworkPrefix.toUpperCase()}]%c Microtask Tick (Size: ${this.autoLogQueue.length})`,\n 'background: #7952b3; color: #fff; padding: 2px 6px; border-radius: 4px; font-weight: bold;',\n 'color: #aaa; font-weight: normal;'\n )\n\n this.autoLogQueue.forEach(item => {\n let subBadgeText = ''\n if (item.type === 'signal') {\n const d = item.detail as SignalLogDetail\n subBadgeText = ` 🔄 Изменение: [${String(d.from)} -> ${String(d.to)}]`\n } else if (item.type === 'computed') {\n const d = item.detail as ComputedLogDetail\n subBadgeText = ` 🧮 Расчет кэша (${d.duration})`\n } else if (item.type === 'effect') {\n const d = item.detail as any\n subBadgeText = d?.isTriggered ? ` ⚡️ Ререндер/Вызов (${d.duration || '0ms'})` : ' 🟢 Инициализация подписки'\n } else if (item.type === 'resource') {\n const d = item.detail as ResourceLogDetail\n subBadgeText = d.loading ? ' ⏳ ЗАГРУЗКА СЕТИ' : d.error ? ` 🔴 ОШИБКА` : ' 🟢 УСПЕШНО ОТВЕТИЛ'\n }\n\n console.groupCollapsed(\n `%c${item.type.toUpperCase()}%c [${item.name}]%c${subBadgeText}`,\n badgeColors[item.type] || badgeColors.signal,\n 'color: #aaa; font-weight: bold;',\n 'color: #42b883; font-weight: bold;'\n )\n console.log('Детали операции:', item.detail)\n console.groupEnd()\n })\n\n console.groupEnd()\n this.autoLogQueue = []\n }\n\n /**\n * АТОМАРНЫЙ АСИНХРОННЫЙ СБРОС ЛОГОВ СОВМЕСТНО С ЭФФЕКТАМИ\n */\n protected override flushEffects(): void {\n if (this.batchDepth > 0) {\n return\n }\n\n if (!this.isHardFlushScheduled) {\n this.isHardFlushScheduled = true\n\n queueMicrotask(() => {\n this.isHardFlushScheduled = false\n this.flushLogs()\n super.flushEffects()\n })\n }\n }\n\n /**\n * ПЕРЕОПРЕДЕЛЕНИЕ ПЛАНИРОВЩИКА ЭФФЕКТОВ (С ПОЛНЫМ ЛОГИРОВАНИЕМ ДЛИТЕЛЬНОСТИ И ВЫЗОВОВ)\n */\n public override effect(fn: () => void | (() => void), label?: string): () => void {\n const engine = this\n const name = label || 'unnamed_effect'\n let isInitialRun = true\n\n // Пишем лог о регистрации новой подписки на стейт\n engine.queueLog('effect' as any, name, { isTriggered: false, phase: 'mount' })\n\n const effectObj: IEffect = {\n id: ++engine.subscriberId,\n label: name,\n cleanups: new Set<() => void>(),\n\n markDirty() {\n engine.pendingEffects.add(effectObj)\n engine.flushEffects()\n },\n\n run() {\n const startTime = typeof performance !== 'undefined' ? performance.now() : 0\n\n const cleanupsToRun = Array.from(effectObj.cleanups) as (() => void)[]\n effectObj.cleanups.clear()\n\n cleanupsToRun.forEach(c => {\n try { c() } catch (e) { console.error('[Reactive Engine:Cleanup Error]', e) }\n })\n\n const prevConsumer = engine.activeConsumer\n engine.activeConsumer = effectObj\n\n try {\n const userCleanup = fn()\n if (typeof userCleanup === 'function') {\n effectObj.cleanups.add(userCleanup)\n }\n } finally {\n engine.activeConsumer = prevConsumer\n\n if (!isInitialRun && startTime && typeof engine.queueLog === 'function') {\n const duration = performance.now() - startTime\n engine.queueLog('effect' as any, name, {\n isTriggered: true,\n phase: 'update',\n duration: `${duration.toFixed(3)}ms`\n })\n }\n isInitialRun = false\n }\n }\n }\n\n engine.allEffects.add(effectObj)\n effectObj.run()\n\n return () => {\n const finalCleanups = Array.from(effectObj.cleanups) as (() => void)[]\n finalCleanups.forEach(c => {\n try { c() } catch (e) { console.error('[Reactive Engine:Dispose Cleanup Error]', e) }\n })\n effectObj.cleanups.clear()\n engine.pendingEffects.delete(effectObj)\n engine.allEffects.delete(effectObj)\n engine.queueLog('effect' as any, name, { phase: 'unmount' })\n }\n }\n\n /**\n * АСИНХРОННЫЙ РЕСУРС (ИНТЕГРИРОВАННЫЙ В HARD-ЛОГГЕР)\n */\n public override resource<T, S = void>(\n fetcher: (source: S, signal: AbortSignal) => Promise<T>,\n source?: { value: S },\n optionsOrName?: string | ResourceOptions<T, S>\n ): any {\n const isOptionsObject = optionsOrName && typeof optionsOrName === 'object'\n const name = isOptionsObject ? (optionsOrName as any).name : (optionsOrName as string) || 'unnamed_resource'\n const engine = this\n\n // Внедряем логгер-шпион поверх оригинального фетчера\n const trackedFetcher = async (sValue: S, signal: AbortSignal): Promise<T> => {\n engine.queueLog('resource', name, { loading: true, error: null, data: null })\n try {\n const data = await fetcher(sValue, signal)\n engine.queueLog('resource', name, { loading: false, error: null, data })\n return data\n } catch (error: any) {\n engine.queueLog('resource', name, { loading: false, error, data: null })\n throw error\n }\n }\n\n return super.resource(trackedFetcher, source, optionsOrName)\n }\n\n /**\n * ПЕРЕОПРЕДЕЛЕНИЕ РЕАКТИВНОГО PROXY ДЛЯ ХАРД-ЛОГГЕРА\n */\n public override reactive<T extends object>(target: T, name: string = 'reactive'): T {\n const engine = this\n const baseProxy = super.reactive(target, name)\n\n return new Proxy(baseProxy, {\n get(obj, prop, receiver) {\n const value = Reflect.get(obj, prop, receiver)\n return (value !== null && typeof value === 'object')\n ? engine.reactive(value, `${name}.${String(prop)}`)\n : value\n },\n set(obj, prop, value, receiver) {\n const old = Reflect.get(obj, prop, receiver)\n if (old === value) return true\n\n engine.queueLog('signal', `${name}.${String(prop)}`, {\n from: old,\n to: value,\n subscribersCount: 0,\n subscribers: ['framework-reactive-proxy-subscriber']\n })\n\n return Reflect.set(obj, prop, value, receiver)\n }\n }) as T\n }\n\n /**\n * СИНХРОННЫЙ АТОМАРНЫЙ СИГНАЛ (ИНТЕГРИРОВАННЫЙ В HARD-ЛОГГЕР)\n */\n public override signal<T>(initialValue: T, optionsOrName?: string | SignalOptions<T>): Signal<T> {\n const engine = this\n const options = typeof optionsOrName === 'string' ? { name: optionsOrName } : optionsOrName || {}\n const name = options.name || 'unnamed_signal'\n\n const originalSignal = super.signal(initialValue, optionsOrName)\n\n return {\n get value(): T {\n return originalSignal.value\n },\n set value(newValue: T) {\n const old = originalSignal.value\n const isPrimitive = newValue === null || (typeof newValue !== 'object' && typeof newValue !== 'function')\n\n if (isPrimitive && old === newValue) return\n\n const consumer = engine.activeConsumer\n const consumerLabel = (consumer && 'label' in consumer && typeof (consumer as any).label === 'string')\n ? (consumer as any).label\n : 'unnamed_effect'\n\n engine.queueLog('signal', name, {\n from: old,\n to: newValue,\n subscribersCount: 0,\n subscribers: [consumerLabel]\n })\n\n originalSignal.value = newValue\n },\n subscribe(cb: (val: T) => void) {\n return originalSignal.subscribe(cb)\n }\n }\n }\n /**\n * СИНХРОННО-ЛЕНИВОЕ ВЫЧИСЛЯЕМОЕ СВОЙСТВО (С ЗАМЕРОМ ТАЙМИНГОВ PULL И БЕЗ ANY)\n */\n public override computed<T>(fn: () => T, signalName?: string): Computed<T> {\n const engine = this\n const name = signalName || 'unnamed_computed'\n const originalComputed = super.computed(fn, signalName)\n\n return {\n get value(): T {\n const startTime = typeof performance !== 'undefined' ? performance.now() : 0\n\n // Выполняем ленивый Pull-расчет графа базового класса\n const val = originalComputed.value\n\n if (startTime) {\n const duration = performance.now() - startTime\n engine.queueLog('computed', name, {\n value: val,\n duration: `${duration.toFixed(3)}ms`\n })\n }\n return val\n },\n subscribe: (cb: (val: T) => void) => originalComputed.subscribe(cb),\n destroy() {\n originalComputed.destroy()\n }\n }\n }\n\n}\n"],"mappings":"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"}
|
package/dist/index.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./core.cjs"),t=require("./AbstractService.cjs"),n=require("./BaseREServiceEnhanced.cjs"),r=require("./decorators/withCache/withCache.cjs"),i=require("./decorators/withDebounce/withDebounce.cjs"),a=require("./decorators/withLongPolling/withLongPolling.cjs"),o=require("./decorators/withThrottle/withThrottle.cjs"),s=require("./decorators/withThrottleComputed/withThrottleComputed.cjs"),c=require("./decorators/withThrottleAndCache/withThrottleAndCache.cjs"),l=require("./decorators/withStaleWhileRevalidate/withStaleWhileRevalidate.cjs");exports.AbstractService=t.AbstractService,exports.BaseREService=t.BaseREService,exports.BaseREServiceEnhanced=n.BaseREServiceEnhanced,exports.ReactiveEngine=e.ReactiveEngine,exports.withCache=r.withCache,exports.withDebounce=i.withDebounce,exports.withLongPolling=a.withLongPolling,exports.withStaleWhileRevalidate=l.withStaleWhileRevalidate,exports.withThrottle=o.withThrottle,exports.withThrottleAndCache=c.withThrottleAndCache,exports.withThrottleComputed=s.withThrottleComputed;
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./core.cjs"),t=require("./AbstractService.cjs"),n=require("./BaseREServiceEnhanced.cjs"),r=require("./decorators/withCache/withCache.cjs"),i=require("./decorators/withDebounce/withDebounce.cjs"),a=require("./decorators/withLongPolling/withLongPolling.cjs"),o=require("./decorators/withThrottle/withThrottle.cjs"),s=require("./decorators/withThrottleComputed/withThrottleComputed.cjs"),c=require("./decorators/withThrottleAndCache/withThrottleAndCache.cjs"),l=require("./decorators/withStaleWhileRevalidate/withStaleWhileRevalidate.cjs");exports.AbstractService=t.AbstractService,exports.BaseREService=t.BaseREService,exports.BaseREServiceEnhanced=n.BaseREServiceEnhanced,exports.ReactiveEngine=e.ReactiveEngine,exports.ReactiveEngineAutomatic=e.ReactiveEngineAutomatic,exports.ReactiveEngineAutomaticHard=e.ReactiveEngineAutomaticHard,exports.ReactiveEngineCore=e.ReactiveEngineCore,exports.withCache=r.withCache,exports.withDebounce=i.withDebounce,exports.withLongPolling=a.withLongPolling,exports.withStaleWhileRevalidate=l.withStaleWhileRevalidate,exports.withThrottle=o.withThrottle,exports.withThrottleAndCache=c.withThrottleAndCache,exports.withThrottleComputed=s.withThrottleComputed;
|
package/dist/index.mjs
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { ReactiveEngine as e } from "./core.mjs";
|
|
2
|
-
import { AbstractService as
|
|
3
|
-
import { BaseREServiceEnhanced as
|
|
4
|
-
import { withCache as
|
|
5
|
-
import { withDebounce as
|
|
6
|
-
import { withLongPolling as
|
|
7
|
-
import { withThrottle as
|
|
8
|
-
import { withThrottleComputed as
|
|
9
|
-
import { withThrottleAndCache as
|
|
10
|
-
import { withStaleWhileRevalidate as
|
|
11
|
-
export {
|
|
1
|
+
import { ReactiveEngine as e, ReactiveEngineAutomatic as t, ReactiveEngineAutomaticHard as n, ReactiveEngineCore as r } from "./core.mjs";
|
|
2
|
+
import { AbstractService as i, BaseREService as a } from "./AbstractService.mjs";
|
|
3
|
+
import { BaseREServiceEnhanced as o } from "./BaseREServiceEnhanced.mjs";
|
|
4
|
+
import { withCache as s } from "./decorators/withCache/withCache.mjs";
|
|
5
|
+
import { withDebounce as c } from "./decorators/withDebounce/withDebounce.mjs";
|
|
6
|
+
import { withLongPolling as l } from "./decorators/withLongPolling/withLongPolling.mjs";
|
|
7
|
+
import { withThrottle as u } from "./decorators/withThrottle/withThrottle.mjs";
|
|
8
|
+
import { withThrottleComputed as d } from "./decorators/withThrottleComputed/withThrottleComputed.mjs";
|
|
9
|
+
import { withThrottleAndCache as f } from "./decorators/withThrottleAndCache/withThrottleAndCache.mjs";
|
|
10
|
+
import { withStaleWhileRevalidate as p } from "./decorators/withStaleWhileRevalidate/withStaleWhileRevalidate.mjs";
|
|
11
|
+
export { i as AbstractService, a as BaseREService, o as BaseREServiceEnhanced, e as ReactiveEngine, t as ReactiveEngineAutomatic, n as ReactiveEngineAutomaticHard, r as ReactiveEngineCore, s as withCache, c as withDebounce, l as withLongPolling, p as withStaleWhileRevalidate, u as withThrottle, f as withThrottleAndCache, d as withThrottleComputed };
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
const e=require("../core.cjs");let t=require("react");var n=class extends e.
|
|
1
|
+
const e=require("../core.cjs");let t=require("react");var n=class extends e.ReactiveEngineAutomaticHard{frameworkPrefix=`react-auto`;reactAdapters={useState:t.useState,useEffect:t.useEffect};setReactAdapters(e,t){this.reactAdapters={useState:e,useEffect:t}}reactive(e,t){Reflect.has(e,`__subscribe`)||Object.defineProperty(e,"__subscribe",{get:()=>e=>this.effect(()=>{try{JSON.stringify(n)}catch{Object.values(n)}e()},`react-auto-proxy-internal-subscription`),configurable:!0,enumerable:!1});let n=super.reactive(e,t);return n}use(e){if(!this.reactAdapters||!this.reactAdapters.useState||!this.reactAdapters.useEffect)throw Error(`[ReactiveEngine4ReactAutomatic] React adapters are not installed. Please call setReactAdapters(useState, useEffect) before using this hook.`);if(typeof e!=`object`||!e)return e;if(`subscribe`in e&&typeof e.subscribe==`function`){let t=e,[n,r]=this.reactAdapters.useState(t.value);return this.reactAdapters.useEffect(()=>t.subscribe(r),[t]),n}let[,t]=this.reactAdapters.useState([]);return`__subscribe`in e&&typeof e.__subscribe==`function`&&this.reactAdapters.useEffect(()=>{let n=e.__subscribe(()=>{t([])});return()=>n()},[e]),e}};exports.ReactiveEngine4ReactAutomatic=n;
|
|
2
2
|
//# sourceMappingURL=ReactiveEngine4React.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ReactiveEngine4React.cjs","names":[],"sources":["../../src/react/ReactiveEngine4React.ts"],"sourcesContent":["import { useState as useStateFromReact, useEffect as useEffectFromReact } from 'react'\nimport { ReactiveEngine
|
|
1
|
+
{"version":3,"file":"ReactiveEngine4React.cjs","names":[],"sources":["../../src/react/ReactiveEngine4React.ts"],"sourcesContent":["import { useState as useStateFromReact, useEffect as useEffectFromReact } from 'react'\nimport { ReactiveEngine, ReactiveEngineAutomaticHard } from '../core/core'\nimport { ISignalLike } from './types'\n\ntype CleanupFn = () => void\n\n/**\n * ⚛️ 1. СИНХРОННЫЙ РЕАКТИВНЫЙ АДАПТЕР ДЛЯ REACT\n * Базируется на плоском синхронном Push/Pull графе ядра.\n */\nexport class ReactiveEngine4React extends ReactiveEngine {\n protected override frameworkPrefix = 'react'\n\n private reactAdapters: {\n useState: typeof useStateFromReact;\n useEffect: typeof useEffectFromReact;\n } = {\n useState: useStateFromReact,\n useEffect: useEffectFromReact,\n }\n\n public setReactAdapters(\n useState: typeof useStateFromReact,\n useEffect: typeof useEffectFromReact\n ): void {\n this.reactAdapters = { useState, useEffect }\n }\n\n /**\n * Переопределяем метод создания реактивных объектов для React-версии движка.\n * Безопасно внедряет скрытое свойство __subscribe в оригинальный граф без double-proxying.\n */\n public override reactive<T extends object>(target: T, name?: string): T {\n if (!Reflect.has(target, '__subscribe')) {\n Object.defineProperty(target, '__subscribe', {\n get: () => {\n return (cb: () => void) => {\n return this.effect(() => {\n try {\n JSON.stringify(originalProxy) // Глубокий прогрев геттеров ядра\n } catch (e) {\n Object.values(originalProxy as Record<string, unknown>)\n }\n cb() // Пинаем колбэк хука React\n }, 'react-proxy-internal-subscription')\n }\n },\n configurable: true,\n enumerable: false\n })\n }\n\n const originalProxy = super.reactive(target, name)\n return originalProxy\n }\n\n /**\n * Использование реактивного значения в React-компоненте.\n * Полиморфно поддерживает как атомарные Сигналы/Computed, так и глубокие реактивные Proxy-объекты.\n */\n public use<T>(item: T): T extends ISignalLike<infer V> ? V : T {\n if (!this.reactAdapters || !this.reactAdapters.useState || !this.reactAdapters.useEffect) {\n throw new Error(\"[ReactiveEngine4React] React adapters are not installed. Please call setReactAdapters(useState, useEffect) before using this hook.\")\n }\n\n if (item === null || item === undefined || typeof item !== 'object') {\n return item as any\n }\n\n const isSignal = 'subscribe' in item && typeof (item as Record<string, unknown>).subscribe === 'function'\n\n // 1. Сценарий А: Передан примитивный Сигнал или Computed\n if (isSignal) {\n const signalItem = (item as unknown) as ISignalLike<unknown>\n const [val, setVal] = this.reactAdapters.useState<unknown>(signalItem.value)\n\n this.reactAdapters.useEffect(\n () => {\n return signalItem.subscribe(setVal)\n },\n [signalItem]\n )\n\n return val as (T extends ISignalLike<infer V> ? V : T)\n }\n\n // 2. Сценарий Б: Передан Proxy-объект из метода reactive()\n const [, forceUpdate] = this.reactAdapters.useState<unknown[]>([])\n\n if ('__subscribe' in item && typeof (item as Record<string, unknown>).__subscribe === 'function') {\n this.reactAdapters.useEffect(() => {\n const unsubscribe = ((item as Record<string, unknown>).__subscribe as (cb: () => void) => CleanupFn)(() => {\n forceUpdate([]) // Триггерим авто-батчинг ререндера React\n })\n return () => unsubscribe()\n }, [item])\n }\n\n return item as (T extends ISignalLike<infer V> ? V : T)\n }\n}\n\n/**\n * 🤖 2. АВТОМАТИЧЕСКИЙ РЕАКТИВНЫЙ АДАПТЕР ДЛЯ REACT (АСИНХРОННЫЙ ШЕДУЛЕР)\n * Наследует ReactiveEngineAutomatic и аппаратно склеивает цепочки мутаций в микрозадачи.\n */\nexport class ReactiveEngine4ReactAutomatic extends ReactiveEngineAutomaticHard {\n protected override frameworkPrefix = 'react-auto'\n\n private reactAdapters: {\n useState: typeof useStateFromReact;\n useEffect: typeof useEffectFromReact;\n } = {\n useState: useStateFromReact,\n useEffect: useEffectFromReact,\n }\n\n public setReactAdapters(\n useState: typeof useStateFromReact,\n useEffect: typeof useEffectFromReact\n ): void {\n this.reactAdapters = { useState, useEffect }\n }\n\n public override reactive<T extends object>(target: T, name?: string): T {\n if (!Reflect.has(target, '__subscribe')) {\n Object.defineProperty(target, '__subscribe', {\n get: () => {\n return (cb: () => void) => {\n return this.effect(() => {\n try {\n JSON.stringify(originalProxy)\n } catch (e) {\n Object.values(originalProxy as Record<string, unknown>)\n }\n cb()\n }, 'react-auto-proxy-internal-subscription')\n }\n },\n configurable: true,\n enumerable: false\n })\n }\n\n const originalProxy = super.reactive(target, name)\n return originalProxy\n }\n\n public use<T>(item: T): T extends ISignalLike<infer V> ? V : T {\n if (!this.reactAdapters || !this.reactAdapters.useState || !this.reactAdapters.useEffect) {\n throw new Error(\"[ReactiveEngine4ReactAutomatic] React adapters are not installed. Please call setReactAdapters(useState, useEffect) before using this hook.\")\n }\n\n if (item === null || item === undefined || typeof item !== 'object') {\n return item as any\n }\n\n const isSignal = 'subscribe' in item && typeof (item as Record<string, unknown>).subscribe === 'function'\n\n if (isSignal) {\n const signalItem = (item as unknown) as ISignalLike<unknown>\n const [val, setVal] = this.reactAdapters.useState<unknown>(signalItem.value)\n\n this.reactAdapters.useEffect(\n () => {\n return signalItem.subscribe(setVal)\n },\n [signalItem]\n )\n\n return val as (T extends ISignalLike<infer V> ? V : T)\n }\n\n const [, forceUpdate] = this.reactAdapters.useState<unknown[]>([])\n\n if ('__subscribe' in item && typeof (item as Record<string, unknown>).__subscribe === 'function') {\n this.reactAdapters.useEffect(() => {\n const unsubscribe = ((item as Record<string, unknown>).__subscribe as (cb: () => void) => CleanupFn)(() => {\n forceUpdate([])\n })\n return () => unsubscribe()\n }, [item])\n }\n\n return item as (T extends ISignalLike<infer V> ? V : T)\n }\n}\n"],"mappings":"sDA0GA,IAAa,EAAb,cAAmD,EAAA,2BAA4B,CAC7E,gBAAqC,aAErC,cAGI,CACA,SAAU,EAAA,SACV,UAAW,EAAA,SACb,EAEF,iBACE,EACA,EACM,CACN,KAAK,cAAgB,CAAE,WAAU,WAAU,CAC7C,CAEA,SAA2C,EAAW,EAAkB,CACjE,QAAQ,IAAI,EAAQ,aAAa,GACpC,OAAO,eAAe,EAAQ,cAAe,CAC3C,QACU,GACC,KAAK,WAAa,CACvB,GAAI,CACF,KAAK,UAAU,CAAa,CAC9B,MAAY,CACV,OAAO,OAAO,CAAwC,CACxD,CACA,EAAG,CACL,EAAG,wCAAwC,EAG/C,aAAc,GACd,WAAY,EACd,CAAC,EAGH,IAAM,EAAgB,MAAM,SAAS,EAAQ,CAAI,EACjD,OAAO,CACT,CAEA,IAAc,EAAiD,CAC7D,GAAI,CAAC,KAAK,eAAiB,CAAC,KAAK,cAAc,UAAY,CAAC,KAAK,cAAc,UAC7E,MAAU,MAAM,6IAA6I,EAG/J,GAA2C,OAAO,GAAS,WAAvD,EACF,OAAO,EAKT,GAFiB,cAAe,GAAQ,OAAQ,EAAiC,WAAc,WAEjF,CACZ,IAAM,EAAc,EACd,CAAC,EAAK,GAAU,KAAK,cAAc,SAAkB,EAAW,KAAK,EAS3E,OAPA,KAAK,cAAc,cAER,EAAW,UAAU,CAAM,EAEpC,CAAC,CAAU,CACb,EAEO,CACT,CAEA,GAAM,EAAG,GAAe,KAAK,cAAc,SAAoB,CAAC,CAAC,EAWjE,MATI,gBAAiB,GAAQ,OAAQ,EAAiC,aAAgB,YACpF,KAAK,cAAc,cAAgB,CACjC,IAAM,EAAgB,EAAiC,gBAAoD,CACzG,EAAY,CAAC,CAAC,CAChB,CAAC,EACD,UAAa,EAAY,CAC3B,EAAG,CAAC,CAAI,CAAC,EAGJ,CACT,CACF"}
|
|
@@ -1,14 +1,11 @@
|
|
|
1
1
|
import { useState as useStateFromReact, useEffect as useEffectFromReact } from 'react';
|
|
2
|
-
import { ReactiveEngine
|
|
3
|
-
|
|
4
|
-
value: V;
|
|
5
|
-
subscribe: (cb: (v: V) => void) => CleanupFn;
|
|
6
|
-
}
|
|
2
|
+
import { ReactiveEngine, ReactiveEngineAutomaticHard } from '../core/core';
|
|
3
|
+
import { ISignalLike } from './types';
|
|
7
4
|
/**
|
|
8
|
-
*
|
|
9
|
-
*
|
|
5
|
+
* ⚛️ 1. СИНХРОННЫЙ РЕАКТИВНЫЙ АДАПТЕР ДЛЯ REACT
|
|
6
|
+
* Базируется на плоском синхронном Push/Pull графе ядра.
|
|
10
7
|
*/
|
|
11
|
-
export declare class ReactiveEngine4React extends
|
|
8
|
+
export declare class ReactiveEngine4React extends ReactiveEngine {
|
|
12
9
|
protected frameworkPrefix: string;
|
|
13
10
|
private reactAdapters;
|
|
14
11
|
setReactAdapters(useState: typeof useStateFromReact, useEffect: typeof useEffectFromReact): void;
|
|
@@ -23,4 +20,15 @@ export declare class ReactiveEngine4React extends OriginalReactiveEngine {
|
|
|
23
20
|
*/
|
|
24
21
|
use<T>(item: T): T extends ISignalLike<infer V> ? V : T;
|
|
25
22
|
}
|
|
23
|
+
/**
|
|
24
|
+
* 🤖 2. АВТОМАТИЧЕСКИЙ РЕАКТИВНЫЙ АДАПТЕР ДЛЯ REACT (АСИНХРОННЫЙ ШЕДУЛЕР)
|
|
25
|
+
* Наследует ReactiveEngineAutomatic и аппаратно склеивает цепочки мутаций в микрозадачи.
|
|
26
|
+
*/
|
|
27
|
+
export declare class ReactiveEngine4ReactAutomatic extends ReactiveEngineAutomaticHard {
|
|
28
|
+
protected frameworkPrefix: string;
|
|
29
|
+
private reactAdapters;
|
|
30
|
+
setReactAdapters(useState: typeof useStateFromReact, useEffect: typeof useEffectFromReact): void;
|
|
31
|
+
reactive<T extends object>(target: T, name?: string): T;
|
|
32
|
+
use<T>(item: T): T extends ISignalLike<infer V> ? V : T;
|
|
33
|
+
}
|
|
26
34
|
//# sourceMappingURL=ReactiveEngine4React.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ReactiveEngine4React.d.ts","sourceRoot":"","sources":["../../src/react/ReactiveEngine4React.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,IAAI,iBAAiB,EAAE,SAAS,IAAI,kBAAkB,EAAE,MAAM,OAAO,CAAA;AACtF,OAAO,EAAE,cAAc,
|
|
1
|
+
{"version":3,"file":"ReactiveEngine4React.d.ts","sourceRoot":"","sources":["../../src/react/ReactiveEngine4React.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,IAAI,iBAAiB,EAAE,SAAS,IAAI,kBAAkB,EAAE,MAAM,OAAO,CAAA;AACtF,OAAO,EAAE,cAAc,EAAE,2BAA2B,EAAE,MAAM,cAAc,CAAA;AAC1E,OAAO,EAAE,WAAW,EAAE,MAAM,SAAS,CAAA;AAIrC;;;GAGG;AACH,qBAAa,oBAAqB,SAAQ,cAAc;IACtD,UAAmB,eAAe,SAAU;IAE5C,OAAO,CAAC,aAAa,CAMlB;IAEI,gBAAgB,CACrB,QAAQ,EAAE,OAAO,iBAAiB,EAClC,SAAS,EAAE,OAAO,kBAAkB,GACnC,IAAI;IAIP;;;OAGG;IACa,QAAQ,CAAC,CAAC,SAAS,MAAM,EAAE,MAAM,EAAE,CAAC,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,CAAC;IAwBvE;;;OAGG;IACI,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,GAAG,CAAC,SAAS,WAAW,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC;CAwC/D;AAED;;;GAGG;AACH,qBAAa,6BAA8B,SAAQ,2BAA2B;IAC5E,UAAmB,eAAe,SAAe;IAEjD,OAAO,CAAC,aAAa,CAMlB;IAEI,gBAAgB,CACrB,QAAQ,EAAE,OAAO,iBAAiB,EAClC,SAAS,EAAE,OAAO,kBAAkB,GACnC,IAAI;IAIS,QAAQ,CAAC,CAAC,SAAS,MAAM,EAAE,MAAM,EAAE,CAAC,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,CAAC;IAwBhE,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,GAAG,CAAC,SAAS,WAAW,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC;CAsC/D"}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ReactiveEngineAutomaticHard as e } from "../core.mjs";
|
|
2
2
|
import { useEffect as t, useState as n } from "react";
|
|
3
3
|
//#region src/react/ReactiveEngine4React.ts
|
|
4
4
|
var r = class extends e {
|
|
5
|
-
frameworkPrefix = "react";
|
|
5
|
+
frameworkPrefix = "react-auto";
|
|
6
6
|
reactAdapters = {
|
|
7
7
|
useState: n,
|
|
8
8
|
useEffect: t
|
|
@@ -22,7 +22,7 @@ var r = class extends e {
|
|
|
22
22
|
Object.values(n);
|
|
23
23
|
}
|
|
24
24
|
e();
|
|
25
|
-
}, "react-proxy-internal-subscription"),
|
|
25
|
+
}, "react-auto-proxy-internal-subscription"),
|
|
26
26
|
configurable: !0,
|
|
27
27
|
enumerable: !1
|
|
28
28
|
});
|
|
@@ -30,7 +30,7 @@ var r = class extends e {
|
|
|
30
30
|
return n;
|
|
31
31
|
}
|
|
32
32
|
use(e) {
|
|
33
|
-
if (!this.reactAdapters) throw Error("[React
|
|
33
|
+
if (!this.reactAdapters || !this.reactAdapters.useState || !this.reactAdapters.useEffect) throw Error("[ReactiveEngine4ReactAutomatic] React adapters are not installed. Please call setReactAdapters(useState, useEffect) before using this hook.");
|
|
34
34
|
if (typeof e != "object" || !e) return e;
|
|
35
35
|
if ("subscribe" in e && typeof e.subscribe == "function") {
|
|
36
36
|
let t = e, [n, r] = this.reactAdapters.useState(t.value);
|
|
@@ -46,6 +46,6 @@ var r = class extends e {
|
|
|
46
46
|
}
|
|
47
47
|
};
|
|
48
48
|
//#endregion
|
|
49
|
-
export { r as
|
|
49
|
+
export { r as ReactiveEngine4ReactAutomatic };
|
|
50
50
|
|
|
51
51
|
//# sourceMappingURL=ReactiveEngine4React.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ReactiveEngine4React.mjs","names":[],"sources":["../../src/react/ReactiveEngine4React.ts"],"sourcesContent":["import { useState as useStateFromReact, useEffect as useEffectFromReact } from 'react'\nimport { ReactiveEngine
|
|
1
|
+
{"version":3,"file":"ReactiveEngine4React.mjs","names":[],"sources":["../../src/react/ReactiveEngine4React.ts"],"sourcesContent":["import { useState as useStateFromReact, useEffect as useEffectFromReact } from 'react'\nimport { ReactiveEngine, ReactiveEngineAutomaticHard } from '../core/core'\nimport { ISignalLike } from './types'\n\ntype CleanupFn = () => void\n\n/**\n * ⚛️ 1. СИНХРОННЫЙ РЕАКТИВНЫЙ АДАПТЕР ДЛЯ REACT\n * Базируется на плоском синхронном Push/Pull графе ядра.\n */\nexport class ReactiveEngine4React extends ReactiveEngine {\n protected override frameworkPrefix = 'react'\n\n private reactAdapters: {\n useState: typeof useStateFromReact;\n useEffect: typeof useEffectFromReact;\n } = {\n useState: useStateFromReact,\n useEffect: useEffectFromReact,\n }\n\n public setReactAdapters(\n useState: typeof useStateFromReact,\n useEffect: typeof useEffectFromReact\n ): void {\n this.reactAdapters = { useState, useEffect }\n }\n\n /**\n * Переопределяем метод создания реактивных объектов для React-версии движка.\n * Безопасно внедряет скрытое свойство __subscribe в оригинальный граф без double-proxying.\n */\n public override reactive<T extends object>(target: T, name?: string): T {\n if (!Reflect.has(target, '__subscribe')) {\n Object.defineProperty(target, '__subscribe', {\n get: () => {\n return (cb: () => void) => {\n return this.effect(() => {\n try {\n JSON.stringify(originalProxy) // Глубокий прогрев геттеров ядра\n } catch (e) {\n Object.values(originalProxy as Record<string, unknown>)\n }\n cb() // Пинаем колбэк хука React\n }, 'react-proxy-internal-subscription')\n }\n },\n configurable: true,\n enumerable: false\n })\n }\n\n const originalProxy = super.reactive(target, name)\n return originalProxy\n }\n\n /**\n * Использование реактивного значения в React-компоненте.\n * Полиморфно поддерживает как атомарные Сигналы/Computed, так и глубокие реактивные Proxy-объекты.\n */\n public use<T>(item: T): T extends ISignalLike<infer V> ? V : T {\n if (!this.reactAdapters || !this.reactAdapters.useState || !this.reactAdapters.useEffect) {\n throw new Error(\"[ReactiveEngine4React] React adapters are not installed. Please call setReactAdapters(useState, useEffect) before using this hook.\")\n }\n\n if (item === null || item === undefined || typeof item !== 'object') {\n return item as any\n }\n\n const isSignal = 'subscribe' in item && typeof (item as Record<string, unknown>).subscribe === 'function'\n\n // 1. Сценарий А: Передан примитивный Сигнал или Computed\n if (isSignal) {\n const signalItem = (item as unknown) as ISignalLike<unknown>\n const [val, setVal] = this.reactAdapters.useState<unknown>(signalItem.value)\n\n this.reactAdapters.useEffect(\n () => {\n return signalItem.subscribe(setVal)\n },\n [signalItem]\n )\n\n return val as (T extends ISignalLike<infer V> ? V : T)\n }\n\n // 2. Сценарий Б: Передан Proxy-объект из метода reactive()\n const [, forceUpdate] = this.reactAdapters.useState<unknown[]>([])\n\n if ('__subscribe' in item && typeof (item as Record<string, unknown>).__subscribe === 'function') {\n this.reactAdapters.useEffect(() => {\n const unsubscribe = ((item as Record<string, unknown>).__subscribe as (cb: () => void) => CleanupFn)(() => {\n forceUpdate([]) // Триггерим авто-батчинг ререндера React\n })\n return () => unsubscribe()\n }, [item])\n }\n\n return item as (T extends ISignalLike<infer V> ? V : T)\n }\n}\n\n/**\n * 🤖 2. АВТОМАТИЧЕСКИЙ РЕАКТИВНЫЙ АДАПТЕР ДЛЯ REACT (АСИНХРОННЫЙ ШЕДУЛЕР)\n * Наследует ReactiveEngineAutomatic и аппаратно склеивает цепочки мутаций в микрозадачи.\n */\nexport class ReactiveEngine4ReactAutomatic extends ReactiveEngineAutomaticHard {\n protected override frameworkPrefix = 'react-auto'\n\n private reactAdapters: {\n useState: typeof useStateFromReact;\n useEffect: typeof useEffectFromReact;\n } = {\n useState: useStateFromReact,\n useEffect: useEffectFromReact,\n }\n\n public setReactAdapters(\n useState: typeof useStateFromReact,\n useEffect: typeof useEffectFromReact\n ): void {\n this.reactAdapters = { useState, useEffect }\n }\n\n public override reactive<T extends object>(target: T, name?: string): T {\n if (!Reflect.has(target, '__subscribe')) {\n Object.defineProperty(target, '__subscribe', {\n get: () => {\n return (cb: () => void) => {\n return this.effect(() => {\n try {\n JSON.stringify(originalProxy)\n } catch (e) {\n Object.values(originalProxy as Record<string, unknown>)\n }\n cb()\n }, 'react-auto-proxy-internal-subscription')\n }\n },\n configurable: true,\n enumerable: false\n })\n }\n\n const originalProxy = super.reactive(target, name)\n return originalProxy\n }\n\n public use<T>(item: T): T extends ISignalLike<infer V> ? V : T {\n if (!this.reactAdapters || !this.reactAdapters.useState || !this.reactAdapters.useEffect) {\n throw new Error(\"[ReactiveEngine4ReactAutomatic] React adapters are not installed. Please call setReactAdapters(useState, useEffect) before using this hook.\")\n }\n\n if (item === null || item === undefined || typeof item !== 'object') {\n return item as any\n }\n\n const isSignal = 'subscribe' in item && typeof (item as Record<string, unknown>).subscribe === 'function'\n\n if (isSignal) {\n const signalItem = (item as unknown) as ISignalLike<unknown>\n const [val, setVal] = this.reactAdapters.useState<unknown>(signalItem.value)\n\n this.reactAdapters.useEffect(\n () => {\n return signalItem.subscribe(setVal)\n },\n [signalItem]\n )\n\n return val as (T extends ISignalLike<infer V> ? V : T)\n }\n\n const [, forceUpdate] = this.reactAdapters.useState<unknown[]>([])\n\n if ('__subscribe' in item && typeof (item as Record<string, unknown>).__subscribe === 'function') {\n this.reactAdapters.useEffect(() => {\n const unsubscribe = ((item as Record<string, unknown>).__subscribe as (cb: () => void) => CleanupFn)(() => {\n forceUpdate([])\n })\n return () => unsubscribe()\n }, [item])\n }\n\n return item as (T extends ISignalLike<infer V> ? V : T)\n }\n}\n"],"mappings":";;;AA0GA,IAAa,IAAb,cAAmD,EAA4B;CAC7E,kBAAqC;CAErC,gBAGI;EACU;EACC;CACb;CAEF,iBACE,GACA,GACM;EACN,KAAK,gBAAgB;GAAE;GAAU;EAAU;CAC7C;CAEA,SAA2C,GAAW,GAAkB;EACtE,AAAK,QAAQ,IAAI,GAAQ,aAAa,KACpC,OAAO,eAAe,GAAQ,eAAe;GAC3C,YACU,MACC,KAAK,aAAa;IACvB,IAAI;KACF,KAAK,UAAU,CAAa;IAC9B,QAAY;KACV,OAAO,OAAO,CAAwC;IACxD;IACA,EAAG;GACL,GAAG,wCAAwC;GAG/C,cAAc;GACd,YAAY;EACd,CAAC;EAGH,IAAM,IAAgB,MAAM,SAAS,GAAQ,CAAI;EACjD,OAAO;CACT;CAEA,IAAc,GAAiD;EAC7D,IAAI,CAAC,KAAK,iBAAiB,CAAC,KAAK,cAAc,YAAY,CAAC,KAAK,cAAc,WAC7E,MAAU,MAAM,6IAA6I;EAG/J,IAA2C,OAAO,KAAS,aAAvD,GACF,OAAO;EAKT,IAFiB,eAAe,KAAQ,OAAQ,EAAiC,aAAc,YAEjF;GACZ,IAAM,IAAc,GACd,CAAC,GAAK,KAAU,KAAK,cAAc,SAAkB,EAAW,KAAK;GAS3E,OAPA,KAAK,cAAc,gBAER,EAAW,UAAU,CAAM,GAEpC,CAAC,CAAU,CACb,GAEO;EACT;EAEA,IAAM,GAAG,KAAe,KAAK,cAAc,SAAoB,CAAC,CAAC;EAWjE,OATI,iBAAiB,KAAQ,OAAQ,EAAiC,eAAgB,cACpF,KAAK,cAAc,gBAAgB;GACjC,IAAM,IAAgB,EAAiC,kBAAoD;IACzG,EAAY,CAAC,CAAC;GAChB,CAAC;GACD,aAAa,EAAY;EAC3B,GAAG,CAAC,CAAI,CAAC,GAGJ;CACT;AACF"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"core.react.auto.test.d.ts","sourceRoot":"","sources":["../../src/react/core.react.auto.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FilteredCatalog.auto.test.d.ts","sourceRoot":"","sources":["../../../src/react/hooks/FilteredCatalog.auto.test.tsx"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useReactiveSubscription.auto.test.d.ts","sourceRoot":"","sources":["../../../../src/react/hooks/useReactiveSubscription/useReactiveSubscription.auto.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useReactiveValue.auto.test.d.ts","sourceRoot":"","sources":["../../../../src/react/hooks/useReactiveValue/useReactiveValue.auto.test.ts"],"names":[],"mappings":""}
|
package/dist/react/index.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./ReactiveEngine4React.cjs"),t=require("./hooks/useReactiveSubscription/useReactiveSubscription.cjs"),n=require("./hooks/useReactiveValue/useReactiveValue.cjs"),r=require("./hooks/useReactiveValue0/useReactiveValue0.cjs");require("./hooks/index.cjs"),exports.ReactiveEngine=e.
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./ReactiveEngine4React.cjs"),t=require("./hooks/useReactiveSubscription/useReactiveSubscription.cjs"),n=require("./hooks/useReactiveValue/useReactiveValue.cjs"),r=require("./hooks/useReactiveValue0/useReactiveValue0.cjs");require("./hooks/index.cjs"),exports.ReactiveEngine=e.ReactiveEngine4ReactAutomatic,exports.useReactiveSubscription=t.useReactiveSubscription,exports.useReactiveValue=n.useReactiveValue,exports.useReactiveValue0=r.useReactiveValue0;
|
package/dist/react/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export {
|
|
1
|
+
import { ReactiveEngine4ReactAutomatic } from './ReactiveEngine4React';
|
|
2
|
+
export { ReactiveEngine4ReactAutomatic as ReactiveEngine };
|
|
3
3
|
export * from './hooks';
|
|
4
4
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/react/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/react/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,6BAA6B,EAAE,MAAM,wBAAwB,CAAA;AAEtE,OAAO,EAAE,6BAA6B,IAAI,cAAc,EAAE,CAAA;AAC1D,cAAc,SAAS,CAAA"}
|