@solidjs/signals 2.0.0-rc.7 → 2.0.0-rc.8

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 (117) hide show
  1. package/dist/dev-shared.js +5243 -0
  2. package/dist/dev.attribution.js +2333 -0
  3. package/dist/dev.js +1229 -6834
  4. package/dist/observe/affects.js +127 -0
  5. package/dist/observe/attribution.js +1 -0
  6. package/dist/observe/boundaries.js +586 -0
  7. package/dist/observe/core/action.js +167 -0
  8. package/dist/observe/core/async.js +736 -0
  9. package/dist/observe/core/attribution-hooks.js +60 -0
  10. package/dist/observe/core/attribution.js +2318 -0
  11. package/dist/{types-cjs/core/constants.d.cts → observe/core/constants.js} +129 -73
  12. package/dist/{types-cjs/core/context.d.cts → observe/core/context.js} +37 -12
  13. package/dist/observe/core/core.js +1289 -0
  14. package/dist/observe/core/dev.js +232 -0
  15. package/dist/observe/core/effect.js +179 -0
  16. package/dist/observe/core/error.js +80 -0
  17. package/dist/observe/core/external.js +98 -0
  18. package/dist/observe/core/graph.js +155 -0
  19. package/dist/observe/core/heap.js +147 -0
  20. package/dist/observe/core/invariants.js +43 -0
  21. package/dist/observe/core/lanes.js +168 -0
  22. package/dist/observe/core/optimistic.js +438 -0
  23. package/dist/observe/core/owner.js +308 -0
  24. package/dist/observe/core/scheduler.js +1190 -0
  25. package/dist/observe/core/verdict.js +551 -0
  26. package/dist/observe/index.js +55 -0
  27. package/dist/observe/map.js +482 -0
  28. package/dist/{types-cjs/signals.d.cts → observe/signals.js} +295 -317
  29. package/dist/observe/store/index.js +38 -0
  30. package/dist/observe/store/next/optimistic.js +651 -0
  31. package/dist/observe/store/next/projection.js +242 -0
  32. package/dist/observe/store/next/reconcile.js +373 -0
  33. package/dist/observe/store/next/store.js +2213 -0
  34. package/dist/observe/store/next/target.js +51 -0
  35. package/dist/observe/store/store.js +323 -0
  36. package/dist/observe/store/storePath.js +103 -0
  37. package/dist/observe/store/utils.js +210 -0
  38. package/dist/prod/attribution.js +32 -0
  39. package/dist/prod/core/action.js +52 -32
  40. package/dist/prod/core/async.js +171 -127
  41. package/dist/prod/core/constants.js +24 -1
  42. package/dist/prod/core/context.js +3 -3
  43. package/dist/prod/core/core.js +434 -291
  44. package/dist/prod/core/effect.js +54 -34
  45. package/dist/prod/core/external.js +2 -2
  46. package/dist/prod/core/graph.js +32 -32
  47. package/dist/prod/core/heap.js +49 -44
  48. package/dist/prod/core/lanes.js +45 -38
  49. package/dist/prod/core/optimistic.js +207 -73
  50. package/dist/prod/core/owner.js +43 -39
  51. package/dist/prod/core/scheduler.js +319 -190
  52. package/dist/prod/core/verdict.js +67 -67
  53. package/dist/prod/index.js +9 -3
  54. package/dist/prod/map.js +292 -141
  55. package/dist/prod/signals.js +7 -10
  56. package/dist/prod/store/next/optimistic.js +140 -125
  57. package/dist/prod/store/next/projection.js +3 -3
  58. package/dist/prod/store/next/reconcile.js +87 -84
  59. package/dist/prod/store/next/store.js +524 -280
  60. package/dist/prod/store/next/target.js +32 -10
  61. package/dist/prod/store/store.js +12 -14
  62. package/dist/prod/store/utils.js +36 -27
  63. package/dist/types/attribution.d.ts +15 -0
  64. package/dist/types/attribution.prod.d.ts +13 -0
  65. package/dist/types/core/async.d.ts +1 -1
  66. package/dist/types/core/attribution-hooks.d.ts +119 -6
  67. package/dist/types/core/attribution.d.ts +208 -53
  68. package/dist/types/core/constants.d.ts +23 -0
  69. package/dist/types/core/core.d.ts +7 -0
  70. package/dist/types/core/dev.d.ts +124 -26
  71. package/dist/types/core/effect.d.ts +8 -1
  72. package/dist/types/core/index.d.ts +2 -1
  73. package/dist/types/core/lanes.d.ts +8 -1
  74. package/dist/types/core/scheduler.d.ts +60 -0
  75. package/dist/types/core/types.d.ts +29 -9
  76. package/dist/types/index.d.ts +9 -2
  77. package/dist/types/map.d.ts +2 -0
  78. package/dist/types/store/index.d.ts +1 -0
  79. package/dist/types/store/next/store.d.ts +5 -0
  80. package/dist/types/store/next/target.d.ts +36 -9
  81. package/dist/types/store/utils.d.ts +7 -0
  82. package/package.json +21 -17
  83. package/dist/node.cjs +0 -10541
  84. package/dist/node.dev.cjs +0 -13724
  85. package/dist/types-cjs/affects.d.cts +0 -47
  86. package/dist/types-cjs/boundaries.d.cts +0 -175
  87. package/dist/types-cjs/core/action.d.cts +0 -64
  88. package/dist/types-cjs/core/async.d.cts +0 -23
  89. package/dist/types-cjs/core/attribution-hooks.d.cts +0 -127
  90. package/dist/types-cjs/core/attribution.d.cts +0 -495
  91. package/dist/types-cjs/core/core.d.cts +0 -185
  92. package/dist/types-cjs/core/dev.d.cts +0 -136
  93. package/dist/types-cjs/core/effect.d.cts +0 -30
  94. package/dist/types-cjs/core/error.d.cts +0 -56
  95. package/dist/types-cjs/core/external.d.cts +0 -15
  96. package/dist/types-cjs/core/graph.d.cts +0 -28
  97. package/dist/types-cjs/core/heap.d.cts +0 -24
  98. package/dist/types-cjs/core/index.d.cts +0 -13
  99. package/dist/types-cjs/core/invariants.d.cts +0 -59
  100. package/dist/types-cjs/core/lanes.d.cts +0 -54
  101. package/dist/types-cjs/core/optimistic.d.cts +0 -6
  102. package/dist/types-cjs/core/owner.d.cts +0 -124
  103. package/dist/types-cjs/core/scheduler.d.cts +0 -236
  104. package/dist/types-cjs/core/types.d.cts +0 -204
  105. package/dist/types-cjs/core/verdict.d.cts +0 -2
  106. package/dist/types-cjs/index.d.cts +0 -10
  107. package/dist/types-cjs/map.d.cts +0 -69
  108. package/dist/types-cjs/package.json +0 -3
  109. package/dist/types-cjs/store/index.d.cts +0 -18
  110. package/dist/types-cjs/store/next/optimistic.d.cts +0 -25
  111. package/dist/types-cjs/store/next/projection.d.cts +0 -8
  112. package/dist/types-cjs/store/next/reconcile.d.cts +0 -10
  113. package/dist/types-cjs/store/next/store.d.cts +0 -121
  114. package/dist/types-cjs/store/next/target.d.cts +0 -166
  115. package/dist/types-cjs/store/store.d.cts +0 -143
  116. package/dist/types-cjs/store/storePath.d.cts +0 -58
  117. package/dist/types-cjs/store/utils.d.cts +0 -74
