@ersbeth/picoflow 2.3.2 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (70) hide show
  1. package/README.md +34 -5
  2. package/SKILL.md +130 -16
  3. package/dist/index.d.ts +767 -0
  4. package/dist/index.js +544 -0
  5. package/dist/inspect.d.ts +252 -0
  6. package/dist/inspect.js +300 -0
  7. package/dist/shared.d.ts +361 -0
  8. package/dist/shared.js +1496 -0
  9. package/dist/shared2.d.ts +93 -0
  10. package/dist/shared2.js +59 -0
  11. package/dist/shared3.d.ts +54 -0
  12. package/dist/shared3.js +17 -0
  13. package/dist/{types/converters/solid.d.ts → solid.d.ts} +10 -8
  14. package/dist/solid.js +63 -0
  15. package/package.json +37 -25
  16. package/dist/picoflow.js +0 -1283
  17. package/dist/types/converters/index.d.ts +0 -1
  18. package/dist/types/core/api/base/flowConfig.d.ts +0 -17
  19. package/dist/types/core/api/base/flowDisposable.d.ts +0 -40
  20. package/dist/types/core/api/base/flowErrors.d.ts +0 -1
  21. package/dist/types/core/api/base/flowObservable.d.ts +0 -26
  22. package/dist/types/core/api/base/flowPrimitiveOptions.d.ts +0 -14
  23. package/dist/types/core/api/base/flowSubscribable.d.ts +0 -78
  24. package/dist/types/core/api/base/flowTracker.d.ts +0 -7
  25. package/dist/types/core/api/base/index.d.ts +0 -7
  26. package/dist/types/core/api/index.d.ts +0 -2
  27. package/dist/types/core/api/nodes/async/flowConstantAsync.d.ts +0 -32
  28. package/dist/types/core/api/nodes/async/flowDerivationAsync.d.ts +0 -37
  29. package/dist/types/core/api/nodes/async/flowStateAsync.d.ts +0 -42
  30. package/dist/types/core/api/nodes/async/flowWritableDerivationAsync.d.ts +0 -31
  31. package/dist/types/core/api/nodes/async/index.d.ts +0 -4
  32. package/dist/types/core/api/nodes/collections/flowArray.d.ts +0 -138
  33. package/dist/types/core/api/nodes/collections/flowMap.d.ts +0 -100
  34. package/dist/types/core/api/nodes/collections/index.d.ts +0 -2
  35. package/dist/types/core/api/nodes/flowEffect.d.ts +0 -28
  36. package/dist/types/core/api/nodes/flowSignal.d.ts +0 -26
  37. package/dist/types/core/api/nodes/flowValue.d.ts +0 -35
  38. package/dist/types/core/api/nodes/index.d.ts +0 -7
  39. package/dist/types/core/api/nodes/sync/flowConstant.d.ts +0 -30
  40. package/dist/types/core/api/nodes/sync/flowDerivation.d.ts +0 -37
  41. package/dist/types/core/api/nodes/sync/flowState.d.ts +0 -40
  42. package/dist/types/core/api/nodes/sync/flowWritableDerivation.d.ts +0 -29
  43. package/dist/types/core/api/nodes/sync/index.d.ts +0 -4
  44. package/dist/types/core/api/nodes/utils.d.ts +0 -22
  45. package/dist/types/core/base/dependenciesRegistry.d.ts +0 -1
  46. package/dist/types/core/base/dependentsRegistry.d.ts +0 -1
  47. package/dist/types/core/base/disposable.d.ts +0 -15
  48. package/dist/types/core/base/errors.d.ts +0 -31
  49. package/dist/types/core/base/executionStack.d.ts +0 -31
  50. package/dist/types/core/base/index.d.ts +0 -8
  51. package/dist/types/core/base/node.d.ts +0 -27
  52. package/dist/types/core/base/observable.d.ts +0 -34
  53. package/dist/types/core/base/observer.d.ts +0 -33
  54. package/dist/types/core/nodes/actionNode.d.ts +0 -1
  55. package/dist/types/core/nodes/arrayNode.d.ts +0 -1
  56. package/dist/types/core/nodes/effectNode.d.ts +0 -1
  57. package/dist/types/core/nodes/index.d.ts +0 -8
  58. package/dist/types/core/nodes/mapNode.d.ts +0 -1
  59. package/dist/types/core/nodes/signalNode.d.ts +0 -1
  60. package/dist/types/core/nodes/valueAsyncNode.d.ts +0 -1
  61. package/dist/types/core/nodes/valueNode.d.ts +0 -1
  62. package/dist/types/core/nodes/valueSyncNode.d.ts +0 -1
  63. package/dist/types/core/schedulers/asyncResolver.d.ts +0 -1
  64. package/dist/types/core/schedulers/asyncScheduler.d.ts +0 -1
  65. package/dist/types/core/schedulers/index.d.ts +0 -4
  66. package/dist/types/core/schedulers/pendingError.d.ts +0 -1
  67. package/dist/types/core/schedulers/scheduler.d.ts +0 -1
  68. package/dist/types/core/schedulers/syncResolver.d.ts +0 -1
  69. package/dist/types/core/schedulers/syncScheduler.d.ts +0 -1
  70. package/dist/types/index.d.ts +0 -2
