@pravosleva/reactive-engine 2.7.2 → 3.0.0-alpha.0
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/core/core.d.ts +89 -203
- package/dist/core/core.d.ts.map +1 -1
- package/dist/core/core.global.d.ts +64 -8
- package/dist/core/core.global.d.ts.map +1 -1
- package/dist/core/core.logger.d.ts +2 -0
- package/dist/core/core.logger.d.ts.map +1 -1
- package/dist/core/core.method.reactive.d.ts +2 -4
- package/dist/core/core.method.reactive.d.ts.map +1 -1
- package/dist/core/core.method.resource.d.ts +3 -11
- package/dist/core/core.method.resource.d.ts.map +1 -1
- package/dist/core/types.d.ts +1 -0
- package/dist/core/types.d.ts.map +1 -1
- package/dist/core.global.mjs +31 -4
- package/dist/core.global.mjs.map +1 -1
- package/dist/core.logger.mjs +49 -2
- package/dist/core.logger.mjs.map +1 -1
- package/dist/core.method.reactive.mjs +73 -30
- package/dist/core.method.reactive.mjs.map +1 -1
- package/dist/core.method.resource.mjs +122 -138
- package/dist/core.method.resource.mjs.map +1 -1
- package/dist/core.mjs +379 -150
- package/dist/core.mjs.map +1 -1
- package/dist/index.mjs +12 -12
- package/dist/index2.mjs +5 -5
- package/dist/react/hooks/useReactiveSubscription.mjs +13 -13
- package/dist/react/hooks/useReactiveSubscription.mjs.map +1 -1
- package/dist/react/hooks/useReactiveValue.d.ts +0 -4
- package/dist/react/hooks/useReactiveValue.d.ts.map +1 -1
- package/dist/react/hooks/useReactiveValue.mjs +24 -9
- package/dist/react/hooks/useReactiveValue.mjs.map +1 -1
- package/dist/reactive-engine.umd.js +2 -2
- package/dist/reactive-engine.umd.js.map +1 -1
- package/package.json +1 -1
- package/dist/core.method.computed.mjs +0 -167
- package/dist/core.method.computed.mjs.map +0 -1
- package/dist/core.method.effect.mjs +0 -120
- package/dist/core.method.effect.mjs.map +0 -1
- package/dist/core.method.signal.mjs +0 -106
- package/dist/core.method.signal.mjs.map +0 -1
- package/dist/core.method.untrack.mjs +0 -14
- package/dist/core.method.untrack.mjs.map +0 -1
- package/dist/utils/getExtractedValues.mjs +0 -24
- package/dist/utils/getExtractedValues.mjs.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 { getExtractedValues } from '../utils/getExtractedValues'\nimport { Signal, Computed, IEffect, EngineLoggerOptions, LogEventType, CleanupFn, TransactionContext, LogRecord, SignalOptions, ResourceOptions, ResourceState, Resource } from './types'\nimport { createComputed } from './core.method.computed'\nimport { createSignal } from './core.method.signal'\n// import { executeBatch } from './core.method.batch'\nimport { executeUntrack } from './core.method.untrack'\nimport { createReactive } from './core.method.reactive'\nimport { createEffect } from './core.method.effect'\nimport { ReactiveDebounceLogger } from './core.logger'\nimport { createResource } from './core.method.resource'\n\n// Тип для конструктора класса\ntype Constructor<T> = new (...args: any[]) => T\n// Тип для фабричной функции зависимостей\ntype Factory<T> = (engine: any) => T\n// Универсальный тип токена DI\ntype InjectionToken<T> = Constructor<T> | Factory<T> | symbol | string\n\nconst badgeColors: Record<LogEventType, 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}\nlet currentTransaction: TransactionContext | null = null\nfunction safeValueToString(value: unknown): string {\n if (value === null) return 'null'\n if (value === undefined) return 'undefined'\n if (typeof value === 'object') {\n try {\n return JSON.stringify(value)\n } catch (e) {\n return '[Cyclic Object or Layer]'\n }\n }\n return String(value)\n}\nexport function queueLog(type: LogEventType, label: string, details?: { from?: unknown; to?: unknown; payload?: unknown }): void {\n if (!currentTransaction) {\n currentTransaction = { id: Math.random().toString(36).substring(2, 9), pendingLogQueue: [], isFlushing: false }\n queueMicrotask(() => flushLogs())\n }\n currentTransaction.pendingLogQueue.push({ type, label, from: details?.from, to: details?.to, payload: details?.payload, timestamp: Date.now() })\n}\nexport function flushLogs(): void {\n if (!currentTransaction || currentTransaction.isFlushing) return\n currentTransaction.isFlushing = true\n const queue = currentTransaction.pendingLogQueue\n if (queue.length === 0) {\n currentTransaction = null\n return\n }\n console.groupCollapsed(`%cREACTIVE TRANSACTION%c [id: ${currentTransaction.id}] (${queue.length} operations)`, 'background: #7952b3; color: #fff; padding: 2px 6px; border-radius: 4px; font-weight: bold;', 'color: #888; font-weight: normal;')\n for (const record of queue) {\n const colorStyle = badgeColors[record.type]\n const hasTransition = record.from !== undefined || record.to !== undefined\n let logMessage = `%c${record.type.toUpperCase()}%c ${record.label}`\n\n if (hasTransition) {\n if (!!record.from)\n logMessage += ` ${safeValueToString(record.from)} → ${safeValueToString(record.to)}`\n else logMessage += ` (${safeValueToString(record.to)})`\n }\n\n if (record.payload !== undefined) {\n console.groupCollapsed(logMessage, colorStyle, 'color: inherit;')\n console.log('Payload:', record.payload)\n console.groupEnd()\n } else {\n console.log(logMessage, colorStyle, 'color: inherit;')\n }\n }\n console.groupEnd()\n currentTransaction = null\n}\nexport class ReactiveEngineCore {\n protected frameworkPrefix = 'core'\n public logger: EngineLoggerOptions\n public epoch = 0\n public activeConsumer: any = null\n public batchDepth = 0\n public subscriberId = 0\n public pendingEffects: Array<Set<any> | undefined> = []\n public maxPendingDepth = 0\n public computedCache = new WeakMap<Function, any>()\n private diRegistry = new Map<unknown, unknown>()\n private diCache = new Map<unknown, unknown>()\n private proxyCache = new WeakMap<object, any>()\n private proxyTargets = new WeakSet<object>()\n private reactiveSignals = new WeakMap<object, Map<string | symbol, any>>()\n private cycleDetectionStack = new Set<unknown>()\n public batchedSignals = new Set<any>()\n public activeOwner: any = null\n public activeCleanupNode: any = null\n // Системная очередь для отложенного батчинга деструкторов\n public pendingCleanups = new Set<() => void>()\n\n // Метод для регистрации отложенной очистки\n public queueCleanup(cleanup: () => void): void {\n this.pendingCleanups.add(cleanup)\n }\n\n constructor(options?: { logger?: EngineLoggerOptions }) {\n this.logger = options?.logger || { isEnabled: false }\n }\n\n public scheduleEffect(effect: any): void {\n const depth = effect.depth || 0\n if (!this.pendingEffects[depth]) {\n this.pendingEffects[depth] = new Set()\n }\n this.pendingEffects[depth]!.add(effect)\n if (depth > this.maxPendingDepth) {\n this.maxPendingDepth = depth\n }\n }\n\n public queueLog(type: LogEventType, label: string, details?: { from?: unknown; to?: unknown; payload?: unknown }): void {\n queueLog(type, label, details)\n }\n\n public batch<T>(fn: () => T): T {\n this.batchDepth++\n try {\n return fn()\n } finally {\n this.batchDepth--\n if (this.batchDepth === 0) {\n if (this.batchedSignals.size > 0) {\n for (const sig of this.batchedSignals) {\n if (sig._flushBatch) sig._flushBatch()\n }\n this.batchedSignals.clear()\n }\n\n this.flushEffects()\n }\n }\n }\n\n public flushEffects(): void {\n if (this.batchDepth > 0) return\n\n const prevConsumer = this.activeConsumer\n\n try {\n for (let depth = 0; depth <= this.maxPendingDepth; depth++) {\n const bucket = this.pendingEffects[depth]\n\n if (!bucket || bucket.size === 0) continue\n\n const effects = Array.from(bucket)\n bucket.clear()\n\n for (const effect of effects) {\n if (effect.isDisposed) continue\n\n // ⚡ ЗОЛОТОЙ СТАНДАРТ ОПТИМИЗАЦИИ (Early Dirty Check Bypass):\n // Переносим проверку грязи в самое начало цикла. Если эффект не был промаркирован\n // как DIRTY волной push-уведомлений, мы мгновенно пропускаем его, полностью\n // избавляя V8 от холостого обхода родителей и тяжелых хэш-поисков depVersions.get(dep).\n if (!effect.isDirty) continue\n\n if (effect.dependencies && effect.dependencies.size > 0) {\n let parentChanged = false\n\n for (const dep of effect.dependencies) {\n const rawNode = dep._node || dep\n\n if (rawNode.type === 'computed' && rawNode.state > 0) {\n if (rawNode.update) rawNode.update()\n }\n\n if (effect.depVersions && effect.depVersions.get(dep) !== rawNode.version) {\n parentChanged = true\n }\n }\n\n if (!parentChanged && effect.dependencies.size > 0) {\n effect.isDirty = false\n continue\n }\n }\n\n try {\n // Вызов метода .run() теперь прозрачно прокидывает наверх ошибки\n // как из пользовательского тела эффекта, так и из обновленной фазы cleanup\n effect.run()\n } catch (err) {\n // ⚡ ФИКС ТЕСТОВ ОШИБОК (#177 и #247): Если один из эффектов (или его очистка)\n // выбросил исключение, принудительно гасим флаги грязи (isDirty) у всех оставшихся\n // в очереди эффектов текущего и последующих уровней глубины.\n // Старые грязные задачи гарантированно изолируются и не протекают в новые микротаски.\n for (let d = depth; d <= this.maxPendingDepth; d++) {\n const remainingBucket = this.pendingEffects[d]\n if (remainingBucket) {\n for (const remEffect of remainingBucket) {\n remEffect.isDirty = false\n }\n remainingBucket.clear()\n }\n }\n this.maxPendingDepth = 0\n\n // Бескомпромиссный проброс ошибки наверх по спецификации тест-суита\n throw err\n }\n }\n\n if (depth > 0) {\n let hasEarlierEffects = false\n for (let i = 0; i < depth; i++) {\n if (this.pendingEffects[i] && this.pendingEffects[i]!.size > 0) {\n hasEarlierEffects = true\n break\n }\n }\n if (hasEarlierEffects) depth = -1\n }\n }\n this.maxPendingDepth = 0\n } finally {\n this.activeConsumer = prevConsumer\n }\n }\n\n // public batch<T>(fn: () => T): T {\n // return executeBatch<T>(this, fn)\n // }\n\n // ⚛️ ФИКС ДЛЯ РЕЛИЗА 2.5.0: Меняем private на public,\n // чтобы изолированные функции-методы имели легальный доступ к регистратору логов\n public log(params: any) {\n if (!this.logger || !this.logger.isEnabled) return\n ReactiveDebounceLogger.processLog(this.logger, queueLog, params)\n }\n\n /**\n * Создает новый реактивный сигнал с заданным начальным значением и опциями.\n *\n * @template T Тип значения сигнала.\n * @param initialValue Начальное значение сигнала.\n * @param optionsOrName Конфигурационные параметры сигнала или его имя.\n * @param optionsOrName.name Уникальное текстовое имя сигнала для отладки и вывода в транзакционный логгер.\n * @param optionsOrName.validate Пользовательская функция валидации значения, возвращающая true/false или строку ошибки.\n *\n * @method signal\n * @memberof ReactiveEngine\n *\n * @example\n * // Пример 1: Чистый TypeScript (Базовый)\n * const engine = new ReactiveEngineCore();\n * const counter = engine.signal(0, { name: 'counter' });\n * console.log(counter.value); // 0\n * counter.value = 1;\n * console.log(counter.value); // 1\n *\n * @example\n * // Пример 2: Чистый TypeScript (Продвинутый с валидацией)\n * interface User { id: number; name: string; }\n * const engine = new ReactiveEngineCore();\n * const userSignal = engine.signal<User>({ id: 1, name: 'John Doe' }, {\n * name: 'user',\n * validate: (user) => user.id > 0 && typeof user.name === 'string'\n * });\n * userSignal.value = { id: -1, name: 'Jane Doe' }; // Ошибка валидации\n *\n * @example\n * // Пример 3: Интеграция с React (через DI контейнер)\n * interface User { id: number; name: string; }\n * class UserService {\n * constructor(engine: ReactiveEngineCore) {\n * this.mySignal = engine.signal<User>({ id: 1, name: 'John Doe' }, { name: 'userSignal' });\n * }\n *\n * mySignal: Signal<User>;\n * }\n *\n * const engine = new ReactiveEngineCore();\n * engine.provide(UserService, UserService);\n * const logic = engine.inject(UserService);\n *\n * function MyComponent() {\n * const user = useReactiveValue(logic.mySignal);\n * return <div>{user.name}</div>;\n * }\n */\n public signal<T>(initialValue: T, optionsOrName?: string | SignalOptions<T>): Signal<T> {\n return createSignal<T>(this, initialValue, optionsOrName)\n }\n\n /**\n * Создает новое вычисляемое свойство (Computed) на основе чистой функции.\n *\n * @template T Тип значения, возвращаемого вычисляемым свойством.\n * @param fn Чистая функция-вычислитель, которая определяет логику вычисления значения.\n * @param signalName Опциональное имя сигнала для отладки и вывода в транзакционный логгер.\n *\n * @method computed\n * @memberof ReactiveEngine\n *\n * @example\n * // Пример 1: Чистый TypeScript (Базовый)\n * const engine = new ReactiveEngineCore();\n * const counter = engine.signal(0, { name: 'counter' });\n * const doubleCounter = engine.computed(() => counter.value * 2);\n * console.log(doubleCounter.value); // 0\n * counter.value = 1;\n * console.log(doubleCounter.value); // 2\n *\n * @example\n * // Пример 2: Чистый TypeScript (Продвинутый с цепочкой зависимостей)\n * interface User { id: number; name: string; }\n * const engine = new ReactiveEngineCore();\n * const userSignal = engine.signal<User>({ id: 1, name: 'John Doe' }, { name: 'user' });\n * const userNameLength = engine.computed(() => userSignal.value.name.length);\n * const hasLongName = engine.computed(() => userNameLength.value > 5);\n *\n * console.log(hasLongName.value); // false\n * userSignal.value = { id: 1, name: 'Johnathan' };\n * console.log(userNameLength.value); // 9\n * console.log(hasLongName.value); // true\n *\n * @example\n * // Пример 3: Интеграция с React (через DI контейнер)\n * interface User { id: number; name: string; }\n * class UserService {\n * constructor(engine: ReactiveEngineCore) {\n * this.userSignal = engine.signal<User>({ id: 1, name: 'John Doe' }, { name: 'userSignal' });\n * this.userNameLength = engine.computed(() => this.userSignal.value.name.length);\n * }\n *\n * userSignal: Signal<User>;\n * userNameLength: Computed<number>;\n * }\n *\n * const engine = new ReactiveEngineCore();\n * engine.provide(UserService, UserService);\n * const logic = engine.inject(UserService);\n *\n * function MyComponent() {\n * const hasLongName = engine.use(logic.userNameLength);\n * return <div>{hasLongName ? 'Long name' : 'Short name'}</div>;\n * }\n */\n public computed<T>(fn: () => T, signalName?: string): Computed<T> {\n // Просто делегируем вызов строго изолированной чистой функции\n return createComputed<T>(this, fn, signalName)\n }\n\n public effect(fn: () => void | CleanupFn, effectName?: string): () => void {\n return createEffect(this, fn, effectName)\n }\n\n public untrack<T>(fn: () => T): T {\n return executeUntrack<T>(this, fn)\n }\n\n public reactive<T extends object>(target: T, name?: string): T {\n return createReactive<T>(this, target, name)\n }\n\n public provide<T>(token: InjectionToken<T>, valueOrFactory: T | Factory<T>): void {\n this.diRegistry.set(token, valueOrFactory)\n this.diCache.delete(token)\n }\n\n public inject<T>(token: InjectionToken<T>): T {\n if (token === undefined || token === null) throw new Error('[DI Error] Token is empty')\n if (this.diCache.has(token)) return this.diCache.get(token) as T\n if (this.cycleDetectionStack.has(token)) throw new Error('[DI Error] Cyclic dependency detected')\n this.cycleDetectionStack.add(token)\n try {\n if (this.diRegistry.has(token)) {\n const entry = this.diRegistry.get(token)\n if (typeof entry === 'function') {\n if ((entry as any)._isMockFunction) {\n const mockRes = (entry as Function)(this)\n if (mockRes !== undefined) {\n this.diCache.set(token, mockRes)\n return mockRes as T\n }\n return entry as unknown as T\n }\n const str = entry.toString()\n const isClass = str.startsWith('class ') || str.startsWith('class{') || (entry.prototype && entry.prototype.constructor === entry && !str.startsWith('function') && !str.includes('=>'))\n if (!isClass) {\n const resolved = (entry as Factory<T>)(this)\n this.diCache.set(token, resolved)\n return resolved\n }\n return entry as unknown as T\n }\n return entry as T\n }\n if (typeof token === 'function') {\n const resolved = new (token as Constructor<T>)(this)\n this.diCache.set(token, resolved)\n return resolved\n }\n throw new Error('[DI Error] Token not found')\n } finally {\n this.cycleDetectionStack.delete(token)\n }\n }\n\n public 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)\n reject(new DOMException('Aborted', 'AbortError'))\n }\n\n signal.addEventListener('abort', onAbort, { once: true })\n })\n }\n\n /**\n * Создает умную реактивную декларативную обертку над асинхронными операциями\n * с автоматическим подавлением Race Conditions и встроенным методом .destroy().\n *\n * @template T Тип данных, возвращаемых фетчером после успешного выполнения.\n * @template S Тип реактивной зависимости (source).\n * @param fetcher Асинхронная функция, выполняющая запрос и возвращающая данные типа T.\n * @param source Реактивный сигнал или примитив, предоставляющий источник данных для фетчера.\n * @param optionsOrName Конфигурационные опции ресурса или его имя.\n * @param optionsOrName.name Имя ресурса.\n * @param optionsOrName.resetDataOnSourceChange Флаг, указывающий, следует ли сбрасывать данные при изменении источника.\n * @param optionsOrName.validateBeforeFetch Функция валидации источника перед выполнением фетча.\n * @param optionsOrName.responseValidate Функция валидации ответа после выполнения фетча.\n * @param optionsOrName.timeout Максимальное время ожидания запроса в миллисекундах.\n * @param optionsOrName.retryCount Количество попыток повторного выполнения запроса в случае ошибки.\n *\n * @example\n * // Пример 1: Чистый TypeScript (Базовый)\n * interface User { id: number; name: string; }\n * interface ApiResponse<T> { ok: boolean; message?: string; data: T; }\n * const engine = new ReactiveEngineCore();\n * const userSignal = engine.signal<User>({ id: 1, name: 'John Doe' });\n * const fetchUser = async (source: User, signal: AbortSignal): Promise<ApiResponse<User>> => {\n * // Реализация фетча пользователя\n * };\n * const userResource = engine.resource(fetchUser, { value: userSignal.value }, { name: 'userResource' });\n *\n * @example\n * // Пример 2: Чистый TypeScript (Продвинутый)\n * interface User { id: number; name: string; }\n * interface ApiResponse<T> { ok: boolean; message?: string; data: T; }\n * const engine = new ReactiveEngineCore();\n * const userSignal = engine.signal<User>({ id: 1, name: 'John Doe' });\n * const fetchUser = async (source: User, signal: AbortSignal): Promise<ApiResponse<User>> => {\n * // Реализация фетча пользователя с использованием AbortSignal и timeout\n * };\n * const userResource = engine.resource(fetchUser, { value: userSignal.value }, {\n * name: 'userResource',\n * timeout: 5000,\n * retryCount: 3,\n * });\n *\n * @example\n * // Пример 3: Интеграция с React (через DI контейнер)\n * interface User { id: number; name: string; }\n * interface ApiResponse<T> { ok: boolean; message?: string; data: T; }\n * class UserService {\n * constructor(engine: ReactiveEngineCore) {\n * const userSignal = engine.signal<User>({ id: 1, name: 'John Doe' });\n * this.myResource = engine.resource(fetchUser, { value: userSignal.value }, { name: 'userResource' });\n * }\n *\n * myResource: Resource<ApiResponse<User>>;\n * }\n *\n * const engine = new ReactiveEngineCore();\n * engine.provide(UserService, UserService);\n * const logic = engine.inject(UserService);\n * const state = useReactiveValue(logic.myResource);\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 // Передаем инстанс движка (this) как IReactiveEngine для соблюдения строгой типизации\n return createResource<T, S>(this, fetcher, source, optionsOrName)\n }\n}\n\nexport { ReactiveEngineCore as ReactiveEngine, ReactiveEngineCore as ReactiveEngineAutomatic }\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"core.mjs","names":[],"sources":["../src/core/core.ts"],"sourcesContent":["import type {\n CleanupFn,\n EffectFn,\n Signal,\n Computed,\n IEffect,\n SignalOptions,\n EngineLoggerOptions,\n LogEventType,\n Token,\n Factory,\n Resource,\n ResourceOptions\n} from './types'\nimport { ReactiveDebounceLogger, queueLog } from './core.logger'\nimport { createReactive } from './core.method.reactive'\nimport { createResource } from './core.method.resource'\n\nexport type NodeState = 0 | 1 | 2\n\nexport class NodeLink {\n public source: ReactiveNode | null = null\n public target: ReactiveNode | null = null\n public nextSubscriber: NodeLink | null = null\n public prevSubscriber: NodeLink | null = null\n public nextDependency: NodeLink | null = null\n public prevDependency: NodeLink | null = null\n public version: number = 0\n\n public clear(): void {\n this.source = null\n this.target = null\n this.nextSubscriber = null\n this.prevSubscriber = null\n this.nextDependency = null\n this.prevDependency = null\n this.version = 0\n }\n}\n\nexport class LinkPool {\n private static pool: NodeLink[] = []\n private static size = 0\n private static maxPoolSize = 100000\n\n public static acquire(source: ReactiveNode, target: ReactiveNode): NodeLink {\n if (this.size > 0) {\n this.size--\n const link = this.pool[this.size]\n this.pool[this.size] = null as unknown as NodeLink\n link.source = source\n link.target = target\n return link\n }\n const link = new NodeLink()\n link.source = source\n link.target = target\n return link\n }\n\n public static release(link: NodeLink): void {\n if (this.size < this.maxPoolSize) {\n link.clear()\n this.pool[this.size] = link\n this.size++\n }\n }\n}\n\nexport class ReactiveNode {\n public id: string\n public type: 'signal' | 'computed' | 'effect'\n public version: number = 0\n public state: NodeState = 0\n public depth: number = 0\n public subscribersHead: NodeLink | null = null\n public subscribersTail: NodeLink | null = null\n public dependenciesHead: NodeLink | null = null\n public dependenciesTail: NodeLink | null = null\n public _value: any\n public _prevValue: any\n public fn: (() => any) | null = null\n public cleanups = new Set<CleanupFn>()\n public isDisposed: boolean = false\n public ownedEffects = new Set<ReactiveNode>()\n public wrapper: any = null\n public engine: ReactiveEngineCore | null = null\n\n constructor(type: 'signal' | 'computed' | 'effect', id: string, initialValue?: any) {\n this.type = type\n this.id = id\n this._value = initialValue\n this._prevValue = initialValue\n }\n\n public get subscribers(): Set<ReactiveNode> {\n const set = new Set<ReactiveNode>()\n let link = this.subscribersHead\n while (link !== null) {\n if (link.target) set.add(link.target)\n link = link.nextSubscriber\n }\n return set\n }\n\n public get dependencies(): Set<ReactiveNode> {\n const set = new Set<ReactiveNode>()\n let link = this.dependenciesHead\n while (link !== null) {\n if (link.source) set.add(link.source)\n link = link.nextDependency\n }\n return set\n }\n}\n\nexport class EffectScheduler {\n private buckets: ReactiveNode[][] = []\n private maxDepth = -1\n\n public schedule(node: ReactiveNode): void {\n const d = node.depth\n if (!this.buckets[d]) {\n this.buckets[d] = []\n }\n if (!this.buckets[d].includes(node)) {\n this.buckets[d].push(node)\n if (d > this.maxDepth) this.maxDepth = d\n }\n }\n\n public clearAll(): void {\n for (let d = 0; d <= this.maxDepth; d++) {\n const bucket = this.buckets[d]\n if (bucket) {\n for (const node of bucket) {\n node.state = 0\n }\n this.buckets[d] = []\n }\n }\n this.maxDepth = -1\n }\n\n public flush(engine: ReactiveEngineCore): void {\n const prevConsumer = engine.activeConsumer\n try {\n let d = 0\n while (d <= this.maxDepth) {\n const bucket = this.buckets[d]\n if (!bucket || bucket.length === 0) {\n d++\n continue\n }\n\n this.buckets[d] = []\n bucket.sort((a, b) => b.depth - a.depth)\n\n for (const node of bucket) {\n if (node.isDisposed || node.state === 0) continue\n\n if (node.state === 1) {\n if (engine.checkNeedsUpdate(node)) {\n node.state = 2\n } else {\n node.state = 0\n }\n }\n\n if (node.state === 2) {\n try {\n engine.runEffectNode(node)\n } catch (err) {\n // Изоляция очереди при падении эффекта (#177, #247)\n this.clearAll()\n throw err\n }\n }\n }\n\n let hasTasks = false\n for (let i = 0; i <= this.maxDepth; i++) {\n if (this.buckets[i] && this.buckets[i].length > 0) {\n d = i\n hasTasks = true\n break\n }\n }\n if (!hasTasks) d++\n }\n } finally {\n engine.activeConsumer = prevConsumer\n this.maxDepth = -1\n }\n }\n}\n\nexport class ReactiveEngineCore {\n public activeConsumer: ReactiveNode | null = null\n public batchDepth = 0\n public batchedSignals: ReactiveNode[] = []\n public batchInitialValues = new Map<ReactiveNode, { value: any; version: number }>()\n public computedCache = new WeakMap<Function, any>()\n public logger: EngineLoggerOptions\n\n public proxyCache = new WeakMap<object, any>()\n public proxyTargets = new WeakSet<object>()\n public reactiveSignals = new WeakMap<object, Map<string | symbol, any>>()\n\n private scheduler = new EffectScheduler()\n private currentOwner: ReactiveNode | null = null\n private effectIdCounter = 0\n\n private diRegistry = new Map<unknown, unknown>()\n private diCache = new Map<unknown, unknown>()\n private cycleDetectionStack = new Set<unknown>()\n\n // public isCleaningUp = false\n\n constructor(options?: { logger?: EngineLoggerOptions }) {\n this.logger = options?.logger || { isEnabled: false }\n }\n\n public log(params: { type: LogEventType; label: string; details?: { from?: unknown; to?: unknown; payload?: unknown }; isInternalCoreSignal?: boolean }): void {\n if (!this.logger || !this.logger.isEnabled) return\n ReactiveDebounceLogger.processLog(this.logger, queueLog, params)\n }\n\n public signal<T>(initialValue: T, optionsOrName?: string | SignalOptions<T>): Signal<T> {\n const name = typeof optionsOrName === 'string' ? optionsOrName : (optionsOrName?.name || 'signal')\n const validate = typeof optionsOrName === 'object' ? optionsOrName?.validate : undefined\n const isInternal = typeof optionsOrName === 'object' ? optionsOrName?.isInternalCoreSignal : false\n const node = new ReactiveNode('signal', name, initialValue)\n node.engine = this\n const self = this\n\n // Логируем стартовую инициализацию сигнала (from: undefined -> формат \"SIGNAL label (initialValue)\")\n this.log({ type: 'signal', label: name, details: { to: initialValue }, isInternalCoreSignal: isInternal })\n\n const publicSignal: Signal<T> & { _node: ReactiveNode; _engine: ReactiveEngineCore } = {\n _node: node,\n _engine: this,\n get value(): T {\n // if (self.isCleaningUp && self.activeConsumer === null) {\n // return node._prevValue\n // }\n if (self.activeConsumer) {\n self.trackNode(node, self.activeConsumer)\n }\n return node._value\n },\n set value(newValue: T) {\n if (validate) {\n const validationResult = validate(newValue)\n if (validationResult === false || typeof validationResult === 'string') {\n console.error(`[Validation Error] Invalid value supplied to signal \"${name}\": ${validationResult}`)\n return\n }\n }\n const isObj = newValue !== null && typeof newValue === 'object'\n if (Object.is(node._value, newValue) && !isObj) return\n\n const oldVal = node._value\n node._prevValue = oldVal\n\n if (self.batchDepth > 0 && !self.batchInitialValues.has(node)) {\n self.batchInitialValues.set(node, { value: oldVal, version: node.version })\n }\n\n node._value = newValue\n node.version++\n\n self.log({ type: 'signal', label: name, details: { from: oldVal, to: newValue }, isInternalCoreSignal: isInternal })\n self.notifySubscribers(node, 2)\n\n if (self.batchDepth > 0) {\n if (!self.batchedSignals.includes(node)) {\n self.batchedSignals.push(node)\n }\n } else {\n self.flushEffects()\n }\n },\n get valueWithoutTracking(): T {\n return node._value\n },\n subscribe(cb: (v: T) => void): CleanupFn {\n return self.effect(() => {\n cb(publicSignal.value)\n })\n },\n destroy(): void {\n self.disposeNode(node)\n }\n }\n\n node.wrapper = publicSignal\n return publicSignal\n }\n\n public notifySubscribers(node: ReactiveNode, state: NodeState): void {\n let link = node.subscribersHead\n while (link !== null) {\n const target = link.target!\n if (target === this.activeConsumer) {\n link = link.nextSubscriber\n continue\n }\n\n if (target.state < state) {\n target.state = state\n if (target.type === 'effect') {\n this.scheduler.schedule(target)\n } else {\n this.notifySubscribers(target, 1)\n }\n }\n link = link.nextSubscriber\n }\n }\n\n public computed<T>(fn: () => T, signalName?: string): Computed<T> {\n const name = signalName || 'computed'\n const node = new ReactiveNode('computed', name)\n node.engine = this\n node.fn = fn\n node.state = 2\n const self = this\n\n const publicComputed: Computed<T> & { _node: ReactiveNode; _engine: ReactiveEngineCore } = {\n _node: node,\n _engine: this,\n get value(): T {\n if (node.state === 1) {\n if (self.checkNeedsUpdate(node)) {\n node.state = 2\n } else {\n node.state = 0\n }\n }\n if (node.state === 2) {\n const oldVal = node._value\n self.evaluateComputed(node)\n // self.log({ type: 'computed', label: name, details: { from: oldVal, to: node._value } })\n }\n if (self.activeConsumer) {\n self.trackNode(node, self.activeConsumer)\n }\n return node._value\n },\n get valueWithoutTracking(): T {\n return node._value\n },\n subscribe(cb: (v: T) => void): CleanupFn {\n return self.effect(() => {\n cb(publicComputed.value)\n })\n },\n destroy(): void {\n self.disposeNode(node)\n },\n _isDirty(): boolean {\n return node.state === 2\n },\n get dependencies(): Set<any> {\n const depsSet = new Set()\n let link = node.dependenciesHead\n while (link !== null) {\n if (link.source && link.source.wrapper) {\n depsSet.add(link.source.wrapper)\n }\n link = link.nextDependency\n }\n return depsSet\n }\n }\n node.wrapper = publicComputed\n if (this.batchDepth === 0) {\n this.computedCache.set(fn, publicComputed)\n }\n return publicComputed\n }\n public effect(fn: EffectFn, effectName?: string): () => void {\n const name = effectName || 'effect'\n const node = new ReactiveNode('effect', name)\n node.state = 2\n node.depth = this.currentOwner ? this.currentOwner.depth + 1 : 0\n const publicEffect: IEffect = {\n id: ++this.effectIdCounter,\n run: () => {\n this.runEffectNode(node)\n },\n markDirty: () => {\n node.state = 2\n this.scheduler.schedule(node)\n },\n cleanups: node.cleanups,\n label: name,\n get isDirty(): boolean { return node.state === 2 },\n get isDisposed(): boolean { return node.isDisposed },\n _node: node\n }\n node.wrapper = publicEffect\n node.fn = () => {\n this.log({ type: 'effect', label: name })\n const res = fn()\n if (typeof res === 'function') {\n node.cleanups.add(res)\n }\n }\n if (this.currentOwner) {\n this.currentOwner.ownedEffects.add(node)\n }\n this.runEffectNode(node)\n const disposeFn = () => {\n this.disposeNode(node)\n }\n;(disposeFn as any)._node = node\n return disposeFn\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 return createResource<T, S>(this, fetcher, source, optionsOrName)\n }\n public batch<T>(fn: () => T): T {\n this.batchDepth++\n try {\n return fn()\n } finally {\n this.batchDepth--\n if (this.batchDepth === 0) {\n // Проверка Net-Zero откатов (#147)\n for (const sig of this.batchedSignals) {\n const initial = this.batchInitialValues.get(sig)\n const isObj = sig._value !== null && typeof sig._value === 'object'\n if (initial && !isObj && Object.is(sig._value, initial.value)) {\n sig.version = initial.version\n this.resetCleanState(sig)\n }\n }\n this.batchedSignals = []\n this.batchInitialValues.clear()\n this.flushEffects()\n }\n }\n }\n private resetCleanState(node: ReactiveNode): void {\n let link = node.subscribersHead\n while (link !== null) {\n const target = link.target!\n if (target.state > 0 && !this.checkNeedsUpdate(target)) {\n target.state = 0\n this.resetCleanState(target)\n }\n link = link.nextSubscriber\n }\n }\n public untrack<T>(fn: () => T): T {\n const prevConsumer = this.activeConsumer\n this.activeConsumer = null\n try {\n return fn()\n } finally {\n this.activeConsumer = prevConsumer\n }\n }\n public flushEffects(): void {\n if (this.batchDepth === 0) {\n this.scheduler.flush(this)\n }\n }\n public trackNode(source: ReactiveNode, target: ReactiveNode): void {\n let link = target.dependenciesHead\n while (link !== null) {\n if (link.source === source) {\n link.version = source.version\n return\n }\n link = link.nextDependency\n }\n const newLink = LinkPool.acquire(source, target)\n newLink.version = source.version\n if (target.depth <= source.depth) {\n target.depth = source.depth + 1\n }\n\n if (source.subscribersTail !== null) {\n source.subscribersTail.nextSubscriber = newLink\n newLink.prevSubscriber = source.subscribersTail\n source.subscribersTail = newLink\n } else {\n source.subscribersHead = newLink\n source.subscribersTail = newLink\n }\n\n if (target.dependenciesTail !== null) {\n target.dependenciesTail.nextDependency = newLink\n newLink.prevDependency = target.dependenciesTail\n target.dependenciesTail = newLink\n } else {\n target.dependenciesHead = newLink\n target.dependenciesTail = newLink\n }\n }\n public unlinkDependencies(target: ReactiveNode, cascadeOrphans = false): void {\n let link = target.dependenciesHead\n target.dependenciesHead = null\n target.dependenciesTail = null\n while (link !== null) {\n const next = link.nextDependency\n const source = link.source!\n if (link.prevSubscriber !== null) {\n link.prevSubscriber.nextSubscriber = link.nextSubscriber\n } else {\n source.subscribersHead = link.nextSubscriber\n }\n if (link.nextSubscriber !== null) {\n link.nextSubscriber.prevSubscriber = link.prevSubscriber\n } else {\n source.subscribersTail = link.prevSubscriber\n }\n LinkPool.release(link)\n\n // Не уничтожаем computed при отписке слушателей (иначе React StrictMode убивает computed при ремаунте),\n // каскадно удаляем только если сам узел явным образом уничтожен через .destroy()\n if (cascadeOrphans && target.isDisposed && target.type === 'computed' && source.type === 'computed' && source.subscribersHead === null) {\n this.disposeNode(source)\n }\n link = next\n }\n }\n public checkNeedsUpdate(node: ReactiveNode): boolean {\n let link = node.dependenciesHead\n while (link !== null) {\n const source = link.source!\n if (source.state === 1) {\n if (this.checkNeedsUpdate(source)) {\n source.state = 2\n } else {\n source.state = 0\n }\n }\n if (source.state === 2) {\n this.evaluateComputed(source)\n }\n if (link.version !== source.version) {\n link.version = source.version\n return true\n }\n link = link.nextDependency\n }\n return false\n }\n public evaluateComputed(node: ReactiveNode): void {\n if (node.ownedEffects.size > 0) {\n const children = Array.from(node.ownedEffects)\n node.ownedEffects.clear()\n for (const eff of children) {\n this.disposeNode(eff)\n }\n }\n\n this.unlinkDependencies(node, false)\n const prevConsumer = this.activeConsumer\n const prevOwner = this.currentOwner\n this.activeConsumer = node\n this.currentOwner = node\n const oldVal = node._value\n try {\n const newValue = node.fn!()\n if (!Object.is(node._value, newValue)) {\n node._value = newValue\n node.version++\n }\n node.state = 0\n this.log({ type: 'computed', label: node.id, details: { from: oldVal, to: node._value } })\n } finally {\n this.activeConsumer = prevConsumer\n this.currentOwner = prevOwner\n }\n }\n private executeCleanups(node: ReactiveNode): void {\n if (node.cleanups.size === 0) return\n const cleanupsList = Array.from(node.cleanups)\n node.cleanups.clear()\n let firstError: unknown = null\n // const prevCleaning = this.isCleaningUp\n // this.isCleaningUp = true\n\n for (const cleanup of cleanupsList) {\n try {\n this.untrack(() => cleanup())\n } catch (err) {\n if (firstError === null) {\n firstError = err\n }\n }\n }\n\n // finally {\n // this.isCleaningUp = prevCleaning\n // }\n if (firstError !== null) {\n throw firstError\n }\n }\n public runEffectNode(node: ReactiveNode): void {\n if (node.isDisposed) return\n\n if (node.ownedEffects.size > 0) {\n const children = Array.from(node.ownedEffects)\n node.ownedEffects.clear()\n for (const eff of children) {\n this.disposeNode(eff)\n }\n }\n\n try {\n this.executeCleanups(node)\n } catch (e) {\n node.state = 0\n throw e\n }\n\n // Не прерываем текущий перезапуск (#111), даже если cleanup вызвал dispose() для будущих циклов;\n // дальнейшая подписка не создастся, так как после fn() мы зачистим зависимости, если isDisposed === true\n this.unlinkDependencies(node, false)\n const prevConsumer = this.activeConsumer\n const prevOwner = this.currentOwner\n this.activeConsumer = node\n this.currentOwner = node\n try {\n node.fn!()\n node.state = 0\n } finally {\n this.activeConsumer = prevConsumer\n this.currentOwner = prevOwner\n if (node.isDisposed) {\n this.unlinkDependencies(node, true)\n }\n }\n }\n public disposeNode(node: ReactiveNode): void {\n if (node.isDisposed) return\n node.isDisposed = true\n node.state = 0\n\n if (node.ownedEffects.size > 0) {\n const children = Array.from(node.ownedEffects)\n node.ownedEffects.clear()\n for (const eff of children) {\n this.disposeNode(eff)\n }\n }\n\n try {\n this.executeCleanups(node)\n } catch (e) {}\n\n this.unlinkDependencies(node, true)\n\n let link = node.subscribersHead\n node.subscribersHead = null\n node.subscribersTail = null\n while (link !== null) {\n const next = link.nextSubscriber\n const target = link.target\n if (target) {\n if (link.prevDependency !== null) {\n link.prevDependency.nextDependency = link.nextDependency\n } else {\n target.dependenciesHead = link.nextDependency\n }\n if (link.nextDependency !== null) {\n link.nextDependency.prevDependency = link.prevDependency\n } else {\n target.dependenciesTail = link.prevDependency\n }\n }\n LinkPool.release(link)\n link = next\n }\n }\n public reactive<T extends object>(target: T, name?: string): T {\n return createReactive<T>(this, target, name)\n }\n public 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 const timeoutId = setTimeout(() => {\n signal.removeEventListener('abort', onAbort)\n resolve()\n }, ms)\n const onAbort = () => {\n clearTimeout(timeoutId)\n reject(new DOMException('Aborted', 'AbortError'))\n }\n signal.addEventListener('abort', onAbort, { once: true })\n })\n }\n public provide<T>(token: Token<T>, valueOrFactory: T | Factory<T>): void {\n this.diRegistry.set(token, valueOrFactory)\n this.diCache.delete(token)\n }\n public inject<T>(token: Token<T>): T {\n if (token === undefined || token === null) {\n throw new Error('[DI Error] Token is empty')\n }\n if (this.diCache.has(token)) {\n return this.diCache.get(token) as T\n }\n if (this.cycleDetectionStack.has(token)) {\n throw new Error('[DI Error] Cyclic dependency detected')\n }\n this.cycleDetectionStack.add(token)\n try {\n if (this.diRegistry.has(token)) {\n const entry = this.diRegistry.get(token)\n if (typeof entry === 'function') {\n if ((entry as any)._isMockFunction) {\n const mockRes = (entry as Function)(this)\n if (mockRes !== undefined) {\n this.diCache.set(token, mockRes)\n return mockRes as T\n }\n return entry as unknown as T\n }\n const str = entry.toString()\n const isClass = str.startsWith('class ') ||\nstr.startsWith('class{') ||\n(entry.prototype && entry.prototype.constructor === entry && !str.startsWith('function') && !str.includes('=>'))\n if (!isClass) {\n const resolved = (entry as Factory<T>)(this)\n this.diCache.set(token, resolved)\n return resolved\n }\n return entry as unknown as T\n }\n return entry as T\n }\n if (typeof token === 'function') {\n const resolved = new (token as any)(this)\n this.diCache.set(token, resolved)\n return resolved\n }\n throw new Error('[DI Error] Token not found')\n } finally {\n this.cycleDetectionStack.delete(token)\n }\n }\n}\nexport let currentEngineInstance = new ReactiveEngineCore()\nexport function resetGlobalReactiveEngine(): void {\n currentEngineInstance = new ReactiveEngineCore()\n}\n\nexport { ReactiveEngineCore as ReactiveEngine, ReactiveEngineCore as ReactiveEngineAutomatic }\n"],"mappings":"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"}
|
package/dist/index.mjs
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import { ReactiveEngine as e } from "./core.mjs";
|
|
2
2
|
import { ReactiveEngineAutomatic as t } from "./core.automatic.mjs";
|
|
3
3
|
import { ReactiveEngineAutolog as n } from "./core.autolog.mjs";
|
|
4
|
-
import { batch as r, computed as i, effect as a,
|
|
5
|
-
import { AbstractService as
|
|
6
|
-
import { BaseREServiceEnhanced as
|
|
7
|
-
import { withCache as
|
|
8
|
-
import { withDebounce as
|
|
9
|
-
import { withLongPolling as
|
|
10
|
-
import { withThrottle as
|
|
11
|
-
import { withThrottleComputed as
|
|
12
|
-
import { withThrottleAndCache as
|
|
13
|
-
import { withStaleWhileRevalidate as
|
|
14
|
-
import { withValidationAsync as
|
|
15
|
-
export {
|
|
4
|
+
import { batch as r, computed as i, effect as a, inject as o, provide as s, resetGlobalReactiveEngine as c, signal as l, untrack as u } from "./core.global.mjs";
|
|
5
|
+
import { AbstractService as d, BaseREService as f } from "./AbstractService.mjs";
|
|
6
|
+
import { BaseREServiceEnhanced as p } from "./BaseREServiceEnhanced.mjs";
|
|
7
|
+
import { withCache as m } from "./decorators/withCache/withCache.mjs";
|
|
8
|
+
import { withDebounce as h } from "./decorators/withDebounce/withDebounce.mjs";
|
|
9
|
+
import { withLongPolling as g } from "./decorators/withLongPolling/withLongPolling.mjs";
|
|
10
|
+
import { withThrottle as _ } from "./decorators/withThrottle/withThrottle.mjs";
|
|
11
|
+
import { withThrottleComputed as v } from "./decorators/withThrottleComputed/withThrottleComputed.mjs";
|
|
12
|
+
import { withThrottleAndCache as y } from "./decorators/withThrottleAndCache/withThrottleAndCache.mjs";
|
|
13
|
+
import { withStaleWhileRevalidate as b } from "./decorators/withStaleWhileRevalidate/withStaleWhileRevalidate.mjs";
|
|
14
|
+
import { withValidationAsync as x, withValidationSync as S } from "./decorators/withValidation/withValidation.mjs";
|
|
15
|
+
export { d as AbstractService, f as BaseREService, p as BaseREServiceEnhanced, t as ReactiveEngine, n as ReactiveEngineAutolog, t as ReactiveEngineAutomatic, e as ReactiveEngineCore, r as batch, i as computed, a as effect, o as inject, s as provide, c as resetGlobalReactiveEngine, l as signal, u as untrack, m as withCache, h as withDebounce, g as withLongPolling, b as withStaleWhileRevalidate, _ as withThrottle, y as withThrottleAndCache, v as withThrottleComputed, x as withValidationAsync, S as withValidationSync };
|
package/dist/index2.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { EffectScheduler as e, LinkPool as t, NodeLink as n, ReactiveEngine as r, ReactiveNode as i, currentEngineInstance as a } from "./core.mjs";
|
|
2
2
|
import "./core.automatic.mjs";
|
|
3
3
|
import "./core.autolog.mjs";
|
|
4
|
-
import { batch as
|
|
5
|
-
import { AbstractService as
|
|
6
|
-
import { BaseREServiceEnhanced as
|
|
7
|
-
export {
|
|
4
|
+
import { batch as o, computed as s, effect as c, inject as l, provide as u, signal as d, untrack as f } from "./core.global.mjs";
|
|
5
|
+
import { AbstractService as p, BaseREService as m } from "./AbstractService.mjs";
|
|
6
|
+
import { BaseREServiceEnhanced as h } from "./BaseREServiceEnhanced.mjs";
|
|
7
|
+
export { p as AbstractService, m as BaseREService, h as BaseREServiceEnhanced, e as EffectScheduler, t as LinkPool, n as NodeLink, r as ReactiveEngineAutomatic, i as ReactiveNode, o as batch, s as computed, a as currentEngineInstance, c as effect, l as inject, u as provide, d as signal, f as untrack };
|
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
import { useEffect as e,
|
|
1
|
+
import { useEffect as e, useLayoutEffect as t, useRef as n } from "react";
|
|
2
2
|
//#region src/react/hooks/useReactiveSubscription.ts
|
|
3
|
-
function
|
|
4
|
-
let
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
}
|
|
8
|
-
if (!(!
|
|
9
|
-
if ("subscribe" in
|
|
10
|
-
|
|
3
|
+
function r(r, i) {
|
|
4
|
+
let a = n(i);
|
|
5
|
+
t(() => {
|
|
6
|
+
a.current = i;
|
|
7
|
+
}), e(() => {
|
|
8
|
+
if (!(!r || typeof r != "object")) {
|
|
9
|
+
if ("subscribe" in r && typeof r.subscribe == "function") return r.subscribe((e) => {
|
|
10
|
+
a.current(e);
|
|
11
11
|
});
|
|
12
|
-
if ("__subscribe" in
|
|
13
|
-
|
|
12
|
+
if ("__subscribe" in r && typeof r.__subscribe == "function") return r.__subscribe(() => {
|
|
13
|
+
a.current(r);
|
|
14
14
|
});
|
|
15
15
|
}
|
|
16
|
-
}, [
|
|
16
|
+
}, [r]);
|
|
17
17
|
}
|
|
18
18
|
//#endregion
|
|
19
|
-
export {
|
|
19
|
+
export { r as useReactiveSubscription };
|
|
20
20
|
|
|
21
21
|
//# sourceMappingURL=useReactiveSubscription.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useReactiveSubscription.mjs","names":[],"sources":["../../../src/react/hooks/useReactiveSubscription.ts"],"sourcesContent":["import { useEffect, useRef } from 'react'\nimport { ISignalLike } from '../../core/types'\n\ntype CleanupFn = () => void\n\n/**\n * 🔄 Универсальный хук подписки без принудительного рендеринга самого компонента.\n * Идеален для вызова аналитики, сайд-эффектов или логов при изменении коллекций.\n */\nexport function useReactiveSubscription<T>(\n item: T,\n callback: (val: T extends ISignalLike<infer V> ? V : T) => void\n): void {\n const callbackRef = useRef(callback)\n\n
|
|
1
|
+
{"version":3,"file":"useReactiveSubscription.mjs","names":[],"sources":["../../../src/react/hooks/useReactiveSubscription.ts"],"sourcesContent":["import { useEffect, useLayoutEffect, useRef } from 'react'\nimport { ISignalLike } from '../../core/types'\n\ntype CleanupFn = () => void\n\n/**\n * 🔄 Универсальный хук подписки без принудительного рендеринга самого компонента.\n * Идеален для вызова аналитики, сайд-эффектов или логов при изменении коллекций.\n */\nexport function useReactiveSubscription<T>(\n item: T,\n callback: (val: T extends ISignalLike<infer V> ? V : T) => void\n): void {\n const callbackRef = useRef(callback)\n\n useLayoutEffect(() => {\n callbackRef.current = callback\n })\n\n useEffect(() => {\n if (!item || typeof item !== 'object') return\n\n if ('subscribe' in item && typeof (item as Record<string, unknown>).subscribe === 'function') {\n const signalItem = (item as unknown) as ISignalLike<unknown>\n return signalItem.subscribe((newValue) => {\n callbackRef.current(newValue as never)\n })\n }\n\n if ('__subscribe' in item && typeof (item as Record<string, unknown>).__subscribe === 'function') {\n return ((item as Record<string, unknown>).__subscribe as (cb: () => void) => CleanupFn)(() => {\n callbackRef.current(item as never)\n })\n }\n }, [item])\n}\n"],"mappings":";;AASA,SAAgB,EACd,GACA,GACM;CACN,IAAM,IAAc,EAAO,CAAQ;CAMnC,AAJA,QAAsB;EACpB,EAAY,UAAU;CACxB,CAAC,GAED,QAAgB;EACV,OAAC,KAAQ,OAAO,KAAS,WAE7B;OAAI,eAAe,KAAQ,OAAQ,EAAiC,aAAc,YAEhF,OAAO,EAAW,WAAW,MAAa;IACxC,EAAY,QAAQ,CAAiB;GACvC,CAAC;GAGH,IAAI,iBAAiB,KAAQ,OAAQ,EAAiC,eAAgB,YACpF,OAAS,EAAiC,kBAAoD;IAC5F,EAAY,QAAQ,CAAa;GACnC,CAAC;EANA;CAQL,GAAG,CAAC,CAAI,CAAC;AACX"}
|
|
@@ -1,8 +1,4 @@
|
|
|
1
1
|
import { ISignalLike } from '../../core/types';
|
|
2
|
-
/**
|
|
3
|
-
* ⚛️ УЛЬТИМАТИВНЫЙ ХУК ДЛЯ СТЯГИВАНИЯ ДАННЫХ ИЗ ГРАФА В СРЕДУ REACT
|
|
4
|
-
* Автоматически выводит тип внутренней структуры данных (V) из любого сигнала или вычисляемого свойства.
|
|
5
|
-
*/
|
|
6
2
|
export declare function useReactiveValue<V>(signal: ISignalLike<V>): V;
|
|
7
3
|
export declare function useReactiveValue<T extends object>(proxy: T): T;
|
|
8
4
|
export declare function useReactiveValue<T>(primitive: T): T;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useReactiveValue.d.ts","sourceRoot":"","sources":["../../../src/react/hooks/useReactiveValue.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAA;AAE9C
|
|
1
|
+
{"version":3,"file":"useReactiveValue.d.ts","sourceRoot":"","sources":["../../../src/react/hooks/useReactiveValue.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAA;AAE9C,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;AAC/D,wBAAgB,gBAAgB,CAAC,CAAC,SAAS,MAAM,EAAE,KAAK,EAAE,CAAC,GAAG,CAAC,CAAC;AAChE,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC,GAAG,CAAC,CAAC"}
|
|
@@ -1,15 +1,30 @@
|
|
|
1
|
-
import { useDebugValue as e, useMemo as t,
|
|
1
|
+
import { useDebugValue as e, useMemo as t, useRef as n, useSyncExternalStore as r } from "react";
|
|
2
2
|
//#region src/react/hooks/useReactiveValue.ts
|
|
3
3
|
function i(i) {
|
|
4
|
-
let a = i && typeof i == "object" && "__subscribe" in i;
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
4
|
+
let a = !!(i && typeof i == "object" && "__subscribe" in i), o = !!(i && typeof i == "object" && "subscribe" in i), s = o || a ? i._node || i : null, c = s ? s.engine || i._engine || i.engine : null, l = n(0);
|
|
5
|
+
return e(r(t(() => (e) => {
|
|
6
|
+
if (!o && !a) return () => {};
|
|
7
|
+
let t = !0, n = () => {
|
|
8
|
+
if (t) {
|
|
9
|
+
t = !1;
|
|
10
|
+
return;
|
|
11
|
+
}
|
|
12
|
+
l.current += 1, e();
|
|
10
13
|
};
|
|
11
|
-
|
|
12
|
-
|
|
14
|
+
if (o && typeof i.subscribe == "function") {
|
|
15
|
+
let e = i.subscribe(n);
|
|
16
|
+
return t = !1, e;
|
|
17
|
+
}
|
|
18
|
+
if (a && typeof i.__subscribe == "function") {
|
|
19
|
+
let e = i.__subscribe(n);
|
|
20
|
+
return t = !1, e;
|
|
21
|
+
}
|
|
22
|
+
return () => {};
|
|
23
|
+
}, [
|
|
24
|
+
i,
|
|
25
|
+
o,
|
|
26
|
+
a
|
|
27
|
+
]), () => l.current, () => 0)), !o && !a ? i : c && typeof c.untrack == "function" ? c.untrack(() => i.value === void 0 ? i : i.value) : i.value === void 0 ? i : i.value;
|
|
13
28
|
}
|
|
14
29
|
//#endregion
|
|
15
30
|
export { i as useReactiveValue };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useReactiveValue.mjs","names":[],"sources":["../../../src/react/hooks/useReactiveValue.ts"],"sourcesContent":["import { useSyncExternalStore, useDebugValue, useMemo,
|
|
1
|
+
{"version":3,"file":"useReactiveValue.mjs","names":[],"sources":["../../../src/react/hooks/useReactiveValue.ts"],"sourcesContent":["import { useSyncExternalStore, useDebugValue, useMemo, useRef } from 'react'\nimport { ISignalLike } from '../../core/types'\n\nexport function useReactiveValue<V>(signal: ISignalLike<V>): V;\nexport function useReactiveValue<T extends object>(proxy: T): T;\nexport function useReactiveValue<T>(primitive: T): T;\nexport function useReactiveValue(signal: any): any {\n const isProxy = Boolean(signal && typeof signal === 'object' && '__subscribe' in signal)\n const isSignal = Boolean(signal && typeof signal === 'object' && 'subscribe' in signal)\n\n const rawNode = (isSignal || isProxy) ? (signal._node || signal) : null\n const engine = rawNode ? (rawNode.engine || signal._engine || signal.engine) : null\n\n const versionRef = useRef(0)\n\n const subscribe = useMemo(() => (onStoreChange: () => void) => {\n if (!isSignal && !isProxy) {\n return () => {}\n }\n\n let isInitialRun = true\n\n const triggerStoreRerender = () => {\n if (isInitialRun) {\n isInitialRun = false\n return\n }\n versionRef.current += 1\n onStoreChange()\n }\n\n if (isSignal && typeof signal.subscribe === 'function') {\n const unsub = signal.subscribe(triggerStoreRerender)\n isInitialRun = false\n return unsub\n }\n\n if (isProxy && typeof signal.__subscribe === 'function') {\n const unsub = signal.__subscribe(triggerStoreRerender)\n isInitialRun = false\n return unsub\n }\n\n return () => {}\n }, [signal, isSignal, isProxy])\n\n const version = useSyncExternalStore(\n subscribe,\n () => versionRef.current,\n () => 0\n )\n\n useDebugValue(version)\n\n if (!isSignal && !isProxy) {\n return signal\n }\n\n if (engine && typeof engine.untrack === 'function') {\n return engine.untrack(() => (signal.value !== undefined ? signal.value : signal))\n }\n\n return signal.value !== undefined ? signal.value : signal\n}\n"],"mappings":";;AAMA,SAAgB,EAAiB,GAAkB;CACjD,IAAM,IAAU,GAAQ,KAAU,OAAO,KAAW,YAAY,iBAAiB,IAC3E,IAAW,GAAQ,KAAU,OAAO,KAAW,YAAY,eAAe,IAE1E,IAAW,KAAY,IAAY,EAAO,SAAS,IAAU,MAC7D,IAAS,IAAW,EAAQ,UAAU,EAAO,WAAW,EAAO,SAAU,MAEzE,IAAa,EAAO,CAAC;CAiD3B,OAVA,EANgB,EA/BE,SAAe,MAA8B;EAC7D,IAAI,CAAC,KAAY,CAAC,GAChB,aAAa,CAAC;EAGhB,IAAI,IAAe,IAEb,UAA6B;GACjC,IAAI,GAAc;IAChB,IAAe;IACf;GACF;GAEA,AADA,EAAW,WAAW,GACtB,EAAc;EAChB;EAEA,IAAI,KAAY,OAAO,EAAO,aAAc,YAAY;GACtD,IAAM,IAAQ,EAAO,UAAU,CAAoB;GAEnD,OADA,IAAe,IACR;EACT;EAEA,IAAI,KAAW,OAAO,EAAO,eAAgB,YAAY;GACvD,IAAM,IAAQ,EAAO,YAAY,CAAoB;GAErD,OADA,IAAe,IACR;EACT;EAEA,aAAa,CAAC;CAChB,GAAG;EAAC;EAAQ;EAAU;CAAO,CAG3B,SACM,EAAW,eACX,CAGM,CAAO,GAEjB,CAAC,KAAY,CAAC,IACT,IAGL,KAAU,OAAO,EAAO,WAAY,aAC/B,EAAO,cAAe,EAAO,UAAU,KAAA,IAA2B,IAAf,EAAO,KAAe,IAG3E,EAAO,UAAU,KAAA,IAA2B,IAAf,EAAO;AAC7C"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* @pravosleva/reactive-engine
|
|
2
|
+
* @pravosleva/reactive-engine v3.0.0-alpha.0
|
|
3
3
|
* High-performance transactional reactive engine with microtask batching.
|
|
4
4
|
*
|
|
5
5
|
* @license MIT
|
|
@@ -9,5 +9,5 @@
|
|
|
9
9
|
* @contact Telegram Channel: https://t.me/bash_exp_ru/3393
|
|
10
10
|
* @contact Developer Telegram: https://t.me/pravosleva
|
|
11
11
|
*/
|
|
12
|
-
(function(e,t){typeof exports==`object`&&typeof module<`u`?t(exports):typeof define==`function`&&define.amd?define([`exports`],t):(e=typeof globalThis<`u`?globalThis:e||self,t(e.ReactiveEngineLib={}))})(this,function(e){Object.defineProperty(e,Symbol.toStringTag,{value:`Module`});function t(e,t,n){let r=e.computedCache.get(t);if(r)return r;let i,a=!0,o=0,s=!1,c=-1,l=2,u=new Set,d=new Map,f=new Set,p=new Set,m=e=>{if(!e)return;let t=e._node||e;if(t.dependencies&&t.dependencies.size>0){for(let n of t.dependencies){let r=n,i=r._node||r;i.subscribers&&(i.subscribers.delete(t),i.subscribers.delete(e),i.subscribers.delete(_),i.type===`computed`&&i.subscribers.size===0&&m(i))}t.dependencies.clear(),t.depVersions&&t.depVersions.clear()}},h=t=>{if(!s||l===2)return t.run();if(p&&p.size>0&&t.verifiedInEpoch===e.epoch&&e.batchDepth===0&&l===0)return!1;let n=!1;if(u&&u.size>0)for(let t of u){let r=t._node||t;if(r.type===`computed`&&r.state>0&&r.update&&r.verifiedInEpoch!==e.epoch&&r.update(),t.hasBatchValue||d.get(t)!==r.version){n=!0;break}}return t.verifiedInEpoch=e.epoch,n||a?t.run():(l=0,!1)},g=0,_={id:e.subscriberId++,dependencies:u,subscribers:p,ownedEffects:f,depth:1,type:`computed`,fn:t,get version(){return o},get state(){return l},set state(e){l=e},get depVersions(){return d},verifiedInEpoch:-1,update:()=>h(_),run:()=>{if(c===e.epoch&&s&&l===0&&e.batchDepth===0)return!1;let r=e.epoch;if(c=r,_.verifiedInEpoch=r,e.cycleDetectionStack.has(_))throw Error(`[Graph Error] Cyclic dependency detected`);e.cycleDetectionStack.add(_);let p=e.activeConsumer,m=e.activeOwner;e.activeConsumer=_,e.activeOwner=_,g++,_.activeRunId=g;let h=u.size>0?Array.from(u):null;u.clear();try{if(f.size>0){for(let e of f)e&&typeof e.dispose==`function`&&e.dispose();f.clear()}let p=t();if(h!==null){let e=h.length===u.size;for(let t of h){let n=t;if(!e||!u.has(n)){let e=n._node||n;e.subscribers&&e.subscribers.delete(_),d.delete(n)}}}let m=a||!Object.is(i,p);if(m){let t=a?void 0:typeof i==`object`&&i?JSON.parse(JSON.stringify(i)):i;i=p,o++,e.log&&n&&e.log({type:`computed`,label:n,details:{from:t,to:p}})}a=!1,l=0,s=!0;let g=0;for(let e of u){let t=e,n=t._node||t;d.set(t,n.version),n.subscribers&&n.subscribers.add(_),n.depth!==void 0&&n.depth>g&&(g=n.depth)}return _.depth=g+1,e.epoch!==r&&(c=-1,_.verifiedInEpoch=-1,l=2),m}finally{e.activeConsumer=p,e.activeOwner=m,e.cycleDetectionStack.delete(_)}},markDirty:t=>{if(!(l>=t)){l=t;for(let t of p){let n=t._node||t;n.type===`effect`?(n.isDirty=!0,e.scheduleEffect(t)):n.markDirty&&n.markDirty(1)}}}},v={get value(){let t=e.activeConsumer;if(t&&t!==_&&typeof t.dependencies?.add==`function`){p.add(t),t.dependencies.add(_);let e=_.depth||1,n=t._node||t;n.depth!==void 0&&e>=n.depth&&(n.depth=e+1),t.activeRunId!==void 0&&(_._lastSeenInRunId=t.activeRunId)}return h(_),t&&t.depVersions&&t.depVersions.set(v,o),i},get valueWithoutTracking(){return i},get version(){return o},get dependencies(){return u},subscribe(t){let n=this,r={id:e.subscriberId++,isDirty:!0,depth:9999,dependencies:new Set,type:`effect`,run:()=>{if(!r.isDisposed)try{t(n.value)}catch(e){console.error(e)}}};return p.add(r),t(this.value),()=>{r.isDisposed=!0,p.delete(r),r.dependencies.clear()}},subscribeState(e){return v.subscribe(e)},destroy:()=>{m(_),p&&p.clear(),e.computedCache.delete(t),u.clear(),d.clear(),f.clear(),a=!0,l=2,s=!1},__subscribe(t){let n={id:e.subscriberId++,type:`effect`,run:t,isDirty:!1};return p.add(n),()=>{p.delete(n)}}};return v.run=()=>_.run(),e.computedCache.set(t,v),v._node=_,v.subscribers=p,v}var n=({tested:e,expectedKey:t,valueType:n})=>{let r=[];if(!e||!Array.isArray(e))return r;for(let i=0,a=e.length;i<a;i++){let a=e[i];if(typeof a!=`string`)continue;let o;switch(n){case`number`:o=RegExp(`\\[${t}=(?<value>\\d+)\\]`,`g`);break;default:o=RegExp(`\\[${t}=(?<value>.*?)\\]`,`g`);break}for(let e of a.matchAll(o))e?.groups&&r.push(e.groups.value)}return r};function r(e,t,r){let i=t,a=0,o=typeof r==`string`?r:r?.name,s=!!o&&n({tested:[o],expectedKey:`CORE_INTERNAL_SIGNAL`,valueType:`number`})?.[0]===`1`||!1,c=new Set,l=!1,u=t,d={type:`signal`,get version(){return a},subscribers:c},f=()=>{for(let t of c){let n=t._node||t;if(n.type===`effect`)n.isDirty=!0,e.scheduleEffect(t);else if(n.type===`computed`)n.markDirty&&n.markDirty(2);else if(typeof t==`function`)try{t(i)}catch(e){console.error(e)}else if(t&&typeof t.run==`function`)try{t.run()}catch(e){console.error(e)}}},p={get value(){let t=e.activeConsumer,n=e.activeCleanupNode;return n&&t===null&&n._snapshotValues&&n._snapshotValues.has(p)?n._snapshotValues.get(p):(t&&t.dependencies&&typeof t.dependencies.add==`function`&&(c.add(t),t.dependencies.add(p),t._snapshotValues&&t._snapshotValues.set(p,i),t.activeRunId!==void 0&&(p._lastSeenInRunId=t.activeRunId)),i)},set value(t){if(Object.is(i,t)&&!(i===t&&typeof i==`object`&&i))return;if(r&&typeof r==`object`&&r.validate){let e=r.validate(t);if(e!==!0){console.error(typeof e==`string`?e:`[Validation Error]`);return}}if(e.batchDepth>0){l||(l=!0,u=i),i=t,e.batchedSignals.add(p);return}let n=i;i=t,a++,e.epoch++,e.log({type:`signal`,label:o||`signal`,details:{from:n,to:t},isInternalCoreSignal:s}),f(),e.batchDepth===0&&e.flushEffects()},get version(){return a},type:`signal`,subscribe(e){return c.add(e),e(i),()=>{c.delete(e)}},_flushBatch:()=>{if(l){if(!Object.is(u,i)||typeof i==`object`&&i){a++,e.epoch++,e.log({type:`signal`,label:o||`signal_batched`,details:{from:u,to:i},isInternalCoreSignal:s});for(let t of c){let n=t._node||t;if(n.type===`effect`)n.isDirty=!0,e.scheduleEffect(t);else if(n.markDirty)n.markDirty(2);else if(typeof t==`function`)try{t(i)}catch(e){console.error(e)}}}l=!1,u=i}},get hasBatchValue(){return l},destroy:()=>{c&&c.clear(),e.batchedSignals&&e.batchedSignals.delete(p),l=!1,i=void 0,u=void 0}};return p._node=d,p.subscribers=c,p}function i(e,t){let n=e.activeConsumer;e.activeConsumer=null;try{return t()}finally{e.activeConsumer=n}}function a(e,t,n){if(e.proxyTargets.has(t))return t;if(e.proxyCache.has(t))return e.proxyCache.get(t);e.reactiveSignals.has(t)||e.reactiveSignals.set(t,new Map);let r=e.reactiveSignals.get(t),i=new Proxy(t,{get(t,i,a){if(i===`__subscribe`&&Array.isArray(t))return n=>{let i=r.get(`length`);return i||(i=e.signal(t.length),r.set(`length`,i)),i.subscribe(n)};if(Array.isArray(t)&&typeof i==`string`&&[`push`,`pop`,`shift`,`unshift`,`splice`,`sort`,`reverse`].includes(i))return(...n)=>{let o;return e.batch(()=>{o=Reflect.get(t,i).apply(a,n);let e=r.get(`length`);e&&(e.value=t.length),r.forEach((e,n)=>{n!==`length`&&(e.value=Reflect.get(t,n))})}),o};if(typeof i==`symbol`||i===`constructor`||i===`toJSON`)return Reflect.get(t,i,a);let o=r.get(i);if(!o){let a=Reflect.get(t,i);o=e.signal(a),r.set(i,o),typeof a==`object`&&a&&(o._proxyCache=e.reactive(a,n?`${n}.${String(i)}`:String(i)))}return o._proxyCache===void 0?o.value:(o.value,o._proxyCache)},set(t,n,i,a){let o=(e.proxyTargets.has(i),i),s=Reflect.get(t,n);if(s===o&&n!==`length`)return!0;Reflect.set(t,n,o);let c=r.get(n);if(c||(c=e.signal(s),r.set(n,c)),c._proxyCache=void 0,c.value=o,Array.isArray(t)&&n!==`length`){let e=r.get(`length`);e&&(e.value=t.length)}return!0}});return e.proxyCache.set(t,i),e.proxyTargets.add(i),i}function o(e,t,n){let r=!1,i=!1,a=!1,o=2,s=new Set,c=new Map,l=new Set,u=new Map,d=()=>{if(a)return;a=!0;let t=e.activeCleanupNode;e.activeCleanupNode=f;try{if(l.size>0){let t=e.activeConsumer,n=e.activeOwner;e.activeConsumer=null,e.activeOwner=null;for(let e of l)e.dispose&&e.dispose();l.clear(),e.activeConsumer=t,e.activeOwner=n}if(f.cleanups.size>0){let t=e.activeConsumer,n=e.activeOwner;e.activeConsumer=null,e.activeOwner=null;let r=null,i=Array.from(f.cleanups);f.cleanups.clear();for(let e of i)try{e()}catch(e){r||=e}if(e.activeConsumer=t,e.activeOwner=n,r)throw r}}finally{e.activeCleanupNode=t,a=!1}},f={id:e.subscriberId++,dependencies:s,ownedEffects:l,cleanups:new Set,type:`effect`,depth:0,label:n,_snapshotValues:u,get isDirty(){return o>0},set isDirty(e){e&&(o=2)},get isDisposed(){return r},set isDisposed(e){r=e},get state(){return o},set state(e){o=e},get depVersions(){return c},get _node(){return f},markDirty:()=>{r||o>=1||(o=1,e.scheduleEffect(f))},run:()=>{if(r||i)return;i=!0;try{d()}catch(e){throw i=!1,e}if(r){i=!1;return}let n=e.activeConsumer,a=e.activeOwner;e.activeConsumer=f,e.activeOwner=f;let l=s.size>0?Array.from(s):null;s.clear();try{o=0;let e=t();if(typeof e==`function`&&f.cleanups.add(e),l!==null)for(let e of l){let t=e;if(!s.has(t)){let e=t._node||t;e.subscribers&&e.subscribers.delete(f),c.delete(t),u.delete(t)}}let n=0;for(let e of s){let t=e,r=t._node||t;c.set(t,r.version),r.subscribers&&r.subscribers.add(f),r.depth!==void 0&&r.depth>n&&(n=r.depth)}f.depth=n+1}finally{i=!1,e.activeConsumer=n,e.activeOwner=a}},dispose:()=>{if(!r){r=!0,f.isDisposed=!0,d();for(let e of s){let t=e._node||e;t.subscribers&&t.subscribers.delete(f)}s.clear(),c.clear(),u.clear()}}},p=e.activeOwner?e.activeOwner._node||e.activeOwner:null;return p&&p.ownedEffects&&p.ownedEffects.add(f),f.run(),()=>{f.dispose()}}var s=class{static churnTracker=new Map;static TIME_WINDOW_MS=1e3;static CHURN_WARNING_THRESHOLD=3;static CHURN_CRITICAL_THRESHOLD=6;static isDeepEqual(e,t){return e===t?!0:typeof e!=`object`||typeof t!=`object`||e===null||t===null?!1:JSON.stringify(e)===JSON.stringify(t)}static analyzeSignalChurn(e){let t=Date.now();this.churnTracker.has(e)||this.churnTracker.set(e,[]);let n=this.churnTracker.get(e),r=t-this.TIME_WINDOW_MS,i=n.filter(e=>e>r);i.push(t);let a=i.length,o=(this.TIME_WINDOW_MS/1e3).toFixed(1);return i.length<=1?(this.churnTracker.delete(e),{marker:`🟢`,info:`[STABLE] (1 изм./${o}s)`}):(this.churnTracker.set(e,i),a>=this.CHURN_CRITICAL_THRESHOLD?{marker:`🔴`,info:`[CRITICAL CHURN] (${a} изм./${o}s) — Нужен debounce!`}:a>=this.CHURN_WARNING_THRESHOLD?{marker:`🟡`,info:`[WARNING CHURN] (${a} изм./${o}s)`}:{marker:`🟢`,info:`[STABLE] (${a} изм./${o}s)`})}static processLog(e,t,n){let{type:r,label:i,details:a,isInternalCoreSignal:o=!1}=n;if(!e.isEnabled||e.filter&&!(e.filter instanceof RegExp?e.filter.test(i):i.includes(e.filter))||o&&!e.isCoreOptimizationDebugEnabled)return;if(a&&`from`in a&&`to`in a&&this.isDeepEqual(a.from,a.to)){if((r===`computed`||r===`resource`)&&e.isCoreOptimizationDebugEnabled){t(r,`🔵 [IDLE] ${i}`,a);return}return}let s=``;if(r===`signal`||r===`resource`||r===`computed`){let e=this.analyzeSignalChurn(i);s=e.marker===`🟢`?` ${e.marker}`:` ${e.marker} ${e.info}`}t(r,`${i}${s}`,a)}};function c(e,t,r,i){let a=i&&typeof i==`object`,o=a?i.name||`unnamed_resource`:i||`unnamed_resource`,s=a?i:{},c=s.resetDataOnSourceChange??!0,l=s.responseValidate,u=s.validateBeforeFetch,d=s.retryCount??0,f=s.timeout??5e3,p=Date.now(),m=e.signal({data:null,loading:!0,error:null,isRetrying:!1,attemptIndex:0,retryCount:d,totalElapsedMs:void 0},`[CORE_INTERNAL_SIGNAL=1]:resource:state:${o}`),h=t=>{e.log({type:`resource`,label:o,details:{to:t,from:m.value}}),m.value=t},g=async(r,i,a=!1)=>{if(i.aborted)return;if(p=Date.now(),u){let t=u(r);if(t===!1||typeof t==`string`){if(i.aborted)return;let n=typeof t==`string`?t:`Pre-fetch validation failed for resource`,r=a?null:e.untrack(()=>m.value.data);h({data:r,loading:!1,error:n,isRetrying:!1,attemptIndex:0,retryCount:d,totalElapsedMs:void 0});return}}let s=a&&c?null:e.untrack(()=>m.value.data);h({data:s,loading:!0,error:null,isRetrying:!1,attemptIndex:0,retryCount:d,totalElapsedMs:void 0});for(let a=0;a<=d;a++){if(i.aborted)return;let s=AbortSignal.timeout(f),c=AbortSignal.any([i,s]);try{let e=await t(r,c);if(i.aborted)return;if(s.aborted)throw new DOMException(`The operation timed out.`,`TimeoutError`);if(l){let t=l(e);if(t===!1||typeof t==`string`){if(i.aborted)return;h({data:null,loading:!1,error:typeof t==`string`?t:`Validation failed`,isRetrying:!1,attemptIndex:0,retryCount:d,totalElapsedMs:void 0});return}}if(i.aborted)return;h({data:e,loading:!1,error:null,isRetrying:!1,attemptIndex:0,retryCount:d,totalElapsedMs:void 0});return}catch(t){let r=s.aborted||t.name===`TimeoutError`||t.message?.includes(`timeout`);if(i.aborted&&!r)return;let c=n({tested:[t.message],expectedKey:`THROW_CUSTOM_VALIDATION_ERROR_NO_RETRY`,valueType:`number`})?.[0]===`1`||!1,l=c&&n({tested:[t.message],expectedKey:`MESSAGE`,valueType:`string`})?.[0]||`Custom validation error`,u=c||t.name===`ValidationError`;if(a===d||u){if(i.aborted)return;let n=Date.now()-p,o=`${r?`Request timed out after ${f}ms (attempt ${a+1}/${d+1})`:c?l:t instanceof Error?t.message:String(t)}.${e.logger.isCoreOptimizationDebugEnabled?` Всего безуспешных попыток с момента изменения исходного сигнала: ${d+1}.`:``}`;h({data:null,loading:!1,error:o,isRetrying:!1,attemptIndex:a+1,retryCount:d,totalElapsedMs:n});return}else{if(i.aborted)return;let t=1e3*2**a;t=Math.min(t,3e5)+Math.random()*200,h({data:m.value.data,loading:!0,error:null,isRetrying:!0,attemptIndex:a+1,retryCount:d}),e.log({type:`resource`,label:`${o}:retry_scheduled`,details:{payload:{attempt:a+1,total:d,nextDelayMs:Math.round(t)}}});let n=r?`таймауту`:`ошибке сети`;e.logger.isEnabled&&console.warn(`[Resource Retry] "${o}" сбой по ${n}. Запрос ${a+1} из ${d+1} не удался. Ожидание повтора: ${Math.round(t)}ms`);try{if(await e.delay(t,i),i.aborted)return}catch{return}}}}},_=null,v=e.effect(()=>{let t=r?r.value:void 0,n=new AbortController;return _=n,e.untrack(()=>{g(t,n.signal,!0)}),()=>n.abort()},`[CORE_INTERNAL_SIGNAL=1]:effect`);return{get data(){return m.value.data},get loading(){return m.value.loading},get error(){return m.value.error},get isRetrying(){return m.value.isRetrying},get value(){return m.value},refetch:()=>{_?.abort(),_=new AbortController,g(r?r.value:void 0,_.signal,!1)},subscribe:e=>m.subscribe(e),destroy:()=>{_?.abort(),_=null,typeof v==`function`&&v(),m.destroy&&m.destroy()}}}var l={signal:`background: #007acc; color: #fff; padding: 2px 6px; border-radius: 4px; font-weight: bold;`,computed:`background: #42b883; color: #fff; padding: 2px 6px; border-radius: 4px; font-weight: bold;`,effect:`background: #e01e5a; color: #fff; padding: 2px 6px; border-radius: 4px; font-weight: bold;`,batch:`background: #7952b3; color: #fff; padding: 2px 6px; border-radius: 4px; font-weight: bold;`,resource:`background: #d97706; color: #fff; padding: 2px 6px; border-radius: 4px; font-weight: bold;`,reactive:`background: #007acc; color: #fff; padding: 2px 6px; border-radius: 4px; font-weight: bold;`},u=null;function d(e){if(e===null)return`null`;if(e===void 0)return`undefined`;if(typeof e==`object`)try{return JSON.stringify(e)}catch{return`[Cyclic Object or Layer]`}return String(e)}function f(e,t,n){u||(u={id:Math.random().toString(36).substring(2,9),pendingLogQueue:[],isFlushing:!1},queueMicrotask(()=>p())),u.pendingLogQueue.push({type:e,label:t,from:n?.from,to:n?.to,payload:n?.payload,timestamp:Date.now()})}function p(){if(!u||u.isFlushing)return;u.isFlushing=!0;let e=u.pendingLogQueue;if(e.length===0){u=null;return}console.groupCollapsed(`%cREACTIVE TRANSACTION%c [id: ${u.id}] (${e.length} operations)`,`background: #7952b3; color: #fff; padding: 2px 6px; border-radius: 4px; font-weight: bold;`,`color: #888; font-weight: normal;`);for(let t of e){let e=l[t.type],n=t.from!==void 0||t.to!==void 0,r=`%c${t.type.toUpperCase()}%c ${t.label}`;n&&(t.from?r+=` ${d(t.from)} → ${d(t.to)}`:r+=` (${d(t.to)})`),t.payload===void 0?console.log(r,e,`color: inherit;`):(console.groupCollapsed(r,e,`color: inherit;`),console.log(`Payload:`,t.payload),console.groupEnd())}console.groupEnd(),u=null}var m=class{frameworkPrefix=`core`;logger;epoch=0;activeConsumer=null;batchDepth=0;subscriberId=0;pendingEffects=[];maxPendingDepth=0;computedCache=new WeakMap;diRegistry=new Map;diCache=new Map;proxyCache=new WeakMap;proxyTargets=new WeakSet;reactiveSignals=new WeakMap;cycleDetectionStack=new Set;batchedSignals=new Set;activeOwner=null;activeCleanupNode=null;pendingCleanups=new Set;queueCleanup(e){this.pendingCleanups.add(e)}constructor(e){this.logger=e?.logger||{isEnabled:!1}}scheduleEffect(e){let t=e.depth||0;this.pendingEffects[t]||(this.pendingEffects[t]=new Set),this.pendingEffects[t].add(e),t>this.maxPendingDepth&&(this.maxPendingDepth=t)}queueLog(e,t,n){f(e,t,n)}batch(e){this.batchDepth++;try{return e()}finally{if(this.batchDepth--,this.batchDepth===0){if(this.batchedSignals.size>0){for(let e of this.batchedSignals)e._flushBatch&&e._flushBatch();this.batchedSignals.clear()}this.flushEffects()}}}flushEffects(){if(this.batchDepth>0)return;let e=this.activeConsumer;try{for(let e=0;e<=this.maxPendingDepth;e++){let t=this.pendingEffects[e];if(!t||t.size===0)continue;let n=Array.from(t);t.clear();for(let t of n)if(!t.isDisposed&&t.isDirty){if(t.dependencies&&t.dependencies.size>0){let e=!1;for(let n of t.dependencies){let r=n._node||n;r.type===`computed`&&r.state>0&&r.update&&r.update(),t.depVersions&&t.depVersions.get(n)!==r.version&&(e=!0)}if(!e&&t.dependencies.size>0){t.isDirty=!1;continue}}try{t.run()}catch(t){for(let t=e;t<=this.maxPendingDepth;t++){let e=this.pendingEffects[t];if(e){for(let t of e)t.isDirty=!1;e.clear()}}throw this.maxPendingDepth=0,t}}if(e>0){let t=!1;for(let n=0;n<e;n++)if(this.pendingEffects[n]&&this.pendingEffects[n].size>0){t=!0;break}t&&(e=-1)}}this.maxPendingDepth=0}finally{this.activeConsumer=e}}log(e){!this.logger||!this.logger.isEnabled||s.processLog(this.logger,f,e)}signal(e,t){return r(this,e,t)}computed(e,n){return t(this,e,n)}effect(e,t){return o(this,e,t)}untrack(e){return i(this,e)}reactive(e,t){return a(this,e,t)}provide(e,t){this.diRegistry.set(e,t),this.diCache.delete(e)}inject(e){if(e==null)throw Error(`[DI Error] Token is empty`);if(this.diCache.has(e))return this.diCache.get(e);if(this.cycleDetectionStack.has(e))throw Error(`[DI Error] Cyclic dependency detected`);this.cycleDetectionStack.add(e);try{if(this.diRegistry.has(e)){let t=this.diRegistry.get(e);if(typeof t==`function`){if(t._isMockFunction){let n=t(this);return n===void 0?t:(this.diCache.set(e,n),n)}let n=t.toString();if(!(n.startsWith(`class `)||n.startsWith(`class{`)||t.prototype&&t.prototype.constructor===t&&!n.startsWith(`function`)&&!n.includes(`=>`))){let n=t(this);return this.diCache.set(e,n),n}return t}return t}if(typeof e==`function`){let t=new e(this);return this.diCache.set(e,t),t}throw Error(`[DI Error] Token not found`)}finally{this.cycleDetectionStack.delete(e)}}delay(e,t){return new Promise((n,r)=>{if(t.aborted)return r(new DOMException(`Aborted`,`AbortError`));let i=setTimeout(()=>{t.removeEventListener(`abort`,a),n()},e),a=()=>{clearTimeout(i),r(new DOMException(`Aborted`,`AbortError`))};t.addEventListener(`abort`,a,{once:!0})})}resource(e,t,n){return c(this,e,t,n)}},h=class extends m{},g=class extends h{autoLogQueue=[];isHardFlushScheduled=!1;queueLog(e,t,n){this.autoLogQueue.push({type:e,name:t,meta:n,timestamp:Date.now()}),this.isHardFlushScheduled||(this.isHardFlushScheduled=!0,queueMicrotask(()=>this.flushLogs()))}flushLogs(){this.isHardFlushScheduled=!1,this.autoLogQueue.length!==0&&(typeof process<`u`&&process.env.NODE_ENV!==`test`&&(console.group(`📊 [Autolog] Срез транзакций: ${this.autoLogQueue.length} операций`),this.autoLogQueue.forEach(e=>console.log(`[${e.type.toUpperCase()}] ${e.name}`,e.meta||``)),console.groupEnd()),this.autoLogQueue=[])}computed(e,t){let n=this,r=t||`unnamed_computed`,i=super.computed(e,t),a=!1,o={get value(){if(a)return i.value;let e=typeof performance<`u`?performance.now():0,t=i.value;return e&&n.queueLog(`computed`,r,{value:t,duration:`${(performance.now()-e).toFixed(3)}ms`}),t},subscribe:e=>i.subscribe(e),destroy(){a=!0,i.destroy()}};return`_node`in i&&Object.defineProperty(o,"_node",{value:i._node,enumerable:!1}),o}},_=new m({logger:{isEnabled:!1}}),v=(e,t)=>_.signal(e,t),y=(e,t)=>_.computed(e,t),b=(e,t)=>_.effect(e,t),x=e=>_.batch(e),S=e=>_.untrack(e);function C(){_=new m({logger:{isEnabled:!1}})}var w=class{engine;constructor(e){this.engine=e,this.onInit()}createNumericSignal(e,t){return this.engine.signal(e,{name:t,validate:e=>typeof e==`number`&&!isNaN(e)})}createComputed(e){return this.engine.computed(e)}createSignal(e,t){return this.engine.signal(e,t)}onInit(){}},T=w,E=class{engine;constructor(e){this.engine=e,setTimeout(()=>this.onInit(),0)}onInit(){}};e.AbstractService=w,e.BaseREService=T,e.BaseREServiceEnhanced=E,e.ReactiveEngine=h,e.ReactiveEngineAutolog=g,e.ReactiveEngineAutomatic=m,e.ReactiveEngineCore=m,e.batch=x,e.computed=y,e.effect=b,e.flushLogs=p,e.queueLog=f,e.resetGlobalReactiveEngine=C,e.signal=v,e.untrack=S});
|
|
12
|
+
(function(e,t){typeof exports==`object`&&typeof module<`u`?t(exports):typeof define==`function`&&define.amd?define([`exports`],t):(e=typeof globalThis<`u`?globalThis:e||self,t(e.ReactiveEngineLib={}))})(this,function(e){Object.defineProperty(e,Symbol.toStringTag,{value:`Module`});var t={signal:`background: #007acc; color: #fff; padding: 2px 6px; border-radius: 4px; font-weight: bold;`,computed:`background: #42b883; color: #fff; padding: 2px 6px; border-radius: 4px; font-weight: bold;`,effect:`background: #e01e5a; color: #fff; padding: 2px 6px; border-radius: 4px; font-weight: bold;`,batch:`background: #7952b3; color: #fff; padding: 2px 6px; border-radius: 4px; font-weight: bold;`,resource:`background: #d97706; color: #fff; padding: 2px 6px; border-radius: 4px; font-weight: bold;`,reactive:`background: #007acc; color: #fff; padding: 2px 6px; border-radius: 4px; font-weight: bold;`},n=null;function r(e){if(e===null)return`null`;if(e===void 0)return`undefined`;if(typeof e==`object`)try{return JSON.stringify(e)}catch{return`[Cyclic Object or Layer]`}return String(e)}function i(e,t,r){n||(n={id:Math.random().toString(36).substring(2,9),pendingLogQueue:[],isFlushing:!1},queueMicrotask(()=>a())),n.pendingLogQueue.push({type:e,label:t,from:r?.from,to:r?.to,payload:r?.payload,timestamp:Date.now()})}function a(){if(!n||n.isFlushing)return;n.isFlushing=!0;let e=n.pendingLogQueue;if(e.length===0){n=null;return}console.groupCollapsed(`%cREACTIVE TRANSACTION%c [id: ${n.id}] (${e.length} operations)`,`background: #7952b3; color: #fff; padding: 2px 6px; border-radius: 4px; font-weight: bold;`,`color: #888; font-weight: normal;`);for(let n of e){let e=t[n.type],i=n.from!==void 0||n.to!==void 0,a=`%c${n.type.toUpperCase()}%c ${n.label}`;i&&(n.from===void 0?a+=` (${r(n.to)})`:a+=` ${r(n.from)} → ${r(n.to)}`),n.payload===void 0?console.log(a,e,`color: inherit;`):(console.groupCollapsed(a,e,`color: inherit;`),console.log(`Payload:`,n.payload),console.groupEnd())}console.groupEnd(),n=null}var o=class{static churnTracker=new Map;static TIME_WINDOW_MS=1e3;static CHURN_WARNING_THRESHOLD=3;static CHURN_CRITICAL_THRESHOLD=6;static isDeepEqual(e,t){return e===t?!0:typeof e!=`object`||typeof t!=`object`||e===null||t===null?!1:JSON.stringify(e)===JSON.stringify(t)}static analyzeSignalChurn(e){let t=Date.now();this.churnTracker.has(e)||this.churnTracker.set(e,[]);let n=this.churnTracker.get(e),r=t-this.TIME_WINDOW_MS,i=n.filter(e=>e>r);i.push(t);let a=i.length,o=(this.TIME_WINDOW_MS/1e3).toFixed(1);return i.length<=1?(this.churnTracker.delete(e),{marker:`🟢`,info:`[STABLE] (1 изм./${o}s)`}):(this.churnTracker.set(e,i),a>=this.CHURN_CRITICAL_THRESHOLD?{marker:`🔴`,info:`[CRITICAL CHURN] (${a} изм./${o}s) — Нужен debounce!`}:a>=this.CHURN_WARNING_THRESHOLD?{marker:`🟡`,info:`[WARNING CHURN] (${a} изм./${o}s)`}:{marker:`🟢`,info:`[STABLE] (${a} изм./${o}s)`})}static processLog(e,t,n){let{type:r,label:i,details:a,isInternalCoreSignal:o=!1}=n;if(!e.isEnabled||e.filter&&!(e.filter instanceof RegExp?e.filter.test(i):i.includes(e.filter))||o&&!e.isCoreOptimizationDebugEnabled)return;if(a&&`from`in a&&`to`in a&&this.isDeepEqual(a.from,a.to)){if((r===`computed`||r===`resource`)&&e.isCoreOptimizationDebugEnabled){t(r,`🔵 [IDLE] ${i}`,a);return}return}let s=``;if(r===`signal`||r===`resource`||r===`computed`){let e=this.analyzeSignalChurn(i);s=e.marker===`🟢`?` ${e.marker}`:` ${e.marker} ${e.info}`}t(r,`${i}${s}`,a)}};function s(e,t,n){if(e.proxyTargets.has(t))return t;if(e.proxyCache.has(t))return e.proxyCache.get(t);let r=n||`reactive`;e.log({type:`reactive`,label:r,details:{to:t}}),e.reactiveSignals.has(t)||e.reactiveSignals.set(t,new Map);let i=e.reactiveSignals.get(t),a=Symbol(`ownKeys`);function o(t,n){let a=i.get(t);return a||(a=e.signal(n,{name:`${r}.${String(t)}`,isInternalCoreSignal:!0}),i.set(t,a)),a}let s=new Proxy(t,{ownKeys(e){return o(a,0).value,Reflect.ownKeys(e)},get(t,r,s){if(r===`__subscribe`&&Array.isArray(t))return e=>o(`length`,t.length).subscribe(e);if(Array.isArray(t)&&typeof r==`string`&&[`push`,`pop`,`shift`,`unshift`,`splice`,`sort`,`reverse`].includes(r))return(...c)=>{let l,u=n?`${n}.${r}`:`array.${r}`,d=t.length;return e.batch(()=>{l=Reflect.get(t,r).apply(s,c);let n=o(`length`,t.length);n.value=t.length;let f=o(a,0);f.value=f.valueWithoutTracking+1,i.forEach((e,n)=>{n!==`length`&&n!==a&&(e.value=Reflect.get(t,n))}),e.log({type:`reactive`,label:u,details:{from:{length:d},to:{length:t.length}}})}),l};if(typeof r==`symbol`||r===`constructor`||r===`toJSON`)return Reflect.get(t,r,s);let c=i.get(r);if(!c){let a=Reflect.get(t,r);c=e.signal(a),i.set(r,c),typeof a==`object`&&a&&(c._proxyCache=e.reactive(a,n?`${n}.${String(r)}`:String(r)))}return c._proxyCache===void 0?c.value:(c.value,c._proxyCache)},set(t,r,i){let s=Object.prototype.hasOwnProperty.call(t,r),c=Reflect.get(t,r);if(s&&c===i&&r!==`length`)return!0;Reflect.set(t,r,i);let l=o(r,c),u=n?`${n}.${String(r)}`:String(r);if(e.log({type:`reactive`,label:u,details:{from:c,to:i}}),l._proxyCache=void 0,l.value=i,!s){let e=o(a,0);e.value=e.valueWithoutTracking+1}if(Array.isArray(t)&&r!==`length`){let e=o(`length`,t.length);e.value=t.length}return!0},deleteProperty(e,t){let n=Object.prototype.hasOwnProperty.call(e,t),r=Reflect.deleteProperty(e,t);if(n&&r){let e=i.get(t);e&&(e._proxyCache=void 0,e.value=void 0);let n=o(a,0);n.value=n.valueWithoutTracking+1}return r}});return e.proxyCache.set(t,s),e.proxyTargets.add(s),s}function c(e,t,n,r){let i=typeof r==`string`?r:r?.name||`resource`,a=typeof r==`object`?r:{},o=a.resetDataOnSourceChange??!1,s=a.timeout,c=a.retryCount??0,l=a.validateBeforeFetch,u=a.responseValidate,d=e.signal(null,`${i}_data`),f=e.signal(!1,`${i}_loading`),p=e.signal(null,`${i}_error`),m=e.signal(!1,`${i}_isRetrying`),h=e.signal(0,`${i}_attemptIndex`),g=e.signal(void 0,`${i}_totalElapsedMs`),_=null,v=!1;function y(){if(!v)return{data:d.value,loading:f.value,error:p.value,isRetrying:m.value,attemptIndex:h.value,retryCount:c,totalElapsedMs:g.value}}async function b(n){let r=Date.now();g.value=void 0,p.value=null,m.value=!1;let a=y();if(l){let t=l(n);if(t===!1||typeof t==`string`){p.value=typeof t==`string`?t:`Validation failed`,f.value=!1,e.log({type:`resource`,label:i,details:{from:a,to:y()}});return}}let b=0;for(h.value=b;b<=c&&!v;){_&&_.abort(),_=new AbortController;let a=_.signal,l=y();f.value=!0,b===0&&o&&(d.value=null),e.log({type:`resource`,label:i,details:{from:l,to:y()}});let x=!1;try{let o=t(n,a);if(s!==void 0&&s>0){let t=e.delay(s,a).then(()=>{throw x=!0,_&&_.abort(),Error(`Request timed out after ${s}ms`)});o=Promise.race([o,t])}let c=await o;if(a.aborted||v)return;if(u){let e=u(c);if(e===!1||typeof e==`string`)throw Error(typeof e==`string`?e:`Response validation failed`)}let l=y();d.value=c,p.value=null,m.value=!1,g.value=Date.now()-r,f.value=!1,e.log({type:`resource`,label:i,details:{from:l,to:y()}});return}catch(t){let n=x||s!==void 0&&t?.name===`TimeoutError`;if(a.aborted&&!n||v)return;let o=y(),l=n?`Request timed out after ${s}ms`:t?.message||String(t);if(b<c){b++,h.value=b,m.value=!0,e.log({type:`resource`,label:i,details:{from:o,to:y()}});try{await e.delay(1e3*b,a)}catch{return}}else{let t=b+1,n=c>0?`. Всего безуспешных попыток с момента изменения исходного сигнала: ${t}`:``;p.value=`${l}${n}`,m.value=!1,g.value=Date.now()-r,f.value=!1,e.log({type:`resource`,label:i,details:{from:o,to:y()}});return}}}}let x=e.effect(()=>{if(n){let t=n.value;e.untrack(()=>{b(t)})}else e.untrack(()=>{b(void 0)})},`${i}_effect`),S={get data(){return v?null:d.value},get loading(){return v?!1:f.value},get error(){return v?null:p.value},get isRetrying(){return v?!1:m.value},get attemptIndex(){return v?0:h.value},get retryCount(){return c},get totalElapsedMs(){return v?void 0:g.value},refetch(){v||e.untrack(()=>{b(n?n.value:void 0)})},subscribe(t){return e.effect(()=>{t(S.value)})},get value(){return y()},destroy(){v=!0,_&&=(_.abort(),null),x(),d.destroy(),f.destroy(),p.destroy(),m.destroy(),h.destroy(),g.destroy()}};return S}var l=class{source=null;target=null;nextSubscriber=null;prevSubscriber=null;nextDependency=null;prevDependency=null;version=0;clear(){this.source=null,this.target=null,this.nextSubscriber=null,this.prevSubscriber=null,this.nextDependency=null,this.prevDependency=null,this.version=0}},u=class{static pool=[];static size=0;static maxPoolSize=1e5;static acquire(e,t){if(this.size>0){this.size--;let n=this.pool[this.size];return this.pool[this.size]=null,n.source=e,n.target=t,n}let n=new l;return n.source=e,n.target=t,n}static release(e){this.size<this.maxPoolSize&&(e.clear(),this.pool[this.size]=e,this.size++)}},d=class{id;type;version=0;state=0;depth=0;subscribersHead=null;subscribersTail=null;dependenciesHead=null;dependenciesTail=null;_value;_prevValue;fn=null;cleanups=new Set;isDisposed=!1;ownedEffects=new Set;wrapper=null;engine=null;constructor(e,t,n){this.type=e,this.id=t,this._value=n,this._prevValue=n}get subscribers(){let e=new Set,t=this.subscribersHead;for(;t!==null;)t.target&&e.add(t.target),t=t.nextSubscriber;return e}get dependencies(){let e=new Set,t=this.dependenciesHead;for(;t!==null;)t.source&&e.add(t.source),t=t.nextDependency;return e}},f=class{buckets=[];maxDepth=-1;schedule(e){let t=e.depth;this.buckets[t]||(this.buckets[t]=[]),this.buckets[t].includes(e)||(this.buckets[t].push(e),t>this.maxDepth&&(this.maxDepth=t))}clearAll(){for(let e=0;e<=this.maxDepth;e++){let t=this.buckets[e];if(t){for(let e of t)e.state=0;this.buckets[e]=[]}}this.maxDepth=-1}flush(e){let t=e.activeConsumer;try{let t=0;for(;t<=this.maxDepth;){let n=this.buckets[t];if(!n||n.length===0){t++;continue}this.buckets[t]=[],n.sort((e,t)=>t.depth-e.depth);for(let t of n)if(!(t.isDisposed||t.state===0)&&(t.state===1&&(e.checkNeedsUpdate(t)?t.state=2:t.state=0),t.state===2))try{e.runEffectNode(t)}catch(e){throw this.clearAll(),e}let r=!1;for(let e=0;e<=this.maxDepth;e++)if(this.buckets[e]&&this.buckets[e].length>0){t=e,r=!0;break}r||t++}}finally{e.activeConsumer=t,this.maxDepth=-1}}},p=class{activeConsumer=null;batchDepth=0;batchedSignals=[];batchInitialValues=new Map;computedCache=new WeakMap;logger;proxyCache=new WeakMap;proxyTargets=new WeakSet;reactiveSignals=new WeakMap;scheduler=new f;currentOwner=null;effectIdCounter=0;diRegistry=new Map;diCache=new Map;cycleDetectionStack=new Set;constructor(e){this.logger=e?.logger||{isEnabled:!1}}log(e){!this.logger||!this.logger.isEnabled||o.processLog(this.logger,i,e)}signal(e,t){let n=typeof t==`string`?t:t?.name||`signal`,r=typeof t==`object`?t?.validate:void 0,i=typeof t==`object`?t?.isInternalCoreSignal:!1,a=new d(`signal`,n,e);a.engine=this;let o=this;this.log({type:`signal`,label:n,details:{to:e},isInternalCoreSignal:i});let s={_node:a,_engine:this,get value(){return o.activeConsumer&&o.trackNode(a,o.activeConsumer),a._value},set value(e){if(r){let t=r(e);if(t===!1||typeof t==`string`){console.error(`[Validation Error] Invalid value supplied to signal "${n}": ${t}`);return}}let t=typeof e==`object`&&!!e;if(Object.is(a._value,e)&&!t)return;let s=a._value;a._prevValue=s,o.batchDepth>0&&!o.batchInitialValues.has(a)&&o.batchInitialValues.set(a,{value:s,version:a.version}),a._value=e,a.version++,o.log({type:`signal`,label:n,details:{from:s,to:e},isInternalCoreSignal:i}),o.notifySubscribers(a,2),o.batchDepth>0?o.batchedSignals.includes(a)||o.batchedSignals.push(a):o.flushEffects()},get valueWithoutTracking(){return a._value},subscribe(e){return o.effect(()=>{e(s.value)})},destroy(){o.disposeNode(a)}};return a.wrapper=s,s}notifySubscribers(e,t){let n=e.subscribersHead;for(;n!==null;){let e=n.target;if(e===this.activeConsumer){n=n.nextSubscriber;continue}e.state<t&&(e.state=t,e.type===`effect`?this.scheduler.schedule(e):this.notifySubscribers(e,1)),n=n.nextSubscriber}}computed(e,t){let n=new d(`computed`,t||`computed`);n.engine=this,n.fn=e,n.state=2;let r=this,i={_node:n,_engine:this,get value(){return n.state===1&&(r.checkNeedsUpdate(n)?n.state=2:n.state=0),n.state===2&&(n._value,r.evaluateComputed(n)),r.activeConsumer&&r.trackNode(n,r.activeConsumer),n._value},get valueWithoutTracking(){return n._value},subscribe(e){return r.effect(()=>{e(i.value)})},destroy(){r.disposeNode(n)},_isDirty(){return n.state===2},get dependencies(){let e=new Set,t=n.dependenciesHead;for(;t!==null;)t.source&&t.source.wrapper&&e.add(t.source.wrapper),t=t.nextDependency;return e}};return n.wrapper=i,this.batchDepth===0&&this.computedCache.set(e,i),i}effect(e,t){let n=t||`effect`,r=new d(`effect`,n);r.state=2,r.depth=this.currentOwner?this.currentOwner.depth+1:0,r.wrapper={id:++this.effectIdCounter,run:()=>{this.runEffectNode(r)},markDirty:()=>{r.state=2,this.scheduler.schedule(r)},cleanups:r.cleanups,label:n,get isDirty(){return r.state===2},get isDisposed(){return r.isDisposed},_node:r},r.fn=()=>{this.log({type:`effect`,label:n});let t=e();typeof t==`function`&&r.cleanups.add(t)},this.currentOwner&&this.currentOwner.ownedEffects.add(r),this.runEffectNode(r);let i=()=>{this.disposeNode(r)};return i._node=r,i}resource(e,t,n){return c(this,e,t,n)}batch(e){this.batchDepth++;try{return e()}finally{if(this.batchDepth--,this.batchDepth===0){for(let e of this.batchedSignals){let t=this.batchInitialValues.get(e),n=e._value!==null&&typeof e._value==`object`;t&&!n&&Object.is(e._value,t.value)&&(e.version=t.version,this.resetCleanState(e))}this.batchedSignals=[],this.batchInitialValues.clear(),this.flushEffects()}}}resetCleanState(e){let t=e.subscribersHead;for(;t!==null;){let e=t.target;e.state>0&&!this.checkNeedsUpdate(e)&&(e.state=0,this.resetCleanState(e)),t=t.nextSubscriber}}untrack(e){let t=this.activeConsumer;this.activeConsumer=null;try{return e()}finally{this.activeConsumer=t}}flushEffects(){this.batchDepth===0&&this.scheduler.flush(this)}trackNode(e,t){let n=t.dependenciesHead;for(;n!==null;){if(n.source===e){n.version=e.version;return}n=n.nextDependency}let r=u.acquire(e,t);r.version=e.version,t.depth<=e.depth&&(t.depth=e.depth+1),e.subscribersTail===null?(e.subscribersHead=r,e.subscribersTail=r):(e.subscribersTail.nextSubscriber=r,r.prevSubscriber=e.subscribersTail,e.subscribersTail=r),t.dependenciesTail===null?(t.dependenciesHead=r,t.dependenciesTail=r):(t.dependenciesTail.nextDependency=r,r.prevDependency=t.dependenciesTail,t.dependenciesTail=r)}unlinkDependencies(e,t=!1){let n=e.dependenciesHead;for(e.dependenciesHead=null,e.dependenciesTail=null;n!==null;){let r=n.nextDependency,i=n.source;n.prevSubscriber===null?i.subscribersHead=n.nextSubscriber:n.prevSubscriber.nextSubscriber=n.nextSubscriber,n.nextSubscriber===null?i.subscribersTail=n.prevSubscriber:n.nextSubscriber.prevSubscriber=n.prevSubscriber,u.release(n),t&&e.isDisposed&&e.type===`computed`&&i.type===`computed`&&i.subscribersHead===null&&this.disposeNode(i),n=r}}checkNeedsUpdate(e){let t=e.dependenciesHead;for(;t!==null;){let e=t.source;if(e.state===1&&(this.checkNeedsUpdate(e)?e.state=2:e.state=0),e.state===2&&this.evaluateComputed(e),t.version!==e.version)return t.version=e.version,!0;t=t.nextDependency}return!1}evaluateComputed(e){if(e.ownedEffects.size>0){let t=Array.from(e.ownedEffects);e.ownedEffects.clear();for(let e of t)this.disposeNode(e)}this.unlinkDependencies(e,!1);let t=this.activeConsumer,n=this.currentOwner;this.activeConsumer=e,this.currentOwner=e;let r=e._value;try{let t=e.fn();Object.is(e._value,t)||(e._value=t,e.version++),e.state=0,this.log({type:`computed`,label:e.id,details:{from:r,to:e._value}})}finally{this.activeConsumer=t,this.currentOwner=n}}executeCleanups(e){if(e.cleanups.size===0)return;let t=Array.from(e.cleanups);e.cleanups.clear();let n=null;for(let e of t)try{this.untrack(()=>e())}catch(e){n===null&&(n=e)}if(n!==null)throw n}runEffectNode(e){if(e.isDisposed)return;if(e.ownedEffects.size>0){let t=Array.from(e.ownedEffects);e.ownedEffects.clear();for(let e of t)this.disposeNode(e)}try{this.executeCleanups(e)}catch(t){throw e.state=0,t}this.unlinkDependencies(e,!1);let t=this.activeConsumer,n=this.currentOwner;this.activeConsumer=e,this.currentOwner=e;try{e.fn(),e.state=0}finally{this.activeConsumer=t,this.currentOwner=n,e.isDisposed&&this.unlinkDependencies(e,!0)}}disposeNode(e){if(e.isDisposed)return;if(e.isDisposed=!0,e.state=0,e.ownedEffects.size>0){let t=Array.from(e.ownedEffects);e.ownedEffects.clear();for(let e of t)this.disposeNode(e)}try{this.executeCleanups(e)}catch{}this.unlinkDependencies(e,!0);let t=e.subscribersHead;for(e.subscribersHead=null,e.subscribersTail=null;t!==null;){let e=t.nextSubscriber,n=t.target;n&&(t.prevDependency===null?n.dependenciesHead=t.nextDependency:t.prevDependency.nextDependency=t.nextDependency,t.nextDependency===null?n.dependenciesTail=t.prevDependency:t.nextDependency.prevDependency=t.prevDependency),u.release(t),t=e}}reactive(e,t){return s(this,e,t)}delay(e,t){return new Promise((n,r)=>{if(t.aborted)return r(new DOMException(`Aborted`,`AbortError`));let i=setTimeout(()=>{t.removeEventListener(`abort`,a),n()},e),a=()=>{clearTimeout(i),r(new DOMException(`Aborted`,`AbortError`))};t.addEventListener(`abort`,a,{once:!0})})}provide(e,t){this.diRegistry.set(e,t),this.diCache.delete(e)}inject(e){if(e==null)throw Error(`[DI Error] Token is empty`);if(this.diCache.has(e))return this.diCache.get(e);if(this.cycleDetectionStack.has(e))throw Error(`[DI Error] Cyclic dependency detected`);this.cycleDetectionStack.add(e);try{if(this.diRegistry.has(e)){let t=this.diRegistry.get(e);if(typeof t==`function`){if(t._isMockFunction){let n=t(this);return n===void 0?t:(this.diCache.set(e,n),n)}let n=t.toString();if(!(n.startsWith(`class `)||n.startsWith(`class{`)||t.prototype&&t.prototype.constructor===t&&!n.startsWith(`function`)&&!n.includes(`=>`))){let n=t(this);return this.diCache.set(e,n),n}return t}return t}if(typeof e==`function`){let t=new e(this);return this.diCache.set(e,t),t}throw Error(`[DI Error] Token not found`)}finally{this.cycleDetectionStack.delete(e)}}},m=new p,h=class extends p{},g=class extends h{autoLogQueue=[];isHardFlushScheduled=!1;queueLog(e,t,n){this.autoLogQueue.push({type:e,name:t,meta:n,timestamp:Date.now()}),this.isHardFlushScheduled||(this.isHardFlushScheduled=!0,queueMicrotask(()=>this.flushLogs()))}flushLogs(){this.isHardFlushScheduled=!1,this.autoLogQueue.length!==0&&(typeof process<`u`&&process.env.NODE_ENV!==`test`&&(console.group(`📊 [Autolog] Срез транзакций: ${this.autoLogQueue.length} операций`),this.autoLogQueue.forEach(e=>console.log(`[${e.type.toUpperCase()}] ${e.name}`,e.meta||``)),console.groupEnd()),this.autoLogQueue=[])}computed(e,t){let n=this,r=t||`unnamed_computed`,i=super.computed(e,t),a=!1,o={get value(){if(a)return i.value;let e=typeof performance<`u`?performance.now():0,t=i.value;return e&&n.queueLog(`computed`,r,{value:t,duration:`${(performance.now()-e).toFixed(3)}ms`}),t},subscribe:e=>i.subscribe(e),destroy(){a=!0,i.destroy()}};return`_node`in i&&Object.defineProperty(o,"_node",{value:i._node,enumerable:!1}),o}};function _(e,t){if(!m)throw Error(`[Reactive Engine v3] Global engine instance is not initialized.`);return m.signal(e,t)}function v(e,t){if(!m)throw Error(`[Reactive Engine v3] Global engine instance is not initialized.`);return m.computed(e,t)}function y(e,t){if(!m)throw Error(`[Reactive Engine v3] Global engine instance is not initialized.`);return m.effect(e,t)}function b(e){if(!m)throw Error(`[Reactive Engine v3] Global engine instance is not initialized.`);return m.batch(e)}function x(e){if(!m)throw Error(`[Reactive Engine v3] Global engine instance is not initialized.`);return m.untrack(e)}function S(e,t){if(!m)throw Error(`[Reactive Engine v3] Global engine instance is not initialized.`);m.provide(e,t)}function C(e){if(!m)throw Error(`[Reactive Engine v3] Global engine instance is not initialized.`);return m.inject(e)}var w=class{engine;constructor(e){this.engine=e,this.onInit()}createNumericSignal(e,t){return this.engine.signal(e,{name:t,validate:e=>typeof e==`number`&&!isNaN(e)})}createComputed(e){return this.engine.computed(e)}createSignal(e,t){return this.engine.signal(e,t)}onInit(){}},T=w,E=class{engine;constructor(e){this.engine=e,setTimeout(()=>this.onInit(),0)}onInit(){}};e.AbstractService=w,e.BaseREService=T,e.BaseREServiceEnhanced=E,e.EffectScheduler=f,e.LinkPool=u,e.NodeLink=l,e.ReactiveEngine=h,e.ReactiveEngineAutolog=g,e.ReactiveEngineAutomatic=p,e.ReactiveEngineCore=p,e.ReactiveNode=d,e.batch=b,e.computed=v,Object.defineProperty(e,"currentEngineInstance",{enumerable:!0,get:function(){return m}}),e.effect=y,e.inject=C,e.provide=S,e.signal=_,e.untrack=x});
|
|
13
13
|
//# sourceMappingURL=reactive-engine.umd.js.map
|