atomirx 0.0.8 → 0.1.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.
Files changed (138) hide show
  1. package/README.md +198 -2234
  2. package/bin/cli.js +90 -0
  3. package/dist/core/derived.d.ts +2 -2
  4. package/dist/core/effect.d.ts +3 -2
  5. package/dist/core/onCreateHook.d.ts +15 -2
  6. package/dist/core/onErrorHook.d.ts +4 -1
  7. package/dist/core/pool.d.ts +78 -0
  8. package/dist/core/pool.test.d.ts +1 -0
  9. package/dist/core/select-boolean.test.d.ts +1 -0
  10. package/dist/core/select-pool.test.d.ts +1 -0
  11. package/dist/core/select.d.ts +278 -86
  12. package/dist/core/types.d.ts +233 -1
  13. package/dist/core/withAbort.d.ts +95 -0
  14. package/dist/core/withReady.d.ts +3 -3
  15. package/dist/devtools/constants.d.ts +41 -0
  16. package/dist/devtools/index.cjs +1 -0
  17. package/dist/devtools/index.d.ts +29 -0
  18. package/dist/devtools/index.js +429 -0
  19. package/dist/devtools/registry.d.ts +98 -0
  20. package/dist/devtools/registry.test.d.ts +1 -0
  21. package/dist/devtools/setup.d.ts +61 -0
  22. package/dist/devtools/types.d.ts +311 -0
  23. package/dist/index-BZEnfIcB.cjs +1 -0
  24. package/dist/index-BbPZhsDl.js +1653 -0
  25. package/dist/index.cjs +1 -1
  26. package/dist/index.d.ts +4 -3
  27. package/dist/index.js +18 -14
  28. package/dist/onDispatchHook-C8yLzr-o.cjs +1 -0
  29. package/dist/onDispatchHook-SKbiIUaJ.js +5 -0
  30. package/dist/onErrorHook-BGGy3tqK.js +38 -0
  31. package/dist/onErrorHook-DHBASmYw.cjs +1 -0
  32. package/dist/react/index.cjs +1 -1
  33. package/dist/react/index.js +191 -151
  34. package/dist/react/onDispatchHook.d.ts +106 -0
  35. package/dist/react/useAction.d.ts +4 -1
  36. package/dist/react-devtools/DevToolsPanel.d.ts +93 -0
  37. package/dist/react-devtools/EntityDetails.d.ts +10 -0
  38. package/dist/react-devtools/EntityList.d.ts +15 -0
  39. package/dist/react-devtools/LogList.d.ts +12 -0
  40. package/dist/react-devtools/hooks.d.ts +50 -0
  41. package/dist/react-devtools/index.cjs +1 -0
  42. package/dist/react-devtools/index.d.ts +31 -0
  43. package/dist/react-devtools/index.js +1589 -0
  44. package/dist/react-devtools/styles.d.ts +148 -0
  45. package/package.json +26 -2
  46. package/skills/atomirx/SKILL.md +456 -0
  47. package/skills/atomirx/references/async-patterns.md +188 -0
  48. package/skills/atomirx/references/atom-patterns.md +238 -0
  49. package/skills/atomirx/references/deferred-loading.md +191 -0
  50. package/skills/atomirx/references/derived-patterns.md +428 -0
  51. package/skills/atomirx/references/effect-patterns.md +426 -0
  52. package/skills/atomirx/references/error-handling.md +140 -0
  53. package/skills/atomirx/references/hooks.md +322 -0
  54. package/skills/atomirx/references/pool-patterns.md +229 -0
  55. package/skills/atomirx/references/react-integration.md +411 -0
  56. package/skills/atomirx/references/rules.md +407 -0
  57. package/skills/atomirx/references/select-context.md +309 -0
  58. package/skills/atomirx/references/service-template.md +172 -0
  59. package/skills/atomirx/references/store-template.md +205 -0
  60. package/skills/atomirx/references/testing-patterns.md +431 -0
  61. package/coverage/base.css +0 -224
  62. package/coverage/block-navigation.js +0 -87
  63. package/coverage/clover.xml +0 -1440
  64. package/coverage/coverage-final.json +0 -14
  65. package/coverage/favicon.png +0 -0
  66. package/coverage/index.html +0 -131
  67. package/coverage/prettify.css +0 -1
  68. package/coverage/prettify.js +0 -2
  69. package/coverage/sort-arrow-sprite.png +0 -0
  70. package/coverage/sorter.js +0 -210
  71. package/coverage/src/core/atom.ts.html +0 -889
  72. package/coverage/src/core/batch.ts.html +0 -223
  73. package/coverage/src/core/define.ts.html +0 -805
  74. package/coverage/src/core/emitter.ts.html +0 -919
  75. package/coverage/src/core/equality.ts.html +0 -631
  76. package/coverage/src/core/hook.ts.html +0 -460
  77. package/coverage/src/core/index.html +0 -281
  78. package/coverage/src/core/isAtom.ts.html +0 -100
  79. package/coverage/src/core/isPromiseLike.ts.html +0 -133
  80. package/coverage/src/core/onCreateHook.ts.html +0 -138
  81. package/coverage/src/core/scheduleNotifyHook.ts.html +0 -94
  82. package/coverage/src/core/types.ts.html +0 -523
  83. package/coverage/src/core/withUse.ts.html +0 -253
  84. package/coverage/src/index.html +0 -116
  85. package/coverage/src/index.ts.html +0 -106
  86. package/dist/index-CBVj1kSj.js +0 -1350
  87. package/dist/index-Cxk9v0um.cjs +0 -1
  88. package/scripts/publish.js +0 -198
  89. package/src/core/atom.test.ts +0 -633
  90. package/src/core/atom.ts +0 -311
  91. package/src/core/atomState.test.ts +0 -342
  92. package/src/core/atomState.ts +0 -256
  93. package/src/core/batch.test.ts +0 -257
  94. package/src/core/batch.ts +0 -172
  95. package/src/core/define.test.ts +0 -343
  96. package/src/core/define.ts +0 -243
  97. package/src/core/derived.test.ts +0 -1215
  98. package/src/core/derived.ts +0 -450
  99. package/src/core/effect.test.ts +0 -802
  100. package/src/core/effect.ts +0 -188
  101. package/src/core/emitter.test.ts +0 -364
  102. package/src/core/emitter.ts +0 -392
  103. package/src/core/equality.test.ts +0 -392
  104. package/src/core/equality.ts +0 -182
  105. package/src/core/getAtomState.ts +0 -69
  106. package/src/core/hook.test.ts +0 -227
  107. package/src/core/hook.ts +0 -177
  108. package/src/core/isAtom.ts +0 -27
  109. package/src/core/isPromiseLike.test.ts +0 -72
  110. package/src/core/isPromiseLike.ts +0 -16
  111. package/src/core/onCreateHook.ts +0 -107
  112. package/src/core/onErrorHook.test.ts +0 -350
  113. package/src/core/onErrorHook.ts +0 -52
  114. package/src/core/promiseCache.test.ts +0 -241
  115. package/src/core/promiseCache.ts +0 -284
  116. package/src/core/scheduleNotifyHook.ts +0 -53
  117. package/src/core/select.ts +0 -729
  118. package/src/core/selector.test.ts +0 -799
  119. package/src/core/types.ts +0 -389
  120. package/src/core/withReady.test.ts +0 -534
  121. package/src/core/withReady.ts +0 -191
  122. package/src/core/withUse.test.ts +0 -249
  123. package/src/core/withUse.ts +0 -56
  124. package/src/index.test.ts +0 -80
  125. package/src/index.ts +0 -65
  126. package/src/react/index.ts +0 -21
  127. package/src/react/rx.test.tsx +0 -571
  128. package/src/react/rx.tsx +0 -531
  129. package/src/react/strictModeTest.tsx +0 -71
  130. package/src/react/useAction.test.ts +0 -987
  131. package/src/react/useAction.ts +0 -607
  132. package/src/react/useSelector.test.ts +0 -182
  133. package/src/react/useSelector.ts +0 -292
  134. package/src/react/useStable.test.ts +0 -553
  135. package/src/react/useStable.ts +0 -288
  136. package/tsconfig.json +0 -9
  137. package/v2.md +0 -725
  138. package/vite.config.ts +0 -42
