@nerdalytics/beacon 1000.2.0 → 1000.2.2

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.
@@ -1,4 +1,4 @@
1
- type Unsubscribe = () => void;
1
+ export type Unsubscribe = () => void;
2
2
  export type ReadOnlyState<T> = () => T;
3
3
  export interface WriteableState<T> {
4
4
  set(value: T): void;
@@ -8,36 +8,12 @@ declare const STATE_ID: unique symbol;
8
8
  export type State<T> = ReadOnlyState<T> & WriteableState<T> & {
9
9
  [STATE_ID]?: symbol;
10
10
  };
11
- /**
12
- * Creates a reactive state container with the provided initial value.
13
- */
14
11
  export declare const state: <T>(initialValue: T, equalityFn?: (a: T, b: T) => boolean) => State<T>;
15
- /**
16
- * Registers a function to run whenever its reactive dependencies change.
17
- */
18
12
  export declare const effect: (fn: () => void) => Unsubscribe;
19
- /**
20
- * Groups multiple state updates to trigger effects only once at the end.
21
- */
22
13
  export declare const batch: <T>(fn: () => T) => T;
23
- /**
24
- * Creates a read-only computed value that updates when its dependencies change.
25
- */
26
14
  export declare const derive: <T>(computeFn: () => T) => ReadOnlyState<T>;
27
- /**
28
- * Creates an efficient subscription to a subset of a state value.
29
- */
30
15
  export declare const select: <T, R>(source: ReadOnlyState<T>, selectorFn: (state: T) => R, equalityFn?: (a: R, b: R) => boolean) => ReadOnlyState<R>;
31
- /**
32
- * Creates a read-only view of a state, hiding mutation methods.
33
- */
34
16
  export declare const readonlyState: <T>(state: State<T>) => ReadOnlyState<T>;
35
- /**
36
- * Creates a state with access control, returning a tuple of reader and writer.
37
- */
38
17
  export declare const protectedState: <T>(initialValue: T, equalityFn?: (a: T, b: T) => boolean) => [ReadOnlyState<T>, WriteableState<T>];
39
- /**
40
- * Creates a lens for direct updates to nested properties of a state.
41
- */
42
18
  export declare const lens: <T, K>(source: State<T>, accessor: (state: T) => K) => State<K>;
43
19
  export {};
package/dist/src/index.js CHANGED
@@ -1,32 +1,10 @@
1
- // Special symbol used for internal tracking
2
- const STATE_ID = Symbol();
3
- /**
4
- * Creates a reactive state container with the provided initial value.
5
- */
1
+ const STATE_ID = Symbol('STATE_ID');
6
2
  export const state = (initialValue, equalityFn = Object.is) => StateImpl.createState(initialValue, equalityFn);
7
- /**
8
- * Registers a function to run whenever its reactive dependencies change.
9
- */
10
3
  export const effect = (fn) => StateImpl.createEffect(fn);
11
- /**
12
- * Groups multiple state updates to trigger effects only once at the end.
13
- */
14
4
  export const batch = (fn) => StateImpl.executeBatch(fn);
15
- /**
16
- * Creates a read-only computed value that updates when its dependencies change.
17
- */
18
5
  export const derive = (computeFn) => StateImpl.createDerive(computeFn);
19
- /**
20
- * Creates an efficient subscription to a subset of a state value.
21
- */
22
6
  export const select = (source, selectorFn, equalityFn = Object.is) => StateImpl.createSelect(source, selectorFn, equalityFn);
23
- /**
24
- * Creates a read-only view of a state, hiding mutation methods.
25
- */
26
7
  export const readonlyState = (state) => () => state();
27
- /**
28
- * Creates a state with access control, returning a tuple of reader and writer.
29
- */
30
8
  export const protectedState = (initialValue, equalityFn = Object.is) => {
31
9
  const fullState = state(initialValue, equalityFn);
32
10
  return [
@@ -37,26 +15,18 @@ export const protectedState = (initialValue, equalityFn = Object.is) => {
37
15
  },
38
16
  ];
39
17
  };
40
- /**
41
- * Creates a lens for direct updates to nested properties of a state.
42
- */
43
18
  export const lens = (source, accessor) => StateImpl.createLens(source, accessor);
44
19
  class StateImpl {
45
- // Static fields track global reactivity state - this centralized approach allows
46
- // for coordinated updates while maintaining individual state isolation
47
20
  static currentSubscriber = null;
48
21
  static pendingSubscribers = new Set();
49
22
  static isNotifying = false;
50
23
  static batchDepth = 0;
51
24
  static deferredEffectCreations = [];
52
25
  static activeSubscribers = new Set();
53
- // WeakMaps enable automatic garbage collection when subscribers are no
54
- // longer referenced, preventing memory leaks in long-running applications
55
26
  static stateTracking = new WeakMap();
56
27
  static subscriberDependencies = new WeakMap();
57
28
  static parentSubscriber = new WeakMap();
58
29
  static childSubscribers = new WeakMap();
59
- // Instance state - each state has unique subscribers and ID
60
30
  value;
61
31
  subscribers = new Set();
62
32
  stateId = Symbol();
@@ -65,10 +35,6 @@ class StateImpl {
65
35
  this.value = initialValue;
66
36
  this.equalityFn = equalityFn;
67
37
  }
68
- /**
69
- * Creates a reactive state container with the provided initial value.
70
- * Implementation of the public 'state' function.
71
- */
72
38
  static createState = (initialValue, equalityFn = Object.is) => {
73
39
  const instance = new StateImpl(initialValue, equalityFn);
74
40
  const get = () => instance.get();
@@ -77,23 +43,16 @@ class StateImpl {
77
43
  get[STATE_ID] = instance.stateId;
78
44
  return get;
79
45
  };
80
- // Auto-tracks dependencies when called within effects, creating a fine-grained
81
- // reactivity graph that only updates affected components
82
46
  get = () => {
83
47
  const currentEffect = StateImpl.currentSubscriber;
84
48
  if (currentEffect) {
85
- // Add this effect to subscribers for future notification
86
49
  this.subscribers.add(currentEffect);
87
- // Maintain bidirectional dependency tracking to enable precise cleanup
88
- // when effects are unsubscribed, preventing memory leaks
89
50
  let dependencies = StateImpl.subscriberDependencies.get(currentEffect);
90
51
  if (!dependencies) {
91
52
  dependencies = new Set();
92
53
  StateImpl.subscriberDependencies.set(currentEffect, dependencies);
93
54
  }
94
55
  dependencies.add(this.subscribers);
95
- // Track read states to detect direct cyclical dependencies that
96
- // could cause infinite loops
97
56
  let readStates = StateImpl.stateTracking.get(currentEffect);
98
57
  if (!readStates) {
99
58
  readStates = new Set();
@@ -103,14 +62,10 @@ class StateImpl {
103
62
  }
104
63
  return this.value;
105
64
  };
106
- // Handles value updates with built-in optimizations and safeguards
107
65
  set = (newValue) => {
108
- // Skip updates for unchanged values to prevent redundant effect executions
109
66
  if (this.equalityFn(this.value, newValue)) {
110
67
  return;
111
68
  }
112
- // Infinite loop detection prevents direct self-mutation within effects,
113
- // while allowing nested effect patterns that would otherwise appear cyclical
114
69
  const effect = StateImpl.currentSubscriber;
115
70
  if (effect) {
116
71
  const states = StateImpl.stateTracking.get(effect);
@@ -119,16 +74,12 @@ class StateImpl {
119
74
  }
120
75
  }
121
76
  this.value = newValue;
122
- // Skip updates when there are no subscribers, avoiding unnecessary processing
123
77
  if (this.subscribers.size === 0) {
124
78
  return;
125
79
  }
126
- // Queue notifications instead of executing immediately to support batch operations
127
- // and prevent redundant effect runs
128
80
  for (const sub of this.subscribers) {
129
81
  StateImpl.pendingSubscribers.add(sub);
130
82
  }
131
- // Immediate execution outside of batches, deferred execution inside batches
132
83
  if (StateImpl.batchDepth === 0 && !StateImpl.isNotifying) {
133
84
  StateImpl.notifySubscribers();
134
85
  }
@@ -136,27 +87,17 @@ class StateImpl {
136
87
  update = (fn) => {
137
88
  this.set(fn(this.value));
138
89
  };
139
- /**
140
- * Registers a function to run whenever its reactive dependencies change.
141
- * Implementation of the public 'effect' function.
142
- */
143
90
  static createEffect = (fn) => {
144
91
  const runEffect = () => {
145
- // Prevent re-entrance to avoid cascade updates during effect execution
146
92
  if (StateImpl.activeSubscribers.has(runEffect)) {
147
93
  return;
148
94
  }
149
95
  StateImpl.activeSubscribers.add(runEffect);
150
96
  const parentEffect = StateImpl.currentSubscriber;
151
97
  try {
152
- // Clean existing subscriptions before running to ensure only
153
- // currently accessed states are tracked as dependencies
154
98
  StateImpl.cleanupEffect(runEffect);
155
- // Set current context for automatic dependency tracking
156
99
  StateImpl.currentSubscriber = runEffect;
157
100
  StateImpl.stateTracking.set(runEffect, new Set());
158
- // Track parent-child relationships to handle nested effects correctly
159
- // and enable hierarchical cleanup later
160
101
  if (parentEffect) {
161
102
  StateImpl.parentSubscriber.set(runEffect, parentEffect);
162
103
  let children = StateImpl.childSubscribers.get(parentEffect);
@@ -166,22 +107,17 @@ class StateImpl {
166
107
  }
167
108
  children.add(runEffect);
168
109
  }
169
- // Execute the effect function, which will auto-track dependencies
170
110
  fn();
171
111
  }
172
112
  finally {
173
- // Restore previous context when done
174
113
  StateImpl.currentSubscriber = parentEffect;
175
114
  StateImpl.activeSubscribers.delete(runEffect);
176
115
  }
177
116
  };
178
- // Run immediately unless we're in a batch operation
179
117
  if (StateImpl.batchDepth === 0) {
180
118
  runEffect();
181
119
  }
182
120
  else {
183
- // Still track parent-child relationship even when deferred,
184
- // ensuring proper hierarchical cleanup later
185
121
  if (StateImpl.currentSubscriber) {
186
122
  const parent = StateImpl.currentSubscriber;
187
123
  StateImpl.parentSubscriber.set(runEffect, parent);
@@ -192,17 +128,13 @@ class StateImpl {
192
128
  }
193
129
  children.add(runEffect);
194
130
  }
195
- // Queue for execution when batch completes
196
131
  StateImpl.deferredEffectCreations.push(runEffect);
197
132
  }
198
- // Return cleanup function to properly disconnect from reactivity graph
199
133
  return () => {
200
- // Remove from dependency tracking to stop future notifications
201
134
  StateImpl.cleanupEffect(runEffect);
202
135
  StateImpl.pendingSubscribers.delete(runEffect);
203
136
  StateImpl.activeSubscribers.delete(runEffect);
204
137
  StateImpl.stateTracking.delete(runEffect);
205
- // Clean up parent-child relationship bidirectionally
206
138
  const parent = StateImpl.parentSubscriber.get(runEffect);
207
139
  if (parent) {
208
140
  const siblings = StateImpl.childSubscribers.get(parent);
@@ -211,8 +143,6 @@ class StateImpl {
211
143
  }
212
144
  }
213
145
  StateImpl.parentSubscriber.delete(runEffect);
214
- // Recursively clean up child effects to prevent memory leaks in
215
- // nested effect scenarios
216
146
  const children = StateImpl.childSubscribers.get(runEffect);
217
147
  if (children) {
218
148
  for (const child of children) {
@@ -223,19 +153,12 @@ class StateImpl {
223
153
  }
224
154
  };
225
155
  };
226
- /**
227
- * Groups multiple state updates to trigger effects only once at the end.
228
- * Implementation of the public 'batch' function.
229
- */
230
156
  static executeBatch = (fn) => {
231
- // Increment depth counter to handle nested batches correctly
232
157
  StateImpl.batchDepth++;
233
158
  try {
234
159
  return fn();
235
160
  }
236
161
  catch (error) {
237
- // Clean up on error to prevent stale subscribers from executing
238
- // and potentially causing cascading errors
239
162
  if (StateImpl.batchDepth === 1) {
240
163
  StateImpl.pendingSubscribers.clear();
241
164
  StateImpl.deferredEffectCreations.length = 0;
@@ -244,173 +167,148 @@ class StateImpl {
244
167
  }
245
168
  finally {
246
169
  StateImpl.batchDepth--;
247
- // Only process effects when exiting the outermost batch,
248
- // maintaining proper execution order while avoiding redundant runs
249
170
  if (StateImpl.batchDepth === 0) {
250
- // Process effects created during the batch
251
171
  if (StateImpl.deferredEffectCreations.length > 0) {
252
- const effectsToRun = [...StateImpl.deferredEffectCreations];
172
+ const effectsToRun = [
173
+ ...StateImpl.deferredEffectCreations,
174
+ ];
253
175
  StateImpl.deferredEffectCreations.length = 0;
254
176
  for (const effect of effectsToRun) {
255
177
  effect();
256
178
  }
257
179
  }
258
- // Process state updates that occurred during the batch
259
180
  if (StateImpl.pendingSubscribers.size > 0 && !StateImpl.isNotifying) {
260
181
  StateImpl.notifySubscribers();
261
182
  }
262
183
  }
263
184
  }
264
185
  };
265
- /**
266
- * Creates a read-only computed value that updates when its dependencies change.
267
- * Implementation of the public 'derive' function.
268
- */
269
186
  static createDerive = (computeFn) => {
270
- const valueState = StateImpl.createState(undefined);
271
- let initialized = false;
272
- let cachedValue;
273
- // Internal effect automatically tracks dependencies and updates the derived value
274
- StateImpl.createEffect(() => {
275
- const newValue = computeFn();
276
- // Only update if the value actually changed to preserve referential equality
277
- // and prevent unnecessary downstream updates
278
- if (!(initialized && Object.is(cachedValue, newValue))) {
279
- cachedValue = newValue;
280
- valueState.set(newValue);
187
+ const container = {
188
+ cachedValue: undefined,
189
+ computeFn,
190
+ initialized: false,
191
+ valueState: StateImpl.createState(undefined),
192
+ };
193
+ StateImpl.createEffect(function deriveEffect() {
194
+ const newValue = container.computeFn();
195
+ if (!(container.initialized && Object.is(container.cachedValue, newValue))) {
196
+ container.cachedValue = newValue;
197
+ container.valueState.set(newValue);
281
198
  }
282
- initialized = true;
199
+ container.initialized = true;
283
200
  });
284
- // Return function with lazy initialization - ensures value is available
285
- // even when accessed before its dependencies have had a chance to update
286
- return () => {
287
- if (!initialized) {
288
- cachedValue = computeFn();
289
- initialized = true;
290
- valueState.set(cachedValue);
201
+ return function deriveGetter() {
202
+ if (!container.initialized) {
203
+ container.cachedValue = container.computeFn();
204
+ container.initialized = true;
205
+ container.valueState.set(container.cachedValue);
291
206
  }
292
- return valueState();
207
+ return container.valueState();
293
208
  };
294
209
  };
295
- /**
296
- * Creates an efficient subscription to a subset of a state value.
297
- * Implementation of the public 'select' function.
298
- */
299
210
  static createSelect = (source, selectorFn, equalityFn = Object.is) => {
300
- let lastSourceValue;
301
- let lastSelectedValue;
302
- let initialized = false;
303
- const valueState = StateImpl.createState(undefined);
304
- // Internal effect to track the source and update only when needed
305
- StateImpl.createEffect(() => {
306
- const sourceValue = source();
307
- // Skip computation if source reference hasn't changed
308
- if (initialized && Object.is(lastSourceValue, sourceValue)) {
211
+ const container = {
212
+ equalityFn,
213
+ initialized: false,
214
+ lastSelectedValue: undefined,
215
+ lastSourceValue: undefined,
216
+ selectorFn,
217
+ source,
218
+ valueState: StateImpl.createState(undefined),
219
+ };
220
+ StateImpl.createEffect(function selectEffect() {
221
+ const sourceValue = container.source();
222
+ if (container.initialized && Object.is(container.lastSourceValue, sourceValue)) {
309
223
  return;
310
224
  }
311
- lastSourceValue = sourceValue;
312
- const newSelectedValue = selectorFn(sourceValue);
313
- // Use custom equality function to determine if value semantically changed,
314
- // allowing for deep equality comparisons with complex objects
315
- if (initialized && lastSelectedValue !== undefined && equalityFn(lastSelectedValue, newSelectedValue)) {
225
+ container.lastSourceValue = sourceValue;
226
+ const newSelectedValue = container.selectorFn(sourceValue);
227
+ if (container.initialized &&
228
+ container.lastSelectedValue !== undefined &&
229
+ container.equalityFn(container.lastSelectedValue, newSelectedValue)) {
316
230
  return;
317
231
  }
318
- // Update cache and notify subscribers due the value has changed
319
- lastSelectedValue = newSelectedValue;
320
- valueState.set(newSelectedValue);
321
- initialized = true;
232
+ container.lastSelectedValue = newSelectedValue;
233
+ container.valueState.set(newSelectedValue);
234
+ container.initialized = true;
322
235
  });
323
- // Return function with eager initialization capability
324
- return () => {
325
- if (!initialized) {
326
- lastSourceValue = source();
327
- lastSelectedValue = selectorFn(lastSourceValue);
328
- valueState.set(lastSelectedValue);
329
- initialized = true;
236
+ return function selectGetter() {
237
+ if (!container.initialized) {
238
+ container.lastSourceValue = container.source();
239
+ container.lastSelectedValue = container.selectorFn(container.lastSourceValue);
240
+ container.valueState.set(container.lastSelectedValue);
241
+ container.initialized = true;
330
242
  }
331
- return valueState();
243
+ return container.valueState();
332
244
  };
333
245
  };
334
- /**
335
- * Creates a lens for direct updates to nested properties of a state.
336
- * Implementation of the public 'lens' function.
337
- */
338
246
  static createLens = (source, accessor) => {
339
- // Extract the property path once during lens creation
247
+ const container = {
248
+ accessor,
249
+ isUpdating: false,
250
+ lensState: null,
251
+ originalSet: null,
252
+ path: [],
253
+ source,
254
+ };
340
255
  const extractPath = () => {
341
- const path = [];
256
+ const pathCollector = [];
342
257
  const proxy = new Proxy({}, {
343
258
  get: (_, prop) => {
344
259
  if (typeof prop === 'string' || typeof prop === 'number') {
345
- path.push(prop);
260
+ pathCollector.push(prop);
346
261
  }
347
262
  return proxy;
348
263
  },
349
264
  });
350
265
  try {
351
- accessor(proxy);
266
+ container.accessor(proxy);
352
267
  }
353
268
  catch {
354
- // Ignore errors, we're just collecting the path
355
269
  }
356
- return path;
270
+ return pathCollector;
357
271
  };
358
- // Capture the path once
359
- const path = extractPath();
360
- // Create a state with the initial value from the source
361
- const lensState = StateImpl.createState(accessor(source()));
362
- // Prevent circular updates
363
- let isUpdating = false;
364
- // Set up an effect to sync from source to lens
365
- StateImpl.createEffect(() => {
366
- if (isUpdating) {
272
+ container.path = extractPath();
273
+ container.lensState = StateImpl.createState(container.accessor(container.source()));
274
+ container.originalSet = container.lensState.set;
275
+ StateImpl.createEffect(function lensEffect() {
276
+ if (container.isUpdating) {
367
277
  return;
368
278
  }
369
- isUpdating = true;
279
+ container.isUpdating = true;
370
280
  try {
371
- lensState.set(accessor(source()));
281
+ container.lensState.set(container.accessor(container.source()));
372
282
  }
373
283
  finally {
374
- isUpdating = false;
284
+ container.isUpdating = false;
375
285
  }
376
286
  });
377
- // Override the lens state's set method to update the source
378
- const originalSet = lensState.set;
379
- lensState.set = (value) => {
380
- if (isUpdating) {
287
+ container.lensState.set = function lensSet(value) {
288
+ if (container.isUpdating) {
381
289
  return;
382
290
  }
383
- isUpdating = true;
291
+ container.isUpdating = true;
384
292
  try {
385
- // Update lens state
386
- originalSet(value);
387
- // Update source by modifying the value at path
388
- source.update((current) => setValueAtPath(current, path, value));
293
+ container.originalSet(value);
294
+ container.source.update((current) => setValueAtPath(current, container.path, value));
389
295
  }
390
296
  finally {
391
- isUpdating = false;
297
+ container.isUpdating = false;
392
298
  }
393
299
  };
394
- // Add update method for completeness
395
- lensState.update = (fn) => {
396
- lensState.set(fn(lensState()));
300
+ container.lensState.update = function lensUpdate(fn) {
301
+ container.lensState.set(fn(container.lensState()));
397
302
  };
398
- return lensState;
303
+ return container.lensState;
399
304
  };
400
- // Processes queued subscriber notifications in a controlled, non-reentrant way
401
305
  static notifySubscribers = () => {
402
- // Prevent reentrance to avoid cascading notification loops when
403
- // effects trigger further state changes
404
306
  if (StateImpl.isNotifying) {
405
307
  return;
406
308
  }
407
309
  StateImpl.isNotifying = true;
408
310
  try {
409
- // Process all pending effects in batches for better perf,
410
- // ensuring topological execution order is maintained
411
311
  while (StateImpl.pendingSubscribers.size > 0) {
412
- // Process in snapshot batches to prevent infinite loops
413
- // when effects trigger further state changes
414
312
  const subscribers = Array.from(StateImpl.pendingSubscribers);
415
313
  StateImpl.pendingSubscribers.clear();
416
314
  for (const effect of subscribers) {
@@ -422,11 +320,8 @@ class StateImpl {
422
320
  StateImpl.isNotifying = false;
423
321
  }
424
322
  };
425
- // Removes effect from dependency tracking to prevent memory leaks
426
323
  static cleanupEffect = (effect) => {
427
- // Remove from execution queue to prevent stale updates
428
324
  StateImpl.pendingSubscribers.delete(effect);
429
- // Remove bidirectional dependency references to prevent memory leaks
430
325
  const deps = StateImpl.subscriberDependencies.get(effect);
431
326
  if (deps) {
432
327
  for (const subscribers of deps) {
@@ -437,72 +332,62 @@ class StateImpl {
437
332
  }
438
333
  };
439
334
  }
440
- // Helper for array updates
441
335
  const updateArrayItem = (arr, index, value) => {
442
- const copy = [...arr];
336
+ const copy = [
337
+ ...arr,
338
+ ];
443
339
  copy[index] = value;
444
340
  return copy;
445
341
  };
446
- // Helper for single-level updates (optimization)
447
342
  const updateShallowProperty = (obj, key, value) => {
448
- const result = { ...obj };
343
+ const result = {
344
+ ...obj,
345
+ };
449
346
  result[key] = value;
450
347
  return result;
451
348
  };
452
- // Helper to create the appropriate container type
453
349
  const createContainer = (key) => {
454
350
  const isArrayKey = typeof key === 'number' || !Number.isNaN(Number(key));
455
351
  return isArrayKey ? [] : {};
456
352
  };
457
- // Helper for handling array path updates
458
353
  const updateArrayPath = (array, pathSegments, value) => {
459
354
  const index = Number(pathSegments[0]);
460
355
  if (pathSegments.length === 1) {
461
- // Simple array item update
462
356
  return updateArrayItem(array, index, value);
463
357
  }
464
- // Nested path in array
465
- const copy = [...array];
358
+ const copy = [
359
+ ...array,
360
+ ];
466
361
  const nextPathSegments = pathSegments.slice(1);
467
362
  const nextKey = nextPathSegments[0];
468
- // For null/undefined values in arrays, create appropriate containers
469
363
  let nextValue = array[index];
470
364
  if (nextValue === undefined || nextValue === null) {
471
- // Use empty object as default if nextKey is undefined
472
365
  nextValue = nextKey !== undefined ? createContainer(nextKey) : {};
473
366
  }
474
367
  copy[index] = setValueAtPath(nextValue, nextPathSegments, value);
475
368
  return copy;
476
369
  };
477
- // Helper for handling object path updates
478
370
  const updateObjectPath = (obj, pathSegments, value) => {
479
- // Ensure we have a valid key
480
371
  const currentKey = pathSegments[0];
481
372
  if (currentKey === undefined) {
482
- // This shouldn't happen given our checks in the main function
483
373
  return obj;
484
374
  }
485
375
  if (pathSegments.length === 1) {
486
- // Simple object property update
487
376
  return updateShallowProperty(obj, currentKey, value);
488
377
  }
489
- // Nested path in object
490
378
  const nextPathSegments = pathSegments.slice(1);
491
379
  const nextKey = nextPathSegments[0];
492
- // For null/undefined values, create appropriate containers
493
380
  let currentValue = obj[currentKey];
494
381
  if (currentValue === undefined || currentValue === null) {
495
- // Use empty object as default if nextKey is undefined
496
382
  currentValue = nextKey !== undefined ? createContainer(nextKey) : {};
497
383
  }
498
- // Create new object with updated property
499
- const result = { ...obj };
384
+ const result = {
385
+ ...obj,
386
+ };
500
387
  result[currentKey] = setValueAtPath(currentValue, nextPathSegments, value);
501
388
  return result;
502
389
  };
503
- // Simplified function to update a nested value at a path
504
390
  const setValueAtPath = (obj, pathSegments, value) => {
505
- // Handle base cases
506
391
  if (pathSegments.length === 0) {
507
392
  return value;
508
393
  }
@@ -513,7 +398,6 @@ const setValueAtPath = (obj, pathSegments, value) => {
513
398
  if (currentKey === undefined) {
514
399
  return obj;
515
400
  }
516
- // Delegate to specialized handlers based on data type
517
401
  if (Array.isArray(obj)) {
518
402
  return updateArrayPath(obj, pathSegments, value);
519
403
  }
@@ -0,0 +1 @@
1
+ let i=Symbol("STATE_ID"),a=(e,t=Object.is)=>l.createState(e,t);var e=e=>l.createEffect(e),t=e=>l.executeBatch(e),r=e=>l.createDerive(e),s=(e,t,r=Object.is)=>l.createSelect(e,t,r);let c=e=>()=>e();var n=(e,t=Object.is)=>{let r=a(e,t);return[()=>c(r)(),{set:e=>r.set(e),update:e=>r.update(e)}]},u=(e,t)=>l.createLens(e,t);class l{static currentSubscriber=null;static pendingSubscribers=new Set;static isNotifying=!1;static batchDepth=0;static deferredEffectCreations=[];static activeSubscribers=new Set;static stateTracking=new WeakMap;static subscriberDependencies=new WeakMap;static parentSubscriber=new WeakMap;static childSubscribers=new WeakMap;value;subscribers=new Set;stateId=Symbol();equalityFn;constructor(e,t=Object.is){this.value=e,this.equalityFn=t}static createState=(e,t=Object.is)=>{let r=new l(e,t);e=()=>r.get();return e.set=e=>r.set(e),e.update=e=>r.update(e),e[i]=r.stateId,e};get=()=>{var r=l.currentSubscriber;if(r){this.subscribers.add(r);let e=l.subscriberDependencies.get(r),t=(e||(e=new Set,l.subscriberDependencies.set(r,e)),e.add(this.subscribers),l.stateTracking.get(r));t||(t=new Set,l.stateTracking.set(r,t)),t.add(this.stateId)}return this.value};set=e=>{if(!this.equalityFn(this.value,e)){var t=l.currentSubscriber;if(t)if(l.stateTracking.get(t)?.has(this.stateId)&&!l.parentSubscriber.get(t))throw new Error("Infinite loop detected: effect() cannot update a state() it depends on!");if(this.value=e,0!==this.subscribers.size){for(var r of this.subscribers)l.pendingSubscribers.add(r);0!==l.batchDepth||l.isNotifying||l.notifySubscribers()}}};update=e=>{this.set(e(this.value))};static createEffect=e=>{let r=()=>{if(!l.activeSubscribers.has(r)){l.activeSubscribers.add(r);var t=l.currentSubscriber;try{if(l.cleanupEffect(r),l.currentSubscriber=r,l.stateTracking.set(r,new Set),t){l.parentSubscriber.set(r,t);let e=l.childSubscribers.get(t);e||(e=new Set,l.childSubscribers.set(t,e)),e.add(r)}e()}finally{l.currentSubscriber=t,l.activeSubscribers.delete(r)}}};if(0===l.batchDepth)r();else{if(l.currentSubscriber){var t=l.currentSubscriber;l.parentSubscriber.set(r,t);let e=l.childSubscribers.get(t);e||(e=new Set,l.childSubscribers.set(t,e)),e.add(r)}l.deferredEffectCreations.push(r)}return()=>{l.cleanupEffect(r),l.pendingSubscribers.delete(r),l.activeSubscribers.delete(r),l.stateTracking.delete(r);var e=l.parentSubscriber.get(r),e=(e&&(e=l.childSubscribers.get(e))&&e.delete(r),l.parentSubscriber.delete(r),l.childSubscribers.get(r));if(e){for(var t of e)l.cleanupEffect(t);e.clear(),l.childSubscribers.delete(r)}}};static executeBatch=e=>{l.batchDepth++;try{return e()}catch(e){throw 1===l.batchDepth&&(l.pendingSubscribers.clear(),l.deferredEffectCreations.length=0),e}finally{if(l.batchDepth--,0===l.batchDepth){if(0<l.deferredEffectCreations.length){var t,e=[...l.deferredEffectCreations];l.deferredEffectCreations.length=0;for(t of e)t()}0<l.pendingSubscribers.size&&!l.isNotifying&&l.notifySubscribers()}}};static createDerive=e=>{let t={cachedValue:void 0,computeFn:e,initialized:!1,valueState:l.createState(void 0)};return l.createEffect(function(){var e=t.computeFn();t.initialized&&Object.is(t.cachedValue,e)||(t.cachedValue=e,t.valueState.set(e)),t.initialized=!0}),function(){return t.initialized||(t.cachedValue=t.computeFn(),t.initialized=!0,t.valueState.set(t.cachedValue)),t.valueState()}};static createSelect=(e,t,r=Object.is)=>{let i={equalityFn:r,initialized:!1,lastSelectedValue:void 0,lastSourceValue:void 0,selectorFn:t,source:e,valueState:l.createState(void 0)};return l.createEffect(function(){var e=i.source();i.initialized&&Object.is(i.lastSourceValue,e)||(i.lastSourceValue=e,e=i.selectorFn(e),i.initialized&&void 0!==i.lastSelectedValue&&i.equalityFn(i.lastSelectedValue,e))||(i.lastSelectedValue=e,i.valueState.set(e),i.initialized=!0)}),function(){return i.initialized||(i.lastSourceValue=i.source(),i.lastSelectedValue=i.selectorFn(i.lastSourceValue),i.valueState.set(i.lastSelectedValue),i.initialized=!0),i.valueState()}};static createLens=(e,t)=>{let a={accessor:t,isUpdating:!1,lensState:null,originalSet:null,path:[],source:e};return a.path=(()=>{let r=[],i=new Proxy({},{get:(e,t)=>("string"!=typeof t&&"number"!=typeof t||r.push(t),i)});try{a.accessor(i)}catch{}return r})(),a.lensState=l.createState(a.accessor(a.source())),a.originalSet=a.lensState.set,l.createEffect(function(){if(!a.isUpdating){a.isUpdating=!0;try{a.lensState.set(a.accessor(a.source()))}finally{a.isUpdating=!1}}}),a.lensState.set=function(t){if(!a.isUpdating){a.isUpdating=!0;try{a.originalSet(t),a.source.update(e=>p(e,a.path,t))}finally{a.isUpdating=!1}}},a.lensState.update=function(e){a.lensState.set(e(a.lensState()))},a.lensState};static notifySubscribers=()=>{if(!l.isNotifying){l.isNotifying=!0;try{for(;0<l.pendingSubscribers.size;){var e,t=Array.from(l.pendingSubscribers);l.pendingSubscribers.clear();for(e of t)e()}}finally{l.isNotifying=!1}}};static cleanupEffect=e=>{l.pendingSubscribers.delete(e);var t=l.subscriberDependencies.get(e);if(t){for(var r of t)r.delete(e);t.clear(),l.subscriberDependencies.delete(e)}}}let b=(e,t,r)=>{e=[...e];return e[t]=r,e},d=(e,t,r)=>{e={...e};return e[t]=r,e},f=e=>"number"==typeof e||!Number.isNaN(Number(e))?[]:{},S=(e,t,r)=>{var i=Number(t[0]);if(1===t.length)return b(e,i,r);var a=[...e],t=t.slice(1),s=t[0];let c=e[i];return null==c&&(c=void 0!==s?f(s):{}),a[i]=p(c,t,r),a},o=(e,t,r)=>{var i=t[0];if(void 0===i)return e;if(1===t.length)return d(e,i,r);var t=t.slice(1),a=t[0];let s=e[i];null==s&&(s=void 0!==a?f(a):{});a={...e};return a[i]=p(s,t,r),a},p=(e,t,r)=>0===t.length?r:null==e?p({},t,r):void 0===t[0]?e:(Array.isArray(e)?S:o)(e,t,r);export{a as state,e as effect,t as batch,r as derive,s as select,c as readonlyState,n as protectedState,u as lens};