@pravosleva/reactive-engine 1.6.1 → 1.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/angular/ReactiveEngine4Angular.cjs +1 -1
- package/dist/angular/ReactiveEngine4Angular.cjs.map +1 -1
- package/dist/angular/ReactiveEngine4Angular.d.ts +16 -10
- package/dist/angular/ReactiveEngine4Angular.d.ts.map +1 -1
- package/dist/angular/ReactiveEngine4Angular.mjs +29 -5
- package/dist/angular/ReactiveEngine4Angular.mjs.map +1 -1
- package/dist/core/core.d.ts.map +1 -1
- package/dist/core.cjs +1 -1
- package/dist/core.cjs.map +1 -1
- package/dist/core.mjs +56 -27
- package/dist/core.mjs.map +1 -1
- package/dist/decorators/withStaleWhileRevalidate/withStaleWhileRevalidate.cjs +1 -1
- package/dist/decorators/withStaleWhileRevalidate/withStaleWhileRevalidate.cjs.map +1 -1
- package/dist/decorators/withStaleWhileRevalidate/withStaleWhileRevalidate.d.ts +7 -25
- package/dist/decorators/withStaleWhileRevalidate/withStaleWhileRevalidate.d.ts.map +1 -1
- package/dist/decorators/withStaleWhileRevalidate/withStaleWhileRevalidate.mjs +23 -8
- package/dist/decorators/withStaleWhileRevalidate/withStaleWhileRevalidate.mjs.map +1 -1
- package/dist/react/ReactiveEngine4React.cjs +1 -4
- package/dist/react/ReactiveEngine4React.cjs.map +1 -1
- package/dist/react/ReactiveEngine4React.d.ts +7 -5
- package/dist/react/ReactiveEngine4React.d.ts.map +1 -1
- package/dist/react/ReactiveEngine4React.mjs +25 -17
- package/dist/react/ReactiveEngine4React.mjs.map +1 -1
- package/dist/react/hooks/types.d.ts +4 -0
- package/dist/react/hooks/types.d.ts.map +1 -1
- package/dist/react/hooks/useReactiveSubscription/useReactiveSubscription.cjs +1 -1
- package/dist/react/hooks/useReactiveSubscription/useReactiveSubscription.cjs.map +1 -1
- package/dist/react/hooks/useReactiveSubscription/useReactiveSubscription.d.ts +4 -10
- package/dist/react/hooks/useReactiveSubscription/useReactiveSubscription.d.ts.map +1 -1
- package/dist/react/hooks/useReactiveSubscription/useReactiveSubscription.mjs +20 -11
- package/dist/react/hooks/useReactiveSubscription/useReactiveSubscription.mjs.map +1 -1
- package/dist/react/hooks/useReactiveValue/useReactiveValue.cjs +1 -1
- package/dist/react/hooks/useReactiveValue/useReactiveValue.cjs.map +1 -1
- package/dist/react/hooks/useReactiveValue/useReactiveValue.d.ts +10 -41
- package/dist/react/hooks/useReactiveValue/useReactiveValue.d.ts.map +1 -1
- package/dist/react/hooks/useReactiveValue/useReactiveValue.mjs +19 -10
- package/dist/react/hooks/useReactiveValue/useReactiveValue.mjs.map +1 -1
- package/dist/reactive-engine.umd.js +2 -2
- package/dist/reactive-engine.umd.js.map +1 -1
- package/dist/vue/ReactiveEngine4Vue.cjs +1 -1
- package/dist/vue/ReactiveEngine4Vue.cjs.map +1 -1
- package/dist/vue/ReactiveEngine4Vue.d.ts +21 -6
- package/dist/vue/ReactiveEngine4Vue.d.ts.map +1 -1
- package/dist/vue/ReactiveEngine4Vue.mjs +31 -8
- package/dist/vue/ReactiveEngine4Vue.mjs.map +1 -1
- package/dist/vue/composables/useReactiveValue.cjs +1 -1
- package/dist/vue/composables/useReactiveValue.cjs.map +1 -1
- package/dist/vue/composables/useReactiveValue.d.ts +4 -45
- package/dist/vue/composables/useReactiveValue.d.ts.map +1 -1
- package/dist/vue/composables/useReactiveValue.mjs +10 -5
- package/dist/vue/composables/useReactiveValue.mjs.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ReactiveEngine4React.cjs","names":[],"sources":["../../src/react/ReactiveEngine4React.ts"],"sourcesContent":["import { useState as useStateFromReact, useEffect as useEffectFromReact } from 'react'\nimport { ReactiveEngine as OriginalReactiveEngine, CleanupFn } from '../core/core'\n\
|
|
1
|
+
{"version":3,"file":"ReactiveEngine4React.cjs","names":[],"sources":["../../src/react/ReactiveEngine4React.ts"],"sourcesContent":["import { useState as useStateFromReact, useEffect as useEffectFromReact } from 'react'\nimport { ReactiveEngine as OriginalReactiveEngine, type CleanupFn } from '../core/core'\n\nexport interface ISignalLike<V> {\n value: V;\n subscribe: (cb: (v: V) => void) => CleanupFn;\n}\n\n/**\n * Класс адаптера для интеграции реактивного движка с React.\n * Предоставляет полиморфные методы для бесшовной работы с Сигналами и Proxy-объектами.\n */\nexport class ReactiveEngine4React extends OriginalReactiveEngine {\n protected override frameworkPrefix = 'react'\n\n private reactAdapters: {\n useState: typeof useStateFromReact;\n useEffect: typeof useEffectFromReact;\n } = {\n useState: useStateFromReact,\n useEffect: useEffectFromReact,\n }\n\n public setReactAdapters(\n useState: typeof useStateFromReact,\n useEffect: typeof useEffectFromReact\n ): void {\n this.reactAdapters = { useState, useEffect }\n }\n\n /**\n * Переопределяем метод создания реактивных объектов для React-версии движка.\n * Безопасно внедряет скрытое свойство __subscribe в оригинальный граф без double-proxying.\n */\n public override reactive<T extends object>(target: T, name?: string): T {\n if (!Reflect.has(target, '__subscribe')) {\n Object.defineProperty(target, '__subscribe', {\n get: () => {\n return (cb: () => void) => {\n return this.effect(() => {\n try {\n JSON.stringify(originalProxy) // Глубокий прогрев геттеров ядра\n } catch (e) {\n Object.values(originalProxy as Record<string, unknown>)\n }\n cb() // Пинаем колбэк хука React\n }, 'react-proxy-internal-subscription')\n }\n },\n configurable: true,\n enumerable: false\n })\n }\n\n const originalProxy = super.reactive(target, name)\n return originalProxy\n }\n\n /**\n * Использование реактивного значения в React-компоненте.\n * Полиморфно поддерживает как атомарные Сигналы/Computed, так и глубокие реактивные Proxy-объекты.\n */\n public use<T>(item: T): T extends ISignalLike<infer V> ? V : T {\n if (!this.reactAdapters) {\n throw new Error(\"[React Error]: Адаптеры React не установлены. Вызовите engine.setReactAdapters(useState, useEffect).\")\n }\n\n if (item === null || item === undefined || typeof item !== 'object') {\n return item as any\n }\n\n const isSignal = 'subscribe' in item && typeof (item as Record<string, unknown>).subscribe === 'function'\n\n // 1. Сценарий А: Передан примитивный Сигнал или Computed\n if (isSignal) {\n const signalItem = (item as unknown) as ISignalLike<unknown>\n const [val, setVal] = this.reactAdapters.useState<unknown>(signalItem.value)\n\n this.reactAdapters.useEffect(\n () => {\n return signalItem.subscribe(setVal)\n },\n [signalItem]\n )\n\n return val as (T extends ISignalLike<infer V> ? V : T)\n }\n\n // 2. Сценарий Б: Передан Proxy-объект из метода reactive()\n const [, forceUpdate] = this.reactAdapters.useState<unknown[]>([])\n\n if ('__subscribe' in item && typeof (item as Record<string, unknown>).__subscribe === 'function') {\n this.reactAdapters.useEffect(() => {\n const unsubscribe = ((item as Record<string, unknown>).__subscribe as (cb: () => void) => CleanupFn)(() => {\n forceUpdate([]) // Триггерим асинхронный авто-батчинг ререндера React\n })\n return () => unsubscribe()\n }, [item])\n }\n\n return item as (T extends ISignalLike<infer V> ? V : T)\n }\n}\n"],"mappings":"sDAYA,IAAa,EAAb,cAA0C,EAAA,cAAuB,CAC/D,gBAAqC,QAErC,cAGI,CACA,SAAU,EAAA,SACV,UAAW,EAAA,SACb,EAEF,iBACE,EACA,EACM,CACN,KAAK,cAAgB,CAAE,WAAU,WAAU,CAC7C,CAMA,SAA2C,EAAW,EAAkB,CACjE,QAAQ,IAAI,EAAQ,aAAa,GACpC,OAAO,eAAe,EAAQ,cAAe,CAC3C,QACU,GACC,KAAK,WAAa,CACvB,GAAI,CACF,KAAK,UAAU,CAAa,CAC9B,MAAY,CACV,OAAO,OAAO,CAAwC,CACxD,CACA,EAAG,CACL,EAAG,mCAAmC,EAG1C,aAAc,GACd,WAAY,EACd,CAAC,EAGH,IAAM,EAAgB,MAAM,SAAS,EAAQ,CAAI,EACjD,OAAO,CACT,CAMA,IAAc,EAAiD,CAC7D,GAAI,CAAC,KAAK,cACR,MAAU,MAAM,sGAAsG,EAGxH,GAA2C,OAAO,GAAS,WAAvD,EACF,OAAO,EAMT,GAHiB,cAAe,GAAQ,OAAQ,EAAiC,WAAc,WAGjF,CACZ,IAAM,EAAc,EACd,CAAC,EAAK,GAAU,KAAK,cAAc,SAAkB,EAAW,KAAK,EAS3E,OAPA,KAAK,cAAc,cAER,EAAW,UAAU,CAAM,EAEpC,CAAC,CAAU,CACb,EAEO,CACT,CAGA,GAAM,EAAG,GAAe,KAAK,cAAc,SAAoB,CAAC,CAAC,EAWjE,MATI,gBAAiB,GAAQ,OAAQ,EAAiC,aAAgB,YACpF,KAAK,cAAc,cAAgB,CACjC,IAAM,EAAgB,EAAiC,gBAAoD,CACzG,EAAY,CAAC,CAAC,CAChB,CAAC,EACD,UAAa,EAAY,CAC3B,EAAG,CAAC,CAAI,CAAC,EAGJ,CACT,CACF"}
|
|
@@ -6,18 +6,20 @@ export interface ISignalLike<V> {
|
|
|
6
6
|
}
|
|
7
7
|
/**
|
|
8
8
|
* Класс адаптера для интеграции реактивного движка с React.
|
|
9
|
+
* Предоставляет полиморфные методы для бесшовной работы с Сигналами и Proxy-объектами.
|
|
9
10
|
*/
|
|
10
11
|
export declare class ReactiveEngine4React extends OriginalReactiveEngine {
|
|
11
12
|
protected frameworkPrefix: string;
|
|
12
13
|
private reactAdapters;
|
|
13
14
|
setReactAdapters(useState: typeof useStateFromReact, useEffect: typeof useEffectFromReact): void;
|
|
15
|
+
/**
|
|
16
|
+
* Переопределяем метод создания реактивных объектов для React-версии движка.
|
|
17
|
+
* Безопасно внедряет скрытое свойство __subscribe в оригинальный граф без double-proxying.
|
|
18
|
+
*/
|
|
19
|
+
reactive<T extends object>(target: T, name?: string): T;
|
|
14
20
|
/**
|
|
15
21
|
* Использование реактивного значения в React-компоненте.
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
* @template T
|
|
19
|
-
* @param {T} item - Реактивный объект (сигнал или прокси)
|
|
20
|
-
* @returns {T extends ISignalLike<infer V> ? V : T} - Развернутое значение или сам прокси-объект
|
|
22
|
+
* Полиморфно поддерживает как атомарные Сигналы/Computed, так и глубокие реактивные Proxy-объекты.
|
|
21
23
|
*/
|
|
22
24
|
use<T>(item: T): T extends ISignalLike<infer V> ? V : T;
|
|
23
25
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ReactiveEngine4React.d.ts","sourceRoot":"","sources":["../../src/react/ReactiveEngine4React.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,IAAI,iBAAiB,EAAE,SAAS,IAAI,kBAAkB,EAAE,MAAM,OAAO,CAAA;AACtF,OAAO,EAAE,cAAc,IAAI,sBAAsB,EAAE,SAAS,EAAE,MAAM,cAAc,CAAA;
|
|
1
|
+
{"version":3,"file":"ReactiveEngine4React.d.ts","sourceRoot":"","sources":["../../src/react/ReactiveEngine4React.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,IAAI,iBAAiB,EAAE,SAAS,IAAI,kBAAkB,EAAE,MAAM,OAAO,CAAA;AACtF,OAAO,EAAE,cAAc,IAAI,sBAAsB,EAAE,KAAK,SAAS,EAAE,MAAM,cAAc,CAAA;AAEvF,MAAM,WAAW,WAAW,CAAC,CAAC;IAC5B,KAAK,EAAE,CAAC,CAAC;IACT,SAAS,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,IAAI,KAAK,SAAS,CAAC;CAC9C;AAED;;;GAGG;AACH,qBAAa,oBAAqB,SAAQ,sBAAsB;IAC9D,UAAmB,eAAe,SAAU;IAE5C,OAAO,CAAC,aAAa,CAMlB;IAEI,gBAAgB,CACrB,QAAQ,EAAE,OAAO,iBAAiB,EAClC,SAAS,EAAE,OAAO,kBAAkB,GACnC,IAAI;IAIP;;;OAGG;IACa,QAAQ,CAAC,CAAC,SAAS,MAAM,EAAE,MAAM,EAAE,CAAC,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,CAAC;IAwBvE;;;OAGG;IACI,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,GAAG,CAAC,SAAS,WAAW,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC;CAwC/D"}
|
|
@@ -13,28 +13,36 @@ var r = class extends e {
|
|
|
13
13
|
useEffect: t
|
|
14
14
|
};
|
|
15
15
|
}
|
|
16
|
+
reactive(e, t) {
|
|
17
|
+
Reflect.has(e, "__subscribe") || Object.defineProperty(e, "__subscribe", {
|
|
18
|
+
get: () => (e) => this.effect(() => {
|
|
19
|
+
try {
|
|
20
|
+
JSON.stringify(n);
|
|
21
|
+
} catch {
|
|
22
|
+
Object.values(n);
|
|
23
|
+
}
|
|
24
|
+
e();
|
|
25
|
+
}, "react-proxy-internal-subscription"),
|
|
26
|
+
configurable: !0,
|
|
27
|
+
enumerable: !1
|
|
28
|
+
});
|
|
29
|
+
let n = super.reactive(e, t);
|
|
30
|
+
return n;
|
|
31
|
+
}
|
|
16
32
|
use(e) {
|
|
17
33
|
if (!this.reactAdapters) throw Error("[React Error]: Адаптеры React не установлены. Вызовите engine.setReactAdapters(useState, useEffect).");
|
|
18
|
-
if (
|
|
34
|
+
if (typeof e != "object" || !e) return e;
|
|
35
|
+
if ("subscribe" in e && typeof e.subscribe == "function") {
|
|
19
36
|
let t = e, [n, r] = this.reactAdapters.useState(t.value);
|
|
20
37
|
return this.reactAdapters.useEffect(() => t.subscribe(r), [t]), n;
|
|
21
38
|
}
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
Object.values(e);
|
|
30
|
-
}
|
|
31
|
-
t([]);
|
|
32
|
-
}, "react-use-reactive-proxy");
|
|
33
|
-
return () => n();
|
|
34
|
-
}, [e]), e;
|
|
35
|
-
}
|
|
36
|
-
let t = "\n [Reactive Error]: engine.use() получил некорректный объект!\n Проверьте, что передаваемый инстанс является Сигналом или создан через engine.reactive().\n ";
|
|
37
|
-
throw console.error(t, { item: e }), Error(t);
|
|
39
|
+
let [, t] = this.reactAdapters.useState([]);
|
|
40
|
+
return "__subscribe" in e && typeof e.__subscribe == "function" && this.reactAdapters.useEffect(() => {
|
|
41
|
+
let n = e.__subscribe(() => {
|
|
42
|
+
t([]);
|
|
43
|
+
});
|
|
44
|
+
return () => n();
|
|
45
|
+
}, [e]), e;
|
|
38
46
|
}
|
|
39
47
|
};
|
|
40
48
|
//#endregion
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ReactiveEngine4React.mjs","names":[],"sources":["../../src/react/ReactiveEngine4React.ts"],"sourcesContent":["import { useState as useStateFromReact, useEffect as useEffectFromReact } from 'react'\nimport { ReactiveEngine as OriginalReactiveEngine, CleanupFn } from '../core/core'\n\
|
|
1
|
+
{"version":3,"file":"ReactiveEngine4React.mjs","names":[],"sources":["../../src/react/ReactiveEngine4React.ts"],"sourcesContent":["import { useState as useStateFromReact, useEffect as useEffectFromReact } from 'react'\nimport { ReactiveEngine as OriginalReactiveEngine, type CleanupFn } from '../core/core'\n\nexport interface ISignalLike<V> {\n value: V;\n subscribe: (cb: (v: V) => void) => CleanupFn;\n}\n\n/**\n * Класс адаптера для интеграции реактивного движка с React.\n * Предоставляет полиморфные методы для бесшовной работы с Сигналами и Proxy-объектами.\n */\nexport class ReactiveEngine4React extends OriginalReactiveEngine {\n protected override frameworkPrefix = 'react'\n\n private reactAdapters: {\n useState: typeof useStateFromReact;\n useEffect: typeof useEffectFromReact;\n } = {\n useState: useStateFromReact,\n useEffect: useEffectFromReact,\n }\n\n public setReactAdapters(\n useState: typeof useStateFromReact,\n useEffect: typeof useEffectFromReact\n ): void {\n this.reactAdapters = { useState, useEffect }\n }\n\n /**\n * Переопределяем метод создания реактивных объектов для React-версии движка.\n * Безопасно внедряет скрытое свойство __subscribe в оригинальный граф без double-proxying.\n */\n public override reactive<T extends object>(target: T, name?: string): T {\n if (!Reflect.has(target, '__subscribe')) {\n Object.defineProperty(target, '__subscribe', {\n get: () => {\n return (cb: () => void) => {\n return this.effect(() => {\n try {\n JSON.stringify(originalProxy) // Глубокий прогрев геттеров ядра\n } catch (e) {\n Object.values(originalProxy as Record<string, unknown>)\n }\n cb() // Пинаем колбэк хука React\n }, 'react-proxy-internal-subscription')\n }\n },\n configurable: true,\n enumerable: false\n })\n }\n\n const originalProxy = super.reactive(target, name)\n return originalProxy\n }\n\n /**\n * Использование реактивного значения в React-компоненте.\n * Полиморфно поддерживает как атомарные Сигналы/Computed, так и глубокие реактивные Proxy-объекты.\n */\n public use<T>(item: T): T extends ISignalLike<infer V> ? V : T {\n if (!this.reactAdapters) {\n throw new Error(\"[React Error]: Адаптеры React не установлены. Вызовите engine.setReactAdapters(useState, useEffect).\")\n }\n\n if (item === null || item === undefined || typeof item !== 'object') {\n return item as any\n }\n\n const isSignal = 'subscribe' in item && typeof (item as Record<string, unknown>).subscribe === 'function'\n\n // 1. Сценарий А: Передан примитивный Сигнал или Computed\n if (isSignal) {\n const signalItem = (item as unknown) as ISignalLike<unknown>\n const [val, setVal] = this.reactAdapters.useState<unknown>(signalItem.value)\n\n this.reactAdapters.useEffect(\n () => {\n return signalItem.subscribe(setVal)\n },\n [signalItem]\n )\n\n return val as (T extends ISignalLike<infer V> ? V : T)\n }\n\n // 2. Сценарий Б: Передан Proxy-объект из метода reactive()\n const [, forceUpdate] = this.reactAdapters.useState<unknown[]>([])\n\n if ('__subscribe' in item && typeof (item as Record<string, unknown>).__subscribe === 'function') {\n this.reactAdapters.useEffect(() => {\n const unsubscribe = ((item as Record<string, unknown>).__subscribe as (cb: () => void) => CleanupFn)(() => {\n forceUpdate([]) // Триггерим асинхронный авто-батчинг ререндера React\n })\n return () => unsubscribe()\n }, [item])\n }\n\n return item as (T extends ISignalLike<infer V> ? V : T)\n }\n}\n"],"mappings":";;;AAYA,IAAa,IAAb,cAA0C,EAAuB;CAC/D,kBAAqC;CAErC,gBAGI;EACU;EACC;CACb;CAEF,iBACE,GACA,GACM;EACN,KAAK,gBAAgB;GAAE;GAAU;EAAU;CAC7C;CAMA,SAA2C,GAAW,GAAkB;EACtE,AAAK,QAAQ,IAAI,GAAQ,aAAa,KACpC,OAAO,eAAe,GAAQ,eAAe;GAC3C,YACU,MACC,KAAK,aAAa;IACvB,IAAI;KACF,KAAK,UAAU,CAAa;IAC9B,QAAY;KACV,OAAO,OAAO,CAAwC;IACxD;IACA,EAAG;GACL,GAAG,mCAAmC;GAG1C,cAAc;GACd,YAAY;EACd,CAAC;EAGH,IAAM,IAAgB,MAAM,SAAS,GAAQ,CAAI;EACjD,OAAO;CACT;CAMA,IAAc,GAAiD;EAC7D,IAAI,CAAC,KAAK,eACR,MAAU,MAAM,sGAAsG;EAGxH,IAA2C,OAAO,KAAS,aAAvD,GACF,OAAO;EAMT,IAHiB,eAAe,KAAQ,OAAQ,EAAiC,aAAc,YAGjF;GACZ,IAAM,IAAc,GACd,CAAC,GAAK,KAAU,KAAK,cAAc,SAAkB,EAAW,KAAK;GAS3E,OAPA,KAAK,cAAc,gBAER,EAAW,UAAU,CAAM,GAEpC,CAAC,CAAU,CACb,GAEO;EACT;EAGA,IAAM,GAAG,KAAe,KAAK,cAAc,SAAoB,CAAC,CAAC;EAWjE,OATI,iBAAiB,KAAQ,OAAQ,EAAiC,eAAgB,cACpF,KAAK,cAAc,gBAAgB;GACjC,IAAM,IAAgB,EAAiC,kBAAoD;IACzG,EAAY,CAAC,CAAC;GAChB,CAAC;GACD,aAAa,EAAY;EAC3B,GAAG,CAAC,CAAI,CAAC,GAGJ;CACT;AACF"}
|
|
@@ -13,4 +13,8 @@ export interface ObservableItem<T> {
|
|
|
13
13
|
* либо функцию-фабрику, которая его лениво возвращает.
|
|
14
14
|
*/
|
|
15
15
|
export type ReactiveInput<T> = ObservableItem<T> | (() => ObservableItem<T>);
|
|
16
|
+
export interface ISignalLike<V> {
|
|
17
|
+
value: V;
|
|
18
|
+
subscribe: (cb: (v: V) => void) => CleanupFn;
|
|
19
|
+
}
|
|
16
20
|
//# sourceMappingURL=types.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/react/hooks/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/react/hooks/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAA;AAEtC;;;GAGG;AACH,MAAM,WAAW,cAAc,CAAC,CAAC;IAC/B,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAC;IAClB,SAAS,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,EAAE,CAAC,KAAK,IAAI,KAAK,SAAS,CAAC;IAC/C,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;CACtB;AAED;;;GAGG;AACH,MAAM,MAAM,aAAa,CAAC,CAAC,IAAI,cAAc,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC;AAE7E,MAAM,WAAW,WAAW,CAAC,CAAC;IAC5B,KAAK,EAAE,CAAC,CAAC;IACT,SAAS,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,IAAI,KAAK,SAAS,CAAC;CAC9C"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
let e=require("react");
|
|
1
|
+
let e=require("react");function t(t,n){let r=(0,e.useRef)(n);(0,e.useEffect)(()=>{r.current=n},[n]),(0,e.useEffect)(()=>{if(!(!t||typeof t!=`object`)){if(`subscribe`in t&&typeof t.subscribe==`function`){let e=t.subscribe(e=>{r.current(e)});return()=>e()}if(`__subscribe`in t&&typeof t.__subscribe==`function`){let e=t.__subscribe(()=>{r.current(t)});return()=>e()}}},[t])}exports.useReactiveSubscription=t;
|
|
2
2
|
//# sourceMappingURL=useReactiveSubscription.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useReactiveSubscription.cjs","names":[],"sources":["../../../../src/react/hooks/useReactiveSubscription/useReactiveSubscription.ts"],"sourcesContent":["import {
|
|
1
|
+
{"version":3,"file":"useReactiveSubscription.cjs","names":[],"sources":["../../../../src/react/hooks/useReactiveSubscription/useReactiveSubscription.ts"],"sourcesContent":["import { useEffect, useRef } from 'react'\nimport { ISignalLike } from '../types'\n\ntype CleanupFn = () => void\n\n/**\n * Универсальный хук подписки на реактивные источники ядра для React.\n * Полиморфно поддерживает как примитивные Сигналы/Computed, так и Proxy-объекты reactive().\n */\nexport function useReactiveSubscription<T>(\n item: T,\n callback: (val: T extends ISignalLike<infer V> ? V : T) => void\n): void {\n // Сохраняем ссылку на актуальный колбэк, чтобы защитить от лишних переподписок\n const callbackRef = useRef(callback)\n\n useEffect(() => {\n callbackRef.current = callback\n }, [callback])\n\n useEffect(() => {\n if (!item || typeof item !== 'object') return\n\n // 1. Сценарий А: У объекта есть нативный метод подписки .subscribe (Сигнал / Computed)\n if ('subscribe' in item && typeof (item as Record<string, unknown>).subscribe === 'function') {\n const signalItem = (item as unknown) as ISignalLike<unknown>\n\n const unsubscribe = signalItem.subscribe((newValue) => {\n callbackRef.current(newValue as any)\n })\n\n return () => unsubscribe()\n }\n\n // 2. Сценарий Б: Передан Proxy-объект (используем служебный геттер фреймворк-адаптеров)\n if ('__subscribe' in item && typeof (item as Record<string, unknown>).__subscribe === 'function') {\n const unsubscribe = ((item as Record<string, unknown>).__subscribe as (cb: () => void) => CleanupFn)(() => {\n // При мутации свойств или массивов Proxy пинаем колбэк с актуальным состоянием объекта\n callbackRef.current(item as any)\n })\n\n return () => unsubscribe()\n }\n }, [item])\n}\n"],"mappings":"uBASA,SAAgB,EACd,EACA,EACM,CAEN,IAAM,GAAA,EAAA,EAAA,OAAA,CAAqB,CAAQ,GAEnC,EAAA,EAAA,UAAA,KAAgB,CACd,EAAY,QAAU,CACxB,EAAG,CAAC,CAAQ,CAAC,GAEb,EAAA,EAAA,UAAA,KAAgB,CACV,MAAC,GAAQ,OAAO,GAAS,UAG7B,IAAI,cAAe,GAAQ,OAAQ,EAAiC,WAAc,WAAY,CAG5F,IAAM,EAAc,EAAW,UAAW,GAAa,CACrD,EAAY,QAAQ,CAAe,CACrC,CAAC,EAED,UAAa,EAAY,CAC3B,CAGA,GAAI,gBAAiB,GAAQ,OAAQ,EAAiC,aAAgB,WAAY,CAChG,IAAM,EAAgB,EAAiC,gBAAoD,CAEzG,EAAY,QAAQ,CAAW,CACjC,CAAC,EAED,UAAa,EAAY,CAC3B,CAVA,CAWF,EAAG,CAAC,CAAI,CAAC,CACX"}
|
|
@@ -1,13 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ISignalLike } from '../types';
|
|
2
2
|
/**
|
|
3
|
-
* Универсальный хук
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* @template T Тип данных внутри реактивного контейнера
|
|
7
|
-
* @param {Pick<Signal<T>, 'subscribe'>} signal Объект подписки (Signal/Computed/Resource)
|
|
8
|
-
* @param {(val: T) => void} callback Функция обратного вызова, принимающая новое значение
|
|
9
|
-
* @returns {void}
|
|
10
|
-
* @source
|
|
3
|
+
* Универсальный хук подписки на реактивные источники ядра для React.
|
|
4
|
+
* Полиморфно поддерживает как примитивные Сигналы/Computed, так и Proxy-объекты reactive().
|
|
11
5
|
*/
|
|
12
|
-
export declare
|
|
6
|
+
export declare function useReactiveSubscription<T>(item: T, callback: (val: T extends ISignalLike<infer V> ? V : T) => void): void;
|
|
13
7
|
//# sourceMappingURL=useReactiveSubscription.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useReactiveSubscription.d.ts","sourceRoot":"","sources":["../../../../src/react/hooks/useReactiveSubscription/useReactiveSubscription.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"useReactiveSubscription.d.ts","sourceRoot":"","sources":["../../../../src/react/hooks/useReactiveSubscription/useReactiveSubscription.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,UAAU,CAAA;AAItC;;;GAGG;AACH,wBAAgB,uBAAuB,CAAC,CAAC,EACvC,IAAI,EAAE,CAAC,EACP,QAAQ,EAAE,CAAC,GAAG,EAAE,CAAC,SAAS,WAAW,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,IAAI,GAC9D,IAAI,CAgCN"}
|
|
@@ -1,17 +1,26 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { useEffect as e, useRef as t } from "react";
|
|
2
2
|
//#region src/react/hooks/useReactiveSubscription/useReactiveSubscription.ts
|
|
3
|
-
|
|
3
|
+
function n(n, r) {
|
|
4
4
|
let i = t(r);
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
5
|
+
e(() => {
|
|
6
|
+
i.current = r;
|
|
7
|
+
}, [r]), e(() => {
|
|
8
|
+
if (!(!n || typeof n != "object")) {
|
|
9
|
+
if ("subscribe" in n && typeof n.subscribe == "function") {
|
|
10
|
+
let e = n.subscribe((e) => {
|
|
11
|
+
i.current(e);
|
|
12
|
+
});
|
|
13
|
+
return () => e();
|
|
14
|
+
}
|
|
15
|
+
if ("__subscribe" in n && typeof n.__subscribe == "function") {
|
|
16
|
+
let e = n.__subscribe(() => {
|
|
17
|
+
i.current(n);
|
|
18
|
+
});
|
|
19
|
+
return () => e();
|
|
20
|
+
}
|
|
21
|
+
}
|
|
13
22
|
}, [n]);
|
|
14
|
-
}
|
|
23
|
+
}
|
|
15
24
|
//#endregion
|
|
16
25
|
export { n as useReactiveSubscription };
|
|
17
26
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useReactiveSubscription.mjs","names":[],"sources":["../../../../src/react/hooks/useReactiveSubscription/useReactiveSubscription.ts"],"sourcesContent":["import {
|
|
1
|
+
{"version":3,"file":"useReactiveSubscription.mjs","names":[],"sources":["../../../../src/react/hooks/useReactiveSubscription/useReactiveSubscription.ts"],"sourcesContent":["import { useEffect, useRef } from 'react'\nimport { ISignalLike } from '../types'\n\ntype CleanupFn = () => void\n\n/**\n * Универсальный хук подписки на реактивные источники ядра для React.\n * Полиморфно поддерживает как примитивные Сигналы/Computed, так и Proxy-объекты reactive().\n */\nexport function useReactiveSubscription<T>(\n item: T,\n callback: (val: T extends ISignalLike<infer V> ? V : T) => void\n): void {\n // Сохраняем ссылку на актуальный колбэк, чтобы защитить от лишних переподписок\n const callbackRef = useRef(callback)\n\n useEffect(() => {\n callbackRef.current = callback\n }, [callback])\n\n useEffect(() => {\n if (!item || typeof item !== 'object') return\n\n // 1. Сценарий А: У объекта есть нативный метод подписки .subscribe (Сигнал / Computed)\n if ('subscribe' in item && typeof (item as Record<string, unknown>).subscribe === 'function') {\n const signalItem = (item as unknown) as ISignalLike<unknown>\n\n const unsubscribe = signalItem.subscribe((newValue) => {\n callbackRef.current(newValue as any)\n })\n\n return () => unsubscribe()\n }\n\n // 2. Сценарий Б: Передан Proxy-объект (используем служебный геттер фреймворк-адаптеров)\n if ('__subscribe' in item && typeof (item as Record<string, unknown>).__subscribe === 'function') {\n const unsubscribe = ((item as Record<string, unknown>).__subscribe as (cb: () => void) => CleanupFn)(() => {\n // При мутации свойств или массивов Proxy пинаем колбэк с актуальным состоянием объекта\n callbackRef.current(item as any)\n })\n\n return () => unsubscribe()\n }\n }, [item])\n}\n"],"mappings":";;AASA,SAAgB,EACd,GACA,GACM;CAEN,IAAM,IAAc,EAAO,CAAQ;CAMnC,AAJA,QAAgB;EACd,EAAY,UAAU;CACxB,GAAG,CAAC,CAAQ,CAAC,GAEb,QAAgB;EACV,OAAC,KAAQ,OAAO,KAAS,WAG7B;OAAI,eAAe,KAAQ,OAAQ,EAAiC,aAAc,YAAY;IAG5F,IAAM,IAAc,EAAW,WAAW,MAAa;KACrD,EAAY,QAAQ,CAAe;IACrC,CAAC;IAED,aAAa,EAAY;GAC3B;GAGA,IAAI,iBAAiB,KAAQ,OAAQ,EAAiC,eAAgB,YAAY;IAChG,IAAM,IAAgB,EAAiC,kBAAoD;KAEzG,EAAY,QAAQ,CAAW;IACjC,CAAC;IAED,aAAa,EAAY;GAC3B;EAVA;CAWF,GAAG,CAAC,CAAI,CAAC;AACX"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
let e=require("react");var t=t=>{let n=typeof t==`function`,r=(0,e.useRef)(t);(0,e.useEffect)(()=>{r.current=t},[t]);let i=(0,e.useMemo)(()=>typeof t==`function`?t():t,[n?void 0:t]),a=(0,e.useCallback)(e=>i.subscribe(e),[i]),
|
|
1
|
+
let e=require("react");var t=t=>{let n=typeof t==`function`,r=(0,e.useRef)(t);(0,e.useEffect)(()=>{r.current=t},[t]);let i=(0,e.useMemo)(()=>typeof t==`function`?t():t,[n?void 0:t]),a=i&&typeof i==`object`&&`subscribe`in i&&typeof i.subscribe==`function`,o=(0,e.useCallback)(e=>a?i.subscribe(e):()=>{},[i,a]),s=(0,e.useCallback)(()=>a?i.value:i,[i,a]);if((0,e.useEffect)(()=>()=>{n&&i&&`destroy`in i&&typeof i.destroy==`function`&&i.destroy()},[i,n]),a)return(0,e.useSyncExternalStore)(o,s);let[,c]=(0,e.useState)([]);return(0,e.useEffect)(()=>{if(i&&`__subscribe`in i&&typeof i.__subscribe==`function`){let e=i.__subscribe(()=>{c([])});return()=>e()}},[i]),i};exports.useReactiveValue=t;
|
|
2
2
|
//# sourceMappingURL=useReactiveValue.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useReactiveValue.cjs","names":[],"sources":["../../../../src/react/hooks/useReactiveValue/useReactiveValue.ts"],"sourcesContent":["import { useSyncExternalStore, useCallback, useMemo, useEffect, useRef } from 'react'\
|
|
1
|
+
{"version":3,"file":"useReactiveValue.cjs","names":[],"sources":["../../../../src/react/hooks/useReactiveValue/useReactiveValue.ts"],"sourcesContent":["import { useSyncExternalStore, useCallback, useMemo, useEffect, useRef, useState } from 'react'\n\ntype CleanupFn = () => void\n\n// Описываем строгий контракт для примитивов реактивного ядра (Signals / Computed / Resources)\nexport interface ISignalLike<V> {\n readonly value: V;\n subscribe: (cb: (val: V) => void) => CleanupFn\n destroy?: () => void\n}\n\ntype ReactiveInput<T> = ISignalLike<T> | (() => ISignalLike<T>) | object | (() => object)\n\n/**\n * Нативный React-хук для извлечения текущего значения из реактивных примитивов ядра\n * (Signal, Computed, Resource) и глубоких реактивных Proxy-объектов (reactive).\n *\n * @template T - Тип входящих данных\n * @param {ReactiveInput<any>} input - Готовый реактивный элемент ядра или функция-фабрика\n * @returns {any} Актуальное синхронизированное значение элемента или сам прокси-объект\n */\nexport const useReactiveValue = <T>(input: ReactiveInput<any>): any => {\n const isFactory = typeof input === 'function'\n\n // Стабилизируем ссылку на фабрику\n const factoryRef = useRef(input)\n useEffect(() => {\n factoryRef.current = input\n }, [input])\n\n // Вычисляем целевой элемент один раз\n const reactiveItem = useMemo(() => {\n if (typeof input === 'function') {\n return input()\n }\n return input\n }, [isFactory ? undefined : input])\n\n // Определяем, является ли объект примитивом (Signal/Computed) или это Proxy-объект reactive()\n const isSignal = reactiveItem &&\n typeof reactiveItem === 'object' &&\n 'subscribe' in reactiveItem &&\n typeof (reactiveItem as Record<string, unknown>).subscribe === 'function'\n\n // ------------------------------------------------====\n // СЦЕНАРИЙ А: Работа с атомарными Сигналами / Computed (useSyncExternalStore)\n // ------------------------------------------------====\n const subscribe = useCallback(\n (reactCallback: () => void) => {\n if (isSignal) {\n return (reactiveItem as ISignalLike<unknown>).subscribe(reactCallback)\n }\n return () => {}\n },\n [reactiveItem, isSignal]\n )\n\n const getSnapshot = useCallback(() => {\n if (isSignal) {\n return (reactiveItem as ISignalLike<unknown>).value\n }\n return reactiveItem\n }, [reactiveItem, isSignal])\n\n // Безопасная очистка локальных фабрик ядра при размонтировании экрана\n useEffect(() => {\n return () => {\n if (isFactory && reactiveItem && 'destroy' in reactiveItem && typeof (reactiveItem as any).destroy === 'function') {\n (reactiveItem as any).destroy()\n }\n }\n }, [reactiveItem, isFactory])\n\n // Если это сигнал — используем Concurrent-безопасныйuseSyncExternalStore\n if (isSignal) {\n return useSyncExternalStore(subscribe, getSnapshot)\n }\n\n // ------------------------------------------------====\n // СЦЕНАРИЙ Б: Работа с глубокими Proxy-объектами / Массивами\n // ------------------------------------------------====\n // Для Proxy-объектовuseSyncExternalStore не подходит, так как у них нет .value.\n // Мы создаем локальный forceUpdate и подписываем его через скрытый геттер __subscribe адаптера\n const [, forceUpdate] = useState([])\n\n useEffect(() => {\n if (reactiveItem && '__subscribe' in reactiveItem && typeof (reactiveItem as any).__subscribe === 'function') {\n const unsubscribe = (reactiveItem as any).__subscribe(() => {\n forceUpdate([]) // Провоцируем ререндер компонента через автобатчинг микрозадач\n })\n return () => unsubscribe()\n }\n }, [reactiveItem])\n\n return reactiveItem\n}\n"],"mappings":"uBAqBA,IAAa,EAAuB,GAAmC,CACrE,IAAM,EAAY,OAAO,GAAU,WAG7B,GAAA,EAAA,EAAA,OAAA,CAAoB,CAAK,GAC/B,EAAA,EAAA,UAAA,KAAgB,CACd,EAAW,QAAU,CACvB,EAAG,CAAC,CAAK,CAAC,EAGV,IAAM,GAAA,EAAA,EAAA,QAAA,KACA,OAAO,GAAU,WACZ,EAAM,EAER,EACN,CAAC,EAAY,IAAA,GAAY,CAAK,CAAC,EAG5B,EAAW,GACA,OAAO,GAAiB,UACxB,cAAe,GACf,OAAQ,EAAyC,WAAc,WAK1E,GAAA,EAAA,EAAA,YAAA,CACH,GACK,EACM,EAAsC,UAAU,CAAa,MAE1D,CAAC,EAEhB,CAAC,EAAc,CAAQ,CACzB,EAEM,GAAA,EAAA,EAAA,YAAA,KACA,EACM,EAAsC,MAEzC,EACN,CAAC,EAAc,CAAQ,CAAC,EAY3B,IATA,EAAA,EAAA,UAAA,SACe,CACP,GAAa,GAAgB,YAAa,GAAgB,OAAQ,EAAqB,SAAY,YACrG,EAAsB,QAAQ,CAElC,EACC,CAAC,EAAc,CAAS,CAAC,EAGxB,EACF,OAAA,EAAA,EAAA,qBAAA,CAA4B,EAAW,CAAW,EAQpD,GAAM,EAAG,IAAA,EAAA,EAAA,SAAA,CAAwB,CAAC,CAAC,EAWnC,OATA,EAAA,EAAA,UAAA,KAAgB,CACd,GAAI,GAAgB,gBAAiB,GAAgB,OAAQ,EAAqB,aAAgB,WAAY,CAC5G,IAAM,EAAe,EAAqB,gBAAkB,CAC1D,EAAY,CAAC,CAAC,CAChB,CAAC,EACD,UAAa,EAAY,CAC3B,CACF,EAAG,CAAC,CAAY,CAAC,EAEV,CACT"}
|
|
@@ -1,49 +1,18 @@
|
|
|
1
|
-
|
|
2
|
-
interface
|
|
3
|
-
readonly value:
|
|
4
|
-
subscribe: (cb: (val:
|
|
1
|
+
type CleanupFn = () => void;
|
|
2
|
+
export interface ISignalLike<V> {
|
|
3
|
+
readonly value: V;
|
|
4
|
+
subscribe: (cb: (val: V) => void) => CleanupFn;
|
|
5
5
|
destroy?: () => void;
|
|
6
6
|
}
|
|
7
|
-
type ReactiveInput<T> =
|
|
7
|
+
type ReactiveInput<T> = ISignalLike<T> | (() => ISignalLike<T>) | object | (() => object);
|
|
8
8
|
/**
|
|
9
9
|
* Нативный React-хук для извлечения текущего значения из реактивных примитивов ядра
|
|
10
|
-
* (Signal, Computed, Resource) и
|
|
10
|
+
* (Signal, Computed, Resource) и глубоких реактивных Proxy-объектов (reactive).
|
|
11
11
|
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
* ### Особенности управления памятью:
|
|
16
|
-
* 1. **Глобальные сигналы (Сервисы/Синглтоны):** При размонтировании компонента хук выполняет
|
|
17
|
-
* только стандартную отписку от обновлений. Метод `.destroy()` **не вызывается**,
|
|
18
|
-
* что сохраняет глобальное состояние системы в безопасности.
|
|
19
|
-
* 2. **Локальные фабрики (`() => engine.computed(...)`):** Если в качестве аргумента передана
|
|
20
|
-
* функция-фабрика, хук понимает, что вычисление создано локально для этого экрана.
|
|
21
|
-
* При анмаунте компонента хук автоматически вызовет `.destroy()`, предотвращая утечки памяти в ядре.
|
|
22
|
-
*
|
|
23
|
-
* @template T - Тип данных, инкапсулированных внутри реактивного элемента.
|
|
24
|
-
* @param {ReactiveInput<T>} input - Готовый реактивный элемент ядра или ленивая функция-фабрика, возвращающая его.
|
|
25
|
-
* @returns {T} Актуальное синхронизированное значение реактивного элемента.
|
|
26
|
-
*
|
|
27
|
-
* @example
|
|
28
|
-
* ```tsx
|
|
29
|
-
* import { useReactiveValue } from '@pravosleva/reactive-engine/react';
|
|
30
|
-
* import { userInfoService } from '~/store';
|
|
31
|
-
*
|
|
32
|
-
* // Сценарий 1: Прямая подписка на долгоживущий сигнал сервиса
|
|
33
|
-
* export const CounterDisplay = () => {
|
|
34
|
-
* const counter = useReactiveValue(userInfoService.counter);
|
|
35
|
-
* return <span>Значение: {counter}</span>;
|
|
36
|
-
* };
|
|
37
|
-
*
|
|
38
|
-
* // Сценарий 2: Использование ленивой фабрики для локальных вычислений (авто-очистка ядра при анмаунте)
|
|
39
|
-
* export const FilteredList = ({ query }: { query: string }) => {
|
|
40
|
-
* const filteredData = useReactiveValue(() =>
|
|
41
|
-
* engine.computed(() => userInfoService.list.value.filter(item => item.includes(query)))
|
|
42
|
-
* );
|
|
43
|
-
* return <ul>{filteredData.map(item => <li key={item}>{item}</li>)}</ul>;
|
|
44
|
-
* };
|
|
45
|
-
* ```
|
|
12
|
+
* @template T - Тип входящих данных
|
|
13
|
+
* @param {ReactiveInput<any>} input - Готовый реактивный элемент ядра или функция-фабрика
|
|
14
|
+
* @returns {any} Актуальное синхронизированное значение элемента или сам прокси-объект
|
|
46
15
|
*/
|
|
47
|
-
export declare const useReactiveValue: <T>(input: ReactiveInput<
|
|
16
|
+
export declare const useReactiveValue: <T>(input: ReactiveInput<any>) => any;
|
|
48
17
|
export {};
|
|
49
18
|
//# sourceMappingURL=useReactiveValue.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useReactiveValue.d.ts","sourceRoot":"","sources":["../../../../src/react/hooks/useReactiveValue/useReactiveValue.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"useReactiveValue.d.ts","sourceRoot":"","sources":["../../../../src/react/hooks/useReactiveValue/useReactiveValue.ts"],"names":[],"mappings":"AAEA,KAAK,SAAS,GAAG,MAAM,IAAI,CAAA;AAG3B,MAAM,WAAW,WAAW,CAAC,CAAC;IAC5B,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAC;IAClB,SAAS,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,EAAE,CAAC,KAAK,IAAI,KAAK,SAAS,CAAA;IAC9C,OAAO,CAAC,EAAE,MAAM,IAAI,CAAA;CACrB;AAED,KAAK,aAAa,CAAC,CAAC,IAAI,WAAW,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,WAAW,CAAC,CAAC,CAAC,CAAC,GAAG,MAAM,GAAG,CAAC,MAAM,MAAM,CAAC,CAAA;AAEzF;;;;;;;GAOG;AACH,eAAO,MAAM,gBAAgB,GAAI,CAAC,EAAE,OAAO,aAAa,CAAC,GAAG,CAAC,KAAG,GA0E/D,CAAA"}
|
|
@@ -1,16 +1,25 @@
|
|
|
1
|
-
import { useCallback as e, useEffect as t, useMemo as n, useRef as r,
|
|
1
|
+
import { useCallback as e, useEffect as t, useMemo as n, useRef as r, useState as i, useSyncExternalStore as a } from "react";
|
|
2
2
|
//#region src/react/hooks/useReactiveValue/useReactiveValue.ts
|
|
3
|
-
var
|
|
4
|
-
let
|
|
3
|
+
var o = (o) => {
|
|
4
|
+
let s = typeof o == "function", c = r(o);
|
|
5
5
|
t(() => {
|
|
6
|
-
|
|
7
|
-
}, [
|
|
8
|
-
let
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
}, [
|
|
6
|
+
c.current = o;
|
|
7
|
+
}, [o]);
|
|
8
|
+
let l = n(() => typeof o == "function" ? o() : o, [s ? void 0 : o]), u = l && typeof l == "object" && "subscribe" in l && typeof l.subscribe == "function", d = e((e) => u ? l.subscribe(e) : () => {}, [l, u]), f = e(() => u ? l.value : l, [l, u]);
|
|
9
|
+
if (t(() => () => {
|
|
10
|
+
s && l && "destroy" in l && typeof l.destroy == "function" && l.destroy();
|
|
11
|
+
}, [l, s]), u) return a(d, f);
|
|
12
|
+
let [, p] = i([]);
|
|
13
|
+
return t(() => {
|
|
14
|
+
if (l && "__subscribe" in l && typeof l.__subscribe == "function") {
|
|
15
|
+
let e = l.__subscribe(() => {
|
|
16
|
+
p([]);
|
|
17
|
+
});
|
|
18
|
+
return () => e();
|
|
19
|
+
}
|
|
20
|
+
}, [l]), l;
|
|
12
21
|
};
|
|
13
22
|
//#endregion
|
|
14
|
-
export {
|
|
23
|
+
export { o as useReactiveValue };
|
|
15
24
|
|
|
16
25
|
//# sourceMappingURL=useReactiveValue.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useReactiveValue.mjs","names":[],"sources":["../../../../src/react/hooks/useReactiveValue/useReactiveValue.ts"],"sourcesContent":["import { useSyncExternalStore, useCallback, useMemo, useEffect, useRef } from 'react'\
|
|
1
|
+
{"version":3,"file":"useReactiveValue.mjs","names":[],"sources":["../../../../src/react/hooks/useReactiveValue/useReactiveValue.ts"],"sourcesContent":["import { useSyncExternalStore, useCallback, useMemo, useEffect, useRef, useState } from 'react'\n\ntype CleanupFn = () => void\n\n// Описываем строгий контракт для примитивов реактивного ядра (Signals / Computed / Resources)\nexport interface ISignalLike<V> {\n readonly value: V;\n subscribe: (cb: (val: V) => void) => CleanupFn\n destroy?: () => void\n}\n\ntype ReactiveInput<T> = ISignalLike<T> | (() => ISignalLike<T>) | object | (() => object)\n\n/**\n * Нативный React-хук для извлечения текущего значения из реактивных примитивов ядра\n * (Signal, Computed, Resource) и глубоких реактивных Proxy-объектов (reactive).\n *\n * @template T - Тип входящих данных\n * @param {ReactiveInput<any>} input - Готовый реактивный элемент ядра или функция-фабрика\n * @returns {any} Актуальное синхронизированное значение элемента или сам прокси-объект\n */\nexport const useReactiveValue = <T>(input: ReactiveInput<any>): any => {\n const isFactory = typeof input === 'function'\n\n // Стабилизируем ссылку на фабрику\n const factoryRef = useRef(input)\n useEffect(() => {\n factoryRef.current = input\n }, [input])\n\n // Вычисляем целевой элемент один раз\n const reactiveItem = useMemo(() => {\n if (typeof input === 'function') {\n return input()\n }\n return input\n }, [isFactory ? undefined : input])\n\n // Определяем, является ли объект примитивом (Signal/Computed) или это Proxy-объект reactive()\n const isSignal = reactiveItem &&\n typeof reactiveItem === 'object' &&\n 'subscribe' in reactiveItem &&\n typeof (reactiveItem as Record<string, unknown>).subscribe === 'function'\n\n // ------------------------------------------------====\n // СЦЕНАРИЙ А: Работа с атомарными Сигналами / Computed (useSyncExternalStore)\n // ------------------------------------------------====\n const subscribe = useCallback(\n (reactCallback: () => void) => {\n if (isSignal) {\n return (reactiveItem as ISignalLike<unknown>).subscribe(reactCallback)\n }\n return () => {}\n },\n [reactiveItem, isSignal]\n )\n\n const getSnapshot = useCallback(() => {\n if (isSignal) {\n return (reactiveItem as ISignalLike<unknown>).value\n }\n return reactiveItem\n }, [reactiveItem, isSignal])\n\n // Безопасная очистка локальных фабрик ядра при размонтировании экрана\n useEffect(() => {\n return () => {\n if (isFactory && reactiveItem && 'destroy' in reactiveItem && typeof (reactiveItem as any).destroy === 'function') {\n (reactiveItem as any).destroy()\n }\n }\n }, [reactiveItem, isFactory])\n\n // Если это сигнал — используем Concurrent-безопасныйuseSyncExternalStore\n if (isSignal) {\n return useSyncExternalStore(subscribe, getSnapshot)\n }\n\n // ------------------------------------------------====\n // СЦЕНАРИЙ Б: Работа с глубокими Proxy-объектами / Массивами\n // ------------------------------------------------====\n // Для Proxy-объектовuseSyncExternalStore не подходит, так как у них нет .value.\n // Мы создаем локальный forceUpdate и подписываем его через скрытый геттер __subscribe адаптера\n const [, forceUpdate] = useState([])\n\n useEffect(() => {\n if (reactiveItem && '__subscribe' in reactiveItem && typeof (reactiveItem as any).__subscribe === 'function') {\n const unsubscribe = (reactiveItem as any).__subscribe(() => {\n forceUpdate([]) // Провоцируем ререндер компонента через автобатчинг микрозадач\n })\n return () => unsubscribe()\n }\n }, [reactiveItem])\n\n return reactiveItem\n}\n"],"mappings":";;AAqBA,IAAa,KAAuB,MAAmC;CACrE,IAAM,IAAY,OAAO,KAAU,YAG7B,IAAa,EAAO,CAAK;CAC/B,QAAgB;EACd,EAAW,UAAU;CACvB,GAAG,CAAC,CAAK,CAAC;CAGV,IAAM,IAAe,QACf,OAAO,KAAU,aACZ,EAAM,IAER,GACN,CAAC,IAAY,KAAA,IAAY,CAAK,CAAC,GAG5B,IAAW,KACA,OAAO,KAAiB,YACxB,eAAe,KACf,OAAQ,EAAyC,aAAc,YAK1E,IAAY,GACf,MACK,IACM,EAAsC,UAAU,CAAa,UAE1D,CAAC,GAEhB,CAAC,GAAc,CAAQ,CACzB,GAEM,IAAc,QACd,IACM,EAAsC,QAEzC,GACN,CAAC,GAAc,CAAQ,CAAC;CAY3B,IATA,cACe;EACX,AAAI,KAAa,KAAgB,aAAa,KAAgB,OAAQ,EAAqB,WAAY,cACrG,EAAsB,QAAQ;CAElC,GACC,CAAC,GAAc,CAAS,CAAC,GAGxB,GACF,OAAO,EAAqB,GAAW,CAAW;CAQpD,IAAM,GAAG,KAAe,EAAS,CAAC,CAAC;CAWnC,OATA,QAAgB;EACd,IAAI,KAAgB,iBAAiB,KAAgB,OAAQ,EAAqB,eAAgB,YAAY;GAC5G,IAAM,IAAe,EAAqB,kBAAkB;IAC1D,EAAY,CAAC,CAAC;GAChB,CAAC;GACD,aAAa,EAAY;EAC3B;CACF,GAAG,CAAC,CAAY,CAAC,GAEV;AACT"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* @pravosleva/reactive-engine v1.
|
|
2
|
+
* @pravosleva/reactive-engine v1.7.1
|
|
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`});var t=({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},n=class{frameworkPrefix=`core`;activeEffect=null;isBatching=!1;pendingEffects=new Set;services=new Map;factories=new Map;proxyCache=new WeakMap;allEffects=new Set;loggerOptions;pendingLogQueue=[];lastTransactionDuration=null;signalMutationCounts=new Map;lastComputedDurations=new Map;effectExecutionCounts=new Map;batchTickCounts=0;constructor(e){this.loggerOptions=e?.logger}log(e,n,r){if(!this.loggerOptions?.isEnabled)return;if(!this.loggerOptions?.isCoreOptimizationDebugEnabled){let e=t({expectedKey:`CORE_INTERNAL_SIGNAL`,tested:[n],valueType:`number`})?.[0]===`1`,r=t({expectedKey:`CORE_INTERNAL_EFFECT`,tested:[n],valueType:`number`})?.[0]===`1`;if(e||r)return}if(this.loggerOptions.filter&&!(this.loggerOptions.filter instanceof RegExp?this.loggerOptions.filter:new RegExp(this.loggerOptions.filter.replace(/^\/|\/$/g,``))).test(n))return;let i={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;`},a=``,o=`color: #aaa; font-weight: normal;`;switch(e){case`signal`:{let s=t({tested:[n],expectedKey:`CORE_INTERNAL_SIGNAL`,valueType:`number`})?.[0]===`1`,c=n,l=(this.signalMutationCounts.get(c)||0)+1;this.signalMutationCounts.set(c,l);let u=r,d=u.subscribers&&u.subscribers.length>0?u.subscribers.every(e=>e?t({tested:[e],expectedKey:`IS_OPTIMIZED`,valueType:`number`})?.[0]===`1`:!1):!1,f=l>50,p=s?`COMPUTED_INTERNAL`:`SIGNAL`;a=` 🔄 Изменений ${s?`кэша`:`сигнала`}: ${l}${f?` ⚠️ (high noise — обнаружен дребезг/спам значений!)`:``}`,f&&(o=`color: orange; font-weight: bold;`,d||(r.__performance_advice__={issue:`Сигнал [${c}] обновляется слишком часто (${l} раз за такт). Это приводит к избыточным ререндерам UI.`,solution:`Оберните чтение этого сигнала в декоратор сжатия потока данных 'withThrottleComputed'`,example:`public throttled = withThrottleComputed(this.engine, () => this.yourSignalName.value, { limit: 300 });`})),console.groupCollapsed(`%c${p}%c [${c}]%c${a}`,s?`background: #42b883; color: #fff; padding: 2px 6px; border-radius: 4px; font-weight: bold;`:i[e],`color: #aaa; font-weight: bold;`,o),console.log(`Данные (Payload):`,r),this.loggerOptions.traceTime&&typeof performance<`u`&&console.log(`Тайминг рантайма:`,`${performance.now().toFixed(2)} ms`),console.groupEnd();return}case`computed`:{let e=r;if(e&&`to`in e){let t=e.to;a=` 🧮 Значение: ${typeof t==`object`&&t?`{...}`:String(t)}`}else if(e&&`duration`in e){let t=parseFloat(e.duration);if(!isNaN(t)){let r=this.lastComputedDurations.get(n);if(r!==void 0&&r>0){let n=(t-r)/r*100;n>5?(a=` 🔴 Замедление: +${n.toFixed(1)}% (${e.duration})`,o=`color: #e01e5a; font-weight: bold;`):n<-5?(a=` 🟢 Ускорение: ${n.toFixed(1)}% (${e.duration})`,o=`color: #42b883; font-weight: bold;`):(a=` 🟢 Стабильно (${e.duration})`,o=`color: #42b883; font-weight: bold;`)}else a=` ⚪ Первый расчет (${e.duration})`;this.lastComputedDurations.set(n,t)}}break}case`effect`:{let e=(this.effectExecutionCounts.get(n)||0)+1;this.effectExecutionCounts.set(n,e);let t=e>30,i=r;a=` 🟢 Стабильно${i&&`duration`in i?` (${i.duration})`:``} | 🚀 Вызовов: ${e}${t?` ⚠️ (heavy re-renders)`:``}`,o=`color: #42b883; font-weight: bold;`,t&&(o=`color: #ff4a4a; font-weight: bold;`);break}case`batch`:this.batchTickCounts+=1,a=` 📦 Номер транзакции: #${this.batchTickCounts}`;break;case`resource`:{let e=r;if(e.loading)a=` ⏳ ЗАГРУЗКА (fetching...)`,o=`color: #d97706; font-weight: bold;`;else if(e.error)a=` 🔴 ОШИБКА: ${e.error.message||`Unknown Error`}`,o=`color: #ff4a4a; font-weight: bold;`;else{let t=e.data;a=` 🟢 УСПЕХ (data: ${typeof t==`object`&&t?`{...}`:String(t)})`,o=`color: #42b883; font-weight: bold;`}break}default:break}console.groupCollapsed(`%c${e.toUpperCase()}%c [${n}]%c${a}`,i[e],`color: #aaa; font-weight: bold;`,o),console.log(`Данные (Payload):`,r),this.loggerOptions.traceTime&&typeof performance<`u`&&console.log(`Тайминг рантайма:`,`${performance.now().toFixed(2)} ms`),console.groupEnd()}onSignalChange;provide(e,t){typeof t==`function`&&!t.prototype?this.factories.set(e,t):this.services.set(e,t)}inject(e){if(!e)throw Error(`[DI Error]: Вы пытаетесь внедрить пустой токен (undefined/null). Проверьте импорты.`);let t=e;if(this.services.has(t))return this.services.get(t);try{let n=this.factories.get(t);if(n){let e=n(this);return this.services.set(t,e),e}if(typeof e==`function`&&e.prototype){let n=new e(this);return this.services.set(t,n),n}throw Error(`Service not found: ${String(e)}`)}catch(t){throw Error(`[DI Error]: Не удалось создать сервис ${String(e)}. Ошибка: ${t?.message||`No e?.message`}`)}}queueLog(e,t,n){this.loggerOptions?.isEnabled&&this.pendingLogQueue.push({type:e,name:t,detail:n})}flushLogs(){if(!this.loggerOptions?.isEnabled||this.pendingLogQueue.length===0)return;let e=typeof performance<`u`?performance.now():0,t=this.pendingLogQueue;if(this.loggerOptions.filter)try{let e;if(this.loggerOptions.filter instanceof RegExp)e=this.loggerOptions.filter;else{let t=this.loggerOptions.filter.replace(/^\/|\/$/g,``);e=new RegExp(t)}t=t.filter(t=>e.test(t.name))}catch(e){console.warn(`[Logger Error]: Некорректный паттерн фильтрации логов`,e)}if(t.length===0){this.pendingLogQueue=[];return}let n=``,r=``,i=`color: #aaa; font-weight: normal;`;if(this.loggerOptions.traceTime&&e){let t=performance.now()-e;if(n=` | Duration: ${t.toFixed(3)} ms`,this.lastTransactionDuration!==null&&this.lastTransactionDuration>0){let e=(t-this.lastTransactionDuration)/this.lastTransactionDuration*100;e>.1?(r=` 🔴 +${e.toFixed(1)}%`,i=`color: #e01e5a; font-weight: bold;`):e<-.1?(r=` 🟢 ${e.toFixed(1)}%`,i=`color: #42b883; font-weight: bold;`):(r=` 🟢 stable`,i=`color: #42b883; font-weight: bold;`)}else r=` ⚪ first`;this.lastTransactionDuration=t}console.groupCollapsed(`%cREACTIVE TRANSACTION${this.loggerOptions.instanceName?` ${this.loggerOptions.instanceName}`:``}%c Microtask Tick (Size: ${t.length}${n})%c${r}`,`background: #7952b3; color: #fff; padding: 2px 6px; border-radius: 4px; font-weight: bold;`,`color: #aaa; font-weight: normal;`,i),t.forEach(e=>{this.log(e.type,e.name,e.detail)}),this.loggerOptions.traceTime&&typeof performance<`u`&&console.log(`%c[Execution Timestamp]: ${performance.now().toFixed(2)} ms`,`color: #7952b3; font-weight: bold;`),console.groupEnd(),this.pendingLogQueue=[]}signal(e,t){let n=this,r=e,i=new Set,a=typeof t==`string`?{name:t}:t||{},o=a.name||`unnamed_signal`;return{get value(){if(n.activeEffect){let e=n.activeEffect;i.has(e)||(i.add(e),e.cleanups.add(()=>{i.delete(e)}))}return r},set value(e){if(r===e)return;if(a.validate){let t=a.validate(e);if(t===!1||typeof t==`string`){let n=typeof t==`string`?t:`[Validation Error]: Некорректное значение для сигнала "${o}"`;console.error(`%c${n}`,`color: orange; font-weight: bold;`,{received:e,current:r});return}}let t=r;r=e,n.onSignalChange?.(o,e,t);let s=Array.from(i).map(e=>e.label||`unnamed_effect`);n.queueLog?.(`signal`,o,{from:t,to:e,subscribersCount:i.size,subscribers:s}),i.forEach(e=>n.pendingEffects.add(e)),n.isBatching||(n.isBatching=!0,queueMicrotask(()=>{for(let e of n.pendingEffects)n.pendingEffects.delete(e),e.run();n.isBatching=!1,n.flushLogs?.()}))},subscribe(e){return n.effect(()=>{e(this.value)},`${n.frameworkPrefix}:use:${o}`)}}}effect(e,t){let n=this,r=!0,i={label:t,cleanups:new Set,run(){let t=Array.from(this.cleanups);this.cleanups.clear(),t.forEach(e=>e());let i=n.activeEffect;n.activeEffect=this;let a=performance.now();n.safeRun(this,()=>{let t=e();typeof t==`function`&&this.cleanups.add(t)}),n.activeEffect=i;let o=performance.now()-a;if(!r&&n.loggerOptions?.isEnabled){let e=n.loggerOptions.filter;(!e||e instanceof RegExp&&this.label&&e.test(this.label))&&typeof n.queueLog==`function`&&n.queueLog(`effect`,this.label||`unnamed-efect-0`,{name:this.label||`unnamed-efect-0`,type:`effect`,detail:{status:`stable`,duration:`${o.toFixed(3)}ms`,timestamp:a}})}r=!1}};return this.allEffects.add(i),i.run(),()=>{i.cleanups.forEach(e=>e()),n.pendingEffects.delete(i),n.allEffects.delete(i)}}computedCache=new Map;cleanupRegistry=new FinalizationRegistry(e=>{e()});computed(e,t){if(this.computedCache.has(e)){let t=this.computedCache.get(e)?.deref();if(t)return t}let n=this,r=t||`unnamed_computed`,i=this.signal(void 0,`[CORE_INTERNAL_SIGNAL=1]:${r}`),a=!0,o,s=this.effect(()=>{o=e(),a=!1;let t=typeof performance<`u`&&performance.now()?`0.010ms`:`N/A`;typeof n.queueLog==`function`&&n.queueLog(`computed`,r,{value:o,duration:t}),i.value=o},`[CORE_INTERNAL_EFFECT=1]:${r}`),c=Array.from(this.allEffects)[this.allEffects.size-1],l=()=>{s(),c&&n.allEffects.delete(c),n.computedCache.delete(e)},u={get value(){return a&&(o=e(),a=!1,i.value=o),i.value},subscribe:e=>i.subscribe(e),destroy(){s(),l(),n.computedCache.delete(e)}};return this.cleanupRegistry.register(u,l),this.computedCache.set(e,new WeakRef(u)),u}reactive(e,t=`reactive`){if(this.proxyCache.has(e))return this.proxyCache.get(e);let n=this,r=new Map,i=new Proxy(e,{get(e,i,a){if(n.activeEffect){let e=n.activeEffect;r.has(i)||r.set(i,new Set);let t=r.get(i);t.has(e)||(t.add(e),e.cleanups.add(()=>{t.delete(e)}))}let o=Reflect.get(e,i,a);return typeof o==`object`&&o?n.reactive(o,`${t}.${String(i)}`):o},set(e,i,a,o){let s=Reflect.get(e,i,o);if(s===a)return!0;if(s!==a){Reflect.set(e,i,a,o),n.onSignalChange?.(`${t}.${String(i)}`,a,s);let c=r.get(i);(c?Array.from(c):[]).forEach(e=>{n.isBatching?n.pendingEffects.add(e):(n.pendingEffects.add(e),n.isBatching||(n.isBatching=!0,queueMicrotask(()=>{for(let e of n.pendingEffects)n.pendingEffects.delete(e),e.run();n.isBatching=!1,n.flushLogs?.()})))}),n.queueLog?.(`reactive`,`${t}.${String(i)}`,{action:`set`,property:String(i),oldValue:s,newValue:a})}return!0}});return this.proxyCache.set(e,i),i}batch(e){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,n,r){let i=r&&typeof r==`object`,a=i?r.name:r||`unnamed_resource`,o=i?r:{},s=o.resetDataOnSourceChange??!0,c=o.responseValidate,l=o.validateBeforeFetch,u=o.retryCount??0,d=o.retryDelay??1e3,f=o.isExponentialBackoffEnabled??!1,p=o.maxRetryDelay??3e4,m=o.timeout,h=this.signal({data:null,loading:!0,error:null,isRetrying:!1},`[CORE_INTERNAL_SIGNAL=1]:resource:state:${a}`),g=e=>{h.value=e,typeof this.queueLog==`function`&&this.queueLog(`resource`,a,{loading:e.loading,data:e.data,error:e.error,isRetrying:e.isRetrying})},_=async(n,r,i=!1)=>{if(r.aborted)return;if(l){let e=l(n);if(e===!1||typeof e==`string`){if(r.aborted)return;let t=typeof e==`string`?e:`Pre-fetch validation failed for resource`,n=i?null:this.untrack(()=>h.value.data);g({data:n,loading:!1,error:Error(t),isRetrying:!1});return}}let o=i&&s?null:this.untrack(()=>h.value.data);g({data:o,loading:!0,error:null,isRetrying:!1});for(let i=0;i<=u;i++){if(r.aborted)return;let o=r;try{if(m&&m>0){let e=AbortSignal.timeout(m);o=AbortSignal.any([r,e])}let t=await e(n,o);if(r.aborted)return;if(o.aborted)throw new DOMException(`The operation timed out.`,`TimeoutError`);if(c){let e=c(t);if(e===!1||typeof e==`string`){if(r.aborted)return;g({data:null,loading:!1,error:Error(typeof e==`string`?e:`Validation failed`),isRetrying:!1});return}}if(r.aborted)return;g({data:t,loading:!1,error:null,isRetrying:!1});return}catch(e){if(r.aborted||e.name===`AbortError`&&r.aborted)return;let n=e.name===`TimeoutError`||e.name===`AbortError`||e.message?.includes(`timeout`),o=t({tested:[e.message],expectedKey:`THROW_CUSTOM_VALIDATION_ERROR_NO_RETRY`,valueType:`number`})?.[0]===`1`||!1,s=o&&t({tested:[e.message],expectedKey:`MESSAGE`,valueType:`string`})?.[0]||`Custom validation error`,c=o||e.name===`ValidationError`;if(i===u||c){if(r.aborted)return;let t=n?Error(`Request timed out after ${m}ms`,{cause:e}):o?Error(s,{cause:e}):e;g({data:null,loading:!1,error:t,isRetrying:!1});return}else{if(r.aborted)return;let e=f?d*2**i:d;e=Math.min(e,p);let t=Math.random()*200;e+=t,g({data:h.value.data,loading:!0,error:null,isRetrying:!0}),console.warn(`[Resource Retry] "${a}" сбой по ${n?`таймауту`:`ошибке сети`}. Попытка ${i+1}/${u+1}...`);try{if(await this.delay(e,r),r.aborted)return}catch{return}}}}},v=null;return this.effect(()=>{let e=n?n.value:void 0,t=new AbortController;return v=t,this.untrack(()=>{_(e,t.signal,!0)}),()=>t.abort()},`[dev]`),{get data(){return h.value.data},get loading(){return h.value.loading},get error(){return h.value.error},get isRetrying(){return h.value.isRetrying},get value(){return h.value},refetch:()=>{v?.abort(),v=new AbortController,_(n?n.value:void 0,v.signal,!1)},subscribe:e=>h.subscribe(e)}}untrack(e){let t=this.activeEffect;this.activeEffect=null;try{return e()}finally{this.activeEffect=t}}safeRun(e,t){try{t()}catch(e){console.error(`%c[Reactive Error] %cОшибка в эффекте/computed:`,`color: white; background: red; padding: 2px 4px; border-radius: 3px;`,`font-weight: bold;`,e)}}},r=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(){}},i=r,a=class{engine;constructor(e){this.engine=e,setTimeout(()=>this.onInit(),0)}onInit(){}};e.AbstractService=r,e.BaseREService=i,e.BaseREServiceEnhanced=a,e.ReactiveEngine=n});
|
|
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=({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},n=class{frameworkPrefix=`core`;activeEffect=null;isBatching=!1;pendingEffects=new Set;services=new Map;factories=new Map;proxyCache=new WeakMap;allEffects=new Set;loggerOptions;pendingLogQueue=[];lastTransactionDuration=null;signalMutationCounts=new Map;lastComputedDurations=new Map;effectExecutionCounts=new Map;batchTickCounts=0;constructor(e){this.loggerOptions=e?.logger}log(e,n,r){if(!this.loggerOptions?.isEnabled)return;if(!this.loggerOptions?.isCoreOptimizationDebugEnabled){let e=t({expectedKey:`CORE_INTERNAL_SIGNAL`,tested:[n],valueType:`number`})?.[0]===`1`,r=t({expectedKey:`CORE_INTERNAL_EFFECT`,tested:[n],valueType:`number`})?.[0]===`1`;if(e||r)return}if(this.loggerOptions.filter&&!(this.loggerOptions.filter instanceof RegExp?this.loggerOptions.filter:new RegExp(this.loggerOptions.filter.replace(/^\/|\/$/g,``))).test(n))return;let i={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;`},a=``,o=`color: #aaa; font-weight: normal;`;switch(e){case`signal`:{let s=t({tested:[n],expectedKey:`CORE_INTERNAL_SIGNAL`,valueType:`number`})?.[0]===`1`,c=n,l=(this.signalMutationCounts.get(c)||0)+1;this.signalMutationCounts.set(c,l);let u=r,d=u.subscribers&&u.subscribers.length>0?u.subscribers.every(e=>e?t({tested:[e],expectedKey:`IS_OPTIMIZED`,valueType:`number`})?.[0]===`1`:!1):!1,f=l>50,p=s?`COMPUTED_INTERNAL`:`SIGNAL`;a=` 🔄 Изменений ${s?`кэша`:`сигнала`}: ${l}${f?` ⚠️ (high noise — обнаружен дребезг/спам значений!)`:``}`,f&&(o=`color: orange; font-weight: bold;`,d||(r.__performance_advice__={issue:`Сигнал [${c}] обновляется слишком часто (${l} раз за такт). Это приводит к избыточным ререндерам UI.`,solution:`Оберните чтение этого сигнала в декоратор сжатия потока данных 'withThrottleComputed'`,example:`public throttled = withThrottleComputed(this.engine, () => this.yourSignalName.value, { limit: 300 });`})),console.groupCollapsed(`%c${p}%c [${c}]%c${a}`,s?`background: #42b883; color: #fff; padding: 2px 6px; border-radius: 4px; font-weight: bold;`:i[e],`color: #aaa; font-weight: bold;`,o),console.log(`Данные (Payload):`,r),this.loggerOptions.traceTime&&typeof performance<`u`&&console.log(`Тайминг рантайма:`,`${performance.now().toFixed(2)} ms`),console.groupEnd();return}case`computed`:{let e=r;if(e&&`to`in e){let t=e.to;a=` 🧮 Значение: ${typeof t==`object`&&t?`{...}`:String(t)}`}else if(e&&`duration`in e){let t=parseFloat(e.duration);if(!isNaN(t)){let r=this.lastComputedDurations.get(n);if(r!==void 0&&r>0){let n=(t-r)/r*100;n>5?(a=` 🔴 Замедление: +${n.toFixed(1)}% (${e.duration})`,o=`color: #e01e5a; font-weight: bold;`):n<-5?(a=` 🟢 Ускорение: ${n.toFixed(1)}% (${e.duration})`,o=`color: #42b883; font-weight: bold;`):(a=` 🟢 Стабильно (${e.duration})`,o=`color: #42b883; font-weight: bold;`)}else a=` ⚪ Первый расчет (${e.duration})`;this.lastComputedDurations.set(n,t)}}break}case`effect`:{let e=(this.effectExecutionCounts.get(n)||0)+1;this.effectExecutionCounts.set(n,e);let t=e>30,i=r;a=` 🟢 Стабильно${i&&`duration`in i?` (${i.duration})`:``} | 🚀 Вызовов: ${e}${t?` ⚠️ (heavy re-renders)`:``}`,o=`color: #42b883; font-weight: bold;`,t&&(o=`color: #ff4a4a; font-weight: bold;`);break}case`batch`:this.batchTickCounts+=1,a=` 📦 Номер транзакции: #${this.batchTickCounts}`;break;case`resource`:{let e=r;if(e.loading)a=` ⏳ ЗАГРУЗКА (fetching...)`,o=`color: #d97706; font-weight: bold;`;else if(e.error)a=` 🔴 ОШИБКА: ${e.error.message||`Unknown Error`}`,o=`color: #ff4a4a; font-weight: bold;`;else{let t=e.data;a=` 🟢 УСПЕХ (data: ${typeof t==`object`&&t?`{...}`:String(t)})`,o=`color: #42b883; font-weight: bold;`}break}default:break}console.groupCollapsed(`%c${e.toUpperCase()}%c [${n}]%c${a}`,i[e],`color: #aaa; font-weight: bold;`,o),console.log(`Данные (Payload):`,r),this.loggerOptions.traceTime&&typeof performance<`u`&&console.log(`Тайминг рантайма:`,`${performance.now().toFixed(2)} ms`),console.groupEnd()}onSignalChange;provide(e,t){typeof t==`function`&&!t.prototype?this.factories.set(e,t):this.services.set(e,t)}inject(e){if(!e)throw Error(`[DI Error]: Вы пытаетесь внедрить пустой токен (undefined/null). Проверьте импорты.`);let t=e;if(this.services.has(t))return this.services.get(t);try{let n=this.factories.get(t);if(n){let e=n(this);return this.services.set(t,e),e}if(typeof e==`function`&&e.prototype){let n=new e(this);return this.services.set(t,n),n}throw Error(`Service not found: ${String(e)}`)}catch(t){throw Error(`[DI Error]: Не удалось создать сервис ${String(e)}. Ошибка: ${t?.message||`No e?.message`}`)}}queueLog(e,t,n){this.loggerOptions?.isEnabled&&this.pendingLogQueue.push({type:e,name:t,detail:n})}flushLogs(){if(!this.loggerOptions?.isEnabled||this.pendingLogQueue.length===0)return;let e=typeof performance<`u`?performance.now():0,t=this.pendingLogQueue;if(this.loggerOptions.filter)try{let e;if(this.loggerOptions.filter instanceof RegExp)e=this.loggerOptions.filter;else{let t=this.loggerOptions.filter.replace(/^\/|\/$/g,``);e=new RegExp(t)}t=t.filter(t=>e.test(t.name))}catch(e){console.warn(`[Logger Error]: Некорректный паттерн фильтрации логов`,e)}if(t.length===0){this.pendingLogQueue=[];return}let n=``,r=``,i=`color: #aaa; font-weight: normal;`;if(this.loggerOptions.traceTime&&e){let t=performance.now()-e;if(n=` | Duration: ${t.toFixed(3)} ms`,this.lastTransactionDuration!==null&&this.lastTransactionDuration>0){let e=(t-this.lastTransactionDuration)/this.lastTransactionDuration*100;e>.1?(r=` 🔴 +${e.toFixed(1)}%`,i=`color: #e01e5a; font-weight: bold;`):e<-.1?(r=` 🟢 ${e.toFixed(1)}%`,i=`color: #42b883; font-weight: bold;`):(r=` 🟢 stable`,i=`color: #42b883; font-weight: bold;`)}else r=` ⚪ first`;this.lastTransactionDuration=t}console.groupCollapsed(`%cREACTIVE TRANSACTION${this.loggerOptions.instanceName?` ${this.loggerOptions.instanceName}`:``}%c Microtask Tick (Size: ${t.length}${n})%c${r}`,`background: #7952b3; color: #fff; padding: 2px 6px; border-radius: 4px; font-weight: bold;`,`color: #aaa; font-weight: normal;`,i),t.forEach(e=>{this.log(e.type,e.name,e.detail)}),this.loggerOptions.traceTime&&typeof performance<`u`&&console.log(`%c[Execution Timestamp]: ${performance.now().toFixed(2)} ms`,`color: #7952b3; font-weight: bold;`),console.groupEnd(),this.pendingLogQueue=[]}signal(e,t){let n=this,r=e,i=new Set,a=typeof t==`string`?{name:t}:t||{},o=a.name||`unnamed_signal`;return{get value(){if(n.activeEffect){let e=n.activeEffect;i.has(e)||(i.add(e),e.cleanups.add(()=>{i.delete(e)}))}return r},set value(e){if(a?.validate&&a.validate(e)!==!0){let t=a.validate(e);console.error(`[ReactiveEngine] Validation failed for signal "${o}": ${typeof t==`string`?t:`Unknown reason`}`,{value:e});return}if((e===null||typeof e!=`object`&&typeof e!=`function`)&&r===e)return;let t=r;r=e,n.onSignalChange?.(o,e,t),i.forEach(e=>{e!==n.activeEffect&&(n.isBatching?n.pendingEffects.add(e):(n.pendingEffects.add(e),n.isBatching||(n.isBatching=!0,queueMicrotask(()=>{for(let e of n.pendingEffects)n.pendingEffects.delete(e),e.run();n.isBatching=!1,n.flushLogs?.()}))))})},subscribe(e){return n.effect(()=>{e(this.value)},`${n.frameworkPrefix}:use:${o}`)}}}effect(e,t){let n=this,r=!0,i={label:t,cleanups:new Set,run(){let t=Array.from(this.cleanups);this.cleanups.clear(),t.forEach(e=>{try{e()}catch(e){console.error(`%c[Reactive Engine:Cleanup Error] %cОшибка в функции очистки (cleanup):`,`color: white; background: red; padding: 2px 4px; border-radius: 3px;`,`font-weight: bold;`,e)}});let i=n.activeEffect;n.activeEffect=this;let a=performance.now();n.safeRun(this,()=>{let t=e();typeof t==`function`&&this.cleanups.add(t)}),n.activeEffect=i;let o=performance.now()-a;if(!r&&n.loggerOptions?.isEnabled){let e=n.loggerOptions.filter;(!e||e instanceof RegExp&&this.label&&e.test(this.label))&&typeof n.queueLog==`function`&&n.queueLog(`effect`,this.label||`unnamed-efect-0`,{name:this.label||`unnamed-efect-0`,type:`effect`,detail:{status:`stable`,duration:`${o.toFixed(3)}ms`,timestamp:a}})}r=!1}};return this.allEffects.add(i),i.run(),()=>{i.cleanups.forEach(e=>{try{e()}catch(e){console.error(`[Reactive Engine:Cleanup Error]`,e)}}),n.pendingEffects.delete(i),n.allEffects.delete(i)}}computedCache=new Map;cleanupRegistry=new FinalizationRegistry(e=>{e()});computed(e,t){if(this.computedCache.has(e)){let t=this.computedCache.get(e)?.deref();if(t)return t}let n=this,r=t||`unnamed_computed`,i=this.signal(void 0,`[CORE_INTERNAL_SIGNAL=1]:${r}`),a=!0,o,s=this.effect(()=>{o=e(),a=!1;let t=typeof performance<`u`&&performance.now()?`0.010ms`:`N/A`;typeof n.queueLog==`function`&&n.queueLog(`computed`,r,{value:o,duration:t}),i.value=o},`[CORE_INTERNAL_EFFECT=1]:${r}`),c=Array.from(this.allEffects)[this.allEffects.size-1],l=()=>{s(),c&&n.allEffects.delete(c),n.computedCache.delete(e)},u={get value(){return a&&(o=e(),a=!1,i.value=o),i.value},subscribe:e=>i.subscribe(e),destroy(){s(),l(),n.computedCache.delete(e)}};return this.cleanupRegistry.register(u,l),this.computedCache.set(e,new WeakRef(u)),u}reactive(e,t=`reactive`){if(this.proxyCache.has(e))return this.proxyCache.get(e);let n=this,r=new Map,i=new Proxy(e,{get(e,i,a){if(n.activeEffect){let e=n.activeEffect;r.has(i)||r.set(i,new Set);let t=r.get(i);t.has(e)||(t.add(e),e.cleanups.add(()=>{t.delete(e)}))}if(Array.isArray(e)&&typeof i==`string`&&[`push`,`pop`,`shift`,`unshift`,`splice`,`sort`,`reverse`].includes(i)){let t=e[i];return function(...a){let o=n.isBatching;n.isBatching=!0;let s=t.apply(e,a);return r.forEach((e,t)=>{t!==i&&Array.from(e).forEach(e=>{e!==n.activeEffect&&n.pendingEffects.add(e)})}),n.isBatching=o,!n.isBatching&&n.pendingEffects.size>0&&(n.isBatching=!0,queueMicrotask(()=>{for(let e of n.pendingEffects)n.pendingEffects.delete(e),e.run();n.isBatching=!1,n.flushLogs?.()})),s}}let o=Reflect.get(e,i,a);return typeof o==`object`&&o?n.reactive(o,`${t}.${String(i)}`):o},set(e,i,a,o){let s=Reflect.get(e,i,o);if(s===a)return!0;if(s!==a){Reflect.set(e,i,a,o),n.onSignalChange?.(`${t}.${String(i)}`,a,s);let c=r.get(i),l=c?Array.from(c):[];if(Array.isArray(e)){let e=r.get(`length`);e&&l.push(...Array.from(e))}l.forEach(e=>{e!==n.activeEffect&&(n.isBatching?n.pendingEffects.add(e):(n.pendingEffects.add(e),n.isBatching||(n.isBatching=!0,queueMicrotask(()=>{for(let e of n.pendingEffects)n.pendingEffects.delete(e),e.run();n.isBatching=!1,n.flushLogs?.()}))))}),n.queueLog?.(`reactive`,`${t}.${String(i)}`,{action:`set`,property:String(i),oldValue:s,newValue:a})}return!0}});return this.proxyCache.set(e,i),i}batch(e){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,n,r){let i=r&&typeof r==`object`,a=i?r.name:r||`unnamed_resource`,o=i?r:{},s=o.resetDataOnSourceChange??!0,c=o.responseValidate,l=o.validateBeforeFetch,u=o.retryCount??0,d=o.retryDelay??1e3,f=o.isExponentialBackoffEnabled??!1,p=o.maxRetryDelay??3e4,m=o.timeout,h=this.signal({data:null,loading:!0,error:null,isRetrying:!1},`[CORE_INTERNAL_SIGNAL=1]:resource:state:${a}`),g=e=>{h.value=e,typeof this.queueLog==`function`&&this.queueLog(`resource`,a,{loading:e.loading,data:e.data,error:e.error,isRetrying:e.isRetrying})},_=async(n,r,i=!1)=>{if(r.aborted)return;if(l){let e=l(n);if(e===!1||typeof e==`string`){if(r.aborted)return;let t=typeof e==`string`?e:`Pre-fetch validation failed for resource`,n=i?null:this.untrack(()=>h.value.data);g({data:n,loading:!1,error:Error(t),isRetrying:!1});return}}let o=i&&s?null:this.untrack(()=>h.value.data);g({data:o,loading:!0,error:null,isRetrying:!1});for(let i=0;i<=u;i++){if(r.aborted)return;let o=r;try{if(m&&m>0){let e=AbortSignal.timeout(m);o=AbortSignal.any([r,e])}let t=await e(n,o);if(r.aborted)return;if(o.aborted)throw new DOMException(`The operation timed out.`,`TimeoutError`);if(c){let e=c(t);if(e===!1||typeof e==`string`){if(r.aborted)return;g({data:null,loading:!1,error:Error(typeof e==`string`?e:`Validation failed`),isRetrying:!1});return}}if(r.aborted)return;g({data:t,loading:!1,error:null,isRetrying:!1});return}catch(e){if(r.aborted||e.name===`AbortError`&&r.aborted)return;let n=e.name===`TimeoutError`||e.name===`AbortError`||e.message?.includes(`timeout`),o=t({tested:[e.message],expectedKey:`THROW_CUSTOM_VALIDATION_ERROR_NO_RETRY`,valueType:`number`})?.[0]===`1`||!1,s=o&&t({tested:[e.message],expectedKey:`MESSAGE`,valueType:`string`})?.[0]||`Custom validation error`,c=o||e.name===`ValidationError`;if(i===u||c){if(r.aborted)return;let t=n?Error(`Request timed out after ${m}ms`,{cause:e}):o?Error(s,{cause:e}):e;g({data:null,loading:!1,error:t,isRetrying:!1});return}else{if(r.aborted)return;let e=f?d*2**i:d;e=Math.min(e,p);let t=Math.random()*200;e+=t,g({data:h.value.data,loading:!0,error:null,isRetrying:!0}),console.warn(`[Resource Retry] "${a}" сбой по ${n?`таймауту`:`ошибке сети`}. Попытка ${i+1}/${u+1}...`);try{if(await this.delay(e,r),r.aborted)return}catch{return}}}}},v=null;return this.effect(()=>{let e=n?n.value:void 0,t=new AbortController;return v=t,this.untrack(()=>{_(e,t.signal,!0)}),()=>t.abort()},`[dev]`),{get data(){return h.value.data},get loading(){return h.value.loading},get error(){return h.value.error},get isRetrying(){return h.value.isRetrying},get value(){return h.value},refetch:()=>{v?.abort(),v=new AbortController,_(n?n.value:void 0,v.signal,!1)},subscribe:e=>h.subscribe(e)}}untrack(e){let t=this.activeEffect;this.activeEffect=null;try{return e()}finally{this.activeEffect=t}}safeRun(e,t){try{t()}catch(e){console.error(`%c[Reactive Error] %cОшибка в эффекте/computed:`,`color: white; background: red; padding: 2px 4px; border-radius: 3px;`,`font-weight: bold;`,e)}}},r=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(){}},i=r,a=class{engine;constructor(e){this.engine=e,setTimeout(()=>this.onInit(),0)}onInit(){}};e.AbstractService=r,e.BaseREService=i,e.BaseREServiceEnhanced=a,e.ReactiveEngine=n});
|
|
13
13
|
//# sourceMappingURL=reactive-engine.umd.js.map
|