@but212/atom-effect 0.16.1 → 0.17.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
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Async computation states for computed atoms
2
+ * Async operation states.
3
3
  */
4
4
  export declare const AsyncState: {
5
5
  readonly IDLE: "idle";
@@ -8,7 +8,9 @@ export declare const AsyncState: {
8
8
  readonly REJECTED: "rejected";
9
9
  };
10
10
 
11
- /** Type derived from AsyncState constant values */
11
+ /**
12
+ * Async state values.
13
+ */
12
14
  export declare type AsyncStateType = (typeof AsyncState)[keyof typeof AsyncState];
13
15
 
14
16
  /**
@@ -20,72 +22,49 @@ export declare type AsyncStateType = (typeof AsyncState)[keyof typeof AsyncState
20
22
  export declare function atom<T>(initialValue: T, options?: AtomOptions): WritableAtom<T>;
21
23
 
22
24
  /**
23
- * Base error class for all atom-effect errors
24
- *
25
- * Provides enhanced error information including:
26
- * - Original cause tracking for error chains
27
- * - Recoverability flag for error handling strategies
28
- * - Timestamp for debugging and logging
29
- *
30
- * @example
31
- * ```ts
32
- * throw new AtomError('Invalid state', originalError, false);
33
- * ```
25
+ * Base error class.
34
26
  */
35
27
  export declare class AtomError extends Error {
36
- /** Original error that caused this error, if any */
37
28
  cause: Error | null;
38
- /** Whether this error can be recovered from */
39
29
  recoverable: boolean;
40
- /** When this error occurred */
41
- timestamp: Date;
42
- /**
43
- * Creates a new AtomError
44
- * @param message - Error message describing what went wrong
45
- * @param cause - Original error that caused this error
46
- * @param recoverable - Whether the operation can be retried
47
- */
30
+ readonly timestamp: Date;
48
31
  constructor(message: string, cause?: Error | null, recoverable?: boolean);
49
32
  }
50
33
 
51
- /** Configuration options for creating an atom. */
34
+ /**
35
+ * Atom options.
36
+ */
52
37
  export declare interface AtomOptions {
53
- /** If true, the atom will notify its subscribers synchronously when its value changes. */
38
+ /** If true, subscribers are notified synchronously. Default: false (microtask scheduled). */
54
39
  sync?: boolean;
55
40
  }
56
41
 
57
42
  /**
58
- * Groups multiple state updates into a single notification cycle.
59
- * This optimizes performance by deferring the execution of scheduled effects
60
- * until the provided callback finishes execution, preventing redundant computations.
43
+ * Batches updates.
61
44
  *
62
- * @param callback - The function containing state updates to be batched.
63
- * @returns The value returned by the callback.
64
- * @throws {AtomError} If the provided callback is not a function.
45
+ * @param fn - Batch function.
46
+ * @returns - Result of `fn`.
65
47
  */
66
- export declare function batch<T>(callback: () => T): T;
48
+ export declare function batch<T>(fn: () => T): T;
67
49
 
68
50
  /**
69
- * Generic Branded Type helper.
70
- * T: The base type (e.g., number, string)
71
- * Brand: The unique brand tag
51
+ * Nominal type brand.
72
52
  */
73
53
  export declare type Branded<T, Brand> = T & {
74
54
  readonly __brand: Brand;
75
55
  };
76
56
 
77
57
  /**
78
- * Context tracked during the computation phase of a reactive node.
58
+ * Computation context.
79
59
  */
80
60
  export declare interface ComputationContext {
81
61
  links: DependencyLink[];
82
62
  }
83
63
 
84
64
  /**
85
- * Creates a computed value with automatic dependency tracking.
86
- * Supports sync/async computations with caching and lazy evaluation.
87
- * @param fn - Computation function (sync or async)
88
- * @param options - { equal?, defaultValue?, onError?, lazy? }
65
+ * Creates a computed value.
66
+ * @param fn - Computation function
67
+ * @param options - Options object
89
68
  */
90
69
  export declare function computed<T>(fn: () => T, options?: ComputedOptions<T>): ComputedAtom<T>;
91
70
 
@@ -93,434 +72,329 @@ export declare function computed<T>(fn: () => Promise<T>, options: ComputedOptio
93
72
  defaultValue: T;
94
73
  }): ComputedAtom<T>;
