@solidjs/signals 2.0.0-beta.15 → 2.0.0-beta.16

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 (86) hide show
  1. package/dist/dev.js +700 -385
  2. package/dist/node.cjs +1865 -1592
  3. package/dist/prod.js +1496 -1232
  4. package/dist/types/boundaries.d.ts +3 -3
  5. package/dist/types/core/async.d.ts +1 -0
  6. package/dist/types/core/core.d.ts +25 -1
  7. package/dist/types/core/dev.d.ts +10 -2
  8. package/dist/types/core/effect.d.ts +1 -3
  9. package/dist/types/core/graph.d.ts +1 -1
  10. package/dist/types/core/index.d.ts +2 -2
  11. package/dist/types/core/invariants.d.ts +49 -0
  12. package/dist/types/core/scheduler.d.ts +8 -0
  13. package/dist/types/core/types.d.ts +19 -0
  14. package/dist/types/index.d.ts +1 -1
  15. package/dist/types/signals.d.ts +39 -2
  16. package/dist/types/store/projection.d.ts +2 -2
  17. package/dist/types/store/store.d.ts +28 -1
  18. package/dist/types-cjs/boundaries.d.cts +3 -3
  19. package/dist/types-cjs/core/async.d.cts +1 -0
  20. package/dist/types-cjs/core/core.d.cts +25 -1
  21. package/dist/types-cjs/core/dev.d.cts +10 -2
  22. package/dist/types-cjs/core/effect.d.cts +1 -3
  23. package/dist/types-cjs/core/graph.d.cts +1 -1
  24. package/dist/types-cjs/core/index.d.cts +2 -2
  25. package/dist/types-cjs/core/invariants.d.cts +49 -0
  26. package/dist/types-cjs/core/scheduler.d.cts +8 -0
  27. package/dist/types-cjs/core/types.d.cts +19 -0
  28. package/dist/types-cjs/index.d.cts +1 -1
  29. package/dist/types-cjs/signals.d.cts +39 -2
  30. package/dist/types-cjs/store/projection.d.cts +2 -2
  31. package/dist/types-cjs/store/store.d.cts +28 -1
  32. package/package.json +1 -1
  33. package/dist/types/src/boundaries.d.ts +0 -173
  34. package/dist/types/src/core/action.d.ts +0 -35
  35. package/dist/types/src/core/async.d.ts +0 -6
  36. package/dist/types/src/core/constants.d.ts +0 -51
  37. package/dist/types/src/core/context.d.ts +0 -36
  38. package/dist/types/src/core/core.d.ts +0 -174
  39. package/dist/types/src/core/dev.d.ts +0 -49
  40. package/dist/types/src/core/effect.d.ts +0 -32
  41. package/dist/types/src/core/error.d.ts +0 -38
  42. package/dist/types/src/core/external.d.ts +0 -45
  43. package/dist/types/src/core/graph.d.ts +0 -5
  44. package/dist/types/src/core/heap.d.ts +0 -14
  45. package/dist/types/src/core/index.d.ts +0 -12
  46. package/dist/types/src/core/lanes.d.ts +0 -54
  47. package/dist/types/src/core/owner.d.ts +0 -116
  48. package/dist/types/src/core/scheduler.d.ts +0 -122
  49. package/dist/types/src/core/types.d.ts +0 -85
  50. package/dist/types/src/index.d.ts +0 -9
  51. package/dist/types/src/map.d.ts +0 -53
  52. package/dist/types/src/signals.d.ts +0 -512
  53. package/dist/types/src/store/index.d.ts +0 -9
  54. package/dist/types/src/store/optimistic.d.ts +0 -45
  55. package/dist/types/src/store/projection.d.ts +0 -66
  56. package/dist/types/src/store/reconcile.d.ts +0 -23
  57. package/dist/types/src/store/store.d.ts +0 -125
  58. package/dist/types/src/store/storePath.d.ts +0 -58
  59. package/dist/types/src/store/utils.d.ts +0 -114
  60. package/dist/types-cjs/src/boundaries.d.cts +0 -173
  61. package/dist/types-cjs/src/core/action.d.cts +0 -35
  62. package/dist/types-cjs/src/core/async.d.cts +0 -6
  63. package/dist/types-cjs/src/core/constants.d.cts +0 -51
  64. package/dist/types-cjs/src/core/context.d.cts +0 -36
  65. package/dist/types-cjs/src/core/core.d.cts +0 -174
  66. package/dist/types-cjs/src/core/dev.d.cts +0 -49
  67. package/dist/types-cjs/src/core/effect.d.cts +0 -32
  68. package/dist/types-cjs/src/core/error.d.cts +0 -38
  69. package/dist/types-cjs/src/core/external.d.cts +0 -45
  70. package/dist/types-cjs/src/core/graph.d.cts +0 -5
  71. package/dist/types-cjs/src/core/heap.d.cts +0 -14
  72. package/dist/types-cjs/src/core/index.d.cts +0 -12
  73. package/dist/types-cjs/src/core/lanes.d.cts +0 -54
  74. package/dist/types-cjs/src/core/owner.d.cts +0 -116
  75. package/dist/types-cjs/src/core/scheduler.d.cts +0 -122
  76. package/dist/types-cjs/src/core/types.d.cts +0 -85
  77. package/dist/types-cjs/src/index.d.cts +0 -9
  78. package/dist/types-cjs/src/map.d.cts +0 -53
  79. package/dist/types-cjs/src/signals.d.cts +0 -512
  80. package/dist/types-cjs/src/store/index.d.cts +0 -9
  81. package/dist/types-cjs/src/store/optimistic.d.cts +0 -45
  82. package/dist/types-cjs/src/store/projection.d.cts +0 -66
  83. package/dist/types-cjs/src/store/reconcile.d.cts +0 -23
  84. package/dist/types-cjs/src/store/store.d.cts +0 -125
  85. package/dist/types-cjs/src/store/storePath.d.cts +0 -58
  86. package/dist/types-cjs/src/store/utils.d.cts +0 -114
@@ -73,9 +73,9 @@ export declare class CollectionQueue extends Queue {
73
73
  * }
74
74
  * ```
75
75
  */
76
- export declare function createLoadingBoundary(fn: () => any, fallback: () => any, options?: {
76
+ export declare function createLoadingBoundary<T, U>(fn: () => T, fallback: () => U, options?: {
77
77
  on?: () => any;
78
- }): import("./signals.js").SourceAccessor<unknown>;
78
+ }): Accessor<T | U>;
79
79
  /**
80
80
  * Lower-level primitive that backs the `<Errored>` flow control. Catches
81
81
  * thrown errors inside `fn` and invokes `fallback(error, reset)` instead.
@@ -99,7 +99,7 @@ export declare function createLoadingBoundary(fn: () => any, fallback: () => any
99
99
  * }
100
100
  * ```
