@pravosleva/reactive-engine 0.2.9-beta → 0.3.0-beta
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +3 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +55 -3
- package/dist/index.iife.js +3 -3
- package/dist/index.iife.js.map +1 -1
- package/dist/index.mjs +255 -319
- package/dist/index.mjs.map +1 -1
- package/package.json +23 -6
package/dist/index.mjs
CHANGED
|
@@ -1,320 +1,256 @@
|
|
|
1
|
-
import { useEffect as
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
* @function use
|
|
253
|
-
* @param {{ value: T; subscribe: (cb: (v: T) => void) => CleanupFn }} item - Реактивный объект.
|
|
254
|
-
* @returns {T} - Значение реактивного объекта.
|
|
255
|
-
*/
|
|
256
|
-
use(e) {
|
|
257
|
-
if (!this.reactAdapters)
|
|
258
|
-
throw new Error("[React Error]: Адаптеры React не установлены. Вызовите engine.setReactAdapters(useState, useEffect).");
|
|
259
|
-
if (!e || typeof e.subscribe != "function") {
|
|
260
|
-
const n = `
|
|
261
|
-
[Reactive Error]: engine.use() получил некорректный объект!
|
|
262
|
-
Скорее всего, вы пытаетесь подписаться на свойство сервиса, которое не было инициализировано.
|
|
263
|
-
Проверьте, что в классе написано: public mySignal = this.engine.signal(...)
|
|
264
|
-
`;
|
|
265
|
-
throw console.error(n, { item: e }), new Error(n);
|
|
266
|
-
}
|
|
267
|
-
const [t, r] = this.reactAdapters.useState(e.value);
|
|
268
|
-
return this.reactAdapters.useEffect(
|
|
269
|
-
() => e.subscribe(r),
|
|
270
|
-
[e]
|
|
271
|
-
), t;
|
|
272
|
-
}
|
|
273
|
-
/**
|
|
274
|
-
* Безопасное выполнение функции.
|
|
275
|
-
* @private
|
|
276
|
-
* @function safeRun
|
|
277
|
-
* @param {IEffect} effect - Эффект.
|
|
278
|
-
* @param {Function} fn - Функция для выполнения.
|
|
279
|
-
* @returns {void}
|
|
280
|
-
*/
|
|
281
|
-
safeRun(e, t) {
|
|
282
|
-
try {
|
|
283
|
-
t();
|
|
284
|
-
} catch (r) {
|
|
285
|
-
console.error(
|
|
286
|
-
"%c[Reactive Error] %cОшибка в эффекте/computed:",
|
|
287
|
-
"color: white; background: red; padding: 2px 4px; border-radius: 3px;",
|
|
288
|
-
"font-weight: bold;",
|
|
289
|
-
r
|
|
290
|
-
);
|
|
291
|
-
}
|
|
292
|
-
}
|
|
293
|
-
}
|
|
294
|
-
class E {
|
|
295
|
-
constructor(e) {
|
|
296
|
-
this.engine = e;
|
|
297
|
-
}
|
|
298
|
-
engine;
|
|
299
|
-
// Просто сохраняем engine
|
|
300
|
-
createNumericSignal(e, t) {
|
|
301
|
-
return this.engine.signal(e, {
|
|
302
|
-
name: t,
|
|
303
|
-
validate: (r) => typeof r == "number" && !isNaN(r)
|
|
304
|
-
});
|
|
305
|
-
}
|
|
306
|
-
}
|
|
307
|
-
class p {
|
|
308
|
-
constructor(e) {
|
|
309
|
-
this.engine = e, setTimeout(() => this.onInit(), 0);
|
|
310
|
-
}
|
|
311
|
-
engine;
|
|
312
|
-
onInit() {
|
|
313
|
-
}
|
|
314
|
-
}
|
|
315
|
-
export {
|
|
316
|
-
E as BaseREService,
|
|
317
|
-
p as BaseREServiceEnhanced,
|
|
318
|
-
v as ReactiveEngine
|
|
1
|
+
import { useCallback as e, useEffect as t, useMemo as n, useRef as r, useState as i, useSyncExternalStore as a } from "react";
|
|
2
|
+
//#region src/BaseREService.ts
|
|
3
|
+
var o = class {
|
|
4
|
+
engine;
|
|
5
|
+
constructor(e) {
|
|
6
|
+
this.engine = e;
|
|
7
|
+
}
|
|
8
|
+
createNumericSignal(e, t) {
|
|
9
|
+
return this.engine.signal(e, {
|
|
10
|
+
name: t,
|
|
11
|
+
validate: (e) => typeof e == "number" && !isNaN(e)
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
}, s = class {
|
|
15
|
+
engine;
|
|
16
|
+
constructor(e) {
|
|
17
|
+
this.engine = e, setTimeout(() => this.onInit(), 0);
|
|
18
|
+
}
|
|
19
|
+
onInit() {}
|
|
20
|
+
}, c = class {
|
|
21
|
+
activeEffect = null;
|
|
22
|
+
isBatching = !1;
|
|
23
|
+
pendingEffects = /* @__PURE__ */ new Set();
|
|
24
|
+
services = /* @__PURE__ */ new Map();
|
|
25
|
+
factories = /* @__PURE__ */ new Map();
|
|
26
|
+
proxyCache = /* @__PURE__ */ new WeakMap();
|
|
27
|
+
allEffects = /* @__PURE__ */ new Set();
|
|
28
|
+
onSignalChange;
|
|
29
|
+
reactAdapters = {
|
|
30
|
+
useState: i,
|
|
31
|
+
useEffect: t
|
|
32
|
+
};
|
|
33
|
+
provide(e, t) {
|
|
34
|
+
typeof t == "function" && !t.prototype ? this.factories.set(e, t) : this.services.set(e, t);
|
|
35
|
+
}
|
|
36
|
+
inject(e) {
|
|
37
|
+
if (!e) throw Error("[DI Error]: Вы пытаетесь внедрить пустой токен (undefined/null). Проверьте импорты.");
|
|
38
|
+
if (this.services.has(e)) return this.services.get(e);
|
|
39
|
+
try {
|
|
40
|
+
let t = this.factories.get(e);
|
|
41
|
+
if (t) {
|
|
42
|
+
let n = t(this);
|
|
43
|
+
return this.services.set(e, n), n;
|
|
44
|
+
}
|
|
45
|
+
if (typeof e == "function" && e.prototype) {
|
|
46
|
+
let t = new e(this);
|
|
47
|
+
return this.services.set(e, t), t;
|
|
48
|
+
}
|
|
49
|
+
throw Error(`Service not found: ${String(e)}`);
|
|
50
|
+
} catch (t) {
|
|
51
|
+
throw Error(`[DI Error]: Не удалось создать сервис ${String(e)}. Ошибка: ${t?.message || "No e?.message"}`);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
signal(e, t) {
|
|
55
|
+
let n = this, r = e, i = /* @__PURE__ */ new Set(), a = typeof t == "string" ? { name: t } : t || {}, o = a.name || "unnamed_signal";
|
|
56
|
+
return {
|
|
57
|
+
get value() {
|
|
58
|
+
return n.activeEffect && i.add(n.activeEffect), r;
|
|
59
|
+
},
|
|
60
|
+
set value(e) {
|
|
61
|
+
if (r === e) return;
|
|
62
|
+
if (a.validate) {
|
|
63
|
+
let t = a.validate(e);
|
|
64
|
+
if (t === !1 || typeof t == "string") {
|
|
65
|
+
let n = typeof t == "string" ? t : `[Validation Error]: Некорректное значение для сигнала "${o}"`;
|
|
66
|
+
console.error(`%c${n}`, "color: orange; font-weight: bold;", {
|
|
67
|
+
received: e,
|
|
68
|
+
current: r
|
|
69
|
+
});
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
let t = r;
|
|
74
|
+
r = e, n.onSignalChange?.(o, e, t), i.forEach((e) => n.pendingEffects.add(e)), n.isBatching || (n.isBatching = !0, queueMicrotask(() => {
|
|
75
|
+
let e = Array.from(n.pendingEffects);
|
|
76
|
+
n.pendingEffects.clear(), n.isBatching = !1, e.forEach((e) => e.run());
|
|
77
|
+
}));
|
|
78
|
+
},
|
|
79
|
+
subscribe(e) {
|
|
80
|
+
return n.effect(() => {
|
|
81
|
+
e(this.value);
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
effect(e) {
|
|
87
|
+
let t = this, n = {
|
|
88
|
+
cleanups: /* @__PURE__ */ new Set(),
|
|
89
|
+
run() {
|
|
90
|
+
this.cleanups.forEach((e) => e()), this.cleanups.clear();
|
|
91
|
+
let n = t.activeEffect;
|
|
92
|
+
t.activeEffect = this, t.safeRun(this, () => {
|
|
93
|
+
let t = e();
|
|
94
|
+
typeof t == "function" && this.cleanups.add(t);
|
|
95
|
+
}), t.activeEffect = n;
|
|
96
|
+
}
|
|
97
|
+
};
|
|
98
|
+
return this.allEffects.add(n), n.run(), () => {
|
|
99
|
+
n.cleanups.forEach((e) => e()), t.pendingEffects.delete(n), t.allEffects.delete(n);
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
computedCache = /* @__PURE__ */ new Map();
|
|
103
|
+
computed(e, t) {
|
|
104
|
+
if (this.computedCache.has(e)) return this.computedCache.get(e);
|
|
105
|
+
let n = this, r = this.signal(void 0, t || "unnamed_computed"), i = this.effect(() => {
|
|
106
|
+
let t = e();
|
|
107
|
+
r.value = t;
|
|
108
|
+
}), a = Array.from(this.allEffects)[this.allEffects.size - 1], o = {
|
|
109
|
+
get value() {
|
|
110
|
+
return r.value;
|
|
111
|
+
},
|
|
112
|
+
subscribe: (e) => r.subscribe(e),
|
|
113
|
+
destroy() {
|
|
114
|
+
i(), a && n.allEffects.delete(a), n.computedCache.delete(e);
|
|
115
|
+
}
|
|
116
|
+
};
|
|
117
|
+
return this.computedCache.set(e, o), o;
|
|
118
|
+
}
|
|
119
|
+
reactive(e, t = "reactive") {
|
|
120
|
+
if (this.proxyCache.has(e)) return this.proxyCache.get(e);
|
|
121
|
+
let n = this, r = /* @__PURE__ */ new Map(), i = new Proxy(e, {
|
|
122
|
+
get(e, i, a) {
|
|
123
|
+
n.activeEffect && (r.has(i) || r.set(i, /* @__PURE__ */ new Set()), r.get(i).add(n.activeEffect));
|
|
124
|
+
let o = Reflect.get(e, i, a);
|
|
125
|
+
return typeof o == "object" && o ? n.reactive(o, `${t}.${String(i)}`) : o;
|
|
126
|
+
},
|
|
127
|
+
set(e, i, a, o) {
|
|
128
|
+
let s = Reflect.get(e, i, o);
|
|
129
|
+
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;
|
|
130
|
+
}
|
|
131
|
+
});
|
|
132
|
+
return this.proxyCache.set(e, i), i;
|
|
133
|
+
}
|
|
134
|
+
batch(e) {
|
|
135
|
+
e();
|
|
136
|
+
}
|
|
137
|
+
resource(e, t, n) {
|
|
138
|
+
let r = this.signal({
|
|
139
|
+
data: null,
|
|
140
|
+
loading: !0,
|
|
141
|
+
error: null
|
|
142
|
+
}, n || "unnamed_resource"), i = null, a = async (t) => {
|
|
143
|
+
i?.abort(), i = new AbortController();
|
|
144
|
+
let n = this.untrack(() => r.value.data);
|
|
145
|
+
r.value = {
|
|
146
|
+
data: n,
|
|
147
|
+
loading: !0,
|
|
148
|
+
error: null
|
|
149
|
+
};
|
|
150
|
+
try {
|
|
151
|
+
let n = await e(t, i.signal);
|
|
152
|
+
i.signal.aborted || (r.value = {
|
|
153
|
+
data: n,
|
|
154
|
+
loading: !1,
|
|
155
|
+
error: null
|
|
156
|
+
});
|
|
157
|
+
} catch (e) {
|
|
158
|
+
e.name !== "AbortError" && (r.value = {
|
|
159
|
+
data: null,
|
|
160
|
+
loading: !1,
|
|
161
|
+
error: e
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
};
|
|
165
|
+
return this.effect(() => {
|
|
166
|
+
let e = t ? t.value : void 0;
|
|
167
|
+
return a(e), () => i?.abort();
|
|
168
|
+
}), {
|
|
169
|
+
get data() {
|
|
170
|
+
return r.value.data;
|
|
171
|
+
},
|
|
172
|
+
get loading() {
|
|
173
|
+
return r.value.loading;
|
|
174
|
+
},
|
|
175
|
+
get error() {
|
|
176
|
+
return r.value.error;
|
|
177
|
+
},
|
|
178
|
+
get value() {
|
|
179
|
+
return r.value;
|
|
180
|
+
},
|
|
181
|
+
refetch: () => a(t ? t.value : void 0),
|
|
182
|
+
subscribe: (e) => r.subscribe(e)
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
untrack(e) {
|
|
186
|
+
let t = this.activeEffect;
|
|
187
|
+
this.activeEffect = null;
|
|
188
|
+
try {
|
|
189
|
+
return e();
|
|
190
|
+
} finally {
|
|
191
|
+
this.activeEffect = t;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
setReactAdapters(e, t) {
|
|
195
|
+
this.reactAdapters = {
|
|
196
|
+
useState: e,
|
|
197
|
+
useEffect: t
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
use(e) {
|
|
201
|
+
if (!this.reactAdapters) throw Error("[React Error]: Адаптеры React не установлены. Вызовите engine.setReactAdapters(useState, useEffect).");
|
|
202
|
+
if (!e || typeof e.subscribe != "function") {
|
|
203
|
+
let t = "\n [Reactive Error]: engine.use() получил некорректный объект!\n Скорее всего, вы пытаетесь подписаться на свойство сервиса, которое не было инициализировано.\n Проверьте, что в классе написано: public mySignal = this.engine.signal(...)\n ";
|
|
204
|
+
throw console.error(t, { item: e }), Error(t);
|
|
205
|
+
}
|
|
206
|
+
let [t, n] = this.reactAdapters.useState(e.value);
|
|
207
|
+
return this.reactAdapters.useEffect(() => e.subscribe(n), [e]), t;
|
|
208
|
+
}
|
|
209
|
+
safeRun(e, t) {
|
|
210
|
+
try {
|
|
211
|
+
t();
|
|
212
|
+
} catch (e) {
|
|
213
|
+
console.error("%c[Reactive Error] %cОшибка в эффекте/computed:", "color: white; background: red; padding: 2px 4px; border-radius: 3px;", "font-weight: bold;", e);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
}, l = (e, t = {}) => {
|
|
217
|
+
let n = t.ttl ?? 300 * 1e3, r = /* @__PURE__ */ new Map();
|
|
218
|
+
return async (t, i) => {
|
|
219
|
+
let a = typeof t == "object" && t ? JSON.stringify(t) : String(t), o = Date.now(), s = r.get(a);
|
|
220
|
+
if (s && o - s.timestamp < n) return s.data;
|
|
221
|
+
let c = await e(t, i);
|
|
222
|
+
return r.set(a, {
|
|
223
|
+
data: c,
|
|
224
|
+
timestamp: Date.now()
|
|
225
|
+
}), c;
|
|
226
|
+
};
|
|
227
|
+
}, u = (e, n) => {
|
|
228
|
+
let i = r(n);
|
|
229
|
+
t(() => {
|
|
230
|
+
i.current = n;
|
|
231
|
+
}, [n]), t(() => e.subscribe((e) => {
|
|
232
|
+
i.current(e);
|
|
233
|
+
}), [e]);
|
|
234
|
+
}, d = (r) => {
|
|
235
|
+
let i = n(() => typeof r == "function" ? r() : r, [r]), o = e((e) => i.subscribe(e), [i]), s = e(() => i.value, [i]);
|
|
236
|
+
return t(() => () => {
|
|
237
|
+
i && typeof i.destroy == "function" && i.destroy();
|
|
238
|
+
}, [i]), a(o, s);
|
|
239
|
+
}, f = (e) => {
|
|
240
|
+
let a = n(() => typeof e == "function" ? e() : e, [e]), [o, s] = i(a.value), c = r(s);
|
|
241
|
+
return t(() => {
|
|
242
|
+
c.current = s;
|
|
243
|
+
}, [s]), t(() => {
|
|
244
|
+
c.current(a.value);
|
|
245
|
+
let e = a.subscribe((e) => {
|
|
246
|
+
c.current(e);
|
|
247
|
+
});
|
|
248
|
+
return () => {
|
|
249
|
+
e(), a && typeof a.destroy == "function" && a.destroy();
|
|
250
|
+
};
|
|
251
|
+
}, [a]), o;
|
|
319
252
|
};
|
|
320
|
-
//#
|
|
253
|
+
//#endregion
|
|
254
|
+
export { o as BaseREService, s as BaseREServiceEnhanced, c as ReactiveEngine, u as useReactiveSubscription, d as useReactiveValue, f as useReactiveValue0, l as withCache };
|
|
255
|
+
|
|
256
|
+
//# sourceMappingURL=index.mjs.map
|