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

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 (107) hide show
  1. package/dist/{core-CyilRD7s.js → core-CClhT8WR.js} +389 -400
  2. package/dist/core-cPQWYD4K.cjs +1 -0
  3. package/dist/debug/api/Raph.cjs +1 -1
  4. package/dist/debug/api/Raph.js +46 -47
  5. package/dist/debug/api/RaphFacadeSession.cjs +1 -1
  6. package/dist/debug/api/RaphFacadeSession.js +85 -89
  7. package/dist/debug/api/RaphReactivityInstance.cjs +1 -1
  8. package/dist/debug/api/RaphReactivityInstance.js +27 -30
  9. package/dist/debug/path/DataPath.cjs +1 -1
  10. package/dist/debug/path/DataPath.js +198 -202
  11. package/dist/debug/path/PathRouter.cjs +1 -1
  12. package/dist/debug/path/PathRouter.js +44 -50
  13. package/dist/debug/path/RaphKernel.cjs +1 -1
  14. package/dist/debug/path/RaphKernel.js +257 -228
  15. package/dist/debug/path/data-path.utils.cjs +1 -1
  16. package/dist/debug/path/data-path.utils.js +41 -41
  17. package/dist/debug/path/derived/DerivedRegistry.cjs +1 -1
  18. package/dist/debug/path/derived/DerivedRegistry.js +52 -66
  19. package/dist/debug/path/derived/RaphDerivedHandle.cjs +1 -1
  20. package/dist/debug/path/derived/RaphDerivedHandle.js +19 -22
  21. package/dist/debug/path/derived/derived-collection.utils.cjs +1 -1
  22. package/dist/debug/path/derived/derived-collection.utils.js +70 -70
  23. package/dist/debug/path/meta/MetaController.cjs +1 -1
  24. package/dist/debug/path/meta/MetaController.js +57 -65
  25. package/dist/debug/path/meta/RaphMeta.cjs +1 -1
  26. package/dist/debug/path/meta/RaphMeta.js +26 -32
  27. package/dist/debug/path/meta/RaphMetaStore.cjs +1 -1
  28. package/dist/debug/path/meta/RaphMetaStore.js +24 -30
  29. package/dist/debug/path/storage/AdapterPathStore.cjs +1 -1
  30. package/dist/debug/path/storage/AdapterPathStore.js +49 -54
  31. package/dist/debug/path/storage/DefaultDataAdapter.cjs +1 -1
  32. package/dist/debug/path/storage/DefaultDataAdapter.js +46 -56
  33. package/dist/debug/path/storage/PathEventHub.cjs +1 -1
  34. package/dist/debug/path/storage/PathEventHub.js +74 -61
  35. package/dist/debug/path/storage/PathStore.cjs +1 -1
  36. package/dist/debug/path/storage/PathStore.js +89 -99
  37. package/dist/debug/path/storage/createDataDraft.cjs +1 -1
  38. package/dist/debug/path/storage/createDataDraft.js +24 -28
  39. package/dist/debug/reactivity/disposal.cjs +1 -0
  40. package/dist/debug/reactivity/disposal.js +32 -0
  41. package/dist/debug/reactivity/engine.cjs +1 -1
  42. package/dist/debug/reactivity/engine.js +787 -392
  43. package/dist/debug/reactivity/reactive-object.cjs +1 -1
  44. package/dist/debug/reactivity/reactive-object.js +81 -96
  45. package/dist/debug/reactivity/scope.cjs +1 -1
  46. package/dist/debug/reactivity/scope.js +221 -117
  47. package/dist/debug/reactivity/watch.cjs +1 -1
  48. package/dist/debug/reactivity/watch.js +1 -1
  49. package/dist/debug/runtime/RaphRuntime.cjs +1 -1
  50. package/dist/debug/runtime/RaphRuntime.js +764 -411
  51. package/dist/debug/runtime/diagnostics/RaphDebug.cjs +1 -1
  52. package/dist/debug/runtime/diagnostics/RaphDebug.js +90 -100
  53. package/dist/debug/runtime/ownership/RaphEffectScope.cjs +1 -1
  54. package/dist/debug/runtime/ownership/RaphEffectScope.js +215 -82
  55. package/dist/debug/runtime/ownership/RaphNode.cjs +1 -1
  56. package/dist/debug/runtime/ownership/RaphNode.js +595 -136
  57. package/dist/debug/runtime/ownership/RaphScope.cjs +1 -1
  58. package/dist/debug/runtime/ownership/RaphScope.js +203 -68
  59. package/dist/debug/runtime/phases/RaphFrameLoop.cjs +1 -1
  60. package/dist/debug/runtime/phases/RaphFrameLoop.js +13 -17
  61. package/dist/debug/runtime/phases/RaphPhasePipeline.cjs +1 -1
  62. package/dist/debug/runtime/phases/RaphPhasePipeline.js +618 -357
  63. package/dist/debug/runtime/phases/RaphPhaseTaskRecord.cjs +1 -0
  64. package/dist/debug/runtime/phases/RaphPhaseTaskRecord.js +176 -0
  65. package/dist/debug/runtime/phases/RaphPhaseWatch.cjs +1 -0
  66. package/dist/debug/runtime/phases/RaphPhaseWatch.js +20 -0
  67. package/dist/debug/runtime/reactivity/PathHandle.cjs +1 -1
  68. package/dist/debug/runtime/reactivity/PathHandle.js +50 -60
  69. package/dist/debug/runtime/reactivity/RaphMetaSource.cjs +1 -1
  70. package/dist/debug/runtime/reactivity/RaphMetaSource.js +28 -32
  71. package/dist/debug/runtime/reactivity/RaphSelector.cjs +1 -0
  72. package/dist/debug/runtime/reactivity/RaphSelector.js +503 -0
  73. package/dist/debug/runtime/reactivity/RaphWorkGraph.cjs +1 -1
  74. package/dist/debug/runtime/reactivity/RaphWorkGraph.js +541 -379
  75. package/dist/debug/runtime/reactivity/RuntimeReactivity.cjs +1 -1
  76. package/dist/debug/runtime/reactivity/RuntimeReactivity.js +484 -90
  77. package/dist/debug/runtime/reactivity/RuntimeWatch.cjs +1 -1
  78. package/dist/debug/runtime/reactivity/RuntimeWatch.js +33 -44
  79. package/dist/debug/runtime/reactivity/disposal-sweep.utils.cjs +1 -0
  80. package/dist/debug/runtime/reactivity/disposal-sweep.utils.js +42 -0
  81. package/dist/entrypoints/runtime.d.ts +2 -1
  82. package/dist/machine-testing.cjs +1 -1
  83. package/dist/machine-testing.js +1 -1
  84. package/dist/machine.cjs +1 -1
  85. package/dist/machine.js +216 -231
  86. package/dist/path/RaphKernel.d.ts +24 -0
  87. package/dist/path/storage/PathEventHub.d.ts +14 -0
  88. package/dist/path/storage/PathStore.d.ts +4 -4
  89. package/dist/reactivity/disposal.d.ts +14 -0
  90. package/dist/reactivity/engine.d.ts +177 -4
  91. package/dist/reactivity/scope.d.ts +108 -30
  92. package/dist/runtime/RaphRuntime.d.ts +236 -17
  93. package/dist/runtime/ownership/RaphEffectScope.d.ts +70 -1
  94. package/dist/runtime/ownership/RaphNode.d.ts +276 -6
  95. package/dist/runtime/ownership/RaphScope.d.ts +144 -14
  96. package/dist/runtime/phases/RaphPhasePipeline.d.ts +202 -28
  97. package/dist/runtime/phases/RaphPhaseTaskRecord.d.ts +195 -0
  98. package/dist/runtime/phases/RaphPhaseWatch.d.ts +22 -0
  99. package/dist/runtime/phases/phase.types.d.ts +83 -4
  100. package/dist/runtime/reactivity/RaphSelector.d.ts +338 -0
  101. package/dist/runtime/reactivity/RaphWorkGraph.d.ts +163 -25
  102. package/dist/runtime/reactivity/RuntimeReactivity.d.ts +258 -10
  103. package/dist/runtime/reactivity/RuntimeWatch.d.ts +8 -8
  104. package/dist/runtime/reactivity/disposal-sweep.utils.d.ts +19 -0
  105. package/dist/runtime/reactivity/runtime-reactivity.types.d.ts +48 -3
  106. package/package.json +9 -1
  107. package/dist/core-ugchZNqC.cjs +0 -1