101
101
  */
102
- export declare function createErrorBoundary<U>(fn: () => any, fallback: (error: Accessor<unknown>, reset: () => void) => U): import("./signals.js").SourceAccessor<unknown>;
102
+ export declare function createErrorBoundary<T, U>(fn: () => T, fallback: (error: Accessor<unknown>, reset: () => void) => U): Accessor<T | U>;
103
103
  /**
104
104
  * Coordinate the reveal timing of sibling loading boundaries.
105
105
  *
@@ -1,6 +1,7 @@
1
1
  import { type OptimisticLane } from "./lanes.js";
2
2
  import type { Computed } from "./types.js";
3
3
  export declare function settlePendingSource(el: Computed<any>): void;
4
+ export declare function isThenable<T>(value: T | PromiseLike<T>): value is PromiseLike<T>;
4
5
  export declare function handleAsync<T>(el: Computed<T>, result: T | PromiseLike<T> | AsyncIterable<T>, setter?: (value: T) => void): T;
5
6
  export declare function clearStatus(el: Computed<any>, clearUninitialized?: boolean): void;
6
7
  export declare function notifyStatus(el: Computed<any>, status: number, error: any, blockStatus?: boolean, lane?: OptimisticLane): void;
@@ -7,7 +7,6 @@ export declare const REACTIVE_WRITE_IN_OWNED_SCOPE_REFRESH_MESSAGE: string;
7
7
  export declare let tracking: boolean;
8
8
  export declare let stale: boolean;
9
9
  export declare let pendingCheckActive: boolean;
10
- export declare let foundPending: boolean;
11
10
  export declare let latestReadActive: boolean;
12
11
  export declare let context: Owner | null;
13
12
  export declare let currentOptimisticLane: OptimisticLane | null;
@@ -98,12 +97,37 @@ export declare function setMemo<T>(el: Computed<T>, v: T | ((prev: T) => T)): T;
98
97
  * ```
99
98
  */
100
99
  export declare function runWithOwner<T>(owner: Owner | null, fn: () => T): T;
100
+ /**
101
+ * Keep the lazily-created isPending()/latest() companion nodes in sync with a
102
+ * new value. Every path that produces a value for `el` — direct set, async
103
+ * resolution, transition-held sync recompute — must route through here so a
104
+ * new write path can't silently skip the companions (#2831).
105
+ */
106
+ export declare function syncCompanions<T>(el: Signal<T> | Computed<T>, value: T): void;
101
107
  /**
102
108
  * Update _pendingSignal when pending state changes. When the override clears
103
109
  * (pending -> not pending), merge the sub-lane into the source's lane so
104
110
  * isPending effects are blocked until the full scope resolves.
105
111
  */
106
112
  export declare function updatePendingSignal(el: Signal<any> | Computed<any>): void;
113
+ /**
114
+ * A firewall's status change re-derives the verdicts of its probed leaves:
115
+ * leaf companions consult the firewall (broad inheritance), so async
116
+ * starting/settling on the firewall must poke them or they keep a stale
117
+ * verdict forever (V4 stuck-companion class, #2838).
118
+ */
119
+ export declare function updateChildCompanions(el: Computed<any>): void;
120
+ /**
121
+ * Settlement checkpoint (#2838): re-derive a node's companions directly from
122
+ * its committed state. Called when the transition machinery for the node is
123
+ * done with it — a pending commit or an optimistic revert. Verdicts are
124
+ * written committed (not through setSignal) because a transition-scoped
125
+ * override window opened here would itself need a settlement, re-scheduling
126
+ * forever while async is still in flight. This is what keeps companions
127
+ * coherent past transition completion: a verdict is a property of the data
128
+ * (A19), so it must survive the transition that happened to produce it.
129
+ */
130
+ export declare function snapCompanionsToState(owner: Signal<any> | Computed<any>): void;
107
131
  export declare function staleValues<T>(fn: () => T, set?: boolean): T;
108
132
  /**
109
133
  * Reads reactive expressions while bypassing any pending async overlay — i.e.
@@ -6,8 +6,8 @@ export interface DevHooks {
6
6
  onStoreNodeUpdate?: (state: any, property: PropertyKey, value: any, prev: any) => void;
7
7
  }
8
8
  export type DiagnosticSeverity = "warn" | "error";
9
- export type DiagnosticCode = "STRICT_READ_UNTRACKED" | "PENDING_ASYNC_UNTRACKED_READ" | "PENDING_ASYNC_FORBIDDEN_SCOPE" | "REACTIVE_WRITE_IN_OWNED_SCOPE" | "RUN_WITH_DISPOSED_OWNER" | "NO_OWNER_CLEANUP" | "CLEANUP_IN_FORBIDDEN_SCOPE" | "PRIMITIVE_IN_FORBIDDEN_SCOPE" | "NO_OWNER_EFFECT" | "NO_OWNER_BOUNDARY" | "ASYNC_OUTSIDE_LOADING_BOUNDARY" | "INVALID_REFRESH_TARGET" | "MISSING_EFFECT_FN" | "SYNC_NODE_RECEIVED_ASYNC";
10
- export type DiagnosticKind = "strict-read" | "async" | "write" | "lifecycle" | "owner";
9
+ export type DiagnosticCode = "STRICT_READ_UNTRACKED" | "PENDING_ASYNC_UNTRACKED_READ" | "PENDING_ASYNC_FORBIDDEN_SCOPE" | "REACTIVE_WRITE_IN_OWNED_SCOPE" | "RUN_WITH_DISPOSED_OWNER" | "NO_OWNER_CLEANUP" | "CLEANUP_IN_FORBIDDEN_SCOPE" | "SETTLED_CLEANUP_UNOWNED" | "PRIMITIVE_IN_FORBIDDEN_SCOPE" | "NO_OWNER_EFFECT" | "NO_OWNER_BOUNDARY" | "ASYNC_OUTSIDE_LOADING_BOUNDARY" | "INVALID_REFRESH_TARGET" | "MISSING_EFFECT_FN" | "SYNC_NODE_RECEIVED_ASYNC" | "REACTIVITY_HALTED" | "INVARIANT_VIOLATION";
10
+ export type DiagnosticKind = "strict-read" | "async" | "write" | "lifecycle" | "owner" | "error";
11
11
  export interface DiagnosticEvent {
12
12
  sequence: number;
13
13
  code: DiagnosticCode;
@@ -39,6 +39,14 @@ export interface Dev {
39
39
  getObservers: typeof getObservers;
40
40
  }
41
41
  export declare const DEV: Dev;
42
+ /**
43
+ * Dev-mode internal consistency check. A failure means the reactive system
44
+ * contradicted itself (not that user code misbehaved) — see
45
+ * INTERNALS-ASYNC-STATE.md for the invariant catalog. Throws under __TEST__
46
+ * so the suite (and fuzzing) treats any violation as a hard failure; logs in
47
+ * dev builds so user apps degrade instead of crashing.
48
+ */
49
+ export declare function assertInvariant(condition: boolean, name: string, message: string): void;
42
50
  export declare function emitDiagnostic(event: Omit<DiagnosticEvent, "sequence">): DiagnosticEvent;