package/dist/index.js ADDED
@@ -0,0 +1,544 @@
1
+ import { _ as PicoFlowPreconditionError, a as ReadableNode, g as PicoFlowInternalError, h as PicoFlowError, m as PicoFlowDisposedError, n as asyncCore, o as EffectNode, p as PicoFlowCycleError, r as syncCore, u as ExecutionStack } from "./shared.js";
2
+ import { n as subscribe, r as DerivationNode, t as derivation } from "./shared2.js";
3
+ import { t as SignalNode } from "./shared3.js";
4
+
5
+ //#region src/core/api/base/flowConfig.ts
6
+ /**
7
+ * Installs a global handler for errors that escape the reactive flush.
8
+ *
9
+ * All reactive work — recomputing derivations, running effects — happens inside an
10
+ * asynchronous flush. Without this hook, an error escaping the flush (an effect callback
11
+ * that throws with no `onError`, or a feedback loop between two effects) becomes an
12
+ * uncaught exception, which terminates a Node process. Installing a handler here makes
13
+ * that error catchable instead.
14
+ *
15
+ * Defaults to `console.error`. The handler replaces any previously installed handler —
16
+ * it is not additive.
17
+ *
18
+ * @param handler - Called with the error that escaped the flush.
19
+ *
20
+ * @public
21
+ */
22
+ function onFlushError(handler) {
23
+ ExecutionStack.setFlushErrorHandler(handler);
24
+ }
25
+ /**
26
+ * Returns the scheduler to its just-started state: both queues emptied, any scheduled flush
27
+ * cancelled, and the flush error handler back to its `console.error` default.
28
+ *
29
+ * Scheduling is process-global, so reactive work left over from one test can still be waiting when
30
+ * the next one starts, and a handler installed with {@link onFlushError} stays installed. Calling
31
+ * this from an `afterEach` gives each test a clean scheduler. It is the supported alternative to
32
+ * reaching into internals, and applications testing their own code need it for the same reason
33
+ * PicoFlow's own suite does.
34
+ *
35
+ * Queued work is **discarded, not run** — this cancels pending reactivity rather than flushing it.
36
+ * Primitives created before the call stay usable, but any recomputation that was waiting is lost:
37
+ * those nodes only recompute once something notifies them again. To let pending work complete
38
+ * instead, `await` a value with `pick()`.
39
+ *
40
+ * @public
41
+ */
42
+ function reset() {
43
+ ExecutionStack.reset();
44
+ }
45
+
46
+ //#endregion
47
+ //#region src/core/api/base/flowDisposable.ts
48
+ /**
49
+ * Type guard to check if an object implements the FlowDisposable interface.
50
+ *
51
+ * Useful for conditionally disposing objects that may or may not be disposable,
52
+ * such as when cleaning up mixed collections of values. Returns true if the object
53
+ * has a `dispose` method, providing type-safe access to disposal functionality.
54
+ *
55
+ * @param obj - The object to check
56
+ * @returns True if the object implements FlowDisposable, false otherwise
57
+ *
58
+ * @public
59
+ */
60
+ function isDisposable(obj) {
61
+ return obj !== null && obj !== void 0 && typeof obj.dispose === "function";
62
+ }
63
+
64
+ //#endregion
65
+ //#region src/core/nodes/constantNode.ts
66
+ /**
67
+ * The primitive behind `constant()` and `constantAsync()`: a {@link ReadableNode} and nothing more.
68
+ * It computes once, lazily, and carries no mutator on its prototype chain (#26, A2-SEM-3).
69
+ * @internal
70
+ */
71
+ var ConstantNode = class extends ReadableNode {};
72
+
73
+ //#endregion
74
+ //#region src/core/api/nodes/async/flowConstantAsync.ts
75
+ function constantAsync(valueOrInitializer, options) {
76
+ return new ConstantNode(asyncCore(valueOrInitializer, options), "constantAsync");
77
+ }
78
+
79
+ //#endregion
80
+ //#region src/core/api/nodes/async/flowDerivationAsync.ts
81
+ /**
82
+ * Creates an async derived value that automatically recomputes when dependencies change.
83
+ *
84
+ * The async compute function tracks dependencies and returns a promise. When any tracked dependency changes,
85
+ * the function runs again and returns a new promise. The resolved value is cached until the next change.
86
+ * While the promise is pending, reactive computations that access this value receive PendingError and automatically
87
+ * retry once resolved. Use for derived data from async sources like filtered API results or computed database queries.
88
+ *
89
+ * @param compute - Async function that accesses dependencies and returns a promise of the derived value
90
+ * @param options - Optional settings; `name` identifies this primitive in error messages, `equals` overrides the
91
+ * default `===` change detection, `eager` recomputes on dirty instead of on read (#118)
92
+ * @returns A FlowDerivationAsync that provides read-only access to the resolved computed value
93
+ *
94
+ * @public
95
+ */
96
+ function derivationAsync(compute, options) {
97
+ return new DerivationNode(asyncCore(compute, options, true), "derivationAsync");
98
+ }
99
+
100
+ //#endregion
101
+ //#region src/core/nodes/stateNode.ts
102
+ /**
103
+ * The primitive behind `state()` and `stateAsync()`: readable and writable. `set` replaces, `update`
104
+ * derives the next value from the stabilised current one (A2-TYPE-1, #43). `I` is the core's input
105
+ * type — the value for a sync state, a promise of it for an async one. No `refresh`: a state has
106
+ * nothing to recompute, and re-running its initializer would undo every write since.
107
+ * @internal
108
+ */
109
+ var StateNode = class extends ReadableNode {
110
+ get _core() {
111
+ return super._core;
112
+ }
113
+ set(input) {
114
+ this._core.overwrite(input);
115
+ }
116
+ update(updater) {
117
+ this._core.update(updater);
118
+ }
119
+ /** Notifies dependents without changing the value — a write, hence its place here (#132). */
120
+ trigger() {
121
+ this._core.trigger();
122
+ }
123
+ };
124
+
125
+ //#endregion
126
+ //#region src/core/api/nodes/async/flowStateAsync.ts
127
+ function stateAsync(valueOrInitializer, options) {
128
+ return new StateNode(asyncCore(valueOrInitializer, options), "stateAsync");
129
+ }
130
+
131
+ //#endregion
132
+ //#region src/core/nodes/writableDerivationNode.ts
133
+ /**
134
+ * The primitive behind `writableDerivation()` and `writableDerivationAsync()`: a {@link StateNode}
135
+ * that also recomputes from its dependencies, hence `refresh()` on top of `set` / `update`. Each
136
+ * mutator is a one-line delegation to the core, so declaring all three here duplicates nothing —
137
+ * which is what lets the sync/async × state/derivation diamond go (#114, step 4 of #110).
138
+ * @internal
139
+ */
140
+ var WritableDerivationNode = class extends StateNode {
141
+ refresh() {
142
+ this._core.refresh();
143
+ }
144
+ };
145
+
146
+ //#endregion
147
+ //#region src/core/api/nodes/async/flowWritableDerivationAsync.ts
148
+ /**
149
+ * Creates an async derived value that recomputes automatically but can also be manually overridden.
150
+ *
151
+ * The async compute function tracks dependencies and returns a promise. When any tracked dependency changes,
152
+ * the function runs again and returns a new promise. However, you can also call `set()` to override the computed
153
+ * value with a new promise. Use for async values that are normally derived but need occasional manual adjustments,
154
+ * such as editable async calculated fields or user-correctable async totals.
155
+ *
156
+ * @param compute - Async function that accesses dependencies and returns a promise of the derived value
157
+ * @param options - Optional settings; `name` identifies this primitive in error messages, `equals` overrides the
158
+ * default `===` change detection, `eager` recomputes on dirty instead of on read (#118)
159
+ * @returns A FlowWritableDerivationAsync that provides both reactive async computation and manual control
160
+ *
161
+ * @public
162
+ */
163
+ function writableDerivationAsync(compute, options) {
164
+ return new WritableDerivationNode(asyncCore(compute, options, true), "writableDerivationAsync");
165
+ }
166
+
167
+ //#endregion
168
+ //#region src/core/nodes/actionNode.ts
169
+ /**
170
+ * Reactive state that tracks the latest action while delivering every emitted action
171
+ * to `.subscribe()` callbacks, including multiple mutations within the same batch.
172
+ *
173
+ * Two read models:
174
+ * - get() / pick(): last-write-wins snapshot (current action value).
175
+ * - subscribe(): event stream — one onData call per emitted action, even when several
176
+ * mutations happen before the next flush. Each subscriber owns its own queue so
177
+ * delivery is not shared or stolen between subscribers.
178
+ *
179
+ * @internal
180
+ */
181
+ var ActionNode = class extends StateNode {
182
+ #slots = /* @__PURE__ */ new Set();
183
+ constructor(value, name) {
184
+ super(syncCore(value, { name }), "action");
185
+ }
186
+ /** The engine's cached value — an action node is built with a value and is always resolved. */
187
+ get _value() {
188
+ return this._core.current;
189
+ }
190
+ _enqueueForSubscribers(action) {
191
+ for (const slot of this.#slots) slot.queue.push(action);
192
+ }
193
+ set(value) {
194
+ this._core.assertAlive();
195
+ if (this.status === "resolved" && value === this._value) return;
196
+ this._enqueueForSubscribers(value);
197
+ super.set(value);
198
+ }
199
+ update(updater) {
200
+ this._core.assertAlive();
201
+ let action;
202
+ try {
203
+ action = updater(this._value);
204
+ } catch (error) {
205
+ this._core.fail(error);
206
+ return;
207
+ }
208
+ this.set(action);
209
+ }
210
+ subscribe(onValue, onError, onPending, options) {
211
+ this._core.assertAlive();
212
+ const slot = { queue: [] };
213
+ this.#slots.add(slot);
214
+ const effect = new EffectNode((tracker) => {
215
+ this.watch(tracker);
216
+ if (slot.queue.length === 0) return [this.get(tracker)];
217
+ return slot.queue.splice(0);
218
+ }, (actions) => {
219
+ for (const action of actions) onValue(action);
220
+ }, onError, onPending, options?.name);
221
+ effect.onDispose(() => {
222
+ this.#slots.delete(slot);
223
+ });
224
+ return effect;
225
+ }
226
+ dispose() {
227
+ super.dispose();
228
+ this.#slots.clear();
229
+ }
230
+ };
231
+
232
+ //#endregion
233
+ //#region src/core/nodes/arrayNode.ts
234
+ /**
235
+ * Internal implementation of reactive array with mutation tracking.
236
+ * @internal
237
+ */
238
+ var ArrayNode = class extends ReadableNode {
239
+ $lastAction;
240
+ get _core() {
241
+ return super._core;
242
+ }
243
+ /** The live backing store, owned by the engine and mutated in place here. */
244
+ get _value() {
245
+ return this._core.current;
246
+ }
247
+ set _value(value) {
248
+ this._core.current = value;
249
+ }
250
+ constructor(value = [], name) {
251
+ super(syncCore(value, { name }), "array");
252
+ this.$lastAction = new ActionNode({
253
+ type: "set",
254
+ setItems: value,
255
+ clearedItems: []
256
+ }, name && `${name}.$lastAction`);
257
+ }
258
+ /** Notifies dependents without changing the contents. */
259
+ trigger() {
260
+ this._core.trigger();
261
+ }
262
+ set(items) {
263
+ this._core.assertAlive();
264
+ const previousValue = this._value;
265
+ if (!this._core.overwrite(items)) return;
266
+ this.$lastAction.set({
267
+ type: "set",
268
+ setItems: this._value,
269
+ clearedItems: previousValue
270
+ });
271
+ }
272
+ setAt(index, item) {
273
+ this._core.assertAlive();
274
+ if (index < 0 || index >= this._value.length || !Number.isInteger(index)) throw new PicoFlowPreconditionError("[PicoFlow] Index out of bounds");
275
+ const previousValue = this._value[index];
276
+ this._value[index] = item;
277
+ this._core.notifyDependents();
278
+ this.$lastAction.set({
279
+ type: "setAt",
280
+ index,
281
+ setItem: item,
282
+ clearedItem: previousValue
283
+ });
284
+ }
285
+ push(item) {
286
+ this._core.assertAlive();
287
+ this._value.push(item);
288
+ this._core.notifyDependents();
289
+ this.$lastAction.set({
290
+ type: "push",
291
+ addedItem: item
292
+ });
293
+ }
294
+ pop() {
295
+ this._core.assertAlive();
296
+ if (this._value.length === 0) return void 0;
297
+ const item = this._value.pop();
298
+ this._core.notifyDependents();
299
+ this.$lastAction.set({
300
+ type: "pop",
301
+ removedItem: item
302
+ });
303
+ return item;
304
+ }
305
+ unshift(item) {
306
+ this._core.assertAlive();
307
+ this._value.unshift(item);
308
+ this._core.notifyDependents();
309
+ this.$lastAction.set({
310
+ type: "unshift",
311
+ addedItem: item
312
+ });
313
+ }
314
+ shift() {
315
+ this._core.assertAlive();
316
+ if (this._value.length === 0) return void 0;
317
+ const item = this._value.shift();
318
+ this._core.notifyDependents();
319
+ this.$lastAction.set({
320
+ type: "shift",
321
+ removedItem: item
322
+ });
323
+ return item;
324
+ }
325
+ splice(start, deleteCount, ...newItems) {
326
+ this._core.assertAlive();
327
+ const length = this._value.length;
328
+ if (!Number.isInteger(start) || start < 0 || start > length) throw new PicoFlowPreconditionError("[PicoFlow] Index out of bounds");
329
+ if (!Number.isInteger(deleteCount) || deleteCount < 0 || deleteCount > length - start) throw new PicoFlowPreconditionError("[PicoFlow] Delete count out of bounds");
330
+ const items = this._value.splice(start, deleteCount, ...newItems);
331
+ this._core.notifyDependents();
332
+ this.$lastAction.set({
333
+ type: "splice",
334
+ start,
335
+ deleteCount,
336
+ addedItems: newItems,
337
+ removedItems: items
338
+ });
339
+ return items;
340
+ }
341
+ clear() {
342
+ this._core.assertAlive();
343
+ const previousValue = [...this._value];
344
+ this._value = [];
345
+ this._core.notifyDependents();
346
+ this.$lastAction.set({
347
+ type: "clear",
348
+ clearedItems: previousValue
349
+ });
350
+ return previousValue;
351
+ }
352
+ dispose() {
353
+ super.dispose();
354
+ this.$lastAction.dispose();
355
+ }
356
+ };
357
+
358
+ //#endregion
359
+ //#region src/core/api/nodes/collections/flowArray.ts
360
+ /**
361
+ * Creates a reactive array with mutation methods and fine-grained action tracking.
362
+ *
363
+ * The array starts with the provided initial items (or empty if none provided). All mutation methods
364
+ * (push, pop, splice, etc.) notify dependents and emit detailed action information to `$lastAction`.
365
+ * Use the array itself for coarse-grained reactivity, or subscribe to `$lastAction` for fine-grained
366
+ * reactivity to specific mutation types. Useful for reactive lists, collections, or any data that
367
+ * needs array-like operations with automatic change propagation.
368
+ *
369
+ * @param initial - Optional initial array of items
370
+ * @param options - Optional settings; `name` identifies this primitive in error messages
371
+ * @returns A FlowArray with reactive mutation methods
372
+ *
373
+ * @public
374
+ */
375
+ function array(initial, options) {
376
+ return new ArrayNode(initial, options?.name);
377
+ }
378
+
379
+ //#endregion
380
+ //#region src/core/nodes/mapNode.ts
381
+ /**
382
+ * Internal implementation of reactive map with mutation tracking.
383
+ * @internal
384
+ */
385
+ var MapNode = class extends ReadableNode {
386
+ $lastAction;
387
+ get _core() {
388
+ return super._core;
389
+ }
390
+ /** The live backing store, owned by the engine and mutated in place here. */
391
+ get _value() {
392
+ return this._core.current;
393
+ }
394
+ set _value(value) {
395
+ this._core.current = value;
396
+ }
397
+ constructor(value = /* @__PURE__ */ new Map(), name) {
398
+ super(syncCore(value, { name }), "map");
399
+ this.$lastAction = new ActionNode({
400
+ type: "set",
401
+ setMap: value,
402
+ clearedMap: /* @__PURE__ */ new Map()
403
+ }, name && `${name}.$lastAction`);
404
+ }
405
+ add(key, value) {
406
+ this._core.assertAlive();
407
+ if (this._value.has(key)) throw new PicoFlowPreconditionError("[PicoFlow] Key already exists");
408
+ this._value.set(key, value);
409
+ this._core.notifyDependents();
410
+ this.$lastAction.set({
411
+ type: "add",
412
+ key,
413
+ addedValue: value
414
+ });
415
+ }
416
+ setAt(key, value) {
417
+ this._core.assertAlive();
418
+ if (!this._value.has(key)) throw new PicoFlowPreconditionError("[PicoFlow] Key does not exist");
419
+ const previousValue = this._value.get(key);
420
+ this._value.set(key, value);
421
+ this._core.notifyDependents();
422
+ this.$lastAction.set({
423
+ type: "setAt",
424
+ key,
425
+ setValue: value,
426
+ clearedValue: previousValue
427
+ });
428
+ }
429
+ delete(key) {
430
+ this._core.assertAlive();
431
+ if (!this._value.has(key)) throw new PicoFlowPreconditionError("[PicoFlow] Key does not exist");
432
+ const value = this._value.get(key);
433
+ this._value.delete(key);
434
+ this._core.notifyDependents();
435
+ this.$lastAction.set({
436
+ type: "delete",
437
+ key,
438
+ removedValue: value
439
+ });
440
+ return value;
441
+ }
442
+ /** Notifies dependents without changing the contents. */
443
+ trigger() {
444
+ this._core.trigger();
445
+ }
446
+ set(map) {
447
+ this._core.assertAlive();
448
+ const previousValue = this._value;
449
+ if (!this._core.overwrite(map)) return;
450
+ this.$lastAction.set({
451
+ type: "set",
452
+ setMap: this._value,
453
+ clearedMap: previousValue
454
+ });
455
+ }
456
+ clear() {
457
+ this._core.assertAlive();
458
+ const previousValue = this._value;
459
+ this._value = /* @__PURE__ */ new Map();
460
+ this._core.notifyDependents();
461
+ this.$lastAction.set({
462
+ type: "clear",
463
+ clearedMap: previousValue
464
+ });
465
+ return previousValue;
466
+ }
467
+ dispose() {
468
+ super.dispose();
469
+ this.$lastAction.dispose();
470
+ }
471
+ };
472
+
473
+ //#endregion
474
+ //#region src/core/api/nodes/collections/flowMap.ts
475
+ function map(initial, options) {
476
+ if (initial instanceof Map) return new MapNode(initial, options?.name);
477
+ return new MapNode(new Map(initial ? Object.entries(initial) : []), options?.name);
478
+ }
479
+
480
+ //#endregion
481
+ //#region src/core/api/nodes/flowSignal.ts
482
+ /**
483
+ * Creates a signal that can be manually triggered to notify dependents.
484
+ *
485
+ * Signals act as event emitters in the reactive graph. Call `trigger()` to notify all subscribers
486
+ * and reactive computations that depend on the signal. Unlike state or derivations, signals don't
487
+ * carry data values - they simply represent that an event occurred.
488
+ *
489
+ * @param options - Optional settings; `name` identifies this primitive in error messages
490
+ * @returns A FlowSignal that can be triggered manually and subscribed to
491
+ *
492
+ * @public
493
+ */
494
+ function signal(options) {
495
+ return new SignalNode(options?.name);
496
+ }
497
+
498
+ //#endregion
499
+ //#region src/core/api/nodes/sync/flowConstant.ts
500
+ /**
501
+ * Creates a constant reactive value that initializes lazily and never recomputes.
502
+ *
503
+ * The initializer function runs once on first access, and the result is cached permanently.
504
+ * Unlike state or derivations, constants never react to changes - they represent immutable values
505
+ * in the reactive graph. Useful for expensive one-time computations or static configuration.
506
+ *
507
+ * @param initializer - Function that computes the constant value on first access
508
+ * @param options - Optional settings; `name` identifies this primitive in error messages, `equals` overrides the default `===` change detection
509
+ * @returns A FlowConstant that provides read-only access to the cached value
510
+ *
511
+ * @public
512
+ */
513
+ function constant(initializer, options) {
514
+ return new ConstantNode(syncCore(initializer, options), "constant");
515
+ }
516
+
517
+ //#endregion
518
+ //#region src/core/api/nodes/sync/flowState.ts
519
+ function state(valueOrInitializer, options) {
520
+ return new StateNode(syncCore(valueOrInitializer, options), "state");
521
+ }
522
+
523
+ //#endregion
524
+ //#region src/core/api/nodes/sync/flowWritableDerivation.ts
525
+ /**
526
+ * Creates a derived value that recomputes automatically but can also be manually overridden.
527
+ *
528
+ * The compute function tracks dependencies and recomputes when they change, just like a regular derivation.
529
+ * However, you can also call `set()` to override the computed value. Use this for values that are normally
530
+ * derived but need occasional manual adjustments, such as editable calculated fields or user-correctable totals.
531
+ *
532
+ * @param compute - Function that accesses dependencies and computes the derived value
533
+ * @param options - Optional settings; `name` identifies this primitive in error messages, `equals` overrides the
534
+ * default `===` change detection, `eager` recomputes on dirty instead of on read (#118)
535
+ * @returns A FlowWritableDerivation that provides both reactive computation and manual control
536
+ *
537
+ * @public
538
+ */
539
+ function writableDerivation(compute, options) {
540
+ return new WritableDerivationNode(syncCore(compute, options, true), "writableDerivation");
541
+ }
542
+
543
+ //#endregion
544
+ export { PicoFlowCycleError, PicoFlowDisposedError, PicoFlowError, PicoFlowInternalError, PicoFlowPreconditionError, array, constant, constantAsync, derivation, derivationAsync, isDisposable, map, onFlushError, reset, signal, state, stateAsync, subscribe, writableDerivation, writableDerivationAsync };