@but212/atom-effect 0.1.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -8,7 +8,7 @@ const S = {
8
8
  // 0001 - Effect has been disposed
9
9
  EXECUTING: 2
10
10
  // 0010 - Effect is currently executing
11
- }, o = {
11
+ }, u = {
12
12
  DIRTY: 1,
13
13
  // 0001 - Needs recomputation
14
14
  IDLE: 2,
@@ -23,7 +23,7 @@ const S = {
23
23
  // 100000 - Currently recomputing
24
24
  HAS_ERROR: 64
25
25
  // 1000000 - Has error state
26
- }, B = {
26
+ }, j = {
27
27
  /** Maximum number of pooled objects to prevent memory bloat */
28
28
  MAX_SIZE: 1e3,
29
29
  /** Number of objects to pre-allocate for performance-critical paths */
@@ -70,7 +70,7 @@ class b extends a {
70
70
  super(e, t, !1), this.name = "EffectError";
71
71
  }
72
72
  }
73
- class D extends a {
73
+ class g extends a {
74
74
  /**
75
75
  * Creates a new SchedulerError
76
76
  * @param message - Error message
@@ -93,36 +93,130 @@ function E(i, e, t) {
93
93
  function A(i) {
94
94
  return i != null && typeof i.then == "function";
95
95
  }
96
- const u = {
96
+ const o = {
97
+ // ─────────────────────────────────────────────────────────────────
97
98
  // Computed errors
99
+ // ─────────────────────────────────────────────────────────────────
100
+ /**
101
+ * Error thrown when computed() receives a non-function argument.
102
+ */
98
103
  COMPUTED_MUST_BE_FUNCTION: "Computed function must be a function",
104
+ /**
105
+ * Error thrown when subscribe() receives a non-function listener.
106
+ */
99
107
  COMPUTED_SUBSCRIBER_MUST_BE_FUNCTION: "Subscriber listener must be a function",
108
+ /**
109
+ * Error thrown when accessing a pending async computed without a default value.
110
+ */
100
111
  COMPUTED_ASYNC_PENDING_NO_DEFAULT: "Async computation is pending. No default value provided",
112
+ /**
113
+ * Error thrown when a synchronous computed computation fails.
114
+ */
101
115
  COMPUTED_COMPUTATION_FAILED: "Computed computation failed",
116
+ /**
117
+ * Error thrown when an asynchronous computed computation fails.
118
+ */
102
119
  COMPUTED_ASYNC_COMPUTATION_FAILED: "Async computed computation failed",
120
+ /**
121
+ * Error thrown when subscribing to a dependency fails.
122
+ */
103
123
  COMPUTED_DEPENDENCY_SUBSCRIPTION_FAILED: "Failed to subscribe to dependency",
124
+ // ─────────────────────────────────────────────────────────────────
104
125
  // Atom errors
126
+ // ─────────────────────────────────────────────────────────────────
127
+ /**
128
+ * Error thrown when atom.subscribe() receives a non-function listener.
129
+ */
105
130
  ATOM_SUBSCRIBER_MUST_BE_FUNCTION: "Subscription listener must be a function",
131
+ /**
132
+ * Error thrown when the atom subscriber notification process fails.
133
+ */
106
134
  ATOM_SUBSCRIBER_EXECUTION_FAILED: "Error occurred while executing atom subscribers",
135
+ /**
136
+ * Error logged when an individual subscriber throws during notification.
137
+ * @remarks This error is caught and logged to prevent cascading failures.
138
+ */
107
139
  ATOM_INDIVIDUAL_SUBSCRIBER_FAILED: "Error during individual atom subscriber execution",
140
+ // ─────────────────────────────────────────────────────────────────
108
141
  // Effect errors
142
+ // ─────────────────────────────────────────────────────────────────
143
+ /**
144
+ * Error thrown when effect() receives a non-function argument.
145
+ */
109
146
  EFFECT_MUST_BE_FUNCTION: "Effect function must be a function",
147
+ /**
148
+ * Error thrown when an effect's execution fails.
149
+ */
110
150
  EFFECT_EXECUTION_FAILED: "Effect execution failed",
151
+ /**
152
+ * Error thrown when an effect's cleanup function fails.
153
+ */
111
154
  EFFECT_CLEANUP_FAILED: "Effect cleanup function execution failed",
155
+ // ─────────────────────────────────────────────────────────────────
112
156
  // Debug warnings
157
+ // ─────────────────────────────────────────────────────────────────
158
+ /**
159
+ * Warning message for large dependency graphs.
160
+ *
161
+ * @param count - The number of dependencies detected
162
+ * @returns Formatted warning message with dependency count
163
+ *
164
+ * @example
165
+ * ```ts
166
+ * console.warn(ERROR_MESSAGES.LARGE_DEPENDENCY_GRAPH(150));
167
+ * // Output: "Large dependency graph detected: 150 dependencies"
168
+ * ```
169
+ */
113
170
  LARGE_DEPENDENCY_GRAPH: (i) => `Large dependency graph detected: ${i} dependencies`,
171
+ /**
172
+ * Warning logged when attempting to unsubscribe a non-existent listener.
173
+ */
114
174
  UNSUBSCRIBE_NON_EXISTENT: "Attempted to unsubscribe a non-existent listener",
175
+ /**
176
+ * Error logged when the onError callback itself throws an error.
177
+ * @remarks This prevents cascading failures from masking the original error.
178
+ */
115
179
  CALLBACK_ERROR_IN_ERROR_HANDLER: "Error occurred during onError callback execution"
116
180
  };
117
181
  class x {
118
182
  constructor() {
119
183
  this.queue = /* @__PURE__ */ new Set(), this.isProcessing = !1, this.isBatching = !1, this.batchDepth = 0, this.batchQueue = [], this.batchQueueSize = 0, this.isFlushingSync = !1, this.maxFlushIterations = 1e3;
120
184
  }
185
+ /**
186
+ * Schedules a callback for execution.
187
+ *
188
+ * If batching is active or a sync flush is in progress, the callback
189
+ * is added to the batch queue. Otherwise, it's added to the main queue
190
+ * and a flush is triggered via microtask.
191
+ *
192
+ * @param callback - The function to schedule for execution
193
+ * @throws {SchedulerError} If callback is not a function
194
+ *
195
+ * @example
196
+ * ```typescript
197
+ * scheduler.schedule(() => {
198
+ * // This runs in the next microtask (or sync if batching)
199
+ * updateUI();
200
+ * });
201
+ * ```
202
+ */
121
203
  schedule(e) {
122
204
  if (typeof e != "function")
123
- throw new D("Scheduler callback must be a function");
205
+ throw new g("Scheduler callback must be a function");
124
206
  this.isBatching || this.isFlushingSync ? this.batchQueue[this.batchQueueSize++] = e : (this.queue.add(e), this.isProcessing || this.flush());
125
207
  }
208
+ /**
209
+ * Flushes the queue asynchronously via microtask.
210
+ *
211
+ * Executes all queued callbacks in a microtask, allowing the current
212
+ * synchronous execution to complete first. Errors in individual
213
+ * callbacks are caught and logged without interrupting others.
214
+ *
215
+ * @private
216
+ * @remarks
217
+ * This method is idempotent - calling it multiple times while
218
+ * processing is active has no effect.
219
+ */
126
220
  flush() {
127
221
  if (this.isProcessing || this.queue.size === 0) return;
128
222
  this.isProcessing = !0;
@@ -133,12 +227,25 @@ class x {
133
227
  e[t]?.();
134
228
  } catch (s) {
135
229
  console.error(
136
- new D("Error occurred during scheduler execution", s)
230
+ new g("Error occurred during scheduler execution", s)
137
231
  );
138
232
  }
139
233
  this.isProcessing = !1, this.queue.size > 0 && !this.isBatching && this.flush();
140
234
  });
141
235
  }
236
+ /**
237
+ * Flushes all queued callbacks synchronously.
238
+ *
239
+ * This method is called when a batch ends. It processes all callbacks
240
+ * in the batch queue and main queue synchronously, allowing callbacks
241
+ * to schedule additional callbacks that are processed in the same flush.
242
+ *
243
+ * @private
244
+ * @remarks
245
+ * - Includes infinite loop protection via maxFlushIterations
246
+ * - Errors in callbacks are caught and logged individually
247
+ * - The isFlushingSync flag prevents re-entrancy issues
248
+ */
142
249
  flushSync() {
143
250
  this.isFlushingSync = !0;
144
251
  try {
@@ -151,7 +258,7 @@ class x {
151
258
  for (; this.queue.size > 0; ) {
152
259
  if (++e > this.maxFlushIterations) {
153
260
  console.error(
154
- new D(
261
+ new g(
155
262
  `Maximum flush iterations (${this.maxFlushIterations}) exceeded. Possible infinite loop in reactive dependencies. Consider increasing the limit with scheduler.setMaxFlushIterations()`
156
263
  )
157
264
  ), this.queue.clear(), this.batchQueueSize = 0;
@@ -164,7 +271,7 @@ class x {
164
271
  t[s]?.();
165
272
  } catch (r) {
166
273
  console.error(
167
- new D("Error occurred during batch execution", r)
274
+ new g("Error occurred during batch execution", r)
168
275
  );
169
276
  }
170
277
  if (this.batchQueueSize > 0) {
@@ -177,33 +284,91 @@ class x {
177
284
  this.isFlushingSync = !1;
178
285
  }
179
286
  }
287
+ /**
288
+ * Starts a new batch operation.
289
+ *
290
+ * While batching is active, all scheduled callbacks are deferred
291
+ * until endBatch() is called. Batches can be nested - only the
292
+ * outermost endBatch() triggers execution.
293
+ *
294
+ * @example
295
+ * ```typescript
296
+ * scheduler.startBatch();
297
+ * // All updates here are deferred
298
+ * atom1.value = 'a';
299
+ * atom2.value = 'b';
300
+ * scheduler.endBatch(); // Both updates processed together
301
+ * ```
302
+ */
180
303
  startBatch() {
181
304
  this.batchDepth++, this.isBatching = !0;
182
305
  }
306
+ /**
307
+ * Ends a batch operation.
308
+ *
309
+ * Decrements the batch depth counter. When depth reaches zero,
310
+ * all queued callbacks are flushed synchronously and batching
311
+ * is disabled.
312
+ *
313
+ * @remarks
314
+ * Safe to call even if startBatch() wasn't called - depth is
315
+ * clamped to zero minimum.
316
+ *
317
+ * @example
318
+ * ```typescript
319
+ * scheduler.startBatch();
320
+ * try {
321
+ * // ... batched operations
322
+ * } finally {
323
+ * scheduler.endBatch(); // Always end batch, even on error
324
+ * }
325
+ * ```
326
+ */
183
327
  endBatch() {
184
328
  this.batchDepth = Math.max(0, this.batchDepth - 1), this.batchDepth === 0 && (this.flushSync(), this.isBatching = !1);
185
329
  }
330
+ /**
331
+ * Sets the maximum number of flush iterations allowed.
332
+ *
333
+ * This limit prevents infinite loops when reactive dependencies
334
+ * form cycles. If exceeded, the queue is cleared and an error
335
+ * is logged.
336
+ *
337
+ * @param max - Maximum iterations (must be at least 10)
338
+ * @throws {SchedulerError} If max is less than 10
339
+ *
340
+ * @example
341
+ * ```typescript
342
+ * // Increase limit for complex dependency graphs
343
+ * scheduler.setMaxFlushIterations(5000);
344
+ * ```
345
+ */
186
346
  setMaxFlushIterations(e) {
187
347
  if (e < 10)
188
- throw new D("Max flush iterations must be at least 10");
348
+ throw new g("Max flush iterations must be at least 10");
189
349
  this.maxFlushIterations = e;
190
350
  }
191
351
  }
192
- const g = new x();
193
- function j(i) {
352
+ const D = new x();
353
+ function G(i) {
194
354
  if (typeof i != "function")
195
355
  throw new a("Batch callback must be a function");
196
- g.startBatch();
356
+ D.startBatch();
197
357
  try {
198
358
  return i();
199
359
  } catch (e) {
200
360
  throw new a("Error occurred during batch execution", e);
201
361
  } finally {
202
- g.endBatch();
362
+ D.endBatch();
203
363
  }
204
364
  }
205
365
  const p = {
366
+ /** @inheritdoc */
206
367
  current: null,
368
+ /**
369
+ * @inheritdoc
370
+ * @throws Re-throws any error from the executed function after restoring context
371
+ */
207
372
  run(i, e) {
208
373
  const t = this.current;
209
374
  this.current = i;
@@ -213,6 +378,7 @@ const p = {
213
378
  this.current = t;
214
379
  }
215
380
  },
381
+ /** @inheritdoc */
216
382
  getCurrent() {
217
383
  return this.current;
218
384
  }
@@ -221,6 +387,26 @@ class F {
221
387
  constructor() {
222
388
  this.depMap = /* @__PURE__ */ new WeakMap(), this.depRefs = [], this.cleanupThreshold = 100, this.addCount = 0;
223
389
  }
390
+ /**
391
+ * Adds a dependency with its associated unsubscribe callback.
392
+ *
393
+ * If the dependency already exists, the new unsubscribe callback is
394
+ * immediately called to prevent duplicate subscriptions.
395
+ *
396
+ * @param dep - The dependency to track (atom, computed, etc.)
397
+ * @param unsubscribe - Callback to invoke when removing the dependency
398
+ *
399
+ * @remarks
400
+ * - Duplicate dependencies are rejected with immediate unsubscribe
401
+ * - Automatic cleanup is triggered every `cleanupThreshold` additions
402
+ * - Time complexity: O(1) for add, O(n) when cleanup triggers
403
+ *
404
+ * @example
405
+ * ```typescript
406
+ * const unsubscribe = atom.subscribe(() => markDirty());
407
+ * manager.addDependency(atom, unsubscribe);
408
+ * ```
409
+ */
224
410
  addDependency(e, t) {
225
411
  if (this.depMap.has(e)) {
226
412
  t();
@@ -228,6 +414,25 @@ class F {
228
414
  }
229
415
  this.depMap.set(e, t), this.depRefs.push(new WeakRef(e)), ++this.addCount >= this.cleanupThreshold && (this.cleanup(), this.addCount = 0);
230
416
  }
417
+ /**
418
+ * Removes a dependency and calls its unsubscribe callback.
419
+ *
420
+ * @param dep - The dependency to remove
421
+ * @returns `true` if the dependency was found and removed, `false` otherwise
422
+ *
423
+ * @remarks
424
+ * - Unsubscribe errors are caught and logged to prevent cascading failures
425
+ * - The WeakRef entry is not immediately removed (cleaned up lazily)
426
+ * - Time complexity: O(1)
427
+ *
428
+ * @example
429
+ * ```typescript
430
+ * const wasRemoved = manager.removeDependency(atom);
431
+ * if (wasRemoved) {
432
+ * console.log('Dependency successfully removed');
433
+ * }
434
+ * ```
435
+ */
231
436
  removeDependency(e) {
232
437
  const t = this.depMap.get(e);
233
438
  if (t) {
@@ -240,9 +445,42 @@ class F {
240
445
  }
241
446
  return !1;
242
447
  }
448
+ /**
449
+ * Checks if a dependency is currently being tracked.
450
+ *
451
+ * @param dep - The dependency to check
452
+ * @returns `true` if the dependency exists in the manager
453
+ *
454
+ * @remarks
455
+ * Time complexity: O(1)
456
+ *
457
+ * @example
458
+ * ```typescript
459
+ * if (manager.hasDependency(atom)) {
460
+ * // Dependency is already tracked
461
+ * }
462
+ * ```
463
+ */
243
464
  hasDependency(e) {
244
465
  return this.depMap.has(e);
245
466
  }
467
+ /**
468
+ * Removes all dependencies and calls their unsubscribe callbacks.
469
+ *
470
+ * This method iterates through all tracked dependencies, calls their
471
+ * unsubscribe callbacks, and clears internal storage.
472
+ *
473
+ * @remarks
474
+ * - Errors during unsubscribe are caught and logged individually
475
+ * - Safe to call multiple times (idempotent after first call)
476
+ * - Time complexity: O(n) where n is the number of dependencies
477
+ *
478
+ * @example
479
+ * ```typescript
480
+ * // Clean up when disposing a computed value
481
+ * manager.unsubscribeAll();
482
+ * ```
483
+ */
246
484
  unsubscribeAll() {
247
485
  for (let e = 0; e < this.depRefs.length; e++) {
248
486
  const t = this.depRefs[e].deref();
@@ -260,12 +498,59 @@ class F {
260
498
  }
261
499
  this.depRefs.length = 0, this.addCount = 0;
262
500
  }
501
+ /**
502
+ * Removes stale WeakRefs from the internal array.
503
+ *
504
+ * WeakRefs whose targets have been garbage collected are filtered out
505
+ * to prevent unbounded growth of the depRefs array.
506
+ *
507
+ * @remarks
508
+ * - Called automatically every `cleanupThreshold` additions
509
+ * - Can be called manually for immediate cleanup
510
+ * - Time complexity: O(n) where n is the number of WeakRefs
511
+ *
512
+ * @example
513
+ * ```typescript
514
+ * // Force immediate cleanup
515
+ * manager.cleanup();
516
+ * ```
517
+ */
263
518
  cleanup() {
264
519
  this.depRefs = this.depRefs.filter((e) => e.deref() !== void 0);
265
520
  }
521
+ /**
522
+ * Gets the current number of live dependencies.
523
+ *
524
+ * @returns The count of dependencies that haven't been garbage collected
525
+ *
526
+ * @remarks
527
+ * - Triggers cleanup before counting for accurate results
528
+ * - Time complexity: O(n) due to cleanup
529
+ *
530
+ * @example
531
+ * ```typescript
532
+ * console.log(`Tracking ${manager.count} dependencies`);
533
+ * ```
534
+ */
266
535
  get count() {
267
536
  return this.cleanup(), this.depRefs.length;
268
537
  }
538
+ /**
539
+ * Gets an array of all live dependencies.
540
+ *
541
+ * @returns Array of dependencies that haven't been garbage collected
542
+ *
543
+ * @remarks
544
+ * - Returns a new array (safe to modify)
545
+ * - Does not trigger cleanup (may include some stale refs)
546
+ * - Time complexity: O(n)
547
+ *
548
+ * @example
549
+ * ```typescript
550
+ * const deps = manager.getDependencies();
551
+ * deps.forEach(dep => console.log(dep));
552
+ * ```
553
+ */
269
554
  getDependencies() {
270
555
  const e = [];
271
556
  for (let t = 0; t < this.depRefs.length; t++) {
@@ -274,14 +559,49 @@ class F {
274
559
  }
275
560
  return e;
276
561
  }
562
+ /**
563
+ * Gets the internal WeakMap for advanced use cases.
564
+ *
565
+ * @returns The internal dependency -> unsubscribe WeakMap
566
+ *
567
+ * @remarks
568
+ * - Returns the actual internal map (not a copy)
569
+ * - Modifications will affect the manager's state
570
+ * - Use with caution in production code
571
+ *
572
+ * @example
573
+ * ```typescript
574
+ * const map = manager.getDepMap();
575
+ * const unsubscribe = map.get(someDependency);
576
+ * ```
577
+ */
277
578
  getDepMap() {
278
579
  return this.depMap;
279
580
  }
581
+ /**
582
+ * Sets the threshold for automatic cleanup triggering.
583
+ *
584
+ * @param threshold - Number of additions before cleanup (minimum 1)
585
+ *
586
+ * @remarks
587
+ * - Lower values mean more frequent cleanup (less memory, more CPU)
588
+ * - Higher values mean less frequent cleanup (more memory, less CPU)
589
+ * - Default is 100, suitable for most use cases
590
+ *
591
+ * @example
592
+ * ```typescript
593
+ * // More aggressive cleanup for memory-constrained environments
594
+ * manager.setCleanupThreshold(50);
595
+ *
596
+ * // Less frequent cleanup for performance-critical paths
597
+ * manager.setCleanupThreshold(500);
598
+ * ```
599
+ */
280
600
  setCleanupThreshold(e) {
281
601
  this.cleanupThreshold = Math.max(1, e);
282
602
  }
283
603
  }
284
- function G(i) {
604
+ function V(i) {
285
605
  if (typeof i != "function")
286
606
  throw new a("Untracked callback must be a function");
287
607
  const e = p.current;
@@ -294,43 +614,148 @@ function G(i) {
294
614
  p.current = e;
295
615
  }
296
616
  }
297
- const C = /* @__PURE__ */ Symbol("debugName"), P = /* @__PURE__ */ Symbol("id"), R = /* @__PURE__ */ Symbol("type"), T = /* @__PURE__ */ Symbol("noDefaultValue"), h = {
617
+ const C = /* @__PURE__ */ Symbol("debugName"), P = /* @__PURE__ */ Symbol("id"), R = /* @__PURE__ */ Symbol("type"), T = /* @__PURE__ */ Symbol("noDefaultValue");
618
+ function w(i) {
619
+ return i !== null && typeof i == "object" && "dependencies" in i && i.dependencies instanceof Set;
620
+ }
621
+ const h = {
622
+ /**
623
+ * Whether debug mode is enabled.
624
+ *
625
+ * @remarks
626
+ * Automatically set based on `NODE_ENV` environment variable.
627
+ * Only `'development'` enables debug features.
628
+ */
298
629
  enabled: typeof process < "u" && process.env?.NODE_ENV === "development",
630
+ /**
631
+ * Maximum number of dependencies before warning.
632
+ *
633
+ * @see {@link DEBUG_CONFIG.MAX_DEPENDENCIES}
634
+ */
299
635
  maxDependencies: m.MAX_DEPENDENCIES,
636
+ /**
637
+ * Whether to warn about potential infinite loops.
638
+ *
639
+ * @see {@link DEBUG_CONFIG.WARN_INFINITE_LOOP}
640
+ */
300
641
  warnInfiniteLoop: m.WARN_INFINITE_LOOP,
642
+ /**
643
+ * Logs a warning message when condition is true and debug is enabled.
644
+ *
645
+ * @param condition - When true, the warning is logged
646
+ * @param message - The warning message to display
647
+ *
648
+ * @example
649
+ * ```typescript
650
+ * debug.warn(deps.length > 100, 'Large dependency graph detected');
651
+ * ```
652
+ */
301
653
  warn(i, e) {
302
654
  this.enabled && i && console.warn(`[Atom Effect] ${e}`);
303
655
  },
656
+ /**
657
+ * Checks for circular dependencies in the dependency graph.
658
+ *
659
+ * Detects two types of circular references:
660
+ * 1. **Direct**: A depends on itself (A → A)
661
+ * 2. **Indirect**: A depends on B which depends on A (A → B → A)
662
+ *
663
+ * @param dep - The dependency being added
664
+ * @param current - The current reactive object adding the dependency
665
+ * @param visited - Set of already visited nodes (for recursion)
666
+ *
667
+ * @throws {ComputedError} When a circular dependency is detected
668
+ *
669
+ * @remarks
670
+ * - Direct circular detection runs in all environments
671
+ * - Indirect circular detection only runs in development mode
672
+ * - Uses depth-first traversal with O(n) time complexity
673
+ *
674
+ * @example
675
+ * ```typescript
676
+ * // This will throw for direct circular reference
677
+ * debug.checkCircular(computedA, computedA);
678
+ *
679
+ * // This will throw for indirect circular reference (dev only)
680
+ * // Given: A → B → C → A
681
+ * debug.checkCircular(computedC, computedA);
682
+ * ```
683
+ */
304
684
  checkCircular(i, e, t = /* @__PURE__ */ new Set()) {
305
685
  if (i === e)
306
686
  throw new d("Direct circular dependency detected");
307
687
  if (this.enabled) {
308
688
  if (t.has(i))
309
689
  throw new d("Indirect circular dependency detected");
310
- if (t.add(i), i && typeof i == "object" && "dependencies" in i) {
311
- const s = i.dependencies;
312
- for (const r of s)
313
- this.checkCircular(r, e, t);
314
- }
690
+ if (t.add(i), w(i))
691
+ for (const s of i.dependencies)
692
+ this.checkCircular(s, e, t);
315
693
  }
316
694
  },
695
+ /**
696
+ * Attaches debug metadata to a reactive object.
697
+ *
698
+ * @param obj - The object to attach metadata to
699
+ * @param type - The type of reactive object ('atom' | 'computed' | 'effect')
700
+ * @param id - The unique identifier for this object
701
+ *
702
+ * @remarks
703
+ * Only attaches metadata when debug mode is enabled.
704
+ * Uses symbol keys to avoid property name collisions.
705
+ *
706
+ * @example
707
+ * ```typescript
708
+ * const atom = createAtomInternal(0);
709
+ * debug.attachDebugInfo(atom, 'atom', 1);
710
+ * // atom[DEBUG_NAME] === 'atom_1'
711
+ * // atom[DEBUG_ID] === 1
712
+ * // atom[DEBUG_TYPE] === 'atom'
713
+ * ```
714
+ */
317
715
  attachDebugInfo(i, e, t) {
318
- if (!this.enabled) return;
716
+ if (!this.enabled)
717
+ return;
319
718
  const s = i;
320
719
  s[C] = `${e}_${t}`, s[P] = t, s[R] = e;
321
720
  },
721
+ /**
722
+ * Retrieves the debug display name from a reactive object.
723
+ *
724
+ * @param obj - The object to get the name from
725
+ * @returns The debug name (e.g., 'atom_1') or undefined if not set
726
+ *
727
+ * @example
728
+ * ```typescript
729
+ * const name = debug.getDebugName(myAtom);
730
+ * console.log(`Updating ${name ?? 'unknown'}`);
731
+ * ```
732
+ */
322
733
  getDebugName(i) {
323
- if (i && typeof i == "object" && C in i)
734
+ if (i !== null && typeof i == "object" && C in i)
324
735
  return i[C];
325
736
  },
737
+ /**
738
+ * Retrieves the debug type from a reactive object.
739
+ *
740
+ * @param obj - The object to get the type from
741
+ * @returns The type ('atom' | 'computed' | 'effect') or undefined if not set
742
+ *
743
+ * @example
744
+ * ```typescript
745
+ * const type = debug.getDebugType(reactiveObj);
746
+ * if (type === 'computed') {
747
+ * // Handle computed-specific logic
748
+ * }
749
+ * ```
750
+ */
326
751
  getDebugType(i) {
327
- if (i && typeof i == "object" && R in i)
752
+ if (i !== null && typeof i == "object" && R in i)
328
753
  return i[R];
329
754
  }
330
755
  };
331
- let w = 1;
332
- const I = () => w++;
333
- class v {
756
+ let v = 1;
757
+ const I = () => v++;
758
+ class L {
334
759
  /**
335
760
  * Creates a new AtomImpl instance.
336
761
  *
@@ -478,7 +903,7 @@ class v {
478
903
  l && l(e, t);
479
904
  } catch (l) {
480
905
  console.error(
481
- new a(u.ATOM_INDIVIDUAL_SUBSCRIBER_FAILED, l)
906
+ new a(o.ATOM_INDIVIDUAL_SUBSCRIBER_FAILED, l)
482
907
  );
483
908
  }
484
909
  for (let f = 0; f < M; f++)
@@ -487,11 +912,11 @@ class v {
487
912
  l && l.execute();
488
913
  } catch (l) {
489
914
  console.error(
490
- new a(u.ATOM_INDIVIDUAL_SUBSCRIBER_FAILED, l)
915
+ new a(o.ATOM_INDIVIDUAL_SUBSCRIBER_FAILED, l)
491
916
  );
492
917
  }
493
918
  };
494
- this._sync && !g.isBatching ? r() : g.schedule(r);
919
+ this._sync && !D.isBatching ? r() : D.schedule(r);
495
920
  }
496
921
  /**
497
922
  * Subscribes a listener function to value changes.
@@ -510,7 +935,7 @@ class v {
510
935
  */
511
936
  subscribe(e) {
512
937
  if (typeof e != "function")
513
- throw new a(u.ATOM_SUBSCRIBER_MUST_BE_FUNCTION);
938
+ throw new a(o.ATOM_SUBSCRIBER_MUST_BE_FUNCTION);
514
939
  return this._addFnSub(e);
515
940
  }
516
941
  /**
@@ -544,8 +969,8 @@ class v {
544
969
  return this._fnSubCount + this._objSubCount;
545
970
  }
546
971
  }
547
- function V(i, e = {}) {
548
- return new v(i, e.sync ?? !1);
972
+ function X(i, e = {}) {
973
+ return new L(i, e.sync ?? !1);
549
974
  }
550
975
  class N {
551
976
  constructor() {
@@ -686,11 +1111,11 @@ class N {
686
1111
  return this.subscribers ? [...this.subscribers] : [];
687
1112
  }
688
1113
  }
689
- class L {
1114
+ class k {
690
1115
  constructor(e, t = {}) {
691
1116
  if (this._error = null, this._promiseId = 0, this.MAX_PROMISE_ID = Number.MAX_SAFE_INTEGER - 1, typeof e != "function")
692
- throw new d(u.COMPUTED_MUST_BE_FUNCTION);
693
- this._fn = e, this._stateFlags = o.DIRTY | o.IDLE, this._value = void 0;
1117
+ throw new d(o.COMPUTED_MUST_BE_FUNCTION);
1118
+ this._fn = e, this._stateFlags = u.DIRTY | u.IDLE, this._value = void 0;
694
1119
  const {
695
1120
  equal: s = Object.is,
696
1121
  defaultValue: r = T,
@@ -709,14 +1134,14 @@ class L {
709
1134
  }
710
1135
  // === PUBLIC API ===
711
1136
  get value() {
712
- if ((this._stateFlags & (o.RESOLVED | o.DIRTY)) === o.RESOLVED)
1137
+ if ((this._stateFlags & (u.RESOLVED | u.DIRTY)) === u.RESOLVED)
713
1138
  return this._registerTracking(), this._value;
714
1139
  const t = this._computeValue();
715
1140
  return this._registerTracking(), t;
716
1141
  }
717
1142
  subscribe(e) {
718
1143
  if (typeof e != "function")
719
- throw new d(u.COMPUTED_SUBSCRIBER_MUST_BE_FUNCTION);
1144
+ throw new d(o.COMPUTED_SUBSCRIBER_MUST_BE_FUNCTION);
720
1145
  return this._functionSubscribers.add(e);
721
1146
  }
722
1147
  peek() {
@@ -741,47 +1166,47 @@ class L {
741
1166
  this._markDirty();
742
1167
  }
743
1168
  dispose() {
744
- this._dependencyManager.unsubscribeAll(), this._functionSubscribers.clear(), this._objectSubscribers.clear(), this._stateFlags = o.DIRTY | o.IDLE, this._error = null, this._value = void 0, this._promiseId = (this._promiseId + 1) % this.MAX_PROMISE_ID;
1169
+ this._dependencyManager.unsubscribeAll(), this._functionSubscribers.clear(), this._objectSubscribers.clear(), this._stateFlags = u.DIRTY | u.IDLE, this._error = null, this._value = void 0, this._promiseId = (this._promiseId + 1) % this.MAX_PROMISE_ID;
745
1170
  }
746
1171
  // === PRIVATE: State Flag Operations (inlined for performance) ===
747
1172
  _isDirty() {
748
- return (this._stateFlags & o.DIRTY) !== 0;
1173
+ return (this._stateFlags & u.DIRTY) !== 0;
749
1174
  }
750
1175
  _setDirty() {
751
- this._stateFlags |= o.DIRTY;
1176
+ this._stateFlags |= u.DIRTY;
752
1177
  }
753
1178
  _clearDirty() {
754
1179
  this._stateFlags &= -2;
755
1180
  }
756
1181
  _isIdle() {
757
- return (this._stateFlags & o.IDLE) !== 0;
1182
+ return (this._stateFlags & u.IDLE) !== 0;
758
1183
  }
759
1184
  _setIdle() {
760
- this._stateFlags |= o.IDLE, this._stateFlags &= -29;
1185
+ this._stateFlags |= u.IDLE, this._stateFlags &= -29;
761
1186
  }
762
1187
  _isPending() {
763
- return (this._stateFlags & o.PENDING) !== 0;
1188
+ return (this._stateFlags & u.PENDING) !== 0;
764
1189
  }
765
1190
  _setPending() {
766
- this._stateFlags |= o.PENDING, this._stateFlags &= -27;
1191
+ this._stateFlags |= u.PENDING, this._stateFlags &= -27;
767
1192
  }
768
1193
  _isResolved() {
769
- return (this._stateFlags & o.RESOLVED) !== 0;
1194
+ return (this._stateFlags & u.RESOLVED) !== 0;
770
1195
  }
771
1196
  _setResolved() {
772
- this._stateFlags |= o.RESOLVED, this._stateFlags &= -87;
1197
+ this._stateFlags |= u.RESOLVED, this._stateFlags &= -87;
773
1198
  }
774
1199
  _isRejected() {
775
- return (this._stateFlags & o.REJECTED) !== 0;
1200
+ return (this._stateFlags & u.REJECTED) !== 0;
776
1201
  }
777
1202
  _setRejected() {
778
- this._stateFlags |= o.REJECTED | o.HAS_ERROR, this._stateFlags &= -15;
1203
+ this._stateFlags |= u.REJECTED | u.HAS_ERROR, this._stateFlags &= -15;
779
1204
  }
780
1205
  _isRecomputing() {
781
- return (this._stateFlags & o.RECOMPUTING) !== 0;
1206
+ return (this._stateFlags & u.RECOMPUTING) !== 0;
782
1207
  }
783
1208
  _setRecomputing(e) {
784
- e ? this._stateFlags |= o.RECOMPUTING : this._stateFlags &= -33;
1209
+ e ? this._stateFlags |= u.RECOMPUTING : this._stateFlags &= -33;
785
1210
  }
786
1211
  _getAsyncState() {
787
1212
  return this._isPending() ? S.PENDING : this._isResolved() ? S.RESOLVED : this._isRejected() ? S.REJECTED : S.IDLE;
@@ -830,29 +1255,29 @@ class L {
830
1255
  this._value = e, this._clearDirty(), this._setResolved(), this._error = null, this._setRecomputing(!1), t && this._notifySubscribers();
831
1256
  }
832
1257
  _handleAsyncRejection(e) {
833
- const t = E(e, d, u.COMPUTED_ASYNC_COMPUTATION_FAILED);
1258
+ const t = E(e, d, o.COMPUTED_ASYNC_COMPUTATION_FAILED);
834
1259
  if (this._error = t, this._setRejected(), this._clearDirty(), this._setRecomputing(!1), this._onError && typeof this._onError == "function")
835
1260
  try {
836
1261
  this._onError(t);
837
1262
  } catch (s) {
838
- console.error(u.CALLBACK_ERROR_IN_ERROR_HANDLER, s);
1263
+ console.error(o.CALLBACK_ERROR_IN_ERROR_HANDLER, s);
839
1264
  }
840
1265
  this._notifySubscribers();
841
1266
  }
842
1267
  _handleComputationError(e) {
843
- const t = E(e, d, u.COMPUTED_COMPUTATION_FAILED);
1268
+ const t = E(e, d, o.COMPUTED_COMPUTATION_FAILED);
844
1269
  if (this._error = t, this._setRejected(), this._clearDirty(), this._setRecomputing(!1), this._onError && typeof this._onError == "function")
845
1270
  try {
846
1271
  this._onError(t);
847
1272
  } catch (s) {
848
- console.error(u.CALLBACK_ERROR_IN_ERROR_HANDLER, s);
1273
+ console.error(o.CALLBACK_ERROR_IN_ERROR_HANDLER, s);
849
1274
  }
850
1275
  throw t;
851
1276
  }
852
1277
  _handlePending() {
853
1278
  if (this._hasDefaultValue)
854
1279
  return this._defaultValue;
855
- throw new d(u.COMPUTED_ASYNC_PENDING_NO_DEFAULT);
1280
+ throw new d(o.COMPUTED_ASYNC_PENDING_NO_DEFAULT);
856
1281
  }
857
1282
  _handleRejected() {
858
1283
  if (this._error?.recoverable && this._hasDefaultValue)
@@ -892,7 +1317,7 @@ class L {
892
1317
  _addDependency(e) {
893
1318
  h.checkCircular(e, this);
894
1319
  const t = this._dependencyManager.count;
895
- h.warn(t > h.maxDependencies, u.LARGE_DEPENDENCY_GRAPH(t));
1320
+ h.warn(t > h.maxDependencies, o.LARGE_DEPENDENCY_GRAPH(t));
896
1321
  try {
897
1322
  const s = e.subscribe(() => this._markDirty());
898
1323
  this._dependencyManager.addDependency(e, s);
@@ -902,7 +1327,7 @@ class L {
902
1327
  }
903
1328
  // === PRIVATE: Subscriber Management ===
904
1329
  _markDirty() {
905
- this._isRecomputing() || this._isDirty() || (this._setDirty(), this._setIdle(), (this._functionSubscribers.hasSubscribers || this._objectSubscribers.hasSubscribers) && g.schedule(() => {
1330
+ this._isRecomputing() || this._isDirty() || (this._setDirty(), this._setIdle(), (this._functionSubscribers.hasSubscribers || this._objectSubscribers.hasSubscribers) && D.schedule(() => {
906
1331
  if (this._isDirty())
907
1332
  try {
908
1333
  this._recompute();
@@ -911,7 +1336,7 @@ class L {
911
1336
  }));
912
1337
  }
913
1338
  _notifySubscribers() {
914
- !this._functionSubscribers.hasSubscribers && !this._objectSubscribers.hasSubscribers || g.schedule(() => {
1339
+ !this._functionSubscribers.hasSubscribers && !this._objectSubscribers.hasSubscribers || D.schedule(() => {
915
1340
  this._functionSubscribers.forEachSafe(
916
1341
  (e) => e(),
917
1342
  (e) => console.error(e)
@@ -926,13 +1351,13 @@ class L {
926
1351
  e && (typeof e == "function" ? this._functionSubscribers.add(e) : e.addDependency ? e.addDependency(this) : e.execute && this._objectSubscribers.add(e));
927
1352
  }
928
1353
  }
929
- function X(i, e = {}) {
930
- return new L(i, e);
1354
+ function z(i, e = {}) {
1355
+ return new k(i, e);
931
1356
  }
932
1357
  function O(i) {
933
1358
  return i !== null && typeof i == "object" && "value" in i && "subscribe" in i && typeof i.subscribe == "function";
934
1359
  }
935
- function z(i) {
1360
+ function q(i) {
936
1361
  if (h.enabled) {
937
1362
  const e = h.getDebugType(i);
938
1363
  if (e)
@@ -940,14 +1365,39 @@ function z(i) {
940
1365
  }
941
1366
  return O(i) && "invalidate" in i && typeof i.invalidate == "function";
942
1367
  }
943
- function q(i) {
1368
+ function Y(i) {
944
1369
  return i !== null && typeof i == "object" && "dispose" in i && "run" in i && typeof i.dispose == "function" && typeof i.run == "function";
945
1370
  }
946
- class k {
1371
+ class B {
1372
+ /**
1373
+ * Creates a new EffectImpl instance.
1374
+ *
1375
+ * @param fn - The effect function to execute. May return a cleanup function
1376
+ * or a Promise that resolves to a cleanup function.
1377
+ * @param options - Configuration options for the effect
1378
+ * @param options.sync - If true, re-executes synchronously on dependency changes.
1379
+ * Defaults to false (scheduled execution).
1380
+ * @param options.maxExecutionsPerSecond - Maximum executions per second before
1381
+ * infinite loop detection triggers.
1382
+ * Defaults to SCHEDULER_CONFIG.MAX_EXECUTIONS_PER_SECOND.
1383
+ * @param options.trackModifications - If true, tracks and warns about dependencies
1384
+ * that are both read and modified. Defaults to false.
1385
+ *
1386
+ * @example
1387
+ * ```typescript
1388
+ * const impl = new EffectImpl(
1389
+ * () => {
1390
+ * console.log(counter.value);
1391
+ * return () => console.log('cleanup');
1392
+ * },
1393
+ * { sync: true }
1394
+ * );
1395
+ * ```
1396
+ */
947
1397
  constructor(e, t = {}) {
948
1398
  this.run = () => {
949
1399
  if (this.isDisposed)
950
- throw new b(u.EFFECT_MUST_BE_FUNCTION);
1400
+ throw new b(o.EFFECT_MUST_BE_FUNCTION);
951
1401
  this.execute();
952
1402
  }, this.dispose = () => {
953
1403
  this.isDisposed || (this._setDisposed(), this._safeCleanup(), this._depManager.unsubscribeAll(), this._trackedDeps.size > 0 && (this._trackedDeps.forEach((s) => {
@@ -962,11 +1412,11 @@ class k {
962
1412
  }, this.addDependency = (s) => {
963
1413
  try {
964
1414
  const r = s.subscribe(() => {
965
- this._sync ? this.execute() : g.schedule(this.execute);
1415
+ this._sync ? this.execute() : D.schedule(this.execute);
966
1416
  });
967
1417
  this._depManager.addDependency(s, r), this._trackModifications && O(s) && this._trackModificationsForDep(s);
968
1418
  } catch (r) {
969
- throw E(r, b, u.EFFECT_EXECUTION_FAILED);
1419
+ throw E(r, b, o.EFFECT_EXECUTION_FAILED);
970
1420
  }
971
1421
  }, this.execute = () => {
972
1422
  if (this.isDisposed || this.isExecuting) return;
@@ -977,40 +1427,145 @@ class k {
977
1427
  this._checkLoopWarnings(), A(r) ? r.then((c) => {
978
1428
  !this.isDisposed && typeof c == "function" && (this._cleanup = c);
979
1429
  }).catch((c) => {
980
- console.error(E(c, b, u.EFFECT_EXECUTION_FAILED));
1430
+ console.error(E(c, b, o.EFFECT_EXECUTION_FAILED));
981
1431
  }) : this._cleanup = typeof r == "function" ? r : null;
982
1432
  } catch (r) {
983
- console.error(E(r, b, u.EFFECT_EXECUTION_FAILED)), this._cleanup = null;
1433
+ console.error(E(r, b, o.EFFECT_EXECUTION_FAILED)), this._cleanup = null;
984
1434
  } finally {
985
1435
  this._setExecuting(!1);
986
1436
  }
987
1437
  }, this._fn = e, this._sync = t.sync ?? !1, this._maxExecutions = t.maxExecutionsPerSecond ?? U.MAX_EXECUTIONS_PER_SECOND, this._trackModifications = t.trackModifications ?? !1, this._id = I(), this._flags = 0, this._cleanup = null, this._depManager = new F(), this._modifiedDeps = /* @__PURE__ */ new Set(), this._originalDescriptors = /* @__PURE__ */ new WeakMap(), this._trackedDeps = /* @__PURE__ */ new Set(), this._historyCapacity = this._maxExecutions + 5, this._history = new Float64Array(this._historyCapacity), this._historyIdx = 0, this._historyCount = 0, this._executionCount = 0, h.attachDebugInfo(this, "effect", this._id);
988
1438
  }
1439
+ /**
1440
+ * Indicates whether this effect has been disposed.
1441
+ *
1442
+ * @returns `true` if the effect has been disposed, `false` otherwise
1443
+ *
1444
+ * @remarks
1445
+ * A disposed effect will not execute and cannot be reactivated.
1446
+ * Use this property to check if the effect is still active before
1447
+ * performing operations that depend on it.
1448
+ *
1449
+ * @example
1450
+ * ```typescript
1451
+ * const fx = effect(() => console.log(counter.value));
1452
+ * console.log(fx.isDisposed); // false
1453
+ * fx.dispose();
1454
+ * console.log(fx.isDisposed); // true
1455
+ * ```
1456
+ */
989
1457
  get isDisposed() {
990
1458
  return (this._flags & y.DISPOSED) !== 0;
991
1459
  }
1460
+ /**
1461
+ * Returns the total number of times this effect has been executed.
1462
+ *
1463
+ * @returns The cumulative execution count since the effect was created
1464
+ *
1465
+ * @remarks
1466
+ * This counter is useful for debugging, testing, and monitoring
1467
+ * effect behavior. It increments on every execution, regardless
1468
+ * of whether the execution succeeds or fails.
1469
+ *
1470
+ * @example
1471
+ * ```typescript
1472
+ * const fx = effect(() => console.log(counter.value));
1473
+ * console.log(fx.executionCount); // 1 (initial execution)
1474
+ * counter.value = 10;
1475
+ * console.log(fx.executionCount); // 2
1476
+ * ```
1477
+ */
992
1478
  get executionCount() {
993
1479
  return this._executionCount;
994
1480
  }
1481
+ /**
1482
+ * Indicates whether this effect is currently executing.
1483
+ *
1484
+ * @returns `true` if the effect is mid-execution, `false` otherwise
1485
+ *
1486
+ * @remarks
1487
+ * This property is used internally to prevent re-entrant execution
1488
+ * (an effect triggering itself during its own execution). It can
1489
+ * also be useful for debugging to understand the effect's state.
1490
+ *
1491
+ * @example
1492
+ * ```typescript
1493
+ * const fx = effect(() => {
1494
+ * console.log('executing:', fx.isExecuting); // true
1495
+ * });
1496
+ * console.log(fx.isExecuting); // false (after execution completes)
1497
+ * ```
1498
+ */
995
1499
  get isExecuting() {
996
1500
  return (this._flags & y.EXECUTING) !== 0;
997
1501
  }
1502
+ /**
1503
+ * Sets the disposed flag on this effect.
1504
+ *
1505
+ * @remarks
1506
+ * This is a low-level method that only sets the bit flag.
1507
+ * Use the public `dispose()` method for proper cleanup.
1508
+ *
1509
+ * @internal
1510
+ */
998
1511
  _setDisposed() {
999
1512
  this._flags |= y.DISPOSED;
1000
1513
  }
1514
+ /**
1515
+ * Sets or clears the executing flag on this effect.
1516
+ *
1517
+ * @param value - `true` to mark as executing, `false` to clear
1518
+ *
1519
+ * @remarks
1520
+ * Uses bitwise operations for efficient flag manipulation.
1521
+ * This flag prevents re-entrant execution of the effect.
1522
+ *
1523
+ * @internal
1524
+ */
1001
1525
  _setExecuting(e) {
1002
1526
  e ? this._flags |= y.EXECUTING : this._flags &= -3;
1003
1527
  }
1528
+ /**
1529
+ * Safely executes the cleanup function if one exists.
1530
+ *
1531
+ * @remarks
1532
+ * This method:
1533
+ * - Checks if a cleanup function exists and is callable
1534
+ * - Wraps the cleanup call in a try-catch to prevent cleanup errors
1535
+ * from breaking the effect lifecycle
1536
+ * - Logs any cleanup errors to the console
1537
+ * - Clears the cleanup reference after execution
1538
+ *
1539
+ * @internal
1540
+ */
1004
1541
  _safeCleanup() {
1005
1542
  if (this._cleanup && typeof this._cleanup == "function") {
1006
1543
  try {
1007
1544
  this._cleanup();
1008
1545
  } catch (e) {
1009
- console.error(E(e, b, u.EFFECT_CLEANUP_FAILED));
1546
+ console.error(E(e, b, o.EFFECT_CLEANUP_FAILED));
1010
1547
  }
1011
1548
  this._cleanup = null;
1012
1549
  }
1013
1550
  }
1551
+ /**
1552
+ * Records an execution timestamp and checks for infinite loop conditions.
1553
+ *
1554
+ * @param now - The current timestamp in milliseconds (from `Date.now()`)
1555
+ *
1556
+ * @remarks
1557
+ * This method implements a circular buffer to track recent execution
1558
+ * timestamps. If the number of executions within the last second exceeds
1559
+ * `_maxExecutions`, the effect is disposed and an error is thrown (in debug mode)
1560
+ * or logged (in production mode).
1561
+ *
1562
+ * The circular buffer approach provides O(1) insertion and efficient
1563
+ * memory usage for tracking execution history.
1564
+ *
1565
+ * @throws {EffectError} In debug mode, throws when infinite loop is detected
1566
+ *
1567
+ * @internal
1568
+ */
1014
1569
  _recordExecution(e) {
1015
1570
  if (this._maxExecutions <= 0) return;
1016
1571
  const t = e - 1e3;
@@ -1024,6 +1579,21 @@ class k {
1024
1579
  throw n;
1025
1580
  }
1026
1581
  }
1582
+ /**
1583
+ * Sets up modification tracking for a dependency.
1584
+ *
1585
+ * @param dep - The dependency (atom) to track modifications on
1586
+ *
1587
+ * @remarks
1588
+ * This method intercepts the `value` setter on the dependency to detect
1589
+ * when the effect modifies a dependency it also reads. This pattern
1590
+ * (read-after-write within the same effect) often indicates an infinite loop.
1591
+ *
1592
+ * The original property descriptor is preserved and can be restored
1593
+ * when the effect is disposed.
1594
+ *
1595
+ * @internal
1596
+ */
1027
1597
  _trackModificationsForDep(e) {
1028
1598
  const t = Object.getPrototypeOf(e), s = Object.getOwnPropertyDescriptor(t, "value");
1029
1599
  if (s?.set && !this._originalDescriptors.has(e)) {
@@ -1041,6 +1611,19 @@ class k {
1041
1611
  });
1042
1612
  }
1043
1613
  }
1614
+ /**
1615
+ * Checks for and warns about potential infinite loop patterns.
1616
+ *
1617
+ * @remarks
1618
+ * When modification tracking is enabled and debug mode is active,
1619
+ * this method checks if any dependencies were both read and modified
1620
+ * during the effect execution. Such patterns often lead to infinite loops.
1621
+ *
1622
+ * Warnings are only emitted in debug mode to avoid performance overhead
1623
+ * in production.
1624
+ *
1625
+ * @internal
1626
+ */
1044
1627
  _checkLoopWarnings() {
1045
1628
  if (this._trackModifications && h.enabled) {
1046
1629
  const e = this._depManager.getDependencies();
@@ -1054,10 +1637,10 @@ class k {
1054
1637
  }
1055
1638
  }
1056
1639
  }
1057
- function Y(i, e = {}) {
1640
+ function Q(i, e = {}) {
1058
1641
  if (typeof i != "function")
1059
- throw new b(u.EFFECT_MUST_BE_FUNCTION);
1060
- const t = new k(i, e);
1642
+ throw new b(o.EFFECT_MUST_BE_FUNCTION);
1643
+ const t = new B(i, e);
1061
1644
  return t.execute(), t;
1062
1645
  }
1063
1646
  export {
@@ -1067,17 +1650,17 @@ export {
1067
1650
  m as DEBUG_CONFIG,
1068
1651
  h as DEBUG_RUNTIME,
1069
1652
  b as EffectError,
1070
- B as POOL_CONFIG,
1653
+ j as POOL_CONFIG,
1071
1654
  U as SCHEDULER_CONFIG,
1072
- D as SchedulerError,
1073
- V as atom,
1074
- j as batch,
1075
- X as computed,
1076
- Y as effect,
1655
+ g as SchedulerError,
1656
+ X as atom,
1657
+ G as batch,
1658
+ z as computed,
1659
+ Q as effect,
1077
1660
  O as isAtom,
1078
- z as isComputed,
1079
- q as isEffect,
1080
- g as scheduler,
1081
- G as untracked
1661
+ q as isComputed,
1662
+ Y as isEffect,
1663
+ D as scheduler,
1664
+ V as untracked
1082
1665
  };
1083
1666
  //# sourceMappingURL=index.mjs.map