bireactive 0.2.3 → 0.3.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 (98) hide show
  1. package/dist/animation/anim.js +4 -0
  2. package/dist/coll.d.ts +7 -7
  3. package/dist/coll.js +3 -1
  4. package/dist/core/cell.d.ts +89 -66
  5. package/dist/core/cell.js +642 -401
  6. package/dist/core/index.d.ts +4 -14
  7. package/dist/core/index.js +4 -14
  8. package/dist/core/lenses/aggregates.d.ts +1 -1
  9. package/dist/core/lenses/aggregates.js +4 -3
  10. package/dist/core/lenses/closed-form-policies.js +6 -6
  11. package/dist/core/lenses/decompositions.js +3 -3
  12. package/dist/core/lenses/domain-aggregates.js +5 -5
  13. package/dist/core/lenses/geometry.d.ts +1 -1
  14. package/dist/core/lenses/geometry.js +6 -7
  15. package/dist/core/lenses/memory.d.ts +2 -2
  16. package/dist/core/lenses/memory.js +3 -3
  17. package/dist/core/lenses/typed-factor.js +4 -3
  18. package/dist/core/traits.d.ts +1 -0
  19. package/dist/core/values/box.js +7 -7
  20. package/dist/core/values/color.js +5 -5
  21. package/dist/core/values/field.d.ts +70 -0
  22. package/dist/core/values/field.js +230 -0
  23. package/dist/core/values/gpu.d.ts +4 -2
  24. package/dist/core/values/gpu.js +11 -4
  25. package/dist/core/values/matrix.js +7 -7
  26. package/dist/core/values/num.d.ts +1 -1
  27. package/dist/core/values/num.js +1 -1
  28. package/dist/core/values/pose.js +4 -4
  29. package/dist/core/values/range.js +6 -6
  30. package/dist/core/values/template.d.ts +1 -1
  31. package/dist/core/values/template.js +2 -1
  32. package/dist/core/values/transform.js +7 -7
  33. package/dist/core/values/tri.js +3 -3
  34. package/dist/core/values/vec.js +8 -12
  35. package/dist/ext/timeline.js +2 -2
  36. package/dist/formats/cst.d.ts +127 -0
  37. package/dist/formats/cst.js +280 -0
  38. package/dist/formats/edn.d.ts +2 -0
  39. package/dist/formats/edn.js +301 -0
  40. package/dist/formats/index.d.ts +6 -0
  41. package/dist/formats/index.js +8 -0
  42. package/dist/formats/json.d.ts +2 -0
  43. package/dist/formats/json.js +332 -0
  44. package/dist/formats/lens.d.ts +8 -0
  45. package/dist/formats/lens.js +54 -0
  46. package/dist/formats/toml.d.ts +2 -0
  47. package/dist/formats/toml.js +526 -0
  48. package/dist/formats/yaml.d.ts +2 -0
  49. package/dist/formats/yaml.js +661 -0
  50. package/dist/index.d.ts +10 -0
  51. package/dist/index.js +10 -0
  52. package/dist/learn/data.d.ts +49 -0
  53. package/dist/learn/data.js +181 -0
  54. package/dist/learn/index.d.ts +3 -0
  55. package/dist/learn/index.js +6 -0
  56. package/dist/learn/lens-net.d.ts +63 -0
  57. package/dist/learn/lens-net.js +219 -0
  58. package/dist/learn/mlp.d.ts +77 -0
  59. package/dist/learn/mlp.js +292 -0
  60. package/dist/propagators/csp.d.ts +13 -0
  61. package/dist/propagators/csp.js +52 -0
  62. package/dist/propagators/flex.d.ts +31 -0
  63. package/dist/propagators/flex.js +189 -0
  64. package/dist/propagators/graph.d.ts +73 -0
  65. package/dist/propagators/graph.js +543 -0
  66. package/dist/propagators/index.d.ts +8 -6
  67. package/dist/propagators/index.js +15 -6
  68. package/dist/propagators/lattice.d.ts +45 -0
  69. package/dist/propagators/lattice.js +113 -0
  70. package/dist/propagators/layout.d.ts +1 -27
  71. package/dist/propagators/layout.js +6 -175
  72. package/dist/propagators/numeric.d.ts +17 -0
  73. package/dist/propagators/numeric.js +93 -0
  74. package/dist/propagators/solver.d.ts +51 -0
  75. package/dist/propagators/solver.js +175 -0
  76. package/dist/schema/index.d.ts +1 -0
  77. package/dist/schema/index.js +3 -0
  78. package/dist/schema/lens.d.ts +121 -0
  79. package/dist/schema/lens.js +429 -0
  80. package/dist/shapes/annular-sector.js +4 -4
  81. package/dist/shapes/button.js +1 -1
  82. package/dist/shapes/circle.js +1 -1
  83. package/dist/shapes/handle.js +2 -2
  84. package/dist/shapes/label.js +1 -1
  85. package/dist/shapes/layout.js +2 -2
  86. package/dist/shapes/rect.js +7 -7
  87. package/dist/shapes/shape.js +8 -8
  88. package/dist/tex/tex.js +9 -2
  89. package/dist/web/diagram.js +2 -2
  90. package/package.json +9 -19
  91. package/dist/propagators/network.d.ts +0 -52
  92. package/dist/propagators/network.js +0 -185
  93. package/dist/propagators/propagator.d.ts +0 -12
  94. package/dist/propagators/propagator.js +0 -16
  95. package/dist/propagators/range.d.ts +0 -45
  96. package/dist/propagators/range.js +0 -147
  97. package/dist/propagators/relations.d.ts +0 -60
  98. package/dist/propagators/relations.js +0 -343