95
74
 
96
- /** Represents a reactive atom whose value is derived from other reactive state. */
75
+ /**
76
+ * Computed atom interface.
77
+ */
97
78
  export declare interface ComputedAtom<T = unknown> extends ReadonlyAtom<T> {
98
- /** Current asynchronous state of the computation. */
99
79
  readonly state: AsyncStateType;
100
- /** true if self or any dependency has an error. */
101
80
  readonly hasError: boolean;
102
- /** The error object from the last failed computation, if any. */
103
81
  readonly lastError: Error | null;
104
- /** true if an asynchronous computation is currently in progress. */
105
82
  readonly isPending: boolean;
106
- /** true if the computation has successfully completed and has a value. */
107
83
  readonly isResolved: boolean;
108
- /** Accumulated errors from self and all dependencies (immutable). */
109
- readonly errors: readonly Error[];
110
- /** true if no errors in self or dependencies (inverse of hasError). */
111
84
  readonly isValid: boolean;
112
- /** Manually invalidates the cached value, forcing recomputation on next access. */
85
+ /** List of errors encountered during computation. */
86
+ readonly errors: readonly Error[];
87
+ /** Invalidates atom. */
113
88
  invalidate(): void;
114
- /** Disposed of the computed atom and its subscriptions. */
115
89
  dispose(): void;
116
90
  }
117
91
 
118
- /**
119
- * Error thrown during computed value computation
120
- *
121
- * Computed errors are considered recoverable by default since they typically
122
- * result from transient data issues rather than programming errors.
123
- */
92
+ /** Computed error. */
124
93
  export declare class ComputedError extends AtomError {
125
- /**
126
- * Creates a new ComputedError
127
- * @param message - Error message
128
- * @param cause - Original error
129
- */
130
94
  constructor(message: string, cause?: Error | null);
131
95
  }
132
96
 
133
- /** Configuration options for creating a computed atom. */
97
+ /**
98
+ * Computed options.
99
+ */
134
100
  export declare interface ComputedOptions<T = unknown> {
135
- /** Optional custom equality check for values. Defaults to `Object.is`. */
101
+ /** Equality check. */
136
102
  equal?: (a: T, b: T) => boolean;
137
- /** Initial value to return while an async computation is pending. */
103
+ /** Initial value. */
138
104
  defaultValue?: T;
139
- /** If true, the computation is deferred until the value is first accessed. */
105
+ /** Lazy evaluation. */
140
106
  lazy?: boolean;
141
- /** Optional error handler for computation failures. */
107
+ /** Error handler. */
142
108
  onError?: (error: Error) => void;
143
109
  }
144
110
 
145
111
  /**
146
- * Debug configuration defaults
112
+ * Debugging thresholds.
147
113
  */
148
114
  export declare const DEBUG_CONFIG: {
149
- /** Maximum dependencies before warning about large dependency graphs */
150
115
  readonly MAX_DEPENDENCIES: 1000;
151
- /** Enable infinite loop detection warnings */
152
116
  readonly WARN_INFINITE_LOOP: true;
153
117
  };
154
118
 
155
119
  /**
156
- * Debug utilities for development-time dependency tracking and circular detection.
157
- * Most features only active when `NODE_ENV === 'development'`.
120
+ * Debug controller.
158
121
  */
159
122
  export declare const DEBUG_RUNTIME: DebugConfig;
160
123
 
161
- /**
162
- * Debug configuration interface
163
- */
164
124
  export declare interface DebugConfig {
165
125
  enabled: boolean;
166
126
  maxDependencies: number;
167
127
  warnInfiniteLoop: boolean;
168
128
  warn(condition: boolean, message: string): void;
169
- /** Checks for circular dependencies between reactive nodes */
170
129
  checkCircular(dep: Dependency, current: object): void;
171
130
  attachDebugInfo(obj: object, type: string, id: number): void;
172
- /** Returns debug name if available (requires obj to have DEBUG_NAME symbol) */
173
131
  getDebugName(obj: object | null | undefined): string | undefined;
174
- /** Returns debug type if available (requires obj to have DEBUG_TYPE symbol) */
175
132
  getDebugType(obj: object | null | undefined): string | undefined;
176
133
  }
