@raphy-js/raph 1.0.1-dev.25 → 1.0.1-dev.54

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 (127) hide show
  1. package/README.md +100 -0
  2. package/dist/api/Raph.d.ts +15 -15
  3. package/dist/api/RaphFacadeSession.d.ts +4 -4
  4. package/dist/api/RaphReactivityInstance.d.ts +4 -4
  5. package/dist/api/types.d.ts +11 -11
  6. package/dist/compact.cjs +1 -0
  7. package/dist/compact.js +4 -0
  8. package/dist/debug/reactivity/engine-core.cjs +1 -0
  9. package/dist/debug/reactivity/engine-core.js +1760 -0
  10. package/dist/debug/reactivity/engine.cjs +1 -1
  11. package/dist/debug/reactivity/engine.js +25 -1689
  12. package/dist/debug/reactivity/reactive-object.cjs +1 -1
  13. package/dist/debug/reactivity/reactive-object.js +604 -167
  14. package/dist/debug/runtime/RaphCompactExecutionRuntime.cjs +1 -0
  15. package/dist/debug/runtime/RaphCompactExecutionRuntime.js +9 -0
  16. package/dist/debug/runtime/RaphExecutionRuntime.cjs +1 -0
  17. package/dist/debug/runtime/RaphExecutionRuntime.js +11 -0
  18. package/dist/debug/runtime/RaphRuntime.cjs +1 -1
  19. package/dist/debug/runtime/RaphRuntime.js +115 -1176
  20. package/dist/debug/runtime/RaphRuntimeBase.cjs +1 -0
  21. package/dist/debug/runtime/RaphRuntimeBase.js +941 -0
  22. package/dist/debug/runtime/diagnostics/RaphDebug.cjs +1 -1
  23. package/dist/debug/runtime/diagnostics/RaphDebug.js +72 -66
  24. package/dist/debug/runtime/ownership/RaphNode.cjs +1 -1
  25. package/dist/debug/runtime/ownership/RaphNode.js +11 -0
  26. package/dist/debug/runtime/ownership/RaphScope.cjs +1 -1
  27. package/dist/debug/runtime/ownership/RaphScope.js +12 -12
  28. package/dist/debug/runtime/phases/RaphPhasePipeline.cjs +1 -1
  29. package/dist/debug/runtime/phases/RaphPhasePipeline.js +361 -242
  30. package/dist/debug/runtime/phases/RaphPhaseTaskRecord.cjs +1 -1
  31. package/dist/debug/runtime/phases/RaphPhaseTaskRecord.js +23 -22
  32. package/dist/debug/runtime/reactivity/RaphSelector.cjs +1 -1
  33. package/dist/debug/runtime/reactivity/RaphSelector.js +111 -90
  34. package/dist/debug/runtime/reactivity/RuntimeObjectSupport.cjs +1 -0
  35. package/dist/debug/runtime/reactivity/RuntimeObjectSupport.js +11 -0
  36. package/dist/debug/runtime/reactivity/RuntimeReactivity.cjs +1 -1
  37. package/dist/debug/runtime/reactivity/RuntimeReactivity.js +118 -103
  38. package/dist/debug/runtime/reactivity/RuntimeSelectorSupport.cjs +1 -0
  39. package/dist/debug/runtime/reactivity/RuntimeSelectorSupport.js +12 -0
  40. package/dist/entrypoints/compact.d.ts +2 -0
  41. package/dist/entrypoints/execution.d.ts +2 -0
  42. package/dist/entrypoints/machine-testing.d.ts +2 -2
  43. package/dist/entrypoints/machine.d.ts +5 -5
  44. package/dist/entrypoints/observable.d.ts +4 -0
  45. package/dist/entrypoints/path.d.ts +14 -14
  46. package/dist/entrypoints/reactivity.d.ts +1 -1
  47. package/dist/entrypoints/runtime.d.ts +19 -18
  48. package/dist/execution.cjs +1 -0
  49. package/dist/execution.js +4 -0
  50. package/dist/index.cjs +1 -1
  51. package/dist/index.js +23 -21
  52. package/dist/machine/compiler.d.ts +1 -1
  53. package/dist/machine/core.d.ts +2 -2
  54. package/dist/machine/persistence.d.ts +1 -1
  55. package/dist/machine/runtime.d.ts +3 -3
  56. package/dist/machine/testing.d.ts +1 -1
  57. package/dist/machine/types.d.ts +3 -3
  58. package/dist/main.d.ts +19 -19
  59. package/dist/observable/buffer.d.ts +6 -0
  60. package/dist/observable/class-admin.d.ts +63 -0
  61. package/dist/observable/class-plan.d.ts +46 -0
  62. package/dist/observable/classes.d.ts +10 -0
  63. package/dist/observable/context.d.ts +73 -0
  64. package/dist/observable/native.d.ts +2 -0
  65. package/dist/observable/observable.d.ts +13 -0
  66. package/dist/observable/types.d.ts +60 -0
  67. package/dist/observable.cjs +1 -0
  68. package/dist/observable.js +1187 -0
  69. package/dist/path/DataPath.d.ts +2 -2
  70. package/dist/path/PathRouter.d.ts +1 -1
  71. package/dist/path/RaphKernel.d.ts +6 -6
  72. package/dist/path/data-path.types.d.ts +1 -1
  73. package/dist/path/data-path.utils.d.ts +2 -2
  74. package/dist/path/derived/DerivedRegistry.d.ts +3 -3
  75. package/dist/path/derived/RaphDerivedHandle.d.ts +3 -3
  76. package/dist/path/derived/derived-collection.types.d.ts +1 -1
  77. package/dist/path/derived/derived-collection.utils.d.ts +3 -3
  78. package/dist/path/derived/derived-strategy.utils.d.ts +1 -1
  79. package/dist/path/meta/MetaController.d.ts +5 -5
  80. package/dist/path/meta/RaphMeta.d.ts +3 -3
  81. package/dist/path/meta/RaphMetaStore.d.ts +1 -1
  82. package/dist/path/meta/meta.types.d.ts +2 -2
  83. package/dist/path/path.types.d.ts +2 -2
  84. package/dist/path/pathSegmentKey.d.ts +1 -1
  85. package/dist/path/storage/AdapterPathStore.d.ts +2 -2
  86. package/dist/path/storage/DefaultDataAdapter.d.ts +2 -2
  87. package/dist/path/storage/PathEventHub.d.ts +1 -1
  88. package/dist/path/storage/PathStore.d.ts +2 -2
  89. package/dist/path/storage/data-adapter.types.d.ts +1 -1
  90. package/dist/raph.cjs +1 -1
  91. package/dist/raph.js +23 -21
  92. package/dist/reactivity/engine-core.d.ts +600 -0
  93. package/dist/reactivity/engine.d.ts +6 -550
  94. package/dist/reactivity/reactive-object.d.ts +143 -2
  95. package/dist/reactivity/scope.d.ts +7 -6
  96. package/dist/reactivity/types.d.ts +9 -12
  97. package/dist/reactivity/watch.d.ts +1 -1
  98. package/dist/runtime/RaphCompactExecutionRuntime.d.ts +7 -0
  99. package/dist/runtime/RaphExecutionRuntime.d.ts +6 -0
  100. package/dist/runtime/RaphRuntime.d.ts +19 -403
  101. package/dist/runtime/RaphRuntimeBase.d.ts +194 -0
  102. package/dist/runtime/diagnostics/RaphDebug.d.ts +8 -5
  103. package/dist/runtime/errors.d.ts +1 -1
  104. package/dist/runtime/ownership/RaphEffectScope.d.ts +13 -12
  105. package/dist/runtime/ownership/RaphNode.d.ts +28 -21
  106. package/dist/runtime/ownership/RaphScope.d.ts +32 -19
  107. package/dist/runtime/ownership/parent-graph.types.d.ts +1 -1
  108. package/dist/runtime/ownership/parentGraph.d.ts +2 -2
  109. package/dist/runtime/phases/RaphFrameLoop.d.ts +1 -1
  110. package/dist/runtime/phases/RaphPhasePipeline.d.ts +80 -29
  111. package/dist/runtime/phases/RaphPhaseTaskRecord.d.ts +21 -21
  112. package/dist/runtime/phases/RaphPhaseWatch.d.ts +3 -3
  113. package/dist/runtime/phases/orderPhaseTasks.d.ts +4 -2
  114. package/dist/runtime/phases/phase.types.d.ts +36 -35
  115. package/dist/runtime/reactivity/PathHandle.d.ts +5 -5
  116. package/dist/runtime/reactivity/RaphMetaSource.d.ts +7 -7
  117. package/dist/runtime/reactivity/RaphSelector.d.ts +27 -6
  118. package/dist/runtime/reactivity/RaphWorkGraph.d.ts +40 -39
  119. package/dist/runtime/reactivity/RuntimeObjectSupport.d.ts +9 -0
  120. package/dist/runtime/reactivity/RuntimeReactivity.d.ts +27 -19
  121. package/dist/runtime/reactivity/RuntimeSelectorSupport.d.ts +10 -0
  122. package/dist/runtime/reactivity/RuntimeWatch.d.ts +1 -1
  123. package/dist/runtime/reactivity/disposal-sweep.utils.d.ts +1 -1
  124. package/dist/runtime/reactivity/runtime-reactivity.types.d.ts +3 -3
  125. package/dist/runtime.cjs +1 -1
  126. package/dist/runtime.js +13 -11
  127. package/package.json +22 -62
