@solidjs/signals 2.0.0-rc.7 → 2.0.0-rc.9
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/dev-shared.js +6357 -0
- package/dist/dev.attribution.js +2485 -0
- package/dist/dev.js +2851 -7027
- package/dist/observe/affects.js +129 -0
- package/dist/observe/attribution.js +7 -0
- package/dist/observe/boundaries.js +641 -0
- package/dist/observe/core/action.js +177 -0
- package/dist/observe/core/async.js +846 -0
- package/dist/observe/core/attribution-costs.js +66 -0
- package/dist/observe/core/attribution-feedback.js +282 -0
- package/dist/observe/core/attribution-hooks.js +82 -0
- package/dist/observe/core/attribution-queries.js +28 -0
- package/dist/observe/core/attribution.js +2095 -0
- package/dist/observe/core/constants.js +248 -0
- package/dist/{types-cjs/core/context.d.cts → observe/core/context.js} +37 -12
- package/dist/observe/core/core.js +1789 -0
- package/dist/observe/core/dev.js +293 -0
- package/dist/observe/core/effect.js +195 -0
- package/dist/observe/core/error-hooks.js +71 -0
- package/dist/observe/core/error.js +80 -0
- package/dist/observe/core/external.js +98 -0
- package/dist/observe/core/graph.js +155 -0
- package/dist/observe/core/heap.js +147 -0
- package/dist/observe/core/invariants.js +45 -0
- package/dist/observe/core/lanes.js +205 -0
- package/dist/observe/core/optimistic.js +585 -0
- package/dist/observe/core/owner.js +322 -0
- package/dist/observe/core/scheduler.js +1428 -0
- package/dist/observe/core/verdict.js +669 -0
- package/dist/observe/index.js +59 -0
- package/dist/observe/map.js +484 -0
- package/dist/{types-cjs/signals.d.cts → observe/signals.js} +311 -317
- package/dist/observe/store/index.js +40 -0
- package/dist/observe/store/next/optimistic.js +660 -0
- package/dist/observe/store/next/projection.js +255 -0
- package/dist/observe/store/next/reconcile.js +375 -0
- package/dist/observe/store/next/store.js +2327 -0
- package/dist/observe/store/next/target.js +51 -0
- package/dist/observe/store/store.js +325 -0
- package/dist/observe/store/storePath.js +103 -0
- package/dist/observe/store/utils.js +1023 -0
- package/dist/prod/attribution.js +41 -0
- package/dist/prod/boundaries.js +128 -76
- package/dist/prod/core/action.js +65 -37
- package/dist/prod/core/async.js +324 -172
- package/dist/prod/core/constants.js +57 -1
- package/dist/prod/core/context.js +3 -3
- package/dist/prod/core/core.js +1003 -364
- package/dist/prod/core/dev.js +17 -1
- package/dist/prod/core/effect.js +76 -42
- package/dist/prod/core/error-hooks.js +71 -0
- package/dist/prod/core/external.js +4 -4
- package/dist/prod/core/graph.js +37 -37
- package/dist/prod/core/heap.js +61 -56
- package/dist/prod/core/lanes.js +107 -63
- package/dist/prod/core/optimistic.js +374 -93
- package/dist/prod/core/owner.js +62 -46
- package/dist/prod/core/scheduler.js +653 -286
- package/dist/prod/core/verdict.js +245 -127
- package/dist/prod/index.js +15 -5
- package/dist/prod/map.js +292 -141
- package/dist/prod/signals.js +29 -16
- package/dist/prod/store/next/optimistic.js +77 -55
- package/dist/prod/store/next/projection.js +31 -20
- package/dist/prod/store/next/reconcile.js +87 -84
- package/dist/prod/store/next/store.js +718 -401
- package/dist/prod/store/next/target.js +32 -10
- package/dist/prod/store/store.js +12 -14
- package/dist/prod/store/utils.js +950 -130
- package/dist/types/attribution.d.ts +20 -0
- package/dist/types/attribution.prod.d.ts +22 -0
- package/dist/types/boundaries.d.ts +10 -1
- package/dist/types/core/action.d.ts +12 -5
- package/dist/types/core/async.d.ts +1 -1
- package/dist/types/core/attribution-costs.d.ts +35 -0
- package/dist/types/core/attribution-feedback.d.ts +133 -0
- package/dist/types/core/attribution-hooks.d.ts +147 -9
- package/dist/types/core/attribution-queries.d.ts +10 -0
- package/dist/types/core/attribution.d.ts +216 -182
- package/dist/types/core/constants.d.ts +56 -0
- package/dist/types/core/core.d.ts +190 -2
- package/dist/types/core/dev.d.ts +246 -28
- package/dist/types/core/effect.d.ts +8 -1
- package/dist/types/core/error-hooks.d.ts +71 -0
- package/dist/types/core/index.d.ts +4 -1
- package/dist/types/core/invariants.d.ts +4 -0
- package/dist/types/core/lanes.d.ts +39 -5
- package/dist/types/core/scheduler.d.ts +153 -0
- package/dist/types/core/types.d.ts +32 -9
- package/dist/types/index.d.ts +10 -3
- package/dist/types/map.d.ts +2 -0
- package/dist/types/signals.d.ts +8 -0
- package/dist/types/store/index.d.ts +2 -0
- package/dist/types/store/next/optimistic.d.ts +1 -1
- package/dist/types/store/next/store.d.ts +11 -5
- package/dist/types/store/next/target.d.ts +37 -10
- package/dist/types/store/utils.d.ts +178 -0
- package/package.json +21 -17
- package/dist/node.cjs +0 -10541
- package/dist/node.dev.cjs +0 -13724
- package/dist/types-cjs/affects.d.cts +0 -47
- package/dist/types-cjs/boundaries.d.cts +0 -175
- package/dist/types-cjs/core/action.d.cts +0 -64
- package/dist/types-cjs/core/async.d.cts +0 -23
- package/dist/types-cjs/core/attribution-hooks.d.cts +0 -127
- package/dist/types-cjs/core/attribution.d.cts +0 -495
- package/dist/types-cjs/core/constants.d.cts +0 -159
- package/dist/types-cjs/core/core.d.cts +0 -185
- package/dist/types-cjs/core/dev.d.cts +0 -136
- package/dist/types-cjs/core/effect.d.cts +0 -30
- package/dist/types-cjs/core/error.d.cts +0 -56
- package/dist/types-cjs/core/external.d.cts +0 -15
- package/dist/types-cjs/core/graph.d.cts +0 -28
- package/dist/types-cjs/core/heap.d.cts +0 -24
- package/dist/types-cjs/core/index.d.cts +0 -13
- package/dist/types-cjs/core/invariants.d.cts +0 -59
- package/dist/types-cjs/core/lanes.d.cts +0 -54
- package/dist/types-cjs/core/optimistic.d.cts +0 -6
- package/dist/types-cjs/core/owner.d.cts +0 -124
- package/dist/types-cjs/core/scheduler.d.cts +0 -236
- package/dist/types-cjs/core/types.d.cts +0 -204
- package/dist/types-cjs/core/verdict.d.cts +0 -2
- package/dist/types-cjs/index.d.cts +0 -10
- package/dist/types-cjs/map.d.cts +0 -69
- package/dist/types-cjs/package.json +0 -3
- package/dist/types-cjs/store/index.d.cts +0 -18
- package/dist/types-cjs/store/next/optimistic.d.cts +0 -25
- package/dist/types-cjs/store/next/projection.d.cts +0 -8
- package/dist/types-cjs/store/next/reconcile.d.cts +0 -10
- package/dist/types-cjs/store/next/store.d.cts +0 -121
- package/dist/types-cjs/store/next/target.d.cts +0 -166
- package/dist/types-cjs/store/store.d.cts +0 -143
- package/dist/types-cjs/store/storePath.d.cts +0 -58
- package/dist/types-cjs/store/utils.d.cts +0 -74
|
@@ -1,4 +1,23 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { TimeoutError } from "./core/error.js";
|
|
2
|
+
|
|
3
|
+
import { computed, optimisticComputed, setSignal, optimisticSignal, runWithOwner, setMemo, signal, installAuthoritativeRead, markRefresh, read, untrack } from "./core/core.js";
|
|
4
|
+
|
|
5
|
+
import { cleanup, createRoot, getOwner, dispose, getObserver } from "./core/owner.js";
|
|
6
|
+
|
|
7
|
+
import { globalQueue, dirtyQueue, Queue, entangleConfirmingTransitions, activeTransition } from "./core/scheduler.js";
|
|
8
|
+
|
|
9
|
+
import { CONFIG_AUTO_DISPOSE, CONFIG_CHILDREN_FORBIDDEN, EFFECT_USER, $REFRESH, CONFIG_DIRECT_COMMIT, CONFIG_AUTHORITATIVE_READ, CONFIG_FRESH_READ } from "./core/constants.js";
|
|
10
|
+
|
|
11
|
+
import "./core/invariants.js";
|
|
12
|
+
|
|
13
|
+
import { registerGraph } from "./core/dev.js";
|
|
14
|
+
|
|
15
|
+
import "./core/verdict.js";
|
|
16
|
+
|
|
17
|
+
import { effect, trackedEffect } from "./core/effect.js";
|
|
18
|
+
|
|
19
|
+
import { installOptimisticEngine } from "./core/optimistic.js";
|
|
20
|
+
|
|
2
21
|
/**
|
|
3
22
|
* Low-level reactive-cleanup primitive. Registers a callback that runs when
|
|
4
23
|
* the surrounding owner is disposed.
|
|
@@ -37,265 +56,31 @@ import type { Disposable, Refreshable } from "./core/index.cjs";
|
|
|
37
56
|
* return resource;
|
|
38
57
|
* }
|
|
39
58
|
* ```
|
|
40
|
-
*/
|
|
41
|
-
|
|
42
|
-
/**
|
|
43
|
-
* A zero-arg getter for a reactive value. Calling it inside a tracking scope
|
|
44
|
-
* (memo, effect compute, JSX expression) subscribes the scope to changes.
|
|
45
|
-
*
|
|
46
|
-
* Reading outside any tracking scope simply returns the current value without
|
|
47
|
-
* creating a subscription.
|
|
48
|
-
*/
|
|
49
|
-
export type Accessor<T> = () => T;
|
|
50
|
-
export type SourceAccessor<T> = Refreshable<Accessor<T>>;
|
|
51
|
-
export declare function accessor<T>(node: any): SourceAccessor<T>;
|
|
52
|
-
/**
|
|
53
|
-
* A signal setter. Accepts either a new value or an updater `(prev) => next`.
|
|
54
|
-
*
|
|
55
|
-
* If the type permits `undefined`, `setState()` (no args) clears to `undefined`.
|
|
56
|
-
*
|
|
57
|
-
* To store a function as the value itself (rather than as an updater), wrap it
|
|
58
|
-
* with an updater: `setHandler(() => myHandler)`.
|
|
59
|
-
*/
|
|
60
|
-
export type Setter<in out T> = {
|
|
61
|
-
<U extends T>(...args: undefined extends T ? [] : [value: Exclude<U, Function> | ((prev: T) => U)]): undefined extends T ? undefined : U;
|
|
62
|
-
<U extends T>(value: (prev: T) => U): U;
|
|
63
|
-
<U extends T>(value: Exclude<U, Function>): U;
|
|
64
|
-
<U extends T>(value: Exclude<U, Function> | ((prev: T) => U)): U;
|
|
65
|
-
};
|
|
66
|
-
/** A `[get, set]` pair returned from `createSignal` / `createOptimistic`. */
|
|
67
|
-
export type Signal<T> = [get: SourceAccessor<T>, set: Setter<T>];
|
|
68
|
-
export type ComputeFunction<Prev, Next extends Prev = Prev> = (v: Prev) => PromiseLike<Next> | AsyncIterable<Next> | Next;
|
|
69
|
-
export type EffectFunction<Prev, Next extends Prev = Prev> = (v: Next, p?: Prev) => (() => void) | void;
|
|
70
|
-
export type EffectBundle<Prev, Next extends Prev = Prev> = {
|
|
71
|
-
effect: EffectFunction<Prev, Next>;
|
|
72
|
-
/**
|
|
73
|
-
* Intercepts compute-phase errors (thrown by the compute function or arriving
|
|
74
|
-
* from upstream sources). Effect-phase throws are NOT routed here — they are
|
|
75
|
-
* your own imperative code and escalate to the nearest error boundary.
|
|
76
|
-
*
|
|
77
|
-
* This is the error arm of the effect phase: it runs on the same queue and
|
|
78
|
-
* in the same imperative, writable scope as `effect` (signal writes are
|
|
79
|
-
* legal), receives the error the user code threw, and observes settled
|
|
80
|
-
* outcomes — an error that recovers before the effect phase runs the
|
|
81
|
-
* `effect` arm instead, and a held transition defers it like `effect`.
|
|
82
|
-
*/
|
|
83
|
-
error: (err: unknown, cleanup: () => void) => void;
|
|
84
|
-
};
|
|
85
|
-
/** Options shared by every effect primitive. */
|
|
86
|
-
interface BaseEffectOptions {
|
|
87
|
-
/** Debug name (dev mode only) */
|
|
88
|
-
name?: string;
|
|
59
|
+
*/ function onCleanup(e) {
|
|
60
|
+
return cleanup(e);
|
|
89
61
|
}
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
* When true, enqueues the initial effect callback through the effect queue instead of running
|
|
96
|
-
* it synchronously at creation. Lets the initial run participate in transitions -- if any
|
|
97
|
-
* source throws `NotReadyError` during the compute phase, the callback is held until the
|
|
98
|
-
* transition settles.
|
|
99
|
-
*
|
|
100
|
-
* Primarily for render effects that need transition-aware initial mounts (e.g. the root
|
|
101
|
-
* `insert()` in `render()`).
|
|
102
|
-
*/
|
|
103
|
-
schedule?: boolean;
|
|
104
|
-
/**
|
|
105
|
-
* Advanced. When true, asserts the compute function returns synchronous
|
|
106
|
-
* values only (never `PromiseLike` / `AsyncIterable`). Skips the
|
|
107
|
-
* async-shape probe in `recompute` for a small fixed-cost win per run.
|
|
108
|
-
* Intended for compiler emissions (`_$effect`) and library code that
|
|
109
|
-
* provably returns sync values. Returning a Promise or async iterable
|
|
110
|
-
* from a `sync: true` effect is undefined behavior — the value will be
|
|
111
|
-
* stored as-is and never awaited.
|
|
112
|
-
*/
|
|
113
|
-
sync?: boolean;
|
|
114
|
-
/**
|
|
115
|
-
* Advanced (integration tier). When true, the effect is invisible to the
|
|
116
|
-
* hydration id scheme: it inherits its parent's id instead of consuming a
|
|
117
|
-
* child slot, and during hydration its compute runs live instead of
|
|
118
|
-
* adopting the serialized server value (its first run is not frozen to
|
|
119
|
-
* the server's decision).
|
|
120
|
-
*
|
|
121
|
-
* For **client-only effects created while hydrating** — effects with no
|
|
122
|
-
* server-rendered counterpart (a router wiring link state, scroll
|
|
123
|
-
* restoration, etc.). An id-consuming node the server never created would
|
|
124
|
-
* shift every later sibling's hydration id, making serialized lookups and
|
|
125
|
-
* template claims after it miss. `transparent` is also the supported
|
|
126
|
-
* alternative to branching on hydration state
|
|
127
|
-
* (`if (hydrating) createEffect(...)`), which freezes whatever the first
|
|
128
|
-
* run decided: create the effect unconditionally and let it observe live
|
|
129
|
-
* state instead.
|
|
130
|
-
*
|
|
131
|
-
* SSR ignores this option (a server-side effect always allocates its id
|
|
132
|
-
* slot), so only mark effects the server does not create. Outside
|
|
133
|
-
* hydration it is a no-op.
|
|
134
|
-
*/
|
|
135
|
-
transparent?: boolean;
|
|
62
|
+
|
|
63
|
+
function accessor(e) {
|
|
64
|
+
const t = read.bind(null, e);
|
|
65
|
+
t[$REFRESH] = e;
|
|
66
|
+
return t;
|
|
136
67
|
}
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
equals?: false | ((prev: T, next: T) => boolean);
|
|
148
|
-
/** Suppress dev-mode warnings when writing inside an owned scope */
|
|
149
|
-
ownedWrite?: boolean;
|
|
150
|
-
/** Callback invoked when the signal loses all subscribers */
|
|
151
|
-
unobserved?: () => void;
|
|
68
|
+
|
|
69
|
+
function createSignal(e, t) {
|
|
70
|
+
if (typeof e === "function") {
|
|
71
|
+
const r = computed(e, t);
|
|
72
|
+
r.C &= ~CONFIG_AUTO_DISPOSE;
|
|
73
|
+
return [ accessor(r), setMemo.bind(null, r) ];
|
|
74
|
+
}
|
|
75
|
+
const r = signal(e, t);
|
|
76
|
+
registerGraph(r, getOwner());
|
|
77
|
+
return [ accessor(r), setSignal.bind(null, r) ];
|
|
152
78
|
}
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
* (`createSignal(fn)` / `createOptimistic(fn)`).
|
|
157
|
-
*/
|
|
158
|
-
export interface MemoOptions<T> {
|
|
159
|
-
/** Stable identifier for the owner hierarchy */
|
|
160
|
-
id?: string;
|
|
161
|
-
/** Debug name (dev mode only) */
|
|
162
|
-
name?: string;
|
|
163
|
-
/**
|
|
164
|
-
* Advanced (integration tier). When true, the memo is invisible to the
|
|
165
|
-
* hydration id scheme: it inherits its parent's id instead of consuming a
|
|
166
|
-
* child slot, and during hydration it computes live instead of adopting
|
|
167
|
-
* the serialized server value. For client-only memos with no
|
|
168
|
-
* server-rendered counterpart — see {@link EffectOptions.transparent} for
|
|
169
|
-
* the full semantics. No-op outside hydration.
|
|
170
|
-
*/
|
|
171
|
-
transparent?: boolean;
|
|
172
|
-
/**
|
|
173
|
-
* Custom equality function, or `false` to always notify subscribers.
|
|
174
|
-
* Defaults to reference equality (`isEqual`). Pass a comparator (e.g.
|
|
175
|
-
* `(a, b) => a.id === b.id`) for value-based equality, or `false` to
|
|
176
|
-
* notify on every recompute regardless of equality.
|
|
177
|
-
*/
|
|
178
|
-
equals?: false | ((prev: T, next: T) => boolean);
|
|
179
|
-
/** Callback invoked when the computed loses all subscribers */
|
|
180
|
-
unobserved?: () => void;
|
|
181
|
-
/**
|
|
182
|
-
* When true, defers the initial computation until the value is first read,
|
|
183
|
-
* **and** opts the memo into autodisposal — once it has no remaining
|
|
184
|
-
* subscribers it is torn down and recomputed from scratch on the next read.
|
|
185
|
-
* Use it for compute-on-demand values that should not retain state across
|
|
186
|
-
* idle periods. Non-lazy owned memos live for their owner's lifetime and
|
|
187
|
-
* never autodispose.
|
|
188
|
-
*/
|
|
189
|
-
lazy?: boolean;
|
|
190
|
-
/**
|
|
191
|
-
* Advanced. When true, asserts the compute function returns synchronous
|
|
192
|
-
* values only (never `PromiseLike` / `AsyncIterable`). Skips the
|
|
193
|
-
* async-shape probe in `recompute` for a small fixed-cost win per run.
|
|
194
|
-
* Intended for compiler emissions (`_$memo`) and library code that
|
|
195
|
-
* provably returns sync values. Returning a Promise or async iterable
|
|
196
|
-
* from a `sync: true` memo is undefined behavior — the value will be
|
|
197
|
-
* stored as-is and never awaited.
|
|
198
|
-
*/
|
|
199
|
-
sync?: boolean;
|
|
200
|
-
/**
|
|
201
|
-
* Commit #0: a committed value the memo is born with, shown until the
|
|
202
|
-
* compute's first real answer lands. While that first answer is in flight
|
|
203
|
-
* the memo reads as a settled value everywhere — nothing suspends to a
|
|
204
|
-
* `<Loading>` boundary, no transition is held (first-flight work is
|
|
205
|
-
* loading-class, like a boundary fallback), and `isPending(memo)` stays
|
|
206
|
-
* **false**: commit #0 answers the question by declaration, so first-load
|
|
207
|
-
* affordances are driven from the value itself (a `null` placeholder, a
|
|
208
|
-
* `skeleton: true` field, etc.). Once the first answer lands, the loading
|
|
209
|
-
* value leaves the lineage forever: refetches use normal pending semantics
|
|
210
|
-
* (stale value shown, `isPending` true, boundaries/transitions coordinate)
|
|
211
|
-
* — the canonical guard is `data.skeleton || isPending(data)`, whose two
|
|
212
|
-
* terms cover the two disjoint states.
|
|
213
|
-
*
|
|
214
|
-
* Typed strictly as `T`: to use `null`/`undefined` as the placeholder,
|
|
215
|
-
* declare it in the memo's type (e.g. `createMemo<User | null>(...)`), so
|
|
216
|
-
* every consumer sees the nullable window honestly. If the placeholder is
|
|
217
|
-
* shaped data standing in for real data, encode its provenance in the data
|
|
218
|
-
* (e.g. a `skeleton: true` field) rather than letting it impersonate truth.
|
|
219
|
-
*
|
|
220
|
-
* The loading value is also the compute's first `prev`, so `prev`-based
|
|
221
|
-
* memos fold from it.
|
|
222
|
-
*/
|
|
223
|
-
loadingValue?: T;
|
|
79
|
+
|
|
80
|
+
function createMemo(e, t) {
|
|
81
|
+
return accessor(computed(e, t));
|
|
224
82
|
}
|
|
225
|
-
|
|
226
|
-
/**
|
|
227
|
-
* Creates a simple reactive state with a getter and setter.
|
|
228
|
-
*
|
|
229
|
-
* When called with a plain value, creates a signal with `SignalOptions` (name, equals, ownedWrite, unobserved).
|
|
230
|
-
* When called with a function, creates a writable memo with `SignalOptions & MemoOptions` (adds id, lazy).
|
|
231
|
-
*
|
|
232
|
-
* ```typescript
|
|
233
|
-
* // Plain signal
|
|
234
|
-
* const [state, setState] = createSignal<T>(value, options?: SignalOptions<T>);
|
|
235
|
-
* // Writable memo (function overload)
|
|
236
|
-
* const [state, setState] = createSignal<T>(fn, initialValue?, options?: SignalOptions<T> & MemoOptions<T>);
|
|
237
|
-
* ```
|
|
238
|
-
* @param value initial value of the state; if empty, the state's type will automatically extended with undefined
|
|
239
|
-
* @param options optional object with a name for debugging purposes and equals, a comparator function for the previous and next value to allow fine-grained control over the reactivity
|
|
240
|
-
*
|
|
241
|
-
* @returns `[state: Accessor<T>, setState: Setter<T>]`
|
|
242
|
-
*
|
|
243
|
-
* @example
|
|
244
|
-
* ```ts
|
|
245
|
-
* const [count, setCount] = createSignal(0);
|
|
246
|
-
*
|
|
247
|
-
* count(); // 0
|
|
248
|
-
* setCount(1); // explicit value
|
|
249
|
-
* setCount(c => c + 1); // updater
|
|
250
|
-
* ```
|
|
251
|
-
*
|
|
252
|
-
* @example
|
|
253
|
-
* ```ts
|
|
254
|
-
* // Writable memo: starts as `fn()`, can be locally overwritten by setter.
|
|
255
|
-
* const [user, setUser] = createSignal(() => fetchUser(userId()));
|
|
256
|
-
*
|
|
257
|
-
* setUser({ ...user(), name: "Alice" }); // optimistic local edit
|
|
258
|
-
* ```
|
|
259
|
-
*
|
|
260
|
-
* @description https://docs.solidjs.com/reference/basic-reactivity/create-signal
|
|
261
|
-
*/
|
|
262
|
-
export declare function createSignal<T>(): Signal<T | undefined>;
|
|
263
|
-
export declare function createSignal<T>(value: Exclude<T, Function>, options?: SignalOptions<T>): Signal<T>;
|
|
264
|
-
export declare function createSignal<T>(fn: ComputeFunction<T>, options?: SignalOptions<T> & MemoOptions<T>): Signal<T>;
|
|
265
|
-
/**
|
|
266
|
-
* Creates a readonly derived reactive memoized signal.
|
|
267
|
-
*
|
|
268
|
-
* ```typescript
|
|
269
|
-
* const value = createMemo<T>(compute, options?: MemoOptions<T>);
|
|
270
|
-
* ```
|
|
271
|
-
* @param compute a function that receives its previous value and returns a new value used to react on a computation
|
|
272
|
-
* @param options `MemoOptions` -- id, name, equals, unobserved, lazy, transparent
|
|
273
|
-
*
|
|
274
|
-
* @example
|
|
275
|
-
* ```ts
|
|
276
|
-
* const [first, setFirst] = createSignal("Ada");
|
|
277
|
-
* const [last, setLast] = createSignal("Lovelace");
|
|
278
|
-
*
|
|
279
|
-
* const fullName = createMemo(() => `${first()} ${last()}`);
|
|
280
|
-
*
|
|
281
|
-
* fullName(); // "Ada Lovelace"
|
|
282
|
-
* ```
|
|
283
|
-
*
|
|
284
|
-
* @example
|
|
285
|
-
* ```ts
|
|
286
|
-
* // Async memo — reads surface as pending inside <Loading>
|
|
287
|
-
* const user = createMemo(async () => {
|
|
288
|
-
* const res = await fetch(`/users/${id()}`);
|
|
289
|
-
* return res.json();
|
|
290
|
-
* });
|
|
291
|
-
* ```
|
|
292
|
-
*
|
|
293
|
-
* @description https://docs.solidjs.com/reference/basic-reactivity/create-memo
|
|
294
|
-
*/
|
|
295
|
-
export declare function createMemo<T>(compute: ComputeFunction<NoInfer<T>, T>, options: MemoOptions<T> & {
|
|
296
|
-
loadingValue: T;
|
|
297
|
-
}): SourceAccessor<T>;
|
|
298
|
-
export declare function createMemo<T>(compute: ComputeFunction<undefined | NoInfer<T>, T>, options?: MemoOptions<T>): SourceAccessor<T>;
|
|
83
|
+
|
|
299
84
|
/**
|
|
300
85
|
* Creates a reactive effect with **separate compute and effect phases**.
|
|
301
86
|
*
|
|
@@ -363,8 +148,13 @@ export declare function createMemo<T>(compute: ComputeFunction<undefined | NoInf
|
|
|
363
148
|
* ```
|
|
364
149
|
*
|
|
365
150
|
* @description https://docs.solidjs.com/reference/basic-reactivity/create-effect
|
|
366
|
-
*/
|
|
367
|
-
|
|
151
|
+
*/ function createEffect(e, t, r) {
|
|
152
|
+
effect(e, t.effect || t, t.error, {
|
|
153
|
+
user: true,
|
|
154
|
+
...r
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
|
|
368
158
|
/**
|
|
369
159
|
* Creates a reactive computation that runs during the render phase as DOM elements
|
|
370
160
|
* are created and updated but not necessarily connected.
|
|
@@ -393,8 +183,10 @@ export declare function createEffect<T>(compute: ComputeFunction<undefined | NoI
|
|
|
393
183
|
* ```
|
|
394
184
|
*
|
|
395
185
|
* @description https://docs.solidjs.com/reference/secondary-primitives/create-render-effect
|
|
396
|
-
*/
|
|
397
|
-
|
|
186
|
+
*/ function createRenderEffect(e, t, r) {
|
|
187
|
+
effect(e, t, undefined, r);
|
|
188
|
+
}
|
|
189
|
+
|
|
398
190
|
/**
|
|
399
191
|
* Creates a tracked reactive effect where dependency tracking and side effects happen
|
|
400
192
|
* in the same scope.
|
|
@@ -439,8 +231,10 @@ export declare function createRenderEffect<T>(compute: ComputeFunction<undefined
|
|
|
439
231
|
* ```
|
|
440
232
|
*
|
|
441
233
|
* @description https://docs.solidjs.com/reference/secondary-primitives/create-tracked-effect
|
|
442
|
-
*/
|
|
443
|
-
|
|
234
|
+
*/ function createTrackedEffect(e, t) {
|
|
235
|
+
trackedEffect(e, t);
|
|
236
|
+
}
|
|
237
|
+
|
|
444
238
|
/**
|
|
445
239
|
* Creates a reactive computation that runs after the render phase with flexible tracking.
|
|
446
240
|
*
|
|
@@ -466,8 +260,44 @@ export declare function createTrackedEffect(compute: () => void | (() => void),
|
|
|
466
260
|
* ```
|
|
467
261
|
*
|
|
468
262
|
* @description https://docs.solidjs.com/reference/secondary-primitives/create-reaction
|
|
469
|
-
*/
|
|
470
|
-
|
|
263
|
+
*/ function createReaction(e, t) {
|
|
264
|
+
let r = undefined;
|
|
265
|
+
cleanup(() => r?.());
|
|
266
|
+
const n = getOwner();
|
|
267
|
+
// The currently armed effect node. `track()` replaces the previous
|
|
268
|
+
// subscription (1.x semantics): without disposing the superseded arm, its
|
|
269
|
+
// sources stayed live (firing the callback for replaced dependencies), each
|
|
270
|
+
// accumulated arm delivered its own fire, and un-fired arms leaked as live
|
|
271
|
+
// effect nodes until the owner disposed (#2861).
|
|
272
|
+
let i;
|
|
273
|
+
return o => {
|
|
274
|
+
if (i) {
|
|
275
|
+
dispose(i);
|
|
276
|
+
i = undefined;
|
|
277
|
+
}
|
|
278
|
+
runWithOwner(n, () => {
|
|
279
|
+
effect(() => (o(), i = getOwner()), t => {
|
|
280
|
+
i = undefined;
|
|
281
|
+
r?.();
|
|
282
|
+
const n = (e.effect || e)?.();
|
|
283
|
+
if (false && n !== undefined && typeof n !== "function") ;
|
|
284
|
+
r = n;
|
|
285
|
+
dispose(t);
|
|
286
|
+
}, e.error, {
|
|
287
|
+
...t,
|
|
288
|
+
user: true,
|
|
289
|
+
defer: true
|
|
290
|
+
});
|
|
291
|
+
});
|
|
292
|
+
};
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
/** Delivers effect applies on a microtask instead of queueing them (#2930). */ class MicrotaskQueue extends Queue {
|
|
296
|
+
enqueue(e, t) {
|
|
297
|
+
queueMicrotask(() => t(e));
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
|
|
471
301
|
/**
|
|
472
302
|
* Awaits a reactive expression and returns its first fully-settled value as a
|
|
473
303
|
* `Promise`. Pending async reads (`createMemo` returning a promise, etc.) are
|
|
@@ -488,8 +318,46 @@ export declare function createReaction(effectFn: EffectFunction<undefined> | Eff
|
|
|
488
318
|
* ```
|
|
489
319
|
*
|
|
490
320
|
* @param fn a reactive expression to resolve
|
|
491
|
-
*/
|
|
492
|
-
|
|
321
|
+
*/ function resolve(e) {
|
|
322
|
+
return new Promise((t, r) => {
|
|
323
|
+
createRoot(n => {
|
|
324
|
+
// Deliver effect applies on a microtask instead of the owner queue: an
|
|
325
|
+
// incomplete transition stashes its effect queues until it settles, but
|
|
326
|
+
// an action yielding this promise is itself what keeps the transition
|
|
327
|
+
// open — the stashed res() deadlocked the action (#2930). The compute
|
|
328
|
+
// still runs in place (under the transaction's view when created inside
|
|
329
|
+
// an action step), and status/boundary notifications keep their normal
|
|
330
|
+
// route through the inherited queue.
|
|
331
|
+
const i = getOwner();
|
|
332
|
+
const o = new MicrotaskQueue;
|
|
333
|
+
o._parent = i.T;
|
|
334
|
+
// notify() forwards up the normal chain
|
|
335
|
+
i.T = o;
|
|
336
|
+
// A user effect rather than a bare computed: computeds are pull-based and
|
|
337
|
+
// are only re-enqueued when a pending source *resolves* — a rejection just
|
|
338
|
+
// marks them errored, so nothing would re-run and the promise would never
|
|
339
|
+
// settle (#2842). The effect's error channel is notified on rejection.
|
|
340
|
+
effect(e, e => {
|
|
341
|
+
t(e);
|
|
342
|
+
n();
|
|
343
|
+
}, e => {
|
|
344
|
+
// The error arm already unwraps StatusError (#2840) — `err` is the
|
|
345
|
+
// user's original error, matching what error boundaries expose.
|
|
346
|
+
r(e);
|
|
347
|
+
n();
|
|
348
|
+
},
|
|
349
|
+
// DIRECT_COMMIT: a source settling INTO the held transaction (e.g. a
|
|
350
|
+
// refresh this action issued) stages its landing; the effect's own
|
|
351
|
+
// recompute must not stage too, or the microtask apply reads the
|
|
352
|
+
// stale mainline value and resolves with old data.
|
|
353
|
+
{
|
|
354
|
+
user: true,
|
|
355
|
+
Xt: CONFIG_DIRECT_COMMIT
|
|
356
|
+
});
|
|
357
|
+
});
|
|
358
|
+
});
|
|
359
|
+
}
|
|
360
|
+
|
|
493
361
|
/**
|
|
494
362
|
* Invalidates one reactive source, forcing it to re-execute even if its inputs
|
|
495
363
|
* haven't changed, and returns a promise for the target's NEXT QUIESCENT
|
|
@@ -530,18 +398,76 @@ export declare function resolve<T>(fn: () => T): Promise<T>;
|
|
|
530
398
|
* // Imperative settle point
|
|
531
399
|
* const fresh = await refresh(user);
|
|
532
400
|
* ```
|
|
533
|
-
*/
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
401
|
+
*/ function refresh(e) {
|
|
402
|
+
const t = e?.[$REFRESH];
|
|
403
|
+
if (!t) {
|
|
404
|
+
return Promise.resolve(undefined);
|
|
405
|
+
}
|
|
406
|
+
// Mark now, watch on a microtask. The waiter is resolve()'s machinery with
|
|
407
|
+
// two extra reader bits, but it must NOT compute at call time (effects
|
|
408
|
+
// recompute eagerly on creation): same-tick refreshes coalesce into ONE
|
|
409
|
+
// re-ask only because every mark lands before anything pulls, and eager
|
|
410
|
+
// per-call pulls turned three refreshes into three fetches. Deferred, the
|
|
411
|
+
// waiter's first read sees the coalesced state: FRESH_READ pulls the node
|
|
412
|
+
// through recompute if it is still dirty (self-deduping — a clean node
|
|
413
|
+
// no-ops, so N waiters cost one pull; this also closes the race where a
|
|
414
|
+
// waiter reads the PRE-re-ask value as settled and delivers stale), after
|
|
415
|
+
// which the read either parks on the re-ask's pending window (async — the
|
|
416
|
+
// settle walk re-runs it on every landing, equal-value and
|
|
417
|
+
// staged-under-hold included, and a rejection arrives through the effect's
|
|
418
|
+
// error channel) or serves the sync answer. AUTHORITATIVE_READ keeps an
|
|
419
|
+
// action's own optimistic override out of the delivered value. resolve()'s
|
|
420
|
+
// own eager compute is untouched: created after a refresh it still settles
|
|
421
|
+
// stale-while-revalidate (#2930) — its contract is "first settled value",
|
|
422
|
+
// not "next quiescent state".
|
|
423
|
+
|
|
424
|
+
// An authoritative reader is woken through a late-bound hook when the truth
|
|
425
|
+
// lands EQUAL to a standing override (the A17-silent path). Every setter of
|
|
426
|
+
// that reader bit must install it — until() does, and this waiter is the
|
|
427
|
+
// other one (#3303: refresh of an optimistic in an app that never called
|
|
428
|
+
// until() dereferenced the null hook).
|
|
429
|
+
installAuthoritativeRead();
|
|
430
|
+
markRefresh(t);
|
|
431
|
+
const r = new Promise((r, n) => {
|
|
432
|
+
queueMicrotask(() => {
|
|
433
|
+
// No createRoot: the microtask has no ambient owner, so the effect is
|
|
434
|
+
// naturally detached, and settle disposes the node directly — the root
|
|
435
|
+
// added ~560B of otherwise-shakeable machinery for nothing but the
|
|
436
|
+
// dev-mode NO_OWNER_EFFECT warning, so dev keeps a root husk purely to
|
|
437
|
+
// stay quiet. The waiter swaps in its microtask queue during its own
|
|
438
|
+
// first compute (before the initial apply enqueue), replacing the
|
|
439
|
+
// root-owner plumbing.
|
|
440
|
+
// Typed as the effect node, not Owner: the capture runs inside the
|
|
441
|
+
// effect's own compute, where the ambient owner IS the effect —
|
|
442
|
+
// exactly what dispose() takes.
|
|
443
|
+
let i = null;
|
|
444
|
+
const make = () => effect(() => {
|
|
445
|
+
if (i === null) {
|
|
446
|
+
i = getOwner();
|
|
447
|
+
const e = new MicrotaskQueue;
|
|
448
|
+
e._parent = i.T;
|
|
449
|
+
i.T = e;
|
|
450
|
+
}
|
|
451
|
+
return read(t);
|
|
452
|
+
}, t => {
|
|
453
|
+
r(typeof e === "function" ? t : e);
|
|
454
|
+
dispose(i);
|
|
455
|
+
}, e => {
|
|
456
|
+
n(e);
|
|
457
|
+
dispose(i);
|
|
458
|
+
}, {
|
|
459
|
+
user: true,
|
|
460
|
+
Xt: CONFIG_DIRECT_COMMIT | CONFIG_AUTHORITATIVE_READ | CONFIG_FRESH_READ
|
|
461
|
+
});
|
|
462
|
+
make();
|
|
463
|
+
});
|
|
464
|
+
});
|
|
465
|
+
// Fire-and-forget refresh must not turn a failed refetch into an unhandled
|
|
466
|
+
// rejection; awaiting callers attach their own handlers to `promise`.
|
|
467
|
+
r.catch(() => {});
|
|
468
|
+
return r;
|
|
544
469
|
}
|
|
470
|
+
|
|
545
471
|
/**
|
|
546
472
|
* Awaits a reactive predicate and resolves the first time it settles *truthy*,
|
|
547
473
|
* with that (narrowed) value. Falsy results and pending async reads both mean
|
|
@@ -582,12 +508,20 @@ export interface UntilOptions {
|
|
|
582
508
|
*
|
|
583
509
|
* Must be called *outside* a tracking scope.
|
|
584
510
|
*
|
|
511
|
+
* Inside an action, call it from a step: after an `await`, put a bare `yield`
|
|
512
|
+
* before `yield until(...)`. The runtime cannot hook an async generator's
|
|
513
|
+
* `await` continuation, so the `until(...)` expression — which CREATES the
|
|
514
|
+
* predicate's reader — would otherwise run outside the transaction; created
|
|
515
|
+
* there it is born held (A29) and replays only at the commit its own promise
|
|
516
|
+
* holds open (#3482). See {@link action}.
|
|
517
|
+
*
|
|
585
518
|
* @example
|
|
586
519
|
* ```ts
|
|
587
520
|
* const send = action(async function* (text: string) {
|
|
588
521
|
* const clientId = crypto.randomUUID();
|
|
589
522
|
* setMessages(m => { m.push({ clientId, text, pending: true }); }); // optimistic
|
|
590
523
|
* await socket.send({ clientId, text }); // fire-and-forget transport
|
|
524
|
+
* yield; // re-enter the transaction after the await
|
|
591
525
|
* // Hold until the live source echoes the write (authoritative view —
|
|
592
526
|
* // the optimistic row above cannot satisfy this):
|
|
593
527
|
* yield until(() => messages.some(m => m.clientId === clientId), { timeout: 10_000 });
|
|
@@ -596,43 +530,84 @@ export interface UntilOptions {
|
|
|
596
530
|
*
|
|
597
531
|
* @param fn a reactive predicate over authoritative state
|
|
598
532
|
* @param options optional `timeout` (ms) and abort `signal`
|
|
599
|
-
*/
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
533
|
+
*/ function until(e, t) {
|
|
534
|
+
// Late-bind the wakeup hook for the A17-silent ack paths (pay-for-use:
|
|
535
|
+
// apps that never call until() never retain it).
|
|
536
|
+
installAuthoritativeRead();
|
|
537
|
+
// Flip-entanglement (#3164 follow-up): the transaction this until() holds
|
|
538
|
+
// open (the action's, when yielded from one). The predicate is the user's
|
|
539
|
+
// declaration of what confirms it — when a foreign transition's staged
|
|
540
|
+
// write flips it truthy, that transition merges here and reveals at the
|
|
541
|
+
// joint settle instead of painting the confirmation under live optimism.
|
|
542
|
+
const r = activeTransition;
|
|
543
|
+
return new Promise((n, i) => {
|
|
544
|
+
const o = t?.signal;
|
|
545
|
+
if (o?.aborted) return i(o.reason);
|
|
546
|
+
createRoot(c => {
|
|
547
|
+
// Same delivery contract as resolve() (#2930): effect applies ride a
|
|
548
|
+
// microtask so the promise can settle while the transaction the caller
|
|
549
|
+
// yielded it into is still open — that transaction being open is the
|
|
550
|
+
// entire point of the hold.
|
|
551
|
+
const u = getOwner();
|
|
552
|
+
const s = new MicrotaskQueue;
|
|
553
|
+
s._parent = u.T;
|
|
554
|
+
u.T = s;
|
|
555
|
+
let f;
|
|
556
|
+
let a;
|
|
557
|
+
const settle = e => {
|
|
558
|
+
if (f !== undefined) clearTimeout(f);
|
|
559
|
+
if (a !== undefined) o.removeEventListener("abort", a);
|
|
560
|
+
e();
|
|
561
|
+
c();
|
|
562
|
+
};
|
|
563
|
+
effect(r === null ? e : () => {
|
|
564
|
+
const t = e();
|
|
565
|
+
// Runs inside the compute (pure phase): the confirming
|
|
566
|
+
// transition's stamps are live and its commit hasn't run, so
|
|
567
|
+
// the merge lands before any reveal. Falsy evaluations skip —
|
|
568
|
+
// non-flipping updates were never named as the confirmation.
|
|
569
|
+
if (t) entangleConfirmingTransitions(getObserver(), r);
|
|
570
|
+
return t;
|
|
571
|
+
}, e => {
|
|
572
|
+
// Falsy is "not yet": keep the subscription live and wait for the
|
|
573
|
+
// next evaluation. Only a truthy settled value resolves.
|
|
574
|
+
if (e) settle(() => n(e));
|
|
575
|
+
}, e => settle(() => i(e)),
|
|
576
|
+
// AUTHORITATIVE_READ: overrides invisible to the predicate.
|
|
577
|
+
// DIRECT_COMMIT: truth that stages into the held transaction (a
|
|
578
|
+
// refresh the action issued) must flow through to the microtask
|
|
579
|
+
// apply — a staged effect value would deadlock the hold on data
|
|
580
|
+
// the hold itself is keeping uncommitted.
|
|
581
|
+
{
|
|
582
|
+
user: true,
|
|
583
|
+
Xt: CONFIG_AUTHORITATIVE_READ | CONFIG_DIRECT_COMMIT
|
|
584
|
+
});
|
|
585
|
+
if (t?.timeout !== undefined) f = setTimeout(() => settle(() => i(new TimeoutError)), t.timeout);
|
|
586
|
+
if (o !== undefined) {
|
|
587
|
+
a = () => settle(() => i(o.reason));
|
|
588
|
+
o.addEventListener("abort", a, {
|
|
589
|
+
once: true
|
|
590
|
+
});
|
|
591
|
+
}
|
|
592
|
+
});
|
|
593
|
+
});
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
function createOptimistic(e, t) {
|
|
597
|
+
// Install before the node exists: only engine-installed programs can carry
|
|
598
|
+
// an _overrideValue slot (same runtime-install pattern as
|
|
599
|
+
// GlobalQueue._clearOptimisticStore in createOptimisticStore).
|
|
600
|
+
installOptimisticEngine();
|
|
601
|
+
if (typeof e === "function") {
|
|
602
|
+
const r = optimisticComputed(e, t);
|
|
603
|
+
r.C &= ~CONFIG_AUTO_DISPOSE;
|
|
604
|
+
return [ accessor(r), setSignal.bind(null, r) ];
|
|
605
|
+
}
|
|
606
|
+
const r = optimisticSignal(e, t);
|
|
607
|
+
registerGraph(r, getOwner());
|
|
608
|
+
return [ accessor(r), setSignal.bind(null, r) ];
|
|
609
|
+
}
|
|
610
|
+
|
|
636
611
|
/**
|
|
637
612
|
* Schedules `callback` to run **once** after the reactive graph has fully
|
|
638
613
|
* settled — i.e. once every pending async read inside the current owner has
|
|
@@ -726,6 +701,25 @@ export declare function createOptimistic<T>(fn: ComputeFunction<T>, options?: Si
|
|
|
726
701
|
*
|
|
727
702
|
* @param callback Function to run; may return a cleanup function that fires
|
|
728
703
|
* on owner disposal
|
|
729
|
-
*/
|
|
730
|
-
|
|
731
|
-
|
|
704
|
+
*/ function onSettled(e) {
|
|
705
|
+
const t = getOwner();
|
|
706
|
+
t && !(t.C & CONFIG_CHILDREN_FORBIDDEN) ? trackedEffect(() => untrack(e), {
|
|
707
|
+
name: "onSettled"
|
|
708
|
+
}) : globalQueue.enqueue(EFFECT_USER, function fire() {
|
|
709
|
+
// Settled means derived. A settle that reverts optimism (or replays
|
|
710
|
+
// gated reads) only enqueues the affected subscribers; the pass after
|
|
711
|
+
// the commit re-derives them. Fired in the commit pass, the callback
|
|
712
|
+
// read the optimistic source already reverted beside a sync memo of it
|
|
713
|
+
// still holding the optimistic value — reads do not pull (#3411). Fall
|
|
714
|
+
// to the next pass while the heap has work; `run` swapped the queue,
|
|
715
|
+
// so this lands there, and `enqueue` keeps the drain alive.
|
|
716
|
+
if (dirtyQueue.EE >= dirtyQueue.Ct) return globalQueue.enqueue(EFFECT_USER, fire);
|
|
717
|
+
// Unowned, out-of-band fire (no owner, or a children-forbidden one this
|
|
718
|
+
// one-shot must not bind to): a returned cleanup has no lifecycle to
|
|
719
|
+
// attach to. Reject it in dev; in production the return is simply
|
|
720
|
+
// dropped — never bound to an unrelated owner or run eagerly.
|
|
721
|
+
e();
|
|
722
|
+
});
|
|
723
|
+
}
|
|
724
|
+
|
|
725
|
+
export { accessor, createEffect, createMemo, createOptimistic, createReaction, createRenderEffect, createSignal, createTrackedEffect, onCleanup, onSettled, refresh, resolve, until };
|