atomirx 0.0.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.
Files changed (121) hide show
  1. package/README.md +1666 -0
  2. package/coverage/base.css +224 -0
  3. package/coverage/block-navigation.js +87 -0
  4. package/coverage/clover.xml +1440 -0
  5. package/coverage/coverage-final.json +14 -0
  6. package/coverage/favicon.png +0 -0
  7. package/coverage/index.html +131 -0
  8. package/coverage/prettify.css +1 -0
  9. package/coverage/prettify.js +2 -0
  10. package/coverage/sort-arrow-sprite.png +0 -0
  11. package/coverage/sorter.js +210 -0
  12. package/coverage/src/core/atom.ts.html +889 -0
  13. package/coverage/src/core/batch.ts.html +223 -0
  14. package/coverage/src/core/define.ts.html +805 -0
  15. package/coverage/src/core/emitter.ts.html +919 -0
  16. package/coverage/src/core/equality.ts.html +631 -0
  17. package/coverage/src/core/hook.ts.html +460 -0
  18. package/coverage/src/core/index.html +281 -0
  19. package/coverage/src/core/isAtom.ts.html +100 -0
  20. package/coverage/src/core/isPromiseLike.ts.html +133 -0
  21. package/coverage/src/core/onCreateHook.ts.html +136 -0
  22. package/coverage/src/core/scheduleNotifyHook.ts.html +94 -0
  23. package/coverage/src/core/types.ts.html +523 -0
  24. package/coverage/src/core/withUse.ts.html +253 -0
  25. package/coverage/src/index.html +116 -0
  26. package/coverage/src/index.ts.html +106 -0
  27. package/dist/core/atom.d.ts +63 -0
  28. package/dist/core/atom.test.d.ts +1 -0
  29. package/dist/core/atomState.d.ts +104 -0
  30. package/dist/core/atomState.test.d.ts +1 -0
  31. package/dist/core/batch.d.ts +126 -0
  32. package/dist/core/batch.test.d.ts +1 -0
  33. package/dist/core/define.d.ts +173 -0
  34. package/dist/core/define.test.d.ts +1 -0
  35. package/dist/core/derived.d.ts +102 -0
  36. package/dist/core/derived.test.d.ts +1 -0
  37. package/dist/core/effect.d.ts +120 -0
  38. package/dist/core/effect.test.d.ts +1 -0
  39. package/dist/core/emitter.d.ts +237 -0
  40. package/dist/core/emitter.test.d.ts +1 -0
  41. package/dist/core/equality.d.ts +62 -0
  42. package/dist/core/equality.test.d.ts +1 -0
  43. package/dist/core/hook.d.ts +134 -0
  44. package/dist/core/hook.test.d.ts +1 -0
  45. package/dist/core/isAtom.d.ts +9 -0
  46. package/dist/core/isPromiseLike.d.ts +9 -0
  47. package/dist/core/isPromiseLike.test.d.ts +1 -0
  48. package/dist/core/onCreateHook.d.ts +79 -0
  49. package/dist/core/promiseCache.d.ts +134 -0
  50. package/dist/core/promiseCache.test.d.ts +1 -0
  51. package/dist/core/scheduleNotifyHook.d.ts +51 -0
  52. package/dist/core/select.d.ts +151 -0
  53. package/dist/core/selector.test.d.ts +1 -0
  54. package/dist/core/types.d.ts +279 -0
  55. package/dist/core/withUse.d.ts +38 -0
  56. package/dist/core/withUse.test.d.ts +1 -0
  57. package/dist/index-2ok7ilik.js +1217 -0
  58. package/dist/index-B_5SFzfl.cjs +1 -0
  59. package/dist/index.cjs +1 -0
  60. package/dist/index.d.ts +14 -0
  61. package/dist/index.js +20 -0
  62. package/dist/index.test.d.ts +1 -0
  63. package/dist/react/index.cjs +30 -0
  64. package/dist/react/index.d.ts +7 -0
  65. package/dist/react/index.js +823 -0
  66. package/dist/react/rx.d.ts +250 -0
  67. package/dist/react/rx.test.d.ts +1 -0
  68. package/dist/react/strictModeTest.d.ts +10 -0
  69. package/dist/react/useAction.d.ts +381 -0
  70. package/dist/react/useAction.test.d.ts +1 -0
  71. package/dist/react/useStable.d.ts +183 -0
  72. package/dist/react/useStable.test.d.ts +1 -0
  73. package/dist/react/useValue.d.ts +134 -0
  74. package/dist/react/useValue.test.d.ts +1 -0
  75. package/package.json +57 -0
  76. package/scripts/publish.js +198 -0
  77. package/src/core/atom.test.ts +369 -0
  78. package/src/core/atom.ts +189 -0
  79. package/src/core/atomState.test.ts +342 -0
  80. package/src/core/atomState.ts +256 -0
  81. package/src/core/batch.test.ts +257 -0
  82. package/src/core/batch.ts +172 -0
  83. package/src/core/define.test.ts +342 -0
  84. package/src/core/define.ts +243 -0
  85. package/src/core/derived.test.ts +381 -0
  86. package/src/core/derived.ts +339 -0
  87. package/src/core/effect.test.ts +196 -0
  88. package/src/core/effect.ts +184 -0
  89. package/src/core/emitter.test.ts +364 -0
  90. package/src/core/emitter.ts +392 -0
  91. package/src/core/equality.test.ts +392 -0
  92. package/src/core/equality.ts +182 -0
  93. package/src/core/hook.test.ts +227 -0
  94. package/src/core/hook.ts +177 -0
  95. package/src/core/isAtom.ts +27 -0
  96. package/src/core/isPromiseLike.test.ts +72 -0
  97. package/src/core/isPromiseLike.ts +16 -0
  98. package/src/core/onCreateHook.ts +92 -0
  99. package/src/core/promiseCache.test.ts +239 -0
  100. package/src/core/promiseCache.ts +279 -0
  101. package/src/core/scheduleNotifyHook.ts +53 -0
  102. package/src/core/select.ts +454 -0
  103. package/src/core/selector.test.ts +257 -0
  104. package/src/core/types.ts +311 -0
  105. package/src/core/withUse.test.ts +249 -0
  106. package/src/core/withUse.ts +56 -0
  107. package/src/index.test.ts +80 -0
  108. package/src/index.ts +51 -0
  109. package/src/react/index.ts +20 -0
  110. package/src/react/rx.test.tsx +416 -0
  111. package/src/react/rx.tsx +300 -0
  112. package/src/react/strictModeTest.tsx +71 -0
  113. package/src/react/useAction.test.ts +989 -0
  114. package/src/react/useAction.ts +605 -0
  115. package/src/react/useStable.test.ts +553 -0
  116. package/src/react/useStable.ts +288 -0
  117. package/src/react/useValue.test.ts +182 -0
  118. package/src/react/useValue.ts +261 -0
  119. package/tsconfig.json +9 -0
  120. package/v2.md +725 -0
  121. package/vite.config.ts +39 -0