43
51
  export declare function registerGraph(value: any, owner: Owner | null): void;
44
52
  export declare function clearSignals(node: Owner): void;
@@ -2,11 +2,10 @@ import type { Computed, NodeOptions, Owner } from "./types.js";
2
2
  export interface Effect<T> extends Computed<T>, Owner {
3
3
  _effectFn: (val: T, prev: T | undefined) => void | (() => void);
4
4
  _errorFn?: (err: unknown, cleanup: () => void) => void;
5
- _cleanup?: () => void;
6
- _cleanupRegistered?: boolean;
7
5
  _modified: boolean;
8
6
  _prevValue: T | undefined;
9
7
  _type: number;
8
+ _boundRunEffect?: () => void;
10
9
  }
11
10
  /**
12
11
  * Effects are the leaf nodes of our reactive graph. When their sources change, they are
@@ -19,7 +18,6 @@ export declare function effect<T>(compute: (prev: T | undefined) => T, effect: (
19
18
  schedule?: boolean;
20
19
  }): void;
21
20
  export interface TrackedEffect extends Computed<void> {
22
- _cleanup?: () => void;
23
21
  _modified: boolean;
24
22
  _type: number;
25
23
  _run: () => void;
@@ -2,4 +2,4 @@ import type { Computed, Link, Signal } from "./types.js";
2
2
  export declare function unlinkSubs(link: Link): Link | null;
3
3
  export declare function trimStaleDeps(el: Computed<any>): void;
4
4
  export declare function unobserved(el: Computed<unknown>): void;
5
- export declare function link(dep: Signal<any> | Computed<any>, sub: Computed<any>): void;
5
+ export declare function link(dep: Signal<any> | Computed<any>, sub: Computed<any>, pendingObserver?: boolean): void;
@@ -1,5 +1,5 @@
1
1
  export { ContextNotFoundError, NoOwnerError, NotReadyError } from "./error.js";
2
- export { isEqual, untrack, runWithOwner, computed, signal, read, setSignal, setMemo, suppressComputedRecompute, optimisticSignal, optimisticComputed, isPending, latest, refresh, staleValues, setSnapshotCapture, markSnapshotScope, releaseSnapshotScope, clearSnapshots } from "./core.js";
2
+ export { isEqual, untrack, runWithOwner, computed, signal, read, setSignal, setMemo, suppressComputedRecompute, optimisticSignal, optimisticComputed, isPending, latest, updatePendingSignal, updateChildCompanions, refresh, staleValues, setSnapshotCapture, markSnapshotScope, releaseSnapshotScope, clearSnapshots } from "./core.js";
3
3
  export { enableExternalSource, _resetExternalSourceConfig, type ExternalSourceFactory, type ExternalSource, type ExternalSourceConfig } from "./external.js";
4
4
  export { createOwner, createRoot, dispose, getNextChildId, getObserver, getOwner, isDisposed, cleanup, peekNextChildId } from "./owner.js";
5
5
  export { createContext, getContext, setContext, type Context, type ContextRecord } from "./context.js";
@@ -7,6 +7,6 @@ export { handleAsync } from "./async.js";
7
7
  export type { Computed, Disposable, FirewallSignal, Link, Owner, Root, Signal, NodeOptions } from "./types.js";
8
8
  export { effect, trackedEffect, type Effect, type TrackedEffect } from "./effect.js";
9
9
  export { action } from "./action.js";
10
- export { flush, Queue, GlobalQueue, trackOptimisticStore, enforceLoadingBoundary, type IQueue, type QueueCallback } from "./scheduler.js";
10
+ export { flush, Queue, GlobalQueue, trackOptimisticStore, enforceLoadingBoundary, resetErrorHalt, type IQueue, type QueueCallback } from "./scheduler.js";
11
11
  export { DEV, type Dev, type DevHooks, type DiagnosticCapture, type DiagnosticCode, type DiagnosticEvent, type DiagnosticKind, type Diagnostics, type DiagnosticSeverity } from "./dev.js";
12
12
  export * from "./constants.js";
@@ -0,0 +1,49 @@
1
+ import type { OptimisticLane } from "./lanes.js";
2
+ import type { Computed, Signal } from "./types.js";
3
+ /**
4
+ * Test-mode invariant checks for the async/transition/lane machinery.
5
+ * Catalog and rationale: packages/solid-signals/INTERNALS-ASYNC-STATE.md.
6
+ *
7
+ * These are implementation self-consistency checks, not semantic rules: a
8
+ * violation means the reactive system contradicted itself.
9
+ *
10
+ * They are gated on `__TEST__` (not just `__DEV__`): the per-write Set
11
+ * tracking and per-flush quiescence sweep are too expensive for shipped dev
12
+ * builds and for benchmarks (they showed up as a 5-21% hit across the
13
+ * CodSpeed suite when they ran under `__DEV__`). Call sites stay `__DEV__`
14
+ * guarded so production tree-shakes the calls; each entry point here
15
+ * early-returns unless `__TEST__` is set, so dev builds pay only a no-op
16
+ * call. The test suite (vitest run) defines `__TEST__: true`; benchmark mode
17
+ * defines `__TEST__: false`.
18
+ */
19
+ type AnyNode = Signal<any> | Computed<any>;
20
+ /** Wired by core.ts at module init to avoid import cycles. */
21
+ export declare const InvariantHooks: {
22
+ pendingProbeActive: (() => boolean) | null;
23
+ /** Fresh oracle for what an isPending companion SHOULD read right now. */
24
+ computePendingState: ((node: AnyNode) => boolean) | null;
25
+ };
26
+ export declare function devTrackHeldPending(node: AnyNode): void;
27
+ export declare function devTrackCompanionOwner(node: AnyNode): void;
28
+ export declare function devTrackOptimistic(node: AnyNode): void;
29
+ /**
30
+ * Open/close the sanctioned registration window. Call sites are `__DEV__`
31
+ * guarded (no prod cost); the code inside the window must not throw.
32
+ */
33
+ export declare function beginAsyncReporterWrites(): void;
34
+ export declare function endAsyncReporterWrites(): void;
35
+ export declare function createAsyncReporters(): Map<Computed<any>, Set<Computed<any>>>;
36
+ export declare function devCheckActiveOverrides(isRegisteredForRevert: (node: AnyNode) => boolean): void;
37
+ /** INV-1: an isPending() probe must never leak past its own call. */
38
+ export declare function devCheckFlushStart(): void;
39
+ /** INV-5: a merged lane's work moved to its root on merge and must stay empty. */
40
+ export declare function devCheckMergedLaneEmpty(lane: OptimisticLane): void;
41
+ export declare function devCensusCompanions(isQueuedForCommit?: (node: AnyNode) => boolean): void;
42
+ /**
43
+ * Quiescence checks. Run only when the system is fully drained: nothing
44
+ * scheduled, no active/stashed transitions, no live lanes. At that point no
45
+ * transition-scoped state may survive, and the lazily-created companions must
46
+ * agree with a fresh computation of their owner's state.
47
+ */
48
+ export declare function devCheckQuiescent(isQueuedForCommit: (node: AnyNode) => boolean): void;
49
+ export {};
@@ -41,6 +41,14 @@ export interface Transition {
41
41
  _gatedSubs: Set<Computed<any>>;
42
42
  }
