@solidjs/signals 2.0.0-rc.17 → 2.0.0-rc.19

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 (71) hide show
  1. package/dist/dev-shared.js +426 -241
  2. package/dist/dev.attribution.js +19 -16
  3. package/dist/dev.js +768 -409
  4. package/dist/observe/boundaries.js +88 -67
  5. package/dist/observe/core/action.js +8 -0
  6. package/dist/observe/core/async.js +183 -138
  7. package/dist/observe/core/attribution.js +30 -28
  8. package/dist/observe/core/constants.js +23 -1
  9. package/dist/observe/core/core.js +185 -157
  10. package/dist/observe/core/effect.js +34 -37
  11. package/dist/observe/core/graph.js +8 -8
  12. package/dist/observe/core/heap.js +5 -5
  13. package/dist/observe/core/lanes.js +104 -84
  14. package/dist/observe/core/owner.js +17 -16
  15. package/dist/observe/core/scheduler.js +61 -47
  16. package/dist/observe/core/truth.js +6 -6
  17. package/dist/observe/core/verdict.js +15 -15
  18. package/dist/observe/deferred.js +40 -38
  19. package/dist/observe/from.js +248 -0
  20. package/dist/observe/index.js +4 -2
  21. package/dist/observe/map.js +22 -22
  22. package/dist/observe/reveal.js +5 -5
  23. package/dist/observe/signals.js +57 -15
  24. package/dist/observe/store/affects.js +1 -1
  25. package/dist/observe/store/hooks.js +3 -0
  26. package/dist/observe/store/optimistic.js +11 -11
  27. package/dist/observe/store/projection.js +34 -21
  28. package/dist/observe/store/reconcile.js +138 -122
  29. package/dist/observe/store/store.js +628 -641
  30. package/dist/observe/store/target.js +1 -5
  31. package/dist/observe/store/utils.js +7 -2
  32. package/dist/prod/boundaries.js +153 -132
  33. package/dist/prod/core/action.js +8 -0
  34. package/dist/prod/core/async.js +242 -197
  35. package/dist/prod/core/constants.js +16 -1
  36. package/dist/prod/core/core.js +166 -138
  37. package/dist/prod/core/effect.js +31 -34
  38. package/dist/prod/core/graph.js +5 -5
  39. package/dist/prod/core/heap.js +12 -12
  40. package/dist/prod/core/lanes.js +98 -78
  41. package/dist/prod/core/owner.js +15 -14
  42. package/dist/prod/core/scheduler.js +64 -50
  43. package/dist/prod/core/truth.js +6 -6
  44. package/dist/prod/core/verdict.js +17 -17
  45. package/dist/prod/deferred.js +40 -38
  46. package/dist/prod/from.js +248 -0
  47. package/dist/prod/index.js +4 -2
  48. package/dist/prod/map.js +14 -14
  49. package/dist/prod/reveal.js +8 -8
  50. package/dist/prod/signals.js +46 -4
  51. package/dist/prod/store/affects.js +1 -1
  52. package/dist/prod/store/hooks.js +3 -0
  53. package/dist/prod/store/optimistic.js +16 -16
  54. package/dist/prod/store/projection.js +22 -9
  55. package/dist/prod/store/reconcile.js +138 -122
  56. package/dist/prod/store/store.js +308 -331
  57. package/dist/prod/store/target.js +13 -17
  58. package/dist/prod/store/utils.js +2 -0
  59. package/dist/types/core/action.d.ts +8 -0
  60. package/dist/types/core/async.d.ts +12 -2
  61. package/dist/types/core/constants.d.ts +25 -0
  62. package/dist/types/core/core.d.ts +33 -4
  63. package/dist/types/core/dev.d.ts +1 -1
  64. package/dist/types/core/index.d.ts +1 -1
  65. package/dist/types/core/lanes.d.ts +5 -1
  66. package/dist/types/core/scheduler.d.ts +17 -3
  67. package/dist/types/from.d.ts +47 -0
  68. package/dist/types/index.d.ts +4 -1
  69. package/dist/types/signals.d.ts +37 -0
  70. package/dist/types/store/target.d.ts +2 -0
  71. package/package.json +1 -1
@@ -17,31 +17,27 @@ const $OWNER = Symbol(0);
17
17
  /** raw → target for plain (family-less) stores. Family stores use their own
18
18
  * map so one raw can wrap once per family (§7b). */ const storeLookup = new WeakMap;
19
19
 
