@esportsplus/reactivity 0.31.3 → 0.33.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 (67) hide show
  1. package/README.md +43 -6
  2. package/bench/cellx.bench.ts +61 -0
  3. package/bench/dynamic.bench.ts +103 -0
  4. package/bench/kairo.bench.ts +368 -0
  5. package/bench/lib/reactive-adapter.ts +51 -0
  6. package/bench/molbench.bench.ts +75 -0
  7. package/{tests/bench/system.ts → bench/system.bench.ts} +3 -3
  8. package/build/compiler/array.d.ts +1 -1
  9. package/build/compiler/constants.d.ts +7 -6
  10. package/build/compiler/constants.js +6 -7
  11. package/build/compiler/object.d.ts +1 -1
  12. package/build/compiler/object.js +1 -2
  13. package/build/compiler/primitives.d.ts +1 -1
  14. package/build/constants.d.ts +3 -1
  15. package/build/constants.js +3 -1
  16. package/build/reactive/array.d.ts +7 -3
  17. package/build/reactive/array.js +32 -24
  18. package/build/reactive/index.d.ts +2 -2
  19. package/build/reactive/index.js +1 -1
  20. package/build/reactive/object.d.ts +4 -4
  21. package/build/reactive/object.js +8 -23
  22. package/build/system.d.ts +15 -6
  23. package/build/system.js +432 -69
  24. package/build/types.d.ts +22 -4
  25. package/package.json +10 -7
  26. package/src/compiler/array.ts +1 -1
  27. package/src/compiler/constants.ts +8 -6
  28. package/src/compiler/index.ts +2 -1
  29. package/src/compiler/object.ts +2 -2
  30. package/src/compiler/plugins/vite.ts +1 -0
  31. package/src/compiler/primitives.ts +1 -1
  32. package/src/constants.ts +6 -2
  33. package/src/reactive/array.ts +50 -35
  34. package/src/reactive/index.ts +6 -6
  35. package/src/reactive/object.ts +16 -41
  36. package/src/system.ts +635 -80
  37. package/src/types.ts +38 -9
  38. package/test/async-computed.test.ts +409 -0
  39. package/test/async-errors.test.ts +146 -0
  40. package/test/async-hardening.test.ts +73 -0
  41. package/test/async-iterable.test.ts +221 -0
  42. package/test/async-nested.test.ts +19 -0
  43. package/test/deep-graphs.test.ts +215 -0
  44. package/{tests/effects.ts → test/effects.test.ts} +122 -0
  45. package/test/equals.test.ts +142 -0
  46. package/test/errors.test.ts +201 -0
  47. package/test/flush.test.ts +185 -0
  48. package/test/glitch-freedom.test.ts +115 -0
  49. package/test/invalidate.test.ts +147 -0
  50. package/test/lib/wait-for.ts +28 -0
  51. package/test/pending-writes.test.ts +139 -0
  52. package/{tests/reactive.ts → test/reactive/reactive.test.ts} +20 -19
  53. package/test/read-dedup.test.ts +120 -0
  54. package/test/signal-selector.test.ts +187 -0
  55. package/{tests/system.ts → test/system.test.ts} +210 -19
  56. package/test/tsconfig.json +16 -0
  57. package/test/untrack.test.ts +146 -0
  58. package/vitest.config.ts +2 -2
  59. package/tests/async-computed.ts +0 -239
  60. /package/{tests/bench/array.ts → bench/reactive/array.bench.ts} +0 -0
  61. /package/{tests/bench/reactive-object.ts → bench/reactive/reactive-object.bench.ts} +0 -0
  62. /package/{tests → bench}/tsconfig.json +0 -0
  63. /package/{tests/compiler.ts → test/compiler/compiler.test.ts} +0 -0
  64. /package/{tests/primitives.ts → test/primitives.test.ts} +0 -0
  65. /package/{tests/array.ts → test/reactive/array.test.ts} +0 -0
  66. /package/{tests/nested.ts → test/reactive/nested.test.ts} +0 -0
  67. /package/{tests/objects.ts → test/reactive/objects.test.ts} +0 -0