43
43
  export declare function schedule(): void;
44
+ /**
45
+ * Permanently halts the reactive system. Called when a user error escapes
46
+ * every boundary — app state is undefined at that point, so scheduling stops
47
+ * entirely rather than limping along with a half-applied update.
48
+ */
49
+ export declare function haltReactivity(): void;
50
+ /** @internal Test/dev-reload hook. Revives scheduling after a halt. */
51
+ export declare function resetErrorHalt(): void;
44
52
  export interface IQueue {
45
53
  enqueue(type: number, fn: QueueCallback): void;
46
54
  run(type: number): boolean | void;
@@ -10,6 +10,14 @@ export interface Link {
10
10
  _nextDep: Link | null;
11
11
  _prevSub: Link | null;
12
12
  _nextSub: Link | null;
13
+ /**
14
+ * `_sub._depGen` at the time this link was created or last revalidated
15
+ * in-order. A link stamped with the subscriber's current pass generation is
16
+ * inside the validated `[deps.._depsTail]` prefix — an O(1) replacement for
17
+ * scanning the dep list to answer membership (see `link()`).
18
+ */
19
+ _gen: number;
20
+ _pendingObserver?: boolean;
13
21
  }
14
22
  export interface NodeOptions<T> {
15
23
  id?: string;
@@ -50,6 +58,8 @@ export interface Owner {
50
58
  id?: string;
51
59
  _config: number;
52
60
  _snapshotScope?: boolean;
61
+ /** Effect-returned cleanup; managed across reruns, invoked at true disposal */
62
+ _cleanup?: () => void;
53
63
  _disposal: Disposable | Disposable[] | null;
54
64
  _parent: Owner | null;
55
65
  _context: Record<symbol | string, unknown>;
@@ -64,6 +74,8 @@ export interface Owner {
64
74
  export interface Computed<T> extends RawSignal<T>, Owner {
65
75
  _deps: Link | null;
66
76
  _depsTail: Link | null;
77
+ /** Recompute-pass counter; bumped when dep revalidation starts. */
78
+ _depGen: number;
67
79
  _flags: number;
68
80
  _blocked?: boolean;
69
81
  _pendingSource?: Computed<any>;
@@ -77,6 +89,13 @@ export interface Computed<T> extends RawSignal<T>, Owner {
77
89
  _inFlight: PromiseLike<T> | AsyncIterable<T> | null;
78
90
  _child: FirewallSignal<any> | null;
79
91
  _notifyStatus?: (status?: number, error?: any) => void;
92
+ /**
93
+ * Store-wide optimistic mask (count of this firewall's store targets with
94
+ * live optimistic writes). Non-zero decrees the whole store settled for
95
+ * `isPending` — the store is the primitive the mask covers (A20 re-rule
96
+ * 2026-07-07c).
97
+ */
98
+ _optimisticMask?: number;
80
99
  }
81
100
  export interface Root extends Owner {
82
101
  _root: true;
@@ -1,4 +1,4 @@
1
- export { $REFRESH, ContextNotFoundError, NoOwnerError, NotReadyError, action, createContext, createOwner, createRoot, runWithOwner, flush, getNextChildId, peekNextChildId, getContext, setContext, getOwner, isDisposed, getObserver, isEqual, untrack, isPending, latest, refresh, SUPPORTS_PROXY, setSnapshotCapture, markSnapshotScope, releaseSnapshotScope, clearSnapshots, enforceLoadingBoundary, enableExternalSource } from "./core/index.js";
1
+ export { $REFRESH, ContextNotFoundError, NoOwnerError, NotReadyError, action, createContext, createOwner, createRoot, runWithOwner, flush, getNextChildId, peekNextChildId, getContext, setContext, getOwner, isDisposed, getObserver, isEqual, untrack, isPending, latest, refresh, SUPPORTS_PROXY, setSnapshotCapture, markSnapshotScope, releaseSnapshotScope, clearSnapshots, enforceLoadingBoundary, enableExternalSource, resetErrorHalt } from "./core/index.js";
2
2
  import { type Dev } from "./core/index.js";
3
3
  export declare const DEV: Dev | undefined;
4
4
  export type { Owner, Context, ContextRecord, IQueue, ExternalSourceFactory, ExternalSource, ExternalSourceConfig, Refreshable, Dev, DevHooks, DiagnosticCapture, DiagnosticCode, DiagnosticEvent, DiagnosticKind, Diagnostics, DiagnosticSeverity } from "./core/index.js";
@@ -69,6 +69,17 @@ export type ComputeFunction<Prev, Next extends Prev = Prev> = (v: Prev) => Promi
69
69
  export type EffectFunction<Prev, Next extends Prev = Prev> = (v: Next, p?: Prev) => (() => void) | void;
70
70
  export type EffectBundle<Prev, Next extends Prev = Prev> = {
71
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
+ */
72
83
  error: (err: unknown, cleanup: () => void) => void;
73
84
  };
74
85
  /** Options shared by every effect primitive. */
@@ -245,7 +256,24 @@ export declare function createMemo<T>(compute: ComputeFunction<undefined | NoInf
245
256
  * `createTrackedEffect` (with the tradeoffs noted there).
246
257
  *
247
258
  * Pass an `EffectBundle` (`{ effect, error }`) instead of a plain function to
248
- * intercept errors thrown from the compute or effect phases.
259
+ * intercept **compute-phase** errors — errors thrown by `compute` or arriving
260
+ * from upstream reactive sources (including async rejections), which your own
261
+ * code has no frame to `try/catch`. The `error` handler is the error arm of
262
+ * the effect phase: it runs on the same schedule and in the same imperative,
263
+ * writable scope as `effect` (setting error state via signals is fine), and
264
+ * only for *settled* errors — a transient error that recovers before the
265
+ * effect phase runs `effect` with the recovered value instead, and a held
266
+ * transition defers it exactly as it defers `effect`. Without an `error`
267
+ * handler a compute-phase error is logged and the effect simply skips that
268
+ * run — a non-render effect's reactivity failing does not crash the app.
269
+ * Rethrowing from `error` escalates it to the nearest error boundary
270
+ * (halting the system if none exists).
271
+ *
272
+ * The **effect phase is different**: it is your own imperative code, so handle
273
+ * failures with `try/catch` where they occur. An uncaught effect-phase throw
274
+ * is treated as an unhandled application error — caught by the nearest
275
+ * `createErrorBoundary`/`<Errored>`, and permanently halting the reactive
276
+ * system if there is none. It is *not* routed to the bundle's `error` handler.
249
277
  *
250
278
  * ```typescript
251
279
  * createEffect<T>(compute, effectFn | { effect, error }, options?: EffectOptions);
@@ -383,7 +411,9 @@ export declare function createReaction(effectFn: EffectFunction<undefined> | Eff
383
411
  * Awaits a reactive expression and returns its first fully-settled value as a
384
412
  * `Promise`. Pending async reads (`createMemo` returning a promise, etc.) are
385
413
  * waited on; once the expression returns synchronously without `NotReadyError`
386
- * the promise resolves with that value.
414
+ * the promise resolves with that value. If the expression settles with an
415
+ * error instead — including an async source that rejects — the promise
416
+ * rejects with it.
387
417
  *
388
418
  * Must be called *outside* a tracking scope — it doesn't subscribe, it just
389
419
  * resolves the current value once.
@@ -459,6 +489,13 @@ export declare function createOptimistic<T>(fn: ComputeFunction<T>, options?: Si
459
489
  * `onCleanup` is **not** allowed inside the callback — return a cleanup
460
490
  * function instead. The returned cleanup runs on owner disposal.
461
491
  *
492
+ * A cleanup return is only honored when `onSettled` is called from an **owned**
493
+ * scope (e.g. a component body). When it fires out of band from an *unowned*
494
+ * scope — an event handler, a tracked effect, or another `onSettled` — there is
495
+ * no owner lifecycle to bind a cleanup to; returning one is a dev-mode error
496
+ * (and is dropped in production). Use the post-settle/event-handler forms below
497
+ * for one-shot work, and keep setup-with-teardown in an owned scope.
498
+ *
462
499
  * @example
463
500
  * ```tsx
464
501
  * // Component-level setup + teardown — replaces onMount + onCleanup.
@@ -1,5 +1,5 @@
1
1
  import { type Computed, type Refreshable } from "../core/index.js";
2
- import { type ProjectionOptions, type Store } from "./store.js";
2
+ import { type NoFn, type ProjectionOptions, type Store } from "./store.js";
3
3
  export declare function createProjectionInternal<T extends object = {}>(fn: (draft: T) => void | T | Promise<void | T> | AsyncIterable<void | T>, seed: Partial<T>, options?: ProjectionOptions): {
4
4
  store: Refreshable<Store<T>>;
5
5
  node: Computed<void | T>;
@@ -47,7 +47,7 @@ export declare function createProjectionInternal<T extends object = {}>(fn: (dra
47
47
  *
48
48
  * @see {@link https://github.com/solidjs/x-reactivity#createprojection}
49
49
  */
50
- export declare function createProjection<T extends object = {}>(fn: (draft: T) => void | T | Promise<void | T> | AsyncIterable<void | T>, seed: Partial<T>, options?: ProjectionOptions): Refreshable<Store<T>>;
50
+ export declare function createProjection<T extends object = {}>(fn: (draft: T) => void | T | Promise<void | T> | AsyncIterable<void | T>, seed: Partial<T> | Store<NoFn<T>>, options?: ProjectionOptions): Refreshable<Store<T>>;
51
51
  /**
52
52
  * Shared projection computed body used by both `createProjection` and the derived
53
53
  * form of `createOptimisticStore`. Encapsulates the write-trap draft, `storeSetter`
@@ -41,7 +41,7 @@ type DataNodes = Record<PropertyKey, DataNode>;
41
41
  * @internal
42
42
  */
43
43
  export declare const $TRACK: unique symbol, $TARGET: unique symbol, $PROXY: unique symbol, $DELETED: unique symbol;
44
- export declare const STORE_VALUE = "v", STORE_OVERRIDE = "o", STORE_OPTIMISTIC_OVERRIDE = "x", STORE_NODE = "n", STORE_HAS = "h", STORE_CUSTOM_PROTO = "c", STORE_WRAP = "w", STORE_LOOKUP = "l", STORE_FIREWALL = "f", STORE_OPTIMISTIC = "p";
44
+ export declare const STORE_VALUE = "v", STORE_OVERRIDE = "o", STORE_OPTIMISTIC_OVERRIDE = "x", STORE_NODE = "n", STORE_HAS = "h", STORE_CUSTOM_PROTO = "c", STORE_WRAP = "w", STORE_LOOKUP = "l", STORE_FIREWALL = "f", STORE_OPTIMISTIC = "p", STORE_MASKED = "m";
45
45
  export type StoreNode = {
46
46
  [$PROXY]: any;
47
47
  [STORE_VALUE]: Record<PropertyKey, any>;
@@ -54,6 +54,8 @@ export type StoreNode = {
54
54
  [STORE_LOOKUP]?: WeakMap<any, any>;
55
55
  [STORE_FIREWALL]?: Computed<any>;
56
56
  [STORE_OPTIMISTIC]?: boolean;
57
+ /** This target currently contributes to its firewall's store-wide mask. */
58
+ [STORE_MASKED]?: boolean;
57
59
  [STORE_SNAPSHOT_PROPS]?: Record<PropertyKey, any>;
58
60
  };
59
61
  export declare namespace SolidStore {
@@ -63,13 +65,38 @@ export declare namespace SolidStore {
63
65
  export type NotWrappable = string | number | bigint | symbol | boolean | Function | null | undefined | SolidStore.Unwrappable[keyof SolidStore.Unwrappable];
64
66
  export declare function createStoreProxy<T extends object>(value: T, traps?: ProxyHandler<StoreNode>, extend?: (target: StoreNode) => void): any;
65
67
  export declare const storeLookup: WeakMap<WeakKey, any>;
68
+ export declare const symbolKeyedRecords: WeakSet<object>;
66
69
  export declare function wrap<T extends Record<PropertyKey, any>>(value: T, target?: StoreNode): T;
67
70
  export declare function isWrappable<T>(obj: T | NotWrappable): obj is T;
68
71
  export declare function setWriteOverride(value: boolean): void;
72
+ export declare function ownEnumerableKeys(o: object): (string | symbol)[];
73
+ /**
74
+ * Single chokepoint for the store's layered value resolution: returns the
75
+ * override layer (optimistic first, then regular) that shadows `property`, or
76
+ * `undefined` when the base `STORE_VALUE` is authoritative. Every trap must
77
+ * resolve through this — hand-inlining the layer order is how the optimistic
78
+ * layer gets missed (#2850).
79
+ */
80
+ export declare function getOverlayLayer(target: StoreNode, property: PropertyKey): Record<PropertyKey, any> | undefined;
81
+ /**
82
+ * The value a store leaf's backing signal currently shows to readers: active
83
+ * override, else held pending value, else committed value.
84
+ */
85
+ export declare function visibleNodeValue(node: DataNode): any;
69
86
  export declare function trackSelf(target: StoreNode, symbol?: symbol): void;
70
87
  export declare function notifySelf(target: StoreNode): void;
71
88
  export declare function getKeys(source: Record<PropertyKey, any>, override: Record<PropertyKey, any> | undefined, enumerable?: boolean): PropertyKey[];
72
89
  export declare function getPropertyDescriptor(source: Record<PropertyKey, any>, override: Record<PropertyKey, any> | undefined, property: PropertyKey): PropertyDescriptor | undefined;
90
+ /**
91
+ * Store-wide mask bookkeeping (A20 re-rule 2026-07-07c): the store is the
92
+ * primitive, so an optimistic write decrees the WHOLE store settled for
93
+ * `isPending` — firewall, written leaves, untouched siblings, structural
94
+ * reads — for the lifetime of the override/transition. The firewall carries a
95
+ * count of masked targets (nested objects mask independently); companions of
96
+ * the firewall and its probed leaves are poked on 0↔1 transitions so an
97
+ * already-materialized verdict flips without waiting for another write.
98
+ */
99
+ export declare function maskStoreTarget(target: StoreNode, on: boolean): void;
73
100
  export declare const storeTraps: ProxyHandler<StoreNode>;
74
101
  export declare function storeSetter<T extends object>(store: Store<T>, fn: (draft: T) => T | void): void;
75
102
  /**
@@ -73,9 +73,9 @@ export declare class CollectionQueue extends Queue {
73
73
  * }
74
74
  * ```
75
75
  */
76
- export declare function createLoadingBoundary(fn: () => any, fallback: () => any, options?: {
76
+ export declare function createLoadingBoundary<T, U>(fn: () => T, fallback: () => U, options?: {
77
77
  on?: () => any;
78
- }): import("./signals.cjs").SourceAccessor<unknown>;
78
+ }): Accessor<T | U>;
79
79
  /**
80
80
  * Lower-level primitive that backs the `<Errored>` flow control. Catches
81
81
  * thrown errors inside `fn` and invokes `fallback(error, reset)` instead.
@@ -99,7 +99,7 @@ export declare function createLoadingBoundary(fn: () => any, fallback: () => any
99
99
  * }
100
100
  * ```
101
101
  */
102
- export declare function createErrorBoundary<U>(fn: () => any, fallback: (error: Accessor<unknown>, reset: () => void) => U): import("./signals.cjs").SourceAccessor<unknown>;
102
+ export declare function createErrorBoundary<T, U>(fn: () => T, fallback: (error: Accessor<unknown>, reset: () => void) => U): Accessor<T | U>;
103
103
  /**
104
104
  * Coordinate the reveal timing of sibling loading boundaries.
105
105
  *
@@ -1,6 +1,7 @@
1
1
  import { type OptimisticLane } from "./lanes.cjs";
2
2
  import type { Computed } from "./types.cjs";
3
3
  export declare function settlePendingSource(el: Computed<any>): void;
4
+ export declare function isThenable<T>(value: T | PromiseLike<T>): value is PromiseLike<T>;
4
5
  export declare function handleAsync<T>(el: Computed<T>, result: T | PromiseLike<T> | AsyncIterable<T>, setter?: (value: T) => void): T;
5
6
  export declare function clearStatus(el: Computed<any>, clearUninitialized?: boolean): void;
6
7
  export declare function notifyStatus(el: Computed<any>, status: number, error: any, blockStatus?: boolean, lane?: OptimisticLane): void;
@@ -7,7 +7,6 @@ export declare const REACTIVE_WRITE_IN_OWNED_SCOPE_REFRESH_MESSAGE: string;
7
7
  export declare let tracking: boolean;
8
8
  export declare let stale: boolean;
9
9
  export declare let pendingCheckActive: boolean;
10
- export declare let foundPending: boolean;
11
10
  export declare let latestReadActive: boolean;
12
11
  export declare let context: Owner | null;
13
12
  export declare let currentOptimisticLane: OptimisticLane | null;
@@ -98,12 +97,37 @@ export declare function setMemo<T>(el: Computed<T>, v: T | ((prev: T) => T)): T;
98
97
  * ```
99
98
  */
100
99
  export declare function runWithOwner<T>(owner: Owner | null, fn: () => T): T;
100
+ /**
101
+ * Keep the lazily-created isPending()/latest() companion nodes in sync with a
102
+ * new value. Every path that produces a value for `el` — direct set, async
103
+ * resolution, transition-held sync recompute — must route through here so a
104
+ * new write path can't silently skip the companions (#2831).
105
+ */
106
+ export declare function syncCompanions<T>(el: Signal<T> | Computed<T>, value: T): void;
101
107
  /**
102
108
  * Update _pendingSignal when pending state changes. When the override clears
103
109
  * (pending -> not pending), merge the sub-lane into the source's lane so
104
110
  * isPending effects are blocked until the full scope resolves.
105
111
  */
106
112
  export declare function updatePendingSignal(el: Signal<any> | Computed<any>): void;
113
+ /**
114
+ * A firewall's status change re-derives the verdicts of its probed leaves:
115
+ * leaf companions consult the firewall (broad inheritance), so async
116
+ * starting/settling on the firewall must poke them or they keep a stale
117
+ * verdict forever (V4 stuck-companion class, #2838).
118
+ */
119
+ export declare function updateChildCompanions(el: Computed<any>): void;
120
+ /**
121
+ * Settlement checkpoint (#2838): re-derive a node's companions directly from
122
+ * its committed state. Called when the transition machinery for the node is
123
+ * done with it — a pending commit or an optimistic revert. Verdicts are
124
+ * written committed (not through setSignal) because a transition-scoped
125
+ * override window opened here would itself need a settlement, re-scheduling
126
+ * forever while async is still in flight. This is what keeps companions
127
+ * coherent past transition completion: a verdict is a property of the data
128
+ * (A19), so it must survive the transition that happened to produce it.
129
+ */
130
+ export declare function snapCompanionsToState(owner: Signal<any> | Computed<any>): void;
107
131
  export declare function staleValues<T>(fn: () => T, set?: boolean): T;
108
132
  /**
109
133
  * Reads reactive expressions while bypassing any pending async overlay — i.e.
@@ -6,8 +6,8 @@ export interface DevHooks {
6
6
  onStoreNodeUpdate?: (state: any, property: PropertyKey, value: any, prev: any) => void;
7
7
  }
8
8
  export type DiagnosticSeverity = "warn" | "error";
9
- export type DiagnosticCode = "STRICT_READ_UNTRACKED" | "PENDING_ASYNC_UNTRACKED_READ" | "PENDING_ASYNC_FORBIDDEN_SCOPE" | "REACTIVE_WRITE_IN_OWNED_SCOPE" | "RUN_WITH_DISPOSED_OWNER" | "NO_OWNER_CLEANUP" | "CLEANUP_IN_FORBIDDEN_SCOPE" | "PRIMITIVE_IN_FORBIDDEN_SCOPE" | "NO_OWNER_EFFECT" | "NO_OWNER_BOUNDARY" | "ASYNC_OUTSIDE_LOADING_BOUNDARY" | "INVALID_REFRESH_TARGET" | "MISSING_EFFECT_FN" | "SYNC_NODE_RECEIVED_ASYNC";
10
- export type DiagnosticKind = "strict-read" | "async" | "write" | "lifecycle" | "owner";
9
+ export type DiagnosticCode = "STRICT_READ_UNTRACKED" | "PENDING_ASYNC_UNTRACKED_READ" | "PENDING_ASYNC_FORBIDDEN_SCOPE" | "REACTIVE_WRITE_IN_OWNED_SCOPE" | "RUN_WITH_DISPOSED_OWNER" | "NO_OWNER_CLEANUP" | "CLEANUP_IN_FORBIDDEN_SCOPE" | "SETTLED_CLEANUP_UNOWNED" | "PRIMITIVE_IN_FORBIDDEN_SCOPE" | "NO_OWNER_EFFECT" | "NO_OWNER_BOUNDARY" | "ASYNC_OUTSIDE_LOADING_BOUNDARY" | "INVALID_REFRESH_TARGET" | "MISSING_EFFECT_FN" | "SYNC_NODE_RECEIVED_ASYNC" | "REACTIVITY_HALTED" | "INVARIANT_VIOLATION";
10
+ export type DiagnosticKind = "strict-read" | "async" | "write" | "lifecycle" | "owner" | "error";
11
11
  export interface DiagnosticEvent {
12
12
  sequence: number;
13
13
  code: DiagnosticCode;
@@ -39,6 +39,14 @@ export interface Dev {
39
39
  getObservers: typeof getObservers;
40
40
  }
41
41
  export declare const DEV: Dev;
42
+ /**
43
+ * Dev-mode internal consistency check. A failure means the reactive system
44
+ * contradicted itself (not that user code misbehaved) — see
45
+ * INTERNALS-ASYNC-STATE.md for the invariant catalog. Throws under __TEST__
46
+ * so the suite (and fuzzing) treats any violation as a hard failure; logs in
47
+ * dev builds so user apps degrade instead of crashing.
48
+ */
49
+ export declare function assertInvariant(condition: boolean, name: string, message: string): void;
42
50
  export declare function emitDiagnostic(event: Omit<DiagnosticEvent, "sequence">): DiagnosticEvent;
43
51
  export declare function registerGraph(value: any, owner: Owner | null): void;
44
52
  export declare function clearSignals(node: Owner): void;
@@ -2,11 +2,10 @@ import type { Computed, NodeOptions, Owner } from "./types.cjs";
2
2
  export interface Effect<T> extends Computed<T>, Owner {
3
3
  _effectFn: (val: T, prev: T | undefined) => void | (() => void);
4
4
  _errorFn?: (err: unknown, cleanup: () => void) => void;
5
- _cleanup?: () => void;
6
- _cleanupRegistered?: boolean;
7
5
  _modified: boolean;
8
6
  _prevValue: T | undefined;
9
7
  _type: number;
8
+ _boundRunEffect?: () => void;
10
9
  }
11
10
  /**
12
11
  * Effects are the leaf nodes of our reactive graph. When their sources change, they are
@@ -19,7 +18,6 @@ export declare function effect<T>(compute: (prev: T | undefined) => T, effect: (
19
18
  schedule?: boolean;
20
19
  }): void;
21
20
  export interface TrackedEffect extends Computed<void> {
22
- _cleanup?: () => void;
23
21
  _modified: boolean;
24
22
  _type: number;
25
23
  _run: () => void;
@@ -2,4 +2,4 @@ import type { Computed, Link, Signal } from "./types.cjs";
2
2
  export declare function unlinkSubs(link: Link): Link | null;
3
3
  export declare function trimStaleDeps(el: Computed<any>): void;
4
4
  export declare function unobserved(el: Computed<unknown>): void;
5
- export declare function link(dep: Signal<any> | Computed<any>, sub: Computed<any>): void;
5
+ export declare function link(dep: Signal<any> | Computed<any>, sub: Computed<any>, pendingObserver?: boolean): void;
@@ -1,5 +1,5 @@
1
1
  export { ContextNotFoundError, NoOwnerError, NotReadyError } from "./error.cjs";
2
- export { isEqual, untrack, runWithOwner, computed, signal, read, setSignal, setMemo, suppressComputedRecompute, optimisticSignal, optimisticComputed, isPending, latest, refresh, staleValues, setSnapshotCapture, markSnapshotScope, releaseSnapshotScope, clearSnapshots } from "./core.cjs";
2
+ export { isEqual, untrack, runWithOwner, computed, signal, read, setSignal, setMemo, suppressComputedRecompute, optimisticSignal, optimisticComputed, isPending, latest, updatePendingSignal, updateChildCompanions, refresh, staleValues, setSnapshotCapture, markSnapshotScope, releaseSnapshotScope, clearSnapshots } from "./core.cjs";
3
3
  export { enableExternalSource, _resetExternalSourceConfig, type ExternalSourceFactory, type ExternalSource, type ExternalSourceConfig } from "./external.cjs";
4
4
  export { createOwner, createRoot, dispose, getNextChildId, getObserver, getOwner, isDisposed, cleanup, peekNextChildId } from "./owner.cjs";
5
5
  export { createContext, getContext, setContext, type Context, type ContextRecord } from "./context.cjs";
@@ -7,6 +7,6 @@ export { handleAsync } from "./async.cjs";
7
7
  export type { Computed, Disposable, FirewallSignal, Link, Owner, Root, Signal, NodeOptions } from "./types.cjs";
8
8
  export { effect, trackedEffect, type Effect, type TrackedEffect } from "./effect.cjs";
9
9
  export { action } from "./action.cjs";
10
- export { flush, Queue, GlobalQueue, trackOptimisticStore, enforceLoadingBoundary, type IQueue, type QueueCallback } from "./scheduler.cjs";
10
+ export { flush, Queue, GlobalQueue, trackOptimisticStore, enforceLoadingBoundary, resetErrorHalt, type IQueue, type QueueCallback } from "./scheduler.cjs";
11
11
  export { DEV, type Dev, type DevHooks, type DiagnosticCapture, type DiagnosticCode, type DiagnosticEvent, type DiagnosticKind, type Diagnostics, type DiagnosticSeverity } from "./dev.cjs";
12
12
  export * from "./constants.cjs";
@@ -0,0 +1,49 @@
1
+ import type { OptimisticLane } from "./lanes.cjs";
2
+ import type { Computed, Signal } from "./types.cjs";
3
+ /**
4
+ * Test-mode invariant checks for the async/transition/lane machinery.
5
+ * Catalog and rationale: packages/solid-signals/INTERNALS-ASYNC-STATE.md.
6
+ *
7
+ * These are implementation self-consistency checks, not semantic rules: a
8
+ * violation means the reactive system contradicted itself.
9
+ *
10
+ * They are gated on `__TEST__` (not just `__DEV__`): the per-write Set
11
+ * tracking and per-flush quiescence sweep are too expensive for shipped dev
12
+ * builds and for benchmarks (they showed up as a 5-21% hit across the
13
+ * CodSpeed suite when they ran under `__DEV__`). Call sites stay `__DEV__`
14
+ * guarded so production tree-shakes the calls; each entry point here
15
+ * early-returns unless `__TEST__` is set, so dev builds pay only a no-op
16
+ * call. The test suite (vitest run) defines `__TEST__: true`; benchmark mode
17
+ * defines `__TEST__: false`.
18
+ */
19
+ type AnyNode = Signal<any> | Computed<any>;
20
+ /** Wired by core.ts at module init to avoid import cycles. */
21
+ export declare const InvariantHooks: {
22
+ pendingProbeActive: (() => boolean) | null;
23
+ /** Fresh oracle for what an isPending companion SHOULD read right now. */
24
+ computePendingState: ((node: AnyNode) => boolean) | null;
25
+ };
26
+ export declare function devTrackHeldPending(node: AnyNode): void;
27
+ export declare function devTrackCompanionOwner(node: AnyNode): void;
28
+ export declare function devTrackOptimistic(node: AnyNode): void;
29
+ /**
30
+ * Open/close the sanctioned registration window. Call sites are `__DEV__`
31
+ * guarded (no prod cost); the code inside the window must not throw.
32
+ */
33
+ export declare function beginAsyncReporterWrites(): void;
34
+ export declare function endAsyncReporterWrites(): void;
35
+ export declare function createAsyncReporters(): Map<Computed<any>, Set<Computed<any>>>;
36
+ export declare function devCheckActiveOverrides(isRegisteredForRevert: (node: AnyNode) => boolean): void;
37
+ /** INV-1: an isPending() probe must never leak past its own call. */
38
+ export declare function devCheckFlushStart(): void;
39
+ /** INV-5: a merged lane's work moved to its root on merge and must stay empty. */
40
+ export declare function devCheckMergedLaneEmpty(lane: OptimisticLane): void;
41
+ export declare function devCensusCompanions(isQueuedForCommit?: (node: AnyNode) => boolean): void;
42
+ /**
43
+ * Quiescence checks. Run only when the system is fully drained: nothing
44
+ * scheduled, no active/stashed transitions, no live lanes. At that point no
45
+ * transition-scoped state may survive, and the lazily-created companions must
46
+ * agree with a fresh computation of their owner's state.
47
+ */
48
+ export declare function devCheckQuiescent(isQueuedForCommit: (node: AnyNode) => boolean): void;
49
+ export {};
@@ -41,6 +41,14 @@ export interface Transition {
41
41
  _gatedSubs: Set<Computed<any>>;
42
42
  }
43
43
  export declare function schedule(): void;
44
+ /**
45
+ * Permanently halts the reactive system. Called when a user error escapes
46
+ * every boundary — app state is undefined at that point, so scheduling stops
47
+ * entirely rather than limping along with a half-applied update.
48
+ */
49
+ export declare function haltReactivity(): void;
50
+ /** @internal Test/dev-reload hook. Revives scheduling after a halt. */
51
+ export declare function resetErrorHalt(): void;
44
52
  export interface IQueue {
45
53
  enqueue(type: number, fn: QueueCallback): void;
46
54
  run(type: number): boolean | void;