@ersbeth/picoflow 2.1.0 → 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/SKILL.md CHANGED
@@ -59,7 +59,12 @@ callback) rather than needing manual `await`/try-catch inside a derivation.
59
59
  - **Creating a subscription inside another subscription's callback** — it re-creates one on every run
60
60
  and leaks. Combine into a single `subscribe()` whose data function reads all the needed primitives.
61
61
  - **A `subscribe()`/`.subscribe()` callback that calls `.set()` on a primitive it also reads** — infinite
62
- loop.
62
+ loop. PicoFlow's own cycle guard stops it after 10 000 steps and reports it through `onFlushError()`
63
+ (see below) rather than crashing the process, but the loop is still a bug to fix, not something to rely
64
+ on the guard for.
65
+ - **`subscribe(fn)` with no `onError`, and no global `onFlushError()` handler installed** — any exception
66
+ thrown inside `fn` is only logged via `console.error` by default; install `onFlushError((error) => ...)`
67
+ once at startup if the application needs to observe or report these instead of the default logging.
63
68
  - **Using `add()`/`update()` on `array`/`map` without checking preconditions** — `array.update(index, x)`
64
69
  throws if the index is out of bounds; `map.add(key, x)` throws if the key exists; `map.update(key, x)`
65
70
  throws if it doesn't. Check first (`.pick()`) or branch on it, don't assume.
package/dist/picoflow.js CHANGED
@@ -1,5 +1,242 @@
1
1
  import { createResource, onMount, createEffect, resetErrorBoundaries, onCleanup } from 'solid-js';
2
2
 
3
+ class Disposable {
4
+ _disposed = false;
5
+ get disposed() {
6
+ return this._disposed;
7
+ }
8
+ }
9
+
10
+ class ExecutionStack {
11
+ static _MAX_FLUSH_STEPS = 1e4;
12
+ static _pendingQueue = [];
13
+ static _effectQueue = [];
14
+ static _executionScheduled;
15
+ static _coalesceResetScheduled = false;
16
+ /** Routes any error escaping the flush loop; defaults to logging rather than crashing (A2-SEM-2, A2-SEC-1). */
17
+ static _onFlushError = (error) => console.error(error);
18
+ /**
19
+ * True once the current synchronous call stack has finished and microtasks have started.
20
+ * EffectNode uses this to treat microtask notifications (e.g. async resolve) differently
21
+ * from coalesced sync-batch notifications.
22
+ */
23
+ static _pastSyncTurn = false;
24
+ /** @internal Used by EffectNode to distinguish sync-batch from microtask notifications. */
25
+ static get pastSyncTurn() {
26
+ return ExecutionStack._pastSyncTurn;
27
+ }
28
+ /**
29
+ * @internal Runs after the current sync turn ends (queueMicrotask).
30
+ * Marks pastSyncTurn so the next coalesced effect notify can bump its epoch,
31
+ * and resets per-effect coalesce flags via onReset.
32
+ */
33
+ static scheduleCoalesceReset(onReset) {
34
+ if (ExecutionStack._coalesceResetScheduled) return;
35
+ ExecutionStack._coalesceResetScheduled = true;
36
+ queueMicrotask(() => {
37
+ ExecutionStack._pastSyncTurn = true;
38
+ ExecutionStack._coalesceResetScheduled = false;
39
+ onReset();
40
+ });
41
+ }
42
+ /** @internal Wired to the public `onFlushError()` API in `src/api/base/flowConfig.ts`. */
43
+ static setFlushErrorHandler(handler) {
44
+ ExecutionStack._onFlushError = handler;
45
+ }
46
+ static pushPending(node) {
47
+ ExecutionStack._beginSyncTurn();
48
+ ExecutionStack._scheduleExecution();
49
+ ExecutionStack._pendingQueue.push(node);
50
+ }
51
+ static pushEffect(effect) {
52
+ ExecutionStack._beginSyncTurn();
53
+ ExecutionStack._scheduleExecution();
54
+ ExecutionStack._effectQueue.push(effect);
55
+ }
56
+ static _beginSyncTurn() {
57
+ ExecutionStack._pastSyncTurn = false;
58
+ }
59
+ static _scheduleExecution() {
60
+ if (ExecutionStack._executionScheduled) return;
61
+ ExecutionStack._executionScheduled = new Promise((resolve) => {
62
+ setTimeout(() => {
63
+ ExecutionStack._executionScheduled = void 0;
64
+ ExecutionStack._execute();
65
+ resolve();
66
+ }, 0);
67
+ });
68
+ }
69
+ static _drain(queue) {
70
+ for (let i = 0; i < queue.length; i++) {
71
+ if (i >= ExecutionStack._MAX_FLUSH_STEPS) {
72
+ ExecutionStack._pendingQueue.length = 0;
73
+ ExecutionStack._effectQueue.length = 0;
74
+ ExecutionStack._onFlushError(new Error("[PicoFlow] Reactive update cycle exceeded maximum depth"));
75
+ return;
76
+ }
77
+ const node = queue[i];
78
+ try {
79
+ node?.execute();
80
+ } catch (error) {
81
+ ExecutionStack._onFlushError(error);
82
+ }
83
+ }
84
+ queue.length = 0;
85
+ }
86
+ static _execute() {
87
+ ExecutionStack._drain(ExecutionStack._pendingQueue);
88
+ ExecutionStack._drain(ExecutionStack._effectQueue);
89
+ }
90
+ }
91
+
92
+ class Node extends Disposable {
93
+ _dependencies = /* @__PURE__ */ new Set();
94
+ _dependents = /* @__PURE__ */ new Set();
95
+ _status = "resolved";
96
+ get status() {
97
+ if (this.disposed) throw new Error("[PicoFlow] Primitive is disposed");
98
+ return this._status;
99
+ }
100
+ set status(status) {
101
+ if (this.disposed) throw new Error("[PicoFlow] Primitive is disposed");
102
+ this._status = status;
103
+ }
104
+ registerDependency(dependency) {
105
+ if (this._disposed) throw new Error("[PicoFlow] Primitive is disposed");
106
+ this._dependencies.add(dependency);
107
+ dependency.registerDependent(this);
108
+ }
109
+ unregisterDependency(dependency) {
110
+ if (this._disposed) throw new Error("[PicoFlow] Primitive is disposed");
111
+ this._dependencies.delete(dependency);
112
+ dependency.unregisterDependent(this);
113
+ }
114
+ clearDependencies() {
115
+ if (this.disposed) throw new Error("[PicoFlow] Primitive is disposed");
116
+ this._dependencies.forEach((dependency) => {
117
+ dependency.unregisterDependent(this);
118
+ });
119
+ this._dependencies.clear();
120
+ }
121
+ registerDependent(dependent) {
122
+ if (this.disposed) throw new Error("[PicoFlow] Primitive is disposed");
123
+ this._dependents.add(dependent);
124
+ }
125
+ unregisterDependent(dependent) {
126
+ if (this.disposed) throw new Error("[PicoFlow] Primitive is disposed");
127
+ this._dependents.delete(dependent);
128
+ }
129
+ markDependencyDisposed() {
130
+ }
131
+ notifyDependents() {
132
+ if (this.disposed) return;
133
+ this._dependents.forEach((dependent) => {
134
+ dependent.notify();
135
+ });
136
+ }
137
+ watch(tracker) {
138
+ if (this.disposed) throw new Error("[PicoFlow] Primitive is disposed");
139
+ tracker.registerDependency(this);
140
+ }
141
+ trigger() {
142
+ if (this.disposed) throw new Error("[PicoFlow] Primitive is disposed");
143
+ this.notifyDependents();
144
+ }
145
+ dispose() {
146
+ if (this._disposed) throw new Error("[PicoFlow] Primitive is disposed");
147
+ Array.from(this._dependents).forEach((dependant) => {
148
+ dependant.markDependencyDisposed();
149
+ dependant.unregisterDependency(this);
150
+ this.unregisterDependent(dependant);
151
+ });
152
+ Array.from(this._dependencies).forEach((dependency) => {
153
+ this.unregisterDependency(dependency);
154
+ });
155
+ this._disposed = true;
156
+ }
157
+ }
158
+
159
+ class Observable extends Disposable {
160
+ _dependents = /* @__PURE__ */ new Set();
161
+ _status = "resolved";
162
+ get status() {
163
+ if (this.disposed) throw new Error("[PicoFlow] Primitive is disposed");
164
+ return this._status;
165
+ }
166
+ set status(status) {
167
+ if (this.disposed) throw new Error("[PicoFlow] Primitive is disposed");
168
+ this._status = status;
169
+ }
170
+ registerDependent(dependent) {
171
+ if (this.disposed) throw new Error("[PicoFlow] Primitive is disposed");
172
+ this._dependents.add(dependent);
173
+ }
174
+ unregisterDependent(dependent) {
175
+ if (this.disposed) throw new Error("[PicoFlow] Primitive is disposed");
176
+ this._dependents.delete(dependent);
177
+ }
178
+ notifyDependents() {
179
+ if (this.disposed) return;
180
+ this._dependents.forEach((dependent) => {
181
+ dependent.notify();
182
+ });
183
+ }
184
+ watch(tracker) {
185
+ if (this.disposed) throw new Error("[PicoFlow] Primitive is disposed");
186
+ tracker.registerDependency(this);
187
+ }
188
+ trigger() {
189
+ if (this.disposed) throw new Error("[PicoFlow] Primitive is disposed");
190
+ this.notifyDependents();
191
+ }
192
+ dispose() {
193
+ if (this._disposed) throw new Error("[PicoFlow] Primitive is disposed");
194
+ Array.from(this._dependents).forEach((dependant) => {
195
+ dependant.markDependencyDisposed();
196
+ dependant.unregisterDependency(this);
197
+ this.unregisterDependent(dependant);
198
+ });
199
+ this._disposed = true;
200
+ }
201
+ }
202
+
203
+ class Observer extends Disposable {
204
+ _dependencies = /* @__PURE__ */ new Set();
205
+ /** Set when a dependency disposed while this observer was queued; consumed by the next execute(). */
206
+ _dependencyDisposed = false;
207
+ markDependencyDisposed() {
208
+ this._dependencyDisposed = true;
209
+ }
210
+ registerDependency(dependency) {
211
+ if (this._disposed) throw new Error("[PicoFlow] Primitive is disposed");
212
+ this._dependencies.add(dependency);
213
+ dependency.registerDependent(this);
214
+ }
215
+ unregisterDependency(dependency) {
216
+ if (this._disposed) throw new Error("[PicoFlow] Primitive is disposed");
217
+ this._dependencies.delete(dependency);
218
+ dependency.unregisterDependent(this);
219
+ }
220
+ clearDependencies() {
221
+ if (this.disposed) throw new Error("[PicoFlow] Primitive is disposed");
222
+ this._dependencies.forEach((dependency) => {
223
+ dependency.unregisterDependent(this);
224
+ });
225
+ this._dependencies.clear();
226
+ }
227
+ dispose() {
228
+ if (this._disposed) throw new Error("[PicoFlow] Primitive is disposed");
229
+ Array.from(this._dependencies).forEach((dependency) => {
230
+ this.unregisterDependency(dependency);
231
+ });
232
+ this._disposed = true;
233
+ }
234
+ }
235
+
236
+ function onFlushError(handler) {
237
+ ExecutionStack.setFlushErrorHandler(handler);
238
+ }
239
+
3
240
  function isDisposable(obj) {
4
241
  return obj !== null && obj !== void 0 && typeof obj.dispose === "function";
5
242
  }