@@ -0,0 +1,75 @@
1
+ import { bench, describe } from 'vitest';
2
+ import { assert, framework } from './lib/reactive-adapter';
3
+
4
+
5
+ // Ported from milomg/js-reactivity-benchmark packages/core/src/benches/kairo/molBench.ts (MIT)
6
+
7
+ let numbers = Array.from({ length: 5 }, (_, i) => i);
8
+
9
+
10
+ function fib(n: number): number {
11
+ if (n < 2) {
12
+ return 1;
13
+ }
14
+
15
+ return fib(n - 1) + fib(n - 2);
16
+ }
17
+
18
+ function hard(n: number) {
19
+ return n + fib(16);
20
+ }
21
+
22
+ function mol() {
23
+ let res: number[] = [];
24
+
25
+ let a = framework.signal(0);
26
+
27
+ let b = framework.signal(0);
28
+
29
+ let c = framework.computed(() => (a.read() % 2) + (b.read() % 2));
30
+
31
+ let d = framework.computed(() => numbers.map((i) => ({ x: i + (a.read() % 2) - (b.read() % 2) })));
32
+
33
+ let e = framework.computed(() => hard(c.read() + a.read() + d.read()[0].x));
34
+
35
+ let f = framework.computed(() => hard(d.read()[2].x || b.read()));
36
+
37
+ let g = framework.computed(() => c.read() + (c.read() || e.read() % 2) + d.read()[4].x + f.read());
38
+
39
+ // Keeper: G reads E conditionally; without a live subscriber E would auto-dispose on first drop
40
+ framework.effect(() => e.read());
41
+
42
+ framework.effect(() => res.push(hard(g.read())));
43
+
44
+ framework.effect(() => res.push(g.read()));
45
+
46
+ framework.effect(() => res.push(hard(f.read())));
47
+
48
+ let i = 0;
49
+
50
+ return async () => {
51
+ i++;
52
+ res.length = 0;
53
+
54
+ await framework.withBatch(() => {
55
+ b.write(1);
56
+ a.write(1 + i * 2);
57
+ });
58
+
59
+ await framework.withBatch(() => {
60
+ a.write(2 + i * 2);
61
+ b.write(2);
62
+ });
63
+
64
+ assert(res.length > 0, 'molBench: effects did not run');
65
+ };
66
+ }
67
+
68
+
69
+ describe('molBench', () => {
70
+ let molRun = framework.withBuild(mol);
71
+
72
+ bench('molBench', async () => {
73
+ await molRun();
74
+ });
75
+ });
@@ -1,5 +1,5 @@
1
1
  import { bench, describe } from 'vitest';
2
- import { asyncComputed, computed, dispose, effect, onCleanup, read, root, signal, write } from '~/system';
2
+ import { computed, dispose, effect, onCleanup, read, root, signal, write } from '~/system';
3
3
 
4
4
 