20
- function setLookup(e, o) {
21
- (o.fam?.map ?? storeLookup).set(e, o);
20
+ function setLookup(o, e) {
21
+ (e.fam?.map ?? storeLookup).set(o, e);
22
22
  }
23
23
 
24
- function isOwned(e) {
25
- return e[$OWNER] !== undefined;
24
+ function isOwned(o) {
25
+ return o[$OWNER] !== undefined;
26
26
  }
27
27
 
28
28
  /** The target wrapping `raw` in `fam` (or the plain lookup). An owned raw
29
- * answers from its stamp; a user raw from the map. */ function lookupTarget(e, o) {
30
- const t = e[$OWNER];
31
- return t !== undefined && t.fam === o ? t : (o?.map ?? storeLookup).get(e);
32
- }
33
-
34
- function devAssertNeverUserMutation(e) {
35
- return;
29
+ * answers from its stamp; a user raw from the map. */ function lookupTarget(o, e) {
30
+ const n = o[$OWNER];
31
+ return n !== undefined && n.fam === e ? n : (e?.map ?? storeLookup).get(o);
36
32
  }
37
33
 
38
34
  /** Sticky descendants flag up the parent chain (§6d): adoption descends
39
- * into a changed child pair only where a target with nodes exists below. */ function markDescendants(e) {
40
- let o = e;
41
- while (o && !o.d) {
42
- o.d = true;
43
- o = o.u;
35
+ * into a changed child pair only where a target with nodes exists below. */ function markDescendants(o) {
36
+ let e = o;
37
+ while (e && !e.d) {
38
+ e.d = true;
39
+ e = e.u;
44
40
  }
45
41
  }
46
42
 
47
- export { $OWNER, devAssertNeverUserMutation, isOwned, lookupTarget, markDescendants, setLookup, storeLookup };
43
+ export { $OWNER, isOwned, lookupTarget, markDescendants, setLookup, storeLookup };
@@ -921,6 +921,8 @@ const omitTraps = {
921
921
  f++;
922
922
  i = o;
923
923
  if (typeof o === "function") {
924
+ // Observe tiers name it and exempt it from UNSTABLE_MEMO_OUTPUT (see
925
+ // CONFIG_KEY_BAG); prod passes no options.
924
926
  n[r] = createMemo(o);
925
927
  t[r++] = SOURCE_MEMO;
926
928
  continue;
@@ -40,6 +40,14 @@
40
40
  * yield until(() => todos.some(t => t.id === saved.id));
41
41
  * ```
42
42
  *
43
+ * The same holds inside an async helper the action yields
44
+ * (`yield (async () => { ... })()`): everything after its first `await` runs
45
+ * outside the transaction. An `await refresh(x)` or `await until(...)` there
46
+ * waits for this action's commit, which waits on the helper, so it hangs
47
+ * whenever `x` re-ran during the action (#4263) and works otherwise. Call
48
+ * `refresh(x)` in the generator once the helper returns; `yield` it only when
49
+ * the action needs the fresh value.
50
+ *
43
51
  * (For the same reason, don't call `flush()` inside an action body — it
44
52
  * cannot reveal the held writes and is refused.)
45
53
  *
@@ -27,12 +27,22 @@ export declare function settlePendingSource(el: Computed<any>, source?: Computed
27
27
  export declare function isThenable<T>(value: T | PromiseLike<T>): value is PromiseLike<T>;
28
28
  /** Fire and clear a node's iterator-flight cancellation hook (#3122). */
29
29
  export declare function releaseFlightTeardown(el: Computed<any>): void;
30
+ /**
31
+ * Internal (not a package export): run `fn` when the current pass's flight
32
+ * is superseded, at the same instant as the iterator close above, instead of
33
+ * when the replacing pass commits (owner cleanups wait for that). Chains onto
34
+ * the node's teardown slot; fires once with it. A no-op unless the ambient
35
+ * owner is a computed in its own pass. `consumeIterator` fills the slot
36
+ * before its first pull, so a source opened in an async generator's body
37
+ * (`for await`) composes after the generator's close.
38
+ */
39
+ export declare function onSupersede(fn: () => void): void;
30
40
  export declare function handleAsync<T>(el: Computed<T>, result: T | PromiseLike<T> | AsyncIterable<T>, setter?: (value: T) => void, onError?: (error: unknown, pending: boolean) => void): T;
31
41
  export declare function clearStatus(el: Computed<any>, clearUninitialized?: boolean): void;
32
- export declare function notifyStatus(el: Computed<any>, status: number, error: any, blockStatus?: boolean): void;
42
+ export declare function notifyStatus(el: Computed<any>, status: number, error: any): void;
33
43
  /** The dependents' half of `notifyStatus`: `el`'s status reaches each
34
44
  * subscriber as a propagated mark (or a re-derive). On its own for a store
35
45
  * family's leaves, which are not the derive's dependents — the family
36
46
  * propagates the derive's status from each leaf to the leaf's readers
37
47
  * (store/projection.ts `wakeFamily`), exactly as a memo's would reach its. */
38
- export declare function propagateStatus(el: Computed<any>, status: number, error: any, downstreamBlockStatus?: boolean): void;
48
+ export declare function propagateStatus(el: Computed<any>, status: number, error: any): void;
@@ -185,10 +185,30 @@ export declare const CONFIG_WIDE: number;
185
185
  * creation by dev builds only (the observe artifact mangles the option name,
186
186
  * as it does `_wide`). */
187
187
  export declare const CONFIG_SUPERSEDES: number;
188
+ /** Observe tiers only: the memo `merge()` creates for a function source — a
189
+ * key bag readers consume key by key, built by the framework (a compiled
190
+ * component spread) with options no user can reach. The attribution engine's
191
+ * UNSTABLE_MEMO_OUTPUT skips it: a fresh-but-equal bag is the idiom
192
+ * (`{...(on() ? { a } : {})}`), and the advice (`equals`) cannot be applied
193
+ * (#4256). Set through `_extraConfig` by observe builds only. */
194
+ export declare const CONFIG_KEY_BAG: number;
195
+ /** The frame (rule 3, D-3): a render effect (set at creation, as
196
+ * `EFFECT_RENDER << 23` — keep the two in step), and a boundary's tree and
197
+ * output (boundaries.ts) — structure between the content and the render
198
+ * effect that shows it, not a user derivation of the content. Outside a
199
+ * hold's own flush it reads that hold's values as committed and is
200
+ * re-derived at its landing, and a re-pass of it publishes mainline: it
201
+ * joins nothing, so two mounts under one boundary made in separate flushes
202
+ * keep their holds apart (D-4, S-5 rows 1′–3′, #4283). */
203
+ export declare const CONFIG_FRAME: number;
188
204
  export declare const STATUS_NONE = 0;
189
205
  export declare const STATUS_PENDING: number;
190
206
  export declare const STATUS_ERROR: number;
191
207
  export declare const STATUS_UNINITIALIZED: number;
208
+ /** An error that answered a node's first read (no value has ever landed):
209
+ * the error, not UNINITIALIZED, is its status while shown, but a re-ask
210
+ * makes it uninitialized-pending again — it still has no value (#4244). */
211
+ export declare const STATUS_NO_VALUE: number;
192
212
  /** `catchHook`'s answer when the catcher is a boundary re-armed by
193
213
  * `on` (truthy, as any catch): what it collects is its own, not the hold's. */
194
214
  export declare const CAUGHT_REARMED = 2;
@@ -219,3 +239,8 @@ export declare const $REFRESH: unique symbol;
219
239
  export type Refreshable<T> = T & {
220
240
  readonly [$REFRESH]: any;
221
241
  };
242
+ /** `Set` under a module binding. Bundlers mark a bare `new Set()` pure with
243
+ * a `/* @__PURE__ *\/` comment that survives minification (16 bytes a site);
244
+ * a construction through a binding carries none. Same constructor, so the
245
+ * same objects. */
246
+ export declare const NewSet: SetConstructor;
@@ -20,7 +20,20 @@ export declare let context: Owner | null;
20
20
  export declare let snapshotCaptureActive: boolean;
21
21
  export declare let snapshotSources: Set<any> | null;
22
22
  export declare function setSnapshotCapture(active: boolean): void;
23
- export declare function markSnapshotScope(owner: Owner): void;
23
+ /**
24
+ * Marks `owner` a snapshot scope: while capture is on, the readers created
25
+ * under it serve each source's snapshot (the value it had when hydration
26
+ * began) and replay at `releaseSnapshotScope`.
27
+ *
28
+ * With `served` (hydration), `owner` is instead a hydrated computed and
29
+ * `served` its server answer — what the server rendered every reader of the
30
+ * node with — landing after the node was created pending (so the creation
31
+ * arm skipped it). It becomes the node's snapshot when it has none, whether
32
+ * the node committed the answer or a client write had already taken its
33
+ * compute over. A claim made later reads the value its markup shows, and
34
+ * replays the node's own value at its release, as for a written signal.
35
+ */
36
+ export declare function markSnapshotScope(owner: Owner, served?: unknown): void;
24
37
  export declare function releaseSnapshotScope(owner: Owner): void;
25
38
  export declare function clearSnapshots(): void;
26
39
  export declare function recompute(el: Computed<any>, create?: boolean): void;
@@ -68,13 +81,13 @@ export declare function createEffectNode<T>(fn: (prev?: T) => T, effectFn: (val:
68
81
  * channel (`_x._notifyStatus`) went with them; effects are the only
69
82
  * display consumers.
70
83
  */
71
- export declare let effectStatusNotify: ((this: any, status?: number, error?: any) => void) | null;
84
+ export declare let effectStatusNotify: ((this: any) => void) | null;
72
85
  export declare function setEffectStatusNotify(fn: NonNullable<typeof effectStatusNotify>): void;
73
86
  /** Resolve a node's status notifier: effect nodes (`_type` — EFFECT_PURE is
74
87
  * 0, and only effect literals carry the field) get the shared notifier.
75
88
  * Presence doubles as the "display consumer" membership test in the status
76
89
  * walks, exactly as the per-node field did when every effect carried one. */
77
- export declare function statusNotifierOf(el: any): ((this: any, status?: number, error?: any) => void) | undefined;
90
+ export declare function statusNotifierOf(el: any): ((this: any) => void) | null;
78
91
  export declare function signal<T>(v: T, options?: NodeOptions<T>): Signal<T>;
79
92
  export declare function isEqual<T>(a: T, b: T): boolean;
80
93
  /** A store slot node (CONFIG_SLOT_NODE): the whole node in ONE literal — the
@@ -128,7 +141,23 @@ export declare let disposalDepth: number;
128
141
  export declare function enterDisposal(): void;
129
142
  export declare function exitDisposal(): void;
130
143
  export declare function resetDisposalDepth(): void;
131
- export declare function setStrictRead(v: string | false): string | false;
144
+ /**
145
+ * Dev-only: the DOM event being dispatched when the open strict-read window
146
+ * opened (`globalThis.event`; null between dispatches and off the main
147
+ * thread's Window), or `ANY_EVENT` when the window did not record one. A DOM
148
+ * call made in an effect callback that dispatches events synchronously
149
+ * (`el.focus()`, `el.click()`, `dialog.showModal()`) runs that event's
150
+ * handlers inside the window; a handler is a one-shot snapshot whoever
151
+ * dispatched the event, so a read made while a different event is current is
152
+ * outside the window (#4235). Only queued effect runs record the event, read
153
+ * once per queue (the getter is costly under jsdom); `strictReadActive` is
154
+ * the check.
155
+ */
156
+ export declare let strictReadEvent: unknown;
157
+ export declare const dispatchingEvent: () => unknown;
158
+ export declare function setStrictRead(v: string | false, event?: unknown): string | false;
159
+ /** Dev-only: is the strict-read window open for a read made now? */
160
+ export declare function strictReadActive(): boolean;
132
161
  /**
133
162
  * Runs `fn` outside of any reactive tracking — reads inside `fn` will not
134
163
  * subscribe the current scope. Returns whatever `fn` returns.
@@ -16,7 +16,7 @@ export interface DevHooks {
16
16
  * `warn`/`error` as failures unless they opt in to `info`.
17
17
  */
18
18
  export type DiagnosticSeverity = "info" | "warn" | "error";
19
- export type DiagnosticCode = "STRICT_READ_UNTRACKED" | "PENDING_ASYNC_UNTRACKED_READ" | "PENDING_ASYNC_FORBIDDEN_SCOPE" | "REACTIVE_WRITE_IN_OWNED_SCOPE" | "ASYNC_STORE_SETTER" | "STORE_WRITE_OUTSIDE_SETTER" | "ACTION_CALLED_IN_OWNED_SCOPE" | "RUN_WITH_DISPOSED_OWNER" | "NO_OWNER_CLEANUP" | "CLEANUP_IN_FORBIDDEN_SCOPE" | "SETTLED_CLEANUP_UNOWNED" | "SETTLE_WALK_UNINITIALIZED_SOURCE" | "FLUSH_IN_EFFECT_CALLBACK" | "PRIMITIVE_IN_FORBIDDEN_SCOPE" | "PRIMITIVE_IN_EFFECT_CALLBACK" | "NO_OWNER_EFFECT" | "NO_OWNER_BOUNDARY" | "ASYNC_OUTSIDE_LOADING_BOUNDARY" | "LOADING_ON_OUTSIDE_HOLD" | "INVALID_REFRESH_TARGET" | "INVALID_AFFECTS_TARGET" | "MISSING_EFFECT_FN" | "SYNC_NODE_RECEIVED_ASYNC" | "UNTRACKED_READ_AFTER_AWAIT" | "REACTIVITY_HALTED" | "INVARIANT_VIOLATION" | "HUGE_FAN_OUT" | "HUGE_FAN_IN" | "GRAPH_GROWTH" | "HOT_SCOPE_RERUNS" | "HOT_SCOPE_TIME" | "WIDE_SCOPE_DEPS" | "UNSTABLE_MEMO_OUTPUT" | "WASTED_RECOMPUTE" | "ASYNC_WATERFALL" | "HOT_SCOPE_FANOUT" | "SILENT_HOLD" | "LONG_HOLD" | "UNTRACKED_ASYNC_HANDLER" | "ABANDONED_FLIGHTS" | "FALLBACK_FLASH" | "STACKED_HOLDS" | "OPTIMISTIC_REVERTED" | "EFFECT_WRITES_OWN_SOURCE" | "EFFECT_RELAY_TEAR" | "IMMUTABLE_UPDATE_IN_STORE" | "UNSTABLE_LIST_IDENTITY" | "SSR_RENDER_ERROR_CONTAINED" | "SSR_SUBTREE_ABANDONED" | "SSR_STREAM_ABANDONED" | "SSR_CLIENT_CONTENT_MASKED" | "LATE_HEADER_WRITE" | "SERVER_ERROR_SANITIZED" | "SSR_BOUNDARY_WATERFALL" | "SSR_UNDECLARED_LIVE_SOURCE" | "SSR_LIVE_HOLE_LATCHED" | "SERVER_WRITE" | "REVEAL_IN_RENDER_TO_STRING" | "LAZY_ASSET_UNMAPPED" | "PRELOAD_DESCRIPTOR_INVALID" | "HEAD_TAG_INVALID" | "UNRECOGNIZED_INSERT_VALUE" | "UNSCOPED_HOLE_ALLOCATED_IDS" | "LOWERCASE_EVENT_ATTRIBUTE" | "UNCOMMITTED_INPUT_OVERWRITTEN" | "FRAME_MARKER_CORRUPTED" | "DYNAMIC_ASYNC_COMPONENT";
19
+ export type DiagnosticCode = "STRICT_READ_UNTRACKED" | "PENDING_ASYNC_UNTRACKED_READ" | "PENDING_ASYNC_FORBIDDEN_SCOPE" | "REACTIVE_WRITE_IN_OWNED_SCOPE" | "ASYNC_STORE_SETTER" | "STORE_WRITE_OUTSIDE_SETTER" | "ACTION_CALLED_IN_OWNED_SCOPE" | "RUN_WITH_DISPOSED_OWNER" | "NO_OWNER_CLEANUP" | "CLEANUP_IN_FORBIDDEN_SCOPE" | "SETTLED_CLEANUP_UNOWNED" | "ON_FLUSH_IN_OWNED_SCOPE" | "SETTLE_WALK_UNINITIALIZED_SOURCE" | "FLUSH_IN_EFFECT_CALLBACK" | "PRIMITIVE_IN_FORBIDDEN_SCOPE" | "PRIMITIVE_IN_EFFECT_CALLBACK" | "NO_OWNER_EFFECT" | "NO_OWNER_BOUNDARY" | "ASYNC_OUTSIDE_LOADING_BOUNDARY" | "LOADING_ON_OUTSIDE_HOLD" | "INVALID_REFRESH_TARGET" | "INVALID_AFFECTS_TARGET" | "MISSING_EFFECT_FN" | "SYNC_NODE_RECEIVED_ASYNC" | "UNTRACKED_READ_AFTER_AWAIT" | "REACTIVITY_HALTED" | "INVARIANT_VIOLATION" | "HUGE_FAN_OUT" | "HUGE_FAN_IN" | "GRAPH_GROWTH" | "HOT_SCOPE_RERUNS" | "HOT_SCOPE_TIME" | "WIDE_SCOPE_DEPS" | "UNSTABLE_MEMO_OUTPUT" | "WASTED_RECOMPUTE" | "ASYNC_WATERFALL" | "HOT_SCOPE_FANOUT" | "SILENT_HOLD" | "LONG_HOLD" | "UNTRACKED_ASYNC_HANDLER" | "ABANDONED_FLIGHTS" | "FALLBACK_FLASH" | "STACKED_HOLDS" | "OPTIMISTIC_REVERTED" | "EFFECT_WRITES_OWN_SOURCE" | "EFFECT_RELAY_TEAR" | "IMMUTABLE_UPDATE_IN_STORE" | "UNSTABLE_LIST_IDENTITY" | "SSR_RENDER_ERROR_CONTAINED" | "SSR_SUBTREE_ABANDONED" | "SSR_STREAM_ABANDONED" | "SSR_CLIENT_CONTENT_MASKED" | "LATE_HEADER_WRITE" | "SERVER_ERROR_SANITIZED" | "SSR_BOUNDARY_WATERFALL" | "SSR_UNDECLARED_LIVE_SOURCE" | "SSR_LIVE_HOLE_LATCHED" | "SERVER_WRITE" | "REVEAL_IN_RENDER_TO_STRING" | "LAZY_ASSET_UNMAPPED" | "PRELOAD_DESCRIPTOR_INVALID" | "HEAD_TAG_INVALID" | "UNRECOGNIZED_INSERT_VALUE" | "UNSCOPED_HOLE_ALLOCATED_IDS" | "LOWERCASE_EVENT_ATTRIBUTE" | "UNCOMMITTED_INPUT_OVERWRITTEN" | "FRAME_MARKER_CORRUPTED" | "DYNAMIC_ASYNC_COMPONENT" | "ASYNC_MEMO_ELEMENT";
20
20
  export type DiagnosticKind = "strict-read" | "async" | "write" | "lifecycle" | "owner" | "error" | "perf" | "graph"
21
21
  /** Perceived responsiveness: the runtime behaved correctly but the user saw no feedback. */
22
22
  | "responsiveness"
@@ -11,7 +11,7 @@ export type { Computed, Disposable, Link, Owner, Root, Signal, NodeOptions } fro
11
11
  export { effect, trackedEffect, type Effect, type TrackedEffect } from "./effect.js";
12
12
  export { flush, GlobalQueue, enforceLoadingBoundary, resetErrorHalt, type IQueue, type QueueCallback } from "./scheduler.js";
13
13
  export type { InteractionRef, NavigationRef } from "./attribution-hooks.js";
14
- export { ROOT_ERROR_HOOK } from "./scheduler.js";
14
+ export { ROOT_ERROR_HOOK, clock } from "./scheduler.js";
15
15
  export { configureClientErrors, type ClientErrorContext, type ClientErrorHook, type ClientErrorsConfig } from "./error-hooks.js";
16
16
  export { DEV, OBSERVE, setConsoleFooter, type AttributionSlot, type Dev, type Observe, type ServerObserve, type Records, type RecordTypes, type HostRecordTypes, type RecordType, type RecordEvent, type RecordLive, type RecordListener, type RecordSubscribeOptions, type DevHooks, type DiagnosticCapture, type DiagnosticCode, type DiagnosticEvent, type DiagnosticKind, type DiagnosticListener, type Diagnostics, type DiagnosticSeverity, type DiagnosticSubject } from "./dev.js";
17
17
  export * from "./constants.js";
@@ -60,5 +60,9 @@ export declare function supersede(n: Signal<any> | Computed<any>, value: unknown
60
60
  * has shown, or one the seam has not judged yet (its run waits on the
61
61
  * verdict: released if the lane shows, held if it blocks) — and sees the
62
62
  * lane's latest. NOT_PENDING falls through: lane work's read of a pending
63
- * member throws like any. */
63
+ * member throws like any. A verdict reader entering a lane the seam has
64
+ * not judged reads ahead of it like a staging read: if the seam holds the
65
+ * lane, the pass re-derives on the screen (`entered`, #4284) — `latest()`
66
+ * beside the lane's nodes tears ahead of the hold however the reads are
67
+ * grouped into effects. */
64
68
  export declare function laneRead(c: Computed<any> | null, el: Signal<any> | Computed<any>): unknown;
@@ -212,7 +212,14 @@ export declare function setQuestion(q: number): void;
212
212
  export declare function nextQuestion(): number;
213
213
  export declare const MAINLINE_QUESTION = 2147483647;
214
214
  export declare let inEffectCallback: boolean;
215
- export declare function setEffectCallback(value: boolean): void;
215
+ /** Dev-only: matches no event, so a window or phase holding it applies
216
+ * whatever event is current (see `strictReadEvent`, core.ts). */
217
+ export declare const ANY_EVENT: {};
218
+ /** Dev-only: the DOM event current when the effect phase was entered. A
219
+ * handler dispatched synchronously from that phase (`el.focus()`) runs under
220
+ * a different event and is not in it (#4235). */
221
+ export declare let effectCallbackEvent: unknown;
222
+ export declare function setEffectCallback(value: boolean, event?: unknown): void;
216
223
  export type QueueCallback = (type: number) => void;
217
224
  export declare function schedule(): void;
218
225
  /**
@@ -313,13 +320,15 @@ export declare class GlobalQueue implements IQueue {
313
320
  * or without the held read) owes nothing. A run this transaction stashed
314
321
  * for it is void (#3322: an effect has one value slot, and the stale pass
315
322
  * overwrote the value that run was for) — the re-derivation's run replaces
316
- * it. */
317
- export declare function reruns(u: Transaction): void;
323
+ * it. Truthy when an effect re-derives (`land`). */
324
+ export declare function reruns(u: Transaction): unknown;
318
325
  /** The held runs join this flush's effect phase after its own runs (the
319
326
  * landing's re-passes, in height order): the frame's effects run as one
320
327
  * pass would have queued them — a shell re-derived at the landing before a
321
328
  * boundary swap held since the write (#3540's log order). */
322
329
  export declare function releaseQueues(u: Transaction): void;
330
+ /** Nodes staged this flush (`_pendingValue` set), committed at its end. */
331
+ export declare const pendingNodes: Signal<any>[];
323
332
  /** Passes that read a staging of this flush as the screen — lane work
324
333
  * (core.ts `stagedRead`), a verdict reader before the frame's verdict
325
334
  * (verdict.ts): if the frame parks they read a held write — re-derived next
@@ -383,3 +392,8 @@ export declare const globalQueue: GlobalQueue;
383
392
  */
384
393
  export declare function flush(): void;
385
394
  export declare function flush<T>(fn: () => T): T;
395
+ /** Dev-only: the DOM event current when the running effect queue started,
396
+ * or `ANY_EVENT` outside one. Read once per queue rather than once per
397
+ * effect (the getter is costly under jsdom); no event starts or ends between
398
+ * two effects of one synchronous queue (#4235). */
399
+ export declare let queueEvent: unknown;
@@ -0,0 +1,47 @@
1
+ /** The observer a `subscribe` call receives. */
2
+ type FromObserver<T> = {
3
+ next(value: T): void;
4
+ error(err: unknown): void;
5
+ complete(): void;
6
+ };
7
+ type Teardown = (() => void) | {
8
+ unsubscribe(): void;
9
+ } | void;
10
+ /**
11
+ * Anything `from` accepts: a subscribe function
12
+ * (`(next, error, complete) => unsubscribe`), an object with
13
+ * `subscribe(observer)` (RxJS and TC39 Observables, including
14
+ * `Symbol.observable` / `"@@observable"` interop), or an AsyncIterable.
15
+ */
16
+ export type FromSource<T> = ((next: (value: T) => void, error: (err: unknown) => void, complete: () => void) => Teardown) | {
17
+ subscribe(observer: FromObserver<T>): Teardown;
18
+ } | AsyncIterable<T>;
19
+ /**
20
+ * Converts a callback subscription, an Observable or an AsyncIterable into an
21
+ * AsyncIterable for a Solid computation. A subscription keeps only the latest
22
+ * value, and a value the source emits during `subscribe` is served without a
23
+ * loading frame; an AsyncIterable streams every value through.
24
+ *
25
+ * The source closes on supersede — the owning computation re-running — and
26
+ * on owner disposal. Inside an async generator memo that holds for a
27
+ * `for await` that starts before the first `await`; one that starts after it
28
+ * has no owner to bind to, so its source closes only when the loop ends.
29
+ * Prefer returning `from(...)` from its own memo, with awaited inputs read
30
+ * from upstream memos and transforms done in a downstream memo.
31
+ *
32
+ * Iterate the result with `for await` or return it from a computation: its
33
+ * `next()` returns an already-buffered value as a bare result, not a promise.
34
+ *
35
+ * @example
36
+ * ```ts
37
+ * const position = createMemo(() =>
38
+ * from<Position>((next, error) => {
39
+ * const id = navigator.geolocation.watchPosition(next, error);
40
+ * return () => navigator.geolocation.clearWatch(id);
41
+ * })
42
+ * );
43
+ * const ticks = createMemo(() => from(interval$(rate())));
44
+ * ```
45
+ */
46
+ export declare function from<T>(source: FromSource<T>): AsyncIterable<T>;
47
+ export {};
@@ -5,6 +5,8 @@ export { $REFRESH, action, ContextNotFoundError, NoOwnerError, NotReadyError, Ti
5
5
  * outside dev builds.
6
6
  */
7
7
  export { setConsoleFooter } from "./core/index.js";
8
+ /** @internal The flush round counter (scheduler.ts): hydration's served pass tells its own round from a later one. */
9
+ export { clock } from "./core/index.js";
8
10
  /** @internal The pre-write hook (`setWriteHook` in core/core.ts); the server-components client's deferred hydration. */
9
11
  /** @internal Plain-signal identities and the dev read watch (dependency edges; the server-components client). */
10
12
  export { setWriteHook, setSignalIdentities, setReadWatch, signalName } from "./core/index.js";
@@ -20,12 +22,13 @@ export declare const OBSERVE: Observe | undefined;
20
22
  /** Dev tier (devtools hooks, graph traversal, console reporting): dev builds only. */
21
23
  export declare const DEV: Dev | undefined;
22
24
  export type { Owner, Context, ContextRecord, IQueue, ExternalSourceFactory, ExternalSource, ExternalSourceConfig, Refreshable, AttributionSlot, ClientErrorContext, ClientErrorHook, ClientErrorsConfig, InteractionRef, NavigationRef, Dev, Observe, ServerObserve, Records, RecordTypes, HostRecordTypes, RecordType, RecordEvent, RecordLive, RecordListener, RecordSubscribeOptions, DevHooks, DiagnosticCapture, DiagnosticCode, DiagnosticEvent, DiagnosticKind, DiagnosticListener, Diagnostics, DiagnosticSeverity, DiagnosticSubject } from "./core/index.js";
23
- export { createSignal, createOptimistic, createMemo, createEffect, createRenderEffect, createTrackedEffect, createReaction, refresh, resolve, until, onSettled, onCleanup } from "./signals.js";
25
+ export { createSignal, createOptimistic, createMemo, createEffect, createRenderEffect, createTrackedEffect, createReaction, refresh, resolve, until, onSettled, onFlush, onCleanup } from "./signals.js";
24
26
  export type { Truthy, UntilOptions, Accessor, SourceAccessor, Setter, Signal, ComputeFunction, EffectFunction, EffectBundle, EffectOptions, SignalOptions, MemoOptions, NoInfer } from "./signals.js";
25
27
  export { mapArray, repeat, type Maybe } from "./map.js";
26
28
  export * from "./store/index.js";
27
29
  export { affects } from "./affects.js";
28
30
  export { createDeferred } from "./deferred.js";
31
+ export { from, type FromSource } from "./from.js";
29
32
  export { flatten } from "./flatten.js";
30
33
  export { createLoadingBoundary, createErrorBoundary } from "./boundaries.js";
31
34
  export { createRevealOrder, type RevealOrder } from "./reveal.js";
@@ -735,4 +735,41 @@ export declare function until<T>(fn: () => T, options?: UntilOptions): Promise<T
735
735
  * on owner disposal
736
736
  */
737
737
  export declare function onSettled(callback: () => void | (() => void)): void;
738
+ /**
739
+ * Schedules `callback` to run **once**, right after the pending flush
740
+ * finishes, in the same microtask checkpoint (before the browser paints).
741
+ * Unlike `onSettled`, it never waits on async work: if that flush is held by
742
+ * a pending transition, the callback still runs.
743
+ *
744
+ * Its main use is keeping a write out of another update's hold. Writes made
745
+ * in the same synchronous frame are applied together, so when one of them
746
+ * starts async work (a route change, a fetch), the others are held with it
747
+ * until it resolves. A write made in `onFlush` happens after that flush, so
748
+ * it is its own update: it commits on its own unless something it changes
749
+ * also derives from the held work (a memo or `createEffect` reading both),
750
+ * in which case it joins that hold as any later write would.
751
+ *
752
+ * Call it from event handlers and effect callbacks (including
753
+ * `createTrackedEffect` and `onSettled` bodies). In an owned scope such as a
754
+ * component body or a computation it warns in dev: use `onSettled` there.
755
+ *
756
+ * - A write in the callback lands after any write made inline in the same
757
+ * frame. Don't write the same signal both inside and outside it; use a
758
+ * functional setter if the order matters.
759
+ * - Several `onFlush` callbacks run in call order and batch into one flush.
760
+ * - `queueMicrotask` is not a substitute: called before the frame's first
761
+ * write, it runs before that flush and its write joins it.
762
+ *
763
+ * @example
764
+ * ```tsx
765
+ * // A menu closes now even when the consumer's onSelect starts async work.
766
+ * const select = (id: string) => {
767
+ * onFlush(() => setOpen(false));
768
+ * props.onSelect?.(id);
769
+ * };
770
+ * ```
771
+ *
772
+ * @param callback Function to run once after the pending flush
773
+ */
774
+ export declare function onFlush(callback: () => void): void;
738
775
  export {};
@@ -34,6 +34,8 @@ export interface StoreFamily {
34
34
  * their readers (A9) — the family's enumerable index, in place of a
35
35
  * per-leaf chain; a target leaves it with its last node. */
36
36
  live: Set<StoreTarget>;
37
+ /** A source's status reaching the derive by propagation (`familyStatus`). */
38
+ st?: (status: number) => void;
37
39
  shallow?: boolean;
38
40
  /** Derive run counter (proj R37): the run whose draft is live. */
39
41
  run?: number;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@solidjs/signals",
3
- "version": "2.0.0-rc.17",
3
+ "version": "2.0.0-rc.19",
4
4
  "description": "Solid's reactive primitives: signals, memos, effects, stores, and async-aware computations.",
5
5
  "author": "Ryan Carniato",
6
6
  "license": "MIT",