177
134
 
178
135
  /**
179
- * Interface for subscribable dependencies
136
+ * Dependency interface.
180
137
  */
181
138
  export declare interface Dependency {
182
139
  readonly id: DependencyId;
140
+ /** Version counter. */
183
141
  version: number;
142
+ /** State flags. */
184
143
  flags: number;
185
- /**
186
- * Last epoch seen by this dependency (used for invalidation)
187
- */
144
+ /** Last validated epoch. */
188
145
  _lastSeenEpoch: number;
189
- /* Excluded from this release type: _tempUnsub */
190
- /* Excluded from this release type: _modifiedAtEpoch */
146
+ /** Temporary unsubscribe. */
147
+ _tempUnsub?: (() => void) | undefined;
148
+ /** Last modified epoch. */
149
+ _modifiedAtEpoch?: number;
191
150
  /**
192
- * Subscribe to dependency updates
151
+ * Adds a subscriber to this dependency.
152
+ * @param listener - The subscriber (function or object with execute method).
193
153
  */
194
154
  subscribe(listener: (() => void) | Subscriber): () => void;
195
- /**
196
- * Peek at value without subscribing
197
- */
155
+ /** Peek hook. */
198
156
  peek?(): unknown;
199
- /**
200
- * Current value (if cached)
201
- */
157
+ /** Value accessor. */
202
158
  value?: unknown;
203
159
  }
204
160
 
205
161
  /**
206
- * WeakRef-based dependency entry structure
162
+ * Graph entry.
207
163
  */
208
164
  export declare interface DependencyEntry<T extends object = Dependency> {
165
+ /** Dependency reference. */
209
166
  ref: WeakRef<T>;
210
167
  unsubscribe: () => void;
211
168
  }
212
169
 
213
170
  /**
214
- * Unique identifier for reactive dependencies (Atoms, Computed, Effects).
215
- * Base type is number.
171
+ * Dependency ID.
216
172
  */
217
173
  export declare type DependencyId = Branded<number, 'DependencyId'>;
218
174
 
219
175
  /**
220
- * Encapsulates a link to a dependency with its version and subscription.
221
- * Part of the AOS (Array of Structs) refactoring to improve data cohesion.
176
+ * Dependency graph edge.
222
177
  */
223
178
  declare class DependencyLink {
224
- /** The dependency node being tracked */
225
179
  node: Dependency;
226
- /** The version of the dependency at the time of tracking */
227
180
  version: number;
228
- /** The unsubscription function for the dependency */
229
181
  unsub: (() => void) | undefined;
230
182
  constructor(node: Dependency, version: number, unsub?: (() => void) | undefined);
231
183
  }
232
184
 
233
185
  /**
234
- * Creates and starts a reactive effect that automatically tracks dependencies.
235
- * The effect function is executed immediately and re-scheduled whenever its
236
- * reactive dependencies change.
186
+ * Creates and starts an effect.
237
187
  *
238
- * @param fn - The function to be executed as a reactive effect.
239
- * @param options - Configuration options to customize effect behavior (e.g., scheduling, error handling).
240
- * @returns An effect instance providing control over the effect's lifecycle.
241
- * @throws {EffectError} If the provided `fn` is not a function.
188
+ * @param fn - Effect function.
189
+ * @param options - Configuration options.
190
+ * @returns Effect instance.
242
191
  */
243
192
  export declare function effect(fn: EffectFunction, options?: EffectOptions): EffectObject;
244
193
 
245
- /**
246
- * Error thrown during effect execution
247
- *
248
- * Effect errors are considered non-recoverable by default since effects
249
- * typically represent critical side effects that shouldn't fail silently.
250
- */
194
+ /** Effect error. */
251
195
  export declare class EffectError extends AtomError {
252
- /**
253
- * Creates a new EffectError
254
- * @param message - Error message
255
- * @param cause - Original error
256
- */
257
196
  constructor(message: string, cause?: Error | null);
258
197
  }
259
198
 
260
- /**
261
- * Internal context used during effect execution to track dependency changes.
262
- * Bundles prev/next state for atomic lifecycle transitions.
263
- */
264
199
  export declare interface EffectExecutionContext {
265
200
  prevLinks: DependencyLink[];
266
201
  nextLinks: DependencyLink[];
267
202
  }
