@pravosleva/reactive-engine 2.6.4-alpha.9 → 2.7.0-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (88) hide show
  1. package/README.md +8 -8
  2. package/dist/core/core.d.ts +161 -0
  3. package/dist/core/core.d.ts.map +1 -1
  4. package/dist/core/core.effect.test.d.ts +2 -0
  5. package/dist/core/core.effect.test.d.ts.map +1 -0
  6. package/dist/core/core.method.computed.d.ts.map +1 -1
  7. package/dist/core/core.method.effect.d.ts.map +1 -1
  8. package/dist/core/core.method.signal.d.ts.map +1 -1
  9. package/dist/core.method.computed.mjs +3 -2
  10. package/dist/core.method.computed.mjs.map +1 -1
  11. package/dist/core.method.effect.mjs +65 -45
  12. package/dist/core.method.effect.mjs.map +1 -1
  13. package/dist/core.method.resource.mjs +3 -1
  14. package/dist/core.method.resource.mjs.map +1 -1
  15. package/dist/core.method.signal.mjs +4 -2
  16. package/dist/core.method.signal.mjs.map +1 -1
  17. package/dist/core.mjs +1 -0
  18. package/dist/core.mjs.map +1 -1
  19. package/dist/decorators/withValidation/withValidation.d.ts +2 -2
  20. package/dist/decorators/withValidation/withValidation.d.ts.map +1 -1
  21. package/dist/decorators/withValidation/withValidation.mjs +1 -1
  22. package/dist/decorators/withValidation/withValidation.mjs.map +1 -1
  23. package/dist/decorators/withValidation/withValidation.test.d.ts +2 -0
  24. package/dist/decorators/withValidation/withValidation.test.d.ts.map +1 -0
  25. package/dist/index.mjs +2 -2
  26. package/dist/reactive-engine.umd.js +2 -2
  27. package/dist/reactive-engine.umd.js.map +1 -1
  28. package/package.json +8 -11
  29. package/dist/AbstractService.cjs +0 -2
  30. package/dist/AbstractService.cjs.map +0 -1
  31. package/dist/BaseREServiceEnhanced.cjs +0 -2
  32. package/dist/BaseREServiceEnhanced.cjs.map +0 -1
  33. package/dist/angular/core.angular-adapter.cjs +0 -2
  34. package/dist/angular/core.angular-adapter.cjs.map +0 -1
  35. package/dist/angular/index.cjs +0 -2
  36. package/dist/angular/index.cjs.map +0 -1
  37. package/dist/core.autolog.cjs +0 -2
  38. package/dist/core.autolog.cjs.map +0 -1
  39. package/dist/core.automatic.cjs +0 -2
  40. package/dist/core.automatic.cjs.map +0 -1
  41. package/dist/core.cjs +0 -2
  42. package/dist/core.cjs.map +0 -1
  43. package/dist/core.global.cjs +0 -2
  44. package/dist/core.global.cjs.map +0 -1
  45. package/dist/core.logger.cjs +0 -2
  46. package/dist/core.logger.cjs.map +0 -1
  47. package/dist/core.method.computed.cjs +0 -2
  48. package/dist/core.method.computed.cjs.map +0 -1
  49. package/dist/core.method.effect.cjs +0 -2
  50. package/dist/core.method.effect.cjs.map +0 -1
  51. package/dist/core.method.reactive.cjs +0 -2
  52. package/dist/core.method.reactive.cjs.map +0 -1
  53. package/dist/core.method.resource.cjs +0 -2
  54. package/dist/core.method.resource.cjs.map +0 -1
  55. package/dist/core.method.signal.cjs +0 -2
  56. package/dist/core.method.signal.cjs.map +0 -1
  57. package/dist/core.method.untrack.cjs +0 -2
  58. package/dist/core.method.untrack.cjs.map +0 -1
  59. package/dist/decorators/withCache/withCache.cjs +0 -2
  60. package/dist/decorators/withCache/withCache.cjs.map +0 -1
  61. package/dist/decorators/withDebounce/withDebounce.cjs +0 -2
  62. package/dist/decorators/withDebounce/withDebounce.cjs.map +0 -1
  63. package/dist/decorators/withLongPolling/withLongPolling.cjs +0 -2
  64. package/dist/decorators/withLongPolling/withLongPolling.cjs.map +0 -1
  65. package/dist/decorators/withStaleWhileRevalidate/withStaleWhileRevalidate.cjs +0 -2
  66. package/dist/decorators/withStaleWhileRevalidate/withStaleWhileRevalidate.cjs.map +0 -1
  67. package/dist/decorators/withThrottle/withThrottle.cjs +0 -2
  68. package/dist/decorators/withThrottle/withThrottle.cjs.map +0 -1
  69. package/dist/decorators/withThrottleAndCache/withThrottleAndCache.cjs +0 -2
  70. package/dist/decorators/withThrottleAndCache/withThrottleAndCache.cjs.map +0 -1
  71. package/dist/decorators/withThrottleComputed/withThrottleComputed.cjs +0 -2
  72. package/dist/decorators/withThrottleComputed/withThrottleComputed.cjs.map +0 -1
  73. package/dist/decorators/withValidation/withValidation.cjs +0 -2
  74. package/dist/decorators/withValidation/withValidation.cjs.map +0 -1
  75. package/dist/index.cjs +0 -1
  76. package/dist/index2.cjs +0 -1
  77. package/dist/react/hooks/useReactiveSubscription.cjs +0 -2
  78. package/dist/react/hooks/useReactiveSubscription.cjs.map +0 -1
  79. package/dist/react/hooks/useReactiveValue.cjs +0 -2
  80. package/dist/react/hooks/useReactiveValue.cjs.map +0 -1
  81. package/dist/react/index.cjs +0 -2
  82. package/dist/react/index.cjs.map +0 -1
  83. package/dist/utils/getExtractedValues.cjs +0 -2
  84. package/dist/utils/getExtractedValues.cjs.map +0 -1
  85. package/dist/vue/core.vue-adapter.cjs +0 -2
  86. package/dist/vue/core.vue-adapter.cjs.map +0 -1
  87. package/dist/vue/index.cjs +0 -2
  88. package/dist/vue/index.cjs.map +0 -1
package/README.md CHANGED
@@ -213,7 +213,7 @@ Copying external async state directly into local mutable signals introduces sync
213
213
  // ❌ Mirroring Trap (Causes redundant pushes & recursion)
214
214
  engine.effect(() => {
215
215
  const data = apiResource.data
216
- if (data) localSignal.value = data
216
+ if (data) localSignal.value = data
217
217
  })
218
218
 
219
219
  // 🟢 Canonical Pattern (Pure Lazy Derivation)
@@ -229,7 +229,7 @@ To eliminate parent re-renders in deep form trees, push state subscriptions down
229
229
  ## Architecture-Grade Form Wizard (Example 254)
230
230
  This enterprise-ready multi-step form implementation demonstrates absolute separation of concerns: state, cross-step validation schemas, and API fetch mechanics are completely decoupled from React.
231
231
 
232
- 1. Action Validation Decorators (`withValidation.ts`)
232
+ 1. Action Validation Decorators (`withValidationSync.ts`)
233
233
  ```ts
234
234
  import { Signal } from '@pravosleva/reactive-engine'
235
235
 
@@ -242,7 +242,7 @@ export interface ValidationOptions<T> {
242
242
  errorsSignal: Signal<Record<string, string>>
243
243
  }
244
244
 
245
- export const withValidation = <T, Args extends any[], R>(
245
+ export const withValidationSync = <T, Args extends any[], R>(
246
246
  targetAction: (...args: Args) => R,
247
247
  options: ValidationOptions<T>
248
248
  ) => {
@@ -269,7 +269,7 @@ export const withValidation = <T, Args extends any[], R>(
269
269
  }
270
270
  }
271
271
 
272
- export const withResourceValidation = <S, T>(
272
+ export const withValidationAsync = <S, T>(
273
273
  fetcher: (source: S, signal: AbortSignal) => Promise<T>,
274
274
  options: ValidationOptions<S>
275
275
  ) => {
@@ -299,7 +299,7 @@ export const withResourceValidation = <S, T>(
299
299
  2. Domain & Validation Service (`FormWizardLogic.ts`)
300
300
  ```tsx
301
301
  import { AbstractService } from '@pravosleva/reactive-engine'
302
- import { withValidation, withResourceValidation, ValidationSchema } from './withValidation'
302
+ import { withValidationSync, withValidationAsync, ValidationSchema } from './withValidation'
303
303
 