@@ -0,0 +1,237 @@
1
+ import { Listener, SingleOrMultipleListeners } from './types';
2
+ /**
3
+ * Event emitter interface for pub/sub pattern.
4
+ *
5
+ * @template T - The type of payload emitted to listeners (defaults to void)
6
+ */
7
+ export interface Emitter<T = void> {
8
+ /**
9
+ * Subscribe to events with one or more listeners.
10
+ *
11
+ * @param listeners - Single listener or array of listeners
12
+ * @returns Unsubscribe function (idempotent - safe to call multiple times)
13
+ */
14
+ on(listeners: SingleOrMultipleListeners<T>): VoidFunction;
15
+ /**
16
+ * Subscribe with a mapping function that filters and transforms events.
17
+ *
18
+ * The map function receives the emitted value and returns either:
19
+ * - `{ value: TValue }` - Listener is called with the transformed value
20
+ * - `undefined` - Listener is NOT called (event filtered out)
21
+ *
22
+ * @template TValue - The transformed value type passed to listeners
23
+ * @param map - Transform function that can filter (return undefined) or map values
24
+ * @param listeners - Single listener or array of listeners for transformed values
25
+ * @returns Unsubscribe function
26
+ *
27
+ * @example Filter and transform
28
+ * ```ts
29
+ * const emitter = emitter<{ type: string; data: number }>();
30
+ *
31
+ * // Only listen to 'success' events, extract just the data
32
+ * emitter.on(
33
+ * (event) => event.type === 'success' ? { value: event.data } : undefined,
34
+ * (data) => console.log('Success data:', data)
35
+ * );
36
+ * ```
37
+ */
38
+ on<TValue>(map: (value: T) => {
39
+ value: TValue;
40
+ } | undefined, listeners: SingleOrMultipleListeners<TValue>): VoidFunction;
41
+ /**
42
+ * Emit an event to all registered listeners.
43
+ *
44
+ * @param payload - The value to pass to all listeners
45
+ */
46
+ emit(payload: T): void;
47
+ /**
48
+ * Emit an event to all registered listeners in LIFO (reverse) order.
49
+ * Useful for cleanup scenarios where resources should be released
50
+ * in reverse order of acquisition.
51
+ *
52
+ * @param payload - The value to pass to all listeners
53
+ */
54
+ emitLifo(payload: T): void;
55
+ /**
56
+ * Remove all registered listeners.
57
+ */
58
+ clear(): void;
59
+ /**
60
+ * Emit an event to all listeners, then clear all listeners.
61
+ * Useful for one-time events like disposal.
62
+ *
63
+ * @param payload - The value to pass to all listeners
64
+ */
65
+ emitAndClear(payload: T): void;
66
+ /**
67
+ * Emit an event to all listeners in LIFO (reverse) order, then clear.
68
+ * Useful for cleanup scenarios where resources should be released
69
+ * in reverse order of acquisition.
70
+ *
71
+ * @param payload - The value to pass to all listeners
72
+ */
73
+ emitAndClearLifo(payload: T): void;
74
+ /**
75
+ * Emit to all listeners, clear, and "settle" the emitter.
76
+ *
77
+ * After settling:
78
+ * - Any new `on()` call immediately invokes the listener with the settled payload
79
+ * - Returns a no-op unsubscribe function
80
+ * - `emit()` and `emitAndClear()` become no-ops
81
+ *
82
+ * Useful for one-time events where late subscribers should still receive the value
83
+ * (similar to Promise behavior).
84
+ *
85
+ * @param payload - The final value to pass to all listeners
86
+ */
87
+ settle(payload: T): void;
88
+ /** Number of registered listeners */
89
+ size(): number;
90
+ /** Whether the emitter has been settled */
91
+ settled(): boolean;
92
+ /**
93
+ * Iterate over all registered listeners.
94
+ * Used for batching to dedupe listeners across multiple atoms.
95
+ */
96
+ forEach(callback: (listener: Listener<T>) => void): void;
97
+ }
98
+ /**
99
+ * Creates an event emitter for managing and notifying listeners.
100
+ *
101
+ * An emitter provides a simple pub/sub pattern for managing event listeners.
102
+ * It's used internally by atoms and effects to manage subscriptions and notifications.
103
+ *
104
+ * ## Key Features
105
+ *
106
+ * 1. **Subscribe/Unsubscribe**: Add listeners that will be notified when events are emitted
107
+ * 2. **Emit events**: Notify all registered listeners with a payload
108
+ * 3. **Mapped subscriptions**: Filter and transform events before they reach listeners
109
+ * 4. **LIFO emission**: Emit in reverse order for cleanup scenarios
110
+ * 5. **Settle pattern**: One-time events where late subscribers still receive the value
111
+ * 6. **Idempotent unsubscribe**: Safe to call unsubscribe multiple times
112
+ *
113
+ * ## Emission Methods
114
+ *
115
+ * | Method | Order | Clears | Settles | Use Case |
116
+ * |--------|-------|--------|---------|----------|
117
+ * | `emit()` | FIFO | No | No | Normal notifications |
118
+ * | `emitLifo()` | LIFO | No | No | Cleanup in reverse order |
119
+ * | `emitAndClear()` | FIFO | Yes | No | One-time broadcast |
120
+ * | `emitAndClearLifo()` | LIFO | Yes | No | One-time cleanup |
121
+ * | `settle()` | FIFO | Yes | Yes | Promise-like one-time events |
122
+ *
123
+ * ## Settle Behavior
124
+ *
125
+ * After `settle()` is called:
126
+ * - New `on()` calls immediately invoke the listener with the settled payload
127
+ * - Returns a no-op unsubscribe function
128
+ * - `emit()` and other methods become no-ops
129
+ *
130
+ * This is similar to how Promises work - late `.then()` calls still receive the value.
131
+ *
132
+ * @template T - The type of payload emitted to listeners (defaults to void)
133
+ * @param initialListeners - Optional array of listeners to start with
134
+ * @returns An Emitter instance
135
+ *
136
+ * @example Basic usage
137
+ * ```ts
138
+ * const events = emitter<string>();
139
+ *
140
+ * // Subscribe
141
+ * const unsubscribe = events.on((message) => {
142
+ * console.log('Received:', message);
143
+ * });
144
+ *
145
+ * // Emit
146
+ * events.emit('Hello'); // Logs: "Received: Hello"
147
+ *
148
+ * // Unsubscribe
149
+ * unsubscribe();
150
+ *
151
+ * events.emit('World'); // Nothing logged
152
+ * ```
153
+ *
154
+ * @example Multiple listeners
155
+ * ```ts
156
+ * const events = emitter<number>();
157
+ *
158
+ * events.on((n) => console.log('A:', n));
159
+ * events.on((n) => console.log('B:', n));
160
+ *
161
+ * events.emit(42);
162
+ * // Logs: "A: 42"
163
+ * // Logs: "B: 42"
164
+ * ```
165
+ *
166
+ * @example Mapped subscriptions (filter and transform)
167
+ * ```ts
168
+ * const events = emitter<{ type: string; data: number }>();
169
+ *
170
+ * // Only listen to 'success' events, extract just the data
171
+ * events.on(
172
+ * (event) => event.type === 'success' ? { value: event.data } : undefined,
173
+ * (data) => console.log('Success data:', data)
174
+ * );
175
+ *
176
+ * events.emit({ type: 'error', data: 0 }); // Nothing logged (filtered)
177
+ * events.emit({ type: 'success', data: 42 }); // Logs: "Success data: 42"
178
+ * ```
179
+ *
180
+ * @example LIFO emission for cleanup
181
+ * ```ts
182
+ * const cleanup = emitter();
183
+ *
184
+ * cleanup.on(() => console.log('First registered, last to clean'));
185
+ * cleanup.on(() => console.log('Second registered, second to clean'));
186
+ * cleanup.on(() => console.log('Last registered, first to clean'));
187
+ *
188
+ * cleanup.emitLifo();
189
+ * // Logs in reverse order:
190
+ * // "Last registered, first to clean"
191
+ * // "Second registered, second to clean"
192
+ * // "First registered, last to clean"
193
+ * ```
194
+ *
195
+ * @example Settle pattern (Promise-like)
196
+ * ```ts
197
+ * const ready = emitter<{ config: Config }>();
198
+ *
199
+ * // Early subscriber
200
+ * ready.on((payload) => console.log('Early:', payload.config));
201
+ *
202
+ * // Settle the emitter
203
+ * ready.settle({ config: loadedConfig });
204
+ * // Logs: "Early: ..."
205
+ *
206
+ * // Late subscriber - still receives the value immediately
207
+ * ready.on((payload) => console.log('Late:', payload.config));
208
+ * // Logs: "Late: ..." (immediately)
209
+ * ```
210
+ *
211
+ * @example Void emitter (no payload)
212
+ * ```ts
213
+ * const tick = emitter(); // emitter<void>
214
+ *
215
+ * tick.on(() => console.log('Tick!'));
216
+ *
217
+ * tick.emit(); // Logs: "Tick!"
218
+ * ```
219
+ *
220
+ * @example Array of listeners
221
+ * ```ts
222
+ * const events = emitter<string>();
223
+ *
224
+ * // Subscribe multiple listeners at once
225
+ * const unsubscribe = events.on([
226
+ * (msg) => console.log('Logger 1:', msg),
227
+ * (msg) => console.log('Logger 2:', msg),
228
+ * ]);
229
+ *
230
+ * events.emit('Hello');
231
+ * // Logs: "Logger 1: Hello"
232
+ * // Logs: "Logger 2: Hello"
233
+ *
234
+ * unsubscribe(); // Removes both listeners
235
+ * ```
236
+ */
237
+ export declare function emitter<T = void>(initialListeners?: Listener<T>[]): Emitter<T>;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,62 @@
1
+ import { Equality, EqualityShorthand } from './types';
2
+ /**
3
+ * Strict equality (Object.is).
4
+ */
5
+ export declare function strictEqual<T>(a: T, b: T): boolean;
6
+ /**
7
+ * Shallow equality for objects/arrays.
8
+ * Compares by reference for each top-level key/index.
9
+ *
10
+ * @param itemEqual - Optional comparator for each item/value (defaults to Object.is)
11
+ */
12
+ export declare function shallowEqual<T>(a: T, b: T, itemEqual?: (a: unknown, b: unknown) => boolean): boolean;
13
+ /**
14
+ * 2-level shallow equality.
15
+ * Compares keys/length, then shallow compares each item/value.
16
+ *
17
+ * @example
18
+ * [{ id: 1, data: obj }] vs [{ id: 1, data: obj }] // true (same obj ref)
19
+ */
20
+ export declare function shallow2Equal<T>(a: T, b: T): boolean;
21
+ /**
22
+ * 3-level shallow equality.
23
+ * Compares keys/length, then shallow2 compares each item/value.
24
+ *
25
+ * @example
26
+ * [{ id: 1, nested: { data: obj } }] vs [{ id: 1, nested: { data: obj } }] // true
27
+ */
28
+ export declare function shallow3Equal<T>(a: T, b: T): boolean;
29
+ /**
30
+ * Deep equality.
31
+ */
32
+ export declare const deepEqual: (value: any, other: any) => boolean;
33
+ /**
34
+ * Resolve equality strategy to a function.
35
+ */
36
+ export declare function resolveEquality<T>(e: Equality<T> | undefined): (a: T, b: T) => boolean;
37
+ export declare function equality(shorthand: EqualityShorthand): (a: unknown, b: unknown) => boolean;
38
+ export type StableFn<TArgs extends any[], TResult> = ((...args: TArgs) => TResult) & {
39
+ getOriginal: () => (...args: TArgs) => TResult;
40
+ getCurrent: () => (...args: TArgs) => TResult;
41
+ setCurrent: (newFn: (...args: TArgs) => TResult) => void;
42
+ };
43
+ export declare function createStableFn<TArgs extends any[], TResult>(fn: (...args: TArgs) => TResult): StableFn<TArgs, TResult>;
44
+ /**
45
+ * Check if a value is a stable function wrapper.
46
+ */
47
+ export declare function isStableFn<TArgs extends any[], TResult>(value: unknown): value is StableFn<TArgs, TResult>;
48
+ /**
49
+ * Stabilize a value with automatic function wrapper support.
50
+ *
51
+ * - Functions: Creates/updates stable wrapper (reference never changes)
52
+ * - Date objects: Compared by timestamp (uses deepEqual)
53
+ * - Other values: Returns previous if equal per equalityFn
54
+ *
55
+ * @param prev - Previous value container (or undefined for first call)
56
+ * @param next - New value
57
+ * @param equalityFn - Equality function for non-function/non-date values
58
+ * @returns Tuple of [stabilized value, wasStable]
59
+ */
60
+ export declare function tryStabilize<T>(prev: {
61
+ value: T;
62
+ } | undefined, next: T, equalityFn: (a: T, b: T) => boolean): [T, boolean];
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,134 @@
1
+ /**
2
+ * A setup function that returns a release function.
3
+ * Called by hook.use() to activate a hook, release restores previous value.
4
+ */
5
+ export type HookSetup = () => VoidFunction;
6
+ /**
7
+ * A hook is a callable factory that creates setup functions,
8
+ * with direct access to current value via `.current`.
9
+ *
10
+ * @example
11
+ * ```ts
12
+ * const myHook = hook<string>("default");
13
+ *
14
+ * // Read current value (fast - direct property access)
15
+ * console.log(myHook.current); // "default"
16
+ *
17
+ * // Create a setup function (reducer receives previous value)
18
+ * const setup = myHook(() => "new value");
19
+ *
20
+ * // Use with hook.use()
21
+ * hook.use([myHook(() => "temp")], () => {
22
+ * console.log(myHook.current); // "temp"
23
+ * });
24
+ * console.log(myHook.current); // "default" (restored)
25
+ *
26
+ * // Compose with previous value
27
+ * myHook.override(prev => {
28
+ * console.log("Previous:", prev);
29
+ * return "next";
30
+ * });
31
+ * ```
32
+ */
33
+ export interface Hook<T> {
34
+ /**
35
+ * Creates a HookSetup that will set this hook using a reducer.
36
+ * The reducer receives the previous value and returns the next value.
37
+ *
38
+ * @param reducer - Function that receives previous value and returns next value
39
+ *
40
+ * @example Set new value (ignore previous)
41
+ * ```ts
42
+ * myHook(() => "new value")
43
+ * ```
44
+ *
45
+ * @example Compose with previous
46
+ * ```ts
47
+ * myHook(prev => {
48
+ * prev?.(); // call previous handler
49
+ * return newHandler;
50
+ * })
51
+ * ```
52
+ */
53
+ (reducer: (prev: T) => T): HookSetup;
54
+ /**
55
+ * Current value of the hook. Direct property access for fast reads.
56
+ */
57
+ current: T;
58
+ /**
59
+ * Override the current value using a reducer.
60
+ * The reducer receives the previous value and returns the next value.
61
+ * Unlike the setup/release pattern, this is an immediate mutation.
62
+ *
63
+ * @param reducer - Function that receives previous value and returns next value
64
+ *
65
+ * @example Set new value (ignore previous)
66
+ * ```ts
67
+ * myHook.override(() => "new value")
68
+ * ```
69
+ *
70
+ * @example Compose with previous (middleware pattern)
71
+ * ```ts
72
+ * onCreateHook.override(prev => (info) => {
73
+ * prev?.(info); // call existing handler
74
+ * console.log("Created:", info.key);
75
+ * });
76
+ * ```
77
+ */
78
+ override(reducer: (prev: T) => T): void;
79
+ /**
80
+ * Reset the hook to its initial value.
81
+ */
82
+ reset(): void;
83
+ }
84
+ /**
85
+ * Creates a new hook with an initial value.
86
+ *
87
+ * Hooks use the setup/release pattern for performance:
88
+ * - Reads are direct property access (fastest)
89
+ * - Writes use setup/release for proper nesting
90
+ *
91
+ * @param initial - Initial value for the hook
92
+ * @returns A Hook instance
93
+ *
94
+ * @example
95
+ * ```ts
96
+ * // Create a hook
97
+ * const countHook = hook(0);
98
+ *
99
+ * // Read
100
+ * console.log(countHook.current); // 0
101
+ *
102
+ * // Use with hook.use() - reducer receives previous value
103
+ * hook.use([countHook(() => 5)], () => {
104
+ * console.log(countHook.current); // 5
105
+ * });
106
+ *
107
+ * // Compose with previous (middleware pattern)
108
+ * myHook.override(prev => (info) => {
109
+ * prev?.(info); // call existing
110
+ * newHandler(info);
111
+ * });
112
+ * ```
113
+ */
114
+ declare function createHook<T>(initial: T): Hook<T>;
115
+ declare function createHook<T>(): Hook<T | undefined>;
116
+ /**
117
+ * Executes a function with multiple hooks temporarily set.
118
+ *
119
+ * @param setups - Array of HookSetup functions (from hook factories)
120
+ * @param fn - Function to execute with hooks active
121
+ * @returns The return value of fn
122
+ *
123
+ * @example
124
+ * ```ts
125
+ * hook.use([trackHook(myTracker), debugHook(true)], () => {
126
+ * // hooks active here
127
+ * });
128
+ * ```
129
+ */
130
+ declare function use<T>(setups: HookSetup[], fn: () => T): T;
131
+ export declare const hook: typeof createHook & {
132
+ use: typeof use;
133
+ };
134
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,9 @@
1
+ import { Atom, DerivedAtom } from './types';
2
+ /**
3
+ * Type guard to check if a value is an Atom.
4
+ */
5
+ export declare function isAtom<T>(value: unknown): value is Atom<T>;
6
+ /**
7
+ * Type guard to check if a value is a DerivedAtom.
8
+ */
9
+ export declare function isDerived<T>(value: unknown): value is DerivedAtom<T, boolean>;
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Check if a value is a PromiseLike (has a .then method).
3
+ *
4
+ * @example
5
+ * isPromiseLike(Promise.resolve(1)) // true
6
+ * isPromiseLike({ then: () => {} }) // true
7
+ * isPromiseLike(42) // false
8
+ */
9
+ export declare function isPromiseLike<T>(value: unknown): value is PromiseLike<T>;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,79 @@
1
+ import { MutableAtomMeta, DerivedAtomMeta, MutableAtom, DerivedAtom, ModuleMeta } from './types';
2
+ /**
3
+ * Information provided when a mutable atom is created.
4
+ */
5
+ export interface MutableAtomCreateInfo {
6
+ /** Discriminator for mutable atoms */
7
+ type: "mutable";
8
+ /** Optional key from atom options (for debugging/devtools) */
9
+ key: string | undefined;
10
+ /** Optional metadata from atom options */
11
+ meta: MutableAtomMeta | undefined;
12
+ /** The created mutable atom instance */
13
+ atom: MutableAtom<unknown>;
14
+ }
15
+ /**
16
+ * Information provided when a derived atom is created.
17
+ */
18
+ export interface DerivedAtomCreateInfo {
19
+ /** Discriminator for derived atoms */
20
+ type: "derived";
21
+ /** Optional key from derived options (for debugging/devtools) */
22
+ key: string | undefined;
23
+ /** Optional metadata from derived options */
24
+ meta: DerivedAtomMeta | undefined;
25
+ /** The created derived atom instance */
26
+ atom: DerivedAtom<unknown, boolean>;
27
+ }
28
+ /**
29
+ * Union type for atom creation info (mutable or derived).
30
+ */
31
+ export type AtomCreateInfo = MutableAtomCreateInfo | DerivedAtomCreateInfo;
32
+ /**
33
+ * Information provided when a module (via define()) is created.
34
+ */
35
+ export interface ModuleCreateInfo {
36
+ /** Discriminator for modules */
37
+ type: "module";
38
+ /** Optional key from define options (for debugging/devtools) */
39
+ key: string | undefined;
40
+ /** Optional metadata from define options */
41
+ meta: ModuleMeta | undefined;
42
+ /** The created module instance */
43
+ module: unknown;
44
+ }
45
+ /**
46
+ * Global hook that fires whenever an atom or module is created.
47
+ *
48
+ * This is useful for:
49
+ * - **DevTools integration** - track all atoms/modules in the app
50
+ * - **Debugging** - log atom creation for troubleshooting
51
+ * - **Testing** - verify expected atoms are created
52
+ *
53
+ * @example Basic logging
54
+ * ```ts
55
+ * onCreateHook.current = (info) => {
56
+ * console.log(`Created ${info.type}: ${info.key ?? "anonymous"}`);
57
+ * };
58
+ * ```
59
+ *
60
+ * @example DevTools integration
61
+ * ```ts
62
+ * const atoms = new Map();
63
+ * const modules = new Map();
64
+ *
65
+ * onCreateHook.current = (info) => {
66
+ * if (info.type === "module") {
67
+ * modules.set(info.key, info.module);
68
+ * } else {
69
+ * atoms.set(info.key, info.atom);
70
+ * }
71
+ * };
72
+ * ```
73
+ *
74
+ * @example Cleanup (disable hook)
75
+ * ```ts
76
+ * onCreateHook.current = undefined;
77
+ * ```
78
+ */
79
+ export declare const onCreateHook: import('./hook').Hook<((info: AtomCreateInfo | ModuleCreateInfo) => void) | undefined>;
@@ -0,0 +1,134 @@
1
+ import { Atom, AtomState, DerivedAtom } from './types';
2
+ /**
3
+ * Represents the state of a tracked Promise.
4
+ */
5
+ export type PromiseState<T> = {
6
+ status: "pending";
7
+ promise: PromiseLike<T>;
8
+ } | {
9
+ status: "fulfilled";
10
+ value: T;
11
+ } | {
12
+ status: "rejected";
13
+ error: unknown;
14
+ };
15
+ /**
16
+ * Tracks a Promise and caches its state.
17
+ * If the Promise is already tracked, returns the existing state.
18
+ * Otherwise, starts tracking and returns the initial pending state.
19
+ *
20
+ * @param promise - The Promise to track
21
+ * @returns The current state of the Promise
22
+ *
23
+ * @example
24
+ * ```ts
25
+ * const promise = fetchData();
26
+ * const state = trackPromise(promise);
27
+ * // state.status === 'pending'
28
+ *
29
+ * await promise;
30
+ * const state2 = trackPromise(promise);
31
+ * // state2.status === 'fulfilled'
32
+ * ```
33
+ */
34
+ export declare function trackPromise<T>(promise: PromiseLike<T>): PromiseState<T>;
35
+ /**
36
+ * Gets the current state of a Promise without tracking it.
37
+ * Returns undefined if the Promise is not being tracked.
38
+ *
39
+ * @param promise - The Promise to check
40
+ * @returns The current state or undefined if not tracked
41
+ */
42
+ export declare function getPromiseState<T>(promise: PromiseLike<T>): PromiseState<T> | undefined;
43
+ /**
44
+ * Checks if a Promise is being tracked.
45
+ *
46
+ * @param promise - The Promise to check
47
+ * @returns true if the Promise is tracked
48
+ */
49
+ export declare function isTracked(promise: PromiseLike<unknown>): boolean;
50
+ /**
51
+ * Type guard to check if a value is a DerivedAtom.
52
+ */
53
+ export declare function isDerived<T>(value: unknown): value is DerivedAtom<T, boolean>;
54
+ /**
55
+ * Returns the current state of an atom as a discriminated union.
56
+ *
57
+ * For DerivedAtom:
58
+ * - Returns atom.state() directly (derived atoms track their own state)
59
+ *
60
+ * For MutableAtom:
61
+ * - If value is not a Promise: returns ready state
62
+ * - If value is a Promise: tracks and returns its state (ready/error/loading)
63
+ *
64
+ * @param atom - The atom to get state from
65
+ * @returns AtomState discriminated union (ready | error | loading)
66
+ *
67
+ * @example
68
+ * ```ts
69
+ * const state = getAtomState(myAtom$);
70
+ *
71
+ * switch (state.status) {
72
+ * case "ready":
73
+ * console.log(state.value); // T
74
+ * break;
75
+ * case "error":
76
+ * console.log(state.error);
77
+ * break;
78
+ * case "loading":
79
+ * console.log(state.promise);
80
+ * break;
81
+ * }
82
+ * ```
83
+ */
84
+ export declare function getAtomState<T>(atom: Atom<T>): AtomState<Awaited<T>>;
85
+ /**
86
+ * Unwraps a value that may be a Promise.
87
+ * - If not a Promise, returns the value directly.
88
+ * - If a resolved Promise, returns the resolved value.
89
+ * - If a loading Promise, throws the Promise (for Suspense).
90
+ * - If a rejected Promise, throws the error.
91
+ *
92
+ * This follows the React Suspense pattern where throwing a Promise
93
+ * signals that the component should suspend until the Promise resolves.
94
+ *
95
+ * @param value - The value to unwrap (may be a Promise)
96
+ * @returns The unwrapped value
97
+ * @throws Promise if loading, Error if rejected
98
+ */
99
+ export declare function unwrap<T>(value: T | PromiseLike<T>): T;
100
+ /**
101
+ * Checks if a value is a pending Promise.
102
+ *
103
+ * @param value - The value to check
104
+ * @returns true if value is a Promise in pending state
105
+ */
106
+ export declare function isPending<T>(value: T | PromiseLike<T>): boolean;
107
+ /**
108
+ * Checks if a value is a fulfilled Promise.
109
+ *
110
+ * @param value - The value to check
111
+ * @returns true if value is a Promise in fulfilled state
112
+ */
113
+ export declare function isFulfilled<T>(value: T | PromiseLike<T>): boolean;
114
+ /**
115
+ * Checks if a value is a rejected Promise.
116
+ *
117
+ * @param value - The value to check
118
+ * @returns true if value is a Promise in rejected state
119
+ */
120
+ export declare function isRejected<T>(value: T | PromiseLike<T>): boolean;
121
+ /**
122
+ * Gets the resolved value of a Promise if fulfilled, otherwise undefined.
123
+ *
124
+ * @param value - The value to check
125
+ * @returns The resolved value or undefined
126
+ */
127
+ export declare function getResolvedValue<T>(value: T | PromiseLike<T>): T | undefined;
128
+ /**
129
+ * Gets the error of a Promise if rejected, otherwise undefined.
130
+ *
131
+ * @param value - The value to check
132
+ * @returns The error or undefined
133
+ */
134
+ export declare function getRejectedError<T>(value: T | PromiseLike<T>): unknown | undefined;
@@ -0,0 +1 @@
1
+ export {};