atomirx 0.1.0 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/core/abortable.d.ts +196 -0
- package/dist/core/abortable.test.d.ts +1 -0
- package/dist/core/derived.d.ts +6 -3
- package/dist/core/effect.d.ts +3 -0
- package/dist/core/event.d.ts +152 -0
- package/dist/core/event.test.d.ts +1 -0
- package/dist/core/onCreateHook.d.ts +16 -3
- package/dist/core/promiseCache.d.ts +35 -0
- package/dist/core/select.d.ts +18 -10
- package/dist/core/types.d.ts +219 -9
- package/dist/core/withReady.d.ts +36 -45
- package/dist/index-B1Kum0se.cjs +1 -0
- package/dist/index-DbZ2r2Im.js +1756 -0
- package/dist/index.cjs +1 -1
- package/dist/index.d.ts +7 -3
- package/dist/index.js +32 -25
- package/dist/react/index.cjs +1 -1
- package/dist/react/index.js +90 -83
- package/package.json +1 -1
- package/skills/atomirx/SKILL.md +154 -15
- package/skills/atomirx/references/async-patterns.md +92 -9
- package/skills/atomirx/references/select-context.md +31 -18
- package/dist/index-BZEnfIcB.cjs +0 -1
- package/dist/index-BbPZhsDl.js +0 -1653
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Options for configuring an abortable promise.
|
|
3
|
+
*/
|
|
4
|
+
export interface AbortableOptions {
|
|
5
|
+
/**
|
|
6
|
+
* External signal(s) to link. The abortable promise will abort when any
|
|
7
|
+
* of these signals abort. Useful for hierarchical cancellation.
|
|
8
|
+
*
|
|
9
|
+
* @example Single signal
|
|
10
|
+
* ```ts
|
|
11
|
+
* const controller = new AbortController();
|
|
12
|
+
* const req = abortable((signal) => fetch('/api', { signal }), {
|
|
13
|
+
* signal: controller.signal
|
|
14
|
+
* });
|
|
15
|
+
* controller.abort(); // Aborts the request
|
|
16
|
+
* ```
|
|
17
|
+
*
|
|
18
|
+
* @example Multiple signals (e.g., timeout + user cancel)
|
|
19
|
+
* ```ts
|
|
20
|
+
* const req = abortable((signal) => fetch('/api', { signal }), {
|
|
21
|
+
* signal: [AbortSignal.timeout(5000), userCancelSignal]
|
|
22
|
+
* });
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
signal?: AbortSignal | AbortSignal[];
|
|
26
|
+
/**
|
|
27
|
+
* Callback invoked when the operation is aborted. Called once, regardless
|
|
28
|
+
* of abort source (manual abort, linked signal, or inner AbortError).
|
|
29
|
+
*
|
|
30
|
+
* @param reason - The abort reason (string, Error, or any value)
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
* ```ts
|
|
34
|
+
* const req = abortable((signal) => fetch('/api', { signal }), {
|
|
35
|
+
* onAbort: (reason) => console.log('Aborted:', reason)
|
|
36
|
+
* });
|
|
37
|
+
* ```
|
|
38
|
+
*/
|
|
39
|
+
onAbort?: (reason: unknown) => void;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Promise with abort control capabilities.
|
|
43
|
+
*
|
|
44
|
+
* Extends the standard Promise interface with:
|
|
45
|
+
* - `abort(reason?)` - Cancel the operation
|
|
46
|
+
* - `aborted()` - Check if operation was aborted
|
|
47
|
+
*/
|
|
48
|
+
export interface AbortablePromise<T> extends Promise<T> {
|
|
49
|
+
/**
|
|
50
|
+
* Abort the operation with an optional reason.
|
|
51
|
+
*
|
|
52
|
+
* - Immediately rejects the promise with an AbortError
|
|
53
|
+
* - Calls the `onAbort` callback if provided
|
|
54
|
+
* - Signals abort to the inner function via its AbortSignal
|
|
55
|
+
* - Safe to call multiple times (subsequent calls are no-ops)
|
|
56
|
+
*
|
|
57
|
+
* @param reason - Optional abort reason (passed to onAbort and error message)
|
|
58
|
+
*
|
|
59
|
+
* @example
|
|
60
|
+
* ```ts
|
|
61
|
+
* const req = abortable((signal) => fetch('/api', { signal }));
|
|
62
|
+
* req.abort('User cancelled');
|
|
63
|
+
* ```
|
|
64
|
+
*/
|
|
65
|
+
abort(reason?: unknown): void;
|
|
66
|
+
/**
|
|
67
|
+
* Returns true if the operation was aborted.
|
|
68
|
+
*
|
|
69
|
+
* Aborted state is set when:
|
|
70
|
+
* - `abort()` is called explicitly
|
|
71
|
+
* - A linked signal aborts
|
|
72
|
+
* - The inner function throws an AbortError
|
|
73
|
+
*
|
|
74
|
+
* @returns boolean indicating abort state
|
|
75
|
+
*
|
|
76
|
+
* @example
|
|
77
|
+
* ```ts
|
|
78
|
+
* const req = abortable((signal) => fetch('/api', { signal }));
|
|
79
|
+
* req.abort();
|
|
80
|
+
* console.log(req.aborted()); // true
|
|
81
|
+
* ```
|
|
82
|
+
*/
|
|
83
|
+
aborted(): boolean;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Creates an AbortError (DOMException with name 'AbortError').
|
|
87
|
+
*
|
|
88
|
+
* @param reason - Optional reason for the abort (string, Error, or any value)
|
|
89
|
+
* @returns DOMException with name 'AbortError'
|
|
90
|
+
*
|
|
91
|
+
* @example
|
|
92
|
+
* ```ts
|
|
93
|
+
* throw createAbortError('User cancelled');
|
|
94
|
+
* throw createAbortError({ message: 'Timeout exceeded' });
|
|
95
|
+
* ```
|
|
96
|
+
*/
|
|
97
|
+
export declare function createAbortError(reason?: unknown): DOMException;
|
|
98
|
+
/**
|
|
99
|
+
* Checks if an error is an AbortError.
|
|
100
|
+
*
|
|
101
|
+
* Returns true for:
|
|
102
|
+
* - DOMException with name 'AbortError'
|
|
103
|
+
* - Error with name 'AbortError'
|
|
104
|
+
*
|
|
105
|
+
* @param error - The error to check
|
|
106
|
+
* @returns true if the error is an AbortError
|
|
107
|
+
*
|
|
108
|
+
* @example
|
|
109
|
+
* ```ts
|
|
110
|
+
* try {
|
|
111
|
+
* await abortableRequest;
|
|
112
|
+
* } catch (e) {
|
|
113
|
+
* if (isAbortError(e)) {
|
|
114
|
+
* console.log('Request was cancelled');
|
|
115
|
+
* } else {
|
|
116
|
+
* throw e;
|
|
117
|
+
* }
|
|
118
|
+
* }
|
|
119
|
+
* ```
|
|
120
|
+
*/
|
|
121
|
+
export declare function isAbortError(error: unknown): boolean;
|
|
122
|
+
/**
|
|
123
|
+
* Wraps an async function with abort control.
|
|
124
|
+
*
|
|
125
|
+
* Returns a Promise that can be aborted, with automatic cleanup and
|
|
126
|
+
* hierarchical cancellation support.
|
|
127
|
+
*
|
|
128
|
+
* ## Features
|
|
129
|
+
*
|
|
130
|
+
* - **Guaranteed rejection on abort**: Immediate rejection when abort is called
|
|
131
|
+
* - **Hierarchical cancellation**: Link to parent signals for nested abort
|
|
132
|
+
* - **Bidirectional abort detection**: Detects abort from both external and internal sources
|
|
133
|
+
* - **Safe abort**: Multiple abort() calls are no-ops
|
|
134
|
+
*
|
|
135
|
+
* ## Behavior Table
|
|
136
|
+
*
|
|
137
|
+
* | Trigger | Promise | aborted() | onAbort |
|
|
138
|
+
* |----------------------------|-----------------|-----------|---------|
|
|
139
|
+
* | `abort()` called | Rejects | `true` | ✓ |
|
|
140
|
+
* | Linked signal aborts | Rejects | `true` | ✓ |
|
|
141
|
+
* | Inner fn throws AbortError | Rejects | `true` | ✓ |
|
|
142
|
+
* | Inner fn throws other | Rejects | `false` | ✗ |
|
|
143
|
+
* | Inner fn resolves | Resolves | `false` | ✗ |
|
|
144
|
+
*
|
|
145
|
+
* @param fn - Function that receives an AbortSignal. Can return sync value or Promise.
|
|
146
|
+
* @param options - Optional configuration (linked signals, onAbort callback)
|
|
147
|
+
* @returns AbortablePromise with abort() and aborted() methods
|
|
148
|
+
*
|
|
149
|
+
* @example Basic usage with async function
|
|
150
|
+
* ```ts
|
|
151
|
+
* const req = abortable((signal) => fetch('/api', { signal }));
|
|
152
|
+
* req.abort('User cancelled');
|
|
153
|
+
* console.log(req.aborted()); // true
|
|
154
|
+
* ```
|
|
155
|
+
*
|
|
156
|
+
* @example Sync function (always returns a Promise)
|
|
157
|
+
* ```ts
|
|
158
|
+
* const result = await abortable(() => computeExpensiveValue());
|
|
159
|
+
* ```
|
|
160
|
+
*
|
|
161
|
+
* @example With timeout and cleanup
|
|
162
|
+
* ```ts
|
|
163
|
+
* const req = abortable(
|
|
164
|
+
* (signal) => fetch('/api/slow', { signal }),
|
|
165
|
+
* {
|
|
166
|
+
* signal: AbortSignal.timeout(5000),
|
|
167
|
+
* onAbort: () => console.log('Request timed out or cancelled')
|
|
168
|
+
* }
|
|
169
|
+
* );
|
|
170
|
+
* ```
|
|
171
|
+
*
|
|
172
|
+
* @example Composing nested abortable operations
|
|
173
|
+
* ```ts
|
|
174
|
+
* const parent = abortable(async (signal) => {
|
|
175
|
+
* const a = await abortable((s) => fetchA(s), { signal });
|
|
176
|
+
* const b = await abortable((s) => fetchB(s), { signal });
|
|
177
|
+
* return { a, b };
|
|
178
|
+
* });
|
|
179
|
+
* parent.abort(); // Cancels entire chain
|
|
180
|
+
* ```
|
|
181
|
+
*
|
|
182
|
+
* @example Component unmount pattern
|
|
183
|
+
* ```ts
|
|
184
|
+
* const unmountController = new AbortController();
|
|
185
|
+
*
|
|
186
|
+
* // In component effect
|
|
187
|
+
* const req = abortable(
|
|
188
|
+
* (signal) => fetchUserData(signal),
|
|
189
|
+
* { signal: unmountController.signal }
|
|
190
|
+
* );
|
|
191
|
+
*
|
|
192
|
+
* // On unmount
|
|
193
|
+
* unmountController.abort();
|
|
194
|
+
* ```
|
|
195
|
+
*/
|
|
196
|
+
export declare function abortable<T>(fn: (signal: AbortSignal) => T | Promise<T>, options?: AbortableOptions): AbortablePromise<T>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/core/derived.d.ts
CHANGED
|
@@ -16,10 +16,13 @@ export interface DerivedInternalOptions {
|
|
|
16
16
|
}
|
|
17
17
|
/**
|
|
18
18
|
* Context object passed to derived atom selector functions.
|
|
19
|
-
* Provides utilities for reading atoms
|
|
19
|
+
* Provides utilities for reading atoms.
|
|
20
20
|
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
21
|
+
* Extends SelectContext with:
|
|
22
|
+
* - `ready()` - Wait for non-null values (from WithReadyContext)
|
|
23
|
+
*
|
|
24
|
+
* Note: Events now implement Atom<Promise<T>> and work directly with
|
|
25
|
+
* `read()`, `race()`, `all()` - no special `wait()` method needed.
|
|
23
26
|
*/
|
|
24
27
|
export interface DerivedContext extends SelectContext, WithReadyContext {
|
|
25
28
|
}
|
package/dist/core/effect.d.ts
CHANGED
|
@@ -5,6 +5,9 @@ import { WithReadyContext } from './withReady';
|
|
|
5
5
|
/**
|
|
6
6
|
* Context object passed to effect functions.
|
|
7
7
|
* Extends `SelectContext` with cleanup utilities.
|
|
8
|
+
*
|
|
9
|
+
* Note: Events now implement Atom<Promise<T>> and work directly with
|
|
10
|
+
* `read()`, `race()`, `all()` - no special `wait()` method needed.
|
|
8
11
|
*/
|
|
9
12
|
export interface EffectContext extends SelectContext, WithReadyContext, WithAbortContext {
|
|
10
13
|
/**
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
import { Equality, Event, EventMeta } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* Options for creating an event.
|
|
4
|
+
*
|
|
5
|
+
* @template T - The type of payload
|
|
6
|
+
*/
|
|
7
|
+
export interface EventOptions<T = void> {
|
|
8
|
+
/** Optional metadata for debugging/devtools */
|
|
9
|
+
meta?: EventMeta;
|
|
10
|
+
/**
|
|
11
|
+
* Equality function to compare payloads.
|
|
12
|
+
*
|
|
13
|
+
* When `fire(payload)` is called after the first fire:
|
|
14
|
+
* - If `equals(lastPayload, payload)` returns true → no-op (no new promise)
|
|
15
|
+
* - If `equals(lastPayload, payload)` returns false → create new resolved promise
|
|
16
|
+
*
|
|
17
|
+
* **Default: `() => false`** - every fire creates a new promise.
|
|
18
|
+
* This is important for void events where `fire()` is called multiple times.
|
|
19
|
+
*
|
|
20
|
+
* @example Dedupe identical payloads
|
|
21
|
+
* ```ts
|
|
22
|
+
* const searchEvent = event<string>({ equals: "shallow" });
|
|
23
|
+
* searchEvent.fire("hello"); // Promise1 resolves
|
|
24
|
+
* searchEvent.fire("hello"); // No-op (same value)
|
|
25
|
+
* searchEvent.fire("world"); // Promise2 created
|
|
26
|
+
* ```
|
|
27
|
+
*/
|
|
28
|
+
equals?: Equality<T>;
|
|
29
|
+
/**
|
|
30
|
+
* If true, the event can only fire once.
|
|
31
|
+
* After first fire, subsequent `fire()` calls are no-op.
|
|
32
|
+
* `next()` returns the same resolved promise forever.
|
|
33
|
+
*
|
|
34
|
+
* Useful for one-time events like initialization, login, or data load.
|
|
35
|
+
*
|
|
36
|
+
* @example
|
|
37
|
+
* ```ts
|
|
38
|
+
* const initEvent = event<Config>({ once: true });
|
|
39
|
+
* initEvent.fire(config); // Promise resolved
|
|
40
|
+
* initEvent.fire(config2); // No-op (already fired)
|
|
41
|
+
* initEvent.get(); // Same resolved promise
|
|
42
|
+
* initEvent.next(); // Same resolved promise
|
|
43
|
+
* ```
|
|
44
|
+
*/
|
|
45
|
+
once?: boolean;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Creates an event - a reactive signal that can be fired with a payload.
|
|
49
|
+
*
|
|
50
|
+
* Events implement `Atom<Promise<T>>`, so they work directly with
|
|
51
|
+
* `read()`, `race()`, `all()` in derived/effect - no wrapper needed.
|
|
52
|
+
*
|
|
53
|
+
* ## Behavior
|
|
54
|
+
*
|
|
55
|
+
* ```
|
|
56
|
+
* event<T>() created
|
|
57
|
+
* │
|
|
58
|
+
* ▼
|
|
59
|
+
* atom.value = Promise1 (pending)
|
|
60
|
+
* │
|
|
61
|
+
* fire(A) ────────────────────────────────┐
|
|
62
|
+
* │ │
|
|
63
|
+
* First fire? │
|
|
64
|
+
* │Yes │
|
|
65
|
+
* ▼ │
|
|
66
|
+
* Promise1.resolve(A) │
|
|
67
|
+
* last = { data: A } │
|
|
68
|
+
* │ │
|
|
69
|
+
* fire(B) ────────────────────────────────┤
|
|
70
|
+
* │ │
|
|
71
|
+
* !equals(A, B)? │
|
|
72
|
+
* │Yes │
|
|
73
|
+
* ▼ │
|
|
74
|
+
* atom.value = Promise2 (resolved B) │
|
|
75
|
+
* → subscribers notified │
|
|
76
|
+
* last = { data: B } │
|
|
77
|
+
* ```
|
|
78
|
+
*
|
|
79
|
+
* ## Key Features
|
|
80
|
+
*
|
|
81
|
+
* 1. **Atom-compatible**: Works with `read()`, `race()`, `all()` directly
|
|
82
|
+
* 2. **Suspend until fire**: `read(event)` suspends if promise is pending
|
|
83
|
+
* 3. **Reactive**: `fire()` triggers derived recomputation via subscription
|
|
84
|
+
* 4. **Deduplication**: Use `equals` option to skip identical payloads
|
|
85
|
+
*
|
|
86
|
+
* @template T - The type of payload (void for no payload)
|
|
87
|
+
* @param options - Optional configuration (meta, equals)
|
|
88
|
+
* @returns An Event instance that implements Atom<Promise<T>>
|
|
89
|
+
*
|
|
90
|
+
* @example Basic usage
|
|
91
|
+
* ```ts
|
|
92
|
+
* const clickEvent = event<{ x: number; y: number }>();
|
|
93
|
+
*
|
|
94
|
+
* // Fire the event
|
|
95
|
+
* clickEvent.fire({ x: 100, y: 200 });
|
|
96
|
+
*
|
|
97
|
+
* // Get last fired payload
|
|
98
|
+
* clickEvent.last(); // { x: 100, y: 200 }
|
|
99
|
+
*
|
|
100
|
+
* // Get current promise
|
|
101
|
+
* const promise = clickEvent.get();
|
|
102
|
+
* ```
|
|
103
|
+
*
|
|
104
|
+
* @example Void event (no payload)
|
|
105
|
+
* ```ts
|
|
106
|
+
* const cancelEvent = event();
|
|
107
|
+
* cancelEvent.fire(); // No payload needed
|
|
108
|
+
* cancelEvent.fire(); // Each fire creates new promise (default equals)
|
|
109
|
+
* ```
|
|
110
|
+
*
|
|
111
|
+
* @example In derived - works directly with read()
|
|
112
|
+
* ```ts
|
|
113
|
+
* const result$ = derived(({ read }) => {
|
|
114
|
+
* const data = read(submitEvent); // suspends until fire
|
|
115
|
+
* return processSubmit(data);
|
|
116
|
+
* });
|
|
117
|
+
* ```
|
|
118
|
+
*
|
|
119
|
+
* @example Race multiple events
|
|
120
|
+
* ```ts
|
|
121
|
+
* const result$ = derived(({ race }) => {
|
|
122
|
+
* const { key, value } = race({
|
|
123
|
+
* submit: submitEvent,
|
|
124
|
+
* cancel: cancelEvent,
|
|
125
|
+
* });
|
|
126
|
+
* return key === 'cancel' ? null : processSubmit(value);
|
|
127
|
+
* });
|
|
128
|
+
* ```
|
|
129
|
+
*
|
|
130
|
+
* @example With equals (dedupe identical payloads)
|
|
131
|
+
* ```ts
|
|
132
|
+
* const searchEvent = event<string>({ equals: "shallow" });
|
|
133
|
+
* searchEvent.fire("hello"); // Promise1 resolves
|
|
134
|
+
* searchEvent.fire("hello"); // No-op (same value)
|
|
135
|
+
* searchEvent.fire("world"); // Promise2 created, subscribers notified
|
|
136
|
+
* ```
|
|
137
|
+
*/
|
|
138
|
+
export declare function event<T = void>(options?: EventOptions<T>): Event<T>;
|
|
139
|
+
/**
|
|
140
|
+
* Type guard to check if a value is an Event.
|
|
141
|
+
*
|
|
142
|
+
* @param value - The value to check
|
|
143
|
+
* @returns true if the value is an Event
|
|
144
|
+
*
|
|
145
|
+
* @example
|
|
146
|
+
* ```ts
|
|
147
|
+
* if (isEvent(value)) {
|
|
148
|
+
* value.fire(payload);
|
|
149
|
+
* }
|
|
150
|
+
* ```
|
|
151
|
+
*/
|
|
152
|
+
export declare function isEvent<T = unknown>(value: unknown): value is Event<T>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Effect } from './effect';
|
|
2
|
-
import { MutableAtomMeta, DerivedAtomMeta, MutableAtom, DerivedAtom, ModuleMeta, EffectMeta, PoolMeta, Pool } from './types';
|
|
2
|
+
import { MutableAtomMeta, DerivedAtomMeta, MutableAtom, DerivedAtom, ModuleMeta, EffectMeta, PoolMeta, Pool, EventMeta, Event } from './types';
|
|
3
3
|
/**
|
|
4
4
|
* Information provided when a mutable atom is created.
|
|
5
5
|
*/
|
|
@@ -40,9 +40,22 @@ export interface EffectInfo {
|
|
|
40
40
|
instance: Effect;
|
|
41
41
|
}
|
|
42
42
|
/**
|
|
43
|
-
*
|
|
43
|
+
* Information provided when an event is created.
|
|
44
44
|
*/
|
|
45
|
-
export
|
|
45
|
+
export interface EventInfo {
|
|
46
|
+
/** Discriminator for events */
|
|
47
|
+
type: "event";
|
|
48
|
+
/** Optional key from event options (for debugging/devtools) */
|
|
49
|
+
key: string | undefined;
|
|
50
|
+
/** Optional metadata from event options */
|
|
51
|
+
meta: EventMeta | undefined;
|
|
52
|
+
/** The created event instance */
|
|
53
|
+
instance: Event<unknown>;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Union type for atom/derived/effect/event creation info.
|
|
57
|
+
*/
|
|
58
|
+
export type CreateInfo = MutableInfo | DerivedInfo | EffectInfo | PoolInfo | EventInfo;
|
|
46
59
|
/**
|
|
47
60
|
* Information provided when a module (via define()) is created.
|
|
48
61
|
*/
|
|
@@ -109,6 +109,41 @@ export declare function isFulfilled<T>(value: T | PromiseLike<T>): boolean;
|
|
|
109
109
|
* @returns true if value is a Promise in rejected state
|
|
110
110
|
*/
|
|
111
111
|
export declare function isRejected<T>(value: T | PromiseLike<T>): boolean;
|
|
112
|
+
/**
|
|
113
|
+
* Creates a Promise that is immediately resolved AND pre-cached as fulfilled.
|
|
114
|
+
* This avoids the loading→resolved flicker when trackPromise() is called.
|
|
115
|
+
*
|
|
116
|
+
* Use this instead of `Promise.resolve(value)` when you need the promise
|
|
117
|
+
* to be recognized as already-resolved by the promise tracking system.
|
|
118
|
+
*
|
|
119
|
+
* @param value - The resolved value
|
|
120
|
+
* @returns A resolved Promise with pre-populated cache state
|
|
121
|
+
*
|
|
122
|
+
* @example
|
|
123
|
+
* ```ts
|
|
124
|
+
* const promise = createResolvedPromise(42);
|
|
125
|
+
* const state = trackPromise(promise);
|
|
126
|
+
* // state.status === 'fulfilled' immediately (no loading flicker)
|
|
127
|
+
* ```
|
|
128
|
+
*/
|
|
129
|
+
export declare function createResolvedPromise<T>(value: T): Promise<T>;
|
|
130
|
+
/**
|
|
131
|
+
* Creates a Promise that is immediately rejected AND pre-cached as rejected.
|
|
132
|
+
* This avoids the loading→rejected flicker when trackPromise() is called.
|
|
133
|
+
*
|
|
134
|
+
* Note: Attaches a no-op catch to prevent unhandled rejection warnings.
|
|
135
|
+
*
|
|
136
|
+
* @param error - The rejection error
|
|
137
|
+
* @returns A rejected Promise with pre-populated cache state
|
|
138
|
+
*
|
|
139
|
+
* @example
|
|
140
|
+
* ```ts
|
|
141
|
+
* const promise = createRejectedPromise(new Error('Failed'));
|
|
142
|
+
* const state = trackPromise(promise);
|
|
143
|
+
* // state.status === 'rejected' immediately (no loading flicker)
|
|
144
|
+
* ```
|
|
145
|
+
*/
|
|
146
|
+
export declare function createRejectedPromise<T = never>(error: unknown): Promise<T>;
|
|
112
147
|
/**
|
|
113
148
|
* Gets the resolved value of a Promise if fulfilled, otherwise undefined.
|
|
114
149
|
*
|
package/dist/core/select.d.ts
CHANGED
|
@@ -103,7 +103,7 @@ export interface SelectContext extends Pipeable {
|
|
|
103
103
|
* const [user, posts] = all([user$, posts$]);
|
|
104
104
|
* ```
|
|
105
105
|
*/
|
|
106
|
-
all<A extends Atom<unknown>[]>(atoms: A): {
|
|
106
|
+
all<const A extends readonly Atom<unknown>[]>(atoms: A): {
|
|
107
107
|
[K in keyof A]: AtomValue<A[K]>;
|
|
108
108
|
};
|
|
109
109
|
/**
|
|
@@ -115,20 +115,24 @@ export interface SelectContext extends Pipeable {
|
|
|
115
115
|
* - If all atoms are loading → throws first Promise
|
|
116
116
|
*
|
|
117
117
|
* The `key` in the result identifies which atom won the race.
|
|
118
|
+
* Returns a discriminated union - checking `key` narrows `value` type.
|
|
118
119
|
*
|
|
119
120
|
* Note: race() does NOT use fallback - it's meant for first "real" settled value.
|
|
120
121
|
*
|
|
121
122
|
* @param atoms - Record of atoms to race
|
|
122
|
-
* @returns KeyedResult with winning key and value
|
|
123
|
+
* @returns KeyedResult discriminated union with winning key and value
|
|
123
124
|
*
|
|
124
125
|
* @example
|
|
125
126
|
* ```ts
|
|
126
127
|
* const result = race({ cache: cache$, api: api$ });
|
|
127
|
-
*
|
|
128
|
-
*
|
|
128
|
+
* if (result.key === "cache") {
|
|
129
|
+
* result.value; // narrowed to cache atom's type
|
|
130
|
+
* }
|
|
129
131
|
* ```
|
|
130
132
|
*/
|
|
131
|
-
race<T extends Record<string, Atom<unknown>>>(atoms: T): KeyedResult<
|
|
133
|
+
race<T extends Record<string, Atom<unknown>>>(atoms: T): KeyedResult<{
|
|
134
|
+
[K in keyof T & string]: AtomValue<T[K]>;
|
|
135
|
+
}>;
|
|
132
136
|
/**
|
|
133
137
|
* Return the first ready value (like Promise.any).
|
|
134
138
|
* Object-based - pass atoms as a record with keys.
|
|
@@ -138,20 +142,24 @@ export interface SelectContext extends Pipeable {
|
|
|
138
142
|
* - If any loading (not all errored) → throws Promise
|
|
139
143
|
*
|
|
140
144
|
* The `key` in the result identifies which atom resolved first.
|
|
145
|
+
* Returns a discriminated union - checking `key` narrows `value` type.
|
|
141
146
|
*
|
|
142
147
|
* Note: any() does NOT use fallback - it waits for a real ready value.
|
|
143
148
|
*
|
|
144
149
|
* @param atoms - Record of atoms to check
|
|
145
|
-
* @returns KeyedResult with winning key and value
|
|
150
|
+
* @returns KeyedResult discriminated union with winning key and value
|
|
146
151
|
*
|
|
147
152
|
* @example
|
|
148
153
|
* ```ts
|
|
149
154
|
* const result = any({ primary: primaryApi$, fallback: fallbackApi$ });
|
|
150
|
-
*
|
|
151
|
-
*
|
|
155
|
+
* if (result.key === "primary") {
|
|
156
|
+
* result.value; // narrowed to primary atom's type
|
|
157
|
+
* }
|
|
152
158
|
* ```
|
|
153
159
|
*/
|
|
154
|
-
any<T extends Record<string, Atom<unknown>>>(atoms: T): KeyedResult<
|
|
160
|
+
any<T extends Record<string, Atom<unknown>>>(atoms: T): KeyedResult<{
|
|
161
|
+
[K in keyof T & string]: AtomValue<T[K]>;
|
|
162
|
+
}>;
|
|
155
163
|
/**
|
|
156
164
|
* Get all atom statuses when all are settled (like Promise.allSettled).
|
|
157
165
|
* Array-based - pass atoms as an array.
|
|
@@ -168,7 +176,7 @@ export interface SelectContext extends Pipeable {
|
|
|
168
176
|
* const [userResult, postsResult] = settled([user$, posts$]);
|
|
169
177
|
* ```
|
|
170
178
|
*/
|
|
171
|
-
settled<A extends Atom<unknown>[]>(atoms: A): {
|
|
179
|
+
settled<const A extends readonly Atom<unknown>[]>(atoms: A): {
|
|
172
180
|
[K in keyof A]: SettledResult<AtomValue<A[K]>>;
|
|
173
181
|
};
|
|
174
182
|
/**
|