268
203
 
269
204
  /**
270
- * A function to be executed by an effect.
271
- * Can optionally return a cleanup function or a Promise that resolves to one.
205
+ * Effect return type.
272
206
  */
273
207
  export declare type EffectFunction = () => void | (() => void) | Promise<undefined | (() => void)>;
274
208
 
275
- /** Represents a running effect instance. */
276
209
  export declare interface EffectObject {
277
- /** Stops the effect and unsubscribes from all dependencies. */
278
210
  dispose(): void;
279
- /** Manually triggers an execution of the effect. */
280
211
  run(): void;
281
- /** true if the effect has been disposed. */
282
212
  readonly isDisposed: boolean;
283
- /** Number of times the effect has executed. */
284
213
  readonly executionCount: number;
285
214
  }
286
215
 
287
- /** Configuration options for creating an effect. */
288
216
  export declare interface EffectOptions {
289
- /** If true, the effect runs synchronously whenever its dependencies change. */
290
217
  sync?: boolean;
291
- /** Maximum number of executions allowed per second for rate limiting. */
292
218
  maxExecutionsPerSecond?: number;
293
- /** Maximum number of executions allowed per scheduler flush for loop detection. */
294
219
  maxExecutionsPerFlush?: number;
295
- /** If true, enables detection and warning for effects that modify their own dependencies. */
296
220
  trackModifications?: boolean;
297
- /** Callback function called when an execution error occurs (including async rejections). */
298
221
  onError?: (error: unknown) => void;
299
222
  }
300
223
 
301
- /** Internal atom interface for core library usage. */
224
+ /**
225
+ * Scheduler atom interface.
226
+ */
302
227
  export declare interface IAtom {
303
- /** Numerical ID for the node. */
304
228
  readonly id: number;
305
- /** Current version of the node's value. */
306
229
  version: number;
307
- /** Internal method to trigger subscriber notifications. */
308
230
  _internalNotifySubscribers(): void;
309
- /** Internal method to trigger recomputation. */
310
231
  recompute?(): void;
311
232
  }
312
233
 
313
- /** Checks if the given object is a ReadonlyAtom. */
234
+ /**
235
+ * Readonly atom check.
236
+ *
237
+ * @param obj - Object to check.
238
+ */
314
239
  export declare function isAtom(obj: unknown): obj is ReadonlyAtom;
315
240
 
316
- /** Internal scheduler interface to break circular dependencies. */
317
241
  export declare interface IScheduler<T> {
318
242
  markDirty(atom: T): void;
319
243
  scheduleNotify(atom: T): void;
320
244
  }
321
245
 
322
- /** Checks if the given object is a ComputedAtom. */
246
+ /**
247
+ * Computed atom check.
248
+ */
323
249
  export declare function isComputed(obj: unknown): obj is ComputedAtom;
324
250
 
325
- /** Checks if the given object is an EffectObject. */
251
+ /**
252
+ * Effect object check.
253
+ */
326
254
  export declare function isEffect(obj: unknown): obj is EffectObject;
327
255
 
328
256
  /**
329
- * Object pool configuration
330
- * Controls memory management and GC pressure reduction
257
+ * Array pool configuration.
331
258
  */
332
259
  export declare const POOL_CONFIG: {
333
- /** Maximum number of pooled objects to prevent memory bloat */
334
260
  readonly MAX_SIZE: 1000;
335
- /** Number of objects to pre-allocate for performance-critical paths */
336
261
  readonly WARMUP_SIZE: 100;
337
262
  };
338
263
 
339
264
  /**
340
- * Interface for poolable objects
265
+ * Poolable interface.
341
266
  */
342
267
  export declare interface Poolable {
343
268
  reset(): void;
344
269
  }
345
270
 
346
- /** Statistics for pool usage and health. */
347
271
  export declare interface PoolStats {
348
- /** Number of items acquired from the pool. */
349
272
  acquired: number;
350
- /** Number of items released back to the pool. */
351
273
  released: number;
352
- /** Details for items that could not be returned to the pool. */
353
274
  rejected: {
354
275
  frozen: number;
355
276
  tooLarge: number;
356
277
  poolFull: number;
357
278
  };
358
- /** Approximate number of items that have leaked (not released or rejected). */
359
279
  leaked: number;
360
- /** Current number of items available in the pool. */
361
280
  poolSize: number;
362
281
  }
