@pravosleva/reactive-engine 0.4.2-beta → 1.0.2-beta
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +29 -0
- package/dist/AbstractService.cjs +2 -0
- package/dist/AbstractService.cjs.map +1 -0
- package/dist/AbstractService.mjs +24 -0
- package/dist/AbstractService.mjs.map +1 -0
- package/dist/BaseREServiceEnhanced.cjs +2 -0
- package/dist/BaseREServiceEnhanced.cjs.map +1 -0
- package/dist/BaseREServiceEnhanced.mjs +12 -0
- package/dist/BaseREServiceEnhanced.mjs.map +1 -0
- package/dist/_react-bindings.d.ts +17 -0
- package/dist/_react-bindings.d.ts.map +1 -0
- package/dist/_virtual/_rolldown/runtime.cjs +1 -0
- package/dist/core/AbstractService.d.ts +11 -0
- package/dist/core/AbstractService.d.ts.map +1 -0
- package/dist/core/BaseREServiceEnhanced.d.ts +7 -0
- package/dist/core/BaseREServiceEnhanced.d.ts.map +1 -0
- package/dist/core/core.d.ts +282 -0
- package/dist/core/core.d.ts.map +1 -0
- package/dist/core/core.test.d.ts +2 -0
- package/dist/core/core.test.d.ts.map +1 -0
- package/dist/core/index.d.ts +5 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/types.d.ts +92 -0
- package/dist/core/types.d.ts.map +1 -0
- package/dist/core.cjs +2 -0
- package/dist/core.cjs.map +1 -0
- package/dist/core.mjs +286 -0
- package/dist/core.mjs.map +1 -0
- package/dist/decorators/index.d.ts +6 -0
- package/dist/decorators/index.d.ts.map +1 -0
- package/dist/decorators/withCache/index.d.ts +2 -0
- package/dist/decorators/withCache/index.d.ts.map +1 -0
- package/dist/decorators/withCache/withCache.d.ts +13 -0
- package/dist/decorators/withCache/withCache.d.ts.map +1 -0
- package/dist/decorators/withCache/withCache.test.d.ts +2 -0
- package/dist/decorators/withCache/withCache.test.d.ts.map +1 -0
- package/dist/decorators/withDebounce/index.d.ts +2 -0
- package/dist/decorators/withDebounce/index.d.ts.map +1 -0
- package/dist/decorators/withDebounce/withDebounce.d.ts +12 -0
- package/dist/decorators/withDebounce/withDebounce.d.ts.map +1 -0
- package/dist/decorators/withDebounce/withDebounce.test.d.ts +2 -0
- package/dist/decorators/withDebounce/withDebounce.test.d.ts.map +1 -0
- package/dist/decorators/withLongPolling/index.d.ts +2 -0
- package/dist/decorators/withLongPolling/index.d.ts.map +1 -0
- package/dist/decorators/withLongPolling/withLongPolling.d.ts +28 -0
- package/dist/decorators/withLongPolling/withLongPolling.d.ts.map +1 -0
- package/dist/decorators/withLongPolling/withLongPolling.test.d.ts +2 -0
- package/dist/decorators/withLongPolling/withLongPolling.test.d.ts.map +1 -0
- package/dist/decorators/withThrottle/index.d.ts +2 -0
- package/dist/decorators/withThrottle/index.d.ts.map +1 -0
- package/dist/decorators/withThrottle/withThrottle.d.ts +12 -0
- package/dist/decorators/withThrottle/withThrottle.d.ts.map +1 -0
- package/dist/decorators/withThrottle/withThrottle.test.d.ts +2 -0
- package/dist/decorators/withThrottle/withThrottle.test.d.ts.map +1 -0
- package/dist/decorators/withThrottleAndCache/index.d.ts +2 -0
- package/dist/decorators/withThrottleAndCache/index.d.ts.map +1 -0
- package/dist/decorators/withThrottleAndCache/withThrottleAndCache.d.ts +13 -0
- package/dist/decorators/withThrottleAndCache/withThrottleAndCache.d.ts.map +1 -0
- package/dist/decorators/withThrottleAndCache/withThrottleAndCache.test.d.ts +2 -0
- package/dist/decorators/withThrottleAndCache/withThrottleAndCache.test.d.ts.map +1 -0
- package/dist/index.cjs +1 -6
- package/dist/index.d.ts +2 -605
- package/dist/index.d.ts.map +1 -0
- package/dist/index.mjs +4 -541
- package/dist/react/ReactiveEngine4React.cjs +6 -0
- package/dist/react/ReactiveEngine4React.cjs.map +1 -0
- package/dist/react/ReactiveEngine4React.d.ts +27 -0
- package/dist/react/ReactiveEngine4React.d.ts.map +1 -0
- package/dist/react/ReactiveEngine4React.mjs +28 -0
- package/dist/react/ReactiveEngine4React.mjs.map +1 -0
- package/dist/react/core.react.test.d.ts +2 -0
- package/dist/react/core.react.test.d.ts.map +1 -0
- package/dist/react/createObserver.cjs +2 -0
- package/dist/react/createObserver.cjs.map +1 -0
- package/dist/react/createObserver.d.ts +70 -0
- package/dist/react/createObserver.d.ts.map +1 -0
- package/dist/react/createObserver.mjs +62 -0
- package/dist/react/createObserver.mjs.map +1 -0
- package/dist/react/createObserver.test.d.ts +2 -0
- package/dist/react/createObserver.test.d.ts.map +1 -0
- package/dist/react/hooks/FilteredCatalog.test.d.ts +2 -0
- package/dist/react/hooks/FilteredCatalog.test.d.ts.map +1 -0
- package/dist/react/hooks/index.cjs +1 -0
- package/dist/react/hooks/index.d.ts +4 -0
- package/dist/react/hooks/index.d.ts.map +1 -0
- package/dist/react/hooks/index.mjs +7 -0
- package/dist/react/hooks/types.d.ts +16 -0
- package/dist/react/hooks/types.d.ts.map +1 -0
- package/dist/react/hooks/useReactiveSubscription/index.cjs +1 -0
- package/dist/react/hooks/useReactiveSubscription/index.d.ts +2 -0
- package/dist/react/hooks/useReactiveSubscription/index.d.ts.map +1 -0
- package/dist/react/hooks/useReactiveSubscription/index.mjs +2 -0
- package/dist/react/hooks/useReactiveSubscription/useReactiveSubscription.cjs +2 -0
- package/dist/react/hooks/useReactiveSubscription/useReactiveSubscription.cjs.map +1 -0
- package/dist/react/hooks/useReactiveSubscription/useReactiveSubscription.d.ts +10 -0
- package/dist/react/hooks/useReactiveSubscription/useReactiveSubscription.d.ts.map +1 -0
- package/dist/react/hooks/useReactiveSubscription/useReactiveSubscription.mjs +14 -0
- package/dist/react/hooks/useReactiveSubscription/useReactiveSubscription.mjs.map +1 -0
- package/dist/react/hooks/useReactiveSubscription/useReactiveSubscription.test.d.ts +2 -0
- package/dist/react/hooks/useReactiveSubscription/useReactiveSubscription.test.d.ts.map +1 -0
- package/dist/react/hooks/useReactiveValue/index.cjs +1 -0
- package/dist/react/hooks/useReactiveValue/index.d.ts +2 -0
- package/dist/react/hooks/useReactiveValue/index.d.ts.map +1 -0
- package/dist/react/hooks/useReactiveValue/index.mjs +2 -0
- package/dist/react/hooks/useReactiveValue/useReactiveValue.cjs +2 -0
- package/dist/react/hooks/useReactiveValue/useReactiveValue.cjs.map +1 -0
- package/dist/react/hooks/useReactiveValue/useReactiveValue.d.ts +16 -0
- package/dist/react/hooks/useReactiveValue/useReactiveValue.d.ts.map +1 -0
- package/dist/react/hooks/useReactiveValue/useReactiveValue.mjs +12 -0
- package/dist/react/hooks/useReactiveValue/useReactiveValue.mjs.map +1 -0
- package/dist/react/hooks/useReactiveValue/useReactiveValue.test.d.ts +2 -0
- package/dist/react/hooks/useReactiveValue/useReactiveValue.test.d.ts.map +1 -0
- package/dist/react/hooks/useReactiveValue0/index.cjs +1 -0
- package/dist/react/hooks/useReactiveValue0/index.d.ts +2 -0
- package/dist/react/hooks/useReactiveValue0/index.d.ts.map +1 -0
- package/dist/react/hooks/useReactiveValue0/index.mjs +2 -0
- package/dist/react/hooks/useReactiveValue0/useReactiveValue0.cjs +2 -0
- package/dist/react/hooks/useReactiveValue0/useReactiveValue0.cjs.map +1 -0
- package/dist/react/hooks/useReactiveValue0/useReactiveValue0.d.ts +15 -0
- package/dist/react/hooks/useReactiveValue0/useReactiveValue0.d.ts.map +1 -0
- package/dist/react/hooks/useReactiveValue0/useReactiveValue0.mjs +20 -0
- package/dist/react/hooks/useReactiveValue0/useReactiveValue0.mjs.map +1 -0
- package/dist/react/index.cjs +1 -0
- package/dist/react/index.d.ts +5 -0
- package/dist/react/index.d.ts.map +1 -0
- package/dist/react/index.mjs +7 -0
- package/dist/react/types.d.ts +2 -0
- package/dist/react/types.d.ts.map +1 -0
- package/dist/utils/getExtractedValues.cjs +2 -0
- package/dist/utils/getExtractedValues.cjs.map +1 -0
- package/dist/utils/getExtractedValues.d.ts +6 -0
- package/dist/utils/getExtractedValues.d.ts.map +1 -0
- package/dist/utils/getExtractedValues.mjs +21 -0
- package/dist/utils/getExtractedValues.mjs.map +1 -0
- package/dist/utils/index.d.ts +2 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/package.json +17 -3
- package/dist/index.cjs.map +0 -1
- package/dist/index.iife.js +0 -6
- package/dist/index.iife.js.map +0 -1
- package/dist/index.mjs.map +0 -1
package/README.md
CHANGED
|
@@ -19,6 +19,35 @@ yarn add @pravosleva/reactive-engine
|
|
|
19
19
|
pnpm add @pravosleva/reactive-engine
|
|
20
20
|
```
|
|
21
21
|
|
|
22
|
+
```tsx
|
|
23
|
+
import { AbstractService, ReactiveEngine } from '@pravosleva/reactive-engine'
|
|
24
|
+
|
|
25
|
+
class Logic extends AbstractService {
|
|
26
|
+
public counter = this.engine.signal<number>(0, 'example-01:signal:counter');
|
|
27
|
+
|
|
28
|
+
public inc() {
|
|
29
|
+
this.counter.value += 1
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const engine = new ReactiveEngine()
|
|
34
|
+
|
|
35
|
+
export const Example001 = () => {
|
|
36
|
+
const logic = engine.inject(Logic)
|
|
37
|
+
const counter = engine.use(logic.counter)
|
|
38
|
+
|
|
39
|
+
return (
|
|
40
|
+
<div>
|
|
41
|
+
<div>Signal example</div>
|
|
42
|
+
<code>{counter}</code>
|
|
43
|
+
<div className={baseClasses.catSection}>
|
|
44
|
+
<button onClick={() => logic.inc()}>+ INC</button>
|
|
45
|
+
</div>
|
|
46
|
+
</div>
|
|
47
|
+
)
|
|
48
|
+
}
|
|
49
|
+
```
|
|
50
|
+
|
|
22
51
|
## 🎯 What Problems This Library Solves
|
|
23
52
|
|
|
24
53
|
When building large-scale React applications, developers constantly run into architectural bottlenecks imposed by built-in state tools. `@pravosleva/reactive-engine` is designed to elegantly solve the following pain points:
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
var e=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=e;exports.AbstractService=e,exports.BaseREService=t;
|
|
2
|
+
//# sourceMappingURL=AbstractService.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AbstractService.cjs","names":[],"sources":["../src/core/AbstractService.ts"],"sourcesContent":["import { ReactiveEngine } from './core';\n\nexport abstract class AbstractService {\n constructor(protected engine: ReactiveEngine) {\n // Вызываем метод инициализации, который можно переопределить в наследниках\n this.onInit();\n }\n\n // NOTE: Полезные хелперы для сокращения кода\n protected createNumericSignal(val: number, name: string) {\n return this.engine.signal(val, {\n name,\n validate: (v) => typeof v === 'number' && !isNaN(v)\n });\n }\n\n protected createComputed<T>(fn: () => T) {\n return this.engine.computed(fn);\n }\n\n protected createSignal<T>(val: T, name?: string) {\n return this.engine.signal(val, name);\n }\n\n // NOTE: Жизненный цикл: вызывается сразу после создания сервиса.\n // Удобно для инициализации сигналов, которые зависят от engine.\n protected onInit(): void { }\n}\n\nexport const BaseREService = AbstractService\n"],"mappings":"AAEA,IAAsB,EAAtB,KAAsC,CACd,OAAtB,YAAY,EAAkC,CAAxB,KAAA,OAAA,EAEpB,KAAK,OAAO,CACd,CAGA,oBAA8B,EAAa,EAAc,CACvD,OAAO,KAAK,OAAO,OAAO,EAAK,CAC7B,OACA,SAAW,GAAM,OAAO,GAAM,UAAY,CAAC,MAAM,CAAC,CACpD,CAAC,CACH,CAEA,eAA4B,EAAa,CACvC,OAAO,KAAK,OAAO,SAAS,CAAE,CAChC,CAEA,aAA0B,EAAQ,EAAe,CAC/C,OAAO,KAAK,OAAO,OAAO,EAAK,CAAI,CACrC,CAIA,QAAyB,CAAE,CAC7B,EAEa,EAAgB"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
//#region src/core/AbstractService.ts
|
|
2
|
+
var e = class {
|
|
3
|
+
engine;
|
|
4
|
+
constructor(e) {
|
|
5
|
+
this.engine = e, this.onInit();
|
|
6
|
+
}
|
|
7
|
+
createNumericSignal(e, t) {
|
|
8
|
+
return this.engine.signal(e, {
|
|
9
|
+
name: t,
|
|
10
|
+
validate: (e) => typeof e == "number" && !isNaN(e)
|
|
11
|
+
});
|
|
12
|
+
}
|
|
13
|
+
createComputed(e) {
|
|
14
|
+
return this.engine.computed(e);
|
|
15
|
+
}
|
|
16
|
+
createSignal(e, t) {
|
|
17
|
+
return this.engine.signal(e, t);
|
|
18
|
+
}
|
|
19
|
+
onInit() {}
|
|
20
|
+
}, t = e;
|
|
21
|
+
//#endregion
|
|
22
|
+
export { e as AbstractService, t as BaseREService };
|
|
23
|
+
|
|
24
|
+
//# sourceMappingURL=AbstractService.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AbstractService.mjs","names":[],"sources":["../src/core/AbstractService.ts"],"sourcesContent":["import { ReactiveEngine } from './core';\n\nexport abstract class AbstractService {\n constructor(protected engine: ReactiveEngine) {\n // Вызываем метод инициализации, который можно переопределить в наследниках\n this.onInit();\n }\n\n // NOTE: Полезные хелперы для сокращения кода\n protected createNumericSignal(val: number, name: string) {\n return this.engine.signal(val, {\n name,\n validate: (v) => typeof v === 'number' && !isNaN(v)\n });\n }\n\n protected createComputed<T>(fn: () => T) {\n return this.engine.computed(fn);\n }\n\n protected createSignal<T>(val: T, name?: string) {\n return this.engine.signal(val, name);\n }\n\n // NOTE: Жизненный цикл: вызывается сразу после создания сервиса.\n // Удобно для инициализации сигналов, которые зависят от engine.\n protected onInit(): void { }\n}\n\nexport const BaseREService = AbstractService\n"],"mappings":";AAEA,IAAsB,IAAtB,MAAsC;CACd;CAAtB,YAAY,GAAkC;EAE5C,AAFoB,KAAA,SAAA,GAEpB,KAAK,OAAO;CACd;CAGA,oBAA8B,GAAa,GAAc;EACvD,OAAO,KAAK,OAAO,OAAO,GAAK;GAC7B;GACA,WAAW,MAAM,OAAO,KAAM,YAAY,CAAC,MAAM,CAAC;EACpD,CAAC;CACH;CAEA,eAA4B,GAAa;EACvC,OAAO,KAAK,OAAO,SAAS,CAAE;CAChC;CAEA,aAA0B,GAAQ,GAAe;EAC/C,OAAO,KAAK,OAAO,OAAO,GAAK,CAAI;CACrC;CAIA,SAAyB,CAAE;AAC7B,GAEa,IAAgB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BaseREServiceEnhanced.cjs","names":[],"sources":["../src/core/BaseREServiceEnhanced.ts"],"sourcesContent":["import { ReactiveEngine } from './core';\n\nexport abstract class BaseREServiceEnhanced {\n constructor(protected engine: ReactiveEngine) {\n setTimeout(() => this.onInit(), 0)\n }\n\n protected onInit(): void { }\n}\n"],"mappings":"AAEA,IAAsB,EAAtB,KAA4C,CACpB,OAAtB,YAAY,EAAkC,CAAxB,KAAA,OAAA,EACpB,eAAiB,KAAK,OAAO,EAAG,CAAC,CACnC,CAEA,QAAyB,CAAE,CAC7B"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
//#region src/core/BaseREServiceEnhanced.ts
|
|
2
|
+
var e = class {
|
|
3
|
+
engine;
|
|
4
|
+
constructor(e) {
|
|
5
|
+
this.engine = e, setTimeout(() => this.onInit(), 0);
|
|
6
|
+
}
|
|
7
|
+
onInit() {}
|
|
8
|
+
};
|
|
9
|
+
//#endregion
|
|
10
|
+
export { e as BaseREServiceEnhanced };
|
|
11
|
+
|
|
12
|
+
//# sourceMappingURL=BaseREServiceEnhanced.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BaseREServiceEnhanced.mjs","names":[],"sources":["../src/core/BaseREServiceEnhanced.ts"],"sourcesContent":["import { ReactiveEngine } from './core';\n\nexport abstract class BaseREServiceEnhanced {\n constructor(protected engine: ReactiveEngine) {\n setTimeout(() => this.onInit(), 0)\n }\n\n protected onInit(): void { }\n}\n"],"mappings":";AAEA,IAAsB,IAAtB,MAA4C;CACpB;CAAtB,YAAY,GAAkC;EAC5C,AADoB,KAAA,SAAA,GACpB,iBAAiB,KAAK,OAAO,GAAG,CAAC;CACnC;CAEA,SAAyB,CAAE;AAC7B"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { ReactiveEngine } from './react';
|
|
2
|
+
import { Signal, Computed, Resource } from './core';
|
|
3
|
+
export declare const engine: ReactiveEngine;
|
|
4
|
+
/**
|
|
5
|
+
* Хук для получения текущего значения Signal и его авто-обновления в React.
|
|
6
|
+
*/
|
|
7
|
+
export declare function useSignal<T>(signal: Signal<T>): T;
|
|
8
|
+
/**
|
|
9
|
+
* Хук для получения значения вычисляемого свойства Computed.
|
|
10
|
+
*/
|
|
11
|
+
export declare function useComputed<T>(computed: Computed<T>): T;
|
|
12
|
+
/**
|
|
13
|
+
* Хук для реактивного отслеживания асинхронного ресурса.
|
|
14
|
+
* Возвращает объект состояния { data, loading, error }
|
|
15
|
+
*/
|
|
16
|
+
export declare function useResource<T>(resource: Resource<T>): import('./core').ResourceState<T>;
|
|
17
|
+
//# sourceMappingURL=_react-bindings.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"_react-bindings.d.ts","sourceRoot":"","sources":["../src/_react-bindings.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AACzC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,QAAQ,CAAC;AAQpD,eAAO,MAAM,MAAM,gBAAuB,CAAC;AAK3C;;GAEG;AACH,wBAAgB,SAAS,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAGjD;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,CAAC,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,CAEvD;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,CAAC,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAC,qCAGnD"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var e=Object.create,t=Object.defineProperty,n=Object.getOwnPropertyDescriptor,r=Object.getOwnPropertyNames,i=Object.getPrototypeOf,a=Object.prototype.hasOwnProperty,o=(e,i,o,s)=>{if(i&&typeof i==`object`||typeof i==`function`)for(var c=r(i),l=0,u=c.length,d;l<u;l++)d=c[l],!a.call(e,d)&&d!==o&&t(e,d,{get:(e=>i[e]).bind(null,d),enumerable:!(s=n(i,d))||s.enumerable});return e},s=(n,r,a)=>(a=n==null?{}:e(i(n)),o(r||!n||!n.__esModule?t(a,`default`,{value:n,enumerable:!0}):a,n));exports.__toESM=s;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { ReactiveEngine } from './core';
|
|
2
|
+
export declare abstract class AbstractService {
|
|
3
|
+
protected engine: ReactiveEngine;
|
|
4
|
+
constructor(engine: ReactiveEngine);
|
|
5
|
+
protected createNumericSignal(val: number, name: string): import('./core').Signal<number>;
|
|
6
|
+
protected createComputed<T>(fn: () => T): import('./core').Computed<T>;
|
|
7
|
+
protected createSignal<T>(val: T, name?: string): import('./core').Signal<T>;
|
|
8
|
+
protected onInit(): void;
|
|
9
|
+
}
|
|
10
|
+
export declare const BaseREService: typeof AbstractService;
|
|
11
|
+
//# sourceMappingURL=AbstractService.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AbstractService.d.ts","sourceRoot":"","sources":["../../src/core/AbstractService.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,QAAQ,CAAC;AAExC,8BAAsB,eAAe;IACvB,SAAS,CAAC,MAAM,EAAE,cAAc;gBAAtB,MAAM,EAAE,cAAc;IAM5C,SAAS,CAAC,mBAAmB,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM;IAOvD,SAAS,CAAC,cAAc,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,CAAC;IAIvC,SAAS,CAAC,YAAY,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,IAAI,CAAC,EAAE,MAAM;IAM/C,SAAS,CAAC,MAAM,IAAI,IAAI;CACzB;AAED,eAAO,MAAM,aAAa,wBAAkB,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BaseREServiceEnhanced.d.ts","sourceRoot":"","sources":["../../src/core/BaseREServiceEnhanced.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,QAAQ,CAAC;AAExC,8BAAsB,qBAAqB;IAC7B,SAAS,CAAC,MAAM,EAAE,cAAc;gBAAtB,MAAM,EAAE,cAAc;IAI5C,SAAS,CAAC,MAAM,IAAI,IAAI;CACzB"}
|
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
import { ResourceOptions, ResourceState, SignalOptions } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* Интерфейс для сигнала.
|
|
4
|
+
* @template T
|
|
5
|
+
* @interface Signal<T>
|
|
6
|
+
*/
|
|
7
|
+
export interface Signal<T> {
|
|
8
|
+
/**
|
|
9
|
+
* Значение сигнала.
|
|
10
|
+
* @type {T}
|
|
11
|
+
*/
|
|
12
|
+
value: T;
|
|
13
|
+
/**
|
|
14
|
+
* Подписка на изменение значения сигнала.
|
|
15
|
+
* @function subscribe
|
|
16
|
+
* @param {Function} cb - Коллбек функция для обработки изменения.
|
|
17
|
+
* @returns {CleanupFn} - Функция для очистки подписки.
|
|
18
|
+
*/
|
|
19
|
+
subscribe: (cb: (val: T) => void) => CleanupFn;
|
|
20
|
+
}
|
|
21
|
+
export type CleanupFn = () => void;
|
|
22
|
+
export type EffectFn = () => CleanupFn | void;
|
|
23
|
+
export type Token<T> = string | symbol | {
|
|
24
|
+
new (engine: ReactiveEngine, ...args: any[]): T;
|
|
25
|
+
};
|
|
26
|
+
export type Factory<T> = (engine: ReactiveEngine) => T;
|
|
27
|
+
/**
|
|
28
|
+
* Интерфейс для вычисляемого значения.
|
|
29
|
+
* @template T
|
|
30
|
+
* @interface Computed<T>
|
|
31
|
+
*/
|
|
32
|
+
export interface Computed<T> {
|
|
33
|
+
/**
|
|
34
|
+
* Только читаемое значение вычисляемого значения.
|
|
35
|
+
* @type {T}
|
|
36
|
+
*/
|
|
37
|
+
readonly value: T;
|
|
38
|
+
/**
|
|
39
|
+
* Подписка на изменение вычисляемого значения.
|
|
40
|
+
* @function subscribe
|
|
41
|
+
* @param {Function} cb - Коллбек функция для обработки изменения.
|
|
42
|
+
* @returns {CleanupFn} - Функция для очистки подписки.
|
|
43
|
+
*/
|
|
44
|
+
subscribe: (cb: (val: T) => void) => CleanupFn;
|
|
45
|
+
/**
|
|
46
|
+
* Принудительное уничтожение вычисляемого значения и его эффекта для предотвращения утечек памяти.
|
|
47
|
+
*/
|
|
48
|
+
destroy: () => void;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Интерфейс для эффекта.
|
|
52
|
+
* @interface IEffect
|
|
53
|
+
*/
|
|
54
|
+
export interface IEffect {
|
|
55
|
+
run: () => void;
|
|
56
|
+
label?: string;
|
|
57
|
+
cleanups: Set<CleanupFn>;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Интерфейс для ресурса.
|
|
61
|
+
* @template T
|
|
62
|
+
* @interface Resource<T>
|
|
63
|
+
*/
|
|
64
|
+
export interface Resource<T> extends ResourceState<T> {
|
|
65
|
+
/**
|
|
66
|
+
* Перезагрузка ресурса.
|
|
67
|
+
* @function refetch
|
|
68
|
+
* @returns {void}
|
|
69
|
+
*/
|
|
70
|
+
refetch: () => void;
|
|
71
|
+
/**
|
|
72
|
+
* Подписка на изменение состояния ресурса.
|
|
73
|
+
* @function subscribe
|
|
74
|
+
* @param {Function} cb - Коллбек функция для обработки изменения.
|
|
75
|
+
* @returns {CleanupFn} - Функция для очистки подписки.
|
|
76
|
+
*/
|
|
77
|
+
subscribe: (cb: (val: ResourceState<T>) => void) => CleanupFn;
|
|
78
|
+
/**
|
|
79
|
+
* Только читаемое состояние ресурса.
|
|
80
|
+
* @type {ResourceState<T>}
|
|
81
|
+
*/
|
|
82
|
+
readonly value: ResourceState<T>;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Класс `ReactiveEngine` представляет собой реактивную систему, которая позволяет создавать и управлять реактивными объектами,
|
|
86
|
+
* сигналами, эффектами, асинхронными ресурсами и другими реактивными примитивами. Реактивные механизмы облегчают разработку
|
|
87
|
+
* сложных пользовательских интерфейсов и приложений, автоматически отслеживая зависимости между данными и реактивно обновляя UI.
|
|
88
|
+
*
|
|
89
|
+
* Основные возможности `ReactiveEngine` включают:
|
|
90
|
+
* - **Сигналы (Signals)**: Реактивные переменные с поддержкой подписки на изменения.
|
|
91
|
+
* - **Эффекты (Effects)**: Автоматические функции, которые выполняются при изменении зависимых сигналов.
|
|
92
|
+
* - **Ресурсы (Resources)**: Асинхронные ресурсы с поддержкой повторных попыток и валидации.
|
|
93
|
+
* - **Прокси-объекты (Proxy Objects)**: Реактивное обертывание объектов для отслеживания изменений свойств.
|
|
94
|
+
* - **Интеграция с React**: Удобные методы для интеграции реактивного ядра с компонентами React.
|
|
95
|
+
*
|
|
96
|
+
* Пример использования:
|
|
97
|
+
*
|
|
98
|
+
* ```javascript
|
|
99
|
+
* const engine = new ReactiveEngine();
|
|
100
|
+
* const count = engine.signal(0);
|
|
101
|
+
*
|
|
102
|
+
* engine.effect(() => {
|
|
103
|
+
* console.log(`Count is ${count.value}`);
|
|
104
|
+
* });
|
|
105
|
+
*
|
|
106
|
+
* count.value++; // Выведет: Count is 1
|
|
107
|
+
* ```
|
|
108
|
+
*
|
|
109
|
+
* @class
|
|
110
|
+
*/
|
|
111
|
+
export declare class ReactiveEngine {
|
|
112
|
+
private activeEffect;
|
|
113
|
+
private isBatching;
|
|
114
|
+
private pendingEffects;
|
|
115
|
+
private services;
|
|
116
|
+
private factories;
|
|
117
|
+
private proxyCache;
|
|
118
|
+
private allEffects;
|
|
119
|
+
/**
|
|
120
|
+
* Коллбек для уведомления об изменении сигнала.
|
|
121
|
+
* Использование unknown вместо any гарантирует безопасную работу с типами prev/next.
|
|
122
|
+
*/
|
|
123
|
+
onSignalChange?: (name: string, next: unknown, prev: unknown) => void;
|
|
124
|
+
/**
|
|
125
|
+
* DI: Регистрация зависимости.
|
|
126
|
+
* @template T
|
|
127
|
+
* @function provide
|
|
128
|
+
* @param {Token<T>} token - Токен для зависимости.
|
|
129
|
+
* @param {T | Factory<T>} valueOrFactory - Значение или фабрика для создания сервиса.
|
|
130
|
+
* @returns {void}
|
|
131
|
+
* @source
|
|
132
|
+
*/
|
|
133
|
+
provide<T>(token: Token<T>, valueOrFactory: T | Factory<T>): void;
|
|
134
|
+
/**
|
|
135
|
+
* DI: Инъекция; Получение сервиса по токену.
|
|
136
|
+
* @template T
|
|
137
|
+
* @function inject
|
|
138
|
+
* @param {Token<T>} token - Токен для зависимости.
|
|
139
|
+
* @returns {T} - Сервис.
|
|
140
|
+
* @source
|
|
141
|
+
*/
|
|
142
|
+
inject<T>(token: Token<T>): T;
|
|
143
|
+
/**
|
|
144
|
+
* Создание сигнала.
|
|
145
|
+
* @template T
|
|
146
|
+
* @function signal
|
|
147
|
+
* @param {T} initialValue - Начальное значение сигнала.
|
|
148
|
+
* @param {string | SignalOptions<T>} [optionsOrName] - Имя или опции сигнала.
|
|
149
|
+
* @returns {Signal<T>} - Сигнал.
|
|
150
|
+
* @source
|
|
151
|
+
*/
|
|
152
|
+
signal<T>(initialValue: T, optionsOrName?: string | SignalOptions<T>): Signal<T>;
|
|
153
|
+
/**
|
|
154
|
+
* Создание эффекта.
|
|
155
|
+
* @function effect
|
|
156
|
+
* @param {EffectFn} fn - Функция эффекта.
|
|
157
|
+
* @param {string} [label] - Необязательная метка для логирования и отладки.
|
|
158
|
+
* @returns {CleanupFn} - Функция для очистки эффекта.
|
|
159
|
+
* @source
|
|
160
|
+
*/
|
|
161
|
+
effect(fn: EffectFn, label?: string): CleanupFn;
|
|
162
|
+
private computedCache;
|
|
163
|
+
private cleanupRegistry;
|
|
164
|
+
/**
|
|
165
|
+
* Создание вычисляемого значения.
|
|
166
|
+
* @template T
|
|
167
|
+
* @function computed
|
|
168
|
+
* @param {Function} fn - Функция для вычисления значения.
|
|
169
|
+
* @param {string} [signalName] - Имя сигнала.
|
|
170
|
+
* @returns {Computed<T>} - Вычисляемое значение с методом destroy.
|
|
171
|
+
* @source
|
|
172
|
+
*/
|
|
173
|
+
computed<T>(fn: () => T, signalName?: string): Computed<T>;
|
|
174
|
+
/**
|
|
175
|
+
* Создание реактивного объекта (Proxy).
|
|
176
|
+
* @template T
|
|
177
|
+
* @function reactive
|
|
178
|
+
* @param {T} target - Целевой объект для проксирования.
|
|
179
|
+
* @param {string} [name] - Имя проксируемого объекта.
|
|
180
|
+
* @returns {T} - Реактивный объект.
|
|
181
|
+
* @source
|
|
182
|
+
*/
|
|
183
|
+
reactive<T extends object>(target: T, name?: string): T;
|
|
184
|
+
/**
|
|
185
|
+
* Группировка изменений. (Оставил для обратной совместимости)
|
|
186
|
+
* @function batch
|
|
187
|
+
* @param {Function} fn - Функция для выполнения в группе.
|
|
188
|
+
* @returns {void}
|
|
189
|
+
* @source
|
|
190
|
+
*/
|
|
191
|
+
batch(fn: () => void): void;
|
|
192
|
+
/**
|
|
193
|
+
* Вспомогательная функция для задержки (sleep), чувствительная к AbortSignal
|
|
194
|
+
*
|
|
195
|
+
* Вызов new DOMException('Aborted', 'AbortError') гарантирует,
|
|
196
|
+
* что ваша кастомная пауза между ретраями this.delay притворяется для движка JavaScript
|
|
197
|
+
* точно таким же нативным процессом отмены, как и fetch().
|
|
198
|
+
* Это делает реактивное ядро бесшовным и избавляет от необходимости
|
|
199
|
+
* писать кучу разных проверок под каждый тип ошибки.
|
|
200
|
+
*/
|
|
201
|
+
private delay;
|
|
202
|
+
/**
|
|
203
|
+
* Создание асинхронного ресурса. Типы на входе: <T - формат ответа, S - источник изменений (сигнал либо computed-кортеж из зачений сигналов через конструкцию `.value`)>
|
|
204
|
+
*
|
|
205
|
+
* Explained 👉 {@link https://github.com/garage-13/reactive-engine/blob/main/README_EN.md#1-async-resources-dependent-on-multiple-signals}
|
|
206
|
+
*
|
|
207
|
+
* @template T, S
|
|
208
|
+
* @see {@link https://github.com/garage-13/reactive-engine/blob/main/examples/200-resource/Example200.tsx Реализация базового компонента Example200}
|
|
209
|
+
* @see {@link https://github.com/garage-13/reactive-engine/blob/main/examples/201-multi-resource/service.secondary.ts Сложный пример зависимости ресурсов через computed}
|
|
210
|
+
* @function resource
|
|
211
|
+
* @param {Function} fetcher - Асинхронная функция для загрузки данных.
|
|
212
|
+
* @param {{ value: S }} [source] - Источник данных.
|
|
213
|
+
* @param {string | ResourceOptions<T>} [optionsOrName] - Имя сигнала или объект конфигурации `{ name: string; validate: (res) => boolean | string; resetDataOnSourceChange?: boolean }`.
|
|
214
|
+
* @returns {Resource<T>} - Асинхронный ресурс.
|
|
215
|
+
*
|
|
216
|
+
* @example
|
|
217
|
+
* // Базовый вызов со строкой (обратная совместимость):
|
|
218
|
+
* const res = engine.resource(fetcher, source, 'my-resource-name');
|
|
219
|
+
*
|
|
220
|
+
* @example
|
|
221
|
+
* // Современный вызов с валидацией ответа:
|
|
222
|
+
* const res = engine.resource(fetcher, source, {
|
|
223
|
+
* name: 'my-resource-name',
|
|
224
|
+
* resetDataOnSourceChange: true, // true by default
|
|
225
|
+
* responseValidate: (data) => !!data || 'Данные пусты', // Проверяйте формат в соотв. с дженериком
|
|
226
|
+
* });
|
|
227
|
+
*
|
|
228
|
+
* @example
|
|
229
|
+
* // (Экспериментальная фича)
|
|
230
|
+
* // В теле fetcher можно выкинуть ошибку в виде
|
|
231
|
+
* // `throw new Error('[THROW_CUSTOM_VALIDATION_ERROR_NO_RETRY=1][MESSAGE=Your msg]')`
|
|
232
|
+
* // Причина: Особенности внутренней реализации определения харакрера ошибки и необходимость делать retry (если такая опция передана)
|
|
233
|
+
* // Рекомендуем вместо этого использовать `validateBeforeFetch` в опциях при создании ресурса.
|
|
234
|
+
* const res = engine.resource(
|
|
235
|
+
* async (counterValue, abortSignal) => {
|
|
236
|
+
* if (counterValue === 0)
|
|
237
|
+
* throw new Error([
|
|
238
|
+
* '[THROW_CUSTOM_VALIDATION_ERROR_NO_RETRY=1]', // Иначе запустится механизм retry (напр. по причине отсутствия сети, далее в этом же примере)
|
|
239
|
+
* `[MESSAGE=Stop for count value ${counterValue} - excepted from fetcher fn body]`,
|
|
240
|
+
* ].join(' '))
|
|
241
|
+
* const res = await fetch(
|
|
242
|
+
* [
|
|
243
|
+
* `${BASE_API_URL}/profile/search`,
|
|
244
|
+
* '?',
|
|
245
|
+
* [
|
|
246
|
+
* `counter=${counterValue}`,
|
|
247
|
+
* '_responseDelay=2000',
|
|
248
|
+
* ].join('&')
|
|
249
|
+
* ].join(''),
|
|
250
|
+
* { signal: abortSignal }
|
|
251
|
+
* )
|
|
252
|
+
* if (!res.ok) throw new Error(`HTTP error! status: ${res.status}`)
|
|
253
|
+
* return res.json()
|
|
254
|
+
* },
|
|
255
|
+
* this.counter,
|
|
256
|
+
* )
|
|
257
|
+
* @source
|
|
258
|
+
*/
|
|
259
|
+
resource<T, S = void>(fetcher: (source: S, signal: AbortSignal) => Promise<T>, source?: {
|
|
260
|
+
value: S;
|
|
261
|
+
}, optionsOrName?: string | ResourceOptions<T, S>): Resource<T>;
|
|
262
|
+
/**
|
|
263
|
+
* Выполняет функцию без отслеживания зависимостей.
|
|
264
|
+
* @template T
|
|
265
|
+
* @function untrack
|
|
266
|
+
* @param {Function} fn - Функция для выполнения.
|
|
267
|
+
* @returns {T} - Результат выполнения функции.
|
|
268
|
+
* @source
|
|
269
|
+
*/
|
|
270
|
+
untrack<T>(fn: () => T): T;
|
|
271
|
+
/**
|
|
272
|
+
* Безопасное выполнение функции.
|
|
273
|
+
* @private
|
|
274
|
+
* @function safeRun
|
|
275
|
+
* @param {IEffect} effect - Эффект.
|
|
276
|
+
* @param {Function} fn - Функция для выполнения.
|
|
277
|
+
* @returns {void}
|
|
278
|
+
* @source
|
|
279
|
+
*/
|
|
280
|
+
private safeRun;
|
|
281
|
+
}
|
|
282
|
+
//# sourceMappingURL=core.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"core.d.ts","sourceRoot":"","sources":["../../src/core/core.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"core.test.d.ts","sourceRoot":"","sources":["../../src/core/core.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/core/index.ts"],"names":[],"mappings":"AAAA,cAAc,QAAQ,CAAA;AACtB,cAAc,SAAS,CAAA;AACvB,cAAc,mBAAmB,CAAA;AACjC,cAAc,yBAAyB,CAAA"}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
export interface ResourceState<T> {
|
|
2
|
+
data: T | null;
|
|
3
|
+
loading: boolean;
|
|
4
|
+
error: any | null;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Функция для очистки эффекта.
|
|
8
|
+
* @typedef {() => void} CleanupFn
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* Функция эффекта, которая может возвращать функцию очистки.
|
|
12
|
+
* @typedef {() => CleanupFn | void} EffectFn
|
|
13
|
+
*/
|
|
14
|
+
/**
|
|
15
|
+
* Токен для зависимости.
|
|
16
|
+
* @typedef {string | symbol | { new(engine: ReactiveEngine, ...args: any[]): T }} Token<T>
|
|
17
|
+
*/
|
|
18
|
+
/**
|
|
19
|
+
* Фабрика для создания сервиса.
|
|
20
|
+
* @template T
|
|
21
|
+
* @typedef {(engine: ReactiveEngine) => T} Factory<T>
|
|
22
|
+
*/
|
|
23
|
+
/**
|
|
24
|
+
* Интерфейс для состояния ресурса.
|
|
25
|
+
* @template T Data format
|
|
26
|
+
* @interface ResourceState<T>
|
|
27
|
+
*/
|
|
28
|
+
export interface ResourceState<T> {
|
|
29
|
+
/**
|
|
30
|
+
* Данные ресурса.
|
|
31
|
+
* @type {T | null}
|
|
32
|
+
*/
|
|
33
|
+
data: T | null;
|
|
34
|
+
/**
|
|
35
|
+
* Состояние загрузки ресурса.
|
|
36
|
+
* @type {boolean}
|
|
37
|
+
*/
|
|
38
|
+
loading: boolean;
|
|
39
|
+
/**
|
|
40
|
+
* Ошибка ресурса.
|
|
41
|
+
* @type {any | null}
|
|
42
|
+
*/
|
|
43
|
+
error: any | null;
|
|
44
|
+
/** Флаг активного процесса повторных попыток после сбоя сети */
|
|
45
|
+
isRetrying: boolean;
|
|
46
|
+
}
|
|
47
|
+
export interface ResourceOptions<T, S> {
|
|
48
|
+
name: string;
|
|
49
|
+
/** Автоматически сбрасывать data в null при изменении source. По умолчанию: true */
|
|
50
|
+
resetDataOnSourceChange?: boolean;
|
|
51
|
+
/** Функция для валидации успешного ответа сервера перед его сохранением в стейт.
|
|
52
|
+
*
|
|
53
|
+
* Варианты возвращаемого значения:
|
|
54
|
+
* - true 👉 все ок
|
|
55
|
+
* - false 👉 в error попадет стандартный текст ошибки
|
|
56
|
+
* - string 👉 попадет в поле error
|
|
57
|
+
* */
|
|
58
|
+
responseValidate?: (responseData: T) => boolean | string;
|
|
59
|
+
/** Функция валидации входных зависимостей (source) перед запуском fetch.
|
|
60
|
+
* Если возвращает false или string (текст ошибки) — запрос и ретраи блокируются. */
|
|
61
|
+
validateBeforeFetch?: (sourceValue: S) => boolean | string;
|
|
62
|
+
/** Настройка лимита повторов retry. */
|
|
63
|
+
retryCount?: number;
|
|
64
|
+
/** Настройка задержки первого повтора retry. */
|
|
65
|
+
retryDelay?: number;
|
|
66
|
+
/** Включить экспоненциальное увеличение задержки (каждая попытка ждет в 2 раза дольше). По умолчанию: false */
|
|
67
|
+
isExponentialBackoffEnabled?: boolean;
|
|
68
|
+
/** Максимальный лимит ожидания между попытками в миллисекундах. По умолчанию: 30000 (30 секунд) */
|
|
69
|
+
maxRetryDelay?: number;
|
|
70
|
+
/** Максимальное время ожидания ответа сервера в миллисекундах. По умолчанию: отсутствует (бесконечно) */
|
|
71
|
+
timeout?: number;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Интерфейс для опций сигнала.
|
|
75
|
+
* @template T
|
|
76
|
+
* @interface SignalOptions<T>
|
|
77
|
+
*/
|
|
78
|
+
export interface SignalOptions<T> {
|
|
79
|
+
/**
|
|
80
|
+
* Имя сигнала.
|
|
81
|
+
* @type {string}
|
|
82
|
+
*/
|
|
83
|
+
name?: string;
|
|
84
|
+
/**
|
|
85
|
+
* Валидатор значения сигнала.
|
|
86
|
+
* @function validate
|
|
87
|
+
* @param {T} val - Значение для валидации.
|
|
88
|
+
* @returns {boolean | string} - Результат валидации.
|
|
89
|
+
*/
|
|
90
|
+
validate?: (val: T) => boolean | string;
|
|
91
|
+
}
|
|
92
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/core/types.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,aAAa,CAAC,CAAC;IAC9B,IAAI,EAAE,CAAC,GAAG,IAAI,CAAC;IACf,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,GAAG,GAAG,IAAI,CAAC;CACnB;AAED;;;GAGG;AAEH;;;GAGG;AAEH;;;GAGG;AAEH;;;;GAIG;AAEH;;;;GAIG;AACH,MAAM,WAAW,aAAa,CAAC,CAAC;IAC9B;;;OAGG;IACH,IAAI,EAAE,CAAC,GAAG,IAAI,CAAC;IAEf;;;OAGG;IACH,OAAO,EAAE,OAAO,CAAC;IAEjB;;;OAGG;IACH,KAAK,EAAE,GAAG,GAAG,IAAI,CAAC;IAElB,gEAAgE;IAChE,UAAU,EAAE,OAAO,CAAC;CACrB;AAED,MAAM,WAAW,eAAe,CAAC,CAAC,EAAE,CAAC;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,oFAAoF;IACpF,uBAAuB,CAAC,EAAE,OAAO,CAAC;IAClC;;;;;;SAMK;IACL,gBAAgB,CAAC,EAAE,CAAC,YAAY,EAAE,CAAC,KAAK,OAAO,GAAG,MAAM,CAAC;IACzD;wFACoF;IACpF,mBAAmB,CAAC,EAAE,CAAC,WAAW,EAAE,CAAC,KAAK,OAAO,GAAG,MAAM,CAAC;IAC3D,uCAAuC;IACvC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,gDAAgD;IAChD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,+GAA+G;IAC/G,2BAA2B,CAAC,EAAE,OAAO,CAAC;IACtC,mGAAmG;IACnG,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,yGAAyG;IACzG,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;;;GAIG;AACH,MAAM,WAAW,aAAa,CAAC,CAAC;IAC9B;;;OAGG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IAEd;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,CAAC,GAAG,EAAE,CAAC,KAAK,OAAO,GAAG,MAAM,CAAC;CACzC"}
|
package/dist/core.cjs
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
const e=require("./utils/getExtractedValues.cjs");var t=class{activeEffect=null;isBatching=!1;pendingEffects=new Set;services=new Map;factories=new Map;proxyCache=new WeakMap;allEffects=new Set;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`}`)}}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(){return n.activeEffect&&i.add(n.activeEffect),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),i.forEach(e=>n.pendingEffects.add(e)),n.isBatching||(n.isBatching=!0,queueMicrotask(()=>{let e=Array.from(n.pendingEffects);n.pendingEffects.clear(),n.isBatching=!1,e.forEach(e=>e.run())}))},subscribe(e){return n.effect(()=>{e(this.value)})}}}effect(e,t){let n=this,r={label:t,cleanups:new Set,run(){this.cleanups.forEach(e=>e()),this.cleanups.clear();let t=n.activeEffect;n.activeEffect=this,n.safeRun(this,()=>{let t=e();typeof t==`function`&&this.cleanups.add(t)}),n.activeEffect=t}};return this.allEffects.add(r),r.run(),()=>{r.cleanups.forEach(e=>e()),n.pendingEffects.delete(r),n.allEffects.delete(r)}}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=this.signal(void 0,t||`unnamed_computed`),i=this.effect(()=>{let t=e();r.value=t}),a=Array.from(this.allEffects)[this.allEffects.size-1],o=()=>{i(),a&&n.allEffects.delete(a),n.computedCache.delete(e)},s={get value(){return r.value},subscribe:e=>r.subscribe(e),destroy(){o()}};return this.cleanupRegistry.register(s,o),this.computedCache.set(e,new WeakRef(s)),s}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){n.activeEffect&&(r.has(i)||r.set(i,new Set),r.get(i).add(n.activeEffect));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);return s===a||s!==a&&(Reflect.set(e,i,a,o),n.onSignalChange?.(`${t}.${String(i)}`,a,s),r.get(i)?.forEach(e=>n.isBatching?n.pendingEffects.add(e):e.run())),!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(t,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},a),g=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);h.value={data:n,loading:!1,error:Error(t),isRetrying:!1};return}}let o=i&&s?null:this.untrack(()=>h.value.data);h.value={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 e=await t(n,o);if(r.aborted)return;if(o.aborted)throw new DOMException(`The operation timed out.`,`TimeoutError`);if(c){let t=c(e);if(t===!1||typeof t==`string`){if(r.aborted)return;h.value={data:null,loading:!1,error:Error(typeof t==`string`?t:`Validation failed`),isRetrying:!1};return}}if(r.aborted)return;h.value={data:e,loading:!1,error:null,isRetrying:!1};return}catch(t){if(r.aborted||t.name===`AbortError`&&r.aborted)return;let n=t.name===`TimeoutError`||t.name===`AbortError`||t.message?.includes(`timeout`),o=e.getExtractedValues({tested:[t.message],expectedKey:`THROW_CUSTOM_VALIDATION_ERROR_NO_RETRY`,valueType:`number`})?.[0]===`1`||!1,s=o&&e.getExtractedValues({tested:[t.message],expectedKey:`MESSAGE`,valueType:`string`})?.[0]||`Custom validation error`,c=o||t.name===`ValidationError`;if(i===u||c){if(r.aborted)return;let e=n?Error(`Request timed out after ${m}ms`,{cause:t}):o?Error(s,{cause:t}):t;h.value={data:null,loading:!1,error:e,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,h.value={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}}}}},_=null;return this.effect(()=>{let e=n?n.value:void 0,t=new AbortController;return _=t,this.untrack(()=>{g(e,t.signal,!0)}),()=>t.abort()}),{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:()=>{_?.abort(),_=new AbortController,g(n?n.value:void 0,_.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)}}};exports.ReactiveEngine=t;
|
|
2
|
+
//# sourceMappingURL=core.cjs.map
|