@@ -12,6 +12,14 @@ export declare const SYMBOL_ATOM: unique symbol;
12
12
  * Symbol to identify derived atoms.
13
13
  */
14
14
  export declare const SYMBOL_DERIVED: unique symbol;
15
+ /**
16
+ * Symbol to identify scoped atoms (temporary wrappers for pool atoms).
17
+ */
18
+ export declare const SYMBOL_SCOPED: unique symbol;
19
+ /**
20
+ * Symbol to identify pool instances.
21
+ */
22
+ export declare const SYMBOL_POOL: unique symbol;
15
23
  /**
16
24
  * Interface for objects that support the `.use()` plugin pattern.
17
25
  *
@@ -33,6 +41,7 @@ export interface Pipeable {
33
41
  use<TNew = void>(plugin: (source: this) => TNew): void extends TNew ? this : TNew extends object ? TNew extends {
34
42
  use: any;
35
43
  } ? TNew : Pipeable & TNew : TNew;
44
+ use<TPlugin extends object>(plugin: TPlugin): TPlugin extends any[] ? this : this & TPlugin;
36
45
  }
37
46
  /**
38
47
  * Optional metadata for atoms.
@@ -113,6 +122,11 @@ export interface MutableAtom<T> extends Atom<T>, Pipeable {
113
122
  * ```
114
123
  */