363
282
 
364
- /** Represents a read-only reactive atom. */
283
+ /**
284
+ * Readonly atom interface.
285
+ */
365
286
  export declare interface ReadonlyAtom<T = unknown> {
366
- /** The current value of the atom. Accessing this tracks it as a dependency. */
287
+ /** The current value of the atom. */
367
288
  readonly value: T;
368
289
  /**
369
- * Subscribes a listener function to changes in the atom's value.
370
- * @param listener - Callback receiving both the new and old values.
371
- * @returns An unsubscribe function.
290
+ * Subscribes to value changes.
291
+ * @param listener - Function called when value changes.
292
+ * @returns Unsubscribe function.
372
293
  */
373
294
  subscribe(listener: (newValue?: T, oldValue?: T) => void): () => void;
374
- /** Returns the current value without registering it as a dependency. */
295
+ /**
296
+ * Non-reactive read.
297
+ */
375
298
  peek(): T;
376
299
  }
377
300
 
378
301
  /**
379
- * Simplified scheduler for reactive updates with double-buffered queue.
302
+ * Scheduler implementation.
380
303
  */
381
- declare class Scheduler {
382
- private readonly _queueBuffer;
383
- private _bufferIndex;
384
- private _size;
385
- private _epoch;
386
- private _isProcessing;
387
- private _isBatching;
388
- private _batchDepth;
389
- private _batchQueue;
390
- private _batchQueueSize;
391
- private _isFlushingSync;
392
- private _maxFlushIterations;
393
- constructor();
394
- /**
395
- * Returns the current operational phase of the scheduler.
396
- */
397
- get phase(): SchedulerPhase;
398
- /** Current number of pending jobs. */
399
- get queueSize(): number;
400
- /**
401
- * Returns whether the scheduler is currently batching updates.
402
- */
403
- get isBatching(): boolean;
304
+ export declare const scheduler: {
305
+ /** Queue buffer */
306
+ _queueBuffer: [SchedulerJob[], SchedulerJob[]];
307
+ _bufferIndex: number;
308
+ _size: number;
309
+ /** Epoch counter */
310
+ _epoch: number;
311
+ /** State flags */
312
+ _isProcessing: boolean;
313
+ _isBatching: boolean;
314
+ _isFlushingSync: boolean;
315
+ /** Batching state */
316
+ _batchDepth: number;
317
+ _batchQueue: SchedulerJob[];
318
+ _batchQueueSize: number;
319
+ /** Config */
320
+ _maxFlushIterations: number;
321
+ readonly phase: SchedulerPhase;
322
+ readonly queueSize: number;
323
+ readonly isBatching: boolean;
404
324
  /**
405
- * Schedules a task for execution.
325
+ * Schedules job.
406
326
  */
407
327
  schedule(callback: SchedulerJob): void;
408
328
  /**
409
- * Schedules a microtask-based flush of the queue.
410
- * Coalesces multiple schedule calls into a single microtask execution.
411
- */
412
- private flush;
413
- /**
414
- * Immediately flushes all queues synchronously.
415
- * Used at the end of a batch block or when immediate reflection is required.
329
+ * Triggers flush.
416
330
  */
417
- private flushSync;
331
+ _flush(): void;
418
332
  /**
419
- * Merges jobs from the batching queue into the primary queue.
420
- * Increments the epoch to ensure deduplication.
333
+ * Scheduler loop.
421
334
  */
422
- private _mergeBatchQueue;
423
- private _drainQueue;
424
- private _processQueue;
425
- private _handleFlushOverflow;
426
- private _processJobs;
335
+ _runLoop: () => void;
336
+ _flushSync(): void;
337
+ _mergeBatchQueue(): void;
338
+ _drainQueue(): void;
339
+ _processQueue(): void;
340
+ _handleFlushOverflow(): void;
427
341
  startBatch(): void;
428
342
  endBatch(): void;
429
343
  setMaxFlushIterations(max: number): void;
430
- }
431
-
432
- export declare const scheduler: Scheduler;
344
+ };
433
345
 