@@ -213,229 +450,6 @@ class SyncScheduler {
213
450
  }
214
451
  }
215
452
 
216
- class Disposable {
217
- _disposed = false;
218
- get disposed() {
219
- return this._disposed;
220
- }
221
- dispose() {
222
- if (this._disposed) throw new Error("[PicoFlow] Primitive is disposed");
223
- this._disposed = true;
224
- }
225
- }
226
-
227
- class ExecutionStack {
228
- static _MAX_FLUSH_STEPS = 1e4;
229
- static _pendingQueue = [];
230
- static _effectQueue = [];
231
- static _executionScheduled;
232
- static _coalesceResetScheduled = false;
233
- /**
234
- * True once the current synchronous call stack has finished and microtasks have started.
235
- * EffectNode uses this to treat microtask notifications (e.g. async resolve) differently
236
- * from coalesced sync-batch notifications.
237
- */
238
- static _pastSyncTurn = false;
239
- /** @internal Used by EffectNode to distinguish sync-batch from microtask notifications. */
240
- static get pastSyncTurn() {
241
- return ExecutionStack._pastSyncTurn;
242
- }
243
- /**
244
- * @internal Runs after the current sync turn ends (queueMicrotask).
245
- * Marks pastSyncTurn so the next coalesced effect notify can bump its epoch,
246
- * and resets per-effect coalesce flags via onReset.
247
- */
248
- static scheduleCoalesceReset(onReset) {
249
- if (ExecutionStack._coalesceResetScheduled) return;
250
- ExecutionStack._coalesceResetScheduled = true;
251
- queueMicrotask(() => {
252
- ExecutionStack._pastSyncTurn = true;
253
- ExecutionStack._coalesceResetScheduled = false;
254
- onReset();
255
- });
256
- }
257
- static pushPending(node) {
258
- ExecutionStack._beginSyncTurn();
259
- ExecutionStack._scheduleExecution();
260
- ExecutionStack._pendingQueue.push(node);
261
- }
262
- static pushEffect(effect) {
263
- ExecutionStack._beginSyncTurn();
264
- ExecutionStack._scheduleExecution();
265
- ExecutionStack._effectQueue.push(effect);
266
- }
267
- static _beginSyncTurn() {
268
- ExecutionStack._pastSyncTurn = false;
269
- }
270
- static _scheduleExecution() {
271
- if (ExecutionStack._executionScheduled) return;
272
- ExecutionStack._executionScheduled = new Promise((resolve) => {
273
- setTimeout(() => {
274
- ExecutionStack._executionScheduled = void 0;
275
- ExecutionStack._execute();
276
- resolve();
277
- }, 0);
278
- });
279
- }
280
- static _drain(queue) {
281
- for (let i = 0; i < queue.length; i++) {
282
- if (i >= ExecutionStack._MAX_FLUSH_STEPS) {
283
- ExecutionStack._pendingQueue.length = 0;
284
- ExecutionStack._effectQueue.length = 0;
285
- throw new Error("[PicoFlow] Reactive update cycle exceeded maximum depth");
286
- }
287
- const node = queue[i];
288
- node?.execute();
289
- }
290
- queue.length = 0;
291
- }
292
- static _execute() {
293
- ExecutionStack._drain(ExecutionStack._pendingQueue);
294
- ExecutionStack._drain(ExecutionStack._effectQueue);
295
- }
296
- }
297
-
298
- class Node extends Disposable {
299
- _dependencies = /* @__PURE__ */ new Set();
300
- _dependents = /* @__PURE__ */ new Set();
301
- _status = "resolved";
302
- get status() {
303
- if (this.disposed) throw new Error("[PicoFlow] Primitive is disposed");
304
- return this._status;
305
- }
306
- set status(status) {
307
- if (this.disposed) throw new Error("[PicoFlow] Primitive is disposed");
308
- this._status = status;
309
- }
310
- registerDependency(dependency) {
311
- if (this._disposed) throw new Error("[PicoFlow] Primitive is disposed");
312
- this._dependencies.add(dependency);
313
- dependency.registerDependent(this);
314
- }
315
- unregisterDependency(dependency) {
316
- if (this._disposed) throw new Error("[PicoFlow] Primitive is disposed");
317
- this._dependencies.delete(dependency);
318
- dependency.unregisterDependent(this);
319
- }
320
- clearDependencies() {
321
- if (this.disposed) throw new Error("[PicoFlow] Primitive is disposed");
322
- this._dependencies.forEach((dependency) => {
323
- dependency.unregisterDependent(this);
324
- });
325
- this._dependencies.clear();
326
- }
327
- registerDependent(dependent) {
328
- if (this.disposed) throw new Error("[PicoFlow] Primitive is disposed");
329
- this._dependents.add(dependent);
330
- }
331
- unregisterDependent(dependent) {
332
- if (this.disposed) throw new Error("[PicoFlow] Primitive is disposed");
333
- this._dependents.delete(dependent);
334
- }
335
- notifyDependents() {
336
- if (this.disposed) return;
337
- this._dependents.forEach((dependent) => {
338
- dependent.notify();
339
- });
340
- }
341
- watch(tracker) {
342
- if (this.disposed) throw new Error("[PicoFlow] Primitive is disposed");
343
- tracker.registerDependency(this);
344
- }
345
- trigger() {
346
- if (this.disposed) throw new Error("[PicoFlow] Primitive is disposed");
347
- this.notifyDependents();
348
- }
349
- notify() {
350
- if (this.disposed) throw new Error("[PicoFlow] Primitive is disposed");
351
- if (this.status === "dirty") return;
352
- this.status = "dirty";
353
- this.notifyDependents();
354
- }
355
- dispose() {
356
- if (this._disposed) throw new Error("[PicoFlow] Primitive is disposed");
357
- Array.from(this._dependents).forEach((dependant) => {
358
- dependant.unregisterDependency(this);
359
- this.unregisterDependent(dependant);
360
- });
361
- Array.from(this._dependencies).forEach((dependency) => {
362
- this.unregisterDependency(dependency);
363
- });
364
- this._disposed = true;
365
- }
366
- }
367
-
368
- class Observable extends Disposable {
369
- _dependents = /* @__PURE__ */ new Set();
370
- _status = "resolved";
371
- get status() {
372
- if (this.disposed) throw new Error("[PicoFlow] Primitive is disposed");
373
- return this._status;
374
- }
375
- set status(status) {
376
- if (this.disposed) throw new Error("[PicoFlow] Primitive is disposed");
377
- this._status = status;
378
- }
379
- registerDependent(dependent) {
380
- if (this.disposed) throw new Error("[PicoFlow] Primitive is disposed");
381
- this._dependents.add(dependent);
382
- }
383
- unregisterDependent(dependent) {
384
- if (this.disposed) throw new Error("[PicoFlow] Primitive is disposed");
385
- this._dependents.delete(dependent);
386
- }
387
- notifyDependents() {
388
- if (this.disposed) return;
389
- this._dependents.forEach((dependent) => {
390
- dependent.notify();
391
- });
392
- }
393
- watch(tracker) {
394
- if (this.disposed) throw new Error("[PicoFlow] Primitive is disposed");
395
- tracker.registerDependency(this);
396
- }
397
- trigger() {
398
- if (this.disposed) throw new Error("[PicoFlow] Primitive is disposed");
399
- this.notifyDependents();
400
- }
401
- dispose() {
402
- if (this._disposed) throw new Error("[PicoFlow] Primitive is disposed");
403
- Array.from(this._dependents).forEach((dependant) => {
404
- dependant.unregisterDependency(this);
405
- this.unregisterDependent(dependant);
406
- });
407
- this._disposed = true;
408
- }
409
- }
410
-
411
- class Observer extends Disposable {
412
- _dependencies = /* @__PURE__ */ new Set();
413
- registerDependency(dependency) {
414
- if (this._disposed) throw new Error("[PicoFlow] Primitive is disposed");
415
- this._dependencies.add(dependency);
416
- dependency.registerDependent(this);
417
- }
418
- unregisterDependency(dependency) {
419
- if (this._disposed) throw new Error("[PicoFlow] Primitive is disposed");
420
- this._dependencies.delete(dependency);
421
- dependency.unregisterDependent(this);
422
- }
423
- clearDependencies() {
424
- if (this.disposed) throw new Error("[PicoFlow] Primitive is disposed");
425
- this._dependencies.forEach((dependency) => {
426
- dependency.unregisterDependent(this);
427
- });
428
- this._dependencies.clear();
429
- }
430
- dispose() {
431
- if (this._disposed) throw new Error("[PicoFlow] Primitive is disposed");
432
- Array.from(this._dependencies).forEach((dependency) => {
433
- this.unregisterDependency(dependency);
434
- });
435
- this._disposed = true;
436
- }
437
- }
438
-
439
453
  class EffectNode extends Observer {
440
454
  _data;
441
455
  _onData;
@@ -482,6 +496,11 @@ class EffectNode extends Observer {
482
496
  this._executedEpoch = this._notifyEpoch;
483
497
  return;
484
498
  }
499
+ if (this._dependencyDisposed) {
500
+ this._dependencyDisposed = false;
501
+ this._executedEpoch = this._notifyEpoch;
502
+ return;
503
+ }
485
504
  const targetEpoch = this._notifyEpoch;
486
505
  while (this._executedEpoch < targetEpoch) {
487
506
  this._executedEpoch++;
@@ -489,6 +508,11 @@ class EffectNode extends Observer {
489
508
  this._executedEpoch = this._notifyEpoch;
490
509
  return;
491
510
  }
511
+ if (this._dependencyDisposed) {
512
+ this._dependencyDisposed = false;
513
+ this._executedEpoch = this._notifyEpoch;
514
+ return;
515
+ }
492
516
  try {
493
517
  this.clearDependencies();
494
518
  const data = this._data(this);
@@ -508,7 +532,9 @@ class EffectNode extends Observer {
508
532
  }
509
533
  }
510
534
 
535
+ const PICOFLOW_VALUE_NODE = /* @__PURE__ */ Symbol.for("picoflow.node");
511
536
  class ValueNode extends Node {
537
+ [PICOFLOW_VALUE_NODE] = true;
512
538
  _value;
513
539
  _error;
514
540
  watch(tracker) {
@@ -889,7 +915,7 @@ class ArrayNode extends ValueSyncNode {
889
915
  }
890
916
  update(index, item) {
891
917
  if (this.disposed) throw new Error("[PicoFlow] Primitive is disposed");
892
- if (index < 0 || index >= this._value.length) {
918
+ if (index < 0 || index >= this._value.length || !Number.isInteger(index)) {
893
919
  throw new Error("[PicoFlow] Index out of bounds");
894
920
  }
895
921
  const previousValue = this._value[index];
@@ -1082,6 +1108,9 @@ function describeFlowInput(value) {
1082
1108
  }
1083
1109
  return typeof value;
1084
1110
  }
1111
+ function isValueNode(flow) {
1112
+ return typeof flow === "object" && flow !== null && PICOFLOW_VALUE_NODE in flow;
1113
+ }
1085
1114
  function fromNode(node, options) {
1086
1115
  const [resource, { refetch }] = createResource(() => node.pick());
1087
1116
  let fx;
@@ -1122,7 +1151,7 @@ function fromGetter(getter) {
1122
1151
  return fromNode(derivation, { disposeNode: true });
1123
1152
  }
1124
1153
  function from(flow) {
1125
- if (flow instanceof ValueAsyncNode || flow instanceof ValueSyncNode) {
1154
+ if (isValueNode(flow)) {
1126
1155
  return fromNode(flow);
1127
1156
  }
1128
1157
  if (typeof flow === "function") {
@@ -1131,4 +1160,4 @@ function from(flow) {
1131
1160
  throw new Error(`[PicoFlow] from(): expected a FlowValue or getter function, received ${describeFlowInput(flow)}`);
1132
1161
  }
1133
1162
 
1134
- export { array, constant, constantAsync, derivation, derivationAsync, from, isDisposable, map, signal, state, stateAsync, subscribe, writableDerivation, writableDerivationAsync };
1163
+ export { array, constant, constantAsync, derivation, derivationAsync, from, isDisposable, map, onFlushError, signal, state, stateAsync, subscribe, writableDerivation, writableDerivationAsync };
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Installs a global handler for errors that escape the reactive flush.
3
+ *
4
+ * All reactive work — recomputing derivations, running effects — happens inside an
5
+ * asynchronous flush. Without this hook, an error escaping the flush (an effect callback
6
+ * that throws with no `onError`, or a feedback loop between two effects) becomes an
7
+ * uncaught exception, which terminates a Node process. Installing a handler here makes
8
+ * that error catchable instead.
9
+ *
10
+ * Defaults to `console.error`. The handler replaces any previously installed handler —
11
+ * it is not additive.
12
+ *
13
+ * @param handler - Called with the error that escaped the flush.
14
+ *
15
+ * @public
16
+ */
17
+ export declare function onFlushError(handler: (error: unknown) => void): void;
18
+ //# sourceMappingURL=flowConfig.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"flowConfig.d.ts","sourceRoot":"","sources":["../../../../src/api/base/flowConfig.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,GAAG,IAAI,CAEpE"}
@@ -1,3 +1,4 @@
1
+ export * from './flowConfig.js';
1
2
  export * from './flowDisposable.js';
2
3
  export * from './flowObservable.js';
3
4
  export * from './flowSubscribable.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/api/base/index.ts"],"names":[],"mappings":"AAAA,cAAc,qBAAqB,CAAC;AACpC,cAAc,qBAAqB,CAAC;AACpC,cAAc,uBAAuB,CAAC;AACtC,cAAc,kBAAkB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/api/base/index.ts"],"names":[],"mappings":"AAAA,cAAc,iBAAiB,CAAC;AAChC,cAAc,qBAAqB,CAAC;AACpC,cAAc,qBAAqB,CAAC;AACpC,cAAc,uBAAuB,CAAC;AACtC,cAAc,kBAAkB,CAAC"}
@@ -1,11 +1,11 @@
1
1
  import { FlowDisposable } from '../api/index.js';
2
2
  /**
3
3
  * Base implementation of the disposable pattern for reactive primitives.
4
- * Throws an error if disposed multiple times.
4
+ * Concrete subclasses implement `dispose()` and are expected to throw if disposed multiple times.
5
5
  */
6
- export declare class Disposable implements FlowDisposable {
6
+ export declare abstract class Disposable implements FlowDisposable {
7
7
  protected _disposed: boolean;
8
8
  get disposed(): boolean;
9
- dispose(): void;
9
+ abstract dispose(): void;
10
10
  }
11
11
  //# sourceMappingURL=disposable.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"disposable.d.ts","sourceRoot":"","sources":["../../../src/base/disposable.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAEtD;;;GAGG;AACH,qBAAa,UAAW,YAAW,cAAc;IAC7C,SAAS,CAAC,SAAS,UAAS;IAE5B,IAAI,QAAQ,IAAI,OAAO,CAEtB;IAED,OAAO,IAAI,IAAI;CAIlB"}
1
+ {"version":3,"file":"disposable.d.ts","sourceRoot":"","sources":["../../../src/base/disposable.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAEtD;;;GAGG;AACH,8BAAsB,UAAW,YAAW,cAAc;IACtD,SAAS,CAAC,SAAS,UAAS;IAE5B,IAAI,QAAQ,IAAI,OAAO,CAEtB;IAED,QAAQ,CAAC,OAAO,IAAI,IAAI;CAC3B"}
@@ -11,6 +11,8 @@ export declare class ExecutionStack {
11
11
  private static readonly _effectQueue;
12
12
  private static _executionScheduled?;
13
13
  private static _coalesceResetScheduled;
14
+ /** Routes any error escaping the flush loop; defaults to logging rather than crashing (A2-SEM-2, A2-SEC-1). */
15
+ private static _onFlushError;
14
16
  /**
15
17
  * True once the current synchronous call stack has finished and microtasks have started.
16
18
  * EffectNode uses this to treat microtask notifications (e.g. async resolve) differently
@@ -25,6 +27,8 @@ export declare class ExecutionStack {
25
27
  * and resets per-effect coalesce flags via onReset.
26
28
  */
27
29
  static scheduleCoalesceReset(onReset: () => void): void;
30
+ /** @internal Wired to the public `onFlushError()` API in `src/api/base/flowConfig.ts`. */
31
+ static setFlushErrorHandler(handler: (error: unknown) => void): void;
28
32
  static pushPending(node: IObserver): void;
29
33
  static pushEffect(effect: IObserver): void;
30
34
  private static _beginSyncTurn;
@@ -1 +1 @@
1
- {"version":3,"file":"executionStack.d.ts","sourceRoot":"","sources":["../../../src/base/executionStack.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAE/C;;;;;GAKG;AACH,qBAAa,cAAc;IACvB,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,gBAAgB,CAAU;IAClD,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,aAAa,CAAmB;IACxD,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,YAAY,CAAmB;IACvD,OAAO,CAAC,MAAM,CAAC,mBAAmB,CAAC,CAAgB;IACnD,OAAO,CAAC,MAAM,CAAC,uBAAuB,CAAS;IAC/C;;;;OAIG;IACH,OAAO,CAAC,MAAM,CAAC,aAAa,CAAS;IAErC,2FAA2F;IAC3F,MAAM,KAAK,YAAY,IAAI,OAAO,CAEjC;IAED;;;;OAIG;IACH,MAAM,CAAC,qBAAqB,CAAC,OAAO,EAAE,MAAM,IAAI,GAAG,IAAI;IAUvD,MAAM,CAAC,WAAW,CAAC,IAAI,EAAE,SAAS,GAAG,IAAI;IAMzC,MAAM,CAAC,UAAU,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI;IAM1C,OAAO,CAAC,MAAM,CAAC,cAAc;IAK7B,OAAO,CAAC,MAAM,CAAC,kBAAkB;IAWjC,OAAO,CAAC,MAAM,CAAC,MAAM;IAerB,OAAO,CAAC,MAAM,CAAC,QAAQ;CAI1B"}
1
+ {"version":3,"file":"executionStack.d.ts","sourceRoot":"","sources":["../../../src/base/executionStack.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAE/C;;;;;GAKG;AACH,qBAAa,cAAc;IACvB,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,gBAAgB,CAAU;IAClD,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,aAAa,CAAmB;IACxD,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,YAAY,CAAmB;IACvD,OAAO,CAAC,MAAM,CAAC,mBAAmB,CAAC,CAAgB;IACnD,OAAO,CAAC,MAAM,CAAC,uBAAuB,CAAS;IAC/C,+GAA+G;IAC/G,OAAO,CAAC,MAAM,CAAC,aAAa,CAA6D;IACzF;;;;OAIG;IACH,OAAO,CAAC,MAAM,CAAC,aAAa,CAAS;IAErC,2FAA2F;IAC3F,MAAM,KAAK,YAAY,IAAI,OAAO,CAEjC;IAED;;;;OAIG;IACH,MAAM,CAAC,qBAAqB,CAAC,OAAO,EAAE,MAAM,IAAI,GAAG,IAAI;IAUvD,0FAA0F;IAC1F,MAAM,CAAC,oBAAoB,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,GAAG,IAAI;IAIpE,MAAM,CAAC,WAAW,CAAC,IAAI,EAAE,SAAS,GAAG,IAAI;IAMzC,MAAM,CAAC,UAAU,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI;IAM1C,OAAO,CAAC,MAAM,CAAC,cAAc;IAK7B,OAAO,CAAC,MAAM,CAAC,kBAAkB;IAWjC,OAAO,CAAC,MAAM,CAAC,MAAM;IAsBrB,OAAO,CAAC,MAAM,CAAC,QAAQ;CAI1B"}
@@ -16,11 +16,12 @@ export declare abstract class Node<T> extends Disposable implements IObservable<
16
16
  clearDependencies(): void;
17
17
  registerDependent(dependent: IObserver): void;
18
18
  unregisterDependent(dependent: IObserver): void;
19
+ markDependencyDisposed(): void;
19
20
  notifyDependents(): void;
20
21
  watch(tracker: FlowTracker): void;
21
22
  trigger(): void;
22
- notify(): void;
23
23
  dispose(): void;
24
+ abstract notify(): void;
24
25
  abstract execute(): void;
25
26
  abstract subscribe(onValue: FlowOnDataListener<T>, onError?: FlowOnErrorListener, onPending?: FlowOnPendingListener): FlowEffect;
26
27
  }
@@ -1 +1 @@
1
- {"version":3,"file":"node.d.ts","sourceRoot":"","sources":["../../../src/base/node.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACR,UAAU,EACV,kBAAkB,EAClB,mBAAmB,EACnB,qBAAqB,EACrB,WAAW,EACd,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,KAAK,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACrE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAE/C;;GAEG;AACH,8BAAsB,IAAI,CAAC,CAAC,CAAE,SAAQ,UAAW,YAAW,WAAW,CAAC,CAAC,CAAC,EAAE,SAAS;IACjF,OAAO,CAAC,aAAa,CAAmC;IACxD,OAAO,CAAC,WAAW,CAAwB;IAC3C,SAAS,CAAC,OAAO,EAAE,gBAAgB,CAAc;IAEjD,IAAI,MAAM,IAAI,gBAAgB,CAG7B;IAED,IAAI,MAAM,CAAC,MAAM,EAAE,gBAAgB,EAGlC;IAED,kBAAkB,CAAC,UAAU,EAAE,WAAW,CAAC,OAAO,CAAC,GAAG,IAAI;IAM1D,oBAAoB,CAAC,UAAU,EAAE,WAAW,CAAC,OAAO,CAAC,GAAG,IAAI;IAM5D,iBAAiB,IAAI,IAAI;IAQzB,iBAAiB,CAAC,SAAS,EAAE,SAAS,GAAG,IAAI;IAK7C,mBAAmB,CAAC,SAAS,EAAE,SAAS,GAAG,IAAI;IAK/C,gBAAgB,IAAI,IAAI;IAOxB,KAAK,CAAC,OAAO,EAAE,WAAW,GAAG,IAAI;IAKjC,OAAO,IAAI,IAAI;IAKf,MAAM,IAAI,IAAI;IAOL,OAAO,IAAI,IAAI;IAaxB,QAAQ,CAAC,OAAO,IAAI,IAAI;IAExB,QAAQ,CAAC,SAAS,CACd,OAAO,EAAE,kBAAkB,CAAC,CAAC,CAAC,EAC9B,OAAO,CAAC,EAAE,mBAAmB,EAC7B,SAAS,CAAC,EAAE,qBAAqB,GAClC,UAAU;CAChB"}
1
+ {"version":3,"file":"node.d.ts","sourceRoot":"","sources":["../../../src/base/node.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACR,UAAU,EACV,kBAAkB,EAClB,mBAAmB,EACnB,qBAAqB,EACrB,WAAW,EACd,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,KAAK,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACrE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAE/C;;GAEG;AACH,8BAAsB,IAAI,CAAC,CAAC,CAAE,SAAQ,UAAW,YAAW,WAAW,CAAC,CAAC,CAAC,EAAE,SAAS;IACjF,OAAO,CAAC,aAAa,CAAmC;IACxD,OAAO,CAAC,WAAW,CAAwB;IAC3C,SAAS,CAAC,OAAO,EAAE,gBAAgB,CAAc;IAEjD,IAAI,MAAM,IAAI,gBAAgB,CAG7B;IAED,IAAI,MAAM,CAAC,MAAM,EAAE,gBAAgB,EAGlC;IAED,kBAAkB,CAAC,UAAU,EAAE,WAAW,CAAC,OAAO,CAAC,GAAG,IAAI;IAM1D,oBAAoB,CAAC,UAAU,EAAE,WAAW,CAAC,OAAO,CAAC,GAAG,IAAI;IAM5D,iBAAiB,IAAI,IAAI;IAQzB,iBAAiB,CAAC,SAAS,EAAE,SAAS,GAAG,IAAI;IAK7C,mBAAmB,CAAC,SAAS,EAAE,SAAS,GAAG,IAAI;IAK/C,sBAAsB,IAAI,IAAI;IAM9B,gBAAgB,IAAI,IAAI;IAOxB,KAAK,CAAC,OAAO,EAAE,WAAW,GAAG,IAAI;IAKjC,OAAO,IAAI,IAAI;IAKN,OAAO,IAAI,IAAI;IAcxB,QAAQ,CAAC,MAAM,IAAI,IAAI;IACvB,QAAQ,CAAC,OAAO,IAAI,IAAI;IAExB,QAAQ,CAAC,SAAS,CACd,OAAO,EAAE,kBAAkB,CAAC,CAAC,CAAC,EAC9B,OAAO,CAAC,EAAE,mBAAmB,EAC7B,SAAS,CAAC,EAAE,qBAAqB,GAClC,UAAU;CAChB"}
@@ -1 +1 @@
1
- {"version":3,"file":"observable.d.ts","sourceRoot":"","sources":["../../../src/base/observable.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACR,UAAU,EACV,cAAc,EACd,kBAAkB,EAClB,mBAAmB,EACnB,qBAAqB,EACrB,WAAW,EACd,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAE/C;;GAEG;AACH,MAAM,MAAM,gBAAgB,GAAG,UAAU,GAAG,SAAS,GAAG,OAAO,GAAG,OAAO,CAAC;AAE1E;;GAEG;AACH,MAAM,WAAW,WAAW,CAAC,CAAC,CAAE,SAAQ,cAAc,CAAC,CAAC,CAAC;IACrD,IAAI,MAAM,IAAI,gBAAgB,CAAC;IAC/B,IAAI,MAAM,CAAC,MAAM,EAAE,gBAAgB,EAAE;IACrC,iBAAiB,CAAC,SAAS,EAAE,SAAS,GAAG,IAAI,CAAC;IAC9C,mBAAmB,CAAC,SAAS,EAAE,SAAS,GAAG,IAAI,CAAC;IAChD,gBAAgB,IAAI,IAAI,CAAC;IACzB,SAAS,CACL,OAAO,EAAE,kBAAkB,CAAC,CAAC,CAAC,EAC9B,OAAO,CAAC,EAAE,mBAAmB,EAC7B,SAAS,CAAC,EAAE,qBAAqB,GAClC,UAAU,CAAC;CACjB;AAED;;GAEG;AACH,8BAAsB,UAAU,CAAC,CAAC,CAAE,SAAQ,UAAW,YAAW,WAAW,CAAC,CAAC,CAAC;IAC5E,OAAO,CAAC,WAAW,CAAwB;IAC3C,SAAS,CAAC,OAAO,EAAE,gBAAgB,CAAc;IAEjD,IAAI,MAAM,IAAI,gBAAgB,CAG7B;IAED,IAAI,MAAM,CAAC,MAAM,EAAE,gBAAgB,EAGlC;IAED,iBAAiB,CAAC,SAAS,EAAE,SAAS,GAAG,IAAI;IAK7C,mBAAmB,CAAC,SAAS,EAAE,SAAS,GAAG,IAAI;IAK/C,gBAAgB,IAAI,IAAI;IAOxB,KAAK,CAAC,OAAO,EAAE,WAAW,GAAG,IAAI;IAKjC,OAAO,IAAI,IAAI;IAKN,OAAO,IAAI,IAAI;IAUxB,QAAQ,CAAC,SAAS,CACd,OAAO,EAAE,kBAAkB,CAAC,CAAC,CAAC,EAC9B,OAAO,CAAC,EAAE,mBAAmB,EAC7B,SAAS,CAAC,EAAE,qBAAqB,GAClC,UAAU;CAChB"}
1
+ {"version":3,"file":"observable.d.ts","sourceRoot":"","sources":["../../../src/base/observable.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACR,UAAU,EACV,cAAc,EACd,kBAAkB,EAClB,mBAAmB,EACnB,qBAAqB,EACrB,WAAW,EACd,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAE/C;;GAEG;AACH,MAAM,MAAM,gBAAgB,GAAG,UAAU,GAAG,SAAS,GAAG,OAAO,GAAG,OAAO,CAAC;AAE1E;;GAEG;AACH,MAAM,WAAW,WAAW,CAAC,CAAC,CAAE,SAAQ,cAAc,CAAC,CAAC,CAAC;IACrD,IAAI,MAAM,IAAI,gBAAgB,CAAC;IAC/B,IAAI,MAAM,CAAC,MAAM,EAAE,gBAAgB,EAAE;IACrC,iBAAiB,CAAC,SAAS,EAAE,SAAS,GAAG,IAAI,CAAC;IAC9C,mBAAmB,CAAC,SAAS,EAAE,SAAS,GAAG,IAAI,CAAC;IAChD,gBAAgB,IAAI,IAAI,CAAC;IACzB,SAAS,CACL,OAAO,EAAE,kBAAkB,CAAC,CAAC,CAAC,EAC9B,OAAO,CAAC,EAAE,mBAAmB,EAC7B,SAAS,CAAC,EAAE,qBAAqB,GAClC,UAAU,CAAC;CACjB;AAED;;GAEG;AACH,8BAAsB,UAAU,CAAC,CAAC,CAAE,SAAQ,UAAW,YAAW,WAAW,CAAC,CAAC,CAAC;IAC5E,OAAO,CAAC,WAAW,CAAwB;IAC3C,SAAS,CAAC,OAAO,EAAE,gBAAgB,CAAc;IAEjD,IAAI,MAAM,IAAI,gBAAgB,CAG7B;IAED,IAAI,MAAM,CAAC,MAAM,EAAE,gBAAgB,EAGlC;IAED,iBAAiB,CAAC,SAAS,EAAE,SAAS,GAAG,IAAI;IAK7C,mBAAmB,CAAC,SAAS,EAAE,SAAS,GAAG,IAAI;IAK/C,gBAAgB,IAAI,IAAI;IAOxB,KAAK,CAAC,OAAO,EAAE,WAAW,GAAG,IAAI;IAKjC,OAAO,IAAI,IAAI;IAKN,OAAO,IAAI,IAAI;IAWxB,QAAQ,CAAC,SAAS,CACd,OAAO,EAAE,kBAAkB,CAAC,CAAC,CAAC,EAC9B,OAAO,CAAC,EAAE,mBAAmB,EAC7B,SAAS,CAAC,EAAE,qBAAqB,GAClC,UAAU;CAChB"}
@@ -9,12 +9,21 @@ export interface IObserver {
9
9
  clearDependencies(): void;
10
10
  notify(): void;
11
11
  execute(): void;
12
+ /**
13
+ * Called by a dependency's `dispose()` on each of its remaining dependents, so an
14
+ * observer already queued for the next flush can skip that run instead of reading
15
+ * through the now-disposed dependency and throwing (A2-SEM-1).
16
+ */
17
+ markDependencyDisposed(): void;
12
18
  }
13
19
  /**
14
20
  * Base implementation managing dependency tracking for reactive observers.
15
21
  */
16
22
  export declare abstract class Observer extends Disposable implements IObserver {
17
23
  private _dependencies;
24
+ /** Set when a dependency disposed while this observer was queued; consumed by the next execute(). */
25
+ protected _dependencyDisposed: boolean;
26
+ markDependencyDisposed(): void;
18
27
  registerDependency(dependency: IObservable<unknown>): void;
19
28
  unregisterDependency(dependency: IObservable<unknown>): void;
20
29
  clearDependencies(): void;
@@ -1 +1 @@
1
- {"version":3,"file":"observer.d.ts","sourceRoot":"","sources":["../../../src/base/observer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAEnD;;GAEG;AACH,MAAM,WAAW,SAAS;IACtB,kBAAkB,CAAC,UAAU,EAAE,WAAW,CAAC,OAAO,CAAC,GAAG,IAAI,CAAC;IAC3D,oBAAoB,CAAC,UAAU,EAAE,WAAW,CAAC,OAAO,CAAC,GAAG,IAAI,CAAC;IAC7D,iBAAiB,IAAI,IAAI,CAAC;IAC1B,MAAM,IAAI,IAAI,CAAC;IACf,OAAO,IAAI,IAAI,CAAC;CACnB;AAED;;GAEG;AACH,8BAAsB,QAAS,SAAQ,UAAW,YAAW,SAAS;IAClE,OAAO,CAAC,aAAa,CAAmC;IAExD,kBAAkB,CAAC,UAAU,EAAE,WAAW,CAAC,OAAO,CAAC,GAAG,IAAI;IAM1D,oBAAoB,CAAC,UAAU,EAAE,WAAW,CAAC,OAAO,CAAC,GAAG,IAAI;IAM5D,iBAAiB,IAAI,IAAI;IAQhB,OAAO,IAAI,IAAI;IAQxB,QAAQ,CAAC,MAAM,IAAI,IAAI;IACvB,QAAQ,CAAC,OAAO,IAAI,IAAI;CAC3B"}
1
+ {"version":3,"file":"observer.d.ts","sourceRoot":"","sources":["../../../src/base/observer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAEnD;;GAEG;AACH,MAAM,WAAW,SAAS;IACtB,kBAAkB,CAAC,UAAU,EAAE,WAAW,CAAC,OAAO,CAAC,GAAG,IAAI,CAAC;IAC3D,oBAAoB,CAAC,UAAU,EAAE,WAAW,CAAC,OAAO,CAAC,GAAG,IAAI,CAAC;IAC7D,iBAAiB,IAAI,IAAI,CAAC;IAC1B,MAAM,IAAI,IAAI,CAAC;IACf,OAAO,IAAI,IAAI,CAAC;IAChB;;;;OAIG;IACH,sBAAsB,IAAI,IAAI,CAAC;CAClC;AAED;;GAEG;AACH,8BAAsB,QAAS,SAAQ,UAAW,YAAW,SAAS;IAClE,OAAO,CAAC,aAAa,CAAmC;IACxD,qGAAqG;IACrG,SAAS,CAAC,mBAAmB,UAAS;IAEtC,sBAAsB,IAAI,IAAI;IAI9B,kBAAkB,CAAC,UAAU,EAAE,WAAW,CAAC,OAAO,CAAC,GAAG,IAAI;IAM1D,oBAAoB,CAAC,UAAU,EAAE,WAAW,CAAC,OAAO,CAAC,GAAG,IAAI;IAM5D,iBAAiB,IAAI,IAAI;IAQhB,OAAO,IAAI,IAAI;IAQxB,QAAQ,CAAC,MAAM,IAAI,IAAI;IACvB,QAAQ,CAAC,OAAO,IAAI,IAAI;CAC3B"}
@@ -1 +1 @@
1
- {"version":3,"file":"solid.d.ts","sourceRoot":"","sources":["../../../src/converters/solid.ts"],"names":[],"mappings":"AAAA,OAAO,EAAoD,KAAK,QAAQ,EAAwB,MAAM,UAAU,CAAC;AACjH,OAAO,EAAmB,KAAK,WAAW,EAAE,KAAK,SAAS,EAAE,KAAK,UAAU,EAAa,MAAM,iBAAiB,CAAC;AAoEhH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4CG;AACH,wBAAgB,IAAI,CAAC,CAAC,EAAE,IAAI,EAAE,SAAS,CAAC,CAAC,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;AACzD,wBAAgB,IAAI,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,WAAW,KAAK,UAAU,CAAC,CAAC,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC"}
1
+ {"version":3,"file":"solid.d.ts","sourceRoot":"","sources":["../../../src/converters/solid.ts"],"names":[],"mappings":"AAAA,OAAO,EAAoD,KAAK,QAAQ,EAAwB,MAAM,UAAU,CAAC;AACjH,OAAO,EAAmB,KAAK,WAAW,EAAE,KAAK,SAAS,EAAE,KAAK,UAAU,EAAa,MAAM,iBAAiB,CAAC;AA8EhH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4CG;AACH,wBAAgB,IAAI,CAAC,CAAC,EAAE,IAAI,EAAE,SAAS,CAAC,CAAC,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;AACzD,wBAAgB,IAAI,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,WAAW,KAAK,UAAU,CAAC,CAAC,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"effectNode.d.ts","sourceRoot":"","sources":["../../../src/nodes/effectNode.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACR,eAAe,EACf,UAAU,EACV,kBAAkB,EAClB,mBAAmB,EACnB,qBAAqB,EACxB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAkB,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAG5D;;;;;;;;;;;GAWG;AACH,qBAAa,UAAU,CAAC,CAAC,CAAE,SAAQ,QAAS,YAAW,UAAU;IAC7D,OAAO,CAAC,KAAK,CAAqB;IAClC,OAAO,CAAC,OAAO,CAAwB;IACvC,OAAO,CAAC,QAAQ,CAAC,CAAsB;IACvC,OAAO,CAAC,UAAU,CAAC,CAAwB;IAC3C,wFAAwF;IACxF,OAAO,CAAC,OAAO,CAAS;IACxB,2FAA2F;IAC3F,OAAO,CAAC,qBAAqB,CAAS;IACtC,yEAAyE;IACzE,OAAO,CAAC,YAAY,CAAK;IACzB,8DAA8D;IAC9D,OAAO,CAAC,cAAc,CAAK;gBAGvB,IAAI,EAAE,eAAe,CAAC,CAAC,CAAC,EACxB,MAAM,EAAE,kBAAkB,CAAC,CAAC,CAAC,EAC7B,OAAO,CAAC,EAAE,mBAAmB,EAC7B,SAAS,CAAC,EAAE,qBAAqB;IAYrC,MAAM,IAAI,IAAI;IAsBd,OAAO,IAAI,IAAI;CAgClB"}
1
+ {"version":3,"file":"effectNode.d.ts","sourceRoot":"","sources":["../../../src/nodes/effectNode.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACR,eAAe,EACf,UAAU,EACV,kBAAkB,EAClB,mBAAmB,EACnB,qBAAqB,EACxB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAkB,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAG5D;;;;;;;;;;;GAWG;AACH,qBAAa,UAAU,CAAC,CAAC,CAAE,SAAQ,QAAS,YAAW,UAAU;IAC7D,OAAO,CAAC,KAAK,CAAqB;IAClC,OAAO,CAAC,OAAO,CAAwB;IACvC,OAAO,CAAC,QAAQ,CAAC,CAAsB;IACvC,OAAO,CAAC,UAAU,CAAC,CAAwB;IAC3C,wFAAwF;IACxF,OAAO,CAAC,OAAO,CAAS;IACxB,2FAA2F;IAC3F,OAAO,CAAC,qBAAqB,CAAS;IACtC,yEAAyE;IACzE,OAAO,CAAC,YAAY,CAAK;IACzB,8DAA8D;IAC9D,OAAO,CAAC,cAAc,CAAK;gBAGvB,IAAI,EAAE,eAAe,CAAC,CAAC,CAAC,EACxB,MAAM,EAAE,kBAAkB,CAAC,CAAC,CAAC,EAC7B,OAAO,CAAC,EAAE,mBAAmB,EAC7B,SAAS,CAAC,EAAE,qBAAqB;IAYrC,MAAM,IAAI,IAAI;IAsBd,OAAO,IAAI,IAAI;CA6ClB"}
@@ -1,11 +1,18 @@
1
1
  import { FlowEffect, FlowOnDataListener, FlowOnErrorListener, FlowOnPendingListener, FlowTracker, NotPromise } from '../api/index.js';
2
2
  import { Node } from '../base/index.js';
3
3
  import { Scheduler } from '../schedulers/index.js';
4
+ /**
5
+ * Global-registry symbol branding a {@link ValueNode} instance, so `from()` can recognize a node
6
+ * built by a different copy of the library — where its class objects, and thus `instanceof`, differ.
7
+ * @internal
8
+ */
9
+ export declare const PICOFLOW_VALUE_NODE: unique symbol;
4
10
  /**
5
11
  * Base class for reactive values that compute, cache, and propagate changes through the dependency graph.
6
12
  * @internal
7
13
  */
8
14
  export declare abstract class ValueNode<T> extends Node<T> {
15
+ readonly [PICOFLOW_VALUE_NODE] = true;
9
16
  protected abstract _scheduler: Scheduler;
10
17
  protected _value?: NotPromise<T>;
11
18
  protected _error?: unknown;
@@ -1 +1 @@
1
- {"version":3,"file":"valueNode.d.ts","sourceRoot":"","sources":["../../../src/nodes/valueNode.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACR,UAAU,EACV,kBAAkB,EAClB,mBAAmB,EACnB,qBAAqB,EACrB,WAAW,EACX,UAAU,EACb,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAkB,IAAI,EAAwC,MAAM,kBAAkB,CAAC;AAC9F,OAAO,EAAgB,KAAK,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAGtE;;;GAGG;AACH,8BAAsB,SAAS,CAAC,CAAC,CAAE,SAAQ,IAAI,CAAC,CAAC,CAAC;IAC9C,SAAS,CAAC,QAAQ,CAAC,UAAU,EAAE,SAAS,CAAC;IACzC,SAAS,CAAC,MAAM,CAAC,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC;IACjC,SAAS,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC;IAElB,KAAK,CAAC,OAAO,EAAE,WAAW,GAAG,IAAI;IA6BjC,MAAM,IAAI,IAAI;IAUd,OAAO,IAAI,IAAI;IAKxB,GAAG,CAAC,OAAO,EAAE,WAAW,GAAG,CAAC;IA8BtB,IAAI,IAAI,OAAO,CAAC,CAAC,CAAC;IAkCxB,OAAO,IAAI,IAAI;IAUf,SAAS,CACL,OAAO,EAAE,kBAAkB,CAAC,CAAC,CAAC,EAC9B,OAAO,CAAC,EAAE,mBAAmB,EAC7B,SAAS,CAAC,EAAE,qBAAqB,GAClC,UAAU;CAKhB"}
1
+ {"version":3,"file":"valueNode.d.ts","sourceRoot":"","sources":["../../../src/nodes/valueNode.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACR,UAAU,EACV,kBAAkB,EAClB,mBAAmB,EACnB,qBAAqB,EACrB,WAAW,EACX,UAAU,EACb,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAkB,IAAI,EAAwC,MAAM,kBAAkB,CAAC;AAC9F,OAAO,EAAgB,KAAK,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAGtE;;;;GAIG;AACH,eAAO,MAAM,mBAAmB,eAA8B,CAAC;AAE/D;;;GAGG;AACH,8BAAsB,SAAS,CAAC,CAAC,CAAE,SAAQ,IAAI,CAAC,CAAC,CAAC;IAC9C,QAAQ,CAAC,CAAC,mBAAmB,CAAC,QAAQ;IACtC,SAAS,CAAC,QAAQ,CAAC,UAAU,EAAE,SAAS,CAAC;IACzC,SAAS,CAAC,MAAM,CAAC,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC;IACjC,SAAS,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC;IAElB,KAAK,CAAC,OAAO,EAAE,WAAW,GAAG,IAAI;IA6BjC,MAAM,IAAI,IAAI;IAUd,OAAO,IAAI,IAAI;IAKxB,GAAG,CAAC,OAAO,EAAE,WAAW,GAAG,CAAC;IA8BtB,IAAI,IAAI,OAAO,CAAC,CAAC,CAAC;IAkCxB,OAAO,IAAI,IAAI;IAUf,SAAS,CACL,OAAO,EAAE,kBAAkB,CAAC,CAAC,CAAC,EAC9B,OAAO,CAAC,EAAE,mBAAmB,EAC7B,SAAS,CAAC,EAAE,qBAAqB,GAClC,UAAU;CAKhB"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ersbeth/picoflow",
3
- "version": "2.1.0",
3
+ "version": "2.2.0",
4
4
  "description": "Minimal Dataflow library for TypeScript",
5
5
  "type": "module",
6
6
  "packageManager": "pnpm@11.9.0",
@@ -23,10 +23,11 @@
23
23
  "test:coverage": "pnpm exec vitest run --coverage",
24
24
  "test:browser": "pnpm exec vitest --config=vitest.browser.config.ts",
25
25
  "test:browser:coverage": "pnpm exec vitest run --config=vitest.browser.config.ts --coverage",
26
+ "test:coverage:merge": "rm -rf .vitest-reports && pnpm exec vitest run --coverage --reporter=blob --outputFile=.vitest-reports/node.json && pnpm exec vitest run --config=vitest.browser.config.ts --coverage --reporter=blob --outputFile=.vitest-reports/browser.json && pnpm exec vitest --mergeReports=.vitest-reports --coverage",
26
27
  "ci:check": "pnpm exec tsc --noEmit",
27
28
  "ci:lint": "pnpm exec biome check .",
28
- "ci:test": "pnpm exec vitest run",
29
- "ci:test:browser": "pnpm exec vitest run --config=vitest.browser.config.ts",
29
+ "ci:test": "pnpm exec vitest run --coverage",
30
+ "ci:test:browser": "pnpm exec vitest run --config=vitest.browser.config.ts --coverage",
30
31
  "ci:pack:smoke": "node tools/release/smoke-tarball.mjs",
31
32
  "ci:release:check": "node tools/release/check-release.mjs",
32
33
  "playwright:install": "playwright install --with-deps chromium",
@@ -69,7 +70,7 @@
69
70
  },
70
71
  "repository": {
71
72
  "type": "git",
72
- "url": "git+ssh://git@gitlab.com/ersbeth-web/picoflow.git"
73
+ "url": "git+https://gitlab.com/ersbeth-web/picoflow.git"
73
74
  },
74
75
  "author": "Elisabeth Rousset",
75
76
  "license": "MIT",