115
124
  dirty(): boolean;
125
+ /**
126
+ * Dispose the atom, aborting any pending operations and running cleanup functions.
127
+ * @internal - Used by pool when removing entries.
128
+ */
129
+ _dispose(): void;
116
130
  }
117
131
  /**
118
132
  * A derived (computed) atom that always returns Promise<T> for its value.
@@ -154,6 +168,11 @@ export interface DerivedAtom<T, F extends boolean = false> extends Atom<Promise<
154
168
  * - With fallback: T (guaranteed)
155
169
  */
156
170
  readonly staleValue: F extends true ? T : T | undefined;
171
+ /**
172
+ * Dispose the derived atom, cleaning up all subscriptions.
173
+ * @internal - Reserved for future use.
174
+ */
175
+ _dispose(): void;
157
176
  }
158
177
  /**
159
178
  * Union type for any atom (mutable or derived).
@@ -319,9 +338,9 @@ export interface EffectOptions {
319
338
  onError?: (error: unknown) => void;
320
339
  }
321
340
  export interface AtomirxMeta {
341
+ key?: string;
322
342
  }
323
343
  export interface EffectMeta extends AtomirxMeta {
324
- key?: string;
325
344
  }
326
345
  /**
327
346
  * A function that returns a value when called.
@@ -362,3 +381,216 @@ export interface ModuleMeta {
362
381
  }
363
382
  export type Listener<T> = (value: T) => void;
364
383
  export type SingleOrMultipleListeners<T> = Listener<T> | Listener<T>[];
384
+ /**
385
+ * Event emitted by pool's `on()` method.
386
+ *
387
+ * @template P - The type of params used to index entries
388
+ * @template T - The type of value stored in each entry
389
+ */
390
+ export type PoolEvent<P, T> = {
391
+ type: "create";
392
+ params: P;
393
+ value: T;
394
+ } | {
395
+ type: "change";
396
+ params: P;
397
+ value: T;
398
+ } | {
399
+ type: "remove";
400
+ params: P;
401
+ value: T;
402
+ };
403
+ /**
404
+ * A scoped atom is a temporary wrapper around a real atom from a pool.
405
+ * It is only valid during a select() context and throws if accessed outside.
406
+ *
407
+ * ScopedAtoms prevent memory leaks by ensuring pool atom references
408
+ * cannot be stored and used after the computation completes.
409
+ *
410
+ * @template T - The type of value stored in the underlying atom
411
+ */
412
+ export interface ScopedAtom<T> extends Atom<T> {
413
+ /** Symbol marker to identify scoped atom instances */
414
+ readonly [SYMBOL_SCOPED]: true;
415
+ /**
416
+ * Get the underlying real atom.
417
+ * @internal
418
+ * @throws Error if called outside select() context
419
+ */
420
+ _getAtom(): Atom<T>;
421
+ /**
422
+ * Mark this scoped atom as disposed.
423
+ * After disposal, any method call will throw.
424
+ * @internal
425
+ */
426
+ _dispose(): void;
427
+ }
428
+ /**
429
+ * Configuration options for creating a pool.
430
+ *
431
+ * @template P - The type of params used to index pool entries (must be object)
432
+ */
433
+ export interface PoolOptions<P> {
434
+ /**
435
+ * Time in milliseconds before an unused entry is garbage collected.
436
+ * The GC timer resets on:
437
+ * - Entry creation
438
+ * - Value change
439
+ * - Access (get/set)
440
+ *
441
+ * GC is paused while the entry's value is a pending Promise.
442
+ */
443
+ gcTime: number;
444
+ /**
445
+ * Equality strategy for params comparison (default: "shallow").
446
+ * Used to determine if two params objects refer to the same cache entry.
447
+ *
448
+ * With default "shallow" equality:
449
+ * - `{ a: 1, b: 2 }` and `{ b: 2, a: 1 }` are considered equal (same entry)
450
+ * - Property order doesn't matter
451
+ *
452
+ * @example
453
+ * ```ts
454
+ * // Default shallow equality
455
+ * const userPool = pool((params: { id: string }) => fetchUser(params.id), {
456
+ * gcTime: 60_000,
457
+ * });
458
+ * userPool.get({ id: "1" });
459
+ * userPool.get({ id: "1" }); // Same entry (shallow equal)
460
+ *
461
+ * // Custom equality
462
+ * const pool = pool((params: { a: number; b: number }) => params.a + params.b, {
463
+ * gcTime: 60_000,
464
+ * equals: (a, b) => a.a === b.a && a.b === b.b,
465
+ * });
466
+ * ```
467
+ */
468
+ equals?: Equality<P>;
469
+ /**
470
+ * Optional metadata for the pool.
471
+ */
472
+ meta?: PoolMeta;
473
+ }
474
+ /**
475
+ * Metadata for pool instances.
476
+ */
477
+ export interface PoolMeta extends AtomirxMeta {
478
+ key?: string;
479
+ }
480
+ /**
481
+ * A pool is a collection of atoms indexed by params.
482
+ * Similar to atomFamily in Jotai/Recoil, but with automatic GC
483
+ * and ScopedAtom pattern to prevent memory leaks.
484
+ *
485
+ * @template P - The type of params used to index entries
486
+ * @template T - The type of value stored in each entry
487
+ *
488
+ * @example
489
+ * ```ts
490
+ * // Create a pool
491
+ * const userPool = pool(
492
+ * (id: string) => fetchUser(id),
493
+ * { gcTime: 60_000 }
494
+ * );
495
+ *
496
+ * // Public API (value-based)
497
+ * userPool.get("user-1"); // T | undefined
498
+ * userPool.set("user-1", newUser);
499
+ * userPool.remove("user-1");
500
+ *
501
+ * // In reactive context
502
+ * derived(({ read, from }) => {
503
+ * const user$ = from(userPool, "user-1");
504
+ * return read(user$);
505
+ * });
506
+ * ```
507
+ */
508
+ export interface Pool<P, T> {
509
+ /** Symbol marker to identify pool instances */
510
+ readonly [SYMBOL_POOL]: true;
511
+ /** Optional metadata for the pool */
512
+ readonly meta?: PoolMeta;
513
+ /**
514
+ * Get the current value for params.
515
+ * Creates entry if it doesn't exist.
516
+ * Extends GC timer on access.
517
+ *
518
+ * @param params - The params to look up
519
+ * @returns The current value
520
+ */
521
+ get(params: P): T;
522
+ /**
523
+ * Set the value for params.
524
+ * Creates entry if it doesn't exist.
525
+ * Extends GC timer on access.
526
+ *
527
+ * @param params - The params to set
528
+ * @param value - The new value or reducer function
529
+ */
530
+ set(params: P, value: T | ((prev: T) => T)): void;
531
+ /**
532
+ * Check if an entry exists for params.
533
+ *
534
+ * @param params - The params to check
535
+ * @returns true if entry exists
536
+ */
537
+ has(params: P): boolean;
538
+ /**
539
+ * Remove an entry from the pool.
540
+ * Triggers onRemove listeners.
541
+ *
542
+ * @param params - The params to remove
543
+ */
544
+ remove(params: P): void;
545
+ /**
546
+ * Remove all entries from the pool.
547
+ * Triggers onRemove listeners for each entry.
548
+ */
549
+ clear(): void;
550
+ size(): number;
551
+ /**
552
+ * Iterate over all entries in the pool.
553
+ *
554
+ * @param callback - Called for each entry with (value, params)
555
+ */
556
+ forEach(callback: (value: T, params: P) => void): void;
557
+ /**
558
+ * Subscribe to pool events.
559
+ *
560
+ * Event types:
561
+ * - `create` - New entry created
562
+ * - `change` - Existing entry value changed
563
+ * - `remove` - Entry removed (manual or GC)
564
+ *
565
+ * @param listener - Called with event object containing type, params, and value
566
+ * @returns Unsubscribe function
567
+ *
568
+ * @example
569
+ * ```ts
570
+ * const unsub = userPool.on((event) => {
571
+ * switch (event.type) {
572
+ * case "create":
573
+ * console.log("Created:", event.params, event.value);
574
+ * break;
575
+ * case "change":
576
+ * console.log("Changed:", event.params, event.value);
577
+ * break;
578
+ * case "remove":
579
+ * console.log("Removed:", event.params, event.value);
580
+ * break;
581
+ * }
582
+ * });
583
+ * ```
584
+ */
585
+ on(listener: (event: PoolEvent<P, T>) => void): VoidFunction;
586
+ /**
587
+ * Get the underlying atom for params.
588
+ * @internal - Use `from(pool, params)` in SelectContext instead.
589
+ */
590
+ _getAtom(params: P): MutableAtom<T>;
591
+ /**
592
+ * Subscribe to removal of a specific entry.
593
+ * @internal - Used by SelectContext for automatic recomputation.
594
+ */
595
+ _onRemove(params: P, listener: VoidFunction): VoidFunction;
596
+ }
@@ -0,0 +1,95 @@
1
+ import { SelectContext } from './select';
2
+ /**
3
+ * Extended context providing abort capabilities.
4
+ *
5
+ * Added to the select context when using `withAbort()` extension.
6
+ */
7
+ export interface WithAbortContext {
8
+ /**
9
+ * AbortSignal that is automatically aborted when the effect/derived
10
+ * re-runs or is disposed. Use this to cancel async operations.
11
+ *
12
+ * @example
13
+ * ```ts
14
+ * effect(({ read, onCleanup }) => {
15
+ * const ctx = context.use(withAbort(onCleanup));
16
+ * fetch('/api/data', { signal: ctx.signal });
17
+ * });
18
+ * ```
19
+ */
20
+ readonly signal: AbortSignal;
21
+ /**
22
+ * Manually trigger abort. Safe to call multiple times - subsequent
23
+ * calls after the first abort are no-ops.
24
+ *
25
+ * @example
26
+ * ```ts
27
+ * effect(({ read, onCleanup }) => {
28
+ * const ctx = context.use(withAbort(onCleanup));
29
+ * if (shouldCancel) ctx.abort();
30
+ * });
31
+ * ```
32
+ */
33
+ abort(): void;
34
+ }
35
+ /**
36
+ * Context extension that provides an AbortSignal for cancellation.
37
+ *
38
+ * Use this to cancel async operations (fetch, timers, etc.) when an
39
+ * effect or derived atom re-runs or is disposed. The signal is
40
+ * automatically aborted when the cleanup function runs.
41
+ *
42
+ * ## Usage Pattern
43
+ *
44
+ * The `withAbort` function takes an `onCleanup` registration function
45
+ * and returns a context extender that can be used with `.use()`:
46
+ *
47
+ * ```ts
48
+ * effect(({ read, onCleanup }) => {
49
+ * const ctx = context.use(withAbort(onCleanup));
50
+ *
51
+ * // Signal is aborted when effect re-runs or disposes
52
+ * fetch('/api/data', { signal: ctx.signal })
53
+ * .then(r => r.json())
54
+ * .then(data => results$.set(data));
55
+ * });
56
+ * ```
57
+ *
58
+ * ## Key Features
59
+ *
60
+ * - **Automatic cleanup**: Signal aborts when `onCleanup` fires
61
+ * - **Manual abort**: Call `ctx.abort()` to cancel immediately
62
+ * - **Safe re-abort**: Multiple `abort()` calls are no-ops
63
+ *
64
+ * @param onCleanup - Cleanup registration function (from effect context)
65
+ * @returns Context extender function for use with `.use()`
66
+ *
67
+ * @example Basic fetch cancellation
68
+ * ```ts
69
+ * effect(({ read, onCleanup }) => {
70
+ * const userId = read(userId$);
71
+ * const ctx = context.use(withAbort(onCleanup));
72
+ *
73
+ * fetch(`/api/users/${userId}`, { signal: ctx.signal })
74
+ * .then(r => r.json())
75
+ * .then(user => user$.set(user))
76
+ * .catch(err => {
77
+ * if (err.name !== 'AbortError') throw err;
78
+ * });
79
+ * });
80
+ * ```
81
+ *
82
+ * @example With timeout
83
+ * ```ts
84
+ * effect(({ read, onCleanup }) => {
85
+ * const ctx = context.use(withAbort(onCleanup));
86
+ *
87
+ * // Abort after 5 seconds
88
+ * const timeout = setTimeout(() => ctx.abort(), 5000);
89
+ * onCleanup(() => clearTimeout(timeout));
90
+ *
91
+ * fetch('/api/slow', { signal: ctx.signal });
92
+ * });
93
+ * ```
94
+ */
95
+ export declare function withAbort(onCleanup: (cleanup: VoidFunction) => void): <TContext extends SelectContext>(context: TContext) => TContext & WithAbortContext;
@@ -4,7 +4,7 @@ import { Atom } from './types';
4
4
  * Extension interface that adds `ready()` method to SelectContext.
