@zeix/cause-effect 0.17.3 → 0.18.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 (89) hide show
  1. package/.ai-context.md +163 -232
  2. package/.cursorrules +41 -35
  3. package/.github/copilot-instructions.md +166 -116
  4. package/ARCHITECTURE.md +274 -0
  5. package/CLAUDE.md +199 -143
  6. package/COLLECTION_REFACTORING.md +161 -0
  7. package/GUIDE.md +298 -0
  8. package/README.md +232 -197
  9. package/REQUIREMENTS.md +100 -0
  10. package/bench/reactivity.bench.ts +577 -0
  11. package/index.dev.js +1325 -997
  12. package/index.js +1 -1
  13. package/index.ts +58 -74
  14. package/package.json +4 -1
  15. package/src/errors.ts +118 -74
  16. package/src/graph.ts +601 -0
  17. package/src/nodes/collection.ts +474 -0
  18. package/src/nodes/effect.ts +149 -0
  19. package/src/nodes/list.ts +588 -0
  20. package/src/nodes/memo.ts +120 -0
  21. package/src/nodes/sensor.ts +139 -0
  22. package/src/nodes/state.ts +135 -0
  23. package/src/nodes/store.ts +383 -0
  24. package/src/nodes/task.ts +146 -0
  25. package/src/signal.ts +112 -66
  26. package/src/util.ts +26 -57
  27. package/test/batch.test.ts +96 -62
  28. package/test/benchmark.test.ts +473 -487
  29. package/test/collection.test.ts +466 -706
  30. package/test/effect.test.ts +293 -696
  31. package/test/list.test.ts +335 -592
  32. package/test/memo.test.ts +380 -0
  33. package/test/regression.test.ts +156 -0
  34. package/test/scope.test.ts +191 -0
  35. package/test/sensor.test.ts +454 -0
  36. package/test/signal.test.ts +220 -213
  37. package/test/state.test.ts +217 -265
  38. package/test/store.test.ts +346 -446
  39. package/test/task.test.ts +395 -0
  40. package/test/untrack.test.ts +167 -0
  41. package/types/index.d.ts +13 -15
  42. package/types/src/errors.d.ts +73 -17
  43. package/types/src/graph.d.ts +208 -0
  44. package/types/src/nodes/collection.d.ts +64 -0
  45. package/types/src/nodes/effect.d.ts +48 -0
  46. package/types/src/nodes/list.d.ts +65 -0
  47. package/types/src/nodes/memo.d.ts +57 -0
  48. package/types/src/nodes/sensor.d.ts +75 -0
  49. package/types/src/nodes/state.d.ts +78 -0
  50. package/types/src/nodes/store.d.ts +51 -0
  51. package/types/src/nodes/task.d.ts +73 -0
  52. package/types/src/signal.d.ts +43 -29
  53. package/types/src/util.d.ts +9 -16
  54. package/archive/benchmark.ts +0 -683
  55. package/archive/collection.ts +0 -253
  56. package/archive/composite.ts +0 -85
  57. package/archive/computed.ts +0 -195
  58. package/archive/list.ts +0 -483
  59. package/archive/memo.ts +0 -139
  60. package/archive/state.ts +0 -90
  61. package/archive/store.ts +0 -298
  62. package/archive/task.ts +0 -189
  63. package/src/classes/collection.ts +0 -245
  64. package/src/classes/computed.ts +0 -349
  65. package/src/classes/list.ts +0 -343
  66. package/src/classes/ref.ts +0 -70
  67. package/src/classes/state.ts +0 -102
  68. package/src/classes/store.ts +0 -262
  69. package/src/diff.ts +0 -138
  70. package/src/effect.ts +0 -93
  71. package/src/match.ts +0 -45
  72. package/src/resolve.ts +0 -49
  73. package/src/system.ts +0 -257
  74. package/test/computed.test.ts +0 -1108
  75. package/test/diff.test.ts +0 -955
  76. package/test/match.test.ts +0 -388
  77. package/test/ref.test.ts +0 -353
  78. package/test/resolve.test.ts +0 -154
  79. package/types/src/classes/collection.d.ts +0 -45
  80. package/types/src/classes/computed.d.ts +0 -94
  81. package/types/src/classes/list.d.ts +0 -43
  82. package/types/src/classes/ref.d.ts +0 -35
  83. package/types/src/classes/state.d.ts +0 -49
  84. package/types/src/classes/store.d.ts +0 -52
  85. package/types/src/diff.d.ts +0 -28
  86. package/types/src/effect.d.ts +0 -15
  87. package/types/src/match.d.ts +0 -21
  88. package/types/src/resolve.d.ts +0 -29
  89. package/types/src/system.d.ts +0 -78
@@ -0,0 +1,73 @@
1
+ import { type ComputedOptions, type TaskCallback } from '../graph';
2
+ /**
3
+ * An asynchronous reactive computation (colorless async).
4
+ * Automatically tracks dependencies and re-executes when they change.
5
+ * Provides abort semantics and pending state tracking.
6
+ *
7
+ * @template T - The type of value resolved by the task
8
+ */
9
+ type Task<T extends {}> = {
10
+ readonly [Symbol.toStringTag]: 'Task';
11
+ /**
12
+ * Gets the current value of the task.
13
+ * Returns the last resolved value, even while a new computation is pending.
14
+ * When called inside another reactive context, creates a dependency.
15
+ * @returns The current value
16
+ * @throws UnsetSignalValueError If the task value is still unset when read.
17
+ */
18
+ get(): T;
19
+ /**
20
+ * Checks if the task is currently executing.
21
+ * @returns True if a computation is in progress
22
+ */
23
+ isPending(): boolean;
24
+ /**
25
+ * Aborts the current computation if one is running.
26
+ * The task's AbortSignal will be triggered.
27
+ */
28
+ abort(): void;
29
+ };
30
+ /**
31
+ * Creates an asynchronous reactive computation (colorless async).
32
+ * The computation automatically tracks dependencies and re-executes when they change.
33
+ * Provides abort semantics - in-flight computations are aborted when dependencies change.
34
+ *
35
+ * @since 0.18.0
36
+ * @template T - The type of value resolved by the task
37
+ * @param fn - The async computation function that receives the previous value and an AbortSignal
38
+ * @param options - Optional configuration for the task
39
+ * @returns A Task object with get(), isPending(), and abort() methods
40
+ *
41
+ * @example
42
+ * ```ts
43
+ * const userId = createState(1);
44
+ * const user = createTask(async (prev, signal) => {
45
+ * const response = await fetch(`/api/users/${userId.get()}`, { signal });
46
+ * return response.json();
47
+ * });
48
+ *
49
+ * // When userId changes, the previous fetch is aborted
50
+ * userId.set(2);
51
+ * ```
52
+ *
53
+ * @example
54
+ * ```ts
55
+ * // Check pending state
56
+ * if (user.isPending()) {
57
+ * console.log('Loading...');
58
+ * }
59
+ * ```
60
+ */
61
+ declare function createTask<T extends {}>(fn: (prev: T, signal: AbortSignal) => Promise<T>, options: ComputedOptions<T> & {
62
+ value: T;
63
+ }): Task<T>;
64
+ declare function createTask<T extends {}>(fn: TaskCallback<T>, options?: ComputedOptions<T>): Task<T>;
65
+ /**
66
+ * Checks if a value is a Task signal.
67
+ *
68
+ * @since 0.18.0
69
+ * @param value - The value to check
70
+ * @returns True if the value is a Task
71
+ */
72
+ declare function isTask<T extends {} = unknown & {}>(value: unknown): value is Task<T>;
73
+ export { createTask, isTask, type Task };
@@ -1,51 +1,65 @@
1
- import { type Computed } from './classes/computed';
2
- import { List } from './classes/list';
3
- import { State } from './classes/state';
4
- import { type Store } from './classes/store';
5
- import type { UnknownRecord } from './diff';
6
- type Signal<T extends {}> = {
1
+ import { type ComputedOptions, type MemoCallback, type Signal, type TaskCallback } from './graph';
2
+ import { type List, type UnknownRecord } from './nodes/list';
3
+ import { type Memo } from './nodes/memo';
4
+ import { type State } from './nodes/state';
5
+ import { type Store } from './nodes/store';
6
+ import { type Task } from './nodes/task';
7
+ type MutableSignal<T extends {}> = {
7
8
  get(): T;
8
- };
9
- type UnknownSignal = Signal<unknown & {}>;
10
- type MutableSignal<T extends {}> = T extends readonly (infer U extends {})[] ? List<U> : T extends UnknownRecord ? Store<T> : State<T>;
11
- type ReadonlySignal<T extends {}> = Computed<T>;
12
- type UnknownSignalRecord = Record<string, UnknownSignal>;
13
- type SignalValues<S extends UnknownSignalRecord> = {
14
- [K in keyof S]: S[K] extends Signal<infer T> ? T : never;
9
+ set(value: T): void;
10
+ update(callback: (value: T) => T): void;
15
11
  };
16
12
  /**
17
- * Check whether a value is a Signal
13
+ * Create a derived signal from existing signals
18
14
  *
19
15
  * @since 0.9.0
20
- * @param {unknown} value - value to check
21
- * @returns {boolean} - true if value is a Signal, false otherwise
16
+ * @param callback - Computation callback function
17
+ * @param options - Optional configuration
22
18
  */
23
- declare const isSignal: <T extends {}>(value: unknown) => value is Signal<T>;
24
- /**
25
- * Check whether a value is a State, Store, or List
26
- *
27
- * @since 0.15.2
28
- * @param {unknown} value - Value to check
29
- * @returns {boolean} - True if value is a State, Store, or List, false otherwise
30
- */
31
- declare const isMutableSignal: (value: unknown) => value is MutableSignal<unknown & {}>;
19
+ declare function createComputed<T extends {}>(callback: TaskCallback<T>, options?: ComputedOptions<T>): Task<T>;
20
+ declare function createComputed<T extends {}>(callback: MemoCallback<T>, options?: ComputedOptions<T>): Memo<T>;
32
21
  /**
33
22
  * Convert a value to a Signal.
34
23
  *
35
24
  * @since 0.9.6
36
25
  */
26
+ declare function createSignal<T extends {}>(value: Signal<T>): Signal<T>;
37
27
  declare function createSignal<T extends {}>(value: readonly T[]): List<T>;
38
- declare function createSignal<T extends {}>(value: T[]): List<T>;
39
28
  declare function createSignal<T extends UnknownRecord>(value: T): Store<T>;
40
- declare function createSignal<T extends {}>(value: () => T): Computed<T>;
29
+ declare function createSignal<T extends {}>(value: TaskCallback<T>): Task<T>;
30
+ declare function createSignal<T extends {}>(value: MemoCallback<T>): Memo<T>;
41
31
  declare function createSignal<T extends {}>(value: T): State<T>;
42
32
  /**
43
33
  * Convert a value to a MutableSignal.
44
34
  *
45
35
  * @since 0.17.0
46
36
  */
37
+ declare function createMutableSignal<T extends {}>(value: MutableSignal<T>): MutableSignal<T>;
47
38
  declare function createMutableSignal<T extends {}>(value: readonly T[]): List<T>;
48
- declare function createMutableSignal<T extends {}>(value: T[]): List<T>;
49
39
  declare function createMutableSignal<T extends UnknownRecord>(value: T): Store<T>;
50
40
  declare function createMutableSignal<T extends {}>(value: T): State<T>;
51
- export { createMutableSignal, createSignal, isMutableSignal, isSignal, type MutableSignal, type ReadonlySignal, type Signal, type SignalValues, type UnknownSignal, type UnknownSignalRecord, };
41
+ /**
42
+ * Check if a value is a computed signal
43
+ *
44
+ * @since 0.9.0
45
+ * @param value - Value to check
46
+ * @returns True if value is a computed signal, false otherwise
47
+ */
48
+ declare function isComputed<T extends {}>(value: unknown): value is Memo<T>;
49
+ /**
50
+ * Check whether a value is a Signal
51
+ *
52
+ * @since 0.9.0
53
+ * @param value - Value to check
54
+ * @returns True if value is a Signal, false otherwise
55
+ */
56
+ declare function isSignal<T extends {}>(value: unknown): value is Signal<T>;
57
+ /**
58
+ * Check whether a value is a State, Store, or List
59
+ *
60
+ * @since 0.15.2
61
+ * @param value - Value to check
62
+ * @returns True if value is a State, Store, or List, false otherwise
63
+ */
64
+ declare function isMutableSignal(value: unknown): value is MutableSignal<unknown & {}>;
65
+ export { type MutableSignal, createComputed, createSignal, createMutableSignal, isComputed, isSignal, isMutableSignal, };
@@ -1,17 +1,10 @@
1
- declare const isString: (value: unknown) => value is string;
2
- declare const isNumber: (value: unknown) => value is number;
3
- declare const isSymbol: (value: unknown) => value is symbol;
4
- declare const isFunction: <T>(fn: unknown) => fn is (...args: unknown[]) => T;
5
- declare const isAsyncFunction: <T>(fn: unknown) => fn is (...args: unknown[]) => Promise<T>;
6
- declare const isSyncFunction: <T extends unknown & {
1
+ declare function isFunction<T>(fn: unknown): fn is (...args: unknown[]) => T;
2
+ declare function isAsyncFunction<T>(fn: unknown): fn is (...args: unknown[]) => Promise<T>;
3
+ declare function isSyncFunction<T extends unknown & {
7
4
  then?: undefined;
8
- }>(fn: unknown) => fn is (...args: unknown[]) => T;
9
- declare const isNonNullObject: (value: unknown) => value is NonNullable<object>;
10
- declare const isObjectOfType: <T>(value: unknown, type: string) => value is T;
11
- declare const isRecord: <T extends Record<string, unknown>>(value: unknown) => value is T;
12
- declare const isRecordOrArray: <T extends Record<string | number, unknown> | ReadonlyArray<unknown>>(value: unknown) => value is T;
13
- declare const isUniformArray: <T>(value: unknown, guard?: (item: T) => item is T & {}) => value is T[];
14
- declare const hasMethod: <T extends object & Record<string, (...args: unknown[]) => unknown>>(obj: T, methodName: string) => obj is T & Record<string, (...args: unknown[]) => unknown>;
15
- declare const isAbortError: (error: unknown) => boolean;
16
- declare const valueString: (value: unknown) => string;
17
- export { isString, isNumber, isSymbol, isFunction, isAsyncFunction, isSyncFunction, isNonNullObject, isObjectOfType, isRecord, isRecordOrArray, isUniformArray, hasMethod, isAbortError, valueString, };
5
+ }>(fn: unknown): fn is (...args: unknown[]) => T;
6
+ declare function isObjectOfType<T>(value: unknown, type: string): value is T;
7
+ declare function isRecord<T extends Record<string, unknown>>(value: unknown): value is T;
8
+ declare function isUniformArray<T>(value: unknown, guard?: (item: T) => item is T & {}): value is T[];
9
+ declare function valueString(value: unknown): string;
10
+ export { isFunction, isAsyncFunction, isSyncFunction, isObjectOfType, isRecord, isUniformArray, valueString, };