@@ -11,6 +11,7 @@
11
11
  //
12
12
  // T (generic), if the suspend is `(wake, spawn) => T`
13
13
  // Example: `const result = yield (wake, spawn) => { ... }`
14
+ import { settle } from "../core/cell.js";
14
15
  /** Cut sentinel — return `cut(v)` from a concurrent kid to settle the
15
16
  * enclosing group with `v` and cancel siblings. Outside a group, the
16
17
  * sentinel is transparently unwrapped to `v`. */
@@ -77,6 +78,9 @@ export class Anim {
77
78
  }
78
79
  }
79
80
  }
81
+ // A frame advances reactive state; flush the effects it woke so observers
82
+ // (and the next frame) see this frame's results synchronously.
83
+ settle();
80
84
  }
81
85
  stepInner(dt) {
82
86
  if (dt > 0 && Number.isFinite(dt))
package/dist/coll.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { type Cell, type Read, type Writable } from "./core/index.js";
2
2
  /** Accessor for an element's writable field cell. Forward reads `.value`;
3
3
  * the backward pass writes it. */
4
- export type Field<E, V> = (e: E) => Writable<Cell<V>>;
4
+ export type Accessor<E, V> = (e: E) => Writable<Cell<V>>;
5
5
  /** A forward test over an element's fields, optionally assertable —
6
6
  * `assert(e)` makes the test pass by writing fields. */
7
7
  export interface FieldPred<E> {
@@ -16,10 +16,10 @@ export interface GroupOpts<E, K> {
16
16
  /** Fixed key order; seeds empty buckets and pins column order. */
17
17
  order?: readonly K[];
18
18
  /** Order field within each group; enables `move(e, key, index)`. */
19
- sort?: Field<E, number>;
19
+ sort?: Accessor<E, number>;
20
20
  }
21
21
  /** `field === value`, assertable by writing the field. */
22
- export declare function is<E, V>(field: Field<E, V>, value: V): FieldPred<E>;
22
+ export declare function is<E, V>(field: Accessor<E, V>, value: V): FieldPred<E>;
23
23
  /** Conjunction; asserts every clause. */
24
24
  export declare function allPass<E>(...preds: readonly FieldPred<E>[]): FieldPred<E>;
25
25
  /** Read-only projection with chainable structural lenses. */
@@ -36,8 +36,8 @@ export declare class View<E> {
36
36
  assertContains(e: E): void;
37
37
  protected assertSelf(_e: E): void;
38
38
  filter(pred: FieldPred<E>): View<E>;
39
- sortBy(field: Field<E, number>): SortView<E>;
40
- groupBy<K>(field: Field<E, K>, opts?: GroupOpts<E, K>): GroupView<K, E>;
39
+ sortBy(field: Accessor<E, number>): SortView<E>;
40
+ groupBy<K>(field: Accessor<E, K>, opts?: GroupOpts<E, K>): GroupView<K, E>;
41
41
  map<F>(f: (e: E) => F): Read<readonly F[]>;
42
42
  /** Remove `e` from the source. */
43
43
  remove(e: E): void;
@@ -53,7 +53,7 @@ export declare class Coll<E> extends View<E> {
53
53
  /** Sorted view. `move` writes the order field between the drop neighbours. */
54
54
  export declare class SortView<E> extends View<E> {
55
55
  #private;
56
- constructor(parent: View<E>, field: Field<E, number>);
56
+ constructor(parent: View<E>, field: Accessor<E, number>);
57
57
  move(e: E, to: number): void;
58
58
  }
59
59
  /** Grouped view. `move`/`insert` write the group field (and, with a `sort`
@@ -61,7 +61,7 @@ export declare class SortView<E> extends View<E> {
61
61
  export declare class GroupView<K, E> {
62
62
  #private;
63
63
  readonly groups: Read<readonly Group<K, E>[]>;
64
- constructor(parent: View<E>, field: Field<E, K>, opts?: GroupOpts<E, K>);
64
+ constructor(parent: View<E>, field: Accessor<E, K>, opts?: GroupOpts<E, K>);
65
65
  get value(): readonly Group<K, E>[];
66
66
  map<F>(f: (g: Group<K, E>) => F): Read<readonly F[]>;
67
67
  /** Place `e` in group `toKey` at `index`. Inserts it into the source if
package/dist/coll.js CHANGED
@@ -147,7 +147,9 @@ export class GroupView {
147
147
  this.#sort = opts.sort;
148
148
  this.groups = derive(() => {
149
149
  const sort = this.#sort;
150
- const items = sort ? [...parent.items].sort((a, b) => sort(a).value - sort(b).value) : parent.items;
150
+ const items = sort
151
+ ? [...parent.items].sort((a, b) => sort(a).value - sort(b).value)
152
+ : parent.items;
151
153
  return groupItems(items, e => field(e).value, this.#order);
152
154
  });
153
155
  }
@@ -1,3 +1,19 @@
1
+ /** Multi-out / stateful back-write sentinel: "leave this parent untouched."
2
+ * A `bwd` returning per-parent updates yields `SKIP` for a parent it declines
3
+ * to write; every other slot value is written verbatim — INCLUDING `undefined`,
4
+ * which is a first-class cell value, not a hole. A SHORT array skips the trailing
5
+ * parents (so writing only the leading few needs no `SKIP` padding); `[]` skips
6
+ * all. (Single-out 1→1 `put` has no skip notion: it always writes its one parent,
7
+ * so it stays `undefined`-safe by construction.) */
8
+ export declare const SKIP: unique symbol;
9
+ export type Skip = typeof SKIP;
10
+ /** Per-parent back-write result over parents `T`: any PREFIX of the full update
11
+ * tuple. A shorter array skips the trailing parents; each present slot is a
12
+ * value or `SKIP`. For a fixed tuple this is the prefix union, so `[a]` /
13
+ * `[a, SKIP]` / `[]` all type against `[A, B]` while a bare `undefined` in a
14
+ * non-undefined slot stays an error (the footgun the `SKIP`/short-array split
15
+ * removes); for a variable-length array of parents it's just that array. */
16
+ export type BackUpdates<T extends readonly unknown[]> = number extends T["length"] ? T : T extends readonly [infer H, ...infer R] ? readonly [] | readonly [H, ...BackUpdates<R>] : readonly [];
1
17
  interface ReactiveNode {
2
18
  flags: number;
3
19
  deps: Link | undefined;
@@ -19,39 +35,28 @@ interface Link {
19
35
  }
20
36
  /** Install a hook fired on every source value-change; returns a restore fn. */
21
37
  export declare function setCellWriteHook(fn: ((cell: Cell<unknown>) => void) | undefined): () => void;
22
- export interface MergePolicy<T> {
23
- readonly identity: T;
24
- combine(acc: T, x: T): T;
25
- /** Optional inverse for incremental fold. */
26
- remove?(acc: T, x: T): T;
27
- }
28
- export declare const DIRECT_SLOT: unique symbol;
38
+ export type MergeFold<T> = (values: readonly T[]) => T;
29
39
  declare class MergeNode<T> {
30
- readonly parent: Cell<T>;
31
- readonly policy: MergePolicy<T>;
32
- readonly slots: Map<unknown, T>;
33
- readonly hasIncrementalAcc: boolean;
34
- acc: T;
35
- constructor(parent: Cell<T>, policy: MergePolicy<T>);
36
- receive(slot: unknown, next: T): void;
37
- fold(): T;
38
- reset(): void;
40
+ readonly foldFn: MergeFold<T> | undefined;
41
+ /** Contributions gathered as this merge's cone resolves; folded and cleared
42
+ * in `foldMerge` (the merge-owned buffer, mutated in place). The parent it
43
+ * writes to is just `b.parent` (a merge's `b.parent` IS its fold target), so
44
+ * this node carries only the policy + buffer — no duplicate edge. */
45
+ contributions: T[];
46
+ constructor(fold: MergeFold<T> | undefined);
39
47
  }
40
48
  declare class BwdSpec {
41
49
  /** Backward target(s): one `Cell` (1→1 / merge) or `Cell[]` (multi-out). */
42
50
  parent: Cell<unknown> | Cell<unknown>[] | undefined;
43
- /** Lens `put` — backward derivation (dual of `getter`). Always called by
44
- * the engine in 1-arg form `put(target)`; a source-reading lens bakes
45
- * `settled(parent)` into this closure at build time. Multi-output:
46
- * returns a per-parent update array. Stateful: the spec's `bwd`. */
51
+ /** Lens `put` — backward derivation (dual of `getter`). A 1→1 / multi-out
52
+ * lens is called as `put(target)` (a source-reading lens reads the current
53
+ * parent(s) at walk time, untracked); multi-out returns a per-parent update
54
+ * array. Stateful is the spec's `bwd`, called `put(target, sources, c)`. */
47
55
  put: ((target: any, current?: any) => any) | undefined;
48
56
  /** Backward aggregation node; presence IS the merge-mode discriminant. */
49
57
  merge: MergeNode<unknown> | undefined;
50
58
  /** Complement machinery; presence IS the stateful-mode discriminant. */
51
59
  stateful: StatefulCore | undefined;
52
- /** Index in `bwdQueue` of this cell's latest push; the drain skips stale
53
- * entries so each cell propagates backward once per flush, last-write. */
54
- queueIdx: number;
55
60
  }
56
61
  /** Runtime state of a stateful (complement-carrying) lens — the rare
57
62
  * backward mode, kept off `BwdSpec` so plain lenses don't carry its slots.
@@ -60,14 +65,17 @@ declare class BwdSpec {
60
65
  declare class StatefulCore {
61
66
  /** Engine-owned memory the view discards. */
62
67
  complement: unknown;
63
- /** Forward projection `fwd(sources, complement) → view`. */
64
- fwd: (sources: any, complement: any) => any;
65
- /** Advance the complement: `step(sources, complement, external)`. */
68
+ /** Advance the complement: `step(sources, complement, external)`. (The
69
+ * forward projection `fwd` is captured directly in the getter closure — it
70
+ * is only ever read there so it costs no slot here.) */
66
71
  step: (sources: any, complement: any, external: boolean) => any;
67
- /** Source values last written back (own-vs-external test); `undefined`
68
- * until the first back-write. */
69
- lastBwd: unknown[] | undefined;
70
- constructor(complement: unknown, fwd: (sources: any, complement: any) => any, step: (sources: any, complement: any, external: boolean) => any);
72
+ /** Sources this lens last committed back (the own-vs-external test compares
73
+ * live sources against these); `undefined` until the first back-write. A
74
+ * back-write reads the live sources into a fresh array, builds the committed
75
+ * candidate in place, and keeps it as `last` for the next own-vs-external
76
+ * comparison. */
77
+ last: unknown[] | undefined;
78
+ constructor(complement: unknown, step: (sources: any, complement: any, external: boolean) => any);
71
79
  }
72
80
  /** Plain T or any read-shape; snapshot via `readNow`, close via `reader`. */
73
81
  export type Val<T> = T | Read<T>;
@@ -110,52 +118,58 @@ export interface CellOptions<T = unknown> {
110
118
  equals?: (a: T, b: T) => boolean;
111
119
  }
112
120
  export declare class Cell<T = unknown> implements ReactiveNode {
121
+ /** @internal */
113
122
  flags: number;
123
+ /** @internal */
114
124
  subs: Link | undefined;
125
+ /** @internal */
115
126
  subsTail: Link | undefined;
127
+ /** @internal */
116
128
  deps: Link | undefined;
129
+ /** @internal */
117
130
  depsTail: Link | undefined;
118
- /** Forward derivation (computed/lens/merge). `undefined` ⇒ source. */
131
+ /** @internal Forward derivation (computed/lens/merge). `undefined` ⇒ source. */
119
132
  getter: (() => T) | undefined;
120
- /** Per-instance equality, always defined (defaults to `Object.is` at
121
- * construction) so hot paths call it without an `undefined` branch. */
133
+ /** @internal Per-instance equality; always defined (defaults to `Object.is`). */
122
134
  _equals: (a: T, b: T) => boolean;
123
- /** First-subscriber / last-subscriber lifecycle hooks. */
135
+ /** @internal First-subscriber / last-subscriber lifecycle hooks. */
124
136
  _watched: (() => void) | undefined;
137
+ /** @internal */
125
138
  _unwatchedHook: (() => void) | undefined;
126
- /** Source: `currentValue` = committed, `pendingValue` = staged write.
127
- * Getter cell: `currentValue` = last derived cache, `pendingValue`
128
- * reused as the deferred backward target (see `set value`). The two
129
- * roles never coexist, so two fields suffice for four. */
139
+ /** @internal Source: committed value + staged write. */
130
140
  currentValue: T;
141
+ /** @internal */
131
142
  pendingValue: T;
132
- /** Backward sidecar: target(s) + lens closures + queue slot, or
133
- * `undefined` for a read-only cell (source or computed). Allocated only
134
- * for writable derived cells, keeping the common node lean. Writability
135
- * is exactly `_bwd !== undefined`. See `BwdSpec`. */
143
+ /** @internal Backward sidecar; `undefined` iff read-only. Writability is `_bwd !== undefined`. */
136
144
  _bwd: BwdSpec | undefined;
145
+ /** @internal Backward dual of `subs`: direct lens-children for back-write cone traversal. */
146
+ _lensSubs: Cell<unknown>[] | undefined;
147
+ /** @internal Backward flag word (`BF`), dual of forward `flags`. */
148
+ bflags: number;
149
+ /** @internal Guards against `linkBack` re-registering a duplicate in `_lensSubs`. */
150
+ _linkedBack: boolean;
137
151
  constructor(initial: T, opts?: CellOptions<T>);
138
152
  readonly value: T;
139
- _enqueueBwd(): void;
140
- /** Source write (alien's signal setter). Self-excludes the active
141
- * network so a body writing its own dep doesn't re-trigger itself. */
153
+ /** @internal Single write-commit point; self-excludes the active network. */
142
154
  _writeSource(next: T): void;
155
+ /** @internal */
143
156
  _update(): boolean;
157
+ /** @internal */
144
158
  _notify(): void;
159
+ /** @internal */
145
160
  _unwatched(): void;
146
161
  peek(): T;
147
- /** Guard: silent coercion to string/number is almost always a bug. */
148
- [Symbol.toPrimitive](hint: string): never;
149
162
  /** Endomorphic lens. A 2-arg `bwd(view, current)` consults the current
150
163
  * source; a 1-arg `bwd(view)` reconstructs it from the view alone. */
151
164
  lens(this: Cell<T>, fwd: (v: T) => T, bwd: (target: T, current: T) => T): this;
152
165
  /** Read-only same-type view: the RO dual of the endo `.lens`. For a cross-type view use the typed static
153
166
  * `Target.derive(src, fn)`. */
154
167
  derive(this: Cell<T>, fn: (v: T) => T): this;
155
- /** Backward-aggregating node bwd dual of computed. Forward, the
156
- * identity view of its parent; backward, folds contributions from
157
- * upstream lenses (slot-keyed) and direct writes (DIRECT_SLOT). */
158
- merge(this: Cell<T>, policy: MergePolicy<T>): Cell<T>;
168
+ /** Backward fan-in node. Forward, the identity view of its parent;
169
+ * backward, the convergence point where N contributors (upstream lenses
170
+ * and direct writes) fold into one value for the parent. `fold` is handed
171
+ * every live push at once; omitted, it is last-writer-wins. */
172
+ merge(this: Cell<T>, fold?: MergeFold<T>): Cell<T>;
159
173
  /** Read-only typed view. `Cls.derive(parent, fn)` (1-input),
160
174
  * `Cls.derive(parents, fn)` (N-input), or `Cls.derive(fn)` (closure).
161
175
  * Polymorphic-`this`: `Vec.derive(...)` → `Vec`. */
@@ -173,9 +187,9 @@ export declare class Cell<T = unknown> implements ReactiveNode {
173
187
  [K in keyof P]: P[K] extends Read<infer V> ? V : never;
174
188
  }) => Inner<InstanceType<C>>, bwd: (target: Inner<InstanceType<C>>, vals: {
175
189
  [K in keyof P]: P[K] extends Read<infer V> ? V : never;
176
- }) => {
177
- [K in keyof P]?: P[K] extends Read<infer V> ? V : never;
178
- }): Writable<InstanceType<C>>;
190
+ }) => BackUpdates<{
191
+ [K in keyof P]: (P[K] extends Read<infer V> ? V : never) | Skip;
192
+ }>): Writable<InstanceType<C>>;
179
193
  static lens<C extends new (...args: never[]) => Cell<any>, P, Cm>(this: C, parent: Read<P>, spec: StatefulLensSpec<readonly [P], Inner<InstanceType<C>>, Cm>): Writable<InstanceType<C>>;