@@ -1,4 +1,23 @@
1
- import type { Disposable, Refreshable } from "./core/index.cjs";
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, 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
- export declare function onCleanup(fn: Disposable): Disposable;
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
- /** Options for effect primitives that support deferring/scheduling their initial run (`createEffect`, `createRenderEffect`, `createReaction`). */
91
- export interface EffectOptions extends BaseEffectOptions {
92
- /** When true, defers the initial effect execution until the next change */
93
- defer?: boolean;
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
- /** Options for plain signals created with `createSignal(value)` or `createOptimistic(value)`. */
138
- export interface SignalOptions<T> {
139
- /** Debug name (dev mode only) */
140
- name?: string;
141
- /**
142
- * Custom equality function, or `false` to always notify subscribers.
143
- * Defaults to reference equality (`isEqual`). Pass a comparator (e.g.
144
- * `(a, b) => a.id === b.id`) for value-based equality, or `false` to
145
- * notify on every write regardless of equality.
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.T &= ~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
- * Options for read-only memos created with `createMemo`.
155
- * Also used in combination with `SignalOptions` for writable memos
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
- export type NoInfer<T extends any> = [T][T extends any ? 0 : never];
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
- export declare function createEffect<T>(compute: ComputeFunction<undefined | NoInfer<T>, T>, effectFn: EffectFunction<NoInfer<T>, T> | EffectBundle<NoInfer<T>, T>, options?: EffectOptions): void;
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
- export declare function createRenderEffect<T>(compute: ComputeFunction<undefined | NoInfer<T>, T>, effectFn: EffectFunction<NoInfer<T>, T>, options?: EffectOptions): void;
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
- export declare function createTrackedEffect(compute: () => void | (() => void), options?: BaseEffectOptions): void;
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
- export declare function createReaction(effectFn: EffectFunction<undefined> | EffectBundle<undefined>, options?: EffectOptions): (tracking: () => void) => void;
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
- export declare function resolve<T>(fn: () => T): Promise<T>;
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.Nt = i.C;
334
+ // notify() forwards up the normal chain
335
+ i.C = 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
+ Kt: 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
- export declare function refresh<T>(target: Refreshable<T>): Promise<T extends (...args: any) => infer V ? V : T>;
535
- /** Falsy values a truthy predicate result is narrowed against. */
536
- export type Truthy<T> = Exclude<T, false | 0 | 0n | "" | null | undefined>;
537
- export interface UntilOptions {
538
- /** Reject with `TimeoutError` if the predicate has not turned truthy within
539
- * this many milliseconds. Strongly recommended when the confirming truth
540
- * arrives over a transport that can drop (sockets, subscriptions). */
541
- timeout?: number;
542
- /** Reject with `signal.reason` on abort. */
543
- signal?: AbortSignal;
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.Nt = i.C;
449
+ i.C = 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
+ Kt: 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
@@ -596,43 +522,84 @@ export interface UntilOptions {
596
522
  *
597
523
  * @param fn a reactive predicate over authoritative state
598
524
  * @param options optional `timeout` (ms) and abort `signal`
599
- */
600
- export declare function until<T>(fn: () => T, options?: UntilOptions): Promise<Truthy<T>>;
601
- /**
602
- * Creates an optimistic signal that can be used to optimistically update a value
603
- * and then revert it back to the previous value at end of transition.
604
- *
605
- * When called with a plain value, creates an optimistic signal with `SignalOptions` (name, equals, ownedWrite, unobserved).
606
- * When called with a function, creates a writable optimistic memo with `SignalOptions & MemoOptions` (adds id, lazy).
607
- *
608
- * ```typescript
609
- * // Plain optimistic signal
610
- * const [state, setState] = createOptimistic<T>(value, options?: SignalOptions<T>);
611
- * // Writable optimistic memo (function overload)
612
- * const [state, setState] = createOptimistic<T>(fn, options?: SignalOptions<T> & MemoOptions<T>);
613
- * ```
614
- * @param value initial value of the signal; if empty, the signal's type will automatically extended with undefined
615
- * @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
616
- *
617
- * @returns `[state: Accessor<T>, setState: Setter<T>]`
618
- *
619
- * @example
620
- * ```ts
621
- * const [todos, setTodos] = createOptimistic(initialTodos);
622
- *
623
- * const addTodo = action(function* (text: string) {
624
- * const tempId = crypto.randomUUID();
625
- * setTodos(t => [...t, { id: tempId, text, pending: true }]); // optimistic
626
- * const saved = yield api.createTodo(text);
627
- * setTodos(t => t.map(x => (x.id === tempId ? saved : x))); // reconcile
628
- * });
629
- * ```
630
- *
631
- * @description https://docs.solidjs.com/reference/basic-reactivity/create-optimistic-signal
632
- */
633
- export declare function createOptimistic<T>(): Signal<T | undefined>;
634
- export declare function createOptimistic<T>(value: Exclude<T, Function>, options?: SignalOptions<T>): Signal<T>;
635
- export declare function createOptimistic<T>(fn: ComputeFunction<T>, options?: SignalOptions<T> & MemoOptions<T>): Signal<T>;
525
+ */ function until(e, t) {
526
+ // Late-bind the wakeup hook for the A17-silent ack paths (pay-for-use:
527
+ // apps that never call until() never retain it).
528
+ installAuthoritativeRead();
529
+ // Flip-entanglement (#3164 follow-up): the transaction this until() holds
530
+ // open (the action's, when yielded from one). The predicate is the user's
531
+ // declaration of what confirms it when a foreign transition's staged
532
+ // write flips it truthy, that transition merges here and reveals at the
533
+ // joint settle instead of painting the confirmation under live optimism.
534
+ const r = activeTransition;
535
+ return new Promise((n, i) => {
536
+ const o = t?.signal;
537
+ if (o?.aborted) return i(o.reason);
538
+ createRoot(c => {
539
+ // Same delivery contract as resolve() (#2930): effect applies ride a
540
+ // microtask so the promise can settle while the transaction the caller
541
+ // yielded it into is still open that transaction being open is the
542
+ // entire point of the hold.
543
+ const s = getOwner();
544
+ const u = new MicrotaskQueue;
545
+ u.Nt = s.C;
546
+ s.C = u;
547
+ let f;
548
+ let a;
549
+ const settle = e => {
550
+ if (f !== undefined) clearTimeout(f);
551
+ if (a !== undefined) o.removeEventListener("abort", a);
552
+ e();
553
+ c();
554
+ };
555
+ effect(r === null ? e : () => {
556
+ const t = e();
557
+ // Runs inside the compute (pure phase): the confirming
558
+ // transition's stamps are live and its commit hasn't run, so
559
+ // the merge lands before any reveal. Falsy evaluations skip —
560
+ // non-flipping updates were never named as the confirmation.
561
+ if (t) entangleConfirmingTransitions(getObserver(), r);
562
+ return t;
563
+ }, e => {
564
+ // Falsy is "not yet": keep the subscription live and wait for the
565
+ // next evaluation. Only a truthy settled value resolves.
566
+ if (e) settle(() => n(e));
567
+ }, e => settle(() => i(e)),
568
+ // AUTHORITATIVE_READ: overrides invisible to the predicate.
569
+ // DIRECT_COMMIT: truth that stages into the held transaction (a
570
+ // refresh the action issued) must flow through to the microtask
571
+ // apply — a staged effect value would deadlock the hold on data
572
+ // the hold itself is keeping uncommitted.
573
+ {
574
+ user: true,
575
+ Kt: CONFIG_AUTHORITATIVE_READ | CONFIG_DIRECT_COMMIT
576
+ });
577
+ if (t?.timeout !== undefined) f = setTimeout(() => settle(() => i(new TimeoutError)), t.timeout);
578
+ if (o !== undefined) {
579
+ a = () => settle(() => i(o.reason));
580
+ o.addEventListener("abort", a, {
581
+ once: true
582
+ });
583
+ }
584
+ });
585
+ });
586
+ }
587
+
588
+ function createOptimistic(e, t) {
589
+ // Install before the node exists: only engine-installed programs can carry
590
+ // an _overrideValue slot (same runtime-install pattern as
591
+ // GlobalQueue._clearOptimisticStore in createOptimisticStore).
592
+ installOptimisticEngine();
593
+ if (typeof e === "function") {
594
+ const r = optimisticComputed(e, t);
595
+ r.T &= ~CONFIG_AUTO_DISPOSE;
596
+ return [ accessor(r), setSignal.bind(null, r) ];
597
+ }
598
+ const r = optimisticSignal(e, t);
599
+ registerGraph(r, getOwner());
600
+ return [ accessor(r), setSignal.bind(null, r) ];
601
+ }
602
+
636
603
  /**
637
604
  * Schedules `callback` to run **once** after the reactive graph has fully
638
605
  * settled — i.e. once every pending async read inside the current owner has
@@ -726,6 +693,17 @@ export declare function createOptimistic<T>(fn: ComputeFunction<T>, options?: Si
726
693
  *
727
694
  * @param callback Function to run; may return a cleanup function that fires
728
695
  * on owner disposal
729
- */
730
- export declare function onSettled(callback: () => void | (() => void)): void;
731
- export {};
696
+ */ function onSettled(e) {
697
+ const t = getOwner();
698
+ t && !(t.T & CONFIG_CHILDREN_FORBIDDEN) ? trackedEffect(() => untrack(e), {
699
+ name: "onSettled"
700
+ }) : globalQueue.enqueue(EFFECT_USER, () => {
701
+ // Unowned, out-of-band fire (no owner, or a children-forbidden one this
702
+ // one-shot must not bind to): a returned cleanup has no lifecycle to
703
+ // attach to. Reject it in dev; in production the return is simply
704
+ // dropped — never bound to an unrelated owner or run eagerly.
705
+ e();
706
+ });
707
+ }
708
+
709
+ export { accessor, createEffect, createMemo, createOptimistic, createReaction, createRenderEffect, createSignal, createTrackedEffect, onCleanup, onSettled, refresh, resolve, until };