@adbl/cells 0.0.21 → 0.0.23
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/README.md +293 -131
- package/dist/library/classes.d.ts +339 -101
- package/dist/library/classes.js +700 -321
- package/dist/library/classes.js.map +1 -1
- package/index.js +1 -0
- package/package.json +1 -1
|
@@ -70,6 +70,133 @@ export class Cell<out T extends unknown> {
|
|
|
70
70
|
* @returns {LocalContext} A new LocalContext instance.
|
|
71
71
|
*/
|
|
72
72
|
static context: () => LocalContext;
|
|
73
|
+
/**
|
|
74
|
+
* Creates a new AsyncDerivedCell that computes its value asynchronously.
|
|
75
|
+
* The cell automatically re-computes when any of its dependencies change,
|
|
76
|
+
* with built-in support for cancellation, loading state, and error handling.
|
|
77
|
+
*
|
|
78
|
+
* @template U
|
|
79
|
+
* @param {(get: <T>(cell: Cell<T>) => T, signal: AbortSignal) => Promise<U>} callback - An async function that computes the derived value.
|
|
80
|
+
* - `get`: A function to read cell values while tracking them as dependencies.
|
|
81
|
+
* - `signal`: An AbortSignal that is aborted when a new computation starts,
|
|
82
|
+
* useful for cancelling in-flight requests.
|
|
83
|
+
* @returns {AsyncDerivedCell<U>} A new AsyncDerivedCell instance.
|
|
84
|
+
*
|
|
85
|
+
* @example
|
|
86
|
+
* ```javascript
|
|
87
|
+
* import { Cell } from '@adbl/cells';
|
|
88
|
+
*
|
|
89
|
+
* const userId = Cell.source(1);
|
|
90
|
+
*
|
|
91
|
+
* const userData = Cell.derivedAsync(async (get, signal) => {
|
|
92
|
+
* const id = get(userId); // Tracks userId as a dependency
|
|
93
|
+
* const response = await fetch(`/api/users/${id}`, { signal });
|
|
94
|
+
* return response.json();
|
|
95
|
+
* });
|
|
96
|
+
*
|
|
97
|
+
* // Access loading and error states
|
|
98
|
+
* userData.pending.listen((loading) => console.log('Loading:', loading));
|
|
99
|
+
* userData.error.listen((err) => err && console.error(err));
|
|
100
|
+
*
|
|
101
|
+
* // Get the async value
|
|
102
|
+
* const data = await userData.get();
|
|
103
|
+
* ```
|
|
104
|
+
*/
|
|
105
|
+
static derivedAsync: (callback: (get: <T_1>(cell: Cell<T_1>) => T_1, signal: AbortSignal) => Promise<U>) => AsyncDerivedCell<U>;
|
|
106
|
+
/**
|
|
107
|
+
* Creates a new AsyncTaskCell that represents a one-time asynchronous computation.
|
|
108
|
+
* Unlike derivedAsync which re-computes automatically when dependencies change,
|
|
109
|
+
* a task only executes when explicitly called via `runWith(input)`.
|
|
110
|
+
*
|
|
111
|
+
* Tasks are ideal for:
|
|
112
|
+
* - Form submissions
|
|
113
|
+
* - One-time API calls
|
|
114
|
+
* - User-triggered actions
|
|
115
|
+
* - Operations that should not auto-execute
|
|
116
|
+
*
|
|
117
|
+
* @template Input, Output
|
|
118
|
+
* @param {(input: Input, signal: AbortSignal) => Promise<Output>} fn - An async function that performs the task.
|
|
119
|
+
* - `input`: The input value passed when calling `runWith(input)`.
|
|
120
|
+
* - `signal`: An AbortSignal that is aborted when a new execution starts,
|
|
121
|
+
* useful for cancelling in-flight requests.
|
|
122
|
+
* @returns {AsyncTaskCell<Input, Output>} A new AsyncTaskCell instance.
|
|
123
|
+
*
|
|
124
|
+
* @example
|
|
125
|
+
* ```javascript
|
|
126
|
+
* // Create a task for submitting form data
|
|
127
|
+
* const submitTask = Cell.task(async (formData, signal) => {
|
|
128
|
+
* const response = await fetch('/api/submit', {
|
|
129
|
+
* method: 'POST',
|
|
130
|
+
* body: formData,
|
|
131
|
+
* signal
|
|
132
|
+
* });
|
|
133
|
+
* return response.json();
|
|
134
|
+
* });
|
|
135
|
+
*
|
|
136
|
+
* // Execute the task
|
|
137
|
+
* const result = await submitTask.runWith({ name: 'John' });
|
|
138
|
+
*
|
|
139
|
+
* // Access loading and error states
|
|
140
|
+
* submitTask.pending.listen((isPending) => {
|
|
141
|
+
* console.log('Submitting:', isPending);
|
|
142
|
+
* });
|
|
143
|
+
*
|
|
144
|
+
* submitTask.error.listen((err) => {
|
|
145
|
+
* if (err) console.error('Submission failed:', err);
|
|
146
|
+
* });
|
|
147
|
+
* ```
|
|
148
|
+
*
|
|
149
|
+
* @example
|
|
150
|
+
* ```javascript
|
|
151
|
+
* // Tasks can be used with Cell.composite for managing multiple operations
|
|
152
|
+
* const uploadTask = Cell.task(async (file) => {
|
|
153
|
+
* // Upload logic
|
|
154
|
+
* });
|
|
155
|
+
*
|
|
156
|
+
* const deleteTask = Cell.task(async (id) => {
|
|
157
|
+
* // Delete logic
|
|
158
|
+
* });
|
|
159
|
+
*
|
|
160
|
+
* const operations = Cell.composite({ upload: uploadTask, delete: deleteTask });
|
|
161
|
+
*
|
|
162
|
+
* // Track overall pending state
|
|
163
|
+
* operations.pending.listen((isPending) => {
|
|
164
|
+
* console.log('Operations in progress:', isPending);
|
|
165
|
+
* });
|
|
166
|
+
* ```
|
|
167
|
+
*/
|
|
168
|
+
static task: (fn: (input: Input, signal: AbortSignal) => Promise<Output>) => AsyncTaskCell<Input, Output>;
|
|
169
|
+
/**
|
|
170
|
+
* Joins multiple cells into a single “all-or-nothing” async unit.
|
|
171
|
+
*
|
|
172
|
+
* Each returned property only produces a new value after **every** input cell
|
|
173
|
+
* has settled for the current round, so reads like:
|
|
174
|
+
*
|
|
175
|
+
* ```js
|
|
176
|
+
* const u = await group.values.user.get();
|
|
177
|
+
* const n = await group.values.notifications.get();
|
|
178
|
+
* ```
|
|
179
|
+
*
|
|
180
|
+
* won’t observe partial updates.
|
|
181
|
+
*
|
|
182
|
+
* @template {Record<string, Cell<any>>} CellData
|
|
183
|
+
* @param {CellData} input Cells to join (may include async and sync cells).
|
|
184
|
+
* @returns {Composite<CellData>}
|
|
185
|
+
*
|
|
186
|
+
* @example
|
|
187
|
+
* const user = Cell.derivedAsync(async (get) => fetchUser(get(id)));
|
|
188
|
+
* const notifications = Cell.derivedAsync(async (get) => fetchNotifs(get(id)));
|
|
189
|
+
*
|
|
190
|
+
* const group = Cell.composite({ user, notifications });
|
|
191
|
+
*
|
|
192
|
+
* group.pending.listen(showSpinner);
|
|
193
|
+
* group.error.listen(showError);
|
|
194
|
+
* group.loaded.listen((isLoaded) => isLoaded && hideInitialSkeleton());
|
|
195
|
+
*
|
|
196
|
+
* const u = await group.values.user.get();
|
|
197
|
+
* const n = await group.values.notifications.get();
|
|
198
|
+
*/
|
|
199
|
+
static composite: (input: CellData) => Composite<CellData>;
|
|
73
200
|
/**
|
|
74
201
|
* Executes a function within a specific LocalContext.
|
|
75
202
|
* Any effects (`.listen`) or derived cells (`Cell.derived`) created synchronously
|
|
@@ -96,46 +223,6 @@ export class Cell<out T extends unknown> {
|
|
|
96
223
|
* @returns {value is Cell<T>} True if the value is an instance of Cell, false otherwise.
|
|
97
224
|
*/
|
|
98
225
|
static isCell: (value: Cell<T_1> | U) => value is Cell<T_1>;
|
|
99
|
-
/**
|
|
100
|
-
* @template T
|
|
101
|
-
* Flattens the provided value by returning the value if it is not a Cell instance, or the value of the Cell instance if it is.
|
|
102
|
-
* @param {T | Cell<T>} value - The value to be flattened.
|
|
103
|
-
* @returns {T} The flattened value.
|
|
104
|
-
*/
|
|
105
|
-
static flatten: (value: T_1 | Cell<T_1>) => T_1;
|
|
106
|
-
/**
|
|
107
|
-
* Flattens an array by applying the `flatten` function to each element.
|
|
108
|
-
* @template T
|
|
109
|
-
* @param {Array<T | Cell<T>>} array - The array to be flattened.
|
|
110
|
-
* @returns {Array<T>} A new array with the flattened elements.
|
|
111
|
-
*/
|
|
112
|
-
static flattenArray: (array: Array<T_1 | Cell<T_1>>) => Array<T_1>;
|
|
113
|
-
/**
|
|
114
|
-
* Flattens an object by applying the `flatten` function to each value.
|
|
115
|
-
* @template {object} T
|
|
116
|
-
* @param {T} object - The object to be flattened.
|
|
117
|
-
* @returns {{ [K in keyof T]: T[K] extends Cell<infer U> ? U : T[K] }} A new object with the flattened values.
|
|
118
|
-
*/
|
|
119
|
-
static flattenObject: (object: T_1) => { [K in keyof T_1]: T_1[K] extends Cell<infer U> ? U : T_1[K]; };
|
|
120
|
-
/**
|
|
121
|
-
* Wraps an asynchronous function with managed state.
|
|
122
|
-
*
|
|
123
|
-
* @template {(...args: any[]) => Promise<any>} Getter - A function that performs the asynchronous operation.
|
|
124
|
-
* @template {Parameters<Getter>[0]} [X=Parameters<Getter>[0]]
|
|
125
|
-
* @template {Awaited<ReturnType<Getter>>} [Y=Awaited<ReturnType<Getter>>]
|
|
126
|
-
* @param {Getter} getter - A function that performs the asynchronous operation.
|
|
127
|
-
* @returns {AsyncRequestAtoms<Parameters<Getter>[0], Awaited<ReturnType<Getter>>, Getter>} An object containing cells for pending, data, and error states,
|
|
128
|
-
* as well as functions to run and reload the operation.
|
|
129
|
-
*
|
|
130
|
-
* @example
|
|
131
|
-
* const { pending, data, error, run, reload } = Cell.async(async (input) => {
|
|
132
|
-
* const response = await fetch(`https://example.com/api/data?input=${input}`);
|
|
133
|
-
* return response.json();
|
|
134
|
-
* });
|
|
135
|
-
*
|
|
136
|
-
* run('input');
|
|
137
|
-
*/
|
|
138
|
-
static async<Getter extends (...args: any[]) => Promise<any>, X extends Parameters<Getter>[0] = Parameters<Getter>[0], Y extends Awaited<ReturnType<Getter>> = Awaited<ReturnType<Getter>>>(getter: Getter): AsyncRequestAtoms<Parameters<Getter>[0], Awaited<ReturnType<Getter>>, Getter>;
|
|
139
226
|
/** @type {WeakRef<this> | null} */
|
|
140
227
|
ref: WeakRef<this> | null;
|
|
141
228
|
/**
|
|
@@ -146,11 +233,6 @@ export class Cell<out T extends unknown> {
|
|
|
146
233
|
* @protected @type T
|
|
147
234
|
*/
|
|
148
235
|
protected wvalue: T;
|
|
149
|
-
/**
|
|
150
|
-
* @protected
|
|
151
|
-
* @param {T} value
|
|
152
|
-
*/
|
|
153
|
-
protected setValue(value: T): void;
|
|
154
236
|
/**
|
|
155
237
|
* Overrides `Object.prototype.valueOf()` to return the value stored in the Cell.
|
|
156
238
|
* @returns {T} The value of the Cell.
|
|
@@ -190,17 +272,6 @@ export class Cell<out T extends unknown> {
|
|
|
190
272
|
* @param {(newValue: T) => void} callback - The effect callback to remove.
|
|
191
273
|
*/
|
|
192
274
|
ignore(callback: (newValue: T) => void): void;
|
|
193
|
-
/**
|
|
194
|
-
* Checks if the cell is listening to a watcher with the specified name.
|
|
195
|
-
* @param {string} name - The name of the watcher to check for.
|
|
196
|
-
* @returns {boolean} `true` if the cell is listening to a watcher with the specified name, `false` otherwise.
|
|
197
|
-
*/
|
|
198
|
-
isListeningTo(name: string): boolean;
|
|
199
|
-
/**
|
|
200
|
-
* Removes the watcher with the specified name from the list of effects for this cell.
|
|
201
|
-
* @param {string} name - The name of the watcher to stop listening to.
|
|
202
|
-
*/
|
|
203
|
-
stopListeningTo(name: string): void;
|
|
204
275
|
/**
|
|
205
276
|
* @protected
|
|
206
277
|
* Updates the root object and notifies any registered watchers and computed dependents.
|
|
@@ -232,27 +303,18 @@ export class DerivedCell<out T extends unknown> extends Cell<T> {
|
|
|
232
303
|
/** @type {() => T} */
|
|
233
304
|
computedFn: () => T;
|
|
234
305
|
[Depth]: any;
|
|
306
|
+
[Deferred]: boolean;
|
|
235
307
|
}
|
|
236
308
|
/**
|
|
237
309
|
* @template {*} out T
|
|
238
310
|
* @extends {Cell<T>}
|
|
239
311
|
* A cell whose value can be directly modified.
|
|
240
312
|
* Source cells are the primary way to introduce reactivity.
|
|
241
|
-
* They can hold any value type and will automatically handle proxying of objects
|
|
242
|
-
* to enable deep reactivity when needed.
|
|
243
313
|
*
|
|
244
314
|
* @example
|
|
245
315
|
* ```typescript
|
|
246
316
|
* const count = Cell.source(0);
|
|
247
317
|
* ```
|
|
248
|
-
*
|
|
249
|
-
* @example
|
|
250
|
-
* ```typescript
|
|
251
|
-
* // With options
|
|
252
|
-
* const immutableCell = Cell.source(42, { immutable: true });
|
|
253
|
-
* // Will throw error:
|
|
254
|
-
* immutableCell.set(43);
|
|
255
|
-
* ```
|
|
256
318
|
*/
|
|
257
319
|
export class SourceCell<out T extends unknown> extends Cell<T> {
|
|
258
320
|
/**
|
|
@@ -267,8 +329,203 @@ export class SourceCell<out T extends unknown> extends Cell<T> {
|
|
|
267
329
|
* @param {T} value
|
|
268
330
|
*/
|
|
269
331
|
set(value: T): void;
|
|
332
|
+
}
|
|
333
|
+
/**
|
|
334
|
+
* @template {*} out T - The type of the resolved async value.
|
|
335
|
+
* @extends {DerivedCell<Promise<T>>}
|
|
336
|
+
*/
|
|
337
|
+
export class AsyncCell<out T extends unknown> extends DerivedCell<Promise<T>> {
|
|
338
|
+
/**
|
|
339
|
+
* @param {(get: <T>(cell: Cell<T>) => T, signal: AbortSignal) => Promise<T>} fn
|
|
340
|
+
*/
|
|
341
|
+
constructor(fn: (get: <T_1>(cell: Cell<T_1>) => T_1, signal: AbortSignal) => Promise<T>);
|
|
342
|
+
/**
|
|
343
|
+
* @protected
|
|
344
|
+
* Aborts the current computation if one is running.
|
|
345
|
+
* @returns {void}
|
|
346
|
+
*/
|
|
347
|
+
protected abort(): void;
|
|
348
|
+
/**
|
|
349
|
+
* Gets the AbortSignal for the current computation.
|
|
350
|
+
* @protected
|
|
351
|
+
* @returns {AbortSignal}
|
|
352
|
+
*/
|
|
353
|
+
protected get _signal(): AbortSignal;
|
|
354
|
+
/**
|
|
355
|
+
* A cell that indicates whether the async computation is currently running.
|
|
356
|
+
* @type {SourceCell<boolean>}
|
|
357
|
+
*/
|
|
358
|
+
pending: SourceCell<boolean>;
|
|
359
|
+
/**
|
|
360
|
+
* A cell that holds any error thrown during the async computation.
|
|
361
|
+
* Resets to `null` when a new computation starts.
|
|
362
|
+
* @type {SourceCell<Error | null>}
|
|
363
|
+
*/
|
|
364
|
+
error: SourceCell<Error | null>;
|
|
365
|
+
[DisposeAsyncCell](): void;
|
|
270
366
|
#private;
|
|
271
367
|
}
|
|
368
|
+
/**
|
|
369
|
+
* A derived cell that computes its value asynchronously.
|
|
370
|
+
*
|
|
371
|
+
* AsyncDerivedCell extends the reactive paradigm to asynchronous operations,
|
|
372
|
+
* automatically re-running the async computation when dependencies change.
|
|
373
|
+
* It provides built-in state management for loading and error states.
|
|
374
|
+
*
|
|
375
|
+
* Key features:
|
|
376
|
+
* - Automatic dependency tracking via the `get` function
|
|
377
|
+
* - Automatic cancellation of in-flight operations when dependencies change
|
|
378
|
+
* - Built-in `pending` cell for loading state
|
|
379
|
+
* - Built-in `error` cell for error handling
|
|
380
|
+
* - Race condition prevention through AbortSignal
|
|
381
|
+
*
|
|
382
|
+
* @template {*} out T - The type of the resolved async value.
|
|
383
|
+
* @extends {AsyncCell<T>}
|
|
384
|
+
*
|
|
385
|
+
* @example
|
|
386
|
+
* ```javascript
|
|
387
|
+
* const searchQuery = Cell.source('');
|
|
388
|
+
*
|
|
389
|
+
* const searchResults = Cell.derivedAsync(async (get, signal) => {
|
|
390
|
+
* const query = get(searchQuery);
|
|
391
|
+
* if (!query) return [];
|
|
392
|
+
*
|
|
393
|
+
* const response = await fetch(`/api/search?q=${query}`, { signal });
|
|
394
|
+
* return response.json();
|
|
395
|
+
* });
|
|
396
|
+
*
|
|
397
|
+
* // React to state changes
|
|
398
|
+
* searchResults.pending.listen((loading) => {
|
|
399
|
+
* showSpinner(loading);
|
|
400
|
+
* });
|
|
401
|
+
*
|
|
402
|
+
* searchResults.error.listen((error) => {
|
|
403
|
+
* if (error) showError(error.message);
|
|
404
|
+
* });
|
|
405
|
+
* ```
|
|
406
|
+
*/
|
|
407
|
+
export class AsyncDerivedCell<out T extends unknown> extends AsyncCell<T> {
|
|
408
|
+
/**
|
|
409
|
+
* Revalidates the async cell by recomputing its value.
|
|
410
|
+
* This will abort any in-flight computation and start a new one.
|
|
411
|
+
* @returns {void}
|
|
412
|
+
*/
|
|
413
|
+
revalidate(): void;
|
|
414
|
+
}
|
|
415
|
+
/**
|
|
416
|
+
* @template I, O
|
|
417
|
+
* @typedef {(input: I, signal: AbortSignal) => Promise<O>} MutatorFn
|
|
418
|
+
*/
|
|
419
|
+
/**
|
|
420
|
+
* A task cell that performs one-time asynchronous computations.
|
|
421
|
+
*
|
|
422
|
+
* AsyncTaskCell is designed for operations that should only execute when explicitly
|
|
423
|
+
* triggered, unlike AsyncDerivedCell which re-computes automatically. This makes it
|
|
424
|
+
* ideal for form submissions, button actions, or any user-triggered operations.
|
|
425
|
+
*
|
|
426
|
+
* Key features:
|
|
427
|
+
* - Only executes when `runWith(input)` is called
|
|
428
|
+
* - Does not deduplicate concurrent `runWith(input)` calls; each call creates
|
|
429
|
+
* an independent execution with no caching
|
|
430
|
+
* - Built-in `pending` cell for loading state (false until first execution)
|
|
431
|
+
* - Built-in `error` cell for error handling
|
|
432
|
+
* - Supports cancellation via AbortSignal (concurrent cancellations must be
|
|
433
|
+
* handled in the task function)
|
|
434
|
+
* - Can be used with Cell.composite for grouping multiple tasks
|
|
435
|
+
*
|
|
436
|
+
* @template {*} out I - The input type of the task function.
|
|
437
|
+
* @template {*} out T - The type of the resolved async value.
|
|
438
|
+
* @extends {AsyncCell<T>}
|
|
439
|
+
*
|
|
440
|
+
* @example
|
|
441
|
+
* ```javascript
|
|
442
|
+
* import { Cell } from '@adbl/cells';
|
|
443
|
+
*
|
|
444
|
+
* // Create a task for user login
|
|
445
|
+
* const loginTask = Cell.task(async (credentials, signal) => {
|
|
446
|
+
* const response = await fetch('/api/login', {
|
|
447
|
+
* method: 'POST',
|
|
448
|
+
* headers: { 'Content-Type': 'application/json' },
|
|
449
|
+
* body: JSON.stringify(credentials),
|
|
450
|
+
* signal
|
|
451
|
+
* });
|
|
452
|
+
*
|
|
453
|
+
* if (!response.ok) {
|
|
454
|
+
* throw new Error('Login failed');
|
|
455
|
+
* }
|
|
456
|
+
*
|
|
457
|
+
* return response.json();
|
|
458
|
+
* });
|
|
459
|
+
*
|
|
460
|
+
* // Execute the task
|
|
461
|
+
* loginTask.runWith({ username: 'john', password: 'secret' });
|
|
462
|
+
*
|
|
463
|
+
* // Monitor states
|
|
464
|
+
* loginTask.pending.listen((isPending) => {
|
|
465
|
+
* submitButton.disabled = isPending;
|
|
466
|
+
* submitButton.textContent = isPending ? 'Logging in...' : 'Login';
|
|
467
|
+
* });
|
|
468
|
+
*
|
|
469
|
+
* loginTask.error.listen((error) => {
|
|
470
|
+
* if (error) {
|
|
471
|
+
* errorMessage.textContent = error.message;
|
|
472
|
+
* }
|
|
473
|
+
* });
|
|
474
|
+
*
|
|
475
|
+
* loginTask.listen(async (promise) => {
|
|
476
|
+
* const user = await promise;
|
|
477
|
+
* console.log('Logged in as:', user.name);
|
|
478
|
+
* });
|
|
479
|
+
* ```
|
|
480
|
+
*
|
|
481
|
+
* @example
|
|
482
|
+
* ```javascript
|
|
483
|
+
* const fetchTask = Cell.task(async (id) => {
|
|
484
|
+
* console.log('Fetching user', id);
|
|
485
|
+
* await delay(1000);
|
|
486
|
+
* return { id, name: 'User ' + id };
|
|
487
|
+
* });
|
|
488
|
+
*
|
|
489
|
+
* // Execute the task
|
|
490
|
+
* const user = await fetchTask.runWith(1);
|
|
491
|
+
* console.log(user.name);
|
|
492
|
+
*
|
|
493
|
+
* // Execute again - each call creates a new execution
|
|
494
|
+
* const anotherUser = await fetchTask.runWith(2);
|
|
495
|
+
* ```
|
|
496
|
+
*/
|
|
497
|
+
export class AsyncTaskCell<out I extends unknown, out T extends unknown> extends AsyncCell<T> {
|
|
498
|
+
/** @param {MutatorFn<I, T>} fn */
|
|
499
|
+
constructor(fn: MutatorFn<I, T>);
|
|
500
|
+
/**
|
|
501
|
+
* Executes the task with the provided input.
|
|
502
|
+
*
|
|
503
|
+
* Each call to runWith creates a new execution of the task function.
|
|
504
|
+
* Concurrent calls are not deduplicated or cached. If you need to cancel
|
|
505
|
+
* work in progress, use the provided AbortSignal and handle it inside the
|
|
506
|
+
* task function.
|
|
507
|
+
*
|
|
508
|
+
* @param {I} input - The input value to pass to the task function.
|
|
509
|
+
* @returns {Promise<T | null>} A promise that resolves with the task result,
|
|
510
|
+
* or null if the task hasn't been executed yet.
|
|
511
|
+
*
|
|
512
|
+
* @example
|
|
513
|
+
* ```javascript
|
|
514
|
+
* const task = Cell.task(async (userId) => {
|
|
515
|
+
* const response = await fetch(`/api/users/${userId}`);
|
|
516
|
+
* return response.json();
|
|
517
|
+
* });
|
|
518
|
+
*
|
|
519
|
+
* // Execute the task
|
|
520
|
+
* const user = await task.runWith(123);
|
|
521
|
+
* console.log(user.name);
|
|
522
|
+
*
|
|
523
|
+
* // Execute again with different input
|
|
524
|
+
* const anotherUser = await task.runWith(456);
|
|
525
|
+
* ```
|
|
526
|
+
*/
|
|
527
|
+
runWith: (input: I) => Promise<T | null>;
|
|
528
|
+
}
|
|
272
529
|
/**
|
|
273
530
|
* An error class that aggregates multiple errors thrown during a cell update cycle.
|
|
274
531
|
*
|
|
@@ -290,30 +547,20 @@ export class CellUpdateError extends Error {
|
|
|
290
547
|
constructor(errors: Error[]);
|
|
291
548
|
errors: Error[];
|
|
292
549
|
}
|
|
293
|
-
export type
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
/**
|
|
303
|
-
* Represents the errors returned by the asynchronous request, if any.
|
|
304
|
-
*/
|
|
305
|
-
error: SourceCell<Error | null>;
|
|
306
|
-
/**
|
|
307
|
-
* Triggers the asynchronous request.
|
|
308
|
-
*/
|
|
309
|
-
run: Getter extends (...args: infer P) => any ? P["length"] extends 0 ? SimplePromiseFn<Output> : PromiseFnWithArgs<P, Output> : SimplePromiseFn<Output>;
|
|
550
|
+
export type ComputedFn<T> = (track: <T_1>(cell: Cell<T_1>) => T_1) => T;
|
|
551
|
+
/**
|
|
552
|
+
* An object of barrier-synchronized async derived cells. Each member waits for
|
|
553
|
+
* *all* inputs to settle before yielding.
|
|
554
|
+
*/
|
|
555
|
+
export type Composite<CellData extends Record<string, Cell<any>>> = {
|
|
556
|
+
values: { [key in keyof CellData]: CellData[key] extends AsyncDerivedCell<infer T> ? AsyncDerivedCell<T> : CellData[key] extends Cell<infer X> ? AsyncDerivedCell<X> : never; };
|
|
557
|
+
pending: Cell<boolean>;
|
|
558
|
+
error: Cell<Error | null>;
|
|
310
559
|
/**
|
|
311
|
-
*
|
|
560
|
+
* Whether the composite has completed its initial load.
|
|
312
561
|
*/
|
|
313
|
-
|
|
562
|
+
loaded: Cell<boolean>;
|
|
314
563
|
};
|
|
315
|
-
export type SimplePromiseFn<Output> = () => Promise<Output | null>;
|
|
316
|
-
export type PromiseFnWithArgs<Args extends Array<any>, Output> = (...args: Args) => Promise<Output | null>;
|
|
317
564
|
export type EffectOptions = {
|
|
318
565
|
/**
|
|
319
566
|
* Whether the effect should be removed after the first run.
|
|
@@ -323,10 +570,6 @@ export type EffectOptions = {
|
|
|
323
570
|
* An AbortSignal to be used to ignore the effect if it is aborted.
|
|
324
571
|
*/
|
|
325
572
|
signal?: AbortSignal | undefined;
|
|
326
|
-
/**
|
|
327
|
-
* The name of the effect for debugging purposes.
|
|
328
|
-
*/
|
|
329
|
-
name?: string | undefined;
|
|
330
573
|
/**
|
|
331
574
|
* Whether the effect should be weakly referenced. This means that the effect will be garbage collected if there are no other references to it.
|
|
332
575
|
*/
|
|
@@ -337,14 +580,6 @@ export type EffectOptions = {
|
|
|
337
580
|
priority?: number | undefined;
|
|
338
581
|
};
|
|
339
582
|
export type CellOptions<T> = {
|
|
340
|
-
/**
|
|
341
|
-
* Whether the cell should be immutable. If set to true, the cell will not allow updates and will throw an error if the value is changed.
|
|
342
|
-
*/
|
|
343
|
-
immutable?: boolean | undefined;
|
|
344
|
-
/**
|
|
345
|
-
* Whether the cell should watch for changes deep into the given value. By default the cell only reacts to changes at the top level.
|
|
346
|
-
*/
|
|
347
|
-
deep?: boolean | undefined;
|
|
348
583
|
/**
|
|
349
584
|
* A function that determines whether two values are equal. If not provided, the default equality function will be used.
|
|
350
585
|
*/
|
|
@@ -356,8 +591,9 @@ export type SetLike<Value extends WeakKey & {
|
|
|
356
591
|
export type MapLike<Key extends WeakKey & {
|
|
357
592
|
ref: WeakRef<any> | null;
|
|
358
593
|
}, Value> = Map<Key, Value> | WeakMap<Key, Value>;
|
|
359
|
-
|
|
360
|
-
|
|
594
|
+
export type MutatorFn<I, O> = (input: I, signal: AbortSignal) => Promise<O>;
|
|
595
|
+
/** @template {*} out T */
|
|
596
|
+
declare class Effect<out T extends unknown> {
|
|
361
597
|
/**
|
|
362
598
|
* @param {(newValue: T) => void} callback
|
|
363
599
|
* @param {EffectOptions} [options]
|
|
@@ -376,6 +612,8 @@ declare class Effect<T> {
|
|
|
376
612
|
}
|
|
377
613
|
declare const IsScheduled: unique symbol;
|
|
378
614
|
declare const Depth: unique symbol;
|
|
615
|
+
declare const Deferred: unique symbol;
|
|
616
|
+
declare const DisposeAsyncCell: unique symbol;
|
|
379
617
|
/**
|
|
380
618
|
* @template {WeakKey & { ref: WeakRef<any> | null }} Value
|
|
381
619
|
* @extends {Set<Value>}
|