180
194
  static lens<C extends new (...args: never[]) => Cell<any>, P extends readonly Read<unknown>[], Cm>(this: C, parents: P, spec: StatefulLensSpec<{
181
195
  [K in keyof P]: P[K] extends Read<infer V> ? V : never;
@@ -183,21 +197,22 @@ export declare class Cell<T = unknown> implements ReactiveNode {
183
197
  /** Type predicate against this class: `Vec.is(x)` narrows `x` to `Vec`.
184
198
  * Inherited static; works for any subclass via polymorphic `this`. */
185
199
  static is<C extends new (...args: never[]) => Cell<any>>(this: C, v: unknown): v is InstanceType<C>;
186
- /** Lift `Val<Inner<Cls>>` → `Cls`: instance → identity, RO cell →
200
+ /** Coerce `Val<Inner<Cls>>` → `Cls`: instance → identity, RO cell →
187
201
  * tracked `derive`, literal → fresh seed. */
188
- static from<C extends new (...args: never[]) => Cell<any>>(this: C, v: Val<Inner<InstanceType<C>>>): InstanceType<C>;
202
+ static coerce<C extends new (...args: never[]) => Cell<any>>(this: C, v: Val<Inner<InstanceType<C>>>): InstanceType<C>;
189
203
  /** Writable-shaped constant: always reads `v`, absorbs writes
190
204
  * (parentless sink lens), for APIs demanding bidirectionality. */
191
205
  static pin<C extends new (...args: never[]) => Cell<any>>(this: C, v: Inner<InstanceType<C>>): Writable<InstanceType<C>>;
192
- /** Typed field lens onto `parent.value[key]`. A read-only computed
193
- * parent yields a RO derive view; any writable parent yields a
194
- * bidirectional field lens with spread-replace `put`. */
195
- static fieldOf<C extends new (...args: never[]) => Cell<any>>(parent: Cell<any>, key: string | number | symbol, Cls: C): InstanceType<C>;
196
206
  }
207
+ /** Typed field lens onto `parent.value[key]`. RO parent → RO derive;
208
+ * writable parent → bidirectional lens with spread-replace `put`. */
209
+ export declare function fieldOf<C extends new (...args: never[]) => Cell<any>>(parent: Cell<any>, key: string | number | symbol, Cls: C): InstanceType<C>;
197
210
  export interface StatefulBwd<S extends readonly unknown[], C> {
198
- updates: {
199
- readonly [K in keyof S]: S[K] | undefined;
200
- };
211
+ /** Per-parent updates: a value (written verbatim, `undefined` included) or
212
+ * `SKIP` to leave that parent. A short array skips the trailing parents. */
213
+ updates: BackUpdates<{
214
+ [K in keyof S]: S[K] | Skip;
215
+ }>;
201
216
  complement: C;
202
217
  }
203
218
  export interface StatefulLensSpec<S extends readonly unknown[], V, C> {
@@ -224,13 +239,21 @@ export declare function lens<P extends readonly Read<unknown>[], R>(parents: P,
224
239
  }) => R, bwd: (target: R, vals: {
225
240
  [K in keyof P]: P[K] extends Read<infer V> ? V : never;
226
241
  }) => {
227
- [K in keyof P]?: P[K] extends Read<infer V> ? V : never;
242
+ [K in keyof P]: (P[K] extends Read<infer V> ? V : never) | Skip;
228
243
  }): Writable<Cell<R>>;
229
244
  export declare function lens<P, R, C>(parent: Read<P>, spec: StatefulLensSpec<readonly [P], R, C>): Writable<Cell<R>>;
230
245
  export declare function lens<P extends readonly Read<unknown>[], R, C>(parents: P, spec: StatefulLensSpec<{
231
246
  [K in keyof P]: P[K] extends Read<infer V> ? V : never;
232
247
  }, R, C>): Writable<Cell<R>>;
233
248
  export declare function effect(fn: () => (() => void) | void): () => void;
249
+ /** Run all pending effects NOW, synchronously. The escape hatch for code (tests,
250
+ * imperative call sites) that must observe effect side-effects before yielding
251
+ * to the microtask queue. Reads never need it — they pull current values. */
252
+ export declare function settle(): void;
253
+ /** Group writes and flush effects SYNCHRONOUSLY at the end of `fn` — a sync
254
+ * barrier. Effects coalesce on the microtask turn anyway (see `schedule`), so
255
+ * `batch` is no longer needed for that; reach for it only when you must run the
256
+ * woken effects before the call returns (and don't want a `settle()`). */
234
257
  export declare function batch<R>(fn: () => R): R;
235
258
  export declare function untracked<R>(fn: () => R): R;
236
259
  /** Handle to a `network` invocation. */
@@ -257,8 +280,8 @@ export declare function network(deps: readonly Cell<any>[], body: (dirty: Readon
257
280
  * replaces the composite. Cached per (instance, key). Return type is
258
281
  * conditional: `Writable<Cls>` on a writable parent, bare `Cls` on RO.
259
282
  *
260
- * get x() { return field(this, "x", Num); } */
261
- export declare function field<S extends Cell<any>, K extends keyof Inner<S>, C extends new (...args: never[]) => Cell<Inner<S>[K]>>(parent: S, key: K, Cls: C): S extends WritableBrand ? Writable<InstanceType<C>> : InstanceType<C>;
283
+ * get x() { return fieldLens(this, "x", Num); } */
284
+ export declare function fieldLens<S extends Cell<any>, K extends keyof Inner<S>, C extends new (...args: never[]) => Cell<Inner<S>[K]>>(parent: S, key: K, Cls: C): S extends WritableBrand ? Writable<InstanceType<C>> : InstanceType<C>;
262
285
  /** Read-only derived view via `Cls.derive(parent, fn)`, memoized per
263
286
  * (instance, key); always bare `Cls` (RO). The cache is the point — the
264
287
  * getter form, not a new kind of cell.