5
5
  describe('signal', () => {
@@ -78,13 +78,13 @@ describe('computed', () => {
78
78
 
79
79
  describe('asyncComputed', () => {
80
80
  bench('create asyncComputed', () => {
81
- asyncComputed(() => Promise.resolve(0));
81
+ computed(() => Promise.resolve(0));
82
82
  });
83
83
 
84
84
  bench('create asyncComputed from signal', () => {
85
85
  let s = signal(0);
86
86
 
87
- asyncComputed(() => Promise.resolve(read(s)));
87
+ computed(() => Promise.resolve(read(s)));
88
88
  });
89
89
  });
90
90
 
@@ -1,5 +1,5 @@
1
- import type { ReplacementIntent } from '@esportsplus/typescript/compiler';
2
1
  import { ts } from '@esportsplus/typescript';
2
+ import type { ReplacementIntent } from '@esportsplus/typescript/compiler';
3
3
  import type { Bindings } from './types.js';
4
4
  declare const _default: (sourceFile: ts.SourceFile, bindings: Bindings, checker?: ts.TypeChecker) => ReplacementIntent[];
5
5
  export default _default;
@@ -1,11 +1,12 @@
1
1
  declare const ENTRYPOINT = "reactive";
2
2
  declare const ENTRYPOINT_REGEX: RegExp;
3
3
  declare const NAMESPACE: string;
4
- declare const enum TYPES {
5
- Array = 0,
6
- Computed = 1,
7
- Object = 2,
8
- Signal = 3
9
- }
4
+ declare const TYPES: {
5
+ readonly Array: 0;
6
+ readonly Computed: 1;
7
+ readonly Object: 2;
8
+ readonly Signal: 3;
9
+ };
10
+ type TYPES = typeof TYPES[keyof typeof TYPES];
10
11
  export { ENTRYPOINT, ENTRYPOINT_REGEX, NAMESPACE, TYPES };
11
12
  export { PACKAGE_NAME } from '../constants.js';
@@ -2,12 +2,11 @@ import { uid } from '@esportsplus/typescript/compiler';
2
2
  const ENTRYPOINT = 'reactive';
3
3
  const ENTRYPOINT_REGEX = /\breactive\b/;
4
4
  const NAMESPACE = uid('reactivity');
5
- var TYPES;
6
- (function (TYPES) {
7
- TYPES[TYPES["Array"] = 0] = "Array";
8
- TYPES[TYPES["Computed"] = 1] = "Computed";
9
- TYPES[TYPES["Object"] = 2] = "Object";
10
- TYPES[TYPES["Signal"] = 3] = "Signal";
11
- })(TYPES || (TYPES = {}));
5
+ const TYPES = {
6
+ Array: 0,
7
+ Computed: 1,
8
+ Object: 2,
9
+ Signal: 3
10
+ };
12
11
  export { ENTRYPOINT, ENTRYPOINT_REGEX, NAMESPACE, TYPES };
13
12
  export { PACKAGE_NAME } from '../constants.js';
@@ -1,5 +1,5 @@
1
- import { type ReplacementIntent } from '@esportsplus/typescript/compiler';
2
1
  import { ts } from '@esportsplus/typescript';
2
+ import type { ReplacementIntent } from '@esportsplus/typescript/compiler';
3
3
  import type { Bindings } from './types.js';
4
4
  type ObjectTransformResult = {
5
5
  prepend: string[];
@@ -1,6 +1,5 @@
1
- import { code, imports } from '@esportsplus/typescript/compiler';
2
1
  import { ts } from '@esportsplus/typescript';
3
- import { uid } from '@esportsplus/typescript/compiler';
2
+ import { code, imports, uid } from '@esportsplus/typescript/compiler';
4
3
  import { ENTRYPOINT, NAMESPACE, PACKAGE_NAME, TYPES } from './constants.js';
5
4
  function analyzeProperty(prop, sourceFile) {
6
5
  if (!ts.isPropertyAssignment(prop)) {
@@ -1,5 +1,5 @@
1
- import type { ReplacementIntent } from '@esportsplus/typescript/compiler';
2
1
  import { ts } from '@esportsplus/typescript';
2
+ import type { ReplacementIntent } from '@esportsplus/typescript/compiler';
3
3
  import type { Bindings } from './types.js';
4
4
  declare const _default: (sourceFile: ts.SourceFile, bindings: Bindings, isReactiveCall: (node: ts.Node) => boolean) => ReplacementIntent[];
5
5
  export default _default;
@@ -13,5 +13,7 @@ declare const STATE_DIRTY: number;
13
13
  declare const STATE_RECOMPUTING: number;
14
14
  declare const STATE_IN_HEAP: number;
15
15
  declare const STATE_COMPUTED: number;
16
+ declare const STATE_ERROR: number;
17
+ declare const STATE_EFFECT: number;
16
18
  declare const STATE_NOTIFY_MASK: number;
17
- export { COMPUTED, REACTIVE_ARRAY, REACTIVE_OBJECT, PACKAGE_NAME, SIGNAL, STABILIZER_IDLE, STABILIZER_RESCHEDULE, STABILIZER_RUNNING, STABILIZER_SCHEDULED, STATE_CHECK, STATE_COMPUTED, STATE_DIRTY, STATE_IN_HEAP, STATE_NONE, STATE_NOTIFY_MASK, STATE_RECOMPUTING };
19
+ export { COMPUTED, PACKAGE_NAME, REACTIVE_ARRAY, REACTIVE_OBJECT, SIGNAL, STABILIZER_IDLE, STABILIZER_RESCHEDULE, STABILIZER_RUNNING, STABILIZER_SCHEDULED, STATE_CHECK, STATE_COMPUTED, STATE_DIRTY, STATE_EFFECT, STATE_ERROR, STATE_IN_HEAP, STATE_NONE, STATE_NOTIFY_MASK, STATE_RECOMPUTING };
@@ -13,5 +13,7 @@ const STATE_DIRTY = 1 << 1;
13
13
  const STATE_RECOMPUTING = 1 << 2;
14
14
  const STATE_IN_HEAP = 1 << 3;
15
15
  const STATE_COMPUTED = 1 << 4;
16
+ const STATE_ERROR = 1 << 5;
17
+ const STATE_EFFECT = 1 << 6;
16
18
  const STATE_NOTIFY_MASK = (STATE_CHECK | STATE_DIRTY);
17
- export { COMPUTED, REACTIVE_ARRAY, REACTIVE_OBJECT, PACKAGE_NAME, SIGNAL, STABILIZER_IDLE, STABILIZER_RESCHEDULE, STABILIZER_RUNNING, STABILIZER_SCHEDULED, STATE_CHECK, STATE_COMPUTED, STATE_DIRTY, STATE_IN_HEAP, STATE_NONE, STATE_NOTIFY_MASK, STATE_RECOMPUTING };
19
+ export { COMPUTED, PACKAGE_NAME, REACTIVE_ARRAY, REACTIVE_OBJECT, SIGNAL, STABILIZER_IDLE, STABILIZER_RESCHEDULE, STABILIZER_RUNNING, STABILIZER_SCHEDULED, STATE_CHECK, STATE_COMPUTED, STATE_DIRTY, STATE_EFFECT, STATE_ERROR, STATE_IN_HEAP, STATE_NONE, STATE_NOTIFY_MASK, STATE_RECOMPUTING };
@@ -33,18 +33,22 @@ type Listener<V> = {
33
33
  once?: boolean;
34
34
  (value: V): void;
35
35
  };
36
- type Listeners = Record<string, (Listener<any> | null)[]>;
36
+ type AnyListener<T> = Listener<Events<T>[keyof Events<T>]>;
37
+ type Listeners<T> = {
38
+ [K in keyof Events<T>]?: (AnyListener<T> | null)[];
39
+ };
37
40
  declare class ReactiveArray<T> extends Array<T> {
38
41
  private _length;
39
- listeners: Listeners;
42
+ listeners: Listeners<T>;
40
43
  constructor(...items: T[]);
44
+ static get [Symbol.species](): ArrayConstructor;
41
45
  get $length(): number;
42
46
  set $length(value: number);
43
47
  $set(i: number, value: T): void;
44
48
  clear(): void;
45
49
  concat(...items: ConcatArray<T>[]): ReactiveArray<T>;
46
50
  concat(...items: (T | ConcatArray<T>)[]): ReactiveArray<T>;
47
- dispatch<K extends keyof Events<T>, V>(event: K, value?: V): void;
51
+ dispatch<K extends keyof Events<T>>(event: K, value?: Events<T>[K]): void;
48
52
  dispose(): void;
49
53
  on<K extends keyof Events<T>>(event: K, listener: Listener<Events<T>[K]>): void;
50
54
  once<K extends keyof Events<T>>(event: K, listener: Listener<Events<T>[K]>): void;
@@ -1,6 +1,6 @@
1
1
  import { isArray } from '@esportsplus/utilities';
2
- import { read, signal, write } from '../system.js';
3
2
  import { REACTIVE_ARRAY } from '../constants.js';
3
+ import { read, signal, write } from '../system.js';
4
4
  import { isReactiveObject } from './object.js';
5
5
  function dispose(value) {
6
6
  if (isReactiveObject(value)) {
@@ -14,6 +14,9 @@ class ReactiveArray extends Array {
14
14
  super(...items);
15
15
  this._length = signal(items.length);
16
16
  }
17
+ static get [Symbol.species]() {
18
+ return Array;
19
+ }
17
20
  get $length() {
18
21
  return read(this._length);
19
22
  }
@@ -97,22 +100,22 @@ class ReactiveArray extends Array {
97
100
  write(this._length, 0);
98
101
  }
99
102
  on(event, listener) {
100
- let listeners = this.listeners[event];
103
+ let entry = listener, listeners = this.listeners[event];
101
104
  if (listeners === undefined) {
102
- this.listeners[event] = [listener];
105
+ this.listeners[event] = [entry];
103
106
  }
104
107
  else {
105
108
  let hole = listeners.length;
106
109
  for (let i = 0, n = hole; i < n; i++) {
107
110
  let l = listeners[i];
108
- if (l === listener) {
111
+ if (l === entry) {
109
112
  return;
110
113
  }
111
114
  else if (l === null && hole === n) {
112
115
  hole = i;
113
116
  }
114
117
  }
115
- listeners[hole] = listener;
118
+ listeners[hole] = entry;
116
119
  while (listeners.length && listeners[listeners.length - 1] === null) {
117
120
  listeners.pop();
118
121
  }
@@ -155,29 +158,34 @@ class ReactiveArray extends Array {
155
158
  return item;
156
159
  }
157
160
  sort(fn) {
158
- let n = this.length, before = new Array(n);
159
- for (let i = 0; i < n; i++) {
160
- before[i] = this[i];
161
- }
162
- super.sort(fn);
163
- let buckets = new Map(), order = new Array(n);
164
- for (let i = 0; i < n; i++) {
165
- let value = before[i], list = buckets.get(value);
166
- if (!list) {
167
- buckets.set(value, [i]);
161
+ if (this.listeners.sort === undefined) {
162
+ super.sort(fn);
163
+ }
164
+ else {
165
+ let n = this.length, before = new Array(n);
166
+ for (let i = 0; i < n; i++) {
167
+ before[i] = this[i];
168
168
  }
169
- else {
170
- list.push(i);
169
+ super.sort(fn);
170
+ let buckets = new Map(), order = new Array(n);
171
+ for (let i = 0; i < n; i++) {
172
+ let value = before[i], list = buckets.get(value);
173
+ if (!list) {
174
+ buckets.set(value, [i]);
175
+ }
176
+ else {
177
+ list.push(i);
178
+ }
171
179
  }
172
- }
173
- for (let i = 0; i < n; i++) {
174
- let list = buckets.get(this[i]);
175
- order[i] = list.length === 1 ? list[0] : list[list.length - 1];
176
- if (list.length > 1) {
177
- list.pop();
180
+ for (let i = 0; i < n; i++) {
181
+ let list = buckets.get(this[i]);
182
+ order[i] = list.length === 1 ? list[0] : list[list.length - 1];
183
+ if (list.length > 1) {
184
+ list.pop();
185
+ }
178
186
  }
187
+ this.dispatch('sort', { order });
179
188
  }
180
- this.dispatch('sort', { order });
181
189
  return this;
182
190
  }
183
191
  splice(start, deleteCount = this.length, ...items) {
@@ -1,8 +1,8 @@
1
- import { Reactive } from '../types.js';
1
+ import type { Reactive } from '../types.js';
2
2
  import { ReactiveArray } from './array.js';
3
3
  import { ReactiveObject } from './object.js';
4
4
  type Guard<T> = T extends Record<PropertyKey, unknown> ? T extends {
5
- dispose: any;
5
+ dispose: unknown;
6
6
  } ? {
7
7
  never: '[ dispose ] is a reserved key';
8
8
  } : T : never;
@@ -1,8 +1,8 @@
1
1
  import { onCleanup, root } from '@esportsplus/reactivity';
2
2
  import { isArray, isObject } from '@esportsplus/utilities';
3
+ import { PACKAGE_NAME } from '../constants.js';
3
4
  import { ReactiveArray } from './array.js';
4
5
  import { ReactiveObject } from './object.js';
5
- import { PACKAGE_NAME } from '../constants.js';
6
6
  function reactive(input) {
7
7
  let dispose = false, value = root(() => {
8
8
  let response;
@@ -1,13 +1,13 @@
1
- import { Computed, Signal } from '../types.js';
2
1
  import { COMPUTED, REACTIVE_ARRAY, SIGNAL } from '../constants.js';
2
+ import { Computed } from '../types.js';
3
3
  import { ReactiveArray } from './array.js';
4
4
  declare class ReactiveObject<T extends Record<PropertyKey, unknown>> {
5
5
  protected disposers: VoidFunction[] | null;
6
6
  constructor(data: T | null);
7
+ protected [COMPUTED]<T extends Computed<ReturnType<T>>['fn']>(value: T): import("../types.js").ComputedResult<ReturnType<T>>;
7
8
  protected [REACTIVE_ARRAY]<U>(value: U[]): ReactiveArray<U>;
8
- protected [COMPUTED]<T extends Computed<ReturnType<T>>['fn']>(value: T): Computed<ReturnType<T>> | Signal<ReturnType<T> | undefined>;
9
- protected [SIGNAL]<T>(value: T): Signal<T>;
9
+ protected [SIGNAL]<T>(value: T): import("../types.js").Signal<T>;
10
10
  dispose(): void;
11
11
  }
12
- declare const isReactiveObject: (value: any) => value is ReactiveObject<any>;
12
+ declare const isReactiveObject: (value: unknown) => value is ReactiveObject<Record<PropertyKey, unknown>>;
13
13
  export { isReactiveObject, ReactiveObject };
@@ -1,6 +1,6 @@
1
- import { defineProperty, isArray, isPromise } from '@esportsplus/utilities';
2
- import { computed, dispose, effect, read, root, signal, write } from '../system.js';
1
+ import { defineProperty, isArray } from '@esportsplus/utilities';
3
2
  import { COMPUTED, REACTIVE_ARRAY, REACTIVE_OBJECT, SIGNAL } from '../constants.js';
3
+ import { computed, dispose, read, root, signal, write } from '../system.js';
4
4
  import { ReactiveArray } from './array.js';
5
5
  class ReactiveObject {
6
6
  disposers = null;
@@ -19,9 +19,7 @@ class ReactiveObject {
19
19
  });
20
20
  continue;
21
21
  }
22
- if (value == null || type !== 'object') {
23
- }
24
- else if (isArray(value)) {
22
+ if (value != null && type === 'object' && isArray(value)) {
25
23
  defineProperty(this, key, {
26
24
  enumerable: true,
27
25
  value: this[REACTIVE_ARRAY](value)
@@ -40,31 +38,18 @@ class ReactiveObject {
40
38
  });
41
39
  }
42
40
  }
43
- [REACTIVE_ARRAY](value) {
44
- let node = new ReactiveArray(...value);
45
- (this.disposers ??= []).push(() => node.dispose());
46
- return node;
47
- }
48
41
  [COMPUTED](value) {
49
42
  return root(() => {
50
43
  let node = computed(value);
51
- if (isPromise(node.value)) {
52
- let factory = node, out = signal(undefined), v = 0;
53
- (this.disposers ??= []).push(effect(() => {
54
- let id = ++v;
55
- read(factory).then((resolved) => {
56
- if (id !== v) {
57
- return;
58
- }
59
- write(out, resolved);
60
- });
61
- }));
62
- return out;
63
- }
64
44
  (this.disposers ??= []).push(() => dispose(node));
65
45
  return node;
66
46
  });
67
47
  }
48
+ [REACTIVE_ARRAY](value) {
49
+ let node = new ReactiveArray(...value);
50
+ (this.disposers ??= []).push(() => node.dispose());
51
+ return node;
52
+ }
68
53
  [SIGNAL](value) {
69
54
  return signal(value);
70
55
  }
package/build/system.d.ts CHANGED
@@ -1,17 +1,26 @@
1
- import { Computed, Signal } from './types.js';
2
- declare const asyncComputed: <T>(fn: Computed<Promise<T>>["fn"]) => Signal<T | undefined>;
3
- declare const computed: <T>(fn: Computed<T>["fn"]) => Computed<T>;
1
+ import { Computed, ComputedResult, Settled, Signal } from './types.js';
2
+ declare const batch: <T>(fn: () => T) => T;
3
+ declare const computed: {
4
+ <T>(fn: Computed<T>["fn"], equals?: ((a: Settled<T>, b: Settled<T>) => boolean) | null): ComputedResult<T>;
5
+ invalidate<T>(c: Computed<T>): void;
6
+ };
4
7
  declare const dispose: <T>(computed: Computed<T>) => void;
5
- declare const effect: <T>(fn: Computed<T>["fn"]) => () => void;
8
+ declare const effect: <T>(fn: Computed<T>["fn"], apply?: (value: T, prev: T | undefined) => void) => () => void;
9
+ declare const flush: () => void;
6
10
  declare const isComputed: (value: unknown) => value is Computed<unknown>;
7
11
  declare const isSignal: (value: unknown) => value is Signal<unknown>;
8
12
  declare const onCleanup: (fn: VoidFunction) => typeof fn;
13
+ declare const peek: <T>(node: Signal<T> | Computed<T>) => T;
9
14
  declare const read: <T>(node: Signal<T> | Computed<T>) => T;
10
15
  declare const root: {
11
16
  <T>(fn: ((dispose: VoidFunction) => T) | (() => T)): T;
12
17
  disposables: number;
13
18
  };
14
- declare const signal: <T>(value: T) => Signal<T>;
19
+ declare const signal: {
20
+ <T>(value: T, equals?: ((a: T, b: T) => boolean) | null): Signal<T>;
21
+ selector<T>(node: Signal<T>, key: T): boolean;
22
+ };
23
+ declare const untrack: <T>(fn: () => T) => T;
15
24
  declare const write: <T>(signal: Signal<T>, value: T) => void;
16
- export { asyncComputed, computed, dispose, effect, isComputed, isSignal, onCleanup, read, root, signal, write };
25
+ export { batch, computed, dispose, effect, flush, isComputed, isSignal, onCleanup, peek, read, root, signal, untrack, write };
17
26
  export type { Computed, Signal };