434
346
  /**
435
- * Scheduler configuration
436
- * Controls batching behavior and performance limits
347
+ * Scheduler configuration.
437
348
  */
438
349
  export declare const SCHEDULER_CONFIG: {
439
- /** Maximum effect executions per second to detect infinite loops (Legacy/Fallback) */
440
350
  readonly MAX_EXECUTIONS_PER_SECOND: 1000;
441
- /** Threshold for cleaning up old execution timestamps */
442
- readonly CLEANUP_THRESHOLD: 1000;
443
- /**
444
- * Maximum executions per effect within a single flush cycle
445
- * Increased from 50 to 100
446
- */
447
351
  readonly MAX_EXECUTIONS_PER_EFFECT: 100;
448
- /**
449
- * Maximum total executions across all effects in a single flush cycle
450
- * Increased from 5000 to 10000
451
- */
452
352
  readonly MAX_EXECUTIONS_PER_FLUSH: 10000;
453
- /** Maximum iterations for synchronous flush loop to prevent infinite loops */
454
353
  readonly MAX_FLUSH_ITERATIONS: 1000;
455
- /** Minimum allowed value for max flush iterations */
456
354
  readonly MIN_FLUSH_ITERATIONS: 10;
457
- /** Threshold for shrinking the batch queue to assist GC */
355
+ readonly CLEANUP_THRESHOLD: 1000;
458
356
  readonly BATCH_QUEUE_SHRINK_THRESHOLD: 1000;
459
357
  };
460
358
 
461
- /**
462
- * Error thrown by the scheduler system
463
- *
464
- * Scheduler errors indicate fundamental issues with the batching/scheduling
465
- * mechanism and are considered non-recoverable.
466
- */
359
+ /** Scheduler error. */
467
360
  export declare class SchedulerError extends AtomError {
468
- /**
469
- * Creates a new SchedulerError
470
- * @param message - Error message
471
- * @param cause - Original error
472
- */
473
361
  constructor(message: string, cause?: Error | null);
474
362
  }
475
363
 
476
- /**
477
- * Scheduler job interface.
478
- */
479
364
  declare interface SchedulerJob {
480
365
  (): void;
481
- /** Epoch for deduplication */
366
+ /** Next scheduled epoch */
482
367
  _nextEpoch?: number;
483
368
  }
484
369
 
485
- /**
486
- * Current state of the scheduler.
487
- */
488
370
  declare enum SchedulerPhase {
489
- /** No pending jobs, not currently flushing. */
490
371
  IDLE = 0,
491
- /** Currently within a batch() block. */
492
372
  BATCHING = 1,
493
- /** Currently executing queued jobs. */
494
373
  FLUSHING = 2
495
374
  }
496
375
 
497
- /**
498
- * Subscriber interface for dependency notifications
499
- */
500
376
  export declare interface Subscriber {
501
377
  execute(): void;
502
378
  }
503
379
 
504
- /**
505
- * Transform function type
506
- */
507
380
  export declare type TransformFunction<T, U> = (value: T) => U;
508
381
 
509
382
  /**
510
- * Executes a function without tracking any reactive dependencies accessed during its execution.
511
- * This prevents the calling context from subscribing to any atoms read within the callback.
383
+ * Untracked execution.
512
384
  *
513
- * @param fn - The function to execute in an untracked context.
514
- * @returns The value returned by the provided function.
515
- * @throws {AtomError} If the provided argument is not a function.
385
+ * @param fn - Function to execute.
386
+ * @returns Result of `fn`.
516
387
  */
517
388
  export declare function untracked<T>(fn: () => T): T;
518
389
 
519
- /** Represents a writable reactive atom. */
390
+ /**
391
+ * Writable atom interface.
392
+ */
520
393
  export declare interface WritableAtom<T = unknown> extends ReadonlyAtom<T> {
521
- /** The current value of the atom. Setting this will trigger notifications if the value changes. */
522
394
  value: T;
523
- /** Disposes of the atom and releases associated resources. */
395
+ /**
396
+ * Cleans up the atom and releases resources.
397
+ */
524
398
  dispose(): void;
525
399
  }
526
400