@but212/atom-effect 0.16.0 → 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/README.md CHANGED
@@ -2,159 +2,46 @@
2
2
 
3
3
  [![npm version](https://img.shields.io/npm/v/@but212/atom-effect.svg)](https://www.npmjs.com/package/@but212/atom-effect)
4
4
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
5
- [![TypeScript](https://img.shields.io/badge/TypeScript-5.9-blue.svg)](https://www.typescriptlang.org/)
6
5
 
7
- a signal for reactive state management.
6
+ ## Quick Start
8
7
 
9
- ## Installation
8
+ ### Installation
10
9
 
11
10
  ```bash
12
- npm i @but212/atom-effect
11
+ npm install @but212/atom-effect
13
12
  ```
14
13
 
15
- ### CDN
16
-
17
- ```html
18
- <script src="https://cdn.jsdelivr.net/npm/@but212/atom-effect@latest"></script>
19
- <!-- or -->
20
- <script src="https://unpkg.com/@but212/atom-effect@latest"></script>
21
- ```
22
-
23
- ## Core API
24
-
25
- ### `atom(value)`
26
-
27
- Creates a mutable state container.
28
-
29
- - **read**: `atom.value` (tracks dependency)
30
- - **write**: `atom.value = newValue` (triggers effects)
31
- - **peek**: `atom.peek()` (read without tracking)
32
-
33
- ```typescript
34
- const count = atom(0);
35
- count.value++;
36
- console.log(count.value);
37
- ```
38
-
39
- ### `computed(fn)`
40
-
41
- Creates a derived value that automatically updates when dependencies change.
42
-
43
- - Lazy evaluation (only computes when read or needed by an effect).
44
- - Caches result until dependencies change.
14
+ ### Usage in 30 Seconds
45
15
 
46
16
  ```typescript
47
- const double = computed(() => count.value * 2);
48
- ```
49
-
50
- ### `effect(fn)`
51
-
52
- Runs a function immediately and re-runs it whenever its dependencies change.
53
-
54
- - Returns a `dispose` function to stop the effect.
55
-
56
- ```typescript
57
- const eff = effect(() => {
58
- console.log(count.value);
59
- });
60
- eff.dispose(); // Stop the effect
61
- ```
62
-
63
- ### `batch(fn)`
64
-
65
- Groups multiple updates and ensures they are **flushed synchronously** when the function completes.
66
-
67
- > **Note:** While the library automatically batches updates using microtasks, `batch()` is useful when you need to ensure all effects have run immediately after a block of changes.
68
-
69
- ```typescript
70
- batch(() => {
71
- count.value = 1;
72
- count.value = 2;
73
- });
74
- // Effects are guaranteed to have run synchronously here
75
- ```
17
+ import { atom, computed, effect } from '@but212/atom-effect';
76
18
 
77
- ### `untracked(fn)`
19
+ // 1. Create State
20
+ const count = atom(0);
21
+ const multiplier = atom(2);
78
22
 
79
- Runs a function without tracking any dependencies accessed within it.
23
+ // 2. Derive State (Lazy & Cached)
24
+ const doubled = computed(() => count.value * multiplier.value);
80
25
 
81
- ```typescript
82
- computed(() => {
83
- // `count` is not tracked as a dependency here
84
- return untracked(() => count.value * 2);
26
+ // 3. React to Changes
27
+ const dispose = effect(() => {
28
+ console.log(`Count: ${count.value}, Doubled: ${doubled.value}`);
85
29
  });
86
- ```
87
-
88
- ## API Reference
89
-
90
- ### Detailed Options
91
-
92
- #### `atom(initialValue, options?)`
93
-
94
- - `name`: (string) Debug name.
95
-
96
- #### `computed(fn, options?)`
97
-
98
- - `equal`: (fn) Comparison function to skip re-computes.
99
- - `defaultValue`: (any) Value to return when pending/error.
100
- - `lazy`: (boolean) If true, defers evaluation until read.
101
-
102
- #### `effect(fn, options?)`
103
-
104
- - `sync`: (boolean) Runs synchronously on change.
105
- - `onError`: (fn) Async error handler.
106
- - `trackModifications`: (boolean) Warns on self-writes.
107
-
108
- ### Advanced Usage
109
-
110
- #### Async Computed
30
+ // Output: "Count: 0, Doubled: 0"
111
31
 
112
- ```typescript
113
- const userId = atom(1);
114
- const user = computed(async () => {
115
- const res = await fetch(`/api/users/${userId.value}`);
116
- return res.json();
117
- }, { defaultValue: { loading: true } });
118
- ```
119
-
120
- ## Utilities & Development
121
-
122
- ### Type Guards
32
+ // 4. Update State
33
+ count.value = 1;
34
+ // Output: "Count: 1, Doubled: 2"
123
35
 
124
- ```typescript
125
- import { isAtom, isComputed, isEffect } from '@but212/atom-effect';
126
-
127
- isAtom(count); // true
128
- isComputed(double); // true
36
+ // 5. Cleanup
37
+ dispose();
129
38
  ```
130
39
 
131
- ### Development Commands
132
-
133
- ```bash
134
- pnpm test # Run unit tests
135
- pnpm bench # Run benchmarks
136
- pnpm lint # Run lint checks
137
- pnpm build # Build production bundle
138
- ```
139
-
140
- ## Performance
141
-
142
- > *Note: These numbers represent pure engine throughput in isolation. Actual app performance often depends on external factors like DOM updates and layout.*
143
-
144
- | Operation | Performance |
145
- | --- | --- |
146
- | Atom creation (x1000) | ~10.7K ops/sec |
147
- | Atom read (x1000) | ~32.8K ops/sec |
148
- | Atom write (x1000) | ~552K ops/sec |
149
- | Computed creation (x1000) | ~3.22K ops/sec |
150
- | Computed recomputation | ~600K ops/sec |
151
- | Effect execution (x1000) | ~9.39K ops/sec |
152
- | Batched updates (x2) (x1000) | ~4.89K ops/sec |
153
- | Deep chain (100 levels) | ~10.0K ops/sec |
154
-
155
- ## Contributing
40
+ ## Documentation
156
41
 
157
- Contributions are welcome! Feel free to open an issue or submit a pull request.
42
+ - [**API Reference**](./docs/API.md): Detailed usage of `atom`, `computed`, `effect`.
43
+ - [**Architecture**](./docs/ARCHITECTURE.md): Deep dive into the epoch-based propagation system.
44
+ - [**Onboarding**](./docs/ONBOARDING.md): Guide for contributors and new team members.
158
45
 
159
46
  ## License
160
47
 
@@ -1,2 +1,2 @@
1
- (function(a,V){typeof exports=="object"&&typeof module<"u"?V(exports):typeof define=="function"&&define.amd?define(["exports"],V):(a=typeof globalThis<"u"?globalThis:a||self,V(a.AtomEffect={}))})(this,(function(a){"use strict";const V={ONE_SECOND_MS:1e3},k={IDLE:"idle",PENDING:"pending",RESOLVED:"resolved",REJECTED:"rejected"},I={DISPOSED:1,HAS_FN_SUBS:2,HAS_OBJ_SUBS:4},b={...I,EXECUTING:8},o={...I,DIRTY:8,IDLE:16,PENDING:32,RESOLVED:64,REJECTED:128,RECOMPUTING:256,HAS_ERROR:512},N={...I,SYNC:8,NOTIFICATION_SCHEDULED:16},fe={MAX_SIZE:1e3,WARMUP_SIZE:100},T={MAX_EXECUTIONS_PER_SECOND:1e3,CLEANUP_THRESHOLD:1e3,MAX_EXECUTIONS_PER_EFFECT:100,MAX_EXECUTIONS_PER_FLUSH:1e4,MAX_FLUSH_ITERATIONS:1e3,MIN_FLUSH_ITERATIONS:10,BATCH_QUEUE_SHRINK_THRESHOLD:1e3},q={MAX_DEPENDENCIES:1e3,WARN_INFINITE_LOOP:!0},v=1073741823,M=typeof process<"u"&&process.env&&process.env.NODE_ENV!=="production",Ee=Object.freeze([]);class A extends Error{constructor(e,t=null,s=!0){super(e),this.name="AtomError",this.cause=t,this.recoverable=s,this.timestamp=new Date}}class y extends A{constructor(e,t=null){super(e,t,!0),this.name="ComputedError"}}class U extends A{constructor(e,t=null){super(e,t,!1),this.name="EffectError"}}class H extends A{constructor(e,t=null){super(e,t,!1),this.name="SchedulerError"}}const E={COMPUTED_MUST_BE_FUNCTION:"Computed function must be a function",COMPUTED_ASYNC_PENDING_NO_DEFAULT:"Async computation is pending. No default value provided",COMPUTED_COMPUTATION_FAILED:"Computed computation failed",COMPUTED_ASYNC_COMPUTATION_FAILED:"Async computed computation failed",COMPUTED_CIRCULAR_DEPENDENCY:"Circular dependency detected during computation",COMPUTED_DISPOSED:"Cannot access a disposed computed",ATOM_SUBSCRIBER_MUST_BE_FUNCTION:"Subscription listener must be a function or Subscriber object",ATOM_INDIVIDUAL_SUBSCRIBER_FAILED:"Error during individual atom subscriber execution",EFFECT_MUST_BE_FUNCTION:"Effect function must be a function",EFFECT_EXECUTION_FAILED:"Effect execution failed",EFFECT_CLEANUP_FAILED:"Effect cleanup function execution failed",EFFECT_DISPOSED:"Cannot run a disposed effect",LARGE_DEPENDENCY_GRAPH:i=>`Large dependency graph detected: ${i} dependencies`,CALLBACK_ERROR_IN_ERROR_HANDLER:"Error occurred during onError callback execution"},Q=Symbol("debugName"),de=Symbol("id"),J=Symbol("type"),$=Symbol("noDefaultValue");function pe(i){return"dependencies"in i&&Array.isArray(i.dependencies)}function ee(i,e,t){if(!t.has(i.id)){if(t.add(i.id),i===e)throw new y("Indirect circular dependency detected");if(pe(i)){const s=i.dependencies;for(let n=0;n<s.length;n++){const r=s[n];r&&ee(r,e,t)}}}}const C={enabled:typeof process<"u"&&process.env?.NODE_ENV==="development",maxDependencies:q.MAX_DEPENDENCIES,warnInfiniteLoop:q.WARN_INFINITE_LOOP,warn(i,e){this.enabled&&i&&console.warn(`[Atom Effect] ${e}`)},checkCircular(i,e){if(i===e)throw new y("Direct circular dependency detected");this.enabled&&ee(i,e,new Set)},attachDebugInfo(i,e,t){if(!this.enabled)return;const s=i;s[Q]=`${e}_${t}`,s[de]=t,s[J]=e},getDebugName(i){if(i!=null&&Q in i)return i[Q]},getDebugType(i){if(i!=null&&J in i)return i[J]}};let Se=1;const ge=()=>Se++;class te{constructor(){this.flags=0,this.version=0,this._lastSeenEpoch=-1,this._modifiedAtEpoch=-1,this.id=ge()&v,this._tempUnsub=void 0}}class se extends te{subscribe(e){if(typeof e=="function")return this._addSubscriber(this._fnSubs,e,I.HAS_FN_SUBS);if(e!==null&&typeof e=="object"&&"execute"in e)return this._addSubscriber(this._objSubs,e,I.HAS_OBJ_SUBS);throw new A(E.ATOM_SUBSCRIBER_MUST_BE_FUNCTION)}_addSubscriber(e,t,s){return e.indexOf(t)!==-1?(M&&console.warn("Attempted to subscribe the same listener twice. Ignoring duplicate subscription."),()=>{}):(e.push(t),this.flags|=s,()=>{const n=e.indexOf(t);if(n===-1)return;const r=e.pop();n<e.length&&(e[n]=r),e.length===0&&(this.flags&=~s)})}subscriberCount(){return this._fnSubs.length+this._objSubs.length}_notifySubscribers(e,t){const s=this.flags;if(s&(I.HAS_FN_SUBS|I.HAS_OBJ_SUBS)){if(s&I.HAS_FN_SUBS){const n=this._fnSubs;for(let r=0;r<n.length;r++)try{n[r](e,t)}catch(h){this._handleNotifyError(h)}}if(s&I.HAS_OBJ_SUBS){const n=this._objSubs;for(let r=0;r<n.length;r++)try{n[r].execute()}catch(h){this._handleNotifyError(h)}}}}_handleNotifyError(e){console.error(new A(E.ATOM_INDIVIDUAL_SUBSCRIBER_FAILED,e))}}class De{constructor(){this.frozen=0,this.tooLarge=0,this.poolFull=0}}class Ie{constructor(){this.acquired=0,this.released=0,this.rejected=new De}}class K{constructor(){this.pool=[],this.maxPoolSize=50,this.maxReusableCapacity=256,this.stats=M?new Ie:null}acquire(){const e=this.stats;return e&&e.acquired++,this.pool.pop()??[]}release(e,t){const s=this.stats;if(t&&e===t)return;if(Object.isFrozen(e)){s&&s.rejected.frozen++;return}if(e.length>this.maxReusableCapacity){s&&s.rejected.tooLarge++;return}const n=this.pool;if(n.length>=this.maxPoolSize){s&&s.rejected.poolFull++;return}e.length=0,n.push(e),s&&s.released++}getStats(){const e=this.stats;if(!e)return null;const{acquired:t,released:s,rejected:n}=e,{frozen:r,tooLarge:h,poolFull:c}=n;return{acquired:t,released:s,rejected:{frozen:r,tooLarge:h,poolFull:c},leaked:t-s-(r+h+c),poolSize:this.pool.length}}reset(){this.pool.length=0;const e=this.stats;e&&(e.acquired=0,e.released=0,e.rejected.frozen=0,e.rejected.tooLarge=0,e.rejected.poolFull=0)}}const S=Object.freeze([]),x=Object.freeze([]),g=Object.freeze([]),F=new K,w=new K,R=new K;function P(i,e,t,s){if(e!=null){if(typeof e.addDependency=="function"){e.addDependency(i);return}if(typeof e=="function"){const n=e;t.indexOf(n)===-1&&(t.push(n),i.flags|=I.HAS_FN_SUBS);return}if(typeof e.execute=="function"){const n=e;s.indexOf(n)===-1&&(s.push(n),i.flags|=I.HAS_OBJ_SUBS)}}}function be(i,e,t,s){const n=e.length;if(n>0)for(let c=0;c<n;c++){const l=e[c];l&&(l._tempUnsub=t[c])}const r=i.length,h=w.acquire();h.length=r;for(let c=0;c<r;c++){const l=i[c];if(!l)continue;const d=l._tempUnsub;d?(h[c]=d,l._tempUnsub=void 0):(C.checkCircular(l,s),h[c]=l.subscribe(s))}if(n>0)for(let c=0;c<n;c++){const l=e[c];if(l){const d=l._tempUnsub;d&&(d(),l._tempUnsub=void 0)}}return t!==x&&w.release(t),h}let z=0;function ie(){return z=z+1&v||1,z}function Ce(){return z}let W=0,Z=0,j=!1;function ne(){return j?(M&&console.warn("Warning: startFlush() called during flush - ignored to prevent infinite loop detection bypass"),!1):(j=!0,W=W+1&v||1,Z=0,!0)}function re(){j=!1}function Oe(){return j?++Z:0}class Ne{constructor(){this._queueBuffer=[[],[]],this._bufferIndex=0,this._size=0,this._epoch=0,this._isProcessing=!1,this._isBatching=!1,this._batchDepth=0,this._batchQueue=[],this._batchQueueSize=0,this._isFlushingSync=!1,this._maxFlushIterations=T.MAX_FLUSH_ITERATIONS}get phase(){return this._isProcessing||this._isFlushingSync?2:this._isBatching?1:0}get queueSize(){return this._size}get isBatching(){return this._isBatching}schedule(e){if(M&&typeof e!="function")throw new H("Scheduler callback must be a function");const t=this._epoch;if(e._nextEpoch===t)return;if(e._nextEpoch=t,this._isBatching||this._isFlushingSync){this._batchQueue[this._batchQueueSize++]=e;return}const s=this._bufferIndex,n=this._size;this._queueBuffer[s][n]=e,this._size=n+1,this._isProcessing||this.flush()}flush(){this._isProcessing||this._size===0||(this._isProcessing=!0,queueMicrotask(()=>{try{if(this._size===0)return;const e=ne();this._drainQueue(),e&&re()}finally{this._isProcessing=!1,this._size>0&&!this._isBatching&&this.flush()}}))}flushSync(){this._isFlushingSync=!0;const e=ne();try{this._mergeBatchQueue(),this._drainQueue()}finally{this._isFlushingSync=!1,e&&re()}}_mergeBatchQueue(){const e=this._batchQueueSize;if(e===0)return;const t=++this._epoch,s=this._batchQueue,n=this._queueBuffer[this._bufferIndex];let r=this._size;for(let h=0;h<e;h++){const c=s[h];c._nextEpoch!==t&&(c._nextEpoch=t,n[r++]=c)}this._size=r,this._batchQueueSize=0,s.length>T.BATCH_QUEUE_SHRINK_THRESHOLD&&(s.length=0)}_drainQueue(){let e=0;const t=this._maxFlushIterations;for(;this._size>0;){if(++e>t){this._handleFlushOverflow();return}this._processQueue(),this._mergeBatchQueue()}}_processQueue(){const e=this._bufferIndex,t=this._queueBuffer[e],s=this._size;this._bufferIndex=e^1,this._size=0,this._epoch++,this._processJobs(t,s)}_handleFlushOverflow(){console.error(new H(`Maximum flush iterations (${this._maxFlushIterations}) exceeded. Possible infinite loop.`)),this._size=0,this._queueBuffer[this._bufferIndex].length=0,this._batchQueueSize=0}_processJobs(e,t){for(let s=0;s<t;s++)try{const n=e[s];n&&n()}catch(n){console.error(new H("Error occurred during scheduler execution",n))}e.length=0}startBatch(){this._batchDepth++,this._isBatching=!0}endBatch(){const e=this._batchDepth;if(e===0){M&&console.warn("endBatch() called without matching startBatch(). Ignoring.");return}const t=e-1;this._batchDepth=t,t===0&&(this.flushSync(),this._isBatching=!1)}setMaxFlushIterations(e){if(e<T.MIN_FLUSH_ITERATIONS)throw new H(`Max flush iterations must be at least ${T.MIN_FLUSH_ITERATIONS}`);this._maxFlushIterations=e}}const B=new Ne;class ye{constructor(){this.current=null}run(e,t){const s=this.current;this.current=e;try{return t()}finally{this.current=s}}getCurrent(){return this.current}}const p=new ye;function oe(i){if(typeof i!="function")throw new A("Untracked callback must be a function");const e=p.current;p.current=null;try{return i()}finally{p.current=e}}class Te extends se{constructor(e,t){super(),this._value=e,this._pendingOldValue=void 0,this._notifyTask=void 0,this._fnSubs=[],this._objSubs=[],t&&(this.flags|=N.SYNC),C.attachDebugInfo(this,"atom",this.id)}get value(){const e=p.current;return e&&P(this,e,this._fnSubs,this._objSubs),this._value}set value(e){const t=this._value;if(t===e||Object.is(t,e))return;this._value=e,this.version=this.version+1&v,this.flags&(N.HAS_FN_SUBS|N.HAS_OBJ_SUBS)&&this._scheduleNotification(t)}_scheduleNotification(e){let t=this.flags;if(t&N.NOTIFICATION_SCHEDULED||(this._pendingOldValue=e,t|=N.NOTIFICATION_SCHEDULED,this.flags=t),t&N.SYNC&&!B.isBatching){this._flushNotifications();return}this._notifyTask||(this._notifyTask=()=>this._flushNotifications());const s=this._notifyTask;B.schedule(s)}_flushNotifications(){const e=this.flags;if(!(e&N.NOTIFICATION_SCHEDULED)||e&N.DISPOSED)return;const t=this._pendingOldValue;this._pendingOldValue=void 0,this.flags=e&-17,this._notifySubscribers(this._value,t)}peek(){return this._value}dispose(){const e=this.flags;e&N.DISPOSED||(this._fnSubs.length=0,this._objSubs.length=0,this.flags=e|N.DISPOSED,this._value=void 0,this._pendingOldValue=void 0,this._notifyTask=void 0)}}function Ae(i,e={}){return new Te(i,e.sync??!1)}function G(i,e,t){if(i instanceof TypeError)return new e(`Type error (${t}): ${i.message}`,i);if(i instanceof ReferenceError)return new e(`Reference error (${t}): ${i.message}`,i);if(i instanceof A)return i;const s=i instanceof Error?i.message:String(i),n=i instanceof Error?i:null;return new e(`Unexpected error (${t}): ${s}`,n)}function ce(i){return i!==null&&typeof i=="object"&&"value"in i&&typeof i.subscribe=="function"}function Re(i){return C.enabled&&i!=null&&typeof i=="object"&&C.getDebugType(i)==="computed"?!0:ce(i)&&typeof i.invalidate=="function"}function me(i){return i!==null&&typeof i=="object"&&typeof i.dispose=="function"&&typeof i.run=="function"}function he(i){return i!=null&&typeof i.then=="function"}const ue=o.RESOLVED|o.PENDING|o.REJECTED,X=Array(ue+1).fill(k.IDLE);X[o.RESOLVED]=k.RESOLVED,X[o.PENDING]=k.PENDING,X[o.REJECTED]=k.REJECTED;const _e=3,ae=Number.MAX_SAFE_INTEGER-1;class le extends se{constructor(e,t={}){if(typeof e!="function")throw new y(E.COMPUTED_MUST_BE_FUNCTION);if(super(),this._value=void 0,this.flags=o.DIRTY|o.IDLE,this._error=null,this._promiseId=0,this._equal=t.equal??Object.is,this._fn=e,this._defaultValue="defaultValue"in t?t.defaultValue:$,this._onError=t.onError??null,this._fnSubs=[],this._objSubs=[],this._dependencies=S,this._dependencyVersions=g,this._unsubscribes=x,this._cachedErrors=null,this._errorCacheEpoch=-1,this._asyncStartAggregateVersion=0,this._asyncRetryCount=0,this._trackEpoch=-1,this._trackDeps=S,this._trackVersions=g,this._trackCount=0,C.attachDebugInfo(this,"computed",this.id),C.enabled){const s=this;s.subscriberCount=this.subscriberCount.bind(this),s.isDirty=()=>(this.flags&o.DIRTY)!==0,s.dependencies=this._dependencies}if(t.lazy===!1)try{this._recompute()}catch{}}get value(){const e=p.current;e&&P(this,e,this._fnSubs,this._objSubs);let t=this.flags;if((t&(o.RESOLVED|o.DIRTY|o.IDLE))===o.RESOLVED)return this._value;if(t&o.DISPOSED)throw new y(E.COMPUTED_DISPOSED);if(t&o.RECOMPUTING){const r=this._defaultValue;if(r!==$)return r;throw new y(E.COMPUTED_CIRCULAR_DEPENDENCY)}if(t&(o.DIRTY|o.IDLE)&&(this._recompute(),t=this.flags),t&o.RESOLVED)return this._value;const s=this._defaultValue,n=s!==$;if(t&o.PENDING){if(n)return s;throw new y(E.COMPUTED_ASYNC_PENDING_NO_DEFAULT)}if(t&o.REJECTED){const r=this._error;if(r?.recoverable&&n)return s;throw r}return this._value}peek(){return this._value}get state(){const e=p.current;return e&&P(this,e,this._fnSubs,this._objSubs),X[this.flags&ue]}get hasError(){const e=p.current;if(e&&P(this,e,this._fnSubs,this._objSubs),this.flags&(o.REJECTED|o.HAS_ERROR))return!0;const s=this._dependencies;for(let n=0,r=s.length;n<r;n++)if(s[n].flags&o.HAS_ERROR)return!0;return!1}get isValid(){return!this.hasError}get errors(){const e=p.current;if(e&&P(this,e,this._fnSubs,this._objSubs),!this.hasError)return Ee;const t=Ce();if(this._errorCacheEpoch===t&&this._cachedErrors!==null)return this._cachedErrors;const s=new Set,n=this._error;n&&s.add(n);const r=this._dependencies;for(let c=0,l=r.length;c<l;c++){const d=r[c];if(d.flags&o.HAS_ERROR){const O=d.errors;if(O)for(let m=0,u=O.length;m<u;m++){const f=O[m];f&&s.add(f)}}}const h=Object.freeze(Array.from(s));return this._errorCacheEpoch=t,this._cachedErrors=h,h}get lastError(){const e=p.current;return e&&P(this,e,this._fnSubs,this._objSubs),this._error}get isPending(){const e=p.current;return e&&P(this,e,this._fnSubs,this._objSubs),(this.flags&o.PENDING)!==0}get isResolved(){const e=p.current;return e&&P(this,e,this._fnSubs,this._objSubs),(this.flags&o.RESOLVED)!==0}invalidate(){this._markDirty();const e=this._dependencyVersions;e!==g&&(R.release(e),this._dependencyVersions=g),this._errorCacheEpoch=-1,this._cachedErrors=null}dispose(){if(this.flags&o.DISPOSED)return;const t=this._unsubscribes;if(t!==x){for(let r=0,h=t.length;r<h;r++){const c=t[r];c&&c()}w.release(t),this._unsubscribes=x}const s=this._dependencies;s!==S&&(F.release(s),this._dependencies=S);const n=this._dependencyVersions;n!==g&&(R.release(n),this._dependencyVersions=g),this._fnSubs.length=0,this._objSubs.length=0,this.flags=o.DISPOSED|o.DIRTY|o.IDLE,this._error=null,this._value=void 0,this._promiseId=(this._promiseId+1)%ae,this._cachedErrors=null,this._errorCacheEpoch=-1}addDependency(e){if(e._lastSeenEpoch===this._trackEpoch)return;e._lastSeenEpoch=this._trackEpoch;const t=this._trackCount,s=this._trackDeps,n=this._trackVersions;t<s.length?(s[t]=e,n[t]=e.version):(s.push(e),n.push(e.version)),this._trackCount=t+1}_commitDeps(e){const t=this._trackDeps,s=this._trackVersions,n=this._trackCount;t.length=n,s.length=n,this._unsubscribes=be(t,e,this._unsubscribes,this),this._dependencies=t,this._dependencyVersions=s}_recompute(){if(this.flags&o.RECOMPUTING)return;this.flags|=o.RECOMPUTING;const e=this._dependencies,t=this._dependencyVersions;this._trackEpoch=ie(),this._trackDeps=F.acquire(),this._trackVersions=R.acquire(),this._trackCount=0;let s=!1;try{const n=p.run(this,this._fn);this._commitDeps(e),s=!0,he(n)?this._handleAsyncComputation(n):this._finalizeResolution(n)}catch(n){let r=n;if(!s)try{this._commitDeps(e),s=!0}catch(h){r=h}this._handleComputationError(r)}finally{s?(e!==S&&F.release(e),t!==g&&R.release(t)):(F.release(this._trackDeps),R.release(this._trackVersions)),this._trackEpoch=-1,this._trackDeps=S,this._trackVersions=g,this._trackCount=0,this.flags&=-257}}_handleAsyncComputation(e){this.flags=(this.flags|o.PENDING)&-217,this._notifySubscribers(void 0,void 0),this._asyncStartAggregateVersion=this._captureVersionSnapshot(),this._asyncRetryCount=0,this._promiseId=(this._promiseId+1)%ae;const t=this._promiseId;e.then(s=>{if(t===this._promiseId){if(this._captureVersionSnapshot()!==this._asyncStartAggregateVersion){if(this._asyncRetryCount<_e){this._asyncRetryCount++,this._markDirty();return}this._handleAsyncRejection(new y(`Async drift threshold exceeded after ${_e} retries.`));return}this._finalizeResolution(s),this._notifySubscribers(s,void 0)}}).catch(s=>{t===this._promiseId&&this._handleAsyncRejection(s)})}_captureVersionSnapshot(){let e=0;const t=this._dependencies;for(let s=0,n=t.length;s<n;s++){const r=t[s];if(r){const h=r.version;e=((e<<5)-e|0)+h&v}}return e}_handleAsyncRejection(e){const t=G(e,y,E.COMPUTED_ASYNC_COMPUTATION_FAILED);this.flags&o.REJECTED||(this.version=this.version+1&v),this._error=t,this.flags=this.flags&-121|(o.REJECTED|o.HAS_ERROR);const s=this._onError;if(s)try{s(t)}catch(n){console.error(E.CALLBACK_ERROR_IN_ERROR_HANDLER,n)}this._notifySubscribers(void 0,void 0)}_finalizeResolution(e){(!(this.flags&o.RESOLVED)||!this._equal(this._value,e))&&(this.version=this.version+1&v),this._value=e,this._error=null,this.flags=(this.flags|o.RESOLVED)&-697,this._cachedErrors=null,this._errorCacheEpoch=-1}_handleComputationError(e){const t=G(e,y,E.COMPUTED_COMPUTATION_FAILED);this._error=t,this.flags=this.flags&-121|(o.REJECTED|o.HAS_ERROR);const s=this._onError;if(s)try{s(t)}catch(n){console.error(E.CALLBACK_ERROR_IN_ERROR_HANDLER,n)}throw t}execute(){this._markDirty()}_markDirty(){const e=this.flags;e&(o.RECOMPUTING|o.DIRTY)||(this.flags=e|o.DIRTY,this._notifySubscribers(void 0,void 0))}}Object.freeze(le.prototype);function Ue(i,e={}){return new le(i,e)}class xe extends te{constructor(e,t={}){super(),this._cleanup=null,this._dependencies=S,this._dependencyVersions=g,this._unsubscribes=x,this._nextDeps=null,this._nextVersions=null,this._nextUnsubs=null,this._executeTask=void 0,this._onError=t.onError??null,this._currentEpoch=-1,this._lastFlushEpoch=-1,this._executionsInEpoch=0,this._fn=e,this._sync=t.sync??!1,this._maxExecutions=t.maxExecutionsPerSecond??T.MAX_EXECUTIONS_PER_SECOND,this._maxExecutionsPerFlush=t.maxExecutionsPerFlush??T.MAX_EXECUTIONS_PER_EFFECT,this._trackModifications=t.trackModifications??!1,this._executionCount=0,this._historyPtr=0;const s=Number.isFinite(this._maxExecutions),n=s?Math.min(this._maxExecutions+1,T.MAX_EXECUTIONS_PER_SECOND+1):0;this._historyCapacity=n,this._history=M&&s&&n>0?new Array(n).fill(0):null,this._execId=0,C.attachDebugInfo(this,"effect",this.id)}run(){if(this.flags&b.DISPOSED)throw new U(E.EFFECT_DISPOSED);this.execute(!0)}dispose(){const e=this.flags;if(e&b.DISPOSED)return;if(this.flags=e|b.DISPOSED,this._cleanup){try{this._cleanup()}catch(r){this._handleExecutionError(r,E.EFFECT_CLEANUP_FAILED)}this._cleanup=null}const t=this._unsubscribes;if(t!==x){for(let r=0,h=t.length;r<h;r++){const c=t[r];c&&c()}w.release(t),this._unsubscribes=x}const s=this._dependencies;s!==S&&(F.release(s),this._dependencies=S);const n=this._dependencyVersions;n!==g&&(R.release(n),this._dependencyVersions=g),this._executeTask=void 0}addDependency(e){if(!(this.flags&b.EXECUTING))return;const s=this._currentEpoch;if(e._lastSeenEpoch===s)return;e._lastSeenEpoch=s;const n=this._nextDeps,r=this._nextVersions,h=this._nextUnsubs;n.push(e),r.push(e.version);const c=e._tempUnsub;if(c){h.push(c),e._tempUnsub=void 0;return}try{const l=this._sync,d=this._trackModifications,O=e.subscribe(()=>{if(d&&this.flags&b.EXECUTING&&(e._modifiedAtEpoch=this._currentEpoch),l){this.execute();return}this._executeTask||(this._executeTask=()=>this.execute());const m=this._executeTask;B.schedule(m)});h.push(O)}catch(l){console.error(G(l,U,E.EFFECT_EXECUTION_FAILED)),h.push(()=>{})}}execute(e=!1){if(this.flags&(b.DISPOSED|b.EXECUTING))return;if(!e){const u=this._dependencies,f=u.length;if(f>0){const _=this._dependencyVersions;let D=!1;for(let L=0;L<f;L++){const Y=u[L];if(Y.version!==_[L]){D=!0;break}if("value"in Y)try{if(oe(()=>Y.value),Y.version!==_[L]){D=!0;break}}catch{D=!0;break}}if(!D)return}}const s=W;this._lastFlushEpoch!==s&&(this._lastFlushEpoch=s,this._executionsInEpoch=0),++this._executionsInEpoch>this._maxExecutionsPerFlush&&this._throwInfiniteLoopError("per-effect"),Oe()>T.MAX_EXECUTIONS_PER_FLUSH&&this._throwInfiniteLoopError("global"),this._executionCount++;const n=this._history;if(n){const u=Date.now(),f=this._historyPtr;n[f]=u;const _=(f+1)%this._historyCapacity;this._historyPtr=_;const D=n[_]||0;if(D>0&&u-D<V.ONE_SECOND_MS){const L=new U("Effect executed too frequently within 1 second. Suspected infinite loop.");if(this.dispose(),this._handleExecutionError(L),M)throw L;return}}if(this.flags|=b.EXECUTING,this._cleanup){try{this._cleanup()}catch(u){this._handleExecutionError(u,E.EFFECT_CLEANUP_FAILED)}this._cleanup=null}const r=this._dependencies,h=this._dependencyVersions,c=this._unsubscribes;if(r!==S)for(let u=0,f=r.length;u<f;u++){const _=r[u];_&&(_._tempUnsub=c[u])}const l=F.acquire(),d=R.acquire(),O=w.acquire();this._nextDeps=l,this._nextVersions=d,this._nextUnsubs=O,this._currentEpoch=ie();let m=!1;try{const u=p.run(this,this._fn);this._dependencies=l,this._dependencyVersions=d,this._unsubscribes=O,m=!0,this._checkLoopWarnings();const f=++this._execId;he(u)?u.then(_=>{if(f!==this._execId||this.flags&b.DISPOSED){if(typeof _=="function")try{_()}catch(D){this._handleExecutionError(D,E.EFFECT_CLEANUP_FAILED)}return}typeof _=="function"&&(this._cleanup=_)}).catch(_=>{f===this._execId&&this._handleExecutionError(_)}):this._cleanup=typeof u=="function"?u:null}catch(u){m=!0,this._handleExecutionError(u),this._cleanup=null}finally{if(this._nextDeps=null,this._nextVersions=null,this._nextUnsubs=null,m){if(r!==S){for(let u=0,f=r.length;u<f;u++){const _=r[u],D=_?_._tempUnsub:void 0;D&&(D(),_&&(_._tempUnsub=void 0))}F.release(r)}h!==g&&R.release(h),c!==x&&w.release(c)}else{F.release(l),R.release(d);for(let u=0,f=O.length;u<f;u++){const _=O[u];_&&_()}if(w.release(O),r!==S)for(let u=0,f=r.length;u<f;u++){const _=r[u];_&&(_._tempUnsub=void 0)}}this.flags&=-9}}get isDisposed(){return(this.flags&b.DISPOSED)!==0}get executionCount(){return this._executionCount}get isExecuting(){return(this.flags&b.EXECUTING)!==0}_throwInfiniteLoopError(e){const t=new U(`Infinite loop detected (${e}): effect executed ${this._executionsInEpoch} times in current flush. Total executions in flush: ${Z}`);throw this.dispose(),console.error(t),t}_handleExecutionError(e,t=E.EFFECT_EXECUTION_FAILED){const s=G(e,U,t);console.error(s);const n=this._onError;if(n)try{n(s)}catch(r){console.error(G(r,U,E.CALLBACK_ERROR_IN_ERROR_HANDLER))}}_checkLoopWarnings(){if(this._trackModifications&&C.enabled){const e=this._dependencies,t=this._currentEpoch;for(let s=0,n=e.length;s<n;s++){const r=e[s];r&&r._modifiedAtEpoch===t&&C.warn(!0,`Effect is reading a dependency (${C.getDebugName(r)||"unknown"}) that it just modified. Infinite loop may occur`)}}}}function Fe(i,e={}){if(typeof i!="function")throw new U(E.EFFECT_MUST_BE_FUNCTION);const t=new xe(i,e);return t.execute(),t}function Pe(i){if(typeof i!="function")throw new A("Batch callback must be a function");B.startBatch();try{return i()}finally{B.endBatch()}}a.AsyncState=k,a.AtomError=A,a.ComputedError=y,a.DEBUG_CONFIG=q,a.DEBUG_RUNTIME=C,a.EffectError=U,a.POOL_CONFIG=fe,a.SCHEDULER_CONFIG=T,a.SchedulerError=H,a.atom=Ae,a.batch=Pe,a.computed=Ue,a.effect=Fe,a.isAtom=ce,a.isComputed=Re,a.isEffect=me,a.scheduler=B,a.untracked=oe,Object.defineProperty(a,Symbol.toStringTag,{value:"Module"})}));
1
+ (function(c,y){typeof exports=="object"&&typeof module<"u"?y(exports):typeof define=="function"&&define.amd?define(["exports"],y):(c=typeof globalThis<"u"?globalThis:c||self,y(c.AtomEffect={}))})(this,(function(c){"use strict";const y={ONE_SECOND_MS:1e3},m={IDLE:"idle",PENDING:"pending",RESOLVED:"resolved",REJECTED:"rejected"},S={DISPOSED:1,HAS_FN_SUBS:2,HAS_OBJ_SUBS:4},E={...S,EXECUTING:8},o={...S,DIRTY:8,IDLE:16,PENDING:32,RESOLVED:64,REJECTED:128,RECOMPUTING:256,HAS_ERROR:512},d={...S,SYNC:8,NOTIFICATION_SCHEDULED:16},rt={MAX_SIZE:1e3,WARMUP_SIZE:100},p={MAX_EXECUTIONS_PER_SECOND:1e3,MAX_EXECUTIONS_PER_EFFECT:100,MAX_EXECUTIONS_PER_FLUSH:1e4,MAX_FLUSH_ITERATIONS:1e3,MIN_FLUSH_ITERATIONS:10,CLEANUP_THRESHOLD:1e3,BATCH_QUEUE_SHRINK_THRESHOLD:1e3},k={MAX_DEPENDENCIES:1e3,WARN_INFINITE_LOOP:!0},b=1073741823,_=typeof process<"u"&&process.env&&process.env.NODE_ENV!=="production"||typeof __DEV__<"u"&&!!__DEV__,ot=Object.freeze([]);class O extends Error{constructor(t,e=null,s=!0){super(t),this.cause=e,this.recoverable=s,this.timestamp=new Date,this.name="AtomError"}}class I extends O{constructor(t,e=null){super(t,e,!0),this.name="ComputedError"}}class D extends O{constructor(t,e=null){super(t,e,!1),this.name="EffectError"}}class R extends O{constructor(t,e=null){super(t,e,!1),this.name="SchedulerError"}}const H=Symbol("AtomEffect.DebugName"),ht=Symbol("AtomEffect.Id"),G=Symbol("AtomEffect.Type"),P=Symbol("AtomEffect.NoDefaultValue"),ct=i=>"dependencies"in i&&Array.isArray(i.dependencies);function V(i,t,e){if(i===t)throw new I("Circular dependency detected: The computation refers to itself explicitly or implicitly.");if(!e.has(i.id)&&(e.add(i.id),ct(i))){const s=i.dependencies;for(let n=0;n<s.length;n++){const r=s[n];r&&V(r,t,e)}}}const g={enabled:_,maxDependencies:k.MAX_DEPENDENCIES,warnInfiniteLoop:k.WARN_INFINITE_LOOP,warn(i,t){_&&this.enabled&&i&&console.warn(`[Atom Effect] ${t}`)},checkCircular(i,t){if(i===t)throw new I("Direct circular dependency detected");_&&this.enabled&&V(i,t,new Set)},attachDebugInfo(i,t,e){if(!_||!this.enabled)return;const s=i;s[H]=`${t}_${e}`,s[ht]=e,s[G]=t},getDebugName:i=>i?.[H],getDebugType:i=>i?.[G]};let ut=1;const _t=()=>ut++;function z(i,t,e){if(typeof t=="function"){const n=t;for(let r=0,h=e.length;r<h;r++){const u=e[r];if(u&&u.fn===n)return}e.push(new M(n,void 0)),i.flags|=S.HAS_FN_SUBS,"_fnSubCount"in i&&i._fnSubCount++;return}if("addDependency"in t){t.addDependency(i);return}const s=t;for(let n=0,r=e.length;n<r;n++){const h=e[n];if(h&&h.sub===s)return}e.push(new M(void 0,s)),i.flags|=S.HAS_OBJ_SUBS,"_objSubCount"in i&&i._objSubCount++}function lt(i,t,e){for(let s=0,n=t.length;s<n;s++){const r=t[s];r&&(r.node._tempUnsub=r.unsub)}for(let s=0,n=i.length;s<n;s++){const r=i[s];if(!r)continue;const h=r.node;h._tempUnsub!==void 0?(r.unsub=h._tempUnsub,h._tempUnsub=void 0):(g.checkCircular(h,e),r.unsub=h.subscribe(e))}for(let s=0,n=t.length;s<n;s++){const r=t[s];if(r){const h=r.node;h._tempUnsub!==void 0&&(h._tempUnsub(),h._tempUnsub=void 0),r.unsub=void 0}}}class x{constructor(t,e,s=void 0){this.node=t,this.version=e,this.unsub=s}}class M{constructor(t,e){this.fn=t,this.sub=e}}const l={COMPUTED_MUST_BE_FUNCTION:"Computed target must be a function",COMPUTED_ASYNC_PENDING_NO_DEFAULT:"Async computation pending with no default value",COMPUTED_COMPUTATION_FAILED:"Computation execution failed",COMPUTED_ASYNC_COMPUTATION_FAILED:"Async computation execution failed",COMPUTED_CIRCULAR_DEPENDENCY:"Circular dependency detected",COMPUTED_DISPOSED:"Attempted to access disposed computed",ATOM_SUBSCRIBER_MUST_BE_FUNCTION:"Subscriber must be a function or Subscriber object",ATOM_INDIVIDUAL_SUBSCRIBER_FAILED:"Subscriber execution failed",EFFECT_MUST_BE_FUNCTION:"Effect target must be a function",EFFECT_EXECUTION_FAILED:"Effect execution failed",EFFECT_CLEANUP_FAILED:"Effect cleanup failed",EFFECT_DISPOSED:"Attempted to run disposed effect",CALLBACK_ERROR_IN_ERROR_HANDLER:"Exception encountered in onError handler"};function N(i,t,e){if(i instanceof O)return i;const s=i instanceof Error,n=s?i.message:String(i),r=s?i:void 0;let h="Unexpected error";i instanceof TypeError?h="Type error":i instanceof ReferenceError&&(h="Reference error");const u=`${h} (${e}): ${n}`;return new t(u,r)}class X{constructor(){this.flags=0,this.version=0,this._lastSeenEpoch=-1,this._modifiedAtEpoch=-1,this.id=_t()&b,this._tempUnsub=void 0}}class j extends X{constructor(){super(...arguments),this._fnSubCount=0,this._objSubCount=0}subscribe(t){const e=typeof t=="function";if(!e&&(!t||typeof t.execute!="function"))throw N(new TypeError("Invalid subscriber"),O,l.ATOM_SUBSCRIBER_MUST_BE_FUNCTION);const s=this._subscribers;for(let r=0,h=s.length;r<h;r++){const u=s[r];if(u&&(e?u.fn===t:u.sub===t))return _&&console.warn("Duplicate subscription ignored."),()=>{}}const n=new M(e?t:void 0,e?void 0:t);return s.push(n),e?(this._fnSubCount++,this.flags|=S.HAS_FN_SUBS):(this._objSubCount++,this.flags|=S.HAS_OBJ_SUBS),()=>this._unsubscribe(n)}_unsubscribe(t){const e=this._subscribers,s=e.indexOf(t);if(s===-1)return;const n=e.pop();s<e.length&&n&&(e[s]=n),t.fn?this._fnSubCount--:this._objSubCount--,e.length===0?(this.flags&=-7,this._fnSubCount=0,this._objSubCount=0):t.fn&&this._fnSubCount<=0?(this.flags&=-3,this._fnSubCount=0):!t.fn&&this._objSubCount<=0&&(this.flags&=-5,this._objSubCount=0)}subscriberCount(){return this._subscribers.length}_notifySubscribers(t,e){if(!(this.flags&(S.HAS_FN_SUBS|S.HAS_OBJ_SUBS)))return;const s=this._subscribers,n=s.length;for(let r=0;r<n;r++){const h=s[r];if(h)try{h.fn?h.fn(t,e):h.sub&&h.sub.execute()}catch(u){this._handleNotifyError(u)}}}_handleNotifyError(t){console.error(N(t,O,l.ATOM_INDIVIDUAL_SUBSCRIBER_FAILED))}}let U=0;const Y=()=>(U=U+1&b||1,U),at=()=>U;let v=0,w=0,F=!1;function Q(){return F?(_&&console.warn("startFlush() called during flush - ignored"),!1):(F=!0,v=v+1&b||1,w=0,!0)}const q=()=>{F=!1},ft=()=>F?++w:0,a={_queueBuffer:[[],[]],_bufferIndex:0,_size:0,_epoch:0,_isProcessing:!1,_isBatching:!1,_isFlushingSync:!1,_batchDepth:0,_batchQueue:[],_batchQueueSize:0,_maxFlushIterations:p.MAX_FLUSH_ITERATIONS,get phase(){return this._isProcessing||this._isFlushingSync?2:this._isBatching?1:0},get queueSize(){return this._size},get isBatching(){return this._isBatching},schedule(i){if(_&&typeof i!="function")throw new R("Scheduler callback must be a function");if(i._nextEpoch!==this._epoch){if(i._nextEpoch=this._epoch,this._isBatching||this._isFlushingSync){this._batchQueue[this._batchQueueSize++]=i;return}this._queueBuffer[this._bufferIndex][this._size++]=i,this._isProcessing||this._flush()}},_flush(){this._isProcessing||this._size===0||(this._isProcessing=!0,queueMicrotask(this._runLoop))},_runLoop:()=>{try{if(a._size===0)return;const i=Q();a._drainQueue(),i&&q()}finally{a._isProcessing=!1,a._size>0&&!a._isBatching&&a._flush()}},_flushSync(){this._isFlushingSync=!0;const i=Q();try{this._mergeBatchQueue(),this._drainQueue()}finally{this._isFlushingSync=!1,i&&q()}},_mergeBatchQueue(){if(this._batchQueueSize===0)return;const i=++this._epoch,t=this._batchQueue,e=this._queueBuffer[this._bufferIndex];let s=this._size;for(let n=0;n<this._batchQueueSize;n++){const r=t[n];r._nextEpoch!==i&&(r._nextEpoch=i,e[s++]=r)}this._size=s,this._batchQueueSize=0,t.length>p.BATCH_QUEUE_SHRINK_THRESHOLD&&(t.length=0)},_drainQueue(){let i=0;for(;this._size>0;){if(++i>this._maxFlushIterations){this._handleFlushOverflow();return}this._processQueue(),this._mergeBatchQueue()}},_processQueue(){const i=this._bufferIndex,t=this._queueBuffer[i],e=this._size;this._bufferIndex=i^1,this._size=0,this._epoch++;for(let s=0;s<e;s++)try{t[s]()}catch(n){console.error(new R("Error occurred during scheduler execution",n))}t.length=0},_handleFlushOverflow(){console.error(new R(`Maximum flush iterations (${this._maxFlushIterations}) exceeded. Possible infinite loop.`)),this._size=0,this._queueBuffer[this._bufferIndex].length=0,this._batchQueueSize=0},startBatch(){this._batchDepth++,this._isBatching=!0},endBatch(){if(this._batchDepth===0){_&&console.warn("endBatch() called without matching startBatch(). Ignoring.");return}--this._batchDepth===0&&(this._flushSync(),this._isBatching=!1)},setMaxFlushIterations(i){if(i<p.MIN_FLUSH_ITERATIONS)throw new R(`Max flush iterations must be at least ${p.MIN_FLUSH_ITERATIONS}`);this._maxFlushIterations=i}},T={current:null,run(i,t){const e=this.current;this.current=i;try{return t()}finally{this.current=e}}};function J(i){const t=T.current;if(t===null)return i();T.current=null;try{return i()}finally{T.current=t}}const Et=d.HAS_FN_SUBS|d.HAS_OBJ_SUBS;class dt extends j{constructor(t,e){super(),this._pendingOldValue=void 0,this._notifyTask=void 0,this._subscribers=[],this._value=t,e&&(this.flags|=d.SYNC),g.attachDebugInfo(this,"atom",this.id)}get value(){const t=T.current;return t&&z(this,t,this._subscribers),this._value}set value(t){const e=this._value;if(Object.is(e,t))return;this._value=t,this.version=this.version+1&b;const s=this.flags;if(!((s&Et)===0||s&d.NOTIFICATION_SCHEDULED)){if(this._pendingOldValue=e,this.flags=s|d.NOTIFICATION_SCHEDULED,s&d.SYNC&&!a.isBatching){this._flushNotifications();return}this._notifyTask||(this._notifyTask=()=>this._flushNotifications()),a.schedule(this._notifyTask)}}_flushNotifications(){const t=this.flags;if(!(t&d.NOTIFICATION_SCHEDULED)||t&d.DISPOSED)return;const e=this._pendingOldValue;this._pendingOldValue=void 0,this.flags&=-17,this._notifySubscribers(this._value,e)}peek(){return this._value}dispose(){this.flags&d.DISPOSED||(this._subscribers.length=0,this.flags|=d.DISPOSED,this._value=void 0,this._pendingOldValue=void 0,this._notifyTask=void 0)}}function St(i,t={}){return new dt(i,t.sync??!1)}class pt{constructor(t=50,e=256){this.limit=t,this.capacity=e,this.pool=[],this.stats=_?{acquired:0,released:0,rejected:{frozen:0,tooLarge:0,poolFull:0}}:null}acquire(){return _&&this.stats&&this.stats.acquired++,this.pool.pop()??[]}release(t,e){if(!(e&&t===e)){if(t.length>this.capacity){_&&this.stats&&this.stats.rejected.tooLarge++;return}if(this.pool.length>=this.limit){_&&this.stats&&this.stats.rejected.poolFull++;return}if(Object.isFrozen(t)){_&&this.stats&&this.stats.rejected.frozen++;return}t.length=0,this.pool.push(t),_&&this.stats&&this.stats.released++}}getStats(){if(!_||!this.stats)return null;const{acquired:t,released:e,rejected:s}=this.stats,n=t-e-(s.frozen+s.tooLarge+s.poolFull);return{acquired:t,released:e,rejected:{...s},leaked:n,poolSize:this.pool.length}}reset(){this.pool.length=0,_&&this.stats&&(this.stats={acquired:0,released:0,rejected:{frozen:0,tooLarge:0,poolFull:0}})}}const A=i=>Object.freeze(i);A([]),A([]),A([]),A([]);const f=A([]);A([]);const C=new pt;function $(i){return i!==null&&typeof i=="object"&&"value"in i&&typeof i.subscribe=="function"}function It(i){return $(i)&&typeof i.invalidate=="function"}function Dt(i){return i!==null&&typeof i=="object"&&typeof i.dispose=="function"&&typeof i.run=="function"}function K(i){return i!==null&&typeof i=="object"&&typeof i.then=="function"}const W=o.RESOLVED|o.PENDING|o.REJECTED,L=Array(W+1).fill(m.IDLE);L[o.RESOLVED]=m.RESOLVED,L[o.PENDING]=m.PENDING,L[o.REJECTED]=m.REJECTED;const Z=3,tt=Number.MAX_SAFE_INTEGER-1;class et extends j{constructor(t,e={}){if(typeof t!="function")throw new I(l.COMPUTED_MUST_BE_FUNCTION);if(super(),this._error=null,this._promiseId=0,this._subscribers=[],this._links=f,this._cachedErrors=null,this._errorCacheEpoch=-1,this._asyncStartAggregateVersion=0,this._asyncRetryCount=0,this._trackEpoch=-1,this._trackLinks=f,this._trackCount=0,this._value=void 0,this.flags=o.DIRTY|o.IDLE,this._equal=e.equal??Object.is,this._fn=t,this._defaultValue="defaultValue"in e?e.defaultValue:P,this._onError=e.onError??null,g.attachDebugInfo(this,"computed",this.id),e.lazy===!1)try{this._recompute()}catch{}}_track(){const t=T.current;t&&z(this,t,this._subscribers)}get value(){this._track();const t=this.flags;if((t&(o.RESOLVED|o.DIRTY|o.IDLE))===o.RESOLVED)return this._value;if(t&o.DISPOSED)throw new I(l.COMPUTED_DISPOSED);if(t&o.RECOMPUTING){if(this._defaultValue!==P)return this._defaultValue;throw new I(l.COMPUTED_CIRCULAR_DEPENDENCY)}if(t&(o.DIRTY|o.IDLE)&&(this._recompute(),this.flags&o.RESOLVED))return this._value;const e=this._defaultValue,s=e!==P;if(this.flags&o.PENDING){if(s)return e;throw new I(l.COMPUTED_ASYNC_PENDING_NO_DEFAULT)}if(this.flags&o.REJECTED){if(this._error?.recoverable&&s)return e;throw this._error}return this._value}peek(){return this._value}get state(){return this._track(),L[this.flags&W]}get hasError(){if(this._track(),this.flags&(o.REJECTED|o.HAS_ERROR))return!0;const t=this._links;for(let e=0,s=t.length;e<s;e++){const n=t[e]?.node;if(n&&n.flags&o.HAS_ERROR)return!0}return!1}get isValid(){return!this.hasError}get errors(){if(this._track(),!this.hasError)return ot;const t=at();if(this._errorCacheEpoch===t&&this._cachedErrors)return this._cachedErrors;const e=new Set;this._error&&e.add(this._error);const s=this._links;for(let r=0,h=s.length;r<h;r++){const u=s[r].node;if(u.flags&o.HAS_ERROR){const st=u;if(st.errors){const it=st.errors;for(let B=0;B<it.length;B++){const nt=it[B];nt&&e.add(nt)}}}}const n=Object.freeze(Array.from(e));return this._errorCacheEpoch=t,this._cachedErrors=n,n}get lastError(){return this._track(),this._error}get isPending(){return this._track(),(this.flags&o.PENDING)!==0}get isResolved(){return this._track(),(this.flags&o.RESOLVED)!==0}invalidate(){this._markDirty(),this._errorCacheEpoch=-1,this._cachedErrors=null}dispose(){if(this.flags&o.DISPOSED)return;const t=this._links;if(t!==f){for(let e=0,s=t.length;e<s;e++)t[e].unsub?.();C.release(t),this._links=f}this._subscribers.length=0,this.flags=o.DISPOSED|o.DIRTY|o.IDLE,this._error=null,this._value=void 0,this._promiseId=(this._promiseId+1)%tt,this._cachedErrors=null,this._errorCacheEpoch=-1}addDependency(t){if(t._lastSeenEpoch!==this._trackEpoch){if(t._lastSeenEpoch=this._trackEpoch,this._trackCount<this._trackLinks.length){const e=this._trackLinks[this._trackCount];e.node=t,e.version=t.version}else this._trackLinks.push(new x(t,t.version));this._trackCount++}}_commitDeps(t){this._trackLinks.length=this._trackCount,lt(this._trackLinks,t,this),this._links=this._trackLinks}_recompute(){if(this.flags&o.RECOMPUTING)return;this.flags|=o.RECOMPUTING;const t=this._links;this._trackEpoch=Y(),this._trackLinks=C.acquire(),this._trackCount=0;let e=!1;try{const s=T.run(this,this._fn);this._commitDeps(t),e=!0,K(s)?this._handleAsyncComputation(s):this._finalizeResolution(s)}catch(s){if(!e)try{this._commitDeps(t),e=!0}catch{}this._handleError(s,l.COMPUTED_COMPUTATION_FAILED,!0)}finally{e&&t!==f?C.release(t):e||C.release(this._trackLinks),this._trackEpoch=-1,this._trackLinks=f,this._trackCount=0,this.flags&=-257}}_handleAsyncComputation(t){this.flags=(this.flags|o.PENDING)&-217,this._notifySubscribers(void 0,void 0),this._asyncStartAggregateVersion=this._captureVersionSnapshot(),this._asyncRetryCount=0,this._promiseId=(this._promiseId+1)%tt;const e=this._promiseId;t.then(s=>{if(e===this._promiseId){if(this._captureVersionSnapshot()!==this._asyncStartAggregateVersion)return this._asyncRetryCount++<Z?this._markDirty():this._handleError(new I(`Async drift threshold exceeded after ${Z} retries.`),l.COMPUTED_ASYNC_COMPUTATION_FAILED);this._finalizeResolution(s),this._notifySubscribers(s,void 0)}},s=>e===this._promiseId&&this._handleError(s,l.COMPUTED_ASYNC_COMPUTATION_FAILED))}_captureVersionSnapshot(){let t=0;const e=this._links;for(let s=0,n=e.length;s<n;s++)t=((t<<5)-t|0)+e[s].node.version&b;return t}_handleError(t,e,s=!1){const n=N(t,I,e);if(!s&&!(this.flags&o.REJECTED)&&(this.version=this.version+1&b),this._error=n,this.flags=this.flags&-121|(o.REJECTED|o.HAS_ERROR),this._onError)try{this._onError(n)}catch(r){console.error(l.CALLBACK_ERROR_IN_ERROR_HANDLER,r)}if(s)throw n;this._notifySubscribers(void 0,void 0)}_finalizeResolution(t){(!(this.flags&o.RESOLVED)||!this._equal(this._value,t))&&(this.version=this.version+1&b),this._value=t,this._error=null,this.flags=(this.flags|o.RESOLVED)&-697,this._cachedErrors=null,this._errorCacheEpoch=-1}execute(){this._markDirty()}_markDirty(){this.flags&(o.RECOMPUTING|o.DIRTY)||(this.flags|=o.DIRTY,this._notifySubscribers(void 0,void 0))}}Object.freeze(et.prototype);function gt(i,t={}){return new et(i,t)}class Ct extends X{constructor(t,e={}){super(),this._cleanup=null,this._links=f,this._nextLinks=null,this._currentEpoch=-1,this._lastFlushEpoch=-1,this._executionsInEpoch=0,this._executionCount=0,this._historyPtr=0,this._execId=0,this._fn=t,this._onError=e.onError??null,this._sync=e.sync??!1,this._maxExecutions=e.maxExecutionsPerSecond??p.MAX_EXECUTIONS_PER_SECOND,this._maxExecutionsPerFlush=e.maxExecutionsPerFlush??p.MAX_EXECUTIONS_PER_EFFECT,this._trackModifications=e.trackModifications??!1;const s=Number.isFinite(this._maxExecutions),n=s?Math.min(this._maxExecutions+1,p.MAX_EXECUTIONS_PER_SECOND+1):0;this._historyCapacity=n,this._history=_&&s&&n>0?new Array(n).fill(0):null,g.attachDebugInfo(this,"effect",this.id)}run(){if(this.flags&E.DISPOSED)throw new D(l.EFFECT_DISPOSED);this.execute(!0)}dispose(){this.flags&E.DISPOSED||(this.flags|=E.DISPOSED,this._execCleanup(),this._releaseLinks(this._links),this._links=f,this._executeTask=void 0)}addDependency(t){if(!(this.flags&E.EXECUTING)||t._lastSeenEpoch===this._currentEpoch)return;t._lastSeenEpoch=this._currentEpoch;const e=this._nextLinks;if(t._tempUnsub){e.push(new x(t,t.version,t._tempUnsub)),t._tempUnsub=void 0;return}try{const s=t.subscribe(()=>{if(this._trackModifications&&this.flags&E.EXECUTING&&(t._modifiedAtEpoch=this._currentEpoch),this._sync)return this.execute();this._executeTask||(this._executeTask=()=>this.execute()),a.schedule(this._executeTask)});e.push(new x(t,t.version,s))}catch(s){console.error(N(s,D,l.EFFECT_EXECUTION_FAILED))}}execute(t=!1){if(this.flags&(E.DISPOSED|E.EXECUTING)||!t&&this._links.length>0&&!this._isDirty())return;this._checkInfiniteLoops(),this.flags|=E.EXECUTING,this._execCleanup();const e=this._links;if(e!==f)for(let r=0,h=e.length;r<h;r++){const u=e[r];u&&(u.node._tempUnsub=u.unsub)}const s=C.acquire();this._nextLinks=s,this._currentEpoch=Y();let n=!1;try{const r=T.run(this,this._fn);this._links=s,n=!0,this._checkLoopWarnings(),K(r)?this._handleAsyncResult(r):this._cleanup=typeof r=="function"?r:null}catch(r){n=!0,this._handleExecutionError(r),this._cleanup=null}finally{this._finalizeDependencies(n,e,s),this.flags&=-9}}_handleAsyncResult(t){const e=++this._execId;t.then(s=>{if(e!==this._execId||this.flags&E.DISPOSED){if(typeof s=="function")try{s()}catch(n){this._handleExecutionError(n,l.EFFECT_CLEANUP_FAILED)}return}typeof s=="function"&&(this._cleanup=s)},s=>e===this._execId&&this._handleExecutionError(s))}_finalizeDependencies(t,e,s){if(this._nextLinks=null,t){if(e!==f){for(let n=0,r=e.length;n<r;n++){const h=e[n],u=h?.node._tempUnsub;u&&(u(),h&&(h.node._tempUnsub=void 0))}C.release(e)}}else if(this._releaseLinks(s),C.release(s),e!==f)for(let n=0,r=e.length;n<r;n++)e[n]&&(e[n].node._tempUnsub=void 0)}_releaseLinks(t){if(t!==f){for(let e=0,s=t.length;e<s;e++)t[e]?.unsub?.();C.release(t)}}_isDirty(){const t=this._links;for(let e=0,s=t.length;e<s;e++){const n=t[e],r=n.node;if(r.version!==n.version)return!0;if("value"in r){try{J(()=>r.value)}catch{return!0}if(r.version!==n.version)return!0}}return!1}_execCleanup(){if(this._cleanup){try{this._cleanup()}catch(t){this._handleExecutionError(t,l.EFFECT_CLEANUP_FAILED)}this._cleanup=null}}_checkInfiniteLoops(){const t=v;if(this._lastFlushEpoch!==t&&(this._lastFlushEpoch=t,this._executionsInEpoch=0),++this._executionsInEpoch>this._maxExecutionsPerFlush&&this._throwInfiniteLoopError("per-effect"),ft()>p.MAX_EXECUTIONS_PER_FLUSH&&this._throwInfiniteLoopError("global"),this._executionCount++,this._history){const e=Date.now();this._history[this._historyPtr]=e,this._historyPtr=(this._historyPtr+1)%this._historyCapacity;const s=this._history[this._historyPtr]||0;if(s>0&&e-s<y.ONE_SECOND_MS){const n=new D("Effect executed too frequently within 1 second. Suspected infinite loop.");if(this.dispose(),this._handleExecutionError(n),_)throw n}}}get isDisposed(){return(this.flags&E.DISPOSED)!==0}get executionCount(){return this._executionCount}get isExecuting(){return(this.flags&E.EXECUTING)!==0}_throwInfiniteLoopError(t){const e=new D(`Infinite loop detected (${t}): effect executed ${this._executionsInEpoch} times in current flush. Total executions in flush: ${w}`);throw this.dispose(),console.error(e),e}_handleExecutionError(t,e=l.EFFECT_EXECUTION_FAILED){const s=N(t,D,e);if(console.error(s),this._onError)try{this._onError(s)}catch(n){console.error(N(n,D,l.CALLBACK_ERROR_IN_ERROR_HANDLER))}}_checkLoopWarnings(){if(this._trackModifications&&g.enabled){const t=this._currentEpoch,e=this._links;for(let s=0,n=e.length;s<n;s++){const r=e[s].node;r._modifiedAtEpoch===t&&g.warn(!0,`Effect is reading a dependency (${g.getDebugName(r)||"unknown"}) that it just modified. Infinite loop may occur`)}}}}function bt(i,t={}){if(typeof i!="function")throw new D(l.EFFECT_MUST_BE_FUNCTION);const e=new Ct(i,t);return e.execute(),e}function Ot(i){if(typeof i!="function")throw new TypeError("Batch callback must be a function");a.startBatch();try{return i()}finally{a.endBatch()}}c.AsyncState=m,c.AtomError=O,c.ComputedError=I,c.DEBUG_CONFIG=k,c.DEBUG_RUNTIME=g,c.EffectError=D,c.POOL_CONFIG=rt,c.SCHEDULER_CONFIG=p,c.SchedulerError=R,c.atom=St,c.batch=Ot,c.computed=gt,c.effect=bt,c.isAtom=$,c.isComputed=It,c.isEffect=Dt,c.scheduler=a,c.untracked=J,Object.defineProperty(c,Symbol.toStringTag,{value:"Module"})}));
2
2
  //# sourceMappingURL=atom-effect.min.js.map