@jucie-reactive/jucie-state 1.0.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 ADDED
@@ -0,0 +1,308 @@
1
+ # @jucie-reactive/reactive-jucie-state
2
+
3
+ Integrate fine-grained reactivity with Jucie State - connect reactive signals and computed values with your state management.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @jucie-reactive/reactive-jucie-state @jucie-state/core
9
+ ```
10
+
11
+ **Note:** Requires both `@jucie-state/core` and `@jucie-reactive/core` as peer dependencies.
12
+
13
+ ## What It Does
14
+
15
+ This plugin bridges the reactive system with Jucie State, enabling:
16
+
17
+ - **Automatic reactivity** for state changes
18
+ - **Fine-grained tracking** at the property level
19
+ - **Computed values** that update when state changes
20
+ - **Subscribers** for side effects on state changes
21
+
22
+ ## Quick Start
23
+
24
+ ### Install the Plugin
25
+
26
+ ```javascript
27
+ import { createState } from '@jucie-state/core';
28
+ import { ReactiveJucieState } from '@jucie-reactive/reactive-jucie-state';
29
+
30
+ const state = createState({
31
+ count: 0,
32
+ user: {
33
+ name: 'John',
34
+ email: 'john@example.com'
35
+ }
36
+ }).install(ReactiveJucieState);
37
+ ```
38
+
39
+ ### Create Reactive Computations
40
+
41
+ ```javascript
42
+ // Create a computed value that tracks state
43
+ const doubled = state.createReactor(() => {
44
+ return state.get(['count']) * 2;
45
+ });
46
+
47
+ console.log(doubled()); // 0
48
+
49
+ state.set(['count'], 5);
50
+ console.log(doubled()); // 10
51
+ ```
52
+
53
+ ### Subscribe to State Changes
54
+
55
+ ```javascript
56
+ // Run side effects when state changes
57
+ state.createSubscriber(
58
+ (s) => s.get(['user', 'name']),
59
+ (name) => {
60
+ console.log('User name changed:', name);
61
+ }
62
+ );
63
+
64
+ state.set(['user', 'name'], 'Jane');
65
+ // Logs: "User name changed: Jane"
66
+ ```
67
+
68
+ ## Examples
69
+
70
+ ### Computed Values from Multiple State Properties
71
+
72
+ ```javascript
73
+ import { createState } from '@jucie-state/core';
74
+ import { ReactiveJucieState } from '@jucie-reactive/reactive-jucie-state';
75
+
76
+ const state = createState({
77
+ firstName: 'John',
78
+ lastName: 'Doe',
79
+ age: 30
80
+ }).install(ReactiveJucieState);
81
+
82
+ // Computed full name
83
+ const fullName = state.createReactor(() => {
84
+ const first = state.get(['firstName']);
85
+ const last = state.get(['lastName']);
86
+ return `${first} ${last}`;
87
+ });
88
+
89
+ console.log(fullName()); // "John Doe"
90
+
91
+ state.set(['firstName'], 'Jane');
92
+ console.log(fullName()); // "Jane Doe"
93
+ ```
94
+
95
+ ### Async Computed Values
96
+
97
+ ```javascript
98
+ const state = createState({
99
+ userId: 1
100
+ }).install(ReactiveJucieState);
101
+
102
+ const userData = state.createReactor(async () => {
103
+ const id = state.get(['userId']);
104
+ const response = await fetch(`/api/users/${id}`);
105
+ return response.json();
106
+ });
107
+
108
+ // Returns a promise
109
+ const user = await userData();
110
+ console.log(user);
111
+
112
+ // Changing userId triggers new fetch
113
+ state.set(['userId'], 2);
114
+ const newUser = await userData();
115
+ ```
116
+
117
+ ### Nested State Tracking
118
+
119
+ ```javascript
120
+ const state = createState({
121
+ cart: {
122
+ items: [],
123
+ total: 0
124
+ }
125
+ }).install(ReactiveJucieState);
126
+
127
+ // Tracks nested property
128
+ const itemCount = state.createReactor(() => {
129
+ const items = state.get(['cart', 'items']);
130
+ return items.length;
131
+ });
132
+
133
+ state.set(['cart', 'items'], [{ id: 1 }, { id: 2 }]);
134
+ console.log(itemCount()); // 2
135
+ ```
136
+
137
+ ### Batched Updates
138
+
139
+ ```javascript
140
+ const state = createState({
141
+ x: 0,
142
+ y: 0
143
+ }).install(ReactiveJucieState);
144
+
145
+ let computeCount = 0;
146
+ const sum = state.createReactor(() => {
147
+ computeCount++;
148
+ return state.get(['x']) + state.get(['y']);
149
+ });
150
+
151
+ // Batch multiple updates
152
+ state.batch(() => {
153
+ state.set(['x'], 10);
154
+ state.set(['y'], 20);
155
+ });
156
+
157
+ // Only computes once for both changes
158
+ console.log(sum()); // 30
159
+ console.log(computeCount); // 1 (not 2!)
160
+ ```
161
+
162
+ ### Side Effects with Subscribers
163
+
164
+ ```javascript
165
+ const state = createState({
166
+ theme: 'light',
167
+ notifications: []
168
+ }).install(ReactiveJucieState);
169
+
170
+ // Update UI when theme changes
171
+ state.createSubscriber(
172
+ (s) => s.get(['theme']),
173
+ (theme) => {
174
+ document.body.className = theme;
175
+ }
176
+ );
177
+
178
+ // Log new notifications
179
+ state.createSubscriber(
180
+ (s) => s.get(['notifications']),
181
+ (notifications) => {
182
+ const latest = notifications[notifications.length - 1];
183
+ if (latest) {
184
+ console.log('New notification:', latest);
185
+ }
186
+ }
187
+ );
188
+ ```
189
+
190
+ ### Child Property Tracking
191
+
192
+ ```javascript
193
+ const state = createState({
194
+ settings: {
195
+ audio: { volume: 50, muted: false },
196
+ video: { quality: 'HD', autoplay: true }
197
+ }
198
+ }).install(ReactiveJucieState);
199
+
200
+ // Tracks entire settings object
201
+ const settingsWatcher = state.createReactor(() => {
202
+ return state.get(['settings']);
203
+ });
204
+
205
+ // Subscribe gets called for ANY change in settings
206
+ state.createSubscriber(
207
+ () => state.get(['settings']),
208
+ (settings) => {
209
+ console.log('Settings changed:', settings);
210
+ }
211
+ );
212
+
213
+ // This triggers the subscriber
214
+ state.set(['settings', 'audio', 'volume'], 75);
215
+ ```
216
+
217
+ ## API
218
+
219
+ ### Plugin Installation
220
+
221
+ ```javascript
222
+ const state = createState(initialState).install(ReactiveJucieState);
223
+ ```
224
+
225
+ ### Plugin Actions
226
+
227
+ #### `state.createReactor(fn, config)`
228
+
229
+ Create a computed value that tracks state dependencies.
230
+
231
+ ```javascript
232
+ const computed = state.createReactor(() => {
233
+ return state.get(['path', 'to', 'value']);
234
+ }, {
235
+ debounce: 100, // Debounce updates
236
+ immediate: true // Compute immediately
237
+ });
238
+ ```
239
+
240
+ #### `state.createSubscriber(getter, callback, config)`
241
+
242
+ Subscribe to state changes and run side effects.
243
+
244
+ ```javascript
245
+ const unsubscribe = state.createSubscriber(
246
+ (state) => state.get(['path']),
247
+ (value) => {
248
+ console.log('Value changed:', value);
249
+ },
250
+ {
251
+ debounce: 50 // Debounce callback
252
+ }
253
+ );
254
+
255
+ // Later: cleanup
256
+ unsubscribe();
257
+ ```
258
+
259
+ ## How It Works
260
+
261
+ The plugin integrates with Jucie State's lifecycle hooks:
262
+
263
+ 1. **Dependency Tracking**: When a reactor accesses state via `state.get()`, it's automatically tracked
264
+ 2. **Change Detection**: When state changes via `state.set()`, the plugin marks dependent reactors as dirty
265
+ 3. **Batching**: Changes are batched and reactors are updated efficiently
266
+ 4. **Fine-Grained**: Only reactors that depend on changed paths are recomputed
267
+
268
+ ## Performance
269
+
270
+ - **Path-based tracking**: Only tracks the specific paths accessed
271
+ - **Batched updates**: Multiple state changes trigger single reactor update
272
+ - **Lazy evaluation**: Computed values only update when accessed
273
+ - **WeakRef cleanup**: Automatic cleanup of destroyed reactors
274
+
275
+ ## License and Usage
276
+
277
+ This software is provided under the MIT License with Commons Clause.
278
+
279
+ ### ✅ What You Can Do
280
+
281
+ - Use this library freely in personal or commercial projects
282
+ - Include it in your paid products and applications
283
+ - Modify and fork for your own use
284
+ - View and learn from the source code
285
+
286
+ ### ❌ What You Cannot Do
287
+
288
+ - Sell this library as a standalone product or competing state management solution
289
+ - Offer it as a paid service (SaaS) where the primary value is this library
290
+ - Create a commercial fork that competes with this project
291
+
292
+ ### ⚠️ No Warranty or Support
293
+
294
+ This software is provided "as-is" without any warranty, support, or guarantees:
295
+
296
+ - No obligation to provide support or answer questions
297
+ - No obligation to accept or implement feature requests
298
+ - No obligation to review or merge pull requests
299
+ - No obligation to fix bugs or security issues
300
+ - No obligation to maintain or update the software
301
+
302
+ You are welcome to submit issues and pull requests, but there is no expectation they will be addressed. Use this software at your own risk.
303
+
304
+ See the LICENSE file for complete terms.
305
+
306
+ ---
307
+
308
+ Made with ⚡ by Adrian Miller
package/dist/main.js ADDED
@@ -0,0 +1,2 @@
1
+ var M=Symbol("STATE_CONTEXT"),V=Symbol("MATCHER");var m=1,v=2,g=4,y=8;function S(s){return(s.type&m)===m}function I(s){return(s.type&v)===v}function D(s){return(s.type&g)===g}function P(s){return(s.type&y)===y}function d(s,{global:e,path:t,ephemeral:i,error:n}){try{if(!s.isMarker)return;if(S(s))return e?e(s):void 0;if(P(s))return i?i(s):t?t(s):void 0;if(I(s))return t?t(s):void 0;if(D(s)){let r=new Array(s.length),o=0;for(;o<s.length;){let a=s.children[o];r[o]=d(a,{global:e,path:t,ephemeral:i,error:n}),o++}return r}return}catch(r){return n?n(r.message):void 0}}var f=class{static name=null;static options={};static configure(e){return e={...this.options,...e},{install:t=>this.install(t,e),name:this.name,options:e}}static install(e,t){t={...this.options,...t};let i=new this(e,t);return Object.defineProperty(i,"state",{value:e,writable:!1,configurable:!1}),Object.defineProperty(i,"options",{value:t,writable:!1,configurable:!1}),i}};function j(s){return typeof window<"u"&&window.requestIdleCallback?window.requestIdleCallback(s,{timeout:100}):typeof window<"u"?window.requestAnimationFrame?window.requestAnimationFrame(()=>{setTimeout(s,0)}):setTimeout(s,0):(typeof s=="function"&&s(),null)}var O=s=>typeof s=="function"&&(s.constructor.name==="AsyncFunction"||s.constructor.name==="AsyncGeneratorFunction"),T=class{constructor(){this.roots=new Map,this.pending=new Set,this.onCompleteCallbacks=new Set,this.onNextIdle=new Set,this.idleScheduled=!1}markAsDirty(s){if(!s.isDirty&&(s.isDirty=!0,s.isAsync||s.immediate||s.effects&&s.effects.size>0?this.scheduleRecomputation(s):(this.onNextIdle.add(s),this.idleScheduled||(this.idleScheduled=!0,j(()=>{for(let e of this.onNextIdle)this.pending.add(e);this.flush(null),this.onNextIdle.clear(),this.idleScheduled=!1}))),s.dependants&&s.dependants.size>0)){let e=[],t=new Set;s.dependants.forEach(i=>{let n=i.deref();n?(this.markAsDirty(n),t.add(n._id)):e.push(i)}),e.forEach(i=>s.dependants.delete(i)),s.dependantIds=t}}scheduleRecomputation(s){if(!s.debounce)return this.recompute(s);let e=Date.now(),t=s._lastComputeTime?e-s._lastComputeTime:1/0;return!s._hasPendingDebounce||t>=s.debounce?(clearTimeout(s._debounceTimer),s._hasPendingDebounce=!0,s._lastComputeTime=e,s._debounceTimer=setTimeout(()=>{s._hasPendingDebounce=!1,s._debounceTimer=null},s.debounce),this.recompute(s)):s.cachedValue}removeReactive(s){this.pending.delete(s),this.onNextIdle.delete(s)}recompute(s){return this.pending.add(s),this.flush(s)}flush(s){let e=Array.from(this.pending);this.pending.clear();let t=this.sortByDependencies(e);for(let i of t)this.onNextIdle.delete(i),i.compute();for(let i of this.onCompleteCallbacks)try{i()}catch(n){console.error("Error in batch completion callback:",n)}if(s)return t.includes(s)||s.compute(),s.cachedValue}sortByDependencies(s){let e=[],t=new Set,i=new Set,n=r=>{if(i.has(r)||t.has(r))return;i.add(r);let o=r.dependants;o&&o.size>0&&o.forEach(a=>{let u=a.deref();u&&s.includes(u)&&n(u)}),i.delete(r),t.add(r),e.unshift(r)};for(let r of s)t.has(r)||n(r);return e}},l=class c{static computationManager=new T;static awaitingRecomputation=new Set;static reactives=new WeakMap;static currentlyComputing=null;static computationStack=[];static currentDepth=0;static effectsCache=new Set;static processingEffects=!1;static#e=void 0;static _nextId=1;static config={maxDepth:2e3};static nextId(){return c._nextId++}static provideContext(e){c.#e=e}static getContext(){return c.#e}static hasContext(){return c.#e!==void 0}static clearContext(){c.#e=void 0}static useContext(){return c.#e}static begin(e){c.awaitingRecomputation.has(e)&&c.awaitingRecomputation.delete(e);let t=c.computationStack.indexOf(e);if(t!==-1){if(e.isAsync){c.computationStack.splice(t,1),c.computationStack.push(e),c.currentlyComputing=e;return}let i=c.computationStack.slice(t).concat(e),n=new Error(`Circular dependency detected: ${i.map(r=>r).join(" -> ")}`);throw n.name="CircularDependencyError",n.displayed=!1,n}if(c.currentDepth>=c.config.maxDepth)throw new Error(`Maximum reactive depth of ${c.config.maxDepth} exceeded`);c.computationStack.push(e),c.currentlyComputing=e,c.currentDepth++}static end(e){if(e.isAsync){c.computationStack.splice(c.computationStack.indexOf(e),1),c.currentlyComputing=c.computationStack[c.computationStack.length-1]||null,c.currentDepth--;return}c.computationStack.pop(),c.currentlyComputing=c.computationStack[c.computationStack.length-1]||null,c.currentDepth--}static addEffect(e,t){let i=c.reactives.get(e);return i.isDirty&&c.computationManager.scheduleRecomputation(i),i.effects||(i.effects=new Set),i.effects.add(t),()=>c.removeEffect(e,t)}static removeEffect(e,t){let i=c.reactives.get(e);i.effects&&i.effects.delete(t)}static recompute(e){return c.awaitingRecomputation.has(e)||c.awaitingRecomputation.add(e),c.computationManager.scheduleRecomputation(e)}static callEffects(e){c.effectsCache.add(e),c.processingEffects||(c.processingEffects=!0,setTimeout(()=>{c.processEffectsCache(),c.processingEffects=!1},0))}static processEffectsCache(){let e=new Set(c.effectsCache);c.effectsCache.clear();for(let t of e)try{(t.effects||new Set).forEach(i=>{i&&i(t.cachedValue)})}catch(i){console.error(`Error in reactive ${t._id} effect:`,i)}c.effectsCache.size>0&&setTimeout(()=>{c.processEffectsCache()},0)}static markAsDirty(e){if(!e.isDirty){e.isDirty=!0,(e.immediate||e.effects&&e.effects.size>0)&&c.computationManager.scheduleRecomputation(e);let t=[],i=new Set;e.dependants.forEach(n=>{let r=n.deref();r?(c.markAsDirty(r),i.add(r._id)):t.push(n)}),t.forEach(n=>e.dependants.delete(n)),e.dependantIds=i}}static destroy(e){let t=c.reactives.get(e);c.computationManager.removeReactive(t),c.reactives.delete(e)}};var k=class E{static create(e,t={}){let i=new E(e,t);return l.reactives.set(i.getter,i),i.getter}constructor(e,t={}){this.fn=e,this._id=l.nextId(),this.isAsync=O(e),this.pendingResolve=void 0,this.roots=new Set,this.dependants=new Set,this.dependantIds=new Set,this.effects=new Set(Array.isArray(t.effects)?t.effects:[]),this.cachedValue=t.initialValue||void 0,this.isDirty=!0,this.debounce=t.debounce||0,this.onAccess=t.onAccess||void 0,this.detatched=t.detatched||!1,this.immediate=t.immediate||!1,this.context=t.context||void 0,this._lastComputeTime=void 0,this._hasPendingDebounce=!1,this._debounceTimer=void 0,this.resolvers=[],this.rejectors=[],this._computationId=0,this.getter=this.#e.bind(this),this.immediate&&this.compute()}compute(){l.begin(this);try{let e=this.context?this.context:l.hasContext()?l.useContext():void 0;if(!this.isAsync)return this.cachedValue=this.fn(e,this.cachedValue),this.isDirty=!1,this.cachedValue;this._computationId=(this._computationId||0)+1;let t=this._computationId;return this.pendingResolve=this.fn(e,this.cachedValue),this.pendingResolve.then(i=>(this._computationId===t&&(this.resolvers.forEach(n=>n(i)),this.resolvers=[],this.cachedValue=i,this.isDirty=!1),i)).catch(i=>{this._computationId===t&&(this.rejectors.forEach(n=>n(i)),this.rejectors=[])}).finally(()=>{this.pendingResolve=null,this._computationId===t&&(l.end(this),l.callEffects(this))}),this.cachedValue=new Promise((i,n)=>{this.resolvers.push(i),this.rejectors.push(n)}),this.cachedValue}finally{this.isAsync||(l.end(this),l.callEffects(this))}}#e(){try{return!this.detatched&&l.currentlyComputing&&l.currentlyComputing!==this&&!this.dependantIds.has(l.currentlyComputing._id)&&(this.dependantIds.add(l.currentlyComputing._id),this.dependants.add(new WeakRef(l.currentlyComputing))),this.isDirty?l.recompute(this):this.isAsync?Promise.resolve(this.cachedValue):this.cachedValue}catch(e){throw e}finally{this.onAccess&&this.onAccess(this.cachedValue)}}},C=(s,e={})=>k.create(s,e);var N=class A{static create(e,t,i={}){let n=new A(e,t,i);return l.reactives.set(n.getter,n),()=>l.destroy(n.getter)}constructor(e,t,i={}){this._id=l.nextId(),this.getter=e,this.isDirty=!1,this.subscriber=t,this.debounce=i.debounce||0,this.onAccess=i.onAccess||null,this.immediate=!0,this._hasPendingDebounce=!1,this._lastComputeTime=null,this._debounceTimer=null,this.dependants=new Set,this.dependantIds=new Set,this.unsubscribe=()=>l.computationManager.removeReactive(this),l.begin(this),this.cachedValue=this.getter(),this.subscriber(this.cachedValue),l.end(this)}compute(){try{this.cachedValue=this.getter(),this.subscriber(this.cachedValue),this.isDirty=!1}catch(e){throw e}}},R=(s,e,t={})=>N.create(s,e,t);var Y=Symbol();function b(s){return typeof window<"u"&&window.requestIdleCallback?window.requestIdleCallback(s,{timeout:100}):typeof window<"u"?window.requestAnimationFrame?window.requestAnimationFrame(()=>{setTimeout(s,0)}):setTimeout(s,0):(typeof s=="function"&&s(),null)}var h=class s{static create(){return new s}constructor(){this.reactives=new Set,this.reactiveIds=new Set,this.childReactives=new Set,this.childReactiveIds=new Set,this.children=new Map,this.hasChildReactives=!1}},w=class s extends f{static name="reactive";static roots=new WeakMap;static states=new Set;#e=!1;#t=new Set;initialize(e){s.states.add(new WeakRef(e)),s.roots.set(e,h.create())}actions(e){return{createReactor:(t,i={})=>C(t,{...i,context:e}),createSubscriber:(t,i,n={})=>R(()=>t(e),i,n)}}onBatchStart(){this.#e=!0}onBatchEnd(){this.#e=!1,this.#t.forEach(e=>{this.propagateChange(this.state,e)}),this.#t.clear()}onStateChange(e){if(!this.#e){this.propagateChange(this.state,e);return}this.#t.add(e)}onStateAccess(e){d(e,{global:()=>{this.addReactive(this.state,null)},path:({path:t})=>{this.addReactive(this.state,t)}})}propagateChange(e,t){d(t,{global:()=>{this.walkMarkerPath(this.getRoot(e),null)},path:({path:i})=>{this.walkMarkerPath(this.getRoot(e),i)}})}walkMarkerPath(e,t,i=new Set){if(this.processReactives(e.reactives,e.reactiveIds,i),!t||t==="*")return this.processReactives(e.childReactives,e.childReactiveIds,i),i;let n=t.length-1,r=0;for(;r<=n;){let o=t[r];if(!e.children.has(o))break;e=e.children.get(o),this.processReactives(e.reactives,e.reactiveIds,i),r===n&&this.processReactives(e.childReactives,e.childReactiveIds,i),r++}return i}processReactives(e,t,i){let n=[],r=new Set;e.forEach(o=>{let a=o.deref();a?(i.has(a)||(i.add(a),l.markAsDirty(a)),r.add(a._id)):n.push(o)}),n.forEach(o=>e.delete(o)),t&&(t.clear(),r.forEach(o=>t.add(o)))}addWeakRefIfNotExists(e,t,i){t.has(i._id)||(t.add(i._id),e.add(new WeakRef(i)))}addReactive(e,t){let i=l.currentlyComputing;if(!i)return;let n=this.getRoot(e),r=n,o=Array.isArray(t)?t:[];(o.length===0||t==="*"||!t)&&this.addWeakRefIfNotExists(r.reactives,r.reactiveIds,i),this.addWeakRefIfNotExists(r.childReactives,r.childReactiveIds,i);let a=o.length;for(let u=0;u<a;u++){let p=o[u];r.children.has(p)||r.children.set(p,h.create()),r=r.children.get(p),u!==a-1?this.addWeakRefIfNotExists(r.childReactives,r.childReactiveIds,i):this.addWeakRefIfNotExists(r.reactives,r.reactiveIds,i)}this.updateHasChildReactives(n,o)}removeReactive(e){s.states.forEach(t=>{let i=this.getRoot(t.deref());i&&this.removeReactiveFromNode(i,e)}),b(()=>{s.states.forEach(t=>{let i=this.getRoot(t.deref());i&&(this.cleanupEmptyNodes(i),this.updateHasChildReactives(i))})})}removeReactiveFromNode(e,t){let i=n=>{let r=[];n.forEach(o=>{let a=o.deref();(a===t||!a)&&r.push(o)}),r.forEach(o=>n.delete(o))};if(i(e.reactives),i(e.childReactives),e.children.size>0)for(let n of e.children.values())this.removeReactiveFromNode(n,t)}getRoot(e){let t=s.roots.get(e);return t||(t=h.create(),s.roots.set(e,t)),t}cleanupEmptyNodes(e){let t=i=>{let n=0,r=[];return i.forEach(o=>{o.deref()?n++:r.push(o)}),r.forEach(o=>i.delete(o)),n};for(let[i,n]of e.children){this.cleanupEmptyNodes(n);let r=t(n.reactives)>0,o=t(n.childReactives)>0;!r&&!o&&n.children.size===0&&e.children.delete(i)}}updateHasChildReactives(e,t=null){let i=r=>{for(let o of r)if(o.deref())return!0;return!1};if(!t){let r=o=>{o.hasChildReactives=Array.from(o.children.values()).some(a=>i(a.reactives)||i(a.childReactives)||a.hasChildReactives);for(let a of o.children.values())r(a)};return r(e)}let n=[];for(let r of t){if(!e.children.has(r))return;n.push(e),e=e.children.get(r)}for(let r=n.length-1;r>=0;r--){let o=n[r],a=Array.from(o.children.values()).some(u=>i(u.reactives)||i(u.childReactives)||u.hasChildReactives);if(o.hasChildReactives!==a)o.hasChildReactives=a;else break}}};export{w as ReactiveJucieState};
2
+ //# sourceMappingURL=main.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../node_modules/@jucie-state/core/dist/lib/TOKENS.js", "../../../node_modules/@jucie-state/core/dist/lib/marker.js", "../../../node_modules/@jucie-state/core/dist/Plugin.js", "../../../shared/utils/nextIdleTick.js", "../../../shared/utils/isAsync.js", "../../../core/src/ComputationManager.js", "../../../core/src/Reactive.js", "../../../core/src/Reactor.js", "../../../core/src/Signal.js", "../../../core/src/Subscriber.js", "../../../core/src/lib/traverse.js", "../../../core/src/Surface.js", "../../../shared/utils/nextIdleTick.js", "../src/ReactiveJucieState.js"],
4
+ "sourcesContent": ["export const GLOBAL_TAG = '*';\nexport const STATE_CONTEXT = Symbol('STATE_CONTEXT');\nexport const MATCHER = Symbol('MATCHER');\nexport const CREATED = 'CREATED';\nexport const DELETED = 'DELETED';\nexport const UPDATED = 'UPDATED';\n\n// Marker type bitflags\nexport const MARKER_GLOBAL = 1; // 0b001\nexport const MARKER_SINGLE = 2; // 0b010\nexport const MARKER_MANY = 4; // 0b100\nexport const MARKER_EPHEMERAL = 8; // 0b1000\n\n// Comparison result constants\nexport const MATCH_EXACT = 0; // Markers are identical\nexport const MATCH_PARENT = 1; // controlMarker is child of comparedMarker (parent changed)\nexport const MATCH_CHILD = 2; // comparedMarker is child of controlMarker (child changed)\nexport const MATCH_NONE = -1; // No relationship", "import { encodePath } from './pathEncoder.js';\nimport { GLOBAL_TAG } from './TOKENS.js';\nimport {\n MARKER_GLOBAL,\n MARKER_SINGLE,\n MARKER_MANY,\n MARKER_EPHEMERAL,\n MATCH_EXACT,\n MATCH_PARENT,\n MATCH_CHILD,\n MATCH_NONE \n} from './TOKENS.js';\n\n// Marker type bitflags\n\n// Helper functions to check marker type\nexport function isGlobalMarker(marker) {\n return (marker.type & MARKER_GLOBAL) === MARKER_GLOBAL;\n}\n\nexport function isPathMarker(marker) {\n return (marker.type & MARKER_SINGLE) === MARKER_SINGLE;\n}\n\nexport function isMarkers(marker) {\n return (marker.type & MARKER_MANY) === MARKER_MANY;\n}\n\nexport function isEphemeralMarker(marker) {\n return (marker.type & MARKER_EPHEMERAL) === MARKER_EPHEMERAL;\n}\n\nexport function isGlobalPath(path) {\n return !path || path.length === 0 || path === GLOBAL_TAG || path[0] === GLOBAL_TAG;\n}\n\nexport function normalizePaths(args = []) { \n const len = args.length;\n if (len === 0) return [0, [] ];\n if (len === 1 && args[0] === GLOBAL_TAG) return [0, [] ];\n \n if (Array.isArray(args[0])) {\n return len === 1 \n ? [1, [args[0]] ]\n : [len, args ];\n }\n \n return [1, [[...args]] ];\n}\n\nfunction pathHasEphemeral(path) {\n if (!Array.isArray(path)) {\n return false;\n }\n\n for (let i = 0; i < path.length; i++) {\n const segment = path[i];\n if (typeof segment === 'string' && segment.charCodeAt(0) === 46) { // '.'\n return true;\n }\n }\n\n return false;\n}\n\n// Marker factory\nexport function createMarker(paths = []) {\n if (isGlobalPath(paths)) {\n return {\n address: GLOBAL_TAG,\n isMarker: true,\n length: 0,\n path: [],\n children: null,\n type: MARKER_GLOBAL\n };\n }\n \n const [length, normalizedPaths] = normalizePaths(paths);\n const type = length === 1 ? MARKER_SINGLE : MARKER_MANY;\n const path = length === 1 ? normalizedPaths[0] : normalizedPaths;\n const children = length > 1 ? normalizedPaths.map(path => createMarker(path)) : null;\n const isEphemeral = type === MARKER_SINGLE\n ? pathHasEphemeral(path)\n : children.some(child => isEphemeralMarker(child));\n\n let markerType = type;\n if (isEphemeral) {\n markerType |= MARKER_EPHEMERAL;\n }\n\n return {\n address: type === MARKER_SINGLE ? encodePath(path) : null,\n isMarker: true,\n length,\n path,\n children,\n type: markerType\n };\n}\n\nexport function createChildMarker(parentMarker, childPaths) {\n if (childPaths.length === 0) {\n return parentMarker;\n }\n // Normalize the child paths\n const [childLength, normalizedChildPaths] = normalizePaths(childPaths);\n \n // Handle global marker - just return marker with child paths\n if (isGlobalMarker(parentMarker)) {\n return createMarker(normalizedChildPaths, parentMarker.state);\n }\n \n // Handle single path marker\n if (isPathMarker(parentMarker)) {\n if (childLength === 0) {\n // No child paths, return parent as-is\n return parentMarker;\n }\n \n if (childLength === 1) {\n // Single child path - append to parent path\n const newPath = [...parentMarker.path, ...normalizedChildPaths[0]];\n return createMarker(newPath, parentMarker.state);\n } else {\n // Multiple child paths - create many markers\n const newPaths = normalizedChildPaths.map(childPath => \n [...parentMarker.path, ...childPath]\n );\n return createMarker(newPaths, parentMarker.state);\n }\n }\n \n // Handle many markers - recursively create child markers for each\n if (isMarkers(parentMarker)) {\n const newMarkers = new Array(parentMarker.length);\n let i = 0;\n while (i < parentMarker.length) {\n newMarkers[i] = createChildMarker(parentMarker.children[i], childPaths);\n i++;\n }\n \n // Collect all paths from the new markers\n const allPaths = [];\n i = 0;\n while (i < newMarkers.length) {\n const marker = newMarkers[i];\n if (isPathMarker(marker)) {\n allPaths.push(marker.path);\n } else if (isMarkers(marker)) {\n let j = 0;\n while (j < marker.length) {\n allPaths.push(marker.children[j].path);\n j++;\n }\n }\n i++;\n }\n \n return createMarker(allPaths, parentMarker.state);\n }\n \n // Fallback - shouldn't reach here\n return parentMarker;\n}\n\nexport function dispatch(marker, { global, path, ephemeral, error }) {\n try {\n if (!marker.isMarker) return undefined;\n if (isGlobalMarker(marker)) return global ? global(marker) : undefined;\n if (isEphemeralMarker(marker)) return ephemeral ? ephemeral(marker) : path ? path(marker) : undefined;\n if (isPathMarker(marker)) return path ? path(marker) : undefined;\n if (isMarkers(marker)) {\n const results = new Array(marker.length);\n let i = 0;\n while (i < marker.length) {\n const nestedMarker = marker.children[i];\n results[i] = dispatch(nestedMarker, { global, path, ephemeral, error });\n i++;\n }\n return results;\n }\n \n return undefined;\n } catch (err) {\n return error ? error(err.message) : undefined;\n }\n}\n\nexport function compareMarkers(controlMarker, comparedMarker) {\n // Both are global markers or exact address match\n if (isGlobalMarker(controlMarker) && isGlobalMarker(comparedMarker)) {\n return MATCH_EXACT;\n }\n\n // If comparedMarker is global, it's always a parent\n if (isGlobalMarker(comparedMarker)) {\n return MATCH_PARENT;\n }\n \n // Need addresses to compare\n if (!controlMarker.address || !comparedMarker.address) {\n return MATCH_NONE;\n }\n \n // Exact match\n if (controlMarker.address === comparedMarker.address) {\n return MATCH_EXACT;\n }\n \n // controlMarker is more nested (child) - parent changed\n if (controlMarker.address.startsWith(comparedMarker.address + '.')) {\n return MATCH_PARENT;\n }\n \n // comparedMarker is more nested (child) - child changed\n if (comparedMarker.address.startsWith(controlMarker.address + '.')) {\n return MATCH_CHILD;\n }\n \n return MATCH_NONE;\n}\n\nexport const Marker = {\n compare: compareMarkers,\n create: createMarker,\n createChild: createChildMarker,\n dispatch: dispatch,\n isGlobal: isGlobalMarker,\n isSingle: isPathMarker,\n isMarkers: isMarkers,\n isEphemeral: isEphemeralMarker\n};", "export class Plugin {\n\n static name = null;\n static options = {};\n\n static configure(options) {\n options = {...this.options, ...options};\n return {\n install: (state) => this.install(state, options),\n name: this.name,\n options\n }\n }\n\n static install(state, options) {\n options = {...this.options, ...options};\n const pluginInstance = new this(state, options);\n\n Object.defineProperty(pluginInstance, 'state', {\n value: state,\n writable: false,\n configurable: false\n });\n \n Object.defineProperty(pluginInstance, 'options', {\n value: options,\n writable: false,\n configurable: false\n });\n\n \n return pluginInstance;\n }\n}\n\nexport default Plugin;", "export function nextIdleTick(callback) {\n if (typeof window !== 'undefined' && window.requestIdleCallback) {\n return window.requestIdleCallback(callback, { timeout: 100 });\n }\n\n // Fallback for browsers without requestIdleCallback (Safari/WebKit)\n if (typeof window !== 'undefined') {\n // Use requestAnimationFrame + setTimeout for better idle approximation\n if (window.requestAnimationFrame) {\n return window.requestAnimationFrame(() => {\n setTimeout(callback, 0);\n });\n }\n // Final fallback to setTimeout\n return setTimeout(callback, 0);\n }\n\n // Server-side or no window object - execute immediately\n if (typeof callback === 'function') {\n callback();\n }\n return null;\n}\n", "export const isAsyncFunction = fn =>\n typeof fn === 'function' &&\n (fn.constructor.name === 'AsyncFunction' ||\n fn.constructor.name === 'AsyncGeneratorFunction');\n", "import { nextIdleTick } from '@shared/utils';\n\nexport class ComputationManager {\n constructor() {\n this.roots = new Map();\n this.pending = new Set();\n this.onCompleteCallbacks = new Set();\n this.onNextIdle = new Set();\n this.idleScheduled = false;\n }\n\n markAsDirty(reactive) {\n if (!reactive.isDirty) {\n reactive.isDirty = true;\n \n if (reactive.isAsync || reactive.immediate || (reactive.effects && reactive.effects.size > 0)) {\n this.scheduleRecomputation(reactive);\n } else {\n this.onNextIdle.add(reactive);\n\n if (!this.idleScheduled) {\n this.idleScheduled = true;\n nextIdleTick(() => {\n for (const reactive of this.onNextIdle) {\n this.pending.add(reactive);\n }\n this.flush(null);\n this.onNextIdle.clear();\n this.idleScheduled = false; // \u2190 Reset flag\n });\n }\n }\n if (reactive.dependants && reactive.dependants.size > 0) {\n // Process WeakRefs and rebuild ID set with only alive IDs\n const deadRefs = [];\n const ids = new Set();\n reactive.dependants.forEach(weakRef => {\n const dependant = weakRef.deref();\n if (dependant) {\n this.markAsDirty(dependant);\n ids.add(dependant._id);\n } else {\n deadRefs.push(weakRef);\n }\n });\n // Clean up dead WeakRefs and sync IDs\n deadRefs.forEach(ref => reactive.dependants.delete(ref));\n reactive.dependantIds = ids;\n }\n }\n }\n\n scheduleRecomputation(reactive) {\n if (!reactive.debounce) {\n return this.recompute(reactive);\n }\n\n // Check if we can recompute (either first time or cooldown expired)\n const now = Date.now();\n const timeElapsed = reactive._lastComputeTime ? now - reactive._lastComputeTime : Infinity;\n const canRecompute = !reactive._hasPendingDebounce || timeElapsed >= reactive.debounce;\n\n if (canRecompute) {\n // Clear any existing timer and set up new cooldown period\n clearTimeout(reactive._debounceTimer);\n reactive._hasPendingDebounce = true;\n reactive._lastComputeTime = now;\n \n reactive._debounceTimer = setTimeout(() => {\n reactive._hasPendingDebounce = false;\n reactive._debounceTimer = null;\n }, reactive.debounce);\n \n return this.recompute(reactive);\n }\n\n // Still in cooldown period, return cached value\n return reactive.cachedValue;\n }\n\n removeReactive(reactive) {\n this.pending.delete(reactive);\n this.onNextIdle.delete(reactive);\n }\n\n recompute(reactive) {\n this.pending.add(reactive);\n return this.flush(reactive);\n }\n\n flush(reactive) {\n const reactives = Array.from(this.pending);\n this.pending.clear();\n\n // Sort by dependencies\n const sortedReactives = this.sortByDependencies(reactives);\n \n // Process in reverse order (dependencies first)\n for (const reactive of sortedReactives) {\n this.onNextIdle.delete(reactive);\n reactive.compute()\n }\n\n // Notify completion callbacks\n for (const callback of this.onCompleteCallbacks) {\n try {\n callback();\n } catch (error) {\n console.error('Error in batch completion callback:', error);\n }\n }\n\n // If we have a target ID, ensure it's computed and return its value\n if (reactive) {\n // Make sure the target reactor is computed if it wasn't in the batch\n if (!sortedReactives.includes(reactive)) {\n reactive.compute();\n }\n return reactive.cachedValue;\n }\n \n return undefined;\n }\n\n sortByDependencies(reactives) {\n const sorted = [];\n const visited = new Set();\n const visiting = new Set();\n\n const visit = (reactive) => {\n if (visiting.has(reactive)) return;\n if (visited.has(reactive)) return;\n\n visiting.add(reactive);\n\n // Get dependant reactors (handle WeakRefs)\n const dependants = reactive.dependants;\n if (dependants && dependants.size > 0) {\n dependants.forEach(weakRef => {\n const dependant = weakRef.deref();\n if (dependant && reactives.includes(dependant)) {\n visit(dependant); // Visit dependants first\n }\n });\n }\n\n visiting.delete(reactive);\n visited.add(reactive);\n sorted.unshift(reactive); // Add to start of array instead of end\n };\n\n // Process all nodes\n for (const reactive of reactives) {\n if (!visited.has(reactive)) {\n visit(reactive);\n }\n }\n\n return sorted;\n }\n}", "import { ComputationManager } from './ComputationManager.js';\n\nexport class Reactive {\n static computationManager = new ComputationManager();\n static awaitingRecomputation = new Set();\n static reactives = new WeakMap();\n static currentlyComputing = null;\n static computationStack = [];\n static currentDepth = 0;\n static effectsCache = new Set();\n static processingEffects = false;\n static #context = undefined;\n static _nextId = 1; // Counter for unique reactive IDs\n static config = {\n maxDepth: 2000,\n }\n \n static nextId() {\n return Reactive._nextId++;\n }\n\n static provideContext(context) {\n Reactive.#context = context;\n }\n\n static getContext() {\n return Reactive.#context;\n }\n\n static hasContext() {\n return Reactive.#context !== undefined;\n }\n\n static clearContext() {\n Reactive.#context = undefined;\n }\n\n static useContext() {\n return Reactive.#context;\n }\n\n static begin(reactive) {\n if (Reactive.awaitingRecomputation.has(reactive)) {\n Reactive.awaitingRecomputation.delete(reactive);\n }\n\n const reactorIndex = Reactive.computationStack.indexOf(reactive);\n\n if (reactorIndex !== -1) {\n if (reactive.isAsync) {\n Reactive.computationStack.splice(reactorIndex, 1);\n Reactive.computationStack.push(reactive);\n Reactive.currentlyComputing = reactive;\n return;\n } \n const cycle = Reactive.computationStack.slice(reactorIndex).concat(reactive);\n const error = new Error(`Circular dependency detected: ${cycle.map(r => r).join(' -> ')}`);\n error.name = 'CircularDependencyError';\n error.displayed = false;\n throw error;\n }\n \n if (Reactive.currentDepth >= Reactive.config.maxDepth) {\n throw new Error(`Maximum reactive depth of ${Reactive.config.maxDepth} exceeded`);\n }\n \n Reactive.computationStack.push(reactive);\n Reactive.currentlyComputing = reactive;\n Reactive.currentDepth++;\n }\n \n static end(reactive) {\n if (reactive.isAsync) {\n Reactive.computationStack.splice(Reactive.computationStack.indexOf(reactive), 1);\n Reactive.currentlyComputing = Reactive.computationStack[Reactive.computationStack.length - 1] || null;\n Reactive.currentDepth--;\n return;\n }\n Reactive.computationStack.pop();\n Reactive.currentlyComputing = Reactive.computationStack[Reactive.computationStack.length - 1] || null;\n Reactive.currentDepth--;\n }\n\n static addEffect(getter, effect) {\n const reactive = Reactive.reactives.get(getter);\n \n // Compute if needed and notify with current value\n if (reactive.isDirty) {\n Reactive.computationManager.scheduleRecomputation(reactive);\n }\n \n if (!reactive.effects) {\n reactive.effects = new Set();\n }\n \n // Store the WeakRef instead of the raw effect\n reactive.effects.add(effect);\n \n // Return unsubscribe function\n return () => Reactive.removeEffect(getter, effect);\n }\n\n static removeEffect(getter, effect) {\n const reactive = Reactive.reactives.get(getter);\n if (reactive.effects) {\n reactive.effects.delete(effect);\n }\n }\n\n static recompute(reactive) {\n if (!Reactive.awaitingRecomputation.has(reactive)) {\n Reactive.awaitingRecomputation.add(reactive);\n }\n\n \n return Reactive.computationManager.scheduleRecomputation(reactive);\n }\n\n static callEffects(reactive) { \n Reactive.effectsCache.add(reactive);\n \n // Use a single setTimeout for batching\n if (!Reactive.processingEffects) {\n Reactive.processingEffects = true;\n setTimeout(() => {\n Reactive.processEffectsCache();\n Reactive.processingEffects = false;\n }, 0);\n }\n }\n\n static processEffectsCache() {\n const reactives = new Set(Reactive.effectsCache);\n Reactive.effectsCache.clear();\n \n for (const reactive of reactives) {\n try {\n // Process effects using WeakRefs\n const effects = reactive.effects || new Set();\n effects.forEach(effect => {\n if (effect) {\n effect(reactive.cachedValue);\n }\n });\n } catch (error) {\n console.error(`Error in reactive ${reactive._id} effect:`, error);\n }\n }\n \n // If new effects were added during processing, schedule another batch\n if (Reactive.effectsCache.size > 0) {\n setTimeout(() => {\n Reactive.processEffectsCache();\n }, 0);\n }\n }\n\n static markAsDirty(reactive) {\n if (!reactive.isDirty) {\n reactive.isDirty = true;\n \n if (reactive.immediate || (reactive.effects && reactive.effects.size > 0)) {\n Reactive.computationManager.scheduleRecomputation(reactive);\n }\n \n // Process WeakRefs and clean up dead ones\n const deadRefs = [];\n const ids = new Set();\n reactive.dependants.forEach(weakRef => {\n const dependant = weakRef.deref();\n if (dependant) {\n Reactive.markAsDirty(dependant);\n ids.add(dependant._id);\n } else {\n deadRefs.push(weakRef);\n }\n });\n // Clean up dead WeakRefs and sync IDs\n deadRefs.forEach(ref => reactive.dependants.delete(ref));\n reactive.dependantIds = ids;\n }\n }\n\n static destroy(getter) {\n const reactive = Reactive.reactives.get(getter);\n Reactive.computationManager.removeReactive(reactive);\n Reactive.reactives.delete(getter);\n }\n}\n\nexport const markAsDirty = (reactive) => {\n if (isReactive(reactive)) {\n const reactiveInstance = Reactive.reactives.get(reactive);\n if (reactiveInstance) {\n return Reactive.markAsDirty(reactiveInstance);\n }\n }\n}\n\nexport const isReactive = (getter) => {\n return Reactive.reactives.has(getter);\n}\n\nexport const addEffect = (getter, effect) => {\n if (!isReactive(getter)) {\n throw new Error('Invalid effect getter');\n \n }\n\n if (!effect || typeof effect !== 'function') {\n throw new Error('Invalid effect function');\n }\n\n return Reactive.addEffect(getter, effect);\n}\n\nexport const removeEffect = (getter, effect) => {\n if (isReactive(getter)) {\n return Reactive.removeEffect(getter, effect);\n }\n}\n\nexport const destroyReactive = (getter) => {\n if (isReactive(getter)) {\n return Reactive.destroy(getter);\n }\n}\n\nexport const provideContext = (context) => {\n Reactive.provideContext(context);\n}\n\nexport const getContext = () => {\n return Reactive.getContext();\n}\n\nexport const hasContext = () => {\n return Reactive.hasContext();\n}\n\nexport const createAdapter = (getter, path = []) => {\n if (!isReactive(getter)) {\n throw new Error('Invalid adapter getter');\n }\n\n let snapshotCache = undefined;\n let unsubscribeAll = null;\n const subscribers = new Set();\n\n const getSnapshot = () => {\n if (snapshotCache !== undefined) {\n return snapshotCache;\n }\n\n const value = path && path.length > 0 ? traverse(getter(), path) : getter();\n\n if (Array.isArray(value)) {\n snapshotCache = value.slice();\n } else if (typeof value === 'object' && value !== null) {\n const clone = Object.create(Object.getPrototypeOf(value));\n Object.defineProperties(clone, Object.getOwnPropertyDescriptors(value));\n snapshotCache = Object.freeze(clone);\n } else {\n snapshotCache = value;\n }\n \n return snapshotCache;\n };\n\n const subscribe = (listener) => {\n if (!unsubscribeAll) {\n unsubscribeAll = addEffect(getter, () => {\n snapshotCache = undefined;\n for (const subscriber of subscribers) {\n subscriber(getSnapshot);\n }\n });\n }\n \n subscribers.add(listener);\n return () => {\n subscribers.delete(listener);\n if (subscribers.size === 0) {\n unsubscribeAll();\n unsubscribeAll = null;\n }\n };\n };\n\n return [getSnapshot, subscribe];\n}", "import { Reactive } from './Reactive.js';\nimport { isAsyncFunction } from '@shared/utils';\n\nexport class Reactor {\n static create(fn, config = {}) {\n const reactor = new Reactor(fn, config);\n Reactive.reactives.set(reactor.getter, reactor);\n return reactor.getter;\n }\n\n constructor(fn, config = {}) {\n this.fn = fn;\n this._id = Reactive.nextId();\n this.isAsync = isAsyncFunction(fn);\n this.pendingResolve = undefined;\n this.roots = new Set();\n this.dependants = new Set();\n this.dependantIds = new Set();\n this.effects = new Set(Array.isArray(config.effects) ? config.effects : []);\n this.cachedValue = config.initialValue || undefined;\n this.isDirty = true;\n this.debounce = config.debounce || 0;\n this.onAccess = config.onAccess || undefined;\n this.detatched = config.detatched || false;\n this.immediate = config.immediate || false;\n this.context = config.context || undefined;\n this._lastComputeTime = undefined;\n this._hasPendingDebounce = false;\n this._debounceTimer = undefined;\n this.resolvers = [];\n this.rejectors = [];\n this._computationId = 0; // Track computation version\n this.getter = this.#getter.bind(this);\n\n if (this.immediate) {\n this.compute();\n }\n }\n\n compute() {\n Reactive.begin(this);\n try {\n const context = this.context ? this.context : Reactive.hasContext() ? Reactive.useContext() : undefined;\n \n if (!this.isAsync) {\n this.cachedValue = this.fn(context, this.cachedValue);\n this.isDirty = false;\n return this.cachedValue;\n }\n\n // Track this specific computation\n this._computationId = (this._computationId || 0) + 1;\n const computationId = this._computationId;\n\n this.pendingResolve = this.fn(context, this.cachedValue);\n this.pendingResolve.then(value => {\n // Only update if this is still the latest computation\n if (this._computationId === computationId) {\n this.resolvers.forEach(resolve => resolve(value));\n this.resolvers = [];\n this.cachedValue = value;\n this.isDirty = false;\n }\n return value;\n }).catch(error => {\n if (this._computationId === computationId) {\n this.rejectors.forEach(reject => reject(error));\n this.rejectors = [];\n }\n }).finally(() => {\n this.pendingResolve = null; // Always clear pending promise\n // Only call end/effects if this is still the latest computation\n if (this._computationId === computationId) {\n Reactive.end(this);\n Reactive.callEffects(this);\n }\n });\n\n this.cachedValue = new Promise((resolve, reject) => {\n this.resolvers.push(resolve);\n this.rejectors.push(reject);\n });\n \n return this.cachedValue;\n } finally {\n if (!this.isAsync) {\n Reactive.end(this);\n Reactive.callEffects(this);\n }\n }\n }\n\n #getter() {\n try {\n if (!this.detatched && Reactive.currentlyComputing && Reactive.currentlyComputing !== this && !this.dependantIds.has(Reactive.currentlyComputing._id)) {\n this.dependantIds.add(Reactive.currentlyComputing._id);\n this.dependants.add(new WeakRef(Reactive.currentlyComputing));\n }\n \n if (!this.isDirty) {\n if (this.isAsync) {\n return Promise.resolve(this.cachedValue);\n }\n\n return this.cachedValue;\n }\n\n // If dirty, always start new computation (even if previous pending)\n return Reactive.recompute(this);\n } catch (error) {\n throw error;\n } finally {\n if (this.onAccess) {\n this.onAccess(this.cachedValue);\n }\n }\n }\n}\n\nexport const createReactor = (fn, config = {}) => Reactor.create(fn, config);\n\nexport const destroyReactor = (target) => {\n if (isReactor(target)) {\n Reactive.destroy(target);\n }\n}\n\nexport const isReactor = (getter) => {\n const reactor = Reactive.reactives.get(getter);\n if (!reactor) {\n return false;\n }\n\n return reactor instanceof Reactor;\n}\n\nexport const isDirtyReactor = (getter) => {\n const reactor = Reactive.reactives.get(getter);\n if (!reactor) {\n return false;\n }\n\n return reactor.isDirty;\n}\n", "import { Reactive } from './Reactive.js';\n\nexport class Signal {\n static create(initialValue, config = {}) {\n const signal = new Signal(initialValue, config);\n Reactive.reactives.set(signal.getter, signal);\n return signal.getter;\n }\n\n constructor(initialValue, config = {}) {\n this._id = Reactive.nextId();\n this.isAsync = false;\n this.cachedValue = undefined;\n this.dependants = new Set();\n this.dependantIds = new Set();\n this.roots = new Set();\n this.effects = new Set(Array.isArray(config.effects) ? config.effects : []);\n this.isDirty = true;\n this.debounce = config.debounce || 0;\n this.onAccess = config.onAccess || null;\n this.detatched = config.detatched || false;\n this.immediate = config.immediate || false;\n this._pendingChange = initialValue;\n this._lastComputeTime = null;\n this._hasPendingDebounce = false;\n this._debounceTimer = null;\n this.getter = (...args) => this.#getter(...args);\n }\n\n compute() {\n Reactive.begin(this);\n try {\n this.cachedValue = this._pendingChange;\n this._pendingChange = undefined;\n this.isDirty = false;\n return this.cachedValue;\n } finally {\n Reactive.end(this);\n Reactive.callEffects(this);\n }\n }\n\n #getter(...args) {\n try {\n if (!this.detatched && Reactive.currentlyComputing && Reactive.currentlyComputing !== this && !this.dependantIds.has(Reactive.currentlyComputing._id)) {\n this.dependantIds.add(Reactive.currentlyComputing._id);\n this.dependants.add(new WeakRef(Reactive.currentlyComputing));\n }\n\n if (args.length > 0) {\n const signal = args[0];\n this._pendingChange = typeof signal === 'function' ? signal(this.cachedValue) : signal;\n Reactive.markAsDirty(this);\n return;\n }\n\n if (this.isDirty) {\n return Reactive.recompute(this);\n }\n\n return this.cachedValue;\n \n } catch (error) {\n throw error;\n } finally {\n if (this.onAccess) {\n this.onAccess(this.cachedValue);\n }\n }\n }\n}\n\nexport const createSignal = (initialValue, config = {}) => Signal.create(initialValue, config);\n\nexport const destroySignal = (getter) => {\n if (isSignal(getter)) {\n Reactive.destroy(getter);\n }\n}\n\nexport const isSignal = (getter) => {\n const signal = Reactive.reactives.get(getter);\n if (!signal) {\n return false;\n }\n\n return signal instanceof Signal;\n}\n\nexport const isDirtySignal = (getter) => {\n const signal = Reactive.reactives.get(getter);\n if (!signal) {\n return false;\n }\n\n return signal.isDirty;\n}", "import { Reactive } from './Reactive.js';\n\nexport class Subscriber {\n static create(getter, fn, config = {}) {\n const subscriber = new Subscriber(getter, fn, config);\n Reactive.reactives.set(subscriber.getter, subscriber);\n return () => Reactive.destroy(subscriber.getter);\n }\n\n constructor(getter, subscriber, config = {}) {\n this._id = Reactive.nextId();\n this.getter = getter;\n this.isDirty = false;\n this.subscriber = subscriber;\n this.debounce = config.debounce || 0;\n this.onAccess = config.onAccess || null;\n this.immediate = true;\n this._hasPendingDebounce = false;\n this._lastComputeTime = null;\n this._debounceTimer = null;\n this.dependants = new Set();\n this.dependantIds = new Set();\n this.unsubscribe = () => Reactive.computationManager.removeReactive(this);\n Reactive.begin(this);\n this.cachedValue = this.getter();\n this.subscriber(this.cachedValue); // Call subscriber with initial value\n Reactive.end(this);\n }\n\n compute() {\n try {\n this.cachedValue = this.getter();\n this.subscriber(this.cachedValue);\n this.isDirty = false;\n } catch (error) {\n throw error;\n }\n }\n}\n\nexport const createSubscriber = (getter, fn, config = {}) => Subscriber.create(getter, fn, config);\n\nexport const destroySubscriber = (getter) => {\n if (isSubscriber(getter)) {\n Reactive.destroy(getter);\n }\n}\n\nexport const isSubscriber = (getter) => {\n const subscriber = Reactive.reactives.get(getter);\n if (!subscriber) {\n return false;\n }\n\n return subscriber instanceof Subscriber;\n}", "const traversalFunctions = [\n null, // index 0 (unused)\n null, // index 1 (single property access doesn't need optimization)\n (obj, path) => obj?.[path[0]]?.[path[1]],\n (obj, path) => obj?.[path[0]]?.[path[1]]?.[path[2]],\n (obj, path) => obj?.[path[0]]?.[path[1]]?.[path[2]]?.[path[3]],\n (obj, path) => obj?.[path[0]]?.[path[1]]?.[path[2]]?.[path[3]]?.[path[4]],\n (obj, path) => obj?.[path[0]]?.[path[1]]?.[path[2]]?.[path[3]]?.[path[4]]?.[path[5]],\n (obj, path) => obj?.[path[0]]?.[path[1]]?.[path[2]]?.[path[3]]?.[path[4]]?.[path[5]]?.[path[6]],\n (obj, path) => obj?.[path[0]]?.[path[1]]?.[path[2]]?.[path[3]]?.[path[4]]?.[path[5]]?.[path[6]]?.[path[7]]\n]\n\nfunction createTraversalFunction(length) {\n const accessors = Array.from({ length }, (_, i) => `?.[path[${i}]]`);\n const expr = \"obj\" + accessors.join(\"\");\n const fn = new Function(\"obj\", \"path\", `return ${expr}`);\n traversalFunctions[length] = fn;\n return fn;\n}\n\nexport function traverse(state, path) {\n const len = path.length;\n if (len === 0) return state;\n if (len === 1) return state[path[0]];\n \n // Use existing function if available\n if (len < traversalFunctions.length && traversalFunctions[len]) {\n return traversalFunctions[len](state, path);\n }\n \n // Create and cache new function if needed\n if (!traversalFunctions[len]) {\n return createTraversalFunction(len)(state, path);\n }\n \n return traversalFunctions[len](state, path);\n}\n", "// Surface.js\nimport { createReactor, destroyReactor } from './Reactor.js';\nimport { addEffect } from './Reactive.js';\nimport { createSignal } from './Signal.js';\nimport { traverse } from './lib/traverse.js';\n\nconst EMPTY_CACHE = Symbol();\n\nexport class Surface {\n static surfaces = new WeakMap();\n static plugins = new Map();\n\n static registerPlugin(name, plugin) {\n if (Surface.plugins.has(name)) {\n throw new Error(`Plugin \"${name}\" already registered`);\n }\n Surface.plugins.set(name, plugin());\n }\n\n static resetPlugins() {\n Surface.plugins.clear();\n }\n\n static create(setupFn, options = {}) {\n const instance = new Surface(options);\n const useSurface = instance.setup(setupFn);\n Surface.surfaces.set(useSurface, instance);\n return useSurface;\n }\n\n static createPlugin(name, fn, options = {}) {\n const plugin = Surface.create(fn, options);\n Surface.registerPlugin(name, plugin);\n return plugin;\n }\n\n constructor(options = {}) {\n this.options = options;\n this.setupFn = null;\n this.subscribers = new Set();\n this.subscribersQueued = false;\n this.destroyCallback = null;\n\n // Values, computeds, actions, and extensions that are pending to be bound to the surface\n this.values = new Set();\n this.computeds = new Set();\n this.actions = new Set();\n this.extensions = new Set();\n\n this.snapshotCache = EMPTY_CACHE;\n this.surface = this.#createSurface();\n this.useSurface = () => this.surface;\n }\n\n setup(setupFn) {\n if (!setupFn) {\n return null;\n }\n\n this.setupFn = setupFn;\n this.reset();\n\n const pendingReactives = new Set();\n\n try {\n let result;\n \n if (typeof setupFn === 'function') {\n result = this.#setupFromFunction(setupFn, pendingReactives);\n } else if (typeof setupFn === 'object' && setupFn !== null) {\n result = this.#setupFromObject(setupFn, pendingReactives);\n } else {\n throw new Error('setupFn must be a function or object configuration');\n }\n \n this.#bindSurface(result);\n pendingReactives.forEach(reactive => addEffect(reactive, () => this.#queueSubscribers()));\n this.#queueSubscribers(); \n return this.useSurface;\n } catch (error) {\n console.error('Error in setup function', error);\n throw error;\n }\n }\n\n reset() {\n this.subscribers.clear();\n this.subscribersQueued = false;\n this.values.clear();\n this.computeds.clear();\n this.actions.clear();\n this.extensions.clear();\n this.snapshotCache = EMPTY_CACHE;\n this.surface = this.#createSurface();\n }\n\n createValue(initial = undefined, cb) {\n const signal = createSignal(initial);\n const value = Object.create(null);\n Object.defineProperty(value, 'value', {\n get: () => signal(),\n set: (newValue) => signal(newValue),\n enumerable: true,\n });\n this.values.add(value);\n cb?.(signal);\n return value;\n }\n\n createComputed(fn, cb) {\n const reactor = createReactor(fn, { context: this.surface });\n const computed = Object.create(null);\n Object.defineProperty(computed, 'value', {\n get: () => reactor(),\n enumerable: true,\n });\n this.computeds.add(computed);\n cb?.(reactor);\n return computed;\n }\n\n createAction(fn) {\n const action = fn.bind(this.surface, this.surface)\n this.actions.add(action);\n return action;\n }\n\n extend(useSurface) {\n \n if (!useSurface) throw new Error('No source surface provided');\n \n if (!isSurface(useSurface)) {\n throw new Error('Cannot extend non-surface');\n }\n const surface = useSurface();\n this.extensions.add(surface);\n return surface;\n }\n\n #setupFromFunction(setupFn, pendingReactives) {\n return setupFn({\n value: (initial = undefined) => this.createValue(initial, (signal) => pendingReactives.add(signal)),\n computed: (fn = () => {}) => this.createComputed(fn, (reactor) => pendingReactives.add(reactor)),\n action: (fn = () => {}) => this.createAction(fn),\n extend: (useSurface) => this.extend(useSurface),\n destroy: () => this.#destroy(),\n ...Object.fromEntries(Surface.plugins.entries())\n }) || {};\n }\n\n #processStateValue(stateConfig, isDev, key) {\n // Support shorthand: state: { count: 0 } instead of { count: { default: 0 } }\n if (typeof stateConfig !== 'object' || stateConfig === null) {\n return typeof stateConfig === 'function' ? stateConfig() : stateConfig;\n }\n \n // If it's an object but doesn't have 'default', treat as shorthand\n if (!('default' in stateConfig)) {\n // Validate state config in dev mode\n if (isDev && 'dummy' in stateConfig) {\n console.warn(`State \"${key}\" has dummy value but no default value`);\n }\n return typeof stateConfig === 'function' ? stateConfig() : stateConfig;\n }\n \n // Full config with default/dummy\n let value = isDev && 'dummy' in stateConfig ? stateConfig.dummy : stateConfig.default;\n return typeof value === 'function' ? value() : value;\n }\n\n #setupFromObject(config, pendingReactives) {\n const result = {};\n const isDev = this.options.mode === 'development' || this.options.mode === 'dev';\n\n // 1. Process extend array first (so extended properties are available)\n if (config.extend && Array.isArray(config.extend)) {\n for (const useSurface of config.extend) {\n this.extend(useSurface);\n }\n }\n\n // 2. Process plugins (if specified) - handled in #bindSurface via Surface.plugins\n // Note: Plugins are automatically added to all surfaces, so we don't need to add them to result\n // If you want selective plugin inclusion, you'd need to modify #bindSurface\n\n // 3. Process state definitions\n if (config.state && typeof config.state === 'object') {\n for (const [key, stateConfig] of Object.entries(config.state)) {\n const initialValue = this.#processStateValue(stateConfig, isDev, key);\n result[key] = this.createValue(initialValue, (signal) => pendingReactives.add(signal));\n }\n }\n\n // 4. Process computed properties\n if (config.computed && typeof config.computed === 'object') {\n for (const [key, fn] of Object.entries(config.computed)) {\n if (typeof fn === 'function') {\n result[key] = this.createComputed(fn, (reactor) => pendingReactives.add(reactor));\n }\n }\n }\n\n // 5. Process actions\n if (config.actions && typeof config.actions === 'object') {\n for (const [key, fn] of Object.entries(config.actions)) {\n if (typeof fn === 'function') {\n result[key] = this.createAction(fn);\n }\n }\n }\n\n // 6. Handle lifecycle hooks\n if (config.onInit && typeof config.onInit === 'function') {\n // Execute after setup is complete\n Promise.resolve().then(() => {\n try {\n config.onInit(this.surface);\n } catch (error) {\n console.error('Error in onInit callback', error);\n }\n });\n }\n\n if (config.onDestroy && typeof config.onDestroy === 'function') {\n // Store for later execution\n this.destroyCallback = config.onDestroy;\n }\n\n return result;\n }\n\n #createAdapter () { \n return [() => this.#getSnapshot(), (subscriber) => this.#subscribe(subscriber)];\n }\n\n #getSnapshot() {\n if (this.snapshotCache !== EMPTY_CACHE) {\n return this.snapshotCache;\n }\n\n const clone = Object.create(Object.getPrototypeOf(this.surface));\n Object.defineProperties(clone, Object.getOwnPropertyDescriptors(this.surface));\n this.snapshotCache = Object.freeze(clone);\n \n return this.snapshotCache;\n };\n\n #subscribe(listener) {\n this.subscribers.add(listener);\n return () => this.subscribers.delete(listener);\n }\n\n #callSubscribers(snapshot) {\n for (const subscriber of this.subscribers) {\n subscriber(snapshot);\n }\n }\n\n #queueSubscribers() {\n if (this.subscribers.size === 0 || this.subscribersQueued) return;\n this.subscribersQueued = true;\n Promise.resolve().then(() => {\n this.subscribersQueued = false;\n this.snapshotCache = EMPTY_CACHE;\n this.#callSubscribers(this.#getSnapshot());\n });\n }\n\n #createSurface(surface = Object.create(null)) {\n Object.defineProperty(surface, '$get', {\n value: (path) => this.#get(path),\n writable: false,\n enumerable: false,\n configurable: false\n });\n \n Object.defineProperty(surface, '$set', {\n value: (path, newValue) => this.#set(path, newValue),\n writable: false,\n enumerable: false,\n configurable: false\n });\n \n Object.defineProperty(surface, '$dispatch', {\n value: (name) => this.#dispatch(name),\n writable: false,\n enumerable: false,\n configurable: false\n });\n \n Object.defineProperty(surface, '$inject', {\n value: (overrides) => Object.assign({}, this.surface, overrides),\n writable: false,\n enumerable: false,\n configurable: false\n });\n\n Object.defineProperty(surface, '$snapshot', {\n value: () => this.#getSnapshot(),\n writable: false,\n enumerable: false,\n configurable: false\n });\n\n Object.defineProperty(surface, '$subscribe', {\n value: (listener) => this.#subscribe(listener),\n writable: false,\n enumerable: false,\n configurable: false\n });\n \n Object.defineProperty(surface, '$adapter', {\n value: () => this.#createAdapter(),\n writable: false,\n enumerable: false,\n configurable: false\n });\n\n Object.defineProperty(surface, '$destroy', {\n value: () => this.#destroy(),\n writable: false,\n enumerable: false,\n configurable: false\n });\n return surface;\n }\n\n #destroy() {\n // Call onDestroy callback if defined\n if (this.destroyCallback && typeof this.destroyCallback === 'function') {\n try {\n this.destroyCallback(this.surface);\n } catch (error) {\n console.error('Error in onDestroy callback', error);\n }\n }\n \n const surfaceReactor = this.surfaceReactor;\n this.surfaceReactor = null;\n Surface.surfaces.delete(surfaceReactor);\n destroyReactor(surfaceReactor);\n }\n\n #get(path = []) {\n return traverse(this.surface, path);\n }\n\n #set(name, newValue) {\n const value = this.values?.get?.(name);\n value.value = newValue;\n return this.surface;\n }\n\n #dispatch(name, ...args) {\n const action = this.actions.has(name)\n ? this.actions.get(name)\n : this.surface[name];\n\n if (typeof action === 'function') {\n return action(...args);\n }\n return this.surfaceReactor();\n }\n\n #bindSurface(result = {}) {\n const oldKeys = Object.keys(this.surface);\n\n while (oldKeys.length > 0) {\n const key = oldKeys.shift();\n if (key in this.surface) {\n delete this.surface[key];\n }\n }\n\n for (const [key, plugin] of Surface.plugins) {\n Object.defineProperty(this.surface, key, {\n value: plugin\n });\n }\n\n for (const extension of this.extensions) {\n const descriptors = Object.getOwnPropertyDescriptors(extension);\n // Filter out the special $ methods if you don't want to inherit those\n const filteredDescriptors = Object.fromEntries(\n Object.entries(descriptors).filter(([key]) => !key.startsWith('$'))\n );\n Object.defineProperties(this.surface, filteredDescriptors);\n }\n\n const entries = Object.entries(result);\n \n for (const [key, value] of entries) {\n if (this.values.has(value)) {\n Object.defineProperty(this.surface, key, {\n get: () => value.value,\n set: (newValue) => value.value = newValue\n });\n\n continue;\n }\n\n if (this.computeds.has(value)) {\n Object.defineProperty(this.surface, key, {\n get: () => value.value\n });\n continue;\n }\n \n if (this.actions.has(value)) {\n Object.defineProperty(this.surface, key, { value });\n continue;\n }\n\n this.surface[key] = value;\n }\n\n return this.surface;\n }\n}\n\nexport const defineSurface = (...args) => Surface.create(...args);\nexport const refreshSurface = (surfaceReactor) => {\n if (isSurface(surfaceReactor)) {\n const surfaceInstance = Surface.surfaces.get(surfaceReactor);\n if (surfaceInstance) {\n surfaceInstance.setup();\n }\n }\n}\nexport const definePlugin = (...args) => Surface.createPlugin(...args);\nexport const isSurface = (surfaceReactor) => Surface.surfaces.has(surfaceReactor);\n\nexport const destroySurface = (surfaceReactor) => {\n if (isSurface(surfaceReactor)) {\n Surface.surfaces.delete(surfaceReactor);\n }\n}\n", "export function nextIdleTick(callback) {\n if (typeof window !== 'undefined' && window.requestIdleCallback) {\n return window.requestIdleCallback(callback, { timeout: 100 });\n }\n\n // Fallback for browsers without requestIdleCallback (Safari/WebKit)\n if (typeof window !== 'undefined') {\n // Use requestAnimationFrame + setTimeout for better idle approximation\n if (window.requestAnimationFrame) {\n return window.requestAnimationFrame(() => {\n setTimeout(callback, 0);\n });\n }\n // Final fallback to setTimeout\n return setTimeout(callback, 0);\n }\n\n // Server-side or no window object - execute immediately\n if (typeof callback === 'function') {\n callback();\n }\n return null;\n}\n", "import { dispatch } from '@jucie-state/core/lib/marker.js';\nimport { Plugin } from '@jucie-state/core/Plugin';\nimport { Reactive, createReactor, createSubscriber } from '@jucie-reactive/core';\nimport { nextIdleTick } from '@shared/utils';\n\nclass Node {\n static create() {\n return new Node();\n }\n\n constructor() {\n this.reactives = new Set();\n this.reactiveIds = new Set();\n this.childReactives = new Set();\n this.childReactiveIds = new Set();\n this.children = new Map();\n this.hasChildReactives = false;\n }\n}\n\nexport class ReactiveJucieState extends Plugin {\n static name = 'reactive';\n static roots = new WeakMap();\n static states = new Set();\n\n #batching = false;\n #markers = new Set();\n\n initialize(state) {\n ReactiveJucieState.states.add(new WeakRef(state));\n ReactiveJucieState.roots.set(state, Node.create());\n }\n\n actions(state) {\n return {\n createReactor: (fn, config = {}) => {\n return createReactor(fn, { ...config, context: state });\n },\n createSubscriber: (getter, callback, config = {}) => {\n return createSubscriber(() => getter(state), callback, config);\n }\n }\n }\n\n onBatchStart() {\n this.#batching = true;\n }\n\n onBatchEnd() {\n this.#batching = false;\n // Propagate all accumulated markers\n this.#markers.forEach(marker => {\n this.propagateChange(this.state, marker);\n });\n this.#markers.clear();\n }\n\n onStateChange(marker) {\n if (!this.#batching) {\n this.propagateChange(this.state, marker);\n return;\n }\n this.#markers.add(marker);\n }\n\n onStateAccess(marker) {\n dispatch(marker, {\n global: () => {\n this.addReactive(this.state, null);\n },\n path: ({ path }) => {\n this.addReactive(this.state, path);\n }\n });\n }\n\n propagateChange(stateInstance, marker) {\n dispatch(marker, {\n global: () => {\n this.walkMarkerPath(this.getRoot(stateInstance), null);\n },\n path: ({ path }) => {\n this.walkMarkerPath(this.getRoot(stateInstance), path);\n }\n });\n }\n\n walkMarkerPath(node, path, visitedReactives = new Set()) {\n this.processReactives(node.reactives, node.reactiveIds, visitedReactives);\n\n // Global update?\n if (!path || path === '*') {\n this.processReactives(node.childReactives, node.childReactiveIds, visitedReactives);\n return visitedReactives;\n }\n \n // Path update\n const lastIndex = path.length - 1;\n let i = 0;\n\n while (i <= lastIndex) {\n const segment = path[i];\n if (!node.children.has(segment)) break;\n \n node = node.children.get(segment);\n \n // Get reactives\n this.processReactives(node.reactives, node.reactiveIds, visitedReactives);\n\n // Last node? Get childReactives\n if (i === lastIndex) {\n this.processReactives(node.childReactives, node.childReactiveIds, visitedReactives);\n }\n \n i++;\n }\n\n return visitedReactives;\n }\n\n processReactives(reactiveSet, idSet, visitedReactives) {\n const deadRefs = [];\n const ids = new Set();\n reactiveSet.forEach(weakRef => {\n const reactive = weakRef.deref();\n if (reactive) {\n if (!visitedReactives.has(reactive)) {\n visitedReactives.add(reactive);\n Reactive.markAsDirty(reactive);\n }\n ids.add(reactive._id);\n } else {\n deadRefs.push(weakRef);\n }\n });\n deadRefs.forEach(ref => reactiveSet.delete(ref));\n if (idSet) {\n idSet.clear();\n ids.forEach(id => idSet.add(id));\n }\n }\n\n addWeakRefIfNotExists(weakRefSet, idSet, reactive) {\n if (!idSet.has(reactive._id)) {\n idSet.add(reactive._id);\n weakRefSet.add(new WeakRef(reactive));\n }\n }\n\n addReactive(stateInstance, path) {\n const reactive = Reactive.currentlyComputing;\n if (!reactive) return;\n \n const root = this.getRoot(stateInstance);\n let node = root;\n \n // Normalize path\n const normalizedPath = Array.isArray(path) ? path : [];\n \n // Add reactor to root level (using WeakRef)\n if (normalizedPath.length === 0 || path === '*' || !path) {\n this.addWeakRefIfNotExists(node.reactives, node.reactiveIds, reactive);\n }\n\n this.addWeakRefIfNotExists(node.childReactives, node.childReactiveIds, reactive);\n \n // Add reactor at each level as we move down\n const length = normalizedPath.length;\n for (let i = 0; i < length; i++) {\n const segment = normalizedPath[i];\n if (!node.children.has(segment)) {\n node.children.set(segment, Node.create());\n }\n node = node.children.get(segment);\n if (i !== length - 1) {\n this.addWeakRefIfNotExists(node.childReactives, node.childReactiveIds, reactive);\n } else {\n this.addWeakRefIfNotExists(node.reactives, node.reactiveIds, reactive);\n }\n }\n \n this.updateHasChildReactives(root, normalizedPath);\n }\n\n removeReactive(reactive) {\n ReactiveJucieState.states.forEach(state => {\n const root = this.getRoot(state.deref());\n if (!root) return;\n this.removeReactiveFromNode(root, reactive);\n });\n \n nextIdleTick(() => {\n ReactiveJucieState.states.forEach(state => {\n const root = this.getRoot(state.deref());\n if (!root) return;\n this.cleanupEmptyNodes(root);\n this.updateHasChildReactives(root);\n });\n });\n }\n\n removeReactiveFromNode(node, reactive) {\n // Need to find and remove the WeakRef that points to this reactive\n const removeFromSet = (set) => {\n const toDelete = [];\n set.forEach(weakRef => {\n const ref = weakRef.deref();\n if (ref === reactive || !ref) {\n toDelete.push(weakRef);\n }\n });\n toDelete.forEach(ref => set.delete(ref));\n };\n\n removeFromSet(node.reactives);\n removeFromSet(node.childReactives);\n\n if (node.children.size > 0) {\n for (const child of node.children.values()) {\n this.removeReactiveFromNode(child, reactive);\n }\n }\n }\n\n getRoot(stateInstance) {\n let root = ReactiveJucieState.roots.get(stateInstance);\n if (!root) {\n root = Node.create();\n ReactiveJucieState.roots.set(stateInstance, root);\n }\n return root;\n }\n\n cleanupEmptyNodes(node) {\n // Helper to count alive WeakRefs\n const countAlive = (set) => {\n let count = 0;\n const deadRefs = [];\n set.forEach(weakRef => {\n if (weakRef.deref()) {\n count++;\n } else {\n deadRefs.push(weakRef);\n }\n });\n deadRefs.forEach(ref => set.delete(ref));\n return count;\n };\n\n // Clean up empty child nodes\n for (const [segment, child] of node.children) {\n this.cleanupEmptyNodes(child);\n \n // If child has no live reactors and no children, remove it\n const hasReactives = countAlive(child.reactives) > 0;\n const hasChildReactives = countAlive(child.childReactives) > 0;\n \n if (!hasReactives && !hasChildReactives && child.children.size === 0) {\n node.children.delete(segment);\n }\n }\n }\n\n updateHasChildReactives(node, path = null) {\n // Helper to check if set has any alive WeakRefs\n const hasAlive = (set) => {\n for (const weakRef of set) {\n if (weakRef.deref()) return true;\n }\n return false;\n };\n\n // If no path provided, update entire trie\n if (!path) {\n const updateNode = (node) => {\n node.hasChildReactives = Array.from(node.children.values()).some(child => \n hasAlive(child.reactives) || \n hasAlive(child.childReactives) || \n child.hasChildReactives\n );\n \n for (const child of node.children.values()) {\n updateNode(child);\n }\n };\n return updateNode(node);\n }\n\n // If path provided, only update that path\n const visited = [];\n\n // Walk down and collect nodes\n for (const segment of path) {\n if (!node.children.has(segment)) return;\n visited.push(node);\n node = node.children.get(segment);\n }\n\n // Walk up and update flags only if needed\n for (let i = visited.length - 1; i >= 0; i--) {\n const parent = visited[i];\n const newValue = Array.from(parent.children.values()).some(child =>\n hasAlive(child.reactives) || \n hasAlive(child.childReactives) || \n child.hasChildReactives\n );\n\n if (parent.hasChildReactives !== newValue) {\n parent.hasChildReactives = newValue;\n } else {\n break; // Early exit if no change\n }\n }\n }\n}\n"],
5
+ "mappings": "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",
6
+ "names": ["STATE_CONTEXT", "MATCHER", "MARKER_GLOBAL", "MARKER_SINGLE", "MARKER_MANY", "MARKER_EPHEMERAL", "isGlobalMarker", "marker", "MARKER_GLOBAL", "isPathMarker", "MARKER_SINGLE", "isMarkers", "MARKER_MANY", "isEphemeralMarker", "MARKER_EPHEMERAL", "dispatch", "marker", "global", "path", "ephemeral", "error", "isGlobalMarker", "isEphemeralMarker", "isPathMarker", "isMarkers", "results", "i", "nestedMarker", "err", "Plugin", "options", "state", "pluginInstance", "nextIdleTick", "callback", "isAsyncFunction", "fn", "ComputationManager", "reactive", "deadRefs", "ids", "weakRef", "dependant", "ref", "now", "timeElapsed", "reactives", "sortedReactives", "error", "sorted", "visited", "visiting", "visit", "dependants", "Reactive", "_Reactive", "#context", "context", "reactorIndex", "cycle", "r", "getter", "effect", "Reactor", "_Reactor", "fn", "config", "reactor", "Reactive", "isAsyncFunction", "#getter", "context", "computationId", "value", "resolve", "error", "reject", "createReactor", "Subscriber", "_Subscriber", "getter", "fn", "config", "subscriber", "Reactive", "error", "createSubscriber", "EMPTY_CACHE", "nextIdleTick", "callback", "Node", "_Node", "ReactiveJucieState", "_ReactiveJucieState", "Plugin", "#batching", "#markers", "state", "fn", "config", "getter", "callback", "z", "marker", "dispatch", "path", "stateInstance", "node", "visitedReactives", "lastIndex", "i", "segment", "reactiveSet", "idSet", "deadRefs", "ids", "weakRef", "reactive", "c", "ref", "id", "weakRefSet", "root", "normalizedPath", "length", "nextIdleTick", "removeFromSet", "set", "toDelete", "child", "countAlive", "count", "hasReactives", "hasChildReactives", "hasAlive", "updateNode", "visited", "parent", "newValue"]
7
+ }
package/package.json ADDED
@@ -0,0 +1,46 @@
1
+ {
2
+ "name": "@jucie-reactive/jucie-state",
3
+ "version": "1.0.0",
4
+ "description": "Jucie State integration for @jucie-reactive - connect reactive signals with Jucie State",
5
+ "type": "module",
6
+ "main": "./dist/main.js",
7
+ "exports": {
8
+ ".": "./dist/main.js"
9
+ },
10
+ "files": [
11
+ "dist/",
12
+ "README.md"
13
+ ],
14
+ "scripts": {
15
+ "build": "node ../../scripts/build-package.js extensions/jucie",
16
+ "test": "echo 'Tests run from root'",
17
+ "prepublishOnly": "npm run build"
18
+ },
19
+ "author": "Adrian Miller",
20
+ "license": "MIT",
21
+ "publishConfig": {
22
+ "access": "public"
23
+ },
24
+ "repository": {
25
+ "type": "git",
26
+ "url": "git+https://github.com/adrianjonmiller/reactive",
27
+ "directory": "extensions/jucie"
28
+ },
29
+ "engines": {
30
+ "node": ">=18.0.0"
31
+ },
32
+ "keywords": [
33
+ "reactive",
34
+ "jucie-state",
35
+ "integration",
36
+ "state-management"
37
+ ],
38
+ "peerDependencies": {
39
+ "@jucie-state/core": "^1.0.0"
40
+ },
41
+ "peerDependenciesMeta": {
42
+ "@jucie-state/core": {
43
+ "optional": false
44
+ }
45
+ }
46
+ }