@but212/atom-effect 0.3.2 → 0.4.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/README.md +13 -83
- package/dist/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +33 -279
- package/dist/index.mjs +460 -903
- package/dist/index.mjs.map +1 -1
- package/package.json +9 -9
package/dist/index.d.ts
CHANGED
|
@@ -2,42 +2,22 @@
|
|
|
2
2
|
* Async computation states for computed atoms
|
|
3
3
|
*/
|
|
4
4
|
export declare const AsyncState: {
|
|
5
|
-
IDLE: "idle";
|
|
6
|
-
PENDING: "pending";
|
|
7
|
-
RESOLVED: "resolved";
|
|
8
|
-
REJECTED: "rejected";
|
|
5
|
+
readonly IDLE: "idle";
|
|
6
|
+
readonly PENDING: "pending";
|
|
7
|
+
readonly RESOLVED: "resolved";
|
|
8
|
+
readonly REJECTED: "rejected";
|
|
9
9
|
};
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
/** Type derived from AsyncState constant values */
|
|
12
|
+
export declare type AsyncStateType = (typeof AsyncState)[keyof typeof AsyncState];
|
|
12
13
|
|
|
13
14
|
/**
|
|
14
|
-
* Creates a
|
|
15
|
-
*
|
|
16
|
-
* @
|
|
17
|
-
* @param initialValue - The initial value of the atom
|
|
18
|
-
* @param options - Optional configuration options
|
|
19
|
-
* @returns A writable atom instance
|
|
20
|
-
*
|
|
21
|
-
* @example
|
|
22
|
-
* ```ts
|
|
23
|
-
* // Basic usage
|
|
24
|
-
* const count = atom(0);
|
|
25
|
-
*
|
|
26
|
-
* // With sync option for immediate notifications
|
|
27
|
-
* const syncCount = atom(0, { sync: true });
|
|
28
|
-
*
|
|
29
|
-
* // Reading and writing
|
|
30
|
-
* console.log(count.value); // 0
|
|
31
|
-
* count.value = 5;
|
|
32
|
-
* console.log(count.peek()); // 5 (non-tracking read)
|
|
33
|
-
* ```
|
|
15
|
+
* Creates a reactive atom holding mutable state.
|
|
16
|
+
* @param initialValue - Initial value
|
|
17
|
+
* @param options - { sync?: boolean } for immediate notifications
|
|
34
18
|
*/
|
|
35
19
|
export declare function atom<T>(initialValue: T, options?: AtomOptions): WritableAtom<T>;
|
|
36
20
|
|
|
37
|
-
/**
|
|
38
|
-
* @fileoverview Error class hierarchy for atom-effect library
|
|
39
|
-
* @description Structured error classes with cause tracking and recoverability flags
|
|
40
|
-
*/
|
|
41
21
|
/**
|
|
42
22
|
* Base error class for all atom-effect errors
|
|
43
23
|
*
|
|
@@ -103,33 +83,10 @@ export declare interface AtomOptions {
|
|
|
103
83
|
export declare function batch<T>(callback: () => T): T;
|
|
104
84
|
|
|
105
85
|
/**
|
|
106
|
-
* Creates a computed value
|
|
107
|
-
*
|
|
108
|
-
*
|
|
109
|
-
* -
|
|
110
|
-
* - Lazily recompute only when dependencies change (dirty checking)
|
|
111
|
-
* - Support both synchronous and asynchronous computations
|
|
112
|
-
* - Cache results until dependencies change (memoization)
|
|
113
|
-
* - Use bit flags for efficient state management
|
|
114
|
-
* - Provide async state tracking (idle/pending/resolved/rejected)
|
|
115
|
-
*
|
|
116
|
-
* @template T - The type of the computed value
|
|
117
|
-
* @param fn - Computation function (can return T or Promise<T>)
|
|
118
|
-
* @param options - Configuration options
|
|
119
|
-
* @returns A readonly computed atom with automatic dependency tracking
|
|
120
|
-
*
|
|
121
|
-
* @example
|
|
122
|
-
* ```ts
|
|
123
|
-
* // Synchronous computed
|
|
124
|
-
* const count = atom(0);
|
|
125
|
-
* const doubled = computed(() => count.value * 2);
|
|
126
|
-
*
|
|
127
|
-
* // Asynchronous computed with default value
|
|
128
|
-
* const userData = computed(
|
|
129
|
-
* async () => fetch(`/api/user/${userId.value}`).then(r => r.json()),
|
|
130
|
-
* { defaultValue: null }
|
|
131
|
-
* );
|
|
132
|
-
* ```
|
|
86
|
+
* Creates a computed value with automatic dependency tracking.
|
|
87
|
+
* Supports sync/async computations with caching and lazy evaluation.
|
|
88
|
+
* @param fn - Computation function (sync or async)
|
|
89
|
+
* @param options - { equal?, defaultValue?, onError?, lazy? }
|
|
133
90
|
*/
|
|
134
91
|
export declare function computed<T>(fn: () => T, options?: ComputedOptions<T>): ComputedAtom<T>;
|
|
135
92
|
|
|
@@ -180,28 +137,8 @@ export declare const DEBUG_CONFIG: {
|
|
|
180
137
|
};
|
|
181
138
|
|
|
182
139
|
/**
|
|
183
|
-
* Debug
|
|
184
|
-
*
|
|
185
|
-
* Provides development-time features including:
|
|
186
|
-
* - Circular dependency detection (direct and indirect)
|
|
187
|
-
* - Large dependency graph warnings
|
|
188
|
-
* - Debug metadata attachment for inspection
|
|
189
|
-
*
|
|
190
|
-
* @remarks
|
|
191
|
-
* Most features are only active when `NODE_ENV === 'development'`
|
|
192
|
-
* to avoid performance overhead in production builds.
|
|
193
|
-
*
|
|
194
|
-
* @example
|
|
195
|
-
* ```typescript
|
|
196
|
-
* // Check for circular dependencies
|
|
197
|
-
* debug.checkCircular(dependencyAtom, computedAtom);
|
|
198
|
-
*
|
|
199
|
-
* // Warn about potential issues
|
|
200
|
-
* debug.warn(count > 100, 'Large dependency count detected');
|
|
201
|
-
*
|
|
202
|
-
* // Attach debug info to a reactive object
|
|
203
|
-
* debug.attachDebugInfo(atom, 'atom', 42);
|
|
204
|
-
* ```
|
|
140
|
+
* Debug utilities for development-time dependency tracking and circular detection.
|
|
141
|
+
* Most features only active when `NODE_ENV === 'development'`.
|
|
205
142
|
*/
|
|
206
143
|
export declare const DEBUG_RUNTIME: DebugConfig;
|
|
207
144
|
|
|
@@ -213,10 +150,13 @@ export declare interface DebugConfig {
|
|
|
213
150
|
maxDependencies: number;
|
|
214
151
|
warnInfiniteLoop: boolean;
|
|
215
152
|
warn(condition: boolean, message: string): void;
|
|
216
|
-
|
|
153
|
+
/** Checks for circular dependencies between reactive nodes */
|
|
154
|
+
checkCircular(dep: Dependency, current: object): void;
|
|
217
155
|
attachDebugInfo(obj: object, type: string, id: number): void;
|
|
218
|
-
|
|
219
|
-
|
|
156
|
+
/** Returns debug name if available (requires obj to have DEBUG_NAME symbol) */
|
|
157
|
+
getDebugName(obj: object | null | undefined): string | undefined;
|
|
158
|
+
/** Returns debug type if available (requires obj to have DEBUG_TYPE symbol) */
|
|
159
|
+
getDebugType(obj: object | null | undefined): string | undefined;
|
|
220
160
|
}
|
|
221
161
|
|
|
222
162
|
/**
|
|
@@ -255,65 +195,10 @@ export declare interface DependencyEntry<T extends object = Dependency> {
|
|
|
255
195
|
}
|
|
256
196
|
|
|
257
197
|
/**
|
|
258
|
-
* Creates a reactive effect that
|
|
259
|
-
*
|
|
260
|
-
* @param
|
|
261
|
-
*
|
|
262
|
-
* @param options - Configuration options for the effect
|
|
263
|
-
* @param options.sync - If true, re-executes synchronously on dependency changes.
|
|
264
|
-
* Defaults to false (scheduled/batched execution).
|
|
265
|
-
* @param options.maxExecutionsPerSecond - Maximum executions per second before
|
|
266
|
-
* infinite loop detection triggers.
|
|
267
|
-
* Defaults to `SCHEDULER_CONFIG.MAX_EXECUTIONS_PER_SECOND`.
|
|
268
|
-
* @param options.trackModifications - If true, tracks and warns about dependencies
|
|
269
|
-
* that are both read and modified. Defaults to false.
|
|
270
|
-
*
|
|
271
|
-
* @returns An {@link EffectObject} with `run()`, `dispose()`, and state properties
|
|
272
|
-
*
|
|
273
|
-
* @throws {EffectError} If `fn` is not a function
|
|
274
|
-
*
|
|
275
|
-
* @remarks
|
|
276
|
-
* Effects are the primary way to perform side effects in response to reactive
|
|
277
|
-
* state changes. They automatically track which reactive values (atoms, computed)
|
|
278
|
-
* are accessed during execution and re-run when those values change.
|
|
279
|
-
*
|
|
280
|
-
* The effect function may return a cleanup function that will be called before
|
|
281
|
-
* the next execution or when the effect is disposed. This is useful for
|
|
282
|
-
* cleaning up subscriptions, timers, or other resources.
|
|
283
|
-
*
|
|
284
|
-
* @example
|
|
285
|
-
* Basic usage:
|
|
286
|
-
* ```typescript
|
|
287
|
-
* const counter = atom(0);
|
|
288
|
-
*
|
|
289
|
-
* const fx = effect(() => {
|
|
290
|
-
* console.log('Counter:', counter.value);
|
|
291
|
-
* });
|
|
292
|
-
* // Logs: "Counter: 0"
|
|
293
|
-
*
|
|
294
|
-
* counter.value = 1;
|
|
295
|
-
* // Logs: "Counter: 1"
|
|
296
|
-
*
|
|
297
|
-
* fx.dispose(); // Stop the effect
|
|
298
|
-
* ```
|
|
299
|
-
*
|
|
300
|
-
* @example
|
|
301
|
-
* With cleanup function:
|
|
302
|
-
* ```typescript
|
|
303
|
-
* const fx = effect(() => {
|
|
304
|
-
* const timer = setInterval(() => console.log('tick'), 1000);
|
|
305
|
-
* return () => clearInterval(timer); // Cleanup
|
|
306
|
-
* });
|
|
307
|
-
* ```
|
|
308
|
-
*
|
|
309
|
-
* @example
|
|
310
|
-
* Synchronous execution:
|
|
311
|
-
* ```typescript
|
|
312
|
-
* const fx = effect(
|
|
313
|
-
* () => console.log(counter.value),
|
|
314
|
-
* { sync: true }
|
|
315
|
-
* );
|
|
316
|
-
* ```
|
|
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
|
|
317
202
|
*/
|
|
318
203
|
export declare function effect(fn: EffectFunction, options?: EffectOptions): EffectObject;
|
|
319
204
|
|
|
@@ -378,139 +263,32 @@ export declare interface ReadonlyAtom<T = unknown> {
|
|
|
378
263
|
peek(): T;
|
|
379
264
|
}
|
|
380
265
|
|
|
266
|
+
/**
|
|
267
|
+
* Scheduler for reactive updates with batching support.
|
|
268
|
+
* Uses epoch-based O(1) deduplication and double buffering.
|
|
269
|
+
*/
|
|
381
270
|
declare class Scheduler {
|
|
382
|
-
/** Queue of callbacks waiting for microtask execution */
|
|
383
|
-
/** Queue buffers for double buffering optimization */
|
|
384
271
|
private queueA;
|
|
385
272
|
private queueB;
|
|
386
|
-
/** Currently active queue receiving new tasks */
|
|
387
273
|
private queue;
|
|
388
274
|
private queueSize;
|
|
389
|
-
/** Epoch for O(1) deduplication */
|
|
390
275
|
private _epoch;
|
|
391
|
-
/** Whether the scheduler is currently processing the queue */
|
|
392
276
|
private isProcessing;
|
|
393
|
-
/** Whether batching is currently active */
|
|
394
277
|
isBatching: boolean;
|
|
395
|
-
/** Current nesting depth of batch operations */
|
|
396
278
|
private batchDepth;
|
|
397
|
-
/** Array of callbacks queued during batching */
|
|
398
279
|
private batchQueue;
|
|
399
|
-
/** Current size of the batch queue (for array reuse) */
|
|
400
280
|
private batchQueueSize;
|
|
401
|
-
/** Whether synchronous flush is in progress */
|
|
402
281
|
private isFlushingSync;
|
|
403
|
-
/** Maximum iterations allowed during flush to prevent infinite loops */
|
|
404
282
|
private maxFlushIterations;
|
|
405
|
-
/**
|
|
406
|
-
* Gets the current phase of the scheduler.
|
|
407
|
-
*/
|
|
408
283
|
get phase(): SchedulerPhase;
|
|
409
|
-
/**
|
|
410
|
-
* Schedules a callback for execution.
|
|
411
|
-
*
|
|
412
|
-
* If batching is active or a sync flush is in progress, the callback
|
|
413
|
-
* is added to the batch queue. Otherwise, it's added to the main queue
|
|
414
|
-
* and a flush is triggered via microtask.
|
|
415
|
-
*
|
|
416
|
-
* @param callback - The function to schedule for execution
|
|
417
|
-
* @throws {SchedulerError} If callback is not a function
|
|
418
|
-
*
|
|
419
|
-
* @example
|
|
420
|
-
* ```typescript
|
|
421
|
-
* scheduler.schedule(() => {
|
|
422
|
-
* // This runs in the next microtask (or sync if batching)
|
|
423
|
-
* updateUI();
|
|
424
|
-
* });
|
|
425
|
-
* ```
|
|
426
|
-
*/
|
|
427
284
|
schedule(callback: SchedulerJob): void;
|
|
428
|
-
/**
|
|
429
|
-
* Flushes the queue asynchronously via microtask.
|
|
430
|
-
*
|
|
431
|
-
* Executes all queued callbacks in a microtask, allowing the current
|
|
432
|
-
* synchronous execution to complete first. Errors in individual
|
|
433
|
-
* callbacks are caught and logged without interrupting others.
|
|
434
|
-
*
|
|
435
|
-
* @private
|
|
436
|
-
* @remarks
|
|
437
|
-
* This method is idempotent - calling it multiple times while
|
|
438
|
-
* processing is active has no effect.
|
|
439
|
-
*/
|
|
440
285
|
private flush;
|
|
441
|
-
/**
|
|
442
|
-
* Flushes all queued callbacks synchronously.
|
|
443
|
-
*
|
|
444
|
-
* This method is called when a batch ends. It processes all callbacks
|
|
445
|
-
* in the batch queue and main queue synchronously, allowing callbacks
|
|
446
|
-
* to schedule additional callbacks that are processed in the same flush.
|
|
447
|
-
*
|
|
448
|
-
* @private
|
|
449
|
-
* @remarks
|
|
450
|
-
* - Includes infinite loop protection via maxFlushIterations
|
|
451
|
-
* - Errors in callbacks are caught and logged individually
|
|
452
|
-
* - The isFlushingSync flag prevents re-entrancy issues
|
|
453
|
-
*/
|
|
454
286
|
private flushSync;
|
|
455
|
-
/**
|
|
456
|
-
* Starts a new batch operation.
|
|
457
|
-
*
|
|
458
|
-
* While batching is active, all scheduled callbacks are deferred
|
|
459
|
-
* until endBatch() is called. Batches can be nested - only the
|
|
460
|
-
* outermost endBatch() triggers execution.
|
|
461
|
-
*
|
|
462
|
-
* @example
|
|
463
|
-
* ```typescript
|
|
464
|
-
* scheduler.startBatch();
|
|
465
|
-
* // All updates here are deferred
|
|
466
|
-
* atom1.value = 'a';
|
|
467
|
-
* atom2.value = 'b';
|
|
468
|
-
* scheduler.endBatch(); // Both updates processed together
|
|
469
|
-
* ```
|
|
470
|
-
*/
|
|
471
287
|
startBatch(): void;
|
|
472
|
-
/**
|
|
473
|
-
* Ends a batch operation.
|
|
474
|
-
*
|
|
475
|
-
* Decrements the batch depth counter. When depth reaches zero,
|
|
476
|
-
* all queued callbacks are flushed synchronously and batching
|
|
477
|
-
* is disabled.
|
|
478
|
-
*
|
|
479
|
-
* @remarks
|
|
480
|
-
* Safe to call even if startBatch() wasn't called - depth is
|
|
481
|
-
* clamped to zero minimum.
|
|
482
|
-
*
|
|
483
|
-
* @example
|
|
484
|
-
* ```typescript
|
|
485
|
-
* scheduler.startBatch();
|
|
486
|
-
* try {
|
|
487
|
-
* // ... batched operations
|
|
488
|
-
* } finally {
|
|
489
|
-
* scheduler.endBatch(); // Always end batch, even on error
|
|
490
|
-
* }
|
|
491
|
-
* ```
|
|
492
|
-
*/
|
|
493
288
|
endBatch(): void;
|
|
494
|
-
/**
|
|
495
|
-
* Sets the maximum number of flush iterations allowed.
|
|
496
|
-
*
|
|
497
|
-
* This limit prevents infinite loops when reactive dependencies
|
|
498
|
-
* form cycles. If exceeded, the queue is cleared and an error
|
|
499
|
-
* is logged.
|
|
500
|
-
*
|
|
501
|
-
* @param max - Maximum iterations (must be at least 10)
|
|
502
|
-
* @throws {SchedulerError} If max is less than 10
|
|
503
|
-
*
|
|
504
|
-
* @example
|
|
505
|
-
* ```typescript
|
|
506
|
-
* // Increase limit for complex dependency graphs
|
|
507
|
-
* scheduler.setMaxFlushIterations(5000);
|
|
508
|
-
* ```
|
|
509
|
-
*/
|
|
510
289
|
setMaxFlushIterations(max: number): void;
|
|
511
290
|
}
|
|
512
291
|
|
|
513
|
-
/** Global scheduler instance for reactive updates */
|
|
514
292
|
export declare const scheduler: Scheduler;
|
|
515
293
|
|
|
516
294
|
/**
|
|
@@ -532,6 +310,10 @@ export declare const SCHEDULER_CONFIG: {
|
|
|
532
310
|
* Increased from 1000 to 5000 based on evaluation report
|
|
533
311
|
*/
|
|
534
312
|
readonly MAX_EXECUTIONS_PER_FLUSH: 5000;
|
|
313
|
+
/** Maximum iterations for synchronous flush loop to prevent infinite loops */
|
|
314
|
+
readonly MAX_FLUSH_ITERATIONS: 1000;
|
|
315
|
+
/** Minimum allowed value for max flush iterations */
|
|
316
|
+
readonly MIN_FLUSH_ITERATIONS: 10;
|
|
535
317
|
};
|
|
536
318
|
|
|
537
319
|
/**
|
|
@@ -553,34 +335,6 @@ declare type SchedulerJob = (() => void) & {
|
|
|
553
335
|
_nextEpoch?: number;
|
|
554
336
|
};
|
|
555
337
|
|
|
556
|
-
/**
|
|
557
|
-
* Scheduler for managing reactive updates and batching operations.
|
|
558
|
-
*
|
|
559
|
-
* The Scheduler is responsible for coordinating when reactive computations
|
|
560
|
-
* are executed. It supports both immediate (microtask) execution and
|
|
561
|
-
* batched synchronous execution for optimal performance.
|
|
562
|
-
*
|
|
563
|
-
* Key features:
|
|
564
|
-
* - Deduplication of callbacks via Set
|
|
565
|
-
* - Nested batch support with depth tracking
|
|
566
|
-
* - Infinite loop protection with configurable iteration limit
|
|
567
|
-
* - Error isolation to prevent one callback from breaking others
|
|
568
|
-
*
|
|
569
|
-
* @example
|
|
570
|
-
* ```typescript
|
|
571
|
-
* // Schedule a callback for microtask execution
|
|
572
|
-
* scheduler.schedule(() => console.log('Updated!'));
|
|
573
|
-
*
|
|
574
|
-
* // Batch multiple updates
|
|
575
|
-
* scheduler.startBatch();
|
|
576
|
-
* scheduler.schedule(() => console.log('Update 1'));
|
|
577
|
-
* scheduler.schedule(() => console.log('Update 2'));
|
|
578
|
-
* scheduler.endBatch(); // Both execute synchronously here
|
|
579
|
-
* ```
|
|
580
|
-
*/
|
|
581
|
-
/**
|
|
582
|
-
* Phases of the scheduler execution cycle.
|
|
583
|
-
*/
|
|
584
338
|
declare enum SchedulerPhase {
|
|
585
339
|
IDLE = 0,
|
|
586
340
|
BATCHING = 1,
|