@@ -1,25 +1,37 @@
1
- import { Disposer, EffectTask } from '../../reactivity/types';
2
1
  import { RaphScope } from '../ownership/RaphScope';
3
- import { RaphFrameContext, RaphPhase, RaphPhaseEffect, RaphPhaseTask, RaphSchedulerMode, RaphWorkCause } from './phase.types';
4
- export interface RaphPhaseBinding extends EffectTask {
5
- readonly task: RaphPhaseTask;
6
- /** Stops the owning implicit effect when a fatal discard cannot re-arm it. @internal */
7
- abort?: Disposer;
8
- enqueue: (cause: RaphWorkCause, key?: object, schedule?: boolean) => void;
9
- pause: () => void;
10
- resume: () => void;
2
+ import { RuntimeReactivity } from '../reactivity/RuntimeReactivity';
3
+ import { RaphFrameContext, RaphPhase, RaphPhaseEffect, RaphSchedulerMode, RaphWorkCause } from './phase.types';
4
+ import { RaphPhaseTaskRecord } from './RaphPhaseTaskRecord';
5
+ /**
6
+ * Постоянное состояние одной phase: живая очередь, запасной массив для обмена
7
+ * при разборе и число bindings. Состояние переживает переопределение phases, пока
8
+ * имя phase сохраняется, поэтому запись binding держит прямую ссылку на него и
9
+ * ставится в очередь без поиска по имени. Через него же запись находит свой
10
+ * pipeline: отдельной ссылки на pipeline у записи нет.
11
+ *
12
+ * Инвариант: каждая запись живой очереди активна и ожидает доставки, а
13
+ * `spare` пуст вне разбора своей phase.
14
+ */
15
+ export declare class RaphPhaseState {
16
+ readonly name: string;
17
+ readonly pipeline: RaphPhasePipeline;
18
+ queue: RaphPhaseTaskRecord[];
19
+ spare: RaphPhaseTaskRecord[];
20
+ bindings: number;
21
+ constructor(name: string, pipeline: RaphPhasePipeline);
11
22
  }
12
23
  /** Единая Runtime-owned очередь persistent phase bindings. */
13
24
  export declare class RaphPhasePipeline {
14
25
  private readonly _scheduler;
15
- private readonly _runUntracked;
26
+ private readonly _reactivity;
16
27
  private readonly _resolveCause;
17
28
  private readonly _deferSync;
18
29
  private readonly _tracePhase?;
19
30
  private _phases;
20
31
  private _phaseByName;
21
- private readonly _phaseBindings;
22
- private readonly _queues;
32
+ private _resolvedInput;
33
+ private _resolvedState;
34
+ private _queuedCount;
23
35
  private readonly _deferred;
24
36
  private readonly _idleWaiters;
25
37
  private _taskSequence;
@@ -28,51 +40,213 @@ export declare class RaphPhasePipeline {
28
40
  private _frameHandle;
29
41
  private _frameHandleKind;
30
42
  private _configurationLocked;
31
- private _running;
43
+ /**
44
+ * Flush исполняется сейчас: новая работа попадёт в его следующий проход.
45
+ *
46
+ * @internal
47
+ */
48
+ _running: boolean;
49
+ private _idleSlotFlags;
32
50
  private _disposed;
33
51
  private _firstFrameAt;
34
52
  private _lastFrameAt;
35
53
  private _frameNumber;
36
54
  private _frame;
37
- constructor(_scheduler: RaphSchedulerMode, _runUntracked: <T>(operation: () => T) => T, _resolveCause: (token: unknown) => RaphWorkCause | undefined, _deferSync?: () => boolean, _tracePhase?: ((phase: string, status: "end" | "error" | "start", error?: unknown) => void) | undefined);
55
+ constructor(_scheduler: RaphSchedulerMode, _reactivity: RuntimeReactivity, _resolveCause: (token: unknown) => RaphWorkCause | undefined, _deferSync?: () => boolean, _tracePhase?: ((phase: string, status: "end" | "error" | "start", error?: unknown) => void) | undefined);
38
56
  get frame(): RaphFrameContext;
39
57
  get phases(): readonly RaphPhase[];
40
58
  definePhases(phases: readonly RaphPhase[]): void;
41
59
  addPhase(phase: RaphPhase): void;
42
60
  clearPhases(): void;
43
- requirePhase(name: string): void;
44
- bindTask(phaseInput: string, consumerOwner: RaphScope, effect: RaphPhaseEffect, priority: number, runner: () => void): RaphPhaseBinding;
61
+ /**
62
+ * Находит состояние объявленной phase по имени, которое передал вызывающий.
63
+ * Подряд идущие bindings одной phase попадают в кэш из одной записи; точное
64
+ * имя находится без `trim()`, и только имя с пробелами по краям нормализуется.
65
+ */
66
+ resolvePhase(input: string): RaphPhaseState;
67
+ /**
68
+ * Создаёт постоянную запись одного binding. Вызывающий уже разрешил phase
69
+ * и проверил priority, поэтому горячий путь регистрации проверяет их один раз.
70
+ * Запись ничего не выполняет, пока вызывающий не подключит engine effect
71
+ * (`node`) или watch lifecycle (`watch`).
72
+ */
73
+ bindTask(phase: RaphPhaseState, consumerOwner: RaphScope, effect: RaphPhaseEffect, priority: number): RaphPhaseTaskRecord;
74
+ /**
75
+ * Создаёт постоянную запись группы из `count` slots: одна запись binding и
76
+ * её состояние с местом под запись графа каждого slot. Вызывающий уже
77
+ * разрешил phase и проверил priority и `count`; записи графа он подключает
78
+ * сам через _allocateTaskEffect() и кладёт в состояние по порядку slots.
79
+ * Slot ничего не исполняет, пока его запись не запланирована.
80
+ *
81
+ * `runSlot` занимает место callback записи: его показывает `task.effect`
82
+ * группы, а вызывает только общее тело записей engine — с состоянием
83
+ * группы, где лежат её context и номер slot. Поэтому запись группы несёт
84
+ * `TASK_TASKLESS`: вместо task тело получает поле `group`.
85
+ */
86
+ bindGroup(phase: RaphPhaseState, consumerOwner: RaphScope, runSlot: RaphPhaseEffect, context: unknown, count: number, priority: number): RaphPhaseTaskRecord;
45
87
  request(): void;
46
88
  afterFlush(): Promise<void>;
47
89
  flush(): void;
48
90
  dispose(): void;
49
91
  _debugPending(): boolean;
50
92
  private _describeQueued;
51
- private _createTask;
93
+ /**
94
+ * Открывает доставку одной записью `state`. Накопленные причины остаются на
95
+ * своих местах и становятся причинами доставки под TASK_CAUSES_DELIVERED:
96
+ * ничего не копируется, а массив для `task.causes` строится, только если его
97
+ * прочитают. Frame доставки получает только запись с facade: без facade его
98
+ * нечем прочитать, а запись ссылки на новый frame в каждую доставленную
99
+ * запись стоит write barrier.
100
+ *
101
+ * Запись попадает сюда только из живой очереди, а в ней нет записей с
102
+ * открытой доставкой, поэтому причин прошлой доставки здесь не бывает.
103
+ */
52
104
  private _beginDelivery;
53
- private _runDelivery;
54
- private _deferDelivery;
55
- private _cancelDelivery;
105
+ /**
106
+ * Исполняет открытую доставку binding. `failures` передаёт default runner:
107
+ * группа складывает туда сбой каждого slot отдельно. Без него сбои slots
108
+ * бросаются вызывающему — `task.run()` внутри `process` — после прохода: один
109
+ * как есть, несколько одним AggregateError.
110
+ *
111
+ * @internal
112
+ */
113
+ _runDelivery(record: RaphPhaseTaskRecord, failures?: unknown[]): void;
114
+ /** @internal */
115
+ _deferDelivery(record: RaphPhaseTaskRecord): void;
116
+ /** @internal */
117
+ _cancelDelivery(record: RaphPhaseTaskRecord): void;
56
118
  private _finishDelivery;
57
- private _appendCause;
58
- private _queue;
59
- private _disposeTask;
60
- private _pauseTask;
61
- private _resumeTask;
119
+ /**
120
+ * Делает исполняемыми slots группы, которые остались запланированными после
121
+ * доставки: slot, изменивший собственную зависимость, и slot, чью зависимость
122
+ * изменили после его запуска. Slot, который не запланирован, не трогается:
123
+ * он уже прочитал актуальные значения и в следующей доставке не исполняется.
124
+ * Запись, сделанную до запуска slot в той же доставке, slot читает в ней же:
125
+ * прямую запись engine переводит в обязательный запуск, отложенную находит
126
+ * проверка зависимостей. Отдельный binding после такой записи исполняется
127
+ * ещё раз следующим проходом; slot повторно не исполняется.
128
+ *
129
+ * Запись без зависимостей пропускается. Запланированной она бывает в двух
130
+ * случаях: slot запущен во время доставки и ждёт первого запуска — тогда она
131
+ * исполняема с момента создания; либо повторно запущен slot, который уже
132
+ * исполнился и ничего не прочитал, — тогда исполнять его нечем.
133
+ */
134
+ private _rearmGroup;
135
+ /** @internal */
136
+ _notifyTask(record: RaphPhaseTaskRecord, token: unknown): void;
137
+ /** @internal */
138
+ _appendCause(record: RaphPhaseTaskRecord, cause: RaphWorkCause, key: object): void;
139
+ /**
140
+ * Переносит причины открытой доставки с места ожидающих в detail, без
141
+ * копирования, и освобождает это место. После вызова запись хранит оба
142
+ * набора раздельно: ожидающие причины — в своих полях, причины доставки — в
143
+ * detail. Массив, уже построенный для `task.causes`, остаётся тем же.
144
+ */
145
+ private _splitDeliveredCauses;
146
+ /** @internal */
147
+ _queue(record: RaphPhaseTaskRecord, schedule?: boolean): void;
148
+ /** @internal */
149
+ _disposeTask(record: RaphPhaseTaskRecord): void;
150
+ /**
151
+ * Полностью освобождает один binding; каждый шаг идемпотентен, поэтому
152
+ * владелец, engine и пользователь могут прийти сюда в любом порядке и
153
+ * повторно войти в метод.
154
+ *
155
+ * @internal
156
+ */
157
+ _disposeBinding(record: RaphPhaseTaskRecord): void;
158
+ /**
159
+ * Убирает из состояния группы slots, записи графа которых уже остановлены, и
160
+ * сообщает, остались ли при этом живые slots.
161
+ *
162
+ * Запись одного slot останавливается отдельно от группы в трёх случаях: упал
163
+ * cleanup перед повторным запуском slot; перезапускается или останавливается
164
+ * effect, внутри тела которого группа зарегистрирована; провалился запуск
165
+ * slot через `start()`. Engine сообщает о каждой такой остановке через task
166
+ * hook, общий для всех slots, и запись в этот момент уже остановлена. Группа
167
+ * тогда теряет только этот slot, как owner потерял бы один из отдельных
168
+ * bindings; запись binding освобождается, когда остановлен последний slot.
169
+ *
170
+ * Вызов владельца или effect scope остановленных записей не находит: место
171
+ * остановленного slot уже занято `null`.
172
+ *
173
+ * @returns true, если вызов был сообщением engine и живые slots остались.
174
+ */
175
+ private _forgetStoppedSlots;
176
+ /**
177
+ * Останавливает записи графа всех slots группы в порядке, обратном порядку
178
+ * slots: так владелец освобождал бы отдельные bindings. Сбой cleanup одного
179
+ * slot не мешает остановить остальные.
180
+ *
181
+ * Группа — один ресурс, поэтому порядок и вид ошибки не зависят от того, кто
182
+ * её освобождает. Effect scope отдельные bindings освободил бы в порядке
183
+ * регистрации и сложил бы их сбои в собственный список; группу он
184
+ * освобождает в обратном порядке slots и получает несколько сбоев одним
185
+ * AggregateError. Владелец получает тот же AggregateError как один сбой
186
+ * ресурса вместо отдельных сбоев bindings.
187
+ *
188
+ * Остановка первой же записи повторно входит в _disposeBinding() через task
189
+ * hook engine: вложенный вызов уже не находит состояния группы и освобождает
190
+ * состояние pipeline до cleanup slots. Группа без живых slots освобождает
191
+ * его здесь.
192
+ */
193
+ private _disposeGroup;
194
+ /**
195
+ * Освобождает подписку и состояние pipeline остановленного watch.
196
+ */
197
+ private _releaseWatch;
198
+ /** @internal */
199
+ _pauseTask(record: RaphPhaseTaskRecord): void;
200
+ /**
201
+ * Убирает ожидающую запись из живой очереди её phase. Запись, которую flush
202
+ * уже забрал на разбор, в живой очереди не находится и счётчик не меняет.
203
+ */
204
+ private _unqueue;
205
+ /** @internal */
206
+ _resumeTask(record: RaphPhaseTaskRecord): void;
207
+ /**
208
+ * Возвращает причины открытой доставки в ожидающие, впереди причин, которые
209
+ * пришли после её открытия; причины одного source сливаются. Причины доставки
210
+ * при этом остаются причинами доставки до её конца, поэтому сначала они
211
+ * отделяются от ожидающих.
212
+ */
62
213
  private _restoreDeliveryCausesBeforePending;
63
- private _takePhase;
64
214
  private _schedule;
65
215
  private _scheduleDeferredTurn;
66
216
  private _cancelScheduled;
67
217
  private _activateDeferred;
68
218
  private _nextFrame;
69
219
  private _assertRetainedPhases;
70
- private _assertDelivery;
71
- private _hasQueued;
72
220
  private _hasPending;
73
221
  private _cancelAllQueued;
74
222
  private _cancelAllDeferred;
75
223
  private _acknowledgeDiscard;
224
+ /**
225
+ * Гасит ожидающую доставку slots группы.
226
+ *
227
+ * Slot, чей первый запуск ещё впереди, погасить нельзя: он не собрал
228
+ * зависимости, и после отмены его ничто не разбудит. Такой slot узнаётся по
229
+ * запланированной записи без единой зависимости: запись, которая уже
230
+ * исполнялась и ничего не прочитала, больше не планируется. Обычная отмена
231
+ * тогда не трогает ни один slot и возвращает false; fatal discard
232
+ * останавливает такие slots окончательно и гасит остальные.
233
+ *
234
+ * Обычная отмена отказывается только от того, что доставка знала при
235
+ * открытии. Причина, пришедшая группе после открытия доставки, означает
236
+ * запись, которую запланированный slot ещё не прочитал. Гашение снимает с
237
+ * записи slot и отметку планирования, и требование запуска, которое engine
238
+ * поставил при прямой записи, поэтому slots, ждавшие запуска, после гашения
239
+ * снова требуют его, как отдельный binding, отменённый при новой причине.
240
+ * Группа тогда доставляется ещё раз с новыми причинами. Fatal discard гасит
241
+ * всё.
242
+ *
243
+ * @returns false, если доставку нельзя отменить либо живых slots не осталось.
244
+ */
245
+ private _cancelGroup;
246
+ /**
247
+ * Сбрасывает ожидающую работу записи, снятой с очереди либо из отложенных.
248
+ * Такая запись не находится в доставке, поэтому её причины ожидающие.
249
+ */
76
250
  private _clearPendingDelivery;
77
251
  private _settleIdleWaiters;
78
252
  private _assertAlive;
@@ -0,0 +1,195 @@
1
+ import { EffectTask, OwnedResource, ReactiveNode, ScopeChildren } from '../../reactivity/types';
2
+ import { RaphScope } from '../ownership/RaphScope';
3
+ import { RaphEffectGroup, RaphEffectInitialMode, RaphFrameContext, RaphPhaseEffect, RaphPhaseTask, RaphWorkCause } from './phase.types';
4
+ import { RaphPhaseState } from './RaphPhasePipeline';
5
+ import { RaphPhaseWatch } from './RaphPhaseWatch';
6
+ export declare const EMPTY_CAUSES: readonly RaphWorkCause[];
7
+ export declare const EMPTY_FRAME: RaphFrameContext;
8
+ export declare const TASK_ACTIVE = 1;
9
+ export declare const TASK_PAUSED: number;
10
+ export declare const TASK_PENDING: number;
11
+ export declare const TASK_DEFERRED: number;
12
+ export declare const TASK_IN_DELIVERY: number;
13
+ export declare const TASK_DISCARD_ACKNOWLEDGED: number;
14
+ export declare const TASK_REQUESTED: number;
15
+ export declare const TASK_EXECUTED: number;
16
+ export declare const TASK_CAUSES_DELIVERED: number;
17
+ export declare const TASK_RESOLUTION: number;
18
+ export declare const TASK_UNRESOLVED = 0;
19
+ export declare const TASK_RUN: number;
20
+ export declare const TASK_DEFER: number;
21
+ export declare const TASK_CANCEL: number;
22
+ export declare const TASK_TASKLESS: number;
23
+ /**
24
+ * Состояние группы effects одного binding: плоский массив
25
+ * `[context, номер исполняемого slot, запись графа slot 0, slot 1, ...]`.
26
+ *
27
+ * Группа делит одну запись binding между несколькими отслеживаемыми
28
+ * вычислениями. У каждого slot своя запись графа engine, то есть свой набор
29
+ * зависимостей и свой признак invalidation; общими остаются запись binding и
30
+ * её место в очереди phase и в списке ресурсов владельца. Тело записи engine
31
+ * у всех slots одно, поэтому номер slot доставка записывает сюда перед
32
+ * запуском каждого slot, а тело slot получает само состояние как свой
33
+ * единственный аргумент — запуск `RaphEffectGroupRun`: первые два элемента и
34
+ * есть его публичная часть.
35
+ *
36
+ * На месте записи slot, остановленного отдельно от группы, стоит `null`.
37
+ *
38
+ * Состояние — массив, а не class: на группу приходится одна аллокация точного
39
+ * размера, и у неё нет hidden class, который терялся бы, когда освобождена
40
+ * последняя группа.
41
+ */
42
+ export type RaphEffectGroupState = unknown[];
43
+ export declare const GROUP_CONTEXT = 0;
44
+ export declare const GROUP_CURSOR = 1;
45
+ export declare const GROUP_NODES = 2;
46
+ /**
47
+ * Frozen public facade of one phase binding. All state stays on the record, so
48
+ * the facade has a single own field and shares its capabilities through the
49
+ * prototype: `run`, `defer` and `cancel` need the task as receiver.
50
+ */
51
+ export declare class RaphPhaseTaskHandle implements RaphPhaseTask {
52
+ /** @internal */
53
+ readonly _record: RaphPhaseTaskRecord;
54
+ constructor(record: RaphPhaseTaskRecord);
55
+ get phase(): string;
56
+ get consumerOwner(): RaphScope;
57
+ get effect(): RaphPhaseEffect;
58
+ get causes(): readonly RaphWorkCause[];
59
+ get frame(): RaphFrameContext;
60
+ get priority(): number;
61
+ get sequence(): number;
62
+ run(): void;
63
+ defer(): void;
64
+ cancel(): void;
65
+ }
66
+ /**
67
+ * Редкое состояние одного phase binding, вынесенное из записи. Объект создаётся
68
+ * при первом входе binding в одно из таких состояний и живёт до освобождения
69
+ * записи:
70
+ *
71
+ * - до доставки накопились причины от второго source (`extraCauses`);
72
+ * - причины открытой доставки пришлось отделить от ожидающих: во время
73
+ * доставки пришла новая причина либо доставка отложена или остановлена
74
+ * pause (`deliveryFirstCause`, `deliveryFirstCauseKey`,
75
+ * `deliveryExtraCauses`);
76
+ * - причины доставки прочитаны через `task.causes` (`deliveryCauses`);
77
+ * - доставка отложена через `defer()` (`deferCount`).
78
+ *
79
+ * Binding, который исполняется и получает не больше одной причины на
80
+ * доставку, не читая `task.causes`, этого объекта не создаёт: ни effect с task
81
+ * или без неё, ни watch, ни группа.
82
+ *
83
+ * Поля объявлены без initializers и присваиваются в constructor в одном
84
+ * фиксированном порядке: у каждого экземпляра один hidden class.
85
+ *
86
+ * Engine удерживает форму экземпляров только через живые экземпляры. Когда в
87
+ * isolate не остаётся ни одного binding с редким состоянием, полная сборка
88
+ * мусора освобождает её вместе с кодом, оптимизированным под неё. Поэтому
89
+ * class владеет одним постоянным экземпляром `_shapeAnchor`.
90
+ */
91
+ export declare class RaphPhaseTaskDetail {
92
+ static _shapeAnchor: RaphPhaseTaskDetail;
93
+ extraCauses: Map<object, RaphWorkCause> | undefined;
94
+ deliveryFirstCause: RaphWorkCause | undefined;
95
+ deliveryFirstCauseKey: object | undefined;
96
+ deliveryExtraCauses: Map<object, RaphWorkCause> | undefined;
97
+ deliveryCauses: readonly RaphWorkCause[] | undefined;
98
+ deferCount: number;
99
+ constructor();
100
+ }
101
+ /**
102
+ * Постоянное состояние одного phase binding. Один и тот же объект является
103
+ * элементом очереди pipeline, внешней задачей engine effect, элементом списка
104
+ * ресурсов своего consumer owner и pausable-регистрацией, передаваемой effect
105
+ * scopes, поэтому binding стоит одной аллокации.
106
+ *
107
+ * Запись несёт только то, что нужно binding между регистрацией и освобождением
108
+ * на обычном пути: признаки одним числом, место в очереди, владельца, callback,
109
+ * запись графа, lifecycle watch либо состояние группы, связи списка ресурсов,
110
+ * первую причину и лениво создаваемый frozen facade с frame, который он
111
+ * показывает. Остальное — причины со второй, причины доставки, отделённые от
112
+ * ожидающих, показанный массив причин и счётчик defer — лежит в `detail`,
113
+ * который создаётся при первом входе в такое состояние. Pipeline запись
114
+ * находит через её phase: `phaseState.pipeline`.
115
+ *
116
+ * Поля объявлены без initializers и присваиваются в constructor в одном
117
+ * фиксированном порядке: у каждой записи один hidden class, и ни один build
118
+ * target не может превратить поля в вызовы helper.
119
+ */
120
+ export declare class RaphPhaseTaskRecord implements EffectTask, OwnedResource, RaphEffectGroup {
121
+ state: number;
122
+ sequence: number;
123
+ readonly phaseState: RaphPhaseState;
124
+ readonly priority: number;
125
+ readonly consumerOwner: RaphScope;
126
+ readonly effect: RaphPhaseEffect;
127
+ node: ReactiveNode | undefined;
128
+ watch: RaphPhaseWatch | undefined;
129
+ group: RaphEffectGroupState | undefined;
130
+ scopeParent: ScopeChildren<OwnedResource> | undefined;
131
+ scopePrevious: OwnedResource | undefined;
132
+ scopeNext: OwnedResource | undefined;
133
+ firstCause: RaphWorkCause | undefined;
134
+ firstCauseKey: object | undefined;
135
+ frame: RaphFrameContext;
136
+ facade: RaphPhaseTaskHandle | undefined;
137
+ detail: RaphPhaseTaskDetail | undefined;
138
+ constructor(phaseState: RaphPhaseState, priority: number, consumerOwner: RaphScope, effect: RaphPhaseEffect);
139
+ get phase(): string;
140
+ get dependencyOwner(): RaphScope;
141
+ get allowScheduleDuringRun(): boolean;
142
+ /**
143
+ * Становится false, когда binding остановлен: так запись видят effect scopes,
144
+ * которым она передана как pausable-регистрация.
145
+ */
146
+ get active(): boolean;
147
+ /**
148
+ * Причины текущей доставки в том виде, в каком их получает callback или
149
+ * `process`. Массив строится при первом чтении в доставке и до её конца
150
+ * остаётся тем же объектом; доставка, причины которой никто не прочитал, не
151
+ * создаёт ни массива, ни заморозки. Вне доставки и для доставки без причин
152
+ * это общий пустой массив.
153
+ *
154
+ * Это единственное место, где причины выходят наружу, поэтому здесь же они
155
+ * становятся неизменяемыми: WorkGraph создаёт причину без заморозки, а
156
+ * замораживает её первое чтение.
157
+ */
158
+ get causes(): readonly RaphWorkCause[];
159
+ /**
160
+ * One facade per record: created on first exposure, then reused.
161
+ *
162
+ * Запись начинает вести frame с появлением facade. Facade создаётся внутри
163
+ * открытой доставки своей записи — его запрашивают только тело binding и
164
+ * `process` — и получает её frame; frame каждой следующей доставки
165
+ * записывает её открытие.
166
+ */
167
+ get task(): RaphPhaseTask;
168
+ /** Возвращает редкое состояние записи и создаёт его при первом обращении. */
169
+ detailed(): RaphPhaseTaskDetail;
170
+ notify(token: unknown): void;
171
+ schedule(): void;
172
+ enqueue(cause: RaphWorkCause, key?: object, schedule?: boolean): void;
173
+ /**
174
+ * Запускает slot группы effects; у записи одиночного effect и watch ничего
175
+ * не делает. Запись группы сама является handle, который возвращает
176
+ * `effectGroup`.
177
+ */
178
+ start(slot: number, initial?: RaphEffectInitialMode): void;
179
+ /**
180
+ * Внутренний initial invocation renderer; публичный start не меняет signature.
181
+ * Continuation не сохраняется в записи и не вызывается при последующих runs.
182
+ * @internal
183
+ */
184
+ _start(slot: number, initial: RaphEffectInitialMode, onExecutionFailure: (error: unknown) => never): void;
185
+ pause(): void;
186
+ resume(): void;
187
+ /**
188
+ * Полностью освобождает binding; безопасен для повторного и вложенного вызова:
189
+ * снимает запись со списка владельца, останавливает engine effect или watch
190
+ * lifecycle и сбрасывает состояние pipeline. Engine вызывает его как task hook
191
+ * остановленного effect, владелец — как элемент списка ресурсов, а
192
+ * пользователь — через disposer.
193
+ */
194
+ dispose(): void;
195
+ }
@@ -0,0 +1,22 @@
1
+ import { Disposer } from '../../reactivity/types';
2
+ import { RaphPhaseTaskRecord } from './RaphPhaseTaskRecord';
3
+ import { RuntimeWatch } from '../reactivity/RuntimeWatch';
4
+ /**
5
+ * Callback lifecycle одного explicit watch binding вместе с подпиской, которая
6
+ * его питает. Подписка освобождается при освобождении binding, до cleanup
7
+ * последней доставки.
8
+ *
9
+ * Lifecycle достаёт callback только через запись своего binding и сбрасывает
10
+ * эту ссылку при освобождении. Публичный watch disposer удерживает lifecycle,
11
+ * а не запись, поэтому disposer, переживший свой binding, не удерживает ни
12
+ * callback, ни захваченное им.
13
+ */
14
+ export declare class RaphPhaseWatch extends RuntimeWatch {
15
+ source: Disposer | undefined;
16
+ record: RaphPhaseTaskRecord | undefined;
17
+ /**
18
+ * Создаёт lifecycle без подписки и без binding; оба поля задаёт регистрация.
19
+ */
20
+ constructor(runUntracked: <T>(operation: () => T) => T, callback: () => void | Disposer);
21
+ }
22
+ export declare function createPhaseWatch(runUntracked: <T>(operation: () => T) => T, record: RaphPhaseTaskRecord): RaphPhaseWatch;
@@ -45,7 +45,86 @@ export interface RaphWorkCause {
45
45
  readonly metadata?: unknown;
46
46
  }
47
47
  export type RaphPhaseEffect = (task: RaphPhaseTask) => void | Disposer;
48
- /** Persistent task identity, передаваемая phase process и effect callback. */
48
+ /**
49
+ * Тело binding, зарегистрированного через `bindEffect`: task ему не передаётся,
50
+ * поэтому тело объявляется без параметров. Возвращённый cleanup выполняется
51
+ * перед следующим запуском и при освобождении binding.
52
+ */
53
+ export type RaphPhaseBody = () => void | Disposer;
54
+ /**
55
+ * Запуск одного slot группы: кортеж, который получает тело slot. Первый элемент
56
+ * — context группы, второй — номер исполняемого slot, считая с нуля.
57
+ *
58
+ * Кортеж один на группу и принадлежит ей: номер slot в нём меняется от запуска
59
+ * к запуску, а остальные элементы — внутреннее состояние группы. Тело читает
60
+ * первые два элемента по индексу во время вызова и не сохраняет кортеж.
61
+ *
62
+ * Кортеж — живое состояние группы, а не копия: от записи его защищает только
63
+ * тип. Тело, которое пишет в кортеж или читает элементы после второго,
64
+ * нарушает contract: запись в первый элемент подменяет context следующим
65
+ * slots, запись в остальные ломает доставку группы.
66
+ *
67
+ * @typeParam Context — значение, которое группа передаёт телу каждого slot.
68
+ */
69
+ export type RaphEffectGroupRun<Context = unknown> = readonly [
70
+ context: Context,
71
+ slot: number,
72
+ ...state: readonly unknown[]
73
+ ];
74
+ /**
75
+ * Тело одного slot группы, зарегистрированной через `effectGroup`. Получает
76
+ * один аргумент — запуск с context группы и номером slot; task ему не
77
+ * передаётся. Чтения внутри вызова отслеживаются отдельно для каждого slot, а
78
+ * возвращённый cleanup принадлежит этому slot: он выполняется перед его
79
+ * следующим запуском и при освобождении группы.
80
+ *
81
+ * Аргумент один, как у тела `effect()`: общее для всех effects тело записи
82
+ * engine вызывает тело slot напрямую, без промежуточной функции на каждый
83
+ * запуск slot.
84
+ *
85
+ * @typeParam Context — значение, которое группа передаёт телу каждого slot.
86
+ */
87
+ export type RaphEffectGroupSlot<Context = unknown> = (run: RaphEffectGroupRun<Context>) => void | Disposer;
88
+ /** Настройки группы effects: порядок её task среди bindings той же phase. */
89
+ export interface RaphEffectGroupOptions {
90
+ readonly priority?: number;
91
+ }
92
+ /**
93
+ * Группа effects одного binding, которую вернул `effectGroup`. Slots группы
94
+ * ничего не исполняют, пока их не запустит `start`; метод вызывается через
95
+ * группу или с явным receiver.
96
+ *
97
+ * Возвращаемое значение — сама запись binding, а не отдельный объект: handle
98
+ * не стоит группе аллокации. Contract — только `start`; остальные поля и
99
+ * методы записи внутренние, и обращение к ним нарушает contract.
100
+ */
101
+ export interface RaphEffectGroup {
102
+ /**
103
+ * Запускает slot: с этого вызова slot ведёт себя как binding, который
104
+ * `bindEffect()` зарегистрировал бы в этом месте. `initial` задаёт первую
105
+ * доставку так же, как у `effect()`: `'scheduled'` (по умолчанию) ставит её
106
+ * в очередь, `'sync'` исполняет её до возврата из вызова, если Runtime не
107
+ * занят доставкой и группа не на pause.
108
+ *
109
+ * Если первая доставка выполняется внутри вызова и flush бросает ошибку,
110
+ * slot останавливается окончательно, а ошибка бросается вызывающему, как
111
+ * при сбое регистрации отдельного binding. Остальные slots группы остаются.
112
+ * Запуск остановленного slot и повторный запуск уже запущенного slot не
113
+ * исполняют его тело.
114
+ *
115
+ * Запуск на освобождённом владельце бросает `RaphDisposedError`, как
116
+ * `bindEffect()`: и когда владелец освобождён до вызова, и когда его
117
+ * освободила первая доставка внутри этого вызова, при любом scheduler.
118
+ * Запуск slot группы, которую освободили при живом владельце — через её
119
+ * effect scope либо остановкой последнего slot, — ничего не делает.
120
+ */
121
+ start: (this: RaphEffectGroup, slot: number, initial?: RaphEffectInitialMode) => void;
122
+ }
123
+ /**
124
+ * Persistent task identity, передаваемая phase process и effect callback.
125
+ * run/defer/cancel вызываются через task или с явным receiver: извлечённый
126
+ * метод не работает без this.
127
+ */
49
128
  export interface RaphPhaseTask {
50
129
  readonly phase: string;
51
130
  readonly consumerOwner: RaphScope;
@@ -54,9 +133,9 @@ export interface RaphPhaseTask {
54
133
  readonly frame: RaphFrameContext;
55
134
  readonly priority: number;
56
135
  readonly sequence: number;
57
- run: () => void;
58
- defer: () => void;
59
- cancel: () => void;
136
+ run: (this: RaphPhaseTask) => void;
137
+ defer: (this: RaphPhaseTask) => void;
138
+ cancel: (this: RaphPhaseTask) => void;
60
139
  }
61
140
  export interface RaphPhaseBatch {
62
141
  readonly phase: string;