@@ -0,0 +1,1760 @@
1
+ import { appendScopeChild as A, ScopeNode as O, throwScopeErrors as m, detachScopeChild as H } from "./scope.js";
2
+ import { watchWithReactivity as F } from "./watch.js";
3
+ const S = 1, f = 2, D = 4, p = 8, E = 16, o = 32, d = 64, R = 128, y = 256, h = 512, N = 1 << 17, L = 1024, g = 4096, C = 8192, k = 16384, x = 32768, _ = 65536, W = g, T = 1e4, b = S | f, U = 16;
4
+ function q(w, e) {
5
+ const t = w.firstSub;
6
+ if (t === null)
7
+ return;
8
+ if (t === w.lastSub)
9
+ return t.sub === e ? t : void 0;
10
+ const i = w.subSearchCursor ?? t;
11
+ if (i.sub === e)
12
+ return w.subSearchCursor = i.nextSub ?? t, i;
13
+ let s = i.nextSub ?? t;
14
+ for (; s !== i; ) {
15
+ if (s.sub === e)
16
+ return w.subSearchCursor = s.nextSub ?? t, s;
17
+ s = s.nextSub ?? t;
18
+ }
19
+ }
20
+ class G {
21
+ // Opt-in стратегия длинного slow path; не добавляет policy field каждой ноде.
22
+ // Потребитель текущего синхронного чтения; null отключает отслеживание.
23
+ activeSub = null;
24
+ /** Потребитель-проба `_probeReads`; создаётся при первом вызове. */
25
+ probeNode = null;
26
+ probeDepth = 0;
27
+ // Глубина вложенных синхронных границ группировки.
28
+ batchDepth = 0;
29
+ // Индекс следующего элемента внутренней очереди эффектов.
30
+ effectReadIndex = 0;
31
+ // Позиция добавления элемента в текущем проходе очереди.
32
+ effectWriteIndex = 0;
33
+ // Граница активного префикса переиспользуемого стека invalidation.
34
+ invalidationDepth = 0;
35
+ // Граница активного префикса стека проверки зависимостей.
36
+ dependencyDepth = 0;
37
+ // Число активных проверок зависимостей; только при нём запись ищет их узлы.
38
+ checkingDepth = 0;
39
+ // Корни активных проверок по глубине вложенности. Остальные проверяемые узлы
40
+ // восстанавливаются из опубликованного префикса dependencyStack: отдельная
41
+ // пометка каждого узла на обычном пути не нужна (серия Raph Top-1, 2026-10-20).
42
+ checkRoots = [];
43
+ // Защита внутренней очереди от вложенного повторного прохода.
44
+ flushingEffects = !1;
45
+ // Переиспользуемый буфер очереди; прочитанная ячейка сразу освобождает ссылку.
46
+ // Первый элемент очереди хранится без обращения к массиву.
47
+ firstEffect;
48
+ effectQueue = new Array(16).fill(void 0);
49
+ // Переиспользуемый стек распространения invalidation; исходный способ выделения сохранён.
50
+ invalidationStack = new Array(512).fill(null);
51
+ // Переиспользуемый стек проверки зависимостей с защитой активного вложенного префикса.
52
+ dependencyStack = [];
53
+ // Общие адаптеры receiver для handles этого экземпляра.
54
+ // Создаются один раз, чтобы computed не хранил дополнительную ссылку на движок
55
+ // и не выделял отдельные get/peek closures на каждый источник.
56
+ handleReaders = this.createHandleReaders();
57
+ // Выбранная внешняя политика; у синхронного экземпляра отсутствует.
58
+ effectScheduler;
59
+ // Прямой обработчик очереди, выбранный один раз при создании экземпляра.
60
+ flushEffects;
61
+ /**
62
+ * Синхронная регистрация эффекта для Runtime и watch независимо от внешней политики.
63
+ * Это связанная ссылка на реализацию effect(), а не делегирующая функция.
64
+ * @internal
65
+ */
66
+ _effectImmediate;
67
+ /**
68
+ * Выбирает политику исполнения и сохраняет совместимость извлечённых методов.
69
+ * Тела методов находятся на прототипе; bind() выполняется только при создании
70
+ * экземпляра, чтобы Runtime и глобальный API могли передавать методы как callbacks.
71
+ * @param options Необязательная внешняя политика эффектов.
72
+ */
73
+ constructor(e = {}) {
74
+ this.effectScheduler = e.effectScheduler, this._effectImmediate = this.effect.bind(this), this.signal = this.signal.bind(this), this.computed = this.computed.bind(this), this.watch = this.watch.bind(this), this.batch = this.batch.bind(this), this.untracked = this.untracked.bind(this), this.scope = this.scope.bind(this), this._signalAccess = this._signalAccess.bind(this), this._computedAccess = this._computedAccess.bind(this), this._ownedSignal = this._ownedSignal.bind(this), this._ownedComputed = this._ownedComputed.bind(this), this._isTracking = this._isTracking.bind(this), this._isFlushingEffects = this._isFlushingEffects.bind(this), this._startBatch = this._startBatch.bind(this), this._endBatch = this._endBatch.bind(this), this.effect = this.effectScheduler === void 0 ? this._effectImmediate : this.createScheduledEffect.bind(this), this.flushEffects = this.effectScheduler === void 0 ? this.flushSyncEffects : this.flushExternalEffects;
75
+ }
76
+ // ---------------------------------------------
77
+ // PUBLIC API
78
+ // ---------------------------------------------
79
+ /**
80
+ * Создаёт объектный signal с get/peek/set.
81
+ * get() регистрирует зависимость только при активном потребителе,
82
+ * а peek() выполняет чтение с временно отключённым отслеживанием.
83
+ */
84
+ signal(e) {
85
+ let t = e, i;
86
+ const s = () => {
87
+ const r = i;
88
+ if (r !== void 0)
89
+ return this.readSignalValue(r);
90
+ const n = this.activeSub;
91
+ return n === null || (i = this.materializeSignal(
92
+ t,
93
+ n
94
+ )), t;
95
+ }, l = (r) => {
96
+ const n = i;
97
+ if (n !== void 0) {
98
+ this.writeSignalValue(n, r);
99
+ return;
100
+ }
101
+ t !== r && (t = r);
102
+ };
103
+ return {
104
+ get: s,
105
+ peek: this.handleReaders.peek,
106
+ set: l
107
+ };
108
+ }
109
+ computed(e) {
110
+ if (typeof e == "function")
111
+ return this.createComputedHandle(e);
112
+ const t = this.createComputedHandle(e.get);
113
+ return t.set = e.set, t;
114
+ }
115
+ /**
116
+ * Создаёт эффект согласно политике экземпляра и возвращает disposer.
117
+ * Прототип содержит синхронную реализацию; при наличии scheduler конструктор
118
+ * подставляет createScheduledEffect, сохраняя этот путь как _effectImmediate.
119
+ * Вложенный эффект включается в список ресурсов активного эффекта.
120
+ * При ошибке регистрации удаляет созданные ресурсы, сохраняя обе причины сбоя.
121
+ * @param fn Синхронное тело с необязательным cleanup очередного запуска.
122
+ * @param onStop Однократная окончательная очистка, независимая от повторных запусков.
123
+ */
124
+ effect(e, t) {
125
+ const i = this.allocateGraphRecord(void 0, e, f | S | o, void 0);
126
+ t !== void 0 && (i.onStop = t);
127
+ const s = this.activeSub;
128
+ s !== null && s.flags & o && A(s, i);
129
+ try {
130
+ this.executeEffect(i);
131
+ } catch (l) {
132
+ try {
133
+ this.disposeEffect(i);
134
+ } catch (r) {
135
+ throw new AggregateError([l, r], "Effect registration and cleanup failed.");
136
+ }
137
+ throw l;
138
+ }
139
+ return this.effectReadIndex !== this.effectWriteIndex && this.flushEffects(), () => this.disposeEffect(i);
140
+ }
141
+ /**
142
+ * Наблюдает за источниками; callback и cleanup не создают зависимостей.
143
+ */
144
+ watch(e, t, i) {
145
+ return F(this.effect, this.untracked, e, t, i);
146
+ }
147
+ /**
148
+ * Группирует синхронные записи и обрабатывает эффекты после внешней границы.
149
+ * Возвращает результат операции. Если тело и очередь завершаются с ошибками,
150
+ * передаёт обе ошибки в AggregateError вместо потери первой. Не является откатом данных.
151
+ */
152
+ batch(e) {
153
+ ++this.batchDepth;
154
+ let t;
155
+ try {
156
+ t = e();
157
+ } catch (i) {
158
+ if (!--this.batchDepth && this.effectReadIndex !== this.effectWriteIndex)
159
+ try {
160
+ this.flushEffects();
161
+ } catch (s) {
162
+ throw new AggregateError(
163
+ [i, s],
164
+ "Batch operation and effect queue processing failed."
165
+ );
166
+ }
167
+ throw i;
168
+ }
169
+ return !--this.batchDepth && this.effectReadIndex !== this.effectWriteIndex && this.flushEffects(), t;
170
+ }
171
+ /**
172
+ * Выполняет синхронную операцию без добавления зависимостей текущему потребителю.
173
+ * Восстанавливает прежний контекст и при исключении. Асинхронное продолжение
174
+ * операции этим контекстом не охватывается.
175
+ */
176
+ untracked(e) {
177
+ if (this.activeSub === null)
178
+ return e();
179
+ const t = this.activeSub;
180
+ this.activeSub = null;
181
+ try {
182
+ return e();
183
+ } finally {
184
+ this.activeSub = t;
185
+ }
186
+ }
187
+ /**
188
+ * Создаёт владельца ресурсов в текущем графе без Runtime и фаз.
189
+ */
190
+ scope() {
191
+ return new O(this);
192
+ }
193
+ // ---------------------------------------------
194
+ // PRIVATE
195
+ // ---------------------------------------------
196
+ /**
197
+ * Создаёт запись графа единой формы для standalone signal, raw computed и effect.
198
+ * Все горячие поля, включая pending-запись signal, курсор поиска потребителя и
199
+ * общий raw reader, объявлены в одном литерале: запись целиком лежит внутри
200
+ * объекта, а signal, computed и effect разделяют один hidden class
201
+ * (серия Raph Top-1, 2026-10-20). Поля внешней задачи, окончательной очистки,
202
+ * владельца и адаптивного индекса добавляются только при необходимости.
203
+ */
204
+ allocateGraphRecord(e, t, i, s) {
205
+ return {
206
+ flags: i,
207
+ firstSub: null,
208
+ lastSub: null,
209
+ firstDep: null,
210
+ tailDep: null,
211
+ evaluate: t,
212
+ cachedValue: e,
213
+ pendingValue: void 0,
214
+ pendingAuthor: void 0,
215
+ subSearchCursor: void 0,
216
+ read: s
217
+ };
218
+ }
219
+ /** Creates a narrow Proxy adapter over the existing intrusive graph. */
220
+ /** Узкий adapter SDK; записи графа остаются инкапсулированы. @internal */
221
+ _createReactivePropertySourceBridge() {
222
+ return {
223
+ batch: this.batch,
224
+ startBatch: this._startBatch,
225
+ endBatch: this._endBatch,
226
+ create: (e) => {
227
+ if (this.activeSub === null)
228
+ throw new Error("[Raph] Reactive property source requires a tracked read.");
229
+ return e === void 0 ? { firstSub: null, lastSub: null } : { firstSub: null, lastSub: null, flags: h, sourceHooks: e };
230
+ },
231
+ createTransient: (e) => {
232
+ if (this.activeSub === null)
233
+ throw new Error("[Raph] Reactive property source requires a tracked read.");
234
+ return { firstSub: null, lastSub: null, flags: N, onUnobserved: e };
235
+ },
236
+ isTracking: this._isTracking,
237
+ track: (e) => {
238
+ const t = this.activeSub;
239
+ t !== null && this.trackDependency(e, t);
240
+ },
241
+ trigger: (e) => {
242
+ const t = e.firstSub;
243
+ t !== null && (this.propagateInvalidation(t), !this.batchDepth && this.effectReadIndex !== this.effectWriteIndex && this.flushEffects());
244
+ },
245
+ hasMultipleSubscribers: (e) => {
246
+ const t = e;
247
+ return t.firstSub !== null && t.firstSub !== t.lastSub;
248
+ },
249
+ release: (e) => this.releaseSourceSubs(e)
250
+ };
251
+ }
252
+ /**
253
+ * Материализует signal в графе при первом отслеживаемом чтении
254
+ * и связывает его с активным потребителем.
255
+ *
256
+ * До этого момента signal может хранить значение только в замыкании
257
+ * и вообще не создавать `ReactiveNode`.
258
+ */
259
+ materializeSignal(e, t, i) {
260
+ const s = i === void 0 ? this.allocateGraphRecord(e, void 0, 0, void 0) : {
261
+ flags: h,
262
+ firstSub: null,
263
+ lastSub: null,
264
+ firstDep: null,
265
+ tailDep: null,
266
+ evaluate: void 0,
267
+ cachedValue: e,
268
+ sourceHooks: i
269
+ };
270
+ return t.flags & R ? this.appendInitialDependency(s, t) : this.trackDependency(s, t), s;
271
+ }
272
+ /**
273
+ * Создаёт объектный computed сразу полной записью графа.
274
+ * Поля графа идут в том же порядке, что и в allocateGraphRecord(), и лежат
275
+ * внутри объекта; первое вычисление выполняет общий get() по флагу UNINITIALIZED.
276
+ * get и peek — общие функции графа с receiver (серия Raph Top-1, 2026-10-20).
277
+ */
278
+ createComputedHandle(e, t) {
279
+ const i = {
280
+ flags: t === void 0 ? E : E | h,
281
+ firstSub: null,
282
+ lastSub: null,
283
+ firstDep: null,
284
+ tailDep: null,
285
+ evaluate: e,
286
+ cachedValue: void 0,
287
+ pendingValue: void 0,
288
+ pendingAuthor: void 0,
289
+ subSearchCursor: void 0,
290
+ get: this.handleReaders.read,
291
+ peek: this.handleReaders.peek
292
+ };
293
+ return t !== void 0 && (i.sourceHooks = t), i;
294
+ }
295
+ /**
296
+ * Создаёт эффект с одной постоянной задачей внешнего scheduler.
297
+ * Первый и последующие запуски проходят через задачу; устаревший runner после stop
298
+ * ничего не выполняет. При синхронной ошибке runner обрабатывает независимую очередь.
299
+ * @param fn Тело эффекта.
300
+ * @param onStop Однократная окончательная очистка.
301
+ */
302
+ createScheduledEffect(e, t) {
303
+ const i = this.allocateGraphRecord(void 0, e, f | S | o, void 0);
304
+ let s = !1;
305
+ t !== void 0 && (i.onStop = t);
306
+ const l = this.activeSub;
307
+ l !== null && l.flags & o && A(l, i);
308
+ const r = () => {
309
+ if (!(!(i.flags & d) || i.evaluate === void 0)) {
310
+ i.flags &= ~d, s = !0;
311
+ try {
312
+ this.executeEffect(i);
313
+ } catch (n) {
314
+ if (!this.batchDepth && this.effectReadIndex !== this.effectWriteIndex)
315
+ try {
316
+ this.flushEffects();
317
+ } catch (a) {
318
+ throw new AggregateError(
319
+ [n, a],
320
+ "Effect execution and queue processing failed."
321
+ );
322
+ }
323
+ throw n;
324
+ }
325
+ !this.batchDepth && this.effectReadIndex !== this.effectWriteIndex && this.flushEffects();
326
+ }
327
+ };
328
+ try {
329
+ const n = this.effectScheduler.bind(r);
330
+ n.cancelPending = () => i.evaluate === void 0 || !s ? !1 : (this.settleCancelledDependencies(i), i.flags &= ~(d | b | D), !this.batchDepth && this.effectReadIndex !== this.effectWriteIndex && this.flushEffects(), !0), n.rearmPending = () => {
331
+ i.evaluate !== void 0 && (i.flags |= f | d, n.schedule());
332
+ }, i.effectTask = n, this.requestEffectTask(i);
333
+ } catch (n) {
334
+ try {
335
+ this.disposeEffect(i);
336
+ } catch (a) {
337
+ throw new AggregateError([n, a], "Effect registration and cleanup failed.");
338
+ }
339
+ throw n;
340
+ }
341
+ return !this.batchDepth && this.effectReadIndex !== this.effectWriteIndex && this.flushEffects(), () => this.disposeEffect(i);
342
+ }
343
+ /**
344
+ * Регистрирует чтение signal и при необходимости фиксирует pending-значение.
345
+ * Текущая связь передаётся фиксации, чтобы не уведомлять читающего потребителя повторно.
346
+ */
347
+ readSignalValue(e) {
348
+ const t = this.activeSub;
349
+ let i = null;
350
+ return t !== null && (i = this.trackDependency(e, t)), e.flags & f && this.commitSignalValue(e, i), t !== null && t.flags & k && t.firstDep === i && (t.flags |= x), e.cachedValue;
351
+ }
352
+ /**
353
+ * Записывает новое значение или откладывает его фиксацию до чтения в batch.
354
+ * Сохраняет исходное сравнение через === и учёт автора pending-записи.
355
+ * Без batch и внешней политики очередь эффектов завершается до возврата из set().
356
+ */
357
+ writeSignalValue(e, t) {
358
+ if (e.flags & f || this.batchDepth) {
359
+ const s = !!(e.flags & f);
360
+ if ((e.flags & f ? e.pendingValue : e.cachedValue) === t)
361
+ return;
362
+ if (e.pendingValue = t, e.cachedValue === t)
363
+ e.flags &= ~f, e.pendingAuthor = void 0;
364
+ else {
365
+ e.flags |= f;
366
+ const n = this.activeSub !== null && this.activeSub.flags & p ? this.activeSub : null;
367
+ s ? e.pendingAuthor !== n && (e.pendingAuthor = null) : e.pendingAuthor = n;
368
+ }
369
+ const r = e.firstSub;
370
+ r != null && (!s || this.activeSub !== null && this.activeSub.flags & p || e.flags & h) && this.propagateInvalidation(r, !0);
371
+ return;
372
+ }
373
+ if (e.cachedValue === t)
374
+ return;
375
+ e.cachedValue = t;
376
+ const i = e.firstSub;
377
+ i != null && (this.propagateInvalidation(i), !this.batchDepth && this.effectReadIndex !== this.effectWriteIndex && this.flushEffects());
378
+ }
379
+ /**
380
+ * Возвращает кеш либо синхронно актуализирует вычисляемое значение.
381
+ * Неуспешное вычисление не считается значением. Ошибка getter сохраняет связь
382
+ * с активным потребителем для восстановления. Повторное чтение во время
383
+ * первого сбора зависимостей отклоняется до регистрации связи и чтения кеша.
384
+ */
385
+ readComputedValue(e) {
386
+ const t = e.flags;
387
+ if ((t & (p | R)) === (p | R))
388
+ throw new Error("Computed value is already being evaluated.");
389
+ const i = t & (E | b | y | _), s = i === 0 ? e.cachedValue : i & E ? this.evaluateFirstValue(e) : this.refreshComputedValue(e, t);
390
+ if (e.evaluate === void 0)
391
+ return s;
392
+ const l = this.activeSub;
393
+ if (l !== null) {
394
+ const r = l.tailDep;
395
+ l.flags & R ? (r === null || r.dep !== e) && this.appendInitialDependency(e, l) : this.trackDependency(e, l);
396
+ }
397
+ return s;
398
+ }
399
+ /**
400
+ * Выполняет первый сбор зависимостей и кеширует только успешный результат.
401
+ * При исключении оставляет состояние повторяемой ошибки, а не чистый undefined.
402
+ * Уже прочитанные зависимости сохраняются для последующего уведомления.
403
+ */
404
+ evaluateFirstValue(e) {
405
+ const t = e.flags & h, i = e.evaluate;
406
+ e.flags = t | p | R;
407
+ const s = this.activeSub;
408
+ this.activeSub = e;
409
+ let l;
410
+ try {
411
+ if (l = i(), e.evaluate !== i)
412
+ return e.cachedValue = void 0, e.flags = 0, l;
413
+ const r = e.firstDep !== null && e.firstDep.nextDep === null && (e.flags & (k | x)) === (k | x);
414
+ if (e.flags = t | (r ? _ : e.flags & D ? f : 0), r)
415
+ return e.cachedValue = l, l;
416
+ } catch (r) {
417
+ throw e.evaluate !== i ? (e.cachedValue = void 0, e.flags = 0, r) : (e.flags = t | y, s !== null && this.trackDependency(e, s), r);
418
+ } finally {
419
+ this.activeSub = s;
420
+ }
421
+ return e.flags & f ? this.refreshComputedValue(e, e.flags) : (e.cachedValue = l, l);
422
+ }
423
+ /**
424
+ * Актуализирует computed: выполняет прямой пересчёт либо проверяет зависимости.
425
+ * После ошибки getter разрешён повторный пересчёт даже без новой записи источника.
426
+ */
427
+ refreshComputedValue(e, t, i = null) {
428
+ try {
429
+ if (t & (f | D | y | _))
430
+ return this.recomputeValue(e, i), e.cachedValue;
431
+ const s = e.firstDep;
432
+ return s !== null && this.walkDependencyChain(e, s) ? this.recomputeValue(e, i) : e.flags &= ~b, e.cachedValue;
433
+ } catch (s) {
434
+ throw this.activeSub !== null && this.trackDependency(e, this.activeSub), s;
435
+ }
436
+ }
437
+ /**
438
+ * Фиксирует pending-значение и уведомляет непосредственных потребителей.
439
+ * Пропускает указанную связь и автора записи, чтобы не дублировать текущую работу.
440
+ * @returns Изменилось ли зафиксированное значение.
441
+ */
442
+ commitSignalValue(e, t) {
443
+ const i = e.cachedValue;
444
+ e.cachedValue = e.pendingValue, e.flags &= ~f;
445
+ const s = e.pendingAuthor;
446
+ return e.pendingAuthor = void 0, i === e.cachedValue ? !1 : (e.firstSub !== null && this.confirmSubUpdates(e.firstSub, t, s ?? null), !0);
447
+ }
448
+ /**
449
+ * Обрабатывает чтение производителя активным потребителем.
450
+ * Сначала проверяет текущую и следующую связи; более дорогой поиск вынесен отдельно.
451
+ */
452
+ trackDependency(e, t) {
453
+ const i = t.tailDep;
454
+ if (i !== null) {
455
+ const l = i.nextDep;
456
+ return l !== null && l.dep === e ? (t.tailDep = l, l) : i.dep === e ? i : this.reconcileDependency(e, t, i, l);
457
+ }
458
+ const s = t.firstDep;
459
+ return s === null ? t.tailDep = this.insertDependency(e, t, null) : s.dep === e ? (t.tailDep = s, s) : this.reconcileDependency(e, t, null, s);
460
+ }
461
+ /**
462
+ * Согласует чтение с существующим списком зависимостей при несовпадении порядка.
463
+ * Использует ограниченный линейный поиск, затем поиск среди потребителей производителя.
464
+ * Существующую связь перемещает или переиспользует; новую создаёт только при необходимости.
465
+ */
466
+ reconcileDependency(e, t, i, s) {
467
+ if (t.flags & L) {
468
+ const a = e.subSearchCursor;
469
+ if (a !== void 0 && a.sub === t && a.dep === e)
470
+ return this.reorderDependency(t, a, i), t.tailDep = a, a;
471
+ }
472
+ let l = 0, r = s;
473
+ for (; r !== null && l < U; ) {
474
+ const a = r;
475
+ if (a.dep === e)
476
+ return this.reorderDependency(t, a, i), t.tailDep = a, a;
477
+ r = a.nextDep, ++l;
478
+ }
479
+ let n = i;
480
+ for (; n !== null && l < U; ) {
481
+ const a = n;
482
+ if (a.dep === e)
483
+ return a;
484
+ n = a.prevDep, ++l;
485
+ }
486
+ if (r !== null && !(t.flags & L)) {
487
+ t.flags |= L;
488
+ for (let c = s; c !== null; c = c.nextDep)
489
+ c.dep.subSearchCursor = c;
490
+ const a = e.subSearchCursor;
491
+ if (a !== void 0 && a.sub === t && a.dep === e)
492
+ return this.reorderDependency(t, a, i), t.tailDep = a, a;
493
+ }
494
+ if (r !== null || n !== null) {
495
+ const a = q(e, t);
496
+ if (a !== void 0)
497
+ return this.reorderDependency(t, a, i), t.tailDep = a, a;
498
+ }
499
+ return s !== null ? (t.tailDep = this.reuseDepLink(s, e), s) : t.tailDep = this.insertDependency(e, t, i);
500
+ }
501
+ /**
502
+ * Добавляет связь при первоначальном сборе зависимостей.
503
+ * Предусловие: after является хвостом собранного префикса нового списка.
504
+ * Связь одновременно включается в список потребителей производителя.
505
+ */
506
+ appendInitialDependency(e, t) {
507
+ const i = t.tailDep, s = e.lastSub, l = {
508
+ dep: e,
509
+ sub: t,
510
+ prevSub: s,
511
+ nextSub: null,
512
+ prevDep: i,
513
+ nextDep: null
514
+ };
515
+ return s === null ? e.firstSub = l : s.nextSub = l, e.lastSub = l, i === null ? t.firstDep = l : i.nextDep = l, t.tailDep = l, e.flags & h && this.attachDependencyCleanup(l), l;
516
+ }
517
+ /**
518
+ * Вставляет связь после заданного курсора зависимостей потребителя.
519
+ * Сохраняет ещё не прочитанный хвост списка и увеличивает dependencyCount.
520
+ */
521
+ insertDependency(e, t, i) {
522
+ const s = e.lastSub, l = {
523
+ dep: e,
524
+ sub: t,
525
+ prevSub: s,
526
+ nextSub: null,
527
+ prevDep: i,
528
+ nextDep: null
529
+ };
530
+ s === null ? e.firstSub = l : s.nextSub = l, e.lastSub = l;
531
+ const r = i === null ? t.firstDep : i.nextDep;
532
+ return l.nextDep = r, r !== null && (r.prevDep = l), i === null ? t.firstDep = l : i.nextDep = l, e.flags & h && this.attachDependencyCleanup(l), l;
533
+ }
534
+ /**
535
+ * Переназначает существующую связь другому производителю.
536
+ * Положение в списке зависимостей потребителя и число его связей сохраняются.
537
+ */
538
+ reuseDepLink(e, t) {
539
+ this.detachSubLink(e);
540
+ const i = t.lastSub;
541
+ return e.dep = t, e.prevSub = i, e.nextSub = null, i === null ? t.firstSub = e : i.nextSub = e, t.lastSub = e, t.flags & h && this.attachDependencyCleanup(e), e;
542
+ }
543
+ /**
544
+ * Перемещает существующую зависимость после курсора текущего чтения.
545
+ * Список потребителей производителя и количество зависимостей не изменяет.
546
+ */
547
+ reorderDependency(e, t, i) {
548
+ if (t.prevDep === i)
549
+ return;
550
+ const s = t.prevDep, l = t.nextDep;
551
+ s === null ? e.firstDep = l : s.nextDep = l, l !== null && (l.prevDep = s);
552
+ const r = i === null ? e.firstDep : i.nextDep;
553
+ t.prevDep = i, t.nextDep = r, r !== null && (r.prevDep = t), i === null ? e.firstDep = t : i.nextDep = t;
554
+ }
555
+ /**
556
+ * Удаляет непрочитанный хвост зависимостей завершившегося запуска.
557
+ * trackedTail обозначает границу прочитанного префикса, а не неизменный конец списка.
558
+ * Ошибка cleanup не прерывает освобождение оставшегося хвоста зависимостей.
559
+ */
560
+ pruneUnreadDependencies(e) {
561
+ const t = e.tailDep;
562
+ let i = t === null ? e.firstDep : t.nextDep;
563
+ if (i === null)
564
+ return;
565
+ t === null ? e.firstDep = null : t.nextDep = null;
566
+ for (let l = i; l !== null; l = l.nextDep)
567
+ l.prevDep = null;
568
+ let s;
569
+ for (; i !== null; ) {
570
+ const l = i.nextDep;
571
+ try {
572
+ this.detachSubLink(i, !0);
573
+ } catch (r) {
574
+ this.unlinkSubLink(i, !0), s ??= [], s.push(r);
575
+ }
576
+ i = l;
577
+ }
578
+ s !== void 0 && m(s, "Dependency cleanup failed.");
579
+ }
580
+ /**
581
+ * Удаляет связь только из списка потребителей производителя.
582
+ * Список зависимостей потребителя и его счётчик здесь не изменяются.
583
+ * Также исправляет курсор поиска, если он указывал на удаляемую связь.
584
+ */
585
+ detachSubLink(e, t = !1) {
586
+ let i;
587
+ e.dep.flags & (h | N) && (i = this.cleanupSourceDependency(e)), this.unlinkSubLink(e, t || i !== void 0);
588
+ }
589
+ /** Optional source cleanup stays outside the ordinary signal detach path. */
590
+ cleanupSourceDependency(e) {
591
+ const t = e.dep;
592
+ if (t.flags & h) {
593
+ const i = e.dependencyCleanup;
594
+ return e.dependencyCleanup = void 0, i?.(), i;
595
+ }
596
+ t.firstSub === e && t.lastSub === e && t.onUnobserved();
597
+ }
598
+ /** Завершает удаление producer-связи без вызова source cleanup. */
599
+ unlinkSubLink(e, t) {
600
+ t && ((e.prevSub === null ? e.dep.firstSub !== e : e.prevSub.nextSub !== e) || (e.nextSub === null ? e.dep.lastSub !== e : e.nextSub.prevSub !== e)) || (e.dep.subSearchCursor === e && (e.dep.subSearchCursor = e.nextSub ?? (e.dep.firstSub === e ? void 0 : e.dep.firstSub ?? void 0)), e.prevSub === null ? e.dep.firstSub = e.nextSub : e.prevSub.nextSub = e.nextSub, e.nextSub === null ? e.dep.lastSub = e.prevSub : e.nextSub.prevSub = e.prevSub);
601
+ }
602
+ /** Connects Runtime ownership metadata only for edges whose producer opted in. */
603
+ attachDependencyCleanup(e) {
604
+ const i = e.dep.sourceHooks?.onDependency;
605
+ if (i === void 0)
606
+ return;
607
+ const s = e.sub.sourceHooks?.dependencyOwner ?? e.sub.effectTask?.dependencyOwner;
608
+ s !== void 0 && (e.dependencyCleanup = i(s));
609
+ }
610
+ /**
611
+ * Отсоединяет owned-источник сразу с обеих сторон каждой связи.
612
+ * Вызывается на границе lifetime, а не при обычных чтениях и записях.
613
+ * Переводит ожидавших проверку потребителей к повторному вычислению при необходимости.
614
+ */
615
+ releaseSourceSubs(e) {
616
+ if (!(e.flags & (h | N))) {
617
+ let s = e.firstSub;
618
+ for (; s != null; ) {
619
+ const l = s.nextSub, r = s.sub;
620
+ this.detachDependencyLink(s), this.detachSubLink(s);
621
+ const n = r.flags;
622
+ (n & (b | p)) === S && (r.flags = n & ~S | f, n & o && this.enqueueEffect(r, e)), s = l;
623
+ }
624
+ e.firstSub = e.lastSub = null, e.subSearchCursor = void 0;
625
+ return;
626
+ }
627
+ let t = e.firstSub, i;
628
+ for (; t != null; ) {
629
+ const s = t.nextSub;
630
+ this.detachDependencyLink(t);
631
+ try {
632
+ this.detachSubLink(t, !0);
633
+ } catch (l) {
634
+ this.unlinkSubLink(t, !0), i ??= [], i.push(l);
635
+ }
636
+ t = s;
637
+ }
638
+ e.firstSub = e.lastSub = null, e.subSearchCursor = void 0, i !== void 0 && m(i, "Source dependency cleanup failed.");
639
+ }
640
+ /**
641
+ * Удаляет связь только из списка зависимостей потребителя.
642
+ * Исправляет курсор прочитанного префикса и dependencyCount; список производителя
643
+ * должен быть обновлён отдельной операцией.
644
+ */
645
+ detachDependencyLink(e) {
646
+ const t = e.sub, i = e.prevDep, s = e.nextDep;
647
+ (i === null ? t.firstDep !== e : i.nextDep !== e) || (i === null ? t.firstDep = s : i.nextDep = s, s !== null && (s.prevDep = i), t.tailDep === e && (t.tailDep = i));
648
+ }
649
+ /**
650
+ * Добавляет эффект во внутреннюю очередь один раз до обработки текущей записи.
651
+ * Флаг SCHEDULED предотвращает повторное добавление без создания task-объекта.
652
+ */
653
+ enqueueEffect(e, t) {
654
+ const i = t !== void 0 && t.flags & h ? t.sourceHooks.token : void 0;
655
+ i !== void 0 && e.effectTask?.notify?.(i), !(e.flags & d) && (e.flags |= d, this.effectWriteIndex === 0 ? this.firstEffect = e : this.effectQueue[this.effectWriteIndex] = e, ++this.effectWriteIndex);
656
+ }
657
+ /**
658
+ * Распространяет invalidation от непосредственных к транзитивным потребителям.
659
+ * Сохраняет исходный итеративный обход с переиспользуемым стеком; callbacks
660
+ * не выполняет. Непосредственное и потенциальное изменения отмечает разными флагами.
661
+ */
662
+ propagateInvalidation(e, t = !1) {
663
+ this.checkingDepth !== 0 && this.markActiveChecks(e);
664
+ const i = this.invalidationDepth;
665
+ let s = i;
666
+ for (let l = e; l !== null; l = l.nextSub) {
667
+ const r = l.sub, n = r.flags;
668
+ let a = 0;
669
+ if (n & (b | p) ? n & p ? a = this.invalidateReadDependency(l, r, n) : !t && !(n & f) && (r.flags = n & ~S | f) : (a = n & ~D | (t ? S : f), r.flags = a), a === 0) {
670
+ if (n & o && n & d) {
671
+ const c = l.dep.flags & h ? l.dep.sourceHooks.token : void 0;
672
+ c !== void 0 && r.effectTask?.notify?.(c);
673
+ } else r.flags & (h | C) && (r.flags & h && r.sourceHooks.onInvalidate?.(r.firstSub !== null), r.flags &= ~C, r.firstSub !== null && (this.invalidationStack[s++] = r.firstSub));
674
+ continue;
675
+ }
676
+ a & o ? (!(a & p) || r.effectTask?.allowScheduleDuringRun === !0) && this.enqueueEffect(r, l.dep) : (!(n & b) && r.flags & h && r.sourceHooks.onInvalidate?.(r.firstSub !== null), r.firstSub !== null && (this.invalidationStack[s++] = r.firstSub));
677
+ }
678
+ for (; s !== i; ) {
679
+ let l = this.invalidationStack[--s];
680
+ do {
681
+ const r = l.sub, n = r.flags;
682
+ let a = 0;
683
+ if (n & (b | p) ? n & p && (a = this.invalidateReadDependency(l, r, n)) : (a = n & ~D | S, r.flags = a), a === 0) {
684
+ if (n & o && n & d) {
685
+ const c = l.dep.flags & h ? l.dep.sourceHooks.token : void 0;
686
+ c !== void 0 && r.effectTask?.notify?.(c);
687
+ } else if (r.flags & (h | C) && (r.flags & h && r.sourceHooks.onInvalidate?.(r.firstSub !== null), r.flags &= ~C, r.firstSub !== null)) {
688
+ l.nextSub !== null && (this.invalidationStack[s++] = l.nextSub), l = r.firstSub;
689
+ continue;
690
+ }
691
+ } else if (a & o)
692
+ this.enqueueEffect(r, l.dep);
693
+ else if (!(n & b) && r.flags & h && r.sourceHooks.onInvalidate?.(r.firstSub !== null), r.firstSub !== null) {
694
+ l.nextSub !== null && (this.invalidationStack[s++] = l.nextSub), l = r.firstSub;
695
+ continue;
696
+ }
697
+ l = l.nextSub;
698
+ } while (l !== null);
699
+ }
700
+ this.invalidationDepth = i;
701
+ }
702
+ // Дополнительный обход не вызывает callbacks и проходит уже dirty computed:
703
+ // флаги обычной invalidation не показывают, какую связь check уже прошёл.
704
+ // Запись во время проверки редка, поэтому множество проверяемых узлов строится
705
+ // только здесь: корни проверок и обе стороны каждой связи опубликованного
706
+ // префикса dependencyStack. Пользовательский код выполняется внутри проверки
707
+ // только после публикации dependencyDepth, поэтому префикс актуален.
708
+ markActiveChecks(e) {
709
+ const t = /* @__PURE__ */ new Set();
710
+ for (let l = 0; l < this.checkingDepth; l++)
711
+ t.add(this.checkRoots[l]);
712
+ for (let l = 0; l < this.dependencyDepth; l++) {
713
+ const r = this.dependencyStack[l];
714
+ t.add(r.sub), t.add(r.dep);
715
+ }
716
+ const i = [e], s = /* @__PURE__ */ new Set();
717
+ for (; i.length !== 0; )
718
+ for (let l = i.pop(); l !== null; l = l.nextSub) {
719
+ const r = l.sub;
720
+ s.has(r) || (s.add(r), t.has(r) && (r.flags |= g), !(r.flags & o) && r.firstSub !== null && i.push(r.firstSub));
721
+ }
722
+ }
723
+ /**
724
+ * Помечает работающего потребителя, только если затронута уже прочитанная связь.
725
+ * Связи за trackedTail принадлежат прошлому запуску и не означают повторную invalidation.
726
+ * @returns Новое состояние либо ноль, если уведомление не требуется.
727
+ */
728
+ invalidateReadDependency(e, t, i) {
729
+ const s = t.tailDep;
730
+ if (s === null)
731
+ return 0;
732
+ if (e !== s) {
733
+ for (let r = e.prevDep; r !== null; r = r.prevDep)
734
+ if (r === s)
735
+ return 0;
736
+ }
737
+ let l = i | D | S;
738
+ return t === this.activeSub && !(i & o) && t.firstDep === e && e.nextDep === null ? l = (l | k) & ~x : l &= -49153, t.flags = l, l;
739
+ }
740
+ /**
741
+ * Подтверждает необходимость пересчёта непосредственных потребителей.
742
+ * Применяется после фиксации реально изменившегося значения; позволяет исключить
743
+ * текущую связь и автора записи.
744
+ */
745
+ confirmSubUpdates(e, t, i = null) {
746
+ for (let s = e; s !== null; s = s.nextSub) {
747
+ if (s === t || s.sub === i)
748
+ continue;
749
+ const l = s.sub, r = l.flags;
750
+ r & f || (l.flags = r & ~S | f, r & o ? this.enqueueEffect(l, s.dep) : r & b || l.flags & h && l.sourceHooks.onInvalidate?.(l.firstSub !== null));
751
+ }
752
+ }
753
+ /**
754
+ * Повторно вычисляет узел, согласует зависимости и сравнивает результат с кешем.
755
+ * При ошибке восстанавливает контекст, удаляет непрочитанный хвост и оставляет
756
+ * повторяемое состояние ошибки. Также восстанавливает непосредственного потребителя
757
+ * skipSub: при разворачивании стека его связь могла быть уже извлечена из буфера.
758
+ * Неверное значение в кеш не записывается.
759
+ */
760
+ recomputeValue(e, t = null) {
761
+ const i = e.cachedValue, s = e.evaluate;
762
+ e.tailDep = null;
763
+ const l = e.flags & -119813 | p;
764
+ e.flags = l;
765
+ const r = this.activeSub;
766
+ this.activeSub = e;
767
+ let n;
768
+ try {
769
+ n = s();
770
+ } catch (c) {
771
+ this.failComputedRun(e, s, t, c, r);
772
+ }
773
+ this.activeSub = r;
774
+ const a = e.tailDep;
775
+ return e.evaluate !== s || (a === null ? e.firstDep : a.nextDep) !== null || e.flags & (D | k | x) ? this.settleComputedValue(e, t, i, s, l, n) : (e.flags = l & -8460, e.cachedValue = n, i === n ? !1 : (e.firstSub !== null && this.confirmSubUpdates(e.firstSub, t), !0));
776
+ }
777
+ /**
778
+ * Медленный путь пересчёта: удаление непрочитанного хвоста, освобождение owner
779
+ * во время getter или cleanup, повторная invalidation и самозапись единственной
780
+ * зависимости. Первое вычисление уже выполнено recomputeValue(); повторные
781
+ * выполняются здесь до предела MAX_NODE_REPEATS вычислений.
782
+ */
783
+ settleComputedValue(e, t, i, s, l, r) {
784
+ for (let n = 1; ; n++) {
785
+ if (e.evaluate !== s)
786
+ return e.cachedValue = void 0, e.flags = 0, !1;
787
+ const a = e.tailDep;
788
+ if ((a === null ? e.firstDep : a.nextDep) !== null)
789
+ try {
790
+ this.pruneUnreadDependencies(e);
791
+ } catch (u) {
792
+ this.failComputedValue(e, t, u);
793
+ }
794
+ if (e.evaluate !== s)
795
+ return e.cachedValue = void 0, e.flags = 0, !1;
796
+ const c = e.flags & D, I = e.firstDep !== null && e.firstDep.nextDep === null && (e.flags & (k | x)) === (k | x);
797
+ if (e.flags = l & -8460, c && !I) {
798
+ if (e.flags |= f, n === T)
799
+ return this.failComputedValue(e, t, new Error(`Computed settlement exceeded ${T} attempts.`));
800
+ s = e.evaluate, e.tailDep = null, l = e.flags & -119813 | p, e.flags = l;
801
+ const u = this.activeSub;
802
+ this.activeSub = e;
803
+ try {
804
+ r = s();
805
+ } catch (v) {
806
+ this.failComputedRun(e, s, t, v, u);
807
+ }
808
+ this.activeSub = u;
809
+ continue;
810
+ }
811
+ return I && (e.flags |= _), e.cachedValue = r, i === r ? !1 : (e.firstSub !== null && this.confirmSubUpdates(e.firstSub, t), !0);
812
+ }
813
+ }
814
+ /**
815
+ * Обрабатывает исключение getter до восстановления активного потребителя,
816
+ * как прежний catch внутри try/finally, и всегда восстанавливает контекст.
817
+ */
818
+ failComputedRun(e, t, i, s, l) {
819
+ try {
820
+ if (e.evaluate !== t)
821
+ throw e.cachedValue = void 0, e.flags = 0, s;
822
+ this.failComputedValue(e, i, s);
823
+ } finally {
824
+ this.activeSub = l;
825
+ }
826
+ }
827
+ /** Сохраняет первичную ошибку и отдельные ошибки cleanup при восстановлении. */
828
+ failComputedValue(e, t, i) {
829
+ try {
830
+ this.restoreComputedFailure(e, t);
831
+ } catch (s) {
832
+ throw new AggregateError([i, s], "Computed evaluation and dependency cleanup failed.");
833
+ }
834
+ throw i;
835
+ }
836
+ /**
837
+ * Восстанавливает связи и состояния после неудачного getter.
838
+ * Отдельная функция удерживает обработку исключений вне обычной части пересчёта.
839
+ * Потребитель исключаемой связи мог уже покинуть активный префикс стека.
840
+ */
841
+ restoreComputedFailure(e, t) {
842
+ e.evaluate !== void 0 && (e.flags = e.flags & -118928 | y);
843
+ try {
844
+ e.evaluate !== void 0 && this.pruneUnreadDependencies(e);
845
+ } finally {
846
+ e.evaluate === void 0 && (e.cachedValue = void 0, e.flags = 0), t !== null && this.restoreFailedDependency(t.sub);
847
+ }
848
+ }
849
+ /** Settles every direct dependency so a cancelled external delivery can be re-armed. */
850
+ settleCancelledDependencies(e) {
851
+ for (let t = e.firstDep; t !== null; t = t.nextDep) {
852
+ const i = t.dep, s = i.flags;
853
+ s & (E | b | y) && (i.evaluate === void 0 ? s & f && this.commitSignalValue(i, t) : this.refreshComputedValue(i, s, t));
854
+ }
855
+ }
856
+ /**
857
+ * Итеративно проверяет зависимые computed и pending-сигналы перед запуском потребителя.
858
+ * Использует общий стек с сохранением активного префикса вложенного обхода и
859
+ * перед пользовательским вычислением публикует его высоту. Единственный
860
+ * обработчик ошибок проверки находится здесь: при исключении он восстанавливает
861
+ * высоту стека, состояния всех незавершённых узлов прохода и корень проверки,
862
+ * включая снятие SCHEDULED у эффекта. Порядок успешного обхода не меняется
863
+ * (серия Raph Top-1, 2026-10-20: прежние три вложенных обработчика объединены).
864
+ */
865
+ walkDependencyChain(e, t) {
866
+ const i = e, s = this.dependencyDepth;
867
+ let l = s, r = !1, n;
868
+ e.flags & g && (e.flags &= ~g), this.checkRoots[this.checkingDepth++] = e;
869
+ try {
870
+ e: for (; ; ) {
871
+ if (e.flags & g) {
872
+ n ??= /* @__PURE__ */ new Map();
873
+ const a = (n.get(e) ?? 0) + 1;
874
+ if (n.set(e, a), a > T)
875
+ throw new Error(`Dependency check exceeded ${T} restarts.`);
876
+ e.flags &= ~g, e.firstDep !== null && (t = e.firstDep);
877
+ }
878
+ if (e.flags & f)
879
+ r = !0;
880
+ else {
881
+ const a = t.dep, c = a.flags;
882
+ if (c & (f | y))
883
+ this.dependencyDepth = l, r = a.evaluate === void 0 ? this.commitSignalValue(a, t) : this.recomputeValue(a, t);
884
+ else if (c & S) {
885
+ if (a.firstDep !== null) {
886
+ this.dependencyStack[l++] = t, e = a, t = a.firstDep;
887
+ continue e;
888
+ }
889
+ this.dependencyDepth = l, r = this.recomputeValue(a, t);
890
+ } else
891
+ r = !1;
892
+ }
893
+ if (!r && t.nextDep !== null) {
894
+ t = t.nextDep;
895
+ continue;
896
+ }
897
+ if (r) {
898
+ for (; l !== s; ) {
899
+ this.dependencyDepth = --l;
900
+ const a = this.dependencyStack[l];
901
+ if (r = this.recomputeValue(e, a), e = a.sub, !r) {
902
+ if (a.nextDep !== null) {
903
+ t = a.nextDep;
904
+ continue e;
905
+ }
906
+ break;
907
+ }
908
+ }
909
+ if (r)
910
+ return this.dependencyDepth = s, e.flags & g && (e.flags &= ~g), this.checkRoots[--this.checkingDepth] = null, !0;
911
+ }
912
+ for (; l !== s; ) {
913
+ if (e.flags & (f | g))
914
+ continue e;
915
+ this.dependencyDepth = --l;
916
+ const a = this.dependencyStack[l];
917
+ if (e.flags &= ~(S | W), e = a.sub, a.nextDep !== null) {
918
+ t = a.nextDep;
919
+ continue e;
920
+ }
921
+ }
922
+ if (e.flags & (f | g))
923
+ continue e;
924
+ return e.flags &= ~(S | W), this.dependencyDepth = s, this.checkRoots[--this.checkingDepth] = null, !1;
925
+ }
926
+ } catch (a) {
927
+ e.flags & g && (e.flags &= ~g);
928
+ for (let c = s; c < l; c++)
929
+ this.dependencyStack[c].sub.flags &= ~W;
930
+ this.checkRoots[--this.checkingDepth] = null, this.markRecoveryDependencies(i), this.restoreFailedDependency(i);
931
+ for (let c = s; c < this.dependencyDepth; c++)
932
+ this.restoreFailedDependency(this.dependencyStack[c].sub);
933
+ throw this.dependencyDepth = s, this.dependencyStack.length = s, i.flags & o && (i.flags &= ~d), a;
934
+ }
935
+ }
936
+ /**
937
+ * Восстанавливает незавершённую запись после прерванной проверки зависимостей.
938
+ * Computed получает повторяемое состояние ошибки, effect остаётся доступным
939
+ * для следующей invalidation. Вызывается только на ошибочном пути.
940
+ */
941
+ restoreFailedDependency(e) {
942
+ if (e.evaluate === void 0) {
943
+ e.cachedValue = void 0, e.flags = 0;
944
+ return;
945
+ }
946
+ e.flags &= -118800, e.flags & o || (e.flags |= y);
947
+ }
948
+ /**
949
+ * Проверяет необходимость запуска, очищает прошлые ресурсы и выполняет тело эффекта.
950
+ * Ошибка cleanup останавливает эффект до создания ресурсов следующего запуска.
951
+ * При ошибке тела сохраняет фактически прочитанные зависимости, останавливает
952
+ * созданных детей и разрешает повторный запуск после следующей записи.
953
+ * Cleanup, возвращённый после собственного stop, освобождается сразу.
954
+ */
955
+ executeEffect(e) {
956
+ const t = e.flags;
957
+ if (!(t & b) || !(t & (f | D)) && !this.refreshEffectBeforeRun(e))
958
+ return;
959
+ const i = e.evaluate;
960
+ if (i === void 0) {
961
+ e.flags &= ~b;
962
+ return;
963
+ }
964
+ if ((e.scopeLastChild !== void 0 || typeof e.cachedValue == "function") && this.cleanupEffectBeforeRun(e), e.evaluate === void 0)
965
+ return;
966
+ e.tailDep = null, e.flags = e.flags & -1029 | p;
967
+ const s = this.activeSub;
968
+ this.activeSub = e;
969
+ let l;
970
+ try {
971
+ l = i();
972
+ } catch (n) {
973
+ this.activeSub = s, e.flags &= ~p, this.failEffectRun(e, n, void 0);
974
+ } finally {
975
+ this.activeSub = s, e.flags &= ~p;
976
+ }
977
+ const r = e.tailDep;
978
+ (r === null ? e.firstDep : r.nextDep) !== null && this.pruneUnreadDependencies(e), typeof l == "function" && (e.evaluate === void 0 ? this.untracked(l) : e.cachedValue = l), e.flags & d ? e.flags = e.flags & -1031 | S : e.flags &= -1032;
979
+ }
980
+ /**
981
+ * Проверяет pending computed только при отсутствии прямой invalidation.
982
+ * Восстановление эффекта после ошибки проверки выполняет walkDependencyChain().
983
+ */
984
+ refreshEffectBeforeRun(e) {
985
+ const t = e.firstDep;
986
+ return t === null || !this.walkDependencyChain(e, t) ? (e.flags &= ~b, !1) : !0;
987
+ }
988
+ /** Освобождает ресурсы предыдущего запуска; обычный effect без cleanup сюда не входит. */
989
+ cleanupEffectBeforeRun(e) {
990
+ let t;
991
+ if (e.scopeLastChild !== void 0)
992
+ try {
993
+ this.disposeNestedEffects(e);
994
+ } catch (s) {
995
+ t = [s];
996
+ }
997
+ const i = typeof e.cachedValue == "function" ? e.cachedValue : void 0;
998
+ if (e.cachedValue = void 0, e.flags &= ~D, i !== void 0)
999
+ try {
1000
+ this.untracked(i);
1001
+ } catch (s) {
1002
+ t ??= [], t.push(s);
1003
+ }
1004
+ if (t !== void 0) {
1005
+ try {
1006
+ this.disposeEffect(e);
1007
+ } catch (s) {
1008
+ t.push(s);
1009
+ }
1010
+ m(t, "Effect cleanup failed.");
1011
+ }
1012
+ }
1013
+ /**
1014
+ * Завершает неудачный запуск эффекта, не затрагивая успешный путь исполнения.
1015
+ * Сохраняет прочитанные зависимости для следующей invalidation, освобождает
1016
+ * детей неудачного запуска и объединяет ошибки с предыдущими ошибками cleanup.
1017
+ */
1018
+ failEffectRun(e, t, i) {
1019
+ const s = i ?? [];
1020
+ s.push(t), this.pruneUnreadDependencies(e);
1021
+ try {
1022
+ this.disposeNestedEffects(e);
1023
+ } catch (l) {
1024
+ s.push(l);
1025
+ }
1026
+ throw e.flags &= -72, s.length === 1 ? s[0] : new AggregateError(s, "Effect execution failed.");
1027
+ }
1028
+ /**
1029
+ * Обрабатывает синхронную очередь до исчерпания, включая добавленную во время прохода работу.
1030
+ * Ошибки отдельных эффектов не блокируют соседей и передаются после обработки.
1031
+ * Путь не проверяет наличие внешней задачи у каждого узла.
1032
+ */
1033
+ flushSyncEffects() {
1034
+ if (!(this.flushingEffects || this.activeSub !== null && (this.activeSub.flags & (o | p)) === (o | p))) {
1035
+ this.flushingEffects = !0;
1036
+ try {
1037
+ for (; this.effectReadIndex !== this.effectWriteIndex; ) {
1038
+ const e = this.effectReadIndex, t = e === 0 ? this.firstEffect : this.effectQueue[e];
1039
+ e === 0 ? this.firstEffect = void 0 : this.effectQueue[e] = void 0, ++this.effectReadIndex, t.flags &= ~d, this.executeEffect(t);
1040
+ }
1041
+ } catch (e) {
1042
+ this.drainQueueAfterError(e, !1);
1043
+ } finally {
1044
+ this.effectReadIndex = 0, this.effectWriteIndex = 0, this.flushingEffects = !1;
1045
+ }
1046
+ }
1047
+ }
1048
+ /**
1049
+ * Обрабатывает очередь экземпляра с внешней политикой выполнения.
1050
+ * Обычные внутренние эффекты выполняет сразу, остальные передаёт постоянной задаче.
1051
+ * Ошибка одного элемента не оставляет необработанные записи со старым SCHEDULED.
1052
+ */
1053
+ flushExternalEffects() {
1054
+ if (!(this.flushingEffects || this.activeSub !== null && (this.activeSub.flags & (o | p)) === (o | p))) {
1055
+ this.flushingEffects = !0;
1056
+ try {
1057
+ for (; this.effectReadIndex !== this.effectWriteIndex; ) {
1058
+ const e = this.effectReadIndex, t = e === 0 ? this.firstEffect : this.effectQueue[e];
1059
+ e === 0 ? this.firstEffect = void 0 : this.effectQueue[e] = void 0, ++this.effectReadIndex;
1060
+ const i = t.effectTask;
1061
+ i === void 0 ? (t.flags &= ~d, this.executeEffect(t)) : t.evaluate !== void 0 ? this.scheduleEffectTask(t, i) : t.flags &= ~d;
1062
+ }
1063
+ } catch (e) {
1064
+ this.drainQueueAfterError(e, !0);
1065
+ } finally {
1066
+ this.effectReadIndex = 0, this.effectWriteIndex = 0, this.flushingEffects = !1;
1067
+ }
1068
+ }
1069
+ }
1070
+ // Только ошибочный путь; новые fields/ссылки в graph records не добавляются.
1071
+ markRecoveryDependencies(e) {
1072
+ const t = [e], i = /* @__PURE__ */ new Set();
1073
+ for (; t.length !== 0; ) {
1074
+ const s = t.pop();
1075
+ if (!i.has(s)) {
1076
+ i.add(s);
1077
+ for (let l = s.firstDep; l !== null; l = l.nextDep) {
1078
+ const r = l.dep;
1079
+ r.evaluate !== void 0 && !(r.flags & o) && (r.flags |= C, t.push(r));
1080
+ }
1081
+ }
1082
+ }
1083
+ }
1084
+ /**
1085
+ * Завершает очередь после первой ошибки, собирая последующие причины сбоя.
1086
+ * Вызывается только на ошибочном пути; успешный проход не создаёт массив ошибок
1087
+ * и не устанавливает отдельный catch для каждого элемента.
1088
+ */
1089
+ drainQueueAfterError(e, t) {
1090
+ const i = [e];
1091
+ for (; this.effectReadIndex !== this.effectWriteIndex; ) {
1092
+ const s = this.effectReadIndex++, l = s === 0 ? this.firstEffect : this.effectQueue[s];
1093
+ s === 0 ? this.firstEffect = void 0 : this.effectQueue[s] = void 0;
1094
+ try {
1095
+ const r = t ? l.effectTask : void 0;
1096
+ r !== void 0 && l.evaluate !== void 0 ? this.scheduleEffectTask(l, r) : (l.flags &= ~d, this.executeEffect(l));
1097
+ } catch (r) {
1098
+ i.push(r);
1099
+ }
1100
+ }
1101
+ throw i.length === 1 ? e : new AggregateError(i, "Effect queue processing failed.");
1102
+ }
1103
+ /**
1104
+ * Передаёт эффект его постоянной внешней задаче.
1105
+ * Если schedule() бросает исключение, снимает незавершённую invalidation,
1106
+ * чтобы последующая запись могла снова запросить выполнение.
1107
+ */
1108
+ requestEffectTask(e) {
1109
+ const t = e.effectTask;
1110
+ t === void 0 || e.evaluate === void 0 || (e.flags |= d, this.scheduleEffectTask(e, t));
1111
+ }
1112
+ // Передаёт уже запланированный эффект его постоянной внешней задаче.
1113
+ scheduleEffectTask(e, t) {
1114
+ try {
1115
+ t.schedule();
1116
+ } catch (i) {
1117
+ this.failEffectSchedule(e, i);
1118
+ }
1119
+ }
1120
+ /** Восстанавливает источники после сбоя scheduler, сохраняя исходную ошибку. */
1121
+ failEffectSchedule(e, t) {
1122
+ try {
1123
+ e.flags & d && this.settleCancelledDependencies(e);
1124
+ } catch (i) {
1125
+ throw new AggregateError([t, i], "Effect scheduling and dependency settlement failed.");
1126
+ } finally {
1127
+ e.flags &= -72;
1128
+ }
1129
+ throw t;
1130
+ }
1131
+ /**
1132
+ * Окончательно останавливает эффект и освобождает все принадлежащие ему ресурсы.
1133
+ * Сначала делает узел неактивным и отсоединяет связи, затем отменяет задачу,
1134
+ * останавливает детей, выполняет cleanup и onStop. Каждая стадия завершается
1135
+ * несмотря на ошибки соседних стадий; повторный или вложенный stop безопасен.
1136
+ */
1137
+ disposeEffect(e) {
1138
+ if (e.evaluate === void 0)
1139
+ return;
1140
+ this.activeSub === e && (this.activeSub = null);
1141
+ const t = e.effectTask, i = e.onStop, s = typeof e.cachedValue == "function" ? e.cachedValue : void 0;
1142
+ e.evaluate = void 0, e.flags = 0, e.cachedValue = void 0, e.effectTask = void 0, i !== void 0 && (e.onStop = void 0), H(e);
1143
+ let l;
1144
+ e.tailDep = null;
1145
+ try {
1146
+ this.pruneUnreadDependencies(e);
1147
+ } catch (r) {
1148
+ l = [r];
1149
+ }
1150
+ if (e.firstDep = e.tailDep = null, t !== void 0)
1151
+ try {
1152
+ t.dispose();
1153
+ } catch (r) {
1154
+ l ??= [], l.push(r);
1155
+ }
1156
+ try {
1157
+ this.disposeNestedEffects(e);
1158
+ } catch (r) {
1159
+ l ??= [], l.push(r);
1160
+ }
1161
+ if (s !== void 0)
1162
+ try {
1163
+ this.untracked(s);
1164
+ } catch (r) {
1165
+ l ??= [], l.push(r);
1166
+ }
1167
+ if (i !== void 0)
1168
+ try {
1169
+ this.untracked(i);
1170
+ } catch (r) {
1171
+ l ??= [], l.push(r);
1172
+ }
1173
+ this.invalidationStack.length !== this.invalidationDepth && (this.invalidationStack.length = this.invalidationDepth), this.dependencyStack.length !== this.dependencyDepth && (this.dependencyStack.length = this.dependencyDepth), l !== void 0 && m(l, "Effect disposal failed.");
1174
+ }
1175
+ /**
1176
+ * Останавливает все вложенные эффекты в обратном порядке регистрации.
1177
+ * Всегда берёт актуальный хвост: cleanup может удалить другого ребёнка.
1178
+ * Передаёт собранные ошибки только после освобождения всех детей.
1179
+ */
1180
+ disposeNestedEffects(e) {
1181
+ let t;
1182
+ for (; e.scopeLastChild !== void 0; )
1183
+ try {
1184
+ this.disposeEffect(e.scopeLastChild);
1185
+ } catch (i) {
1186
+ t ??= [], t.push(i);
1187
+ }
1188
+ t !== void 0 && m(t, "Nested effect disposal failed.");
1189
+ }
1190
+ /**
1191
+ * Связывает два разных receiver: движок-владелец и читаемый handle.
1192
+ * Общие функции адаптируют this; алгоритмы чтения остаются методами
1193
+ * ReactivityEngine. Адаптеры создаются один раз на граф, а не на каждое вычисление.
1194
+ */
1195
+ createHandleReaders() {
1196
+ const e = this;
1197
+ return {
1198
+ /**
1199
+ * Общий reader computed: get() объектного и read() raw handle.
1200
+ * Handle сам является записью графа, поэтому reader требует receiver;
1201
+ * извлечённый без receiver метод не поддерживается (серия Raph Top-1, 2026-10-20).
1202
+ */
1203
+ read() {
1204
+ return e.readComputedValue(this);
1205
+ },
1206
+ /**
1207
+ * Передаёт handle как аргумент; this самого движка берётся из замыкания.
1208
+ */
1209
+ peek() {
1210
+ return e.peekHandle(this);
1211
+ }
1212
+ };
1213
+ }
1214
+ /**
1215
+ * Читает handle без подписки текущего потребителя, сохраняя receiver get().
1216
+ * Прежний контекст восстанавливается и после исключения getter.
1217
+ */
1218
+ peekHandle(e) {
1219
+ const t = this.activeSub;
1220
+ if (t === null)
1221
+ return e.get();
1222
+ this.activeSub = null;
1223
+ try {
1224
+ return e.get();
1225
+ } finally {
1226
+ this.activeSub = t;
1227
+ }
1228
+ }
1229
+ // ---------------------------------------------
1230
+ // INTERNAL
1231
+ // ---------------------------------------------
1232
+ /**
1233
+ * Создаёт единый низкоуровневый read/write accessor для core-дорожки Bench Lab.
1234
+ * Публичный объектный API остаётся отдельным и измеряется в API-tax.
1235
+ * @internal
1236
+ */
1237
+ _signalAccess(e) {
1238
+ const t = this;
1239
+ let i = e, s;
1240
+ function l(r) {
1241
+ if (arguments.length !== 0) {
1242
+ const c = s;
1243
+ c !== void 0 ? t.writeSignalValue(c, r) : i !== r && (i = r);
1244
+ return;
1245
+ }
1246
+ const n = s;
1247
+ if (n !== void 0)
1248
+ return t.readSignalValue(n);
1249
+ const a = t.activeSub;
1250
+ return a === null || (s = t.materializeSignal(i, a)), i;
1251
+ }
1252
+ return {
1253
+ read: l,
1254
+ write: l
1255
+ };
1256
+ }
1257
+ /**
1258
+ * Создаёт computed для низкоуровневого read API сразу записью графа единой формы.
1259
+ * read — общий reader графа с receiver; первое чтение вычисляет значение по
1260
+ * флагу UNINITIALIZED (серия Raph Top-1, 2026-10-20).
1261
+ * @internal
1262
+ */
1263
+ _computedAccess(e) {
1264
+ return this.allocateGraphRecord(
1265
+ void 0,
1266
+ e,
1267
+ E,
1268
+ this.handleReaders.read
1269
+ );
1270
+ }
1271
+ /**
1272
+ * Создаёт signal, жизненным циклом которого управляет `ScopeNode`.
1273
+ *
1274
+ * Реактивная логика совпадает с обычным `signal()`, но disposer
1275
+ * дополнительно отсоединяет материализованный источник от графа.
1276
+ *
1277
+ * @internal
1278
+ */
1279
+ _ownedSignal(e, t) {
1280
+ const i = this;
1281
+ let s = e, l, r = !1;
1282
+ const n = () => {
1283
+ const u = l;
1284
+ if (u !== void 0)
1285
+ return this.readSignalValue(u);
1286
+ const v = this.activeSub;
1287
+ if (v === null)
1288
+ return s;
1289
+ const V = s;
1290
+ return l = this.materializeSignal(
1291
+ V,
1292
+ v,
1293
+ t
1294
+ ), s = void 0, V;
1295
+ }, a = t === void 0 ? (u) => {
1296
+ const v = l;
1297
+ v !== void 0 ? this.writeSignalValue(v, u) : s !== u && (s = u);
1298
+ } : (u) => {
1299
+ const v = l;
1300
+ if (v !== void 0) {
1301
+ const V = v.flags & f ? v.pendingValue : v.cachedValue;
1302
+ V !== u && t.onChange?.(V, u, v.firstSub !== null), this.writeSignalValue(v, u);
1303
+ return;
1304
+ }
1305
+ s !== u && (t.onChange?.(s, u, !1), s = u);
1306
+ }, I = {
1307
+ source: {
1308
+ get: n,
1309
+ peek: this.handleReaders.peek,
1310
+ set: a
1311
+ },
1312
+ /**
1313
+ * Освобождает источник и отсоединяет его от реактивного графа.
1314
+ */
1315
+ dispose() {
1316
+ if (r)
1317
+ return !0;
1318
+ r = !0, s = void 0;
1319
+ let u;
1320
+ try {
1321
+ t?.onDispose?.(l?.firstSub != null);
1322
+ } catch (v) {
1323
+ (u ??= []).push(v);
1324
+ }
1325
+ if (l !== void 0) {
1326
+ try {
1327
+ i.releaseSourceSubs(l);
1328
+ } catch (v) {
1329
+ (u ??= []).push(v);
1330
+ }
1331
+ l.cachedValue = void 0, l.pendingValue = void 0, l.pendingAuthor = void 0, l.flags = 0;
1332
+ }
1333
+ if (l = void 0, u?.length === 1)
1334
+ throw u[0];
1335
+ if (u !== void 0 && u.length > 1)
1336
+ throw new AggregateError(u, "Owned signal disposal failed.");
1337
+ return !0;
1338
+ }
1339
+ };
1340
+ return t !== void 0 && (I.hasSubscribers = () => l?.firstSub != null), I;
1341
+ }
1342
+ /**
1343
+ * Создаёт ленивый computed с финализатором исходящих и входящих связей.
1344
+ * Финализатор работает и до первого вычисления, не материализуя узел ради очистки.
1345
+ * @internal
1346
+ */
1347
+ _ownedComputed(e, t) {
1348
+ const i = this, s = this.createComputedHandle(e, t);
1349
+ let l = !1;
1350
+ const r = {
1351
+ source: s,
1352
+ /**
1353
+ * Отсоединяет принадлежащий источник и освобождает его ссылки.
1354
+ * Повторный вызов возвращает true без повторной очистки.
1355
+ */
1356
+ dispose() {
1357
+ if (l)
1358
+ return !0;
1359
+ l = !0, i.activeSub === s && (i.activeSub = null);
1360
+ const n = [];
1361
+ try {
1362
+ t?.onDispose?.(s.firstSub != null);
1363
+ } catch (c) {
1364
+ n.push(c);
1365
+ }
1366
+ const a = !(s.flags & E);
1367
+ if (a)
1368
+ try {
1369
+ i.releaseSourceSubs(s);
1370
+ } catch (c) {
1371
+ n.push(c);
1372
+ }
1373
+ if (s.evaluate = void 0, s.cachedValue = void 0, s.flags = 0, s.tailDep = null, a)
1374
+ try {
1375
+ i.pruneUnreadDependencies(s);
1376
+ } catch (c) {
1377
+ n.push(c);
1378
+ }
1379
+ if (s.firstDep = s.tailDep = null, n.length === 1)
1380
+ throw n[0];
1381
+ if (n.length > 1)
1382
+ throw new AggregateError(n, "Owned computed disposal failed.");
1383
+ return !0;
1384
+ }
1385
+ };
1386
+ return t !== void 0 && (r.hasSubscribers = () => s.firstSub != null), r;
1387
+ }
1388
+ /**
1389
+ * Открывает вложенную синхронную границу группировки.
1390
+ * Внутренний вызывающий код обязан выполнить соответствующий endBatch().
1391
+ * @internal
1392
+ */
1393
+ _startBatch() {
1394
+ ++this.batchDepth;
1395
+ }
1396
+ /**
1397
+ * Закрывает ранее открытую границу и обрабатывает очередь на внешнем уровне.
1398
+ * Предусловие: число закрытий не должно превышать число открытий.
1399
+ * @internal
1400
+ */
1401
+ _endBatch() {
1402
+ !--this.batchDepth && this.effectReadIndex !== this.effectWriteIndex && this.flushEffects();
1403
+ }
1404
+ /**
1405
+ * Проверяет наличие активного потребителя в текущем синхронном стеке чтения.
1406
+ * @internal
1407
+ */
1408
+ _isTracking() {
1409
+ return this.activeSub !== null;
1410
+ }
1411
+ /**
1412
+ * Выполняет операцию с потребителем-пробой вместо текущего и сообщает, было ли
1413
+ * в ней хотя бы одно отслеживаемое чтение. Связи пробы снимаются сразу, и
1414
+ * проба не остаётся потребителем ни одного источника: renderer узнаёт, нужен
1415
+ * ли вычислению эффект, не создавая его. Операция без отслеживаемых чтений
1416
+ * стоит пробе нескольких присваиваний. Вложенный вызов получает собственную
1417
+ * пробу. Прежний потребитель восстанавливается и при исключении.
1418
+ * @internal
1419
+ */
1420
+ _probeReads(e) {
1421
+ const t = this.probeDepth === 0 ? this.probeNode ??= this.allocateGraphRecord(void 0, B, 0, void 0) : this.allocateGraphRecord(void 0, B, 0, void 0), i = this.activeSub;
1422
+ this.activeSub = t, this.probeDepth++;
1423
+ let s = !1;
1424
+ try {
1425
+ e();
1426
+ } finally {
1427
+ this.probeDepth--, this.activeSub = i, t.firstDep !== null && (s = !0, t.tailDep = null, this.pruneUnreadDependencies(t));
1428
+ }
1429
+ return s;
1430
+ }
1431
+ /**
1432
+ * Состояние уже открытой границы, без нового batch/queue.
1433
+ * @internal
1434
+ */
1435
+ _isBatching() {
1436
+ return this.batchDepth !== 0;
1437
+ }
1438
+ /**
1439
+ * Показывает, обрабатывает ли экземпляр внутреннюю очередь эффектов.
1440
+ * @internal
1441
+ */
1442
+ _isFlushingEffects() {
1443
+ return this.flushingEffects;
1444
+ }
1445
+ // ---------------------------------------------
1446
+ // TASK EFFECT GLUE
1447
+ // ---------------------------------------------
1448
+ //
1449
+ // Аналог createScheduledEffect() без closures для вызывающего слоя, который
1450
+ // владеет одним постоянным объектом задачи на эффект. Вызывающий слой хранит
1451
+ // состояние запусков и управляет записью графа через методы ниже; engine не
1452
+ // создаёт closures runner, cancel и re-arm. Такие эффекты требуют экземпляр
1453
+ // с внешним effect scheduler, как и эффекты, связанные через scheduler.
1454
+ /**
1455
+ * Создаёт запись графа для эффекта с внешним планированием и подключает его
1456
+ * постоянную задачу. Запуск ещё не запрошен: вызывающий слой сохраняет запись
1457
+ * и затем вызывает _requestTaskEffect(). Запись, созданная во время работы
1458
+ * другого эффекта, становится его вложенным ресурсом.
1459
+ * @internal
1460
+ */
1461
+ _allocateTaskEffect(e, t) {
1462
+ const i = this.allocateGraphRecord(void 0, e, f | S | o, void 0), s = this.activeSub;
1463
+ return s !== null && s.flags & o && A(s, i), i.effectTask = t, i;
1464
+ }
1465
+ /**
1466
+ * Запрашивает первый запуск эффекта с задачей. При `schedule` задача получает
1467
+ * schedule(), как на пути scheduler bind; без него вызывающий слой уже сам
1468
+ * поставил задачу в очередь, и запись только помечается запланированной.
1469
+ * Если метод бросает исключение, запись освобождает вызывающий слой.
1470
+ * @internal
1471
+ */
1472
+ _requestTaskEffect(e, t) {
1473
+ t ? this.requestEffectTask(e) : e.effectTask !== void 0 && e.evaluate !== void 0 && (e.flags |= d), !this.batchDepth && this.effectReadIndex !== this.effectWriteIndex && this.flushEffects();
1474
+ }
1475
+ /**
1476
+ * Открывает одну доставку эффекта с задачей. Возвращает false для устаревшей
1477
+ * доставки: запись остановлена или запуск больше не запланирован.
1478
+ * @internal
1479
+ */
1480
+ /**
1481
+ * Сбой первой доставки, выполненной вызывающим слоем без task.schedule():
1482
+ * та же обработка, что у сбоя scheduler.
1483
+ * @internal
1484
+ */
1485
+ _failTaskEffectSchedule(e, t) {
1486
+ return this.failEffectSchedule(e, t);
1487
+ }
1488
+ _beginTaskEffectRun(e) {
1489
+ return !(e.flags & d) || e.evaluate === void 0 ? !1 : (e.flags &= ~d, !0);
1490
+ }
1491
+ /**
1492
+ * Выполняет доставку, открытую через _beginTaskEffectRun(), вне активного
1493
+ * потребителя и затем обрабатывает очередь эффектов, в том числе после
1494
+ * неудачного запуска; при двух сбоях передаёт обе причины.
1495
+ * @internal
1496
+ */
1497
+ _finishTaskEffectRun(e) {
1498
+ const t = this.activeSub;
1499
+ this.activeSub = null;
1500
+ try {
1501
+ try {
1502
+ this.executeEffect(e);
1503
+ } catch (i) {
1504
+ if (!this.batchDepth && this.effectReadIndex !== this.effectWriteIndex)
1505
+ try {
1506
+ this.flushEffects();
1507
+ } catch (s) {
1508
+ throw new AggregateError(
1509
+ [i, s],
1510
+ "Effect execution and queue processing failed."
1511
+ );
1512
+ }
1513
+ throw i;
1514
+ }
1515
+ !this.batchDepth && this.effectReadIndex !== this.effectWriteIndex && this.flushEffects();
1516
+ } finally {
1517
+ this.activeSub = t;
1518
+ }
1519
+ }
1520
+ /**
1521
+ * Гасит ожидающую доставку, от которой отказывается задача. Вызывающий слой
1522
+ * не должен отменять доставку до первого запуска: зависимости до него ещё не
1523
+ * собраны. Возвращает false, если запись уже остановлена.
1524
+ * @internal
1525
+ */
1526
+ _cancelTaskEffect(e) {
1527
+ return e.evaluate === void 0 ? !1 : (this.settleCancelledDependencies(e), e.flags &= -72, !this.batchDepth && this.effectReadIndex !== this.effectWriteIndex && this.flushEffects(), !0);
1528
+ }
1529
+ /**
1530
+ * Делает следующую доставку исполняемой и снова планирует задачу. Нужен,
1531
+ * когда invalidation пришла после снимка текущей доставки: её запуск
1532
+ * расходует предыдущее dirty-состояние.
1533
+ * @internal
1534
+ */
1535
+ _rearmTaskEffect(e) {
1536
+ const t = e.effectTask;
1537
+ t === void 0 || e.evaluate === void 0 || (e.flags |= f | d, t.schedule());
1538
+ }
1539
+ /**
1540
+ * Окончательно останавливает эффект с задачей. Engine один раз вызывает
1541
+ * task.dispose() изнутри, поэтому задача может направлять собственное
1542
+ * освобождение через этот метод.
1543
+ * @internal
1544
+ */
1545
+ _disposeTaskEffect(e) {
1546
+ this.disposeEffect(e);
1547
+ }
1548
+ // ---------------------------------------------
1549
+ // SIGNAL NODE GLUE
1550
+ // ---------------------------------------------
1551
+ //
1552
+ // Аналог _ownedSignal() без closures для вызывающего слоя, который хранит
1553
+ // значение, запись графа и source hooks одного signal в одном постоянном
1554
+ // объекте. Вызывающий слой сам держит значение до материализации и ссылку на
1555
+ // запись после неё; engine не создаёт handle, closures чтения и записи и
1556
+ // объект финализатора. Методы повторяют шаги _ownedSignal() по одному.
1557
+ /**
1558
+ * Материализует signal для активного потребителя и связывает их. Без
1559
+ * потребителя возвращает undefined: signal остаётся значением у вызывающего
1560
+ * слоя. После материализации значением владеет запись.
1561
+ * @internal
1562
+ */
1563
+ _trackSignalNode(e, t) {
1564
+ const i = this.activeSub;
1565
+ if (i !== null)
1566
+ return this.materializeSignal(e, i, t);
1567
+ }
1568
+ /**
1569
+ * Читает материализованный signal и регистрирует зависимость активного
1570
+ * потребителя.
1571
+ * @internal
1572
+ */
1573
+ _readSignalNode(e) {
1574
+ return this.readSignalValue(e);
1575
+ }
1576
+ /**
1577
+ * Читает материализованный signal без подписки текущего потребителя;
1578
+ * pending-значение фиксируется так же, как при обычном чтении.
1579
+ * @internal
1580
+ */
1581
+ _peekSignalNode(e) {
1582
+ const t = this.activeSub;
1583
+ if (t === null)
1584
+ return this.readSignalValue(e);
1585
+ this.activeSub = null;
1586
+ try {
1587
+ return this.readSignalValue(e);
1588
+ } finally {
1589
+ this.activeSub = t;
1590
+ }
1591
+ }
1592
+ /**
1593
+ * Возвращает значение, которое увидит следующее чтение: pending-значение
1594
+ * незавершённой группировки либо зафиксированное. Ничего не фиксирует.
1595
+ * @internal
1596
+ */
1597
+ _visibleSignalValue(e) {
1598
+ return e.flags & f ? e.pendingValue : e.cachedValue;
1599
+ }
1600
+ /**
1601
+ * Записывает значение материализованного signal с обычной семантикой batch.
1602
+ * @internal
1603
+ */
1604
+ _writeSignalNode(e, t) {
1605
+ this.writeSignalValue(e, t);
1606
+ }
1607
+ /**
1608
+ * Сообщает, есть ли у материализованного signal потребители в графе.
1609
+ * @internal
1610
+ */
1611
+ _signalNodeHasSubscribers(e) {
1612
+ return e.firstSub !== null;
1613
+ }
1614
+ /**
1615
+ * Отсоединяет материализованный signal от потребителей и освобождает его
1616
+ * значения. Значения освобождаются и при сбое отсоединения. Поля pending
1617
+ * сбрасываются, только если запись их получала: запись без группировок не
1618
+ * меняет набор своих полей при освобождении.
1619
+ * @internal
1620
+ */
1621
+ _releaseSignalNode(e) {
1622
+ try {
1623
+ this.releaseSourceSubs(e);
1624
+ } finally {
1625
+ e.cachedValue = void 0, e.pendingValue !== void 0 && (e.pendingValue = void 0), e.pendingAuthor != null && (e.pendingAuthor = void 0), e.flags = 0;
1626
+ }
1627
+ }
1628
+ // ---------------------------------------------
1629
+ // SUBSCRIBER OWNER GLUE
1630
+ // ---------------------------------------------
1631
+ //
1632
+ // Чтение живых связей производителя для вызывающего слоя, которому нужен
1633
+ // ответ о владельцах потребителей только по запросу. Слой не ведёт своего
1634
+ // учёта рёбер: связь, снятая графом, перестаёт быть видимой сразу, без
1635
+ // отдельного cleanup на ребро.
1636
+ /**
1637
+ * Ищет среди текущих потребителей записи первого, чьего владельца принимает
1638
+ * accept, и возвращает этого владельца. Владелец потребителя определяется
1639
+ * так же, как при привязке ребра через onDependency: у computed это
1640
+ * dependencyOwner его source hooks, у эффекта — dependencyOwner его задачи.
1641
+ * Потребители без владельца пропускаются. Обход идёт в порядке списка
1642
+ * потребителей, ничего не выделяет и не меняет граф; accept не должен менять
1643
+ * связи этой записи.
1644
+ * @param node Материализованная запись производителя.
1645
+ * @param accept Проверка владельца потребителя; context передаётся ей без closure.
1646
+ * @param context Произвольное значение вызывающего слоя для accept.
1647
+ * @internal
1648
+ */
1649
+ _findSubscriberOwner(e, t, i) {
1650
+ for (let s = e.firstSub; s !== null; s = s.nextSub) {
1651
+ const l = s.sub, r = l.sourceHooks?.dependencyOwner ?? l.effectTask?.dependencyOwner;
1652
+ if (r !== void 0 && t(r, i))
1653
+ return r;
1654
+ }
1655
+ }
1656
+ /**
1657
+ * Возвращает владельца активного потребителя: того, кому engine привязал бы
1658
+ * ребро следующего отслеживаемого чтения. Владелец определяется так же, как
1659
+ * в _findSubscriberOwner(). Без активного потребителя и у потребителя без
1660
+ * владельца результат undefined. Метод ничего не выделяет и не меняет граф.
1661
+ *
1662
+ * Вызывающий слой проверяет по этому владельцу допустимость чтения, когда
1663
+ * его собственный контекст снят, а потребитель engine остался активным.
1664
+ * @internal
1665
+ */
1666
+ _activeSubscriberOwner() {
1667
+ const e = this.activeSub;
1668
+ if (e !== null)
1669
+ return e.sourceHooks?.dependencyOwner ?? e.effectTask?.dependencyOwner;
1670
+ }
1671
+ // ---------------------------------------------
1672
+ // COUNTER NODE GLUE
1673
+ // ---------------------------------------------
1674
+ //
1675
+ // Запись графа со счётчиком вместо значения: вызывающий слой будит через неё
1676
+ // потребителей, которым важен сам факт изменения. Значение счётчика только
1677
+ // растёт, поэтому одну запись нельзя отменить следующей.
1678
+ /**
1679
+ * Увеличивает счётчик материализованного signal и уведомляет его
1680
+ * потребителей. Без потребителей ничего не пишет и возвращает false.
1681
+ *
1682
+ * Сдвиг — обычная запись signal. Вне группировки она прямая: счётчик
1683
+ * фиксируется сразу, а потребитель становится обязательным к пересчёту, в
1684
+ * том числе тот, кто ждал только проверки зависимостей или стоит на стеке
1685
+ * идущей проверки. Внутри группировки и у записи с ещё не прочитанным
1686
+ * отложенным сдвигом запись откладывается до первого чтения, как любая запись
1687
+ * внутри batch().
1688
+ *
1689
+ * Потребитель, который выполняется в момент прямого сдвига, получает его по
1690
+ * общему правилу записи во время запуска: у записи не остаётся отложенного
1691
+ * сдвига, который позже подтвердил бы ему изменение.
1692
+ *
1693
+ * Очередь эффектов обрабатывается на выходе, если группировки нет: отложенная
1694
+ * запись сама её не обрабатывает, а потребитель, которого она поставила в
1695
+ * очередь, не должен ждать следующей записи.
1696
+ * @internal
1697
+ */
1698
+ _bumpSignalNode(e) {
1699
+ return e.firstSub === null ? !1 : (this.writeSignalValue(
1700
+ e,
1701
+ (e.flags & f ? e.pendingValue : e.cachedValue) + 1
1702
+ ), !this.batchDepth && this.effectReadIndex !== this.effectWriteIndex && this.flushEffects(), !0);
1703
+ }
1704
+ /**
1705
+ * Создаёт запись-счётчик для активного потребителя и связывает их; без
1706
+ * потребителя возвращает undefined. Счётчик начинается с нуля и сдвигается
1707
+ * через _bumpSignalNode().
1708
+ *
1709
+ * Счётчик — производитель без собственных зависимостей. Граф читает у него
1710
+ * то же, что у записи signal в роли производителя: признаки, список
1711
+ * потребителей, отсутствие getter, значение и source hooks. Полей списка
1712
+ * зависимостей у записи нет, а hooks лежат в ней самой: счётчик стоит одной
1713
+ * аллокации из шести полей, а запись signal с hooks — двух. Поля отложенной
1714
+ * записи появляются у счётчика с первым сдвигом.
1715
+ * @internal
1716
+ */
1717
+ _trackCounterNode(e) {
1718
+ const t = this.activeSub;
1719
+ if (t === null)
1720
+ return;
1721
+ const i = {
1722
+ flags: h,
1723
+ firstSub: null,
1724
+ lastSub: null,
1725
+ evaluate: void 0,
1726
+ cachedValue: 0,
1727
+ sourceHooks: e
1728
+ };
1729
+ return t.flags & R ? this.appendInitialDependency(i, t) : this.trackDependency(i, t), i;
1730
+ }
1731
+ // ---------------------------------------------
1732
+ // ACTIVE TASK GLUE
1733
+ // ---------------------------------------------
1734
+ //
1735
+ // Тело эффекта с задачей engine вызывает без аргументов и без receiver.
1736
+ // Вызывающий слой, который даёт всем своим эффектам одно общее тело, находит
1737
+ // через метод ниже эффект, ради которого тело вызвано: записи графа не нужна
1738
+ // собственная closure тела.
1739
+ /**
1740
+ * Возвращает постоянную задачу активного потребителя. Engine делает запись
1741
+ * эффекта активным потребителем непосредственно перед вызовом её тела,
1742
+ * поэтому первое обращение из тела возвращает задачу именно этого эффекта,
1743
+ * какие бы доставки ни выполнил cleanup его прошлого запуска.
1744
+ *
1745
+ * Без активного потребителя и у потребителя без задачи — computed либо
1746
+ * эффекта, созданного без внешнего планирования, — результат undefined.
1747
+ * Метод ничего не выделяет и не меняет граф.
1748
+ * @internal
1749
+ */
1750
+ _activeEffectTask() {
1751
+ const e = this.activeSub;
1752
+ return e === null ? void 0 : e.effectTask;
1753
+ }
1754
+ }
1755
+ function B() {
1756
+ }
1757
+ export {
1758
+ G as ReactivityEngine,
1759
+ O as ScopeNode
1760
+ };