5
5
  * Used in derived atoms and effects to wait for non-null values.
6
6
  */
7
- export interface WithReadySelectContext {
7
+ export interface WithReadyContext {
8
8
  /**
9
9
  * Wait for an atom to have a non-null/non-undefined value.
10
10
  *
@@ -109,7 +109,7 @@ export interface WithReadySelectContext {
109
109
  * @example
110
110
  * ```ts
111
111
  * // Used internally by derived() - you don't need to call this directly
112
- * const result = select((context) => fn(context.use(withReady())));
112
+ * const { result } = select((context) => fn(context.use(withReady())));
113
113
  * ```
114
114
  */
115
- export declare function withReady(): <TContext extends SelectContext>(context: TContext) => TContext & WithReadySelectContext;
115
+ export declare function withReady(): <TContext extends SelectContext>(context: TContext) => TContext & WithReadyContext;
@@ -0,0 +1,41 @@
1
+ /**
2
+ * LocalStorage key for devtools preferences.
3
+ * Global across all domains.
4
+ */
5
+ export declare const STORAGE_KEY_PREFERENCES = "atomirx-devtools-preferences";
6
+ /**
7
+ * Maximum history entries per entity.
8
+ */
9
+ export declare const DEFAULT_MAX_HISTORY_SIZE = 50;
10
+ /**
11
+ * Prefix for generating entity IDs.
12
+ */
13
+ export declare const ENTITY_ID_PREFIX = "atomirx";
14
+ /**
15
+ * Version for storage schema (for future migrations).
16
+ */
17
+ export declare const STORAGE_VERSION = 1;
18
+ /**
19
+ * Z-index for devtools panel.
20
+ */
21
+ export declare const DEVTOOLS_Z_INDEX = 999999;
22
+ /**
23
+ * Minimum panel size in pixels.
24
+ */
25
+ export declare const MIN_PANEL_SIZE = 200;
26
+ /**
27
+ * Maximum panel size in pixels.
28
+ */
29
+ export declare const MAX_PANEL_SIZE = 800;
30
+ /**
31
+ * Default panel size in pixels.
32
+ */
33
+ export declare const DEFAULT_PANEL_SIZE = 300;
34
+ /**
35
+ * Floating button size in pixels.
36
+ */
37
+ export declare const FLOATING_BUTTON_SIZE = 48;
38
+ /**
39
+ * Animation duration in milliseconds.
40
+ */
41
+ export declare const ANIMATION_DURATION = 200;
@@ -0,0 +1 @@
1
+ "use strict";var D=Object.defineProperty;var L=(r,t,o)=>t in r?D(r,t,{enumerable:!0,configurable:!0,writable:!0,value:o}):r[t]=o;var a=(r,t,o)=>L(r,typeof t!="symbol"?t+"":t,o);Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const y=require("../onErrorHook-DHBASmYw.cjs"),m=require("../onDispatchHook-C8yLzr-o.cjs");var g=typeof document<"u"?document.currentScript:null;const R="atomirx-devtools-preferences",E=50,S="atomirx",A=1,k=999999,I=200,b=800,C=300,w=48,T=200;let N=0;function f(r){return`${S}-${r}-${++N}`}class P{constructor(t=E){a(this,"_entities",new Map);a(this,"_logs",[]);a(this,"_listeners",new Set);a(this,"_maxHistorySize");a(this,"_maxLogSize",200);a(this,"_logIdCounter",0);a(this,"_version",0);a(this,"_cachedEntities",null);a(this,"_cachedLogs",null);a(this,"_notifyScheduled",!1);this._maxHistorySize=t}get entities(){return this._cachedEntities||(this._cachedEntities=new Map(this._entities)),this._cachedEntities}get logs(){return this._cachedLogs||(this._cachedLogs=[...this._logs]),this._cachedLogs}get version(){return this._version}addLog(t){const o={...t,id:`log-${++this._logIdCounter}`};this._logs=[o,...this._logs].slice(0,this._maxLogSize),this._notifyListeners()}clearLogs(){this._logs=[],this._notifyListeners()}registerMutable(t,o){const n=f("mutable"),e=Date.now(),s={id:n,type:"mutable",key:o,createdAt:e,lastUpdatedAt:e,changeCount:0,instanceRef:new WeakRef(t),subscriberCount:0,history:[]};return this._entities.set(n,s),this._notifyListeners(),this._trackMutableChanges(n,t),n}registerDerived(t,o,n=[]){const e=f("derived"),s=Date.now(),i={id:e,type:"derived",key:o,createdAt:s,lastUpdatedAt:s,changeCount:0,instanceRef:new WeakRef(t),dependencyIds:n,subscriberCount:0,history:[]};return this._entities.set(e,i),this._notifyListeners(),this._trackDerivedChanges(e,t),e}registerEffect(t,o,n=[]){const e=f("effect"),s=Date.now(),i={id:e,type:"effect",key:o,createdAt:s,lastUpdatedAt:s,changeCount:0,instanceRef:new WeakRef(t),dependencyIds:n,runCount:0,isActive:!0};return this._entities.set(e,i),this._notifyListeners(),e}registerPool(t,o,n){const e=f("pool"),s=Date.now(),i={id:e,type:"pool",key:o,createdAt:s,lastUpdatedAt:s,changeCount:0,instanceRef:new WeakRef(t),entryCount:0,gcTime:n};return this._entities.set(e,i),this._notifyListeners(),this._trackPoolChanges(e,t),e}registerModule(t,o){const n=f("module"),e=Date.now(),s={id:n,type:"module",key:o,createdAt:e,lastUpdatedAt:e,changeCount:0,instanceRef:new WeakRef(t)};return this._entities.set(n,s),this._notifyListeners(),n}_trackMutableChanges(t,o){let n=this._serializeValue(o.get());o.on(()=>{var h;const e=this._entities.get(t);if(!e)return;const s=this._serializeValue(o.get()),i=Date.now(),_={timestamp:i,previousValue:n,newValue:s};e.history=[_,...e.history].slice(0,this._maxHistorySize),e.changeCount++,e.lastUpdatedAt=i,n=s,this._notifyListeners();const u=(h=o.meta)==null?void 0:h.key;u&&this.addLog({type:"mutable.change",timestamp:i,atomKey:u})})}_trackDerivedChanges(t,o){let n=this._serializeValue(o.staleValue);o.on(()=>{var h;const e=this._entities.get(t);if(!e)return;const s=this._serializeValue(o.staleValue),i=Date.now(),_={timestamp:i,previousValue:n,newValue:s};e.history=[_,...e.history].slice(0,this._maxHistorySize),e.changeCount++,e.lastUpdatedAt=i,n=s,this._notifyListeners();const u=(h=o.meta)==null?void 0:h.key;u&&this.addLog({type:"derived.change",timestamp:i,atomKey:u})})}_trackPoolChanges(t,o){o.on(n=>{var i;const e=this._entities.get(t);if(!e)return;(n.type==="create"||n.type==="change")&&(e.changeCount++,e.lastUpdatedAt=Date.now()),this._updatePoolEntryCount(t,o),this._notifyListeners();const s=(i=o.meta)==null?void 0:i.key;if(s){const _={create:"pool.create",change:"pool.set",remove:"pool.remove"},u=this._serializeParams(n.params);this.addLog({type:_[n.type],timestamp:Date.now(),poolKey:s,params:u.slice(0,50)})}})}_serializeParams(t){try{return JSON.stringify(t)}catch{return String(t)}}_updatePoolEntryCount(t,o){const n=this._entities.get(t);n&&(n.entryCount=o.size())}_serializeValue(t){if(t===void 0)return"undefined";if(t===null)return"null";try{const o=new WeakSet;return JSON.stringify(t,(n,e)=>{if(typeof e=="object"&&e!==null){if(o.has(e))return"[Circular]";o.add(e)}return typeof e=="function"?"[Function]":typeof e=="symbol"?e.toString():e instanceof Error?`[Error: ${e.message}]`:e instanceof Promise?"[Promise]":e},2)}catch{return"[unserializable]"}}getByType(t){const o=[];for(const n of this._entities.values())n.type===t&&o.push(n);return o}get(t){return this._entities.get(t)}subscribe(t){return this._listeners.add(t),()=>{this._listeners.delete(t)}}getStats(){let t=0,o=0,n=0,e=0,s=0;for(const i of this._entities.values())switch(i.type){case"mutable":t++;break;case"derived":o++;break;case"effect":n++;break;case"pool":e++;break;case"module":s++;break}return{mutableCount:t,derivedCount:o,effectCount:n,poolCount:e,moduleCount:s,totalCount:t+o+n+e+s}}clear(){this._entities.clear(),this._notifyListeners()}_notifyListeners(){this._version++,this._cachedEntities=null,this._cachedLogs=null,!this._notifyScheduled&&(this._notifyScheduled=!0,queueMicrotask(()=>{this._notifyScheduled=!1;for(const t of this._listeners)try{t()}catch{}}))}}let l=null;function p(r){return l||(l=new P(r)),l}function O(){l==null||l.clear(),l=null}function U(){l=null}const v={BASE_URL:"/",DEV:!1,MODE:"production",PROD:!0,SSR:!1};function M(){try{if(typeof process<"u"&&process.env)return process.env.NODE_ENV==="production"}catch{}try{if(typeof{url:typeof document>"u"?require("url").pathToFileURL(__filename).href:g&&g.tagName.toUpperCase()==="SCRIPT"&&g.src||new URL("devtools/index.cjs",document.baseURI).href}<"u"&&v)return!0}catch{}return!1}let d=!1,c=null;function z(r={}){const{maxHistorySize:t=E,enableInProduction:o=!1}=r;if(M()&&!o)return console.warn("[atomirx-devtools] Devtools disabled in production. Use { enableInProduction: true } to enable."),()=>{};if(d&&c)return c;const n=p(t);return y.onCreateHook.override(e=>s=>{switch(e==null||e(s),s.type){case"mutable":n.registerMutable(s.instance,s.key);break;case"derived":n.registerDerived(s.instance,s.key);break;case"effect":n.registerEffect(s.instance,s.key);break;case"pool":n.registerPool(s.instance,s.key,0);break;case"module":typeof s.instance=="object"&&s.instance!==null&&n.registerModule(s.instance,s.key);break}}),m.onDispatchHook.override(e=>s=>{var i;e==null||e(s),(i=s.meta)!=null&&i.key&&n.addLog({type:"action.dispatch",timestamp:Date.now(),actionKey:s.meta.key,deps:JSON.stringify(s.deps).slice(0,100)})}),y.onErrorHook.override(e=>s=>{e==null||e(s),n.addLog({type:"error",timestamp:Date.now(),sourceType:s.source.type,sourceKey:s.source.key,error:String(s.error).slice(0,200)})}),d=!0,c=()=>{y.onCreateHook.reset(),m.onDispatchHook.reset(),y.onErrorHook.reset(),n.clear(),n.clearLogs(),d=!1,c=null},c}function F(){return d?p():null}function V(){return d}function H(){c&&c(),U(),d=!1,c=null}const x={isOpen:!1,position:"bottom",activeTab:"atoms",panelSize:300,searchText:{atoms:"",effects:"",pools:"",modules:"",logs:""},atomFilter:"all",selectedEntityId:null,showAtomValues:!1};exports.ANIMATION_DURATION=T;exports.DEFAULT_MAX_HISTORY_SIZE=E;exports.DEFAULT_PANEL_SIZE=C;exports.DEFAULT_PREFERENCES=x;exports.DEVTOOLS_Z_INDEX=k;exports.ENTITY_ID_PREFIX=S;exports.FLOATING_BUTTON_SIZE=w;exports.MAX_PANEL_SIZE=b;exports.MIN_PANEL_SIZE=I;exports.STORAGE_KEY_PREFERENCES=R;exports.STORAGE_VERSION=A;exports._resetDevtools=H;exports.getDevtoolsRegistry=F;exports.getRegistry=p;exports.isDevtoolsEnabled=V;exports.resetRegistry=O;exports.setupDevtools=z;
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Atomirx Devtools - Core API
3
+ *
4
+ * This module provides the core devtools functionality for tracking
5
+ * and inspecting atomirx entities (atoms, derived, effects, pools, modules).
6
+ *
7
+ * @packageDocumentation
8
+ *
9
+ * @example Basic usage
10
+ * ```ts
11
+ * import { setupDevtools, getDevtoolsRegistry } from 'atomirx/devtools';
12
+ *
13
+ * // Enable devtools (call once at app startup)
14
+ * setupDevtools();
15
+ *
16
+ * // Access registry for custom integrations
17
+ * const registry = getDevtoolsRegistry();
18
+ * if (registry) {
19
+ * registry.subscribe(() => {
20
+ * console.log('Entities changed:', registry.getStats());
21
+ * });
22
+ * }
23
+ * ```
24
+ */
25
+ export { setupDevtools, getDevtoolsRegistry, isDevtoolsEnabled, _resetDevtools, } from './setup';
26
+ export { getRegistry, resetRegistry } from './registry';
27
+ export type { EntityType, EntityInfo, BaseEntityInfo, MutableEntityInfo, DerivedEntityInfo, EffectEntityInfo, PoolEntityInfo, ModuleEntityInfo, DevtoolsRegistry, DevtoolsStats, DevtoolsOptions, ChangeHistoryEntry, LogEntry, LogEntryType, ActionDispatchLogEntry, ErrorLogEntry, PoolCreateLogEntry, NewLogEntry, PanelPosition, DevtoolsTab, AtomFilter, DevtoolsPreferences, DevtoolsAtomState, } from './types';
28
+ export { DEFAULT_PREFERENCES } from './types';
29
+ export { STORAGE_KEY_PREFERENCES, DEFAULT_MAX_HISTORY_SIZE, ENTITY_ID_PREFIX, STORAGE_VERSION, DEVTOOLS_Z_INDEX, MIN_PANEL_SIZE, MAX_PANEL_SIZE, DEFAULT_PANEL_SIZE, FLOATING_BUTTON_SIZE, ANIMATION_DURATION, } from './constants';