304
304
  export interface WizardState {
305
305
  step: number
@@ -345,15 +345,15 @@ export class FormWizardLogic extends AbstractService {
345
345
  private profileSource = this.engine.computed(() => this.formData.profile)
346
346
 
347
347
  public nextToProfileStep = () => {
348
- const action = withValidation(() => {
348
+ const action = withValidationSync(() => {
349
349
  this.currentStep.value = 2
350
350
  }, { schema: this.accountSchema, errorsSignal: this.errors })
351
-
351
+
352
352
  action(this.formData.account)
353
353
  }
354
354
 
355
355
  public submitWizardForm = this.engine.resource(
356
- withResourceValidation(
356
+ withValidationAsync(
357
357
  async (profileData, abortSignal) => {
358
358
  return this.api.submitWizard(profileData)
359
359
  },
@@ -26,6 +26,7 @@ export declare class ReactiveEngineCore {
26
26
  private cycleDetectionStack;
27
27
  batchedSignals: Set<any>;
28
28
  activeOwner: any;
29
+ activeCleanupNode: any;
29
30
  pendingCleanups: Set<() => void>;
30
31
  queueCleanup(cleanup: () => void): void;
31
32
  constructor(options?: {
@@ -40,7 +41,111 @@ export declare class ReactiveEngineCore {
40
41
  batch<T>(fn: () => T): T;
41
42
  flushEffects(): void;
42
43
  log(params: any): void;
44
+ /**
45
+ * Создает новый реактивный сигнал с заданным начальным значением и опциями.
46
+ *
47
+ * @template T Тип значения сигнала.
48
+ * @param initialValue Начальное значение сигнала.
49
+ * @param optionsOrName Конфигурационные параметры сигнала или его имя.
50
+ * @param optionsOrName.name Уникальное текстовое имя сигнала для отладки и вывода в транзакционный логгер.
51
+ * @param optionsOrName.validate Пользовательская функция валидации значения, возвращающая true/false или строку ошибки.
52
+ *
53
+ * @method signal
54
+ * @memberof ReactiveEngine
55
+ *
56
+ * @example
57
+ * // Пример 1: Чистый TypeScript (Базовый)
58
+ * const engine = new ReactiveEngineCore();
59
+ * const counter = engine.signal(0, { name: 'counter' });
60
+ * console.log(counter.value); // 0
61
+ * counter.value = 1;
62
+ * console.log(counter.value); // 1
63
+ *
64
+ * @example
65
+ * // Пример 2: Чистый TypeScript (Продвинутый с валидацией)
66
+ * interface User { id: number; name: string; }
67
+ * const engine = new ReactiveEngineCore();
68
+ * const userSignal = engine.signal<User>({ id: 1, name: 'John Doe' }, {
69
+ * name: 'user',
70
+ * validate: (user) => user.id > 0 && typeof user.name === 'string'
71
+ * });
72
+ * userSignal.value = { id: -1, name: 'Jane Doe' }; // Ошибка валидации
73
+ *
74
+ * @example
75
+ * // Пример 3: Интеграция с React (через DI контейнер)
76
+ * interface User { id: number; name: string; }
77
+ * class UserService {
78
+ * constructor(engine: ReactiveEngineCore) {
79
+ * this.mySignal = engine.signal<User>({ id: 1, name: 'John Doe' }, { name: 'userSignal' });
80
+ * }
81
+ *
82
+ * mySignal: Signal<User>;
83
+ * }
84
+ *
85
+ * const engine = new ReactiveEngineCore();
86
+ * engine.provide(UserService, UserService);
87
+ * const logic = engine.inject(UserService);
88
+ *
89
+ * function MyComponent() {
90
+ * const user = useReactiveValue(logic.mySignal);
91
+ * return <div>{user.name}</div>;
92
+ * }
93
+ */
43
94
  signal<T>(initialValue: T, optionsOrName?: string | SignalOptions<T>): Signal<T>;
95
+ /**
96
+ * Создает новое вычисляемое свойство (Computed) на основе чистой функции.
97
+ *
98
+ * @template T Тип значения, возвращаемого вычисляемым свойством.
99
+ * @param fn Чистая функция-вычислитель, которая определяет логику вычисления значения.
100
+ * @param signalName Опциональное имя сигнала для отладки и вывода в транзакционный логгер.
101
+ *
102
+ * @method computed
103
+ * @memberof ReactiveEngine
104
+ *
105
+ * @example
106
+ * // Пример 1: Чистый TypeScript (Базовый)
107
+ * const engine = new ReactiveEngineCore();
108
+ * const counter = engine.signal(0, { name: 'counter' });
109
+ * const doubleCounter = engine.computed(() => counter.value * 2);
110
+ * console.log(doubleCounter.value); // 0
111
+ * counter.value = 1;
112
+ * console.log(doubleCounter.value); // 2
113
+ *
114
+ * @example
115
+ * // Пример 2: Чистый TypeScript (Продвинутый с цепочкой зависимостей)
116
+ * interface User { id: number; name: string; }
117
+ * const engine = new ReactiveEngineCore();
118
+ * const userSignal = engine.signal<User>({ id: 1, name: 'John Doe' }, { name: 'user' });
119
+ * const userNameLength = engine.computed(() => userSignal.value.name.length);
120
+ * const hasLongName = engine.computed(() => userNameLength.value > 5);
121
+ *
122
+ * console.log(hasLongName.value); // false
123
+ * userSignal.value = { id: 1, name: 'Johnathan' };
124
+ * console.log(userNameLength.value); // 9
125
+ * console.log(hasLongName.value); // true
126
+ *
127
+ * @example
128
+ * // Пример 3: Интеграция с React (через DI контейнер)
129
+ * interface User { id: number; name: string; }
130
+ * class UserService {
131
+ * constructor(engine: ReactiveEngineCore) {
132
+ * this.userSignal = engine.signal<User>({ id: 1, name: 'John Doe' }, { name: 'userSignal' });
133
+ * this.userNameLength = engine.computed(() => this.userSignal.value.name.length);
134
+ * }
135
+ *
136
+ * userSignal: Signal<User>;
137
+ * userNameLength: Computed<number>;
138
+ * }
139
+ *
140
+ * const engine = new ReactiveEngineCore();
141
+ * engine.provide(UserService, UserService);
142
+ * const logic = engine.inject(UserService);
143
+ *
144
+ * function MyComponent() {
145
+ * const hasLongName = engine.use(logic.userNameLength);
146
+ * return <div>{hasLongName ? 'Long name' : 'Short name'}</div>;
147
+ * }
148
+ */
44
149
  computed<T>(fn: () => T, signalName?: string): Computed<T>;
45
150
  effect(fn: () => void | CleanupFn, effectName?: string): () => void;
46
151
  untrack<T>(fn: () => T): T;
@@ -51,6 +156,62 @@ export declare class ReactiveEngineCore {
51
156
  /**
52
157
  * Создает умную реактивную декларативную обертку над асинхронными операциями
53
158
  * с автоматическим подавлением Race Conditions и встроенным методом .destroy().
159
+ *
160
+ * @template T Тип данных, возвращаемых фетчером после успешного выполнения.
161
+ * @template S Тип реактивной зависимости (source).
162
+ * @param fetcher Асинхронная функция, выполняющая запрос и возвращающая данные типа T.
163
+ * @param source Реактивный сигнал или примитив, предоставляющий источник данных для фетчера.
164
+ * @param optionsOrName Конфигурационные опции ресурса или его имя.
165
+ * @param optionsOrName.name Имя ресурса.
166
+ * @param optionsOrName.resetDataOnSourceChange Флаг, указывающий, следует ли сбрасывать данные при изменении источника.
167
+ * @param optionsOrName.validateBeforeFetch Функция валидации источника перед выполнением фетча.
168
+ * @param optionsOrName.responseValidate Функция валидации ответа после выполнения фетча.
169
+ * @param optionsOrName.timeout Максимальное время ожидания запроса в миллисекундах.
170
+ * @param optionsOrName.retryCount Количество попыток повторного выполнения запроса в случае ошибки.
171
+ *
172
+ * @example
173
+ * // Пример 1: Чистый TypeScript (Базовый)
174
+ * interface User { id: number; name: string; }
175
+ * interface ApiResponse<T> { ok: boolean; message?: string; data: T; }
176
+ * const engine = new ReactiveEngineCore();
177
+ * const userSignal = engine.signal<User>({ id: 1, name: 'John Doe' });
178
+ * const fetchUser = async (source: User, signal: AbortSignal): Promise<ApiResponse<User>> => {
179
+ * // Реализация фетча пользователя
180
+ * };
181
+ * const userResource = engine.resource(fetchUser, { value: userSignal.value }, { name: 'userResource' });
182
+ *
183
+ * @example
184
+ * // Пример 2: Чистый TypeScript (Продвинутый)
185
+ * interface User { id: number; name: string; }
186
+ * interface ApiResponse<T> { ok: boolean; message?: string; data: T; }
187
+ * const engine = new ReactiveEngineCore();
188
+ * const userSignal = engine.signal<User>({ id: 1, name: 'John Doe' });
189
+ * const fetchUser = async (source: User, signal: AbortSignal): Promise<ApiResponse<User>> => {
190
+ * // Реализация фетча пользователя с использованием AbortSignal и timeout
191
+ * };
192
+ * const userResource = engine.resource(fetchUser, { value: userSignal.value }, {
193
+ * name: 'userResource',
194
+ * timeout: 5000,
195
+ * retryCount: 3,
196
+ * });
197
+ *
198
+ * @example
199
+ * // Пример 3: Интеграция с React (через DI контейнер)
200
+ * interface User { id: number; name: string; }
201
+ * interface ApiResponse<T> { ok: boolean; message?: string; data: T; }
202
+ * class UserService {
203
+ * constructor(engine: ReactiveEngineCore) {
204
+ * const userSignal = engine.signal<User>({ id: 1, name: 'John Doe' });
205
+ * this.myResource = engine.resource(fetchUser, { value: userSignal.value }, { name: 'userResource' });
206
+ * }
207
+ *
208
+ * myResource: Resource<ApiResponse<User>>;
209
+ * }
210
+ *
211
+ * const engine = new ReactiveEngineCore();
212
+ * engine.provide(UserService, UserService);
213
+ * const logic = engine.inject(UserService);
214
+ * const state = useReactiveValue(logic.myResource);
54
215
  */
55
216
  resource<T, S = void>(fetcher: (source: S, signal: AbortSignal) => Promise<T>, source?: {
56
217
  value: S;
@@ -1 +1 @@
1
- {"version":3,"file":"core.d.ts","sourceRoot":"","sources":["../../src/core/core.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"core.d.ts","sourceRoot":"","sources":["../../src/core/core.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=core.effect.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"core.effect.test.d.ts","sourceRoot":"","sources":["../../src/core/core.effect.test.ts"],"names":[],"mappings":""}
@@ -1 +1 @@
1
- {"version":3,"file":"core.method.computed.d.ts","sourceRoot":"","sources":["../../src/core/core.method.computed.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAa,MAAM,SAAS,CAAA;AAE7C,wBAAgB,cAAc,CAAC,CAAC,EAC9B,MAAM,EAAE,GAAG,EACX,EAAE,EAAE,MAAM,CAAC,EACX,UAAU,CAAC,EAAE,MAAM,GAClB,QAAQ,CAAC,CAAC,CAAC,CAiVb"}
1
+ {"version":3,"file":"core.method.computed.d.ts","sourceRoot":"","sources":["../../src/core/core.method.computed.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAa,MAAM,SAAS,CAAA;AAE7C,wBAAgB,cAAc,CAAC,CAAC,EAC9B,MAAM,EAAE,GAAG,EACX,EAAE,EAAE,MAAM,CAAC,EACX,UAAU,CAAC,EAAE,MAAM,GAClB,QAAQ,CAAC,CAAC,CAAC,CA8Tb"}
@@ -1 +1 @@
1
- {"version":3,"file":"core.method.effect.d.ts","sourceRoot":"","sources":["../../src/core/core.method.effect.ts"],"names":[],"mappings":"AAAA,OAAO,EAAW,QAAQ,EAAa,MAAM,SAAS,CAAA;AAatD,wBAAgB,YAAY,CAAC,MAAM,EAAE,GAAG,EAAE,EAAE,EAAE,QAAQ,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,MAAM,IAAI,CAuJvF"}
1
+ {"version":3,"file":"core.method.effect.d.ts","sourceRoot":"","sources":["../../src/core/core.method.effect.ts"],"names":[],"mappings":"AAAA,OAAO,EAAW,QAAQ,EAAa,MAAM,SAAS,CAAA;AActD,wBAAgB,YAAY,CAAC,MAAM,EAAE,GAAG,EAAE,EAAE,EAAE,QAAQ,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,MAAM,IAAI,CA2LvF"}
@@ -1 +1 @@
1
- {"version":3,"file":"core.method.signal.d.ts","sourceRoot":"","sources":["../../src/core/core.method.signal.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,SAAS,CAAA;AAE/C,wBAAgB,YAAY,CAAC,CAAC,EAC5B,MAAM,EAAE,GAAG,EACX,YAAY,EAAE,CAAC,EACf,aAAa,CAAC,EAAE,aAAa,CAAC,CAAC,CAAC,GAAG,MAAM,GACxC,MAAM,CAAC,CAAC,CAAC,CAyJX"}
1
+ {"version":3,"file":"core.method.signal.d.ts","sourceRoot":"","sources":["../../src/core/core.method.signal.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,SAAS,CAAA;AAE/C,wBAAgB,YAAY,CAAC,CAAC,EAC5B,MAAM,EAAE,GAAG,EACX,YAAY,EAAE,CAAC,EACf,aAAa,CAAC,EAAE,aAAa,CAAC,CAAC,CAAC,GAAG,MAAM,GACxC,MAAM,CAAC,CAAC,CAAC,CAuKX"}
@@ -14,6 +14,7 @@ function e(e, t, n) {
14
14
  }
15
15
  }, h = (t) => {
16
16
  if (!s || l === 2) return t.run();
17
+ if (p && p.size > 0 && t.verifiedInEpoch === e.epoch && e.batchDepth === 0 && l === 0) return !1;
17
18
  let n = !1;
18
19
  if (u && u.size > 0) for (let t of u) {
19
20
  let r = t._node || t;
@@ -22,7 +23,7 @@ function e(e, t, n) {
22
23
  break;
23
24
  }
24
25
  }
25
- return n ? (c = -1, t.verifiedInEpoch = -1, t.run()) : p && p.size > 0 && t.verifiedInEpoch === e.epoch && e.batchDepth === 0 && l === 0 ? !1 : a ? t.run() : (t.verifiedInEpoch !== -1 && t.verifiedInEpoch < e.epoch && (!p || p.size === 0) ? t.verifiedInEpoch = -1 : t.verifiedInEpoch = e.epoch, l = 0, !1);
26
+ return t.verifiedInEpoch = e.epoch, n || a ? t.run() : (l = 0, !1);
26
27
  }, g = 0, _ = {
27
28
  id: e.subscriberId++,
28
29
  dependencies: u,
@@ -110,7 +111,7 @@ function e(e, t, n) {
110
111
  let e = _.depth || 1, n = t._node || t;
111
112
  n.depth !== void 0 && e >= n.depth && (n.depth = e + 1), t.activeRunId !== void 0 && (_._lastSeenInRunId = t.activeRunId);
112
113
  }
113
- return (l === 2 || _.verifiedInEpoch !== -1 && _.verifiedInEpoch < e.epoch) && (_.verifiedInEpoch = -1, c = -1), h(_), t && t.depVersions && t.depVersions.set(v, o), i;
114
+ return h(_), t && t.depVersions && t.depVersions.set(v, o), i;
114
115
  },
115
116
  get valueWithoutTracking() {
116
117
  return i;
@@ -1 +1 @@
1
- {"version":3,"file":"core.method.computed.mjs","names":[],"sources":["../src/core/core.method.computed.ts"],"sourcesContent":["import { Computed, CleanupFn } from './types'\n\nexport function createComputed<T>(\n engine: any,\n fn: () => T,\n signalName?: string\n): Computed<T> {\n // 1. Ультимативный канонический WeakMap путь (строго по ссылке на объект-функцию)\n // Работает со скоростью нативной ссылки в V8, полностью исключая утечки памяти\n const existing = engine.computedCache.get(fn)\n if (existing) return existing as Computed<T>\n\n let value: T\n let isDirty = true\n let version = 0\n let isInitialized = false\n let evaluatedInEpoch = -1\n let state = 2 // 2 = DIRTY, 1 = CHECK, 0 = STABLE\n\n const dependencies = new Set<any>()\n const depVersions = new Map<any, number>()\n const ownedEffects = new Set<any>()\n const subscribers = new Set<any>()\n\n const releaseNode = (node: any): void => {\n if (!node) return\n const actNode = node._node || node\n\n if (actNode.dependencies && actNode.dependencies.size > 0) {\n for (const unknownDep of actNode.dependencies) {\n const dep = unknownDep as any\n const rawDepNode = dep._node || dep\n\n if (rawDepNode.subscribers) {\n rawDepNode.subscribers.delete(actNode)\n rawDepNode.subscribers.delete(node)\n rawDepNode.subscribers.delete(computedNode)\n\n if (rawDepNode.type === 'computed' && rawDepNode.subscribers.size === 0) {\n releaseNode(rawDepNode)\n }\n }\n }\n actNode.dependencies.clear()\n if (actNode.depVersions) actNode.depVersions.clear()\n }\n }\n\n const updateIfNecessary = (node: any): boolean => {\n if (!isInitialized || state === 2) {\n return node.run()\n }\n\n // 1. Сначала честно сканируем родителей по физическим версиям мутаций в V8.\n // Это единственный способ отловить inner write на фазе ленивого pull-запроса,\n // так как вложенный сеттер мог сдвинуть версии сигналов в обход markDirty.\n let hasChangedParent = false\n\n if (dependencies && dependencies.size > 0) {\n for (const dep of dependencies) {\n const rawDep = dep._node || dep\n\n if (rawDep.type === 'computed' && rawDep.state > 0) {\n if (rawDep.update && rawDep.verifiedInEpoch !== engine.epoch) {\n rawDep.update()\n }\n }\n\n if (dep.hasBatchValue || depVersions.get(dep) !== rawDep.version) {\n hasChangedParent = true\n break\n }\n }\n }\n\n // ⚛️ УЛЬТИМАТИВНЫЙ ФИКС ТЕСТOВ #180 и #186:\n // Если обход родителей подтвердил изменение версий из побочного канала (hasChangedParent === true),\n // мы ОБЯЗАНЫ сбросить кэши эпох текущей ноды и пустить её на честный пересчет.\n // При этом мы НЕ выставляем принудительно state = 2, благодаря чему метод run()\n // сможет сравнить результаты через Object.is и легитимно остановить волну (Value-Equality Cut)!\n if (hasChangedParent) {\n evaluatedInEpoch = -1\n node.verifiedInEpoch = -1\n return node.run()\n }\n\n // 2. И только если родители НЕ менялись, мы можем применить быстрый O(1) возврат по эпохам\n if (subscribers && subscribers.size > 0) {\n if (node.verifiedInEpoch === engine.epoch && engine.batchDepth === 0 && state === 0) {\n return false\n }\n }\n\n if (isDirty) {\n return node.run()\n }\n\n // Канонический сброс для unobserved pull-цепочек из тестов матрицы сайта\n if (node.verifiedInEpoch !== -1 && node.verifiedInEpoch < engine.epoch && (!subscribers || subscribers.size === 0)) {\n node.verifiedInEpoch = -1\n } else {\n node.verifiedInEpoch = engine.epoch\n }\n\n state = 0\n return false\n }\n\n let currentRunId = 0\n\n const computedNode: any = {\n id: engine.subscriberId++,\n dependencies,\n subscribers,\n ownedEffects,\n depth: 1,\n type: 'computed',\n fn,\n get version() { return version },\n get state() { return state },\n set state(val: number) { state = val },\n get depVersions() { return depVersions },\n verifiedInEpoch: -1, // Перенесено напрямую на объект ноды для ультимативного O(1)\n update: () => updateIfNecessary(computedNode),\n run: () => {\n // ⚛️ КАНOНИЧЕСКИЙ БЫСТРЫЙ ВЫХOД:\n // Срабатывает только если эпоха стабильна, узел не сброшен в updateIfNecessary\n // и в текущем кадре не происходило inner write мутаций у родителей\n if (evaluatedInEpoch === engine.epoch && isInitialized && state === 0 && engine.batchDepth === 0) {\n return false\n }\n\n // Запоминаем стартовую эпоху до вызова функции пользователя\n const startEpoch = engine.epoch\n evaluatedInEpoch = startEpoch\n computedNode.verifiedInEpoch = startEpoch\n\n if (engine.cycleDetectionStack.has(computedNode)) {\n throw new Error('[Graph Error] Cyclic dependency detected')\n }\n engine.cycleDetectionStack.add(computedNode)\n\n const prevConsumer = engine.activeConsumer\n const prevOwner = engine.activeOwner\n\n engine.activeConsumer = computedNode\n engine.activeOwner = computedNode\n\n currentRunId++\n computedNode.activeRunId = currentRunId\n\n const oldDeps = dependencies.size > 0 ? Array.from(dependencies) : null\n dependencies.clear()\n\n try {\n if (ownedEffects.size > 0) {\n for (const child of ownedEffects) {\n if (child && typeof child.dispose === 'function') {\n child.dispose()\n }\n }\n ownedEffects.clear()\n }\n\n // Выполняем пользовательскую функцию (здесь могут произойти inner writes из тестов #179, #180, #186)\n const newValue = fn()\n\n if (oldDeps !== null) {\n const isSizeIdentical = oldDeps.length === dependencies.size\n for (const unknownDep of oldDeps) {\n const dep = unknownDep as any\n if (!isSizeIdentical || !dependencies.has(dep)) {\n const rawDepNode = dep._node || dep\n if (rawDepNode.subscribers) rawDepNode.subscribers.delete(computedNode)\n depVersions.delete(dep)\n }\n }\n }\n\n const changed = isDirty || !Object.is(value, newValue)\n\n if (changed) {\n const previousValueSnapshot = isDirty ? undefined : (typeof value === 'object' && value !== null ? JSON.parse(JSON.stringify(value)) : value)\n value = newValue\n version++\n\n if (engine.log && signalName) {\n engine.log({\n type: 'computed',\n label: signalName,\n details: { from: previousValueSnapshot, to: newValue }\n })\n }\n }\n\n isDirty = false\n state = 0\n isInitialized = true\n\n let maxDepDepth = 0\n for (const unknownDep of dependencies) {\n const dep = unknownDep as any\n const rawNode = dep._node || dep\n depVersions.set(dep, rawNode.version)\n if (rawNode.subscribers) rawNode.subscribers.add(computedNode)\n if (rawNode.depth !== undefined && rawNode.depth > maxDepDepth) {\n maxDepDepth = rawNode.depth\n }\n }\n\n computedNode.depth = maxDepDepth + 1\n\n // ⚡ ФИКС ДЛЯ INNER WRITES (#179, #180, #186):\n // Если во время исполнения fn() эпоха ядра сдвинулась (был вложенный сеттер),\n // мы обязаны сбросить кэш верификации этой эпохи, чтобы последующие цепочки\n // зависимостей внутри этого же тика пересчитали свои значения нативно.\n if (engine.epoch !== startEpoch) {\n evaluatedInEpoch = -1\n computedNode.verifiedInEpoch = -1\n state = 2 // Переводим в DIRTY для немедленной инвалидации\n }\n\n return changed\n } finally {\n engine.activeConsumer = prevConsumer\n engine.activeOwner = prevOwner\n engine.cycleDetectionStack.delete(computedNode)\n }\n },\n markDirty: (parentState: number) => {\n if (state >= parentState) return\n state = parentState\n\n for (const sub of subscribers) {\n const rawSub = sub._node || sub\n if (rawSub.type === 'effect') {\n rawSub.isDirty = true\n engine.scheduleEffect(sub)\n } else if (rawSub.markDirty) {\n rawSub.markDirty(1)\n }\n }\n }\n }\n\n const computedInstance: Computed<T> = {\n get value() {\n const consumer = engine.activeConsumer\n if (consumer && consumer !== computedNode) {\n if (typeof consumer.dependencies?.add === 'function') {\n subscribers.add(consumer)\n consumer.dependencies.add(computedNode)\n\n const currentDepth = computedNode.depth || 1\n const consumerRaw = consumer._node || consumer\n if (consumerRaw.depth !== undefined && currentDepth >= consumerRaw.depth) {\n consumerRaw.depth = currentDepth + 1\n }\n\n if (consumer.activeRunId !== undefined) {\n computedNode._lastSeenInRunId = consumer.activeRunId\n }\n }\n }\n\n // ⚛️ ВЕЛИКИЙ ПРЕДOХРАНИТЕЛЬ ДЛЯ INNER WRITES (#180 и #186):\n // Если у ноды есть сохраненный маркер эпохи, но состояние у узла DIRTY (state === 2)\n // из-за вложенного вызова markDirty(2) во время flush-цикла, либо если глобальная эпоха\n // ядра ушла вперед — мы ОБЯЗАНЫ обнулить verifiedInEpoch, чтобы пропустить пулл-запрос к родителям!\n if (state === 2 || (computedNode.verifiedInEpoch !== -1 && computedNode.verifiedInEpoch < engine.epoch)) {\n computedNode.verifiedInEpoch = -1\n evaluatedInEpoch = -1\n }\n\n updateIfNecessary(computedNode)\n\n if (consumer && consumer.depVersions) {\n consumer.depVersions.set(computedInstance, version)\n }\n return value\n },\n get valueWithoutTracking() { return value },\n get version() { return version },\n get dependencies() { return dependencies },\n\n subscribe(cb: (val: T) => void): CleanupFn {\n const self = this\n const fakeEffect: any = {\n id: engine.subscriberId++,\n isDirty: true,\n depth: 9999,\n dependencies: new Set(),\n type: 'effect',\n run: () => {\n if (fakeEffect.isDisposed) return\n try { cb(self.value) } catch (err) { console.error(err) }\n }\n }\n subscribers.add(fakeEffect)\n cb(this.value)\n return () => {\n fakeEffect.isDisposed = true\n subscribers.delete(fakeEffect)\n fakeEffect.dependencies.clear()\n }\n },\n subscribeState(cb: () => void): CleanupFn {\n return (computedInstance as any).subscribe(cb)\n },\n destroy: () => {\n releaseNode(computedNode)\n if (subscribers) subscribers.clear()\n engine.computedCache.delete(fn)\n\n dependencies.clear()\n depVersions.clear()\n ownedEffects.clear()\n\n isDirty = true\n state = 2\n isInitialized = false\n },\n __subscribe(cb: () => void): CleanupFn {\n const hookEffect: any = {\n id: engine.subscriberId++,\n type: 'effect',\n run: cb,\n isDirty: false\n }\n subscribers.add(hookEffect)\n return () => {\n subscribers.delete(hookEffect)\n }\n }\n } as any\n\n computedInstance.run = () => computedNode.run()\n engine.computedCache.set(fn, computedInstance)\n\n ;(computedInstance as any)._node = computedNode\n ;(computedInstance as any).subscribers = subscribers\n\n return computedInstance\n}\n"],"mappings":";AAEA,SAAgB,EACd,GACA,GACA,GACa;CAGb,IAAM,IAAW,EAAO,cAAc,IAAI,CAAE;CAC5C,IAAI,GAAU,OAAO;CAErB,IAAI,GACA,IAAU,IACV,IAAU,GACV,IAAgB,IAChB,IAAmB,IACnB,IAAQ,GAEN,oBAAe,IAAI,IAAS,GAC5B,oBAAc,IAAI,IAAiB,GACnC,oBAAe,IAAI,IAAS,GAC5B,oBAAc,IAAI,IAAS,GAE3B,KAAe,MAAoB;EACvC,IAAI,CAAC,GAAM;EACX,IAAM,IAAU,EAAK,SAAS;EAE9B,IAAI,EAAQ,gBAAgB,EAAQ,aAAa,OAAO,GAAG;GACzD,KAAK,IAAM,KAAc,EAAQ,cAAc;IAC7C,IAAM,IAAM,GACN,IAAa,EAAI,SAAS;IAEhC,AAAI,EAAW,gBACb,EAAW,YAAY,OAAO,CAAO,GACrC,EAAW,YAAY,OAAO,CAAI,GAClC,EAAW,YAAY,OAAO,CAAY,GAEtC,EAAW,SAAS,cAAc,EAAW,YAAY,SAAS,KACpE,EAAY,CAAU;GAG5B;GAEA,AADA,EAAQ,aAAa,MAAM,GACvB,EAAQ,eAAa,EAAQ,YAAY,MAAM;EACrD;CACF,GAEM,KAAqB,MAAuB;EAChD,IAAI,CAAC,KAAiB,MAAU,GAC9B,OAAO,EAAK,IAAI;EAMlB,IAAI,IAAmB;EAEvB,IAAI,KAAgB,EAAa,OAAO,GACtC,KAAK,IAAM,KAAO,GAAc;GAC9B,IAAM,IAAS,EAAI,SAAS;GAQ5B,IANI,EAAO,SAAS,cAAc,EAAO,QAAQ,KAC3C,EAAO,UAAU,EAAO,oBAAoB,EAAO,SACrD,EAAO,OAAO,GAId,EAAI,iBAAiB,EAAY,IAAI,CAAG,MAAM,EAAO,SAAS;IAChE,IAAmB;IACnB;GACF;EACF;EAiCF,OAzBI,KACF,IAAmB,IACnB,EAAK,kBAAkB,IAChB,EAAK,IAAI,KAId,KAAe,EAAY,OAAO,KAChC,EAAK,oBAAoB,EAAO,SAAS,EAAO,eAAe,KAAK,MAAU,IACzE,KAIP,IACK,EAAK,IAAI,KAId,EAAK,oBAAoB,MAAM,EAAK,kBAAkB,EAAO,UAAU,CAAC,KAAe,EAAY,SAAS,KAC9G,EAAK,kBAAkB,KAEvB,EAAK,kBAAkB,EAAO,OAGhC,IAAQ,GACD;CACT,GAEI,IAAe,GAEb,IAAoB;EACxB,IAAI,EAAO;EACX;EACA;EACA;EACA,OAAO;EACP,MAAM;EACN;EACA,IAAI,UAAU;GAAE,OAAO;EAAQ;EAC/B,IAAI,QAAQ;GAAE,OAAO;EAAM;EAC3B,IAAI,MAAM,GAAa;GAAE,IAAQ;EAAI;EACrC,IAAI,cAAc;GAAE,OAAO;EAAY;EACvC,iBAAiB;EACjB,cAAc,EAAkB,CAAY;EAC5C,WAAW;GAIT,IAAI,MAAqB,EAAO,SAAS,KAAiB,MAAU,KAAK,EAAO,eAAe,GAC7F,OAAO;GAIT,IAAM,IAAa,EAAO;GAI1B,IAHA,IAAmB,GACnB,EAAa,kBAAkB,GAE3B,EAAO,oBAAoB,IAAI,CAAY,GAC7C,MAAU,MAAM,0CAA0C;GAE5D,EAAO,oBAAoB,IAAI,CAAY;GAE3C,IAAM,IAAe,EAAO,gBACtB,IAAY,EAAO;GAMzB,AAJA,EAAO,iBAAiB,GACxB,EAAO,cAAc,GAErB,KACA,EAAa,cAAc;GAE3B,IAAM,IAAU,EAAa,OAAO,IAAI,MAAM,KAAK,CAAY,IAAI;GACnE,EAAa,MAAM;GAEnB,IAAI;IACF,IAAI,EAAa,OAAO,GAAG;KACzB,KAAK,IAAM,KAAS,GAClB,AAAI,KAAS,OAAO,EAAM,WAAY,cACpC,EAAM,QAAQ;KAGlB,EAAa,MAAM;IACrB;IAGA,IAAM,IAAW,EAAG;IAEpB,IAAI,MAAY,MAAM;KACpB,IAAM,IAAkB,EAAQ,WAAW,EAAa;KACxD,KAAK,IAAM,KAAc,GAAS;MAChC,IAAM,IAAM;MACZ,IAAI,CAAC,KAAmB,CAAC,EAAa,IAAI,CAAG,GAAG;OAC9C,IAAM,IAAa,EAAI,SAAS;OAEhC,AADI,EAAW,eAAa,EAAW,YAAY,OAAO,CAAY,GACtE,EAAY,OAAO,CAAG;MACxB;KACF;IACF;IAEA,IAAM,IAAU,KAAW,CAAC,OAAO,GAAG,GAAO,CAAQ;IAErD,IAAI,GAAS;KACX,IAAM,IAAwB,IAAU,KAAA,IAAa,OAAO,KAAU,YAAY,IAAiB,KAAK,MAAM,KAAK,UAAU,CAAK,CAAC,IAAI;KAIvI,AAHA,IAAQ,GACR,KAEI,EAAO,OAAO,KAChB,EAAO,IAAI;MACT,MAAM;MACN,OAAO;MACP,SAAS;OAAE,MAAM;OAAuB,IAAI;MAAS;KACvD,CAAC;IAEL;IAIA,AAFA,IAAU,IACV,IAAQ,GACR,IAAgB;IAEhB,IAAI,IAAc;IAClB,KAAK,IAAM,KAAc,GAAc;KACrC,IAAM,IAAM,GACN,IAAU,EAAI,SAAS;KAG7B,AAFA,EAAY,IAAI,GAAK,EAAQ,OAAO,GAChC,EAAQ,eAAa,EAAQ,YAAY,IAAI,CAAY,GACzD,EAAQ,UAAU,KAAA,KAAa,EAAQ,QAAQ,MACjD,IAAc,EAAQ;IAE1B;IAcA,OAZA,EAAa,QAAQ,IAAc,GAM/B,EAAO,UAAU,MACnB,IAAmB,IACnB,EAAa,kBAAkB,IAC/B,IAAQ,IAGH;GACT,UAAU;IAGR,AAFA,EAAO,iBAAiB,GACxB,EAAO,cAAc,GACrB,EAAO,oBAAoB,OAAO,CAAY;GAChD;EACF;EACA,YAAY,MAAwB;GAC9B,WAAS,IACb;QAAQ;IAER,KAAK,IAAM,KAAO,GAAa;KAC7B,IAAM,IAAS,EAAI,SAAS;KAC5B,AAAI,EAAO,SAAS,YAClB,EAAO,UAAU,IACjB,EAAO,eAAe,CAAG,KAChB,EAAO,aAChB,EAAO,UAAU,CAAC;IAEtB;GAVQ;EAWV;CACF,GAEM,IAAgC;EACpC,IAAI,QAAQ;GACV,IAAM,IAAW,EAAO;GACxB,IAAI,KAAY,MAAa,KACvB,OAAO,EAAS,cAAc,OAAQ,YAAY;IAEpD,AADA,EAAY,IAAI,CAAQ,GACxB,EAAS,aAAa,IAAI,CAAY;IAEtC,IAAM,IAAe,EAAa,SAAS,GACrC,IAAc,EAAS,SAAS;IAKtC,AAJI,EAAY,UAAU,KAAA,KAAa,KAAgB,EAAY,UACjE,EAAY,QAAQ,IAAe,IAGjC,EAAS,gBAAgB,KAAA,MAC3B,EAAa,mBAAmB,EAAS;GAE7C;GAiBF,QAVI,MAAU,KAAM,EAAa,oBAAoB,MAAM,EAAa,kBAAkB,EAAO,WAC/F,EAAa,kBAAkB,IAC/B,IAAmB,KAGrB,EAAkB,CAAY,GAE1B,KAAY,EAAS,eACvB,EAAS,YAAY,IAAI,GAAkB,CAAO,GAE7C;EACT;EACA,IAAI,uBAAuB;GAAE,OAAO;EAAM;EAC1C,IAAI,UAAU;GAAE,OAAO;EAAQ;EAC/B,IAAI,eAAe;GAAE,OAAO;EAAa;EAEzC,UAAU,GAAiC;GACzC,IAAM,IAAO,MACP,IAAkB;IACtB,IAAI,EAAO;IACX,SAAS;IACT,OAAO;IACP,8BAAc,IAAI,IAAI;IACtB,MAAM;IACN,WAAW;KACL,OAAW,YACf,IAAI;MAAE,EAAG,EAAK,KAAK;KAAE,SAAS,GAAK;MAAE,QAAQ,MAAM,CAAG;KAAE;IAC1D;GACF;GAGA,OAFA,EAAY,IAAI,CAAU,GAC1B,EAAG,KAAK,KAAK,SACA;IAGX,AAFA,EAAW,aAAa,IACxB,EAAY,OAAO,CAAU,GAC7B,EAAW,aAAa,MAAM;GAChC;EACF;EACA,eAAe,GAA2B;GACxC,OAAQ,EAAyB,UAAU,CAAE;EAC/C;EACA,eAAe;GAWb,AAVA,EAAY,CAAY,GACpB,KAAa,EAAY,MAAM,GACnC,EAAO,cAAc,OAAO,CAAE,GAE9B,EAAa,MAAM,GACnB,EAAY,MAAM,GAClB,EAAa,MAAM,GAEnB,IAAU,IACV,IAAQ,GACR,IAAgB;EAClB;EACA,YAAY,GAA2B;GACrC,IAAM,IAAkB;IACtB,IAAI,EAAO;IACX,MAAM;IACN,KAAK;IACL,SAAS;GACX;GAEA,OADA,EAAY,IAAI,CAAU,SACb;IACX,EAAY,OAAO,CAAU;GAC/B;EACF;CACF;CAQA,OANA,EAAiB,YAAY,EAAa,IAAI,GAC9C,EAAO,cAAc,IAAI,GAAI,CAAgB,GAE5C,EAA0B,QAAQ,GAClC,EAA0B,cAAc,GAElC;AACT"}
1
+ {"version":3,"file":"core.method.computed.mjs","names":[],"sources":["../src/core/core.method.computed.ts"],"sourcesContent":["import { Computed, CleanupFn } from './types'\n\nexport function createComputed<T>(\n engine: any,\n fn: () => T,\n signalName?: string\n): Computed<T> {\n // 1. Ультимативный канонический WeakMap путь (строго по ссылке на объект-функцию)\n // Работает со скоростью нативной ссылки в V8, полностью исключая утечки памяти\n const existing = engine.computedCache.get(fn)\n if (existing) return existing as Computed<T>\n\n let value: T\n let isDirty = true\n let version = 0\n let isInitialized = false\n let evaluatedInEpoch = -1\n let state = 2 // 2 = DIRTY, 1 = CHECK, 0 = STABLE\n\n const dependencies = new Set<any>()\n const depVersions = new Map<any, number>()\n const ownedEffects = new Set<any>()\n const subscribers = new Set<any>()\n\n const releaseNode = (node: any): void => {\n if (!node) return\n const actNode = node._node || node\n\n if (actNode.dependencies && actNode.dependencies.size > 0) {\n for (const unknownDep of actNode.dependencies) {\n const dep = unknownDep as any\n const rawDepNode = dep._node || dep\n\n if (rawDepNode.subscribers) {\n rawDepNode.subscribers.delete(actNode)\n rawDepNode.subscribers.delete(node)\n rawDepNode.subscribers.delete(computedNode)\n\n if (rawDepNode.type === 'computed' && rawDepNode.subscribers.size === 0) {\n releaseNode(rawDepNode)\n }\n }\n }\n actNode.dependencies.clear()\n if (actNode.depVersions) actNode.depVersions.clear()\n }\n }\n\n const updateIfNecessary = (node: any): boolean => {\n if (!isInitialized || state === 2) {\n return node.run()\n }\n\n // ⚛️ КОРРЕКТНЫЙ МЕМОИЗАЦИОННЫЙ ГВАРД (Pull-совместимый проход):\n // Если у узла есть активные подписчики (observed), мы можем оптимизировать расчет через эпохи.\n // Но если подписчиков НЕТ (unobserved), мы ОБЯЗАНЫ пропустить быстрый выход по эпохам\n // и честно проверить, изменились ли версии родителей ниже.\n if (subscribers && subscribers.size > 0) {\n if (node.verifiedInEpoch === engine.epoch && engine.batchDepth === 0 && state === 0) {\n return false\n }\n }\n\n let hasChangedParent = false\n\n if (dependencies && dependencies.size > 0) {\n for (const dep of dependencies) {\n const rawDep = dep._node || dep\n\n if (rawDep.type === 'computed' && rawDep.state > 0) {\n // ⚛️ ЗАЩИТА ОТ КАСКАДНОГО ОБХОДА:\n // Вызываем update() родителя только если он еще не был верифицирован в текущей эпохе.\n // Это ликвидирует квадратичную рекурсию на динамических структурах графа!\n if (rawDep.update && rawDep.verifiedInEpoch !== engine.epoch) {\n rawDep.update()\n }\n }\n\n // Если родитель имеет отложенное батч-значение (hasBatchValue)\n // или его версия изменилась — кэш невалиден!\n if (dep.hasBatchValue || depVersions.get(dep) !== rawDep.version) {\n hasChangedParent = true\n break\n }\n }\n }\n\n node.verifiedInEpoch = engine.epoch\n\n if (hasChangedParent || isDirty) {\n return node.run()\n }\n\n state = 0\n return false\n }\n\n let currentRunId = 0\n\n const computedNode: any = {\n id: engine.subscriberId++,\n dependencies,\n subscribers,\n ownedEffects,\n depth: 1,\n type: 'computed',\n fn,\n get version() { return version },\n get state() { return state },\n set state(val: number) { state = val },\n get depVersions() { return depVersions },\n verifiedInEpoch: -1, // Перенесено напрямую на объект ноды для ультимативного O(1)\n update: () => updateIfNecessary(computedNode),\n run: () => {\n // Стандартный быстрый выход для стабильных эпох\n if (evaluatedInEpoch === engine.epoch && isInitialized && state === 0 && engine.batchDepth === 0) {\n return false\n }\n\n // Запоминаем стартовую эпоху до вызова функции пользователя\n const startEpoch = engine.epoch\n evaluatedInEpoch = startEpoch\n computedNode.verifiedInEpoch = startEpoch\n\n if (engine.cycleDetectionStack.has(computedNode)) {\n throw new Error('[Graph Error] Cyclic dependency detected')\n }\n engine.cycleDetectionStack.add(computedNode)\n\n const prevConsumer = engine.activeConsumer\n const prevOwner = engine.activeOwner\n\n engine.activeConsumer = computedNode\n engine.activeOwner = computedNode\n\n currentRunId++\n computedNode.activeRunId = currentRunId\n\n const oldDeps = dependencies.size > 0 ? Array.from(dependencies) : null\n dependencies.clear()\n\n try {\n if (ownedEffects.size > 0) {\n for (const child of ownedEffects) {\n if (child && typeof child.dispose === 'function') {\n child.dispose()\n }\n }\n ownedEffects.clear()\n }\n\n // Выполняем пользовательскую функцию (здесь могут произойти inner writes из тестов #179, #180, #186)\n const newValue = fn()\n\n if (oldDeps !== null) {\n const isSizeIdentical = oldDeps.length === dependencies.size\n for (const unknownDep of oldDeps) {\n const dep = unknownDep as any\n if (!isSizeIdentical || !dependencies.has(dep)) {\n const rawDepNode = dep._node || dep\n if (rawDepNode.subscribers) rawDepNode.subscribers.delete(computedNode)\n depVersions.delete(dep)\n }\n }\n }\n\n const changed = isDirty || !Object.is(value, newValue)\n\n if (changed) {\n const previousValueSnapshot = isDirty ? undefined : (typeof value === 'object' && value !== null ? JSON.parse(JSON.stringify(value)) : value)\n value = newValue\n version++\n\n if (engine.log && signalName) {\n engine.log({\n type: 'computed',\n label: signalName,\n details: { from: previousValueSnapshot, to: newValue }\n })\n }\n }\n\n isDirty = false\n state = 0\n isInitialized = true\n\n let maxDepDepth = 0\n for (const unknownDep of dependencies) {\n const dep = unknownDep as any\n const rawNode = dep._node || dep\n depVersions.set(dep, rawNode.version)\n if (rawNode.subscribers) rawNode.subscribers.add(computedNode)\n if (rawNode.depth !== undefined && rawNode.depth > maxDepDepth) {\n maxDepDepth = rawNode.depth\n }\n }\n\n computedNode.depth = maxDepDepth + 1\n\n // ⚡ ФИКС ДЛЯ INNER WRITES (#179, #180, #186):\n // Если во время исполнения fn() эпоха ядра сдвинулась (был вложенный сеттер),\n // мы обязаны сбросить кэш верификации этой эпохи, чтобы последующие цепочки\n // зависимостей внутри этого же тика пересчитали свои значения нативно.\n if (engine.epoch !== startEpoch) {\n evaluatedInEpoch = -1\n computedNode.verifiedInEpoch = -1\n state = 2 // Переводим в DIRTY для немедленной инвалидации\n }\n\n return changed\n } finally {\n engine.activeConsumer = prevConsumer\n engine.activeOwner = prevOwner\n engine.cycleDetectionStack.delete(computedNode)\n }\n },\n markDirty: (parentState: number) => {\n if (state >= parentState) return\n state = parentState\n\n for (const sub of subscribers) {\n const rawSub = sub._node || sub\n if (rawSub.type === 'effect') {\n rawSub.isDirty = true\n engine.scheduleEffect(sub)\n } else if (rawSub.markDirty) {\n rawSub.markDirty(1)\n }\n }\n }\n }\n\n const computedInstance: Computed<T> = {\n get value() {\n // 🛡️ АТОМАРНАЯ ЗАЩИТА: Фиксируем ссылку локально и работаем строго с ней.\n // Это полностью предотвращает TypeError: ... reading 'add' на проде Next.js.\n const consumer = engine.activeConsumer\n if (consumer && consumer !== computedNode) {\n // Проверяем наличие метода add у консьюмера, страхуя граф от стороннего мусора Webpack\n if (typeof consumer.dependencies?.add === 'function') {\n subscribers.add(consumer)\n consumer.dependencies.add(computedNode)\n\n const currentDepth = computedNode.depth || 1\n const consumerRaw = consumer._node || consumer\n if (consumerRaw.depth !== undefined && currentDepth >= consumerRaw.depth) {\n consumerRaw.depth = currentDepth + 1\n }\n\n if (consumer.activeRunId !== undefined) {\n computedNode._lastSeenInRunId = consumer.activeRunId\n }\n }\n }\n\n updateIfNecessary(computedNode)\n\n if (consumer && consumer.depVersions) {\n consumer.depVersions.set(computedInstance, version)\n }\n return value\n },\n get valueWithoutTracking() { return value },\n get version() { return version },\n get dependencies() { return dependencies },\n\n subscribe(cb: (val: T) => void): CleanupFn {\n const self = this\n const fakeEffect: any = {\n id: engine.subscriberId++,\n isDirty: true,\n depth: 9999,\n dependencies: new Set(),\n type: 'effect',\n run: () => {\n if (fakeEffect.isDisposed) return\n try { cb(self.value) } catch (err) { console.error(err) }\n }\n }\n subscribers.add(fakeEffect)\n cb(this.value)\n return () => {\n fakeEffect.isDisposed = true\n subscribers.delete(fakeEffect)\n fakeEffect.dependencies.clear()\n }\n },\n subscribeState(cb: () => void): CleanupFn {\n return (computedInstance as any).subscribe(cb)\n },\n destroy: () => {\n releaseNode(computedNode)\n if (subscribers) subscribers.clear()\n engine.computedCache.delete(fn)\n\n dependencies.clear()\n depVersions.clear()\n ownedEffects.clear()\n\n isDirty = true\n state = 2\n isInitialized = false\n },\n __subscribe(cb: () => void): CleanupFn {\n const hookEffect: any = {\n id: engine.subscriberId++,\n type: 'effect',\n run: cb,\n isDirty: false\n }\n subscribers.add(hookEffect)\n return () => {\n subscribers.delete(hookEffect)\n }\n }\n } as any\n\n computedInstance.run = () => computedNode.run()\n engine.computedCache.set(fn, computedInstance)\n\n ;(computedInstance as any)._node = computedNode\n ;(computedInstance as any).subscribers = subscribers\n\n return computedInstance\n}\n"],"mappings":";AAEA,SAAgB,EACd,GACA,GACA,GACa;CAGb,IAAM,IAAW,EAAO,cAAc,IAAI,CAAE;CAC5C,IAAI,GAAU,OAAO;CAErB,IAAI,GACA,IAAU,IACV,IAAU,GACV,IAAgB,IAChB,IAAmB,IACnB,IAAQ,GAEN,oBAAe,IAAI,IAAS,GAC5B,oBAAc,IAAI,IAAiB,GACnC,oBAAe,IAAI,IAAS,GAC5B,oBAAc,IAAI,IAAS,GAE3B,KAAe,MAAoB;EACvC,IAAI,CAAC,GAAM;EACX,IAAM,IAAU,EAAK,SAAS;EAE9B,IAAI,EAAQ,gBAAgB,EAAQ,aAAa,OAAO,GAAG;GACzD,KAAK,IAAM,KAAc,EAAQ,cAAc;IAC7C,IAAM,IAAM,GACN,IAAa,EAAI,SAAS;IAEhC,AAAI,EAAW,gBACb,EAAW,YAAY,OAAO,CAAO,GACrC,EAAW,YAAY,OAAO,CAAI,GAClC,EAAW,YAAY,OAAO,CAAY,GAEtC,EAAW,SAAS,cAAc,EAAW,YAAY,SAAS,KACpE,EAAY,CAAU;GAG5B;GAEA,AADA,EAAQ,aAAa,MAAM,GACvB,EAAQ,eAAa,EAAQ,YAAY,MAAM;EACrD;CACF,GAEM,KAAqB,MAAuB;EAChD,IAAI,CAAC,KAAiB,MAAU,GAC9B,OAAO,EAAK,IAAI;EAOlB,IAAI,KAAe,EAAY,OAAO,KAChC,EAAK,oBAAoB,EAAO,SAAS,EAAO,eAAe,KAAK,MAAU,GAChF,OAAO;EAIX,IAAI,IAAmB;EAEvB,IAAI,KAAgB,EAAa,OAAO,GACtC,KAAK,IAAM,KAAO,GAAc;GAC9B,IAAM,IAAS,EAAI,SAAS;GAa5B,IAXI,EAAO,SAAS,cAAc,EAAO,QAAQ,KAI3C,EAAO,UAAU,EAAO,oBAAoB,EAAO,SACrD,EAAO,OAAO,GAMd,EAAI,iBAAiB,EAAY,IAAI,CAAG,MAAM,EAAO,SAAS;IAChE,IAAmB;IACnB;GACF;EACF;EAUF,OAPA,EAAK,kBAAkB,EAAO,OAE1B,KAAoB,IACf,EAAK,IAAI,KAGlB,IAAQ,GACD;CACT,GAEI,IAAe,GAEb,IAAoB;EACxB,IAAI,EAAO;EACX;EACA;EACA;EACA,OAAO;EACP,MAAM;EACN;EACA,IAAI,UAAU;GAAE,OAAO;EAAQ;EAC/B,IAAI,QAAQ;GAAE,OAAO;EAAM;EAC3B,IAAI,MAAM,GAAa;GAAE,IAAQ;EAAI;EACrC,IAAI,cAAc;GAAE,OAAO;EAAY;EACvC,iBAAiB;EACjB,cAAc,EAAkB,CAAY;EAC5C,WAAW;GAET,IAAI,MAAqB,EAAO,SAAS,KAAiB,MAAU,KAAK,EAAO,eAAe,GAC7F,OAAO;GAIT,IAAM,IAAa,EAAO;GAI1B,IAHA,IAAmB,GACnB,EAAa,kBAAkB,GAE3B,EAAO,oBAAoB,IAAI,CAAY,GAC7C,MAAU,MAAM,0CAA0C;GAE5D,EAAO,oBAAoB,IAAI,CAAY;GAE3C,IAAM,IAAe,EAAO,gBACtB,IAAY,EAAO;GAMzB,AAJA,EAAO,iBAAiB,GACxB,EAAO,cAAc,GAErB,KACA,EAAa,cAAc;GAE3B,IAAM,IAAU,EAAa,OAAO,IAAI,MAAM,KAAK,CAAY,IAAI;GACnE,EAAa,MAAM;GAEnB,IAAI;IACF,IAAI,EAAa,OAAO,GAAG;KACzB,KAAK,IAAM,KAAS,GAClB,AAAI,KAAS,OAAO,EAAM,WAAY,cACpC,EAAM,QAAQ;KAGlB,EAAa,MAAM;IACrB;IAGA,IAAM,IAAW,EAAG;IAEpB,IAAI,MAAY,MAAM;KACpB,IAAM,IAAkB,EAAQ,WAAW,EAAa;KACxD,KAAK,IAAM,KAAc,GAAS;MAChC,IAAM,IAAM;MACZ,IAAI,CAAC,KAAmB,CAAC,EAAa,IAAI,CAAG,GAAG;OAC9C,IAAM,IAAa,EAAI,SAAS;OAEhC,AADI,EAAW,eAAa,EAAW,YAAY,OAAO,CAAY,GACtE,EAAY,OAAO,CAAG;MACxB;KACF;IACF;IAEA,IAAM,IAAU,KAAW,CAAC,OAAO,GAAG,GAAO,CAAQ;IAErD,IAAI,GAAS;KACX,IAAM,IAAwB,IAAU,KAAA,IAAa,OAAO,KAAU,YAAY,IAAiB,KAAK,MAAM,KAAK,UAAU,CAAK,CAAC,IAAI;KAIvI,AAHA,IAAQ,GACR,KAEI,EAAO,OAAO,KAChB,EAAO,IAAI;MACT,MAAM;MACN,OAAO;MACP,SAAS;OAAE,MAAM;OAAuB,IAAI;MAAS;KACvD,CAAC;IAEL;IAIA,AAFA,IAAU,IACV,IAAQ,GACR,IAAgB;IAEhB,IAAI,IAAc;IAClB,KAAK,IAAM,KAAc,GAAc;KACrC,IAAM,IAAM,GACN,IAAU,EAAI,SAAS;KAG7B,AAFA,EAAY,IAAI,GAAK,EAAQ,OAAO,GAChC,EAAQ,eAAa,EAAQ,YAAY,IAAI,CAAY,GACzD,EAAQ,UAAU,KAAA,KAAa,EAAQ,QAAQ,MACjD,IAAc,EAAQ;IAE1B;IAcA,OAZA,EAAa,QAAQ,IAAc,GAM/B,EAAO,UAAU,MACnB,IAAmB,IACnB,EAAa,kBAAkB,IAC/B,IAAQ,IAGH;GACT,UAAU;IAGR,AAFA,EAAO,iBAAiB,GACxB,EAAO,cAAc,GACrB,EAAO,oBAAoB,OAAO,CAAY;GAChD;EACF;EACA,YAAY,MAAwB;GAC9B,WAAS,IACb;QAAQ;IAER,KAAK,IAAM,KAAO,GAAa;KAC7B,IAAM,IAAS,EAAI,SAAS;KAC5B,AAAI,EAAO,SAAS,YAClB,EAAO,UAAU,IACjB,EAAO,eAAe,CAAG,KAChB,EAAO,aAChB,EAAO,UAAU,CAAC;IAEtB;GAVQ;EAWV;CACF,GAEM,IAAgC;EACpC,IAAI,QAAQ;GAGV,IAAM,IAAW,EAAO;GACxB,IAAI,KAAY,MAAa,KAEvB,OAAO,EAAS,cAAc,OAAQ,YAAY;IAEpD,AADA,EAAY,IAAI,CAAQ,GACxB,EAAS,aAAa,IAAI,CAAY;IAEtC,IAAM,IAAe,EAAa,SAAS,GACrC,IAAc,EAAS,SAAS;IAKtC,AAJI,EAAY,UAAU,KAAA,KAAa,KAAgB,EAAY,UACjE,EAAY,QAAQ,IAAe,IAGjC,EAAS,gBAAgB,KAAA,MAC3B,EAAa,mBAAmB,EAAS;GAE7C;GAQF,OALA,EAAkB,CAAY,GAE1B,KAAY,EAAS,eACvB,EAAS,YAAY,IAAI,GAAkB,CAAO,GAE7C;EACT;EACA,IAAI,uBAAuB;GAAE,OAAO;EAAM;EAC1C,IAAI,UAAU;GAAE,OAAO;EAAQ;EAC/B,IAAI,eAAe;GAAE,OAAO;EAAa;EAEzC,UAAU,GAAiC;GACzC,IAAM,IAAO,MACP,IAAkB;IACtB,IAAI,EAAO;IACX,SAAS;IACT,OAAO;IACP,8BAAc,IAAI,IAAI;IACtB,MAAM;IACN,WAAW;KACL,OAAW,YACf,IAAI;MAAE,EAAG,EAAK,KAAK;KAAE,SAAS,GAAK;MAAE,QAAQ,MAAM,CAAG;KAAE;IAC1D;GACF;GAGA,OAFA,EAAY,IAAI,CAAU,GAC1B,EAAG,KAAK,KAAK,SACA;IAGX,AAFA,EAAW,aAAa,IACxB,EAAY,OAAO,CAAU,GAC7B,EAAW,aAAa,MAAM;GAChC;EACF;EACA,eAAe,GAA2B;GACxC,OAAQ,EAAyB,UAAU,CAAE;EAC/C;EACA,eAAe;GAWb,AAVA,EAAY,CAAY,GACpB,KAAa,EAAY,MAAM,GACnC,EAAO,cAAc,OAAO,CAAE,GAE9B,EAAa,MAAM,GACnB,EAAY,MAAM,GAClB,EAAa,MAAM,GAEnB,IAAU,IACV,IAAQ,GACR,IAAgB;EAClB;EACA,YAAY,GAA2B;GACrC,IAAM,IAAkB;IACtB,IAAI,EAAO;IACX,MAAM;IACN,KAAK;IACL,SAAS;GACX;GAEA,OADA,EAAY,IAAI,CAAU,SACb;IACX,EAAY,OAAO,CAAU;GAC/B;EACF;CACF;CAQA,OANA,EAAiB,YAAY,EAAa,IAAI,GAC9C,EAAO,cAAc,IAAI,GAAI,CAAgB,GAE5C,EAA0B,QAAQ,GAClC,EAA0B,cAAc,GAElC;AACT"}
@@ -1,35 +1,46 @@
1
1
  //#region src/core/core.method.effect.ts
2
2
  function e(e, t, n) {
3
- let r = !1, i = !1, a = 2, o = /* @__PURE__ */ new Set(), s = /* @__PURE__ */ new Map(), c = /* @__PURE__ */ new Set(), l = () => {
4
- if (c.size > 0) {
5
- let t = e.activeConsumer, n = e.activeOwner;
6
- e.activeConsumer = null, e.activeOwner = null;
7
- for (let e of c) e.dispose && e.dispose();
8
- c.clear(), e.activeConsumer = t, e.activeOwner = n;
9
- }
10
- if (u.cleanups.size > 0) {
11
- let t = e.activeConsumer;
12
- e.activeConsumer = null;
13
- for (let e of u.cleanups) try {
14
- e();
15
- } catch (e) {
16
- console.error(e);
3
+ let r = !1, i = !1, a = !1, o = 2, s = /* @__PURE__ */ new Set(), c = /* @__PURE__ */ new Map(), l = /* @__PURE__ */ new Set(), u = /* @__PURE__ */ new Map(), d = () => {
4
+ if (a) return;
5
+ a = !0;
6
+ let t = e.activeCleanupNode;
7
+ e.activeCleanupNode = f;
8
+ try {
9
+ if (l.size > 0) {
10
+ let t = e.activeConsumer, n = e.activeOwner;
11
+ e.activeConsumer = null, e.activeOwner = null;
12
+ for (let e of l) e.dispose && e.dispose();
13
+ l.clear(), e.activeConsumer = t, e.activeOwner = n;
14
+ }
15
+ if (f.cleanups.size > 0) {
16
+ let t = e.activeConsumer;
17
+ e.activeConsumer = null;
18
+ let n = null, r = Array.from(f.cleanups);
19
+ f.cleanups.clear();
20
+ for (let e of r) try {
21
+ e();
22
+ } catch (e) {
23
+ console.error(e), n ||= e;
24
+ }
25
+ if (e.activeConsumer = t, n) throw n;
17
26
  }
18
- u.cleanups.clear(), e.activeConsumer = t;
27
+ } finally {
28
+ e.activeCleanupNode = t, a = !1;
19
29
  }
20
- }, u = {
30
+ }, f = {
21
31
  id: e.subscriberId++,
22
- dependencies: o,
23
- ownedEffects: c,
32
+ dependencies: s,
33
+ ownedEffects: l,
24
34
  cleanups: /* @__PURE__ */ new Set(),
25
35
  type: "effect",
26
36
  depth: 0,
27
37
  label: n,
38
+ _snapshotValues: u,
28
39
  get isDirty() {
29
- return a > 0;
40
+ return o > 0;
30
41
  },
31
42
  set isDirty(e) {
32
- e && (a = 2);
43
+ e && (o = 2);
33
44
  },
34
45
  get isDisposed() {
35
46
  return r;
@@ -38,60 +49,69 @@ function e(e, t, n) {
38
49
  r = e;
39
50
  },
40
51
  get state() {
41
- return a;
52
+ return o;
42
53
  },
43
54
  set state(e) {
44
- a = e;
55
+ o = e;
45
56
  },
46
57
  get depVersions() {
47
- return s;
58
+ return c;
48
59
  },
49
60
  get _node() {
50
- return u;
61
+ return f;
51
62
  },
52
63
  markDirty: () => {
53
- a >= 1 || (a = 1, e.scheduleEffect(u));
64
+ r || o >= 1 || (o = 1, e.scheduleEffect(f));
54
65
  },
55
66
  run: () => {
56
67
  if (r || i) return;
57
- i = !0, l();
58
- let n = e.activeConsumer, c = e.activeOwner;
59
- e.activeConsumer = u, e.activeOwner = u;
60
- let d = o.size > 0 ? Array.from(o) : null;
61
- o.clear();
68
+ i = !0;
69
+ try {
70
+ d();
71
+ } catch (e) {
72
+ throw i = !1, e;
73
+ }
74
+ if (r) {
75
+ i = !1;
76
+ return;
77
+ }
78
+ let n = e.activeConsumer, a = e.activeOwner;
79
+ e.activeConsumer = f, e.activeOwner = f;
80
+ let l = s.size > 0 ? Array.from(s) : null;
81
+ s.clear();
62
82
  try {
63
- a = 0;
83
+ o = 0;
64
84
  let e = t();
65
- if (typeof e == "function" && u.cleanups.add(e), d !== null) for (let e of d) {
85
+ if (typeof e == "function" && f.cleanups.add(e), l !== null) for (let e of l) {
66
86
  let t = e;
67
- if (!o.has(t)) {
87
+ if (!s.has(t)) {
68
88
  let e = t._node || t;
69
- e.subscribers && e.subscribers.delete(u), s.delete(t);
89
+ e.subscribers && e.subscribers.delete(f), c.delete(t), u.delete(t);
70
90
  }
71
91
  }
72
92
  let n = 0;
73
- for (let e of o) {
93
+ for (let e of s) {
74
94
  let t = e, r = t._node || t;
75
- s.set(t, r.version), r.subscribers && r.subscribers.add(u), r.depth !== void 0 && r.depth > n && (n = r.depth);
95
+ c.set(t, r.version), r.subscribers && r.subscribers.add(f), r.depth !== void 0 && r.depth > n && (n = r.depth);
76
96
  }
77
- u.depth = n + 1;
97
+ f.depth = n + 1;
78
98
  } finally {
79
- i = !1, e.activeConsumer = n, e.activeOwner = c;
99
+ i = !1, e.activeConsumer = n, e.activeOwner = a;
80
100
  }
81
101
  },
82
102
  dispose: () => {
83
103
  if (!r) {
84
- r = !0, u.isDisposed = !0, l();
85
- for (let e of o) {
104
+ r = !0, f.isDisposed = !0, d();
105
+ for (let e of s) {
86
106
  let t = e._node || e;
87
- t.subscribers && t.subscribers.delete(u);
107
+ t.subscribers && t.subscribers.delete(f);
88
108
  }
89
- o.clear(), s.clear();
109
+ s.clear(), c.clear(), u.clear();
90
110
  }
91
111
  }
92
- }, d = e.activeOwner ? e.activeOwner._node || e.activeOwner : null;
93
- return d && d.ownedEffects && d.ownedEffects.add(u), u.run(), () => {
94
- u.dispose();
112
+ }, p = e.activeOwner ? e.activeOwner._node || e.activeOwner : null;
113
+ return p && p.ownedEffects && p.ownedEffects.add(f), f.run(), () => {
114
+ f.dispose();
95
115
  };
96
116
  }
97
117
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"core.method.effect.mjs","names":[],"sources":["../src/core/core.method.effect.ts"],"sourcesContent":["import { IEffect, EffectFn, CleanupFn } from './types'\n\ninterface ICoreEffectNode extends IEffect {\n dependencies: Set<any>;\n depVersions: Map<any, number>;\n ownedEffects: Set<ICoreEffectNode>;\n type: string;\n depth: number;\n state: number;\n _node: any;\n dispose: () => void;\n}\n\nexport function createEffect(engine: any, fn: EffectFn, effectName?: string): () => void {\n let isDisposed = false\n let isRunning = false\n let state = 2 // 0 = STABLE, 1 = CHECK, 2 = DIRTY\n\n const dependencies = new Set<any>()\n const depVersions = new Map<any, number>()\n const ownedEffects = new Set<ICoreEffectNode>()\n\n const runCleanupPhase = () => {\n // Каскадное уничтожение вложенных детей через быстрый for...of\n if (ownedEffects.size > 0) {\n const prevConsumer = engine.activeConsumer\n const prevOwner = engine.activeOwner\n engine.activeConsumer = null\n engine.activeOwner = null\n\n for (const child of ownedEffects) {\n if (child.dispose) child.dispose()\n }\n ownedEffects.clear()\n\n engine.activeConsumer = prevConsumer\n engine.activeOwner = prevOwner\n }\n\n // Изоляция ошибок в деструкторах пользователя через быстрый for...of\n if (effectNode.cleanups.size > 0) {\n const prevConsumer = engine.activeConsumer\n engine.activeConsumer = null\n\n for (const cleanup of effectNode.cleanups) {\n try {\n cleanup()\n } catch (err) {\n console.error(err)\n }\n }\n\n effectNode.cleanups.clear()\n engine.activeConsumer = prevConsumer\n }\n }\n\n const effectNode: ICoreEffectNode = {\n id: engine.subscriberId++,\n dependencies,\n ownedEffects,\n cleanups: new Set<CleanupFn>(),\n type: 'effect',\n depth: 0,\n label: effectName,\n\n get isDirty(): boolean { return state > 0 },\n set isDirty(val: boolean) { if (val) state = 2 },\n\n get isDisposed(): boolean { return isDisposed },\n set isDisposed(val: boolean) { isDisposed = val },\n\n get state(): number { return state },\n set state(val: number) { state = val },\n get depVersions(): Map<any, number> { return depVersions },\n get _node(): any { return effectNode },\n\n markDirty: () => {\n if (state >= 1) return\n state = 1\n engine.scheduleEffect(effectNode)\n },\n\n run: () => {\n if (isDisposed || isRunning) return\n isRunning = true\n\n runCleanupPhase()\n\n const prevConsumer = engine.activeConsumer\n const prevOwner = engine.activeOwner\n\n engine.activeConsumer = effectNode\n engine.activeOwner = effectNode\n\n const oldDeps = dependencies.size > 0 ? Array.from(dependencies) : null\n dependencies.clear()\n\n try {\n state = 0 // Сбрасываем флаг грязи перед чтением графа\n\n const result = fn()\n if (typeof result === 'function') {\n effectNode.cleanups.add(result)\n }\n\n if (oldDeps !== null) {\n for (const unknownDep of oldDeps) {\n const dep = unknownDep as any\n if (!dependencies.has(dep)) {\n const rawDepNode = dep._node || dep\n if (rawDepNode.subscribers) rawDepNode.subscribers.delete(effectNode)\n depVersions.delete(dep)\n }\n }\n }\n\n let maxDepDepth = 0\n for (const unknownDep of dependencies) {\n const dep = unknownDep as any\n const rawNode = dep._node || dep\n depVersions.set(dep, rawNode.version)\n if (rawNode.subscribers) rawNode.subscribers.add(effectNode)\n if (rawNode.depth !== undefined && rawNode.depth > maxDepDepth) {\n maxDepDepth = rawNode.depth\n }\n }\n effectNode.depth = maxDepDepth + 1\n\n } finally {\n isRunning = false\n engine.activeConsumer = prevConsumer\n engine.activeOwner = prevOwner\n }\n },\n\n dispose: () => {\n if (isDisposed) return\n isDisposed = true\n effectNode.isDisposed = true\n\n runCleanupPhase()\n\n // ⚡ ОПТИМИЗАЦИЯ: Замена .forEach на быстрый for...of при полном уничтожении эффекта\n for (const dep of dependencies) {\n const rawNode = dep._node || dep\n if (rawNode.subscribers) rawNode.subscribers.delete(effectNode)\n }\n dependencies.clear()\n depVersions.clear()\n }\n }\n\n const actualOwnerNode = engine.activeOwner ? (engine.activeOwner._node || engine.activeOwner) : null\n\n if (actualOwnerNode && actualOwnerNode.ownedEffects) {\n actualOwnerNode.ownedEffects.add(effectNode)\n }\n\n effectNode.run()\n\n return () => {\n effectNode.dispose()\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"core.method.effect.mjs","names":[],"sources":["../src/core/core.method.effect.ts"],"sourcesContent":["import { IEffect, EffectFn, CleanupFn } from './types'\n\ninterface ICoreEffectNode extends IEffect {\n dependencies: Set<any>;\n depVersions: Map<any, number>;\n ownedEffects: Set<ICoreEffectNode>;\n type: string;\n depth: number;\n state: number;\n _node: any;\n dispose: () => void;\n _snapshotValues: Map<any, any>;\n}\n\nexport function createEffect(engine: any, fn: EffectFn, effectName?: string): () => void {\n let isDisposed = false\n let isRunning = false\n let isCleaning = false\n let state = 2 // 0 = STABLE, 1 = CHECK, 2 = DIRTY (Гарантированное объявление переменной)\n\n const dependencies = new Set<any>()\n const depVersions = new Map<any, number>()\n const ownedEffects = new Set<ICoreEffectNode>()\n const snapshotValues = new Map<any, any>()\n\n const runCleanupPhase = () => {\n if (isCleaning) return\n isCleaning = true\n\n // Активируем контекст чтения исторических снапшотов\n const prevCleanupNode = engine.activeCleanupNode\n engine.activeCleanupNode = effectNode\n\n try {\n // 1. Каскадное уничтожение вложенных дочерних эффектов\n if (ownedEffects.size > 0) {\n const prevConsumer = engine.activeConsumer\n const prevOwner = engine.activeOwner\n engine.activeConsumer = null\n engine.activeOwner = null\n\n for (const child of ownedEffects) {\n if (child.dispose) child.dispose()\n }\n ownedEffects.clear()\n\n engine.activeConsumer = prevConsumer\n engine.activeOwner = prevOwner\n }\n\n // 2. Вызов деструкторов пользователя в режиме untracked\n if (effectNode.cleanups.size > 0) {\n const prevConsumer = engine.activeConsumer\n engine.activeConsumer = null\n\n let firstError: unknown = null\n const cleanupsArray = Array.from(effectNode.cleanups)\n effectNode.cleanups.clear()\n\n for (const cleanup of cleanupsArray) {\n try {\n cleanup()\n } catch (err) {\n console.error(err)\n if (!firstError) {\n firstError = err\n }\n }\n }\n\n engine.activeConsumer = prevConsumer\n\n if (firstError) {\n throw firstError\n }\n }\n } finally {\n engine.activeCleanupNode = prevCleanupNode\n isCleaning = false\n }\n }\n\n const effectNode: ICoreEffectNode = {\n id: engine.subscriberId++,\n dependencies,\n ownedEffects,\n cleanups: new Set<CleanupFn>(),\n type: 'effect',\n depth: 0,\n label: effectName,\n _snapshotValues: snapshotValues,\n\n get isDirty(): boolean { return state > 0 },\n set isDirty(val: boolean) { if (val) state = 2 },\n\n get isDisposed(): boolean { return isDisposed },\n set isDisposed(val: boolean) { isDisposed = val },\n\n get state(): number { return state },\n set state(val: number) { state = val },\n get depVersions(): Map<any, number> { return depVersions },\n get _node(): any { return effectNode },\n\n markDirty: () => {\n if (isDisposed || state >= 1) return\n state = 1\n engine.scheduleEffect(effectNode)\n },\n\n run: () => {\n if (isDisposed || isRunning) return\n isRunning = true\n\n try {\n runCleanupPhase()\n } catch (err) {\n isRunning = false\n throw err\n }\n\n if (isDisposed) {\n isRunning = false\n return\n }\n\n const prevConsumer = engine.activeConsumer\n const prevOwner = engine.activeOwner\n\n engine.activeConsumer = effectNode\n engine.activeOwner = effectNode\n\n const oldDeps = dependencies.size > 0 ? Array.from(dependencies) : null\n dependencies.clear()\n\n try {\n state = 0 // Локальная переменная замыкания теперь успешно сбрасывается в STABLE\n\n const result = fn()\n if (typeof result === 'function') {\n effectNode.cleanups.add(result)\n }\n\n if (oldDeps !== null) {\n for (const unknownDep of oldDeps) {\n const dep = unknownDep as any\n if (!dependencies.has(dep)) {\n const rawDepNode = dep._node || dep\n if (rawDepNode.subscribers) rawDepNode.subscribers.delete(effectNode)\n depVersions.delete(dep)\n snapshotValues.delete(dep)\n }\n }\n }\n\n let maxDepDepth = 0\n for (const unknownDep of dependencies) {\n const dep = unknownDep as any\n const rawNode = dep._node || dep\n depVersions.set(dep, rawNode.version)\n if (rawNode.subscribers) rawNode.subscribers.add(effectNode)\n if (rawNode.depth !== undefined && rawNode.depth > maxDepDepth) {\n maxDepDepth = rawNode.depth\n }\n }\n effectNode.depth = maxDepDepth + 1\n\n } finally {\n isRunning = false\n engine.activeConsumer = prevConsumer\n engine.activeOwner = prevOwner\n }\n },\n\n dispose: () => {\n if (isDisposed) return\n isDisposed = true\n effectNode.isDisposed = true\n\n runCleanupPhase()\n\n for (const dep of dependencies) {\n const rawNode = dep._node || dep\n if (rawNode.subscribers) rawNode.subscribers.delete(effectNode)\n }\n dependencies.clear()\n depVersions.clear()\n snapshotValues.clear()\n }\n }\n\n const actualOwnerNode = engine.activeOwner ? (engine.activeOwner._node || engine.activeOwner) : null\n\n if (actualOwnerNode && actualOwnerNode.ownedEffects) {\n actualOwnerNode.ownedEffects.add(effectNode)\n }\n\n effectNode.run()\n\n return () => {\n effectNode.dispose()\n }\n}\n"],"mappings":"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"}
@@ -124,7 +124,9 @@ function t(t, n, r, i) {
124
124
  total: d,
125
125
  nextDelayMs: Math.round(e)
126
126
  } }
127
- }), console.warn(`[Resource Retry] "${o}" сбой по ${r ? "таймауту" : "ошибке сети"}. Запрос ${a + 1} из ${d + 1} не удался. Ожидание повтора: ${Math.round(e)}ms`);
127
+ });
128
+ let n = r ? "таймауту" : "ошибке сети";
129
+ t.logger.isEnabled && console.warn(`[Resource Retry] "${o}" сбой по ${n}. Запрос ${a + 1} из ${d + 1} не удался. Ожидание повтора: ${Math.round(e)}ms`);
128
130
  try {
129
131
  if (await t.delay(e, i), i.aborted) return;
130
132
  } catch {