@but212/atom-effect 0.4.0 → 0.5.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/dist/index.d.ts CHANGED
@@ -13,8 +13,21 @@ export declare type AsyncStateType = (typeof AsyncState)[keyof typeof AsyncState
13
13
 
14
14
  /**
15
15
  * Creates a reactive atom holding mutable state.
16
- * @param initialValue - Initial value
17
- * @param options - { sync?: boolean } for immediate notifications
16
+ *
17
+ * Atoms are the building blocks of reactive state. When an atom's value changes,
18
+ * any effects or computed atoms that depend on it will be automatically re-executed.
19
+ *
20
+ * @param initialValue - The initial value of the atom.
21
+ * @param options - Configuration options.
22
+ * @param options.sync - If true, notifications are delivered synchronously when the value changes.
23
+ * @returns A writable atom object.
24
+ *
25
+ * @example
26
+ * ```ts
27
+ * const count = atom(0);
28
+ * count.value = 1; // Notifies subscribers
29
+ * console.log(count.value); // 1
30
+ * ```
18
31
  */
19
32
  export declare function atom<T>(initialValue: T, options?: AtomOptions): WritableAtom<T>;
20
33
 
@@ -47,7 +60,9 @@ export declare class AtomError extends Error {
47
60
  constructor(message: string, cause?: Error | null, recoverable?: boolean);
48
61
  }
49
62
 
63
+ /** Configuration options for creating an atom. */
50
64
  export declare interface AtomOptions {
65
+ /** If true, the atom will notify its subscribers synchronously when its value changes. */
51
66
  sync?: boolean;
52
67
  }
53
68
 
@@ -62,7 +77,7 @@ export declare interface AtomOptions {
62
77
  * @param callback - The function containing batched updates
63
78
  * @returns The result of the callback function
64
79
  * @throws {AtomError} If the callback is not a function
65
- * @throws {AtomError} If an error occurs during batch execution
80
+ * @throws Propagates any error thrown by the callback function
66
81
  *
67
82
  * @example
68
83
  * ```typescript
@@ -82,6 +97,15 @@ export declare interface AtomOptions {
82
97
  */
83
98
  export declare function batch<T>(callback: () => T): T;
84
99
 
100
+ /**
101
+ * Generic Branded Type helper.
102
+ * T: The base type (e.g., number, string)
103
+ * Brand: The unique brand tag
104
+ */
105
+ export declare type Branded<T, Brand> = T & {
106
+ readonly __brand: Brand;
107
+ };
108
+
85
109
  /**
86
110
  * Creates a computed value with automatic dependency tracking.
87
111
  * Supports sync/async computations with caching and lazy evaluation.
@@ -94,13 +118,21 @@ export declare function computed<T>(fn: () => Promise<T>, options: ComputedOptio
94
118
  defaultValue: T;
95
119
  }): ComputedAtom<T>;
96
120
 
121
+ /** Represents a reactive atom whose value is derived from other reactive state. */
97
122
  export declare interface ComputedAtom<T = unknown> extends ReadonlyAtom<T> {
123
+ /** Current asynchronous state of the computation. */
98
124
  readonly state: AsyncStateType;
125
+ /** true if the last computation attempt failed. */
99
126
  readonly hasError: boolean;
127
+ /** The error object from the last failed computation, if any. */
100
128
  readonly lastError: Error | null;
129
+ /** true if an asynchronous computation is currently in progress. */
101
130
  readonly isPending: boolean;
131
+ /** true if the computation has successfully completed and has a value. */
102
132
  readonly isResolved: boolean;
133
+ /** Manually invalidates the cached value, forcing recomputation on next access. */
103
134
  invalidate(): void;
135
+ /** Disposed of the computed atom and its subscriptions. */
104
136
  dispose(): void;
105
137
  }
106
138
 
@@ -119,10 +151,15 @@ export declare class ComputedError extends AtomError {
119
151
  constructor(message: string, cause?: Error | null);
120
152
  }
121
153
 
154
+ /** Configuration options for creating a computed atom. */
122
155
  export declare interface ComputedOptions<T = unknown> {
156
+ /** Optional custom equality check for values. Defaults to `Object.is`. */
123
157
  equal?: (a: T, b: T) => boolean;
158
+ /** Initial value to return while an async computation is pending. */
124
159
  defaultValue?: T;
160
+ /** If true, the computation is deferred until the value is first accessed. */
125
161
  lazy?: boolean;
162
+ /** Optional error handler for computation failures. */
126
163
  onError?: (error: Error) => void;
127
164
  }
128
165
 
@@ -163,7 +200,7 @@ export declare interface DebugConfig {
163
200
  * Interface for subscribable dependencies
164
201
  */
165
202
  export declare interface Dependency {
166
- readonly id: number;
203
+ readonly id: DependencyId;
167
204
  version: number;
168
205
  /**
169
206
  * Last epoch seen by this dependency (used for invalidation)
@@ -195,10 +232,33 @@ export declare interface DependencyEntry<T extends object = Dependency> {
195
232
  }
196
233
 
197
234
  /**
198
- * Creates a reactive effect that re-executes when dependencies change.
199
- * @param fn - Effect function (may return cleanup function or Promise)
200
- * @param options - { sync?: boolean, maxExecutionsPerSecond?: number, trackModifications?: boolean }
201
- * @throws {EffectError} If fn is not a function
235
+ * Unique identifier for reactive dependencies (Atoms, Computed, Effects).
236
+ * Base type is number.
237
+ */
238
+ export declare type DependencyId = Branded<number, 'DependencyId'>;
239
+
240
+ /**
241
+ * Creates a reactive effect that re-executes when its dependencies change.
242
+ *
243
+ * An effect automatically tracks any reactive state (atoms, computed) accessed during its execution.
244
+ * When those dependencies change, the effect is scheduled for re-execution.
245
+ *
246
+ * @param fn - The effect function to execute. Can return a cleanup function or a Promise that resolves to one.
247
+ * @param options - Configuration options for the effect.
248
+ * @param options.sync - If true, the effect runs synchronously when dependencies change. Defaults to false (scheduled).
249
+ * @param options.maxExecutionsPerSecond - Rate limiting for the effect.
250
+ * @param options.trackModifications - If true, warns when an effect modifies its own dependencies.
251
+ * @returns An object representing the effect with `run()` and `dispose()` methods.
252
+ * @throws {EffectError} If `fn` is not a function.
253
+ *
254
+ * @example
255
+ * ```ts
256
+ * const count = atom(0);
257
+ * const stop = effect(() => {
258
+ * console.log('Count changed:', count.value);
259
+ * return () => console.log('Cleaning up...');
260
+ * });
261
+ * ```
202
262
  */
203
263
  export declare function effect(fn: EffectFunction, options?: EffectOptions): EffectObject;
204
264
 
@@ -217,26 +277,43 @@ export declare class EffectError extends AtomError {
217
277
  constructor(message: string, cause?: Error | null);
218
278
  }
219
279
 
280
+ /**
281
+ * A function to be executed by an effect.
282
+ * Can optionally return a cleanup function or a Promise that resolves to one.
283
+ */
220
284
  export declare type EffectFunction = () => void | (() => void) | Promise<undefined | (() => void)>;
221
285
 
286
+ /** Represents a running effect instance. */
222
287
  export declare interface EffectObject {
288
+ /** Stops the effect and unsubscribes from all dependencies. */
223
289
  dispose(): void;
290
+ /** Manually triggers an execution of the effect. */
224
291
  run(): void;
292
+ /** true if the effect has been disposed. */
225
293
  readonly isDisposed: boolean;
294
+ /** Number of times the effect has executed. */
226
295
  readonly executionCount: number;
227
296
  }
228
297
 
298
+ /** Configuration options for creating an effect. */
229
299
  export declare interface EffectOptions {
300
+ /** If true, the effect runs synchronously whenever its dependencies change. */
230
301
  sync?: boolean;
302
+ /** Maximum number of executions allowed per second for rate limiting. */
231
303
  maxExecutionsPerSecond?: number;
304
+ /** Maximum number of executions allowed per scheduler flush for loop detection. */
232
305
  maxExecutionsPerFlush?: number;
306
+ /** If true, enables detection and warning for effects that modify their own dependencies. */
233
307
  trackModifications?: boolean;
234
308
  }
235
309
 
310
+ /** Checks if the given object is a ReadonlyAtom. */
236
311
  export declare function isAtom(obj: unknown): obj is ReadonlyAtom;
237
312
 
313
+ /** Checks if the given object is a ComputedAtom. */
238
314
  export declare function isComputed(obj: unknown): obj is ComputedAtom;
239
315
 
316
+ /** Checks if the given object is an EffectObject. */
240
317
  export declare function isEffect(obj: unknown): obj is EffectObject;
241
318
 
242
319
  /**
@@ -257,15 +334,24 @@ export declare interface Poolable {
257
334
  reset(): void;
258
335
  }
259
336
 
337
+ /** Represents a read-only reactive atom. */
260
338
  export declare interface ReadonlyAtom<T = unknown> {
339
+ /** The current value of the atom. Accessing this tracks it as a dependency. */
261
340
  readonly value: T;
341
+ /**
342
+ * Subscribes a listener function to changes in the atom's value.
343
+ * @param listener - Callback receiving both the new and old values.
344
+ * @returns An unsubscribe function.
345
+ */
262
346
  subscribe(listener: (newValue?: T, oldValue?: T) => void): () => void;
347
+ /** Returns the current value without registering it as a dependency. */
263
348
  peek(): T;
264
349
  }
265
350
 
266
351
  /**
267
- * Scheduler for reactive updates with batching support.
268
- * Uses epoch-based O(1) deduplication and double buffering.
352
+ * Scheduler for reactive updates.
353
+ * Manages the execution of effects and computed updates using batching and double-buffering.
354
+ * Supports both asynchronous (microtask-based) and synchronous (manual or batch-end) flushing.
269
355
  */
270
356
  declare class Scheduler {
271
357
  private queueA;
@@ -281,11 +367,31 @@ declare class Scheduler {
281
367
  private isFlushingSync;
282
368
  private maxFlushIterations;
283
369
  get phase(): SchedulerPhase;
370
+ /**
371
+ * Schedules a task for execution.
372
+ * Tasks are deduplicated within the same flush cycle using epoch tracking.
373
+ * @param callback - The function to execute.
374
+ * @throws {SchedulerError} If the callback is not a function.
375
+ */
284
376
  schedule(callback: SchedulerJob): void;
285
377
  private flush;
286
378
  private flushSync;
379
+ private _mergeBatchQueue;
380
+ private _drainQueue;
381
+ private _processCurrentQueue;
382
+ private _handleFlushOverflow;
383
+ private _processJobs;
384
+ /** Starts a new batch of updates. Updates will be deferred until endBatch is called. */
287
385
  startBatch(): void;
386
+ /**
387
+ * Ends the current batch. If the batch depth reaches zero, all pending updates are flushed synchronously.
388
+ */
288
389
  endBatch(): void;
390
+ /**
391
+ * Configures the maximum number of iterations allowed during a synchronous flush.
392
+ * Used to prevent infinite loops.
393
+ * @param max - Maximum iterations count.
394
+ */
289
395
  setMaxFlushIterations(max: number): void;
290
396
  }
291
397
 
@@ -331,9 +437,10 @@ export declare class SchedulerError extends AtomError {
331
437
  constructor(message: string, cause?: Error | null);
332
438
  }
333
439
 
334
- declare type SchedulerJob = (() => void) & {
440
+ declare interface SchedulerJob {
441
+ (): void;
335
442
  _nextEpoch?: number;
336
- };
443
+ }
337
444
 
338
445
  declare enum SchedulerPhase {
339
446
  IDLE = 0,
@@ -364,7 +471,7 @@ export declare type TransformFunction<T, U> = (value: T) => U;
364
471
  * @param fn - The function to execute without tracking
365
472
  * @returns The result of the executed function
366
473
  * @throws {AtomError} If the callback is not a function
367
- * @throws {AtomError} If an error occurs during execution
474
+ * @throws Propagates any error thrown by the callback function
368
475
  *
369
476
  * @example
370
477
  * ```typescript
@@ -378,8 +485,11 @@ export declare type TransformFunction<T, U> = (value: T) => U;
378
485
  */
379
486
  export declare function untracked<T>(fn: () => T): T;
380
487
 
488
+ /** Represents a writable reactive atom. */
381
489
  export declare interface WritableAtom<T = unknown> extends ReadonlyAtom<T> {
490
+ /** The current value of the atom. Setting this will trigger notifications if the value changes. */
382
491
  value: T;
492
+ /** Disposes of the atom and releases associated resources. */
383
493
  dispose(): void;
384
494
  }
385
495