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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (134) hide show
  1. package/dist/dev-shared.js +6357 -0
  2. package/dist/dev.attribution.js +2485 -0
  3. package/dist/dev.js +2851 -7027
  4. package/dist/observe/affects.js +129 -0
  5. package/dist/observe/attribution.js +7 -0
  6. package/dist/observe/boundaries.js +641 -0
  7. package/dist/observe/core/action.js +177 -0
  8. package/dist/observe/core/async.js +846 -0
  9. package/dist/observe/core/attribution-costs.js +66 -0
  10. package/dist/observe/core/attribution-feedback.js +282 -0
  11. package/dist/observe/core/attribution-hooks.js +82 -0
  12. package/dist/observe/core/attribution-queries.js +28 -0
  13. package/dist/observe/core/attribution.js +2095 -0
  14. package/dist/observe/core/constants.js +248 -0
  15. package/dist/{types-cjs/core/context.d.cts → observe/core/context.js} +37 -12
  16. package/dist/observe/core/core.js +1789 -0
  17. package/dist/observe/core/dev.js +293 -0
  18. package/dist/observe/core/effect.js +195 -0
  19. package/dist/observe/core/error-hooks.js +71 -0
  20. package/dist/observe/core/error.js +80 -0
  21. package/dist/observe/core/external.js +98 -0
  22. package/dist/observe/core/graph.js +155 -0
  23. package/dist/observe/core/heap.js +147 -0
  24. package/dist/observe/core/invariants.js +45 -0
  25. package/dist/observe/core/lanes.js +205 -0
  26. package/dist/observe/core/optimistic.js +585 -0
  27. package/dist/observe/core/owner.js +322 -0
  28. package/dist/observe/core/scheduler.js +1428 -0
  29. package/dist/observe/core/verdict.js +669 -0
  30. package/dist/observe/index.js +59 -0
  31. package/dist/observe/map.js +484 -0
  32. package/dist/{types-cjs/signals.d.cts → observe/signals.js} +311 -317
  33. package/dist/observe/store/index.js +40 -0
  34. package/dist/observe/store/next/optimistic.js +660 -0
  35. package/dist/observe/store/next/projection.js +255 -0
  36. package/dist/observe/store/next/reconcile.js +375 -0
  37. package/dist/observe/store/next/store.js +2327 -0
  38. package/dist/observe/store/next/target.js +51 -0
  39. package/dist/observe/store/store.js +325 -0
  40. package/dist/observe/store/storePath.js +103 -0
  41. package/dist/observe/store/utils.js +1023 -0
  42. package/dist/prod/attribution.js +41 -0
  43. package/dist/prod/boundaries.js +128 -76
  44. package/dist/prod/core/action.js +65 -37
  45. package/dist/prod/core/async.js +324 -172
  46. package/dist/prod/core/constants.js +57 -1
  47. package/dist/prod/core/context.js +3 -3
  48. package/dist/prod/core/core.js +1003 -364
  49. package/dist/prod/core/dev.js +17 -1
  50. package/dist/prod/core/effect.js +76 -42
  51. package/dist/prod/core/error-hooks.js +71 -0
  52. package/dist/prod/core/external.js +4 -4
  53. package/dist/prod/core/graph.js +37 -37
  54. package/dist/prod/core/heap.js +61 -56
  55. package/dist/prod/core/lanes.js +107 -63
  56. package/dist/prod/core/optimistic.js +374 -93
  57. package/dist/prod/core/owner.js +62 -46
  58. package/dist/prod/core/scheduler.js +653 -286
  59. package/dist/prod/core/verdict.js +245 -127
  60. package/dist/prod/index.js +15 -5
  61. package/dist/prod/map.js +292 -141
  62. package/dist/prod/signals.js +29 -16
  63. package/dist/prod/store/next/optimistic.js +77 -55
  64. package/dist/prod/store/next/projection.js +31 -20
  65. package/dist/prod/store/next/reconcile.js +87 -84
  66. package/dist/prod/store/next/store.js +718 -401
  67. package/dist/prod/store/next/target.js +32 -10
  68. package/dist/prod/store/store.js +12 -14
  69. package/dist/prod/store/utils.js +950 -130
  70. package/dist/types/attribution.d.ts +20 -0
  71. package/dist/types/attribution.prod.d.ts +22 -0
  72. package/dist/types/boundaries.d.ts +10 -1
  73. package/dist/types/core/action.d.ts +12 -5
  74. package/dist/types/core/async.d.ts +1 -1
  75. package/dist/types/core/attribution-costs.d.ts +35 -0
  76. package/dist/types/core/attribution-feedback.d.ts +133 -0
  77. package/dist/types/core/attribution-hooks.d.ts +147 -9
  78. package/dist/types/core/attribution-queries.d.ts +10 -0
  79. package/dist/types/core/attribution.d.ts +216 -182
  80. package/dist/types/core/constants.d.ts +56 -0
  81. package/dist/types/core/core.d.ts +190 -2
  82. package/dist/types/core/dev.d.ts +246 -28
  83. package/dist/types/core/effect.d.ts +8 -1
  84. package/dist/types/core/error-hooks.d.ts +71 -0
  85. package/dist/types/core/index.d.ts +4 -1
  86. package/dist/types/core/invariants.d.ts +4 -0
  87. package/dist/types/core/lanes.d.ts +39 -5
  88. package/dist/types/core/scheduler.d.ts +153 -0
  89. package/dist/types/core/types.d.ts +32 -9
  90. package/dist/types/index.d.ts +10 -3
  91. package/dist/types/map.d.ts +2 -0
  92. package/dist/types/signals.d.ts +8 -0
  93. package/dist/types/store/index.d.ts +2 -0
  94. package/dist/types/store/next/optimistic.d.ts +1 -1
  95. package/dist/types/store/next/store.d.ts +11 -5
  96. package/dist/types/store/next/target.d.ts +37 -10
  97. package/dist/types/store/utils.d.ts +178 -0
  98. package/package.json +21 -17
  99. package/dist/node.cjs +0 -10541
  100. package/dist/node.dev.cjs +0 -13724
  101. package/dist/types-cjs/affects.d.cts +0 -47
  102. package/dist/types-cjs/boundaries.d.cts +0 -175
  103. package/dist/types-cjs/core/action.d.cts +0 -64
  104. package/dist/types-cjs/core/async.d.cts +0 -23
  105. package/dist/types-cjs/core/attribution-hooks.d.cts +0 -127
  106. package/dist/types-cjs/core/attribution.d.cts +0 -495
  107. package/dist/types-cjs/core/constants.d.cts +0 -159
  108. package/dist/types-cjs/core/core.d.cts +0 -185
  109. package/dist/types-cjs/core/dev.d.cts +0 -136
  110. package/dist/types-cjs/core/effect.d.cts +0 -30
  111. package/dist/types-cjs/core/error.d.cts +0 -56
  112. package/dist/types-cjs/core/external.d.cts +0 -15
  113. package/dist/types-cjs/core/graph.d.cts +0 -28
  114. package/dist/types-cjs/core/heap.d.cts +0 -24
  115. package/dist/types-cjs/core/index.d.cts +0 -13
  116. package/dist/types-cjs/core/invariants.d.cts +0 -59
  117. package/dist/types-cjs/core/lanes.d.cts +0 -54
  118. package/dist/types-cjs/core/optimistic.d.cts +0 -6
  119. package/dist/types-cjs/core/owner.d.cts +0 -124
  120. package/dist/types-cjs/core/scheduler.d.cts +0 -236
  121. package/dist/types-cjs/core/types.d.cts +0 -204
  122. package/dist/types-cjs/core/verdict.d.cts +0 -2
  123. package/dist/types-cjs/index.d.cts +0 -10
  124. package/dist/types-cjs/map.d.cts +0 -69
  125. package/dist/types-cjs/package.json +0 -3
  126. package/dist/types-cjs/store/index.d.cts +0 -18
  127. package/dist/types-cjs/store/next/optimistic.d.cts +0 -25
  128. package/dist/types-cjs/store/next/projection.d.cts +0 -8
  129. package/dist/types-cjs/store/next/reconcile.d.cts +0 -10
  130. package/dist/types-cjs/store/next/store.d.cts +0 -121
  131. package/dist/types-cjs/store/next/target.d.cts +0 -166
  132. package/dist/types-cjs/store/store.d.cts +0 -143
  133. package/dist/types-cjs/store/storePath.d.cts +0 -58
  134. package/dist/types-cjs/store/utils.d.cts +0 -74
@@ -0,0 +1,71 @@
1
+ import type { Owner } from "./types.js";
2
+ /**
3
+ * The client error hook — the prod-tier seam through which an app or an
4
+ * error monitor hears the one failure nothing else can see: an error
5
+ * boundary (`createErrorBoundary`, `<Errored>`) collected it and is rendering
6
+ * its fallback. The browser's global handlers hear what reaches
7
+ * `window.onerror`; a rendered fallback never does. An UNCAUGHT error is not
8
+ * this hook's: the halt (`REACTIVITY_HALTED`) hands its cause to the
9
+ * platform's `reportError`, the channel every monitor already listens on —
10
+ * one event, not two.
11
+ *
12
+ * Called once per error object: a boundary's `reset()` recomputing the same
13
+ * failing node re-collects the same error and does not report it again.
14
+ * Two tiers: ambient (`configureClientErrors`) and per root
15
+ * (`render`/`hydrate`'s `onError` in `@solidjs/web`), the nearest root's
16
+ * winning. Fires in every tier; no return — the client has no wire to map
17
+ * for. `ownerPath` carries the component labels where the runtime keeps
18
+ * owner names (the observe and dev artifacts).
19
+ *
20
+ * Pay-for-use: this module is retained by `createErrorBoundary` (which
21
+ * reports here) or the app's own `configureClientErrors` import. A root's
22
+ * hook is parked ON the root owner under a registered symbol
23
+ * (`ROOT_ERROR_HOOK`, defined in the scheduler), so `render` writes it
24
+ * without importing anything: an app that configures no hook and renders no
25
+ * boundary carries none of this.
26
+ */
27
+ export interface ClientErrorContext {
28
+ /**
29
+ * Where the error was THROWN: labels root-first up the owner chain of the
30
+ * computation that threw — component labels and named primitives — when
31
+ * the runtime keeps owner names (the observe and dev artifacts). The
32
+ * boundary's own chain when the thrower is unknown (a value thrown
33
+ * outside any computation).
34
+ */
35
+ ownerPath?: string[];
36
+ /**
37
+ * Where the error was MET: the same labels up the chain of the `<Errored>`
38
+ * that rendered its fallback for it — what the user saw, as against
39
+ * `ownerPath`, which is what broke.
40
+ */
41
+ boundaryPath?: string[];
42
+ }
43
+ export type ClientErrorHook = (error: unknown, context: ClientErrorContext) => void;
44
+ export interface ClientErrorsConfig {
45
+ /** The hook, or `undefined` to clear it. */
46
+ onError?: ClientErrorHook;
47
+ }
48
+ /**
49
+ * Registers the ambient client error hook — the one call a browser `init()`
50
+ * makes to see every failure a boundary renders a fallback for, in
51
+ * production. (Uncaught errors reach `reportError` / `window.onerror`.)
52
+ *
53
+ * ```ts
54
+ * configureClientErrors({
55
+ * onError: (error, { ownerPath }) =>
56
+ * Sentry.captureException(error, {
57
+ * mechanism: { type: "solid.error_boundary", handled: true }
58
+ * })
59
+ * });
60
+ * ```
61
+ */
62
+ export declare function configureClientErrors(config: ClientErrorsConfig): void;
63
+ /**
64
+ * Tells the client error hook about `error`, caught by the boundary whose
65
+ * owner is `owner`, thrown by `thrower` (the computation the engine's status
66
+ * wrapper named; unknown for a value that never crossed one) — once per
67
+ * error object. A throwing hook is reported on the console and otherwise
68
+ * ignored — a monitor must never take the app down.
69
+ * @internal
70
+ */
71
+ export declare function reportClientError(error: unknown, owner: Owner | null | undefined, thrower?: Owner | null): void;
@@ -9,5 +9,8 @@ export type { Computed, Disposable, FirewallSignal, Link, Owner, Root, Signal, N
9
9
  export { effect, trackedEffect, type Effect, type TrackedEffect } from "./effect.js";
10
10
  export { action } from "./action.js";
11
11
  export { flush, Queue, GlobalQueue, enforceLoadingBoundary, resetErrorHalt, type IQueue, type QueueCallback } from "./scheduler.js";
12
- export { DEV, type Dev, type DevHooks, type DiagnosticCapture, type DiagnosticCode, type DiagnosticEvent, type DiagnosticKind, type Diagnostics, type DiagnosticSeverity } from "./dev.js";
12
+ export type { AttributionHooks, InteractionRef, NavigationRef, OriginRef } from "./attribution-hooks.js";
13
+ export { ROOT_ERROR_HOOK } from "./scheduler.js";
14
+ export { configureClientErrors, type ClientErrorContext, type ClientErrorHook, type ClientErrorsConfig } from "./error-hooks.js";
15
+ export { DEV, OBSERVE, ownerPath, type AttributionSlot, type Dev, type Observe, type ServerObserve, type Records, type RecordTypes, type HostRecordTypes, type RecordType, type RecordEvent, type RecordLive, type RecordListener, type DevHooks, type DiagnosticCapture, type DiagnosticCode, type DiagnosticEvent, type DiagnosticKind, type DiagnosticListener, type Diagnostics, type DiagnosticSeverity, type DiagnosticSubject } from "./dev.js";
13
16
  export * from "./constants.js";
@@ -25,6 +25,10 @@ export declare const InvariantHooks: {
25
25
  };
26
26
  export declare function devTrackHeldPending(node: AnyNode): void;
27
27
  export declare function devTrackCompanionOwner(node: AnyNode): void;
28
+ /** #3503: a firewall child the store released (unobserved sweep) leaves the
29
+ * registry with it — the runtime drops it from `_companionChildren` so the
30
+ * projection stops retaining it; the test-only set must not either. */
31
+ export declare function devUntrackCompanionOwner(node: AnyNode): void;
28
32
  export declare function devTrackOptimistic(node: AnyNode): void;
29
33
  export declare function devTrackAffects(node: AnyNode): void;
30
34
  /**
@@ -1,3 +1,5 @@
1
+ import { hasActiveOverride } from "./core.js";
2
+ export { hasActiveOverride };
1
3
  import { type QueueCallback, type Transition } from "./scheduler.js";
2
4
  import type { Computed, Signal } from "./types.js";
3
5
  /**
@@ -26,14 +28,50 @@ export declare function getOrCreateLane(signal: Signal<any>): OptimisticLane;
26
28
  export declare function findLane(lane: OptimisticLane): OptimisticLane;
27
29
  /**
28
30
  * Is the lane held? `_pendingAsync` records the async the lane OWNS (derived
29
- * under it); the transaction's reporter map records the async a render effect
31
+ * under it); a transaction's reporter map records the async a render effect
30
32
  * OBSERVED pending with no boundary taking it (INV-3, the one registration
31
33
  * site). A hold needs both — the same rule the transaction itself uses, so a
32
34
  * memo nobody renders, or one a fallback-showing boundary caught, cannot tear
33
35
  * a frame and holds nothing (#3289). An orphan lane has no observation record
34
36
  * and never holds.
37
+ *
38
+ * The observation is looked up per NODE, in whichever live transaction
39
+ * recorded it — not in this lane's transaction. Lanes merge across
40
+ * transactions (#2912: ownership never travels through lanes), so after a
41
+ * merge the root's transaction holds the observations of only one member;
42
+ * the async the other member's transaction observed must hold the merged
43
+ * reveal just the same (A15 for lanes, #3335).
35
44
  */
36
45
  export declare function laneHeld(lane: OptimisticLane): boolean;
46
+ /**
47
+ * Lanes mirror transitions (#3460): a render effect OFF a HELD lane that reads
48
+ * a value the lane is revealing — an override, a `latest()` shadow — sees the
49
+ * committed value, exactly as a stale reader of a held transaction does
50
+ * (A15 reveal corollary): it publishes now, with the frame that is on screen
51
+ * (the lane defers its own readers' runs, so the committed value is what is
52
+ * visible), entangles nothing — a sync write is never held by a lane — and
53
+ * re-derives at the release. The release re-run rides the lane's own render
54
+ * queue, which runs when the lane reveals (runLaneEffects) or its transaction
55
+ * commits (cleanupCompletedLanes). A reader ON the lane computes the lane's
56
+ * reveal and takes the value as before.
57
+ *
58
+ * OFF the lane is provenance, not membership — the transaction mirror
59
+ * exactly: a stale reader of a transaction is a pass that runs outside it. A
60
+ * pass under the lane's own transaction is the lane's work — its write (lane
61
+ * posture), or the landing of its async, which re-enters the transaction
62
+ * (#3334) and runs a member with no ambient lane. Read as an outsider, that
63
+ * pass published the committed view and queued a replay that revealed the
64
+ * override beside its unready derivation at the release (`1:0` for an
65
+ * optimistic frame that never became ready; #3479 review). Membership is the
66
+ * wrong test the other way: a member re-run by a sibling's sync write is a
67
+ * mainline pass and shows the committed view.
68
+ */
69
+ export declare function readsHeldCommitted(owner: Computed<any>, c: Computed<any>): boolean;
70
+ /** The ownership relation for a lane hold (core `ownsHold`, §6 ruling 2): the
71
+ * running pass owns `lane`'s hold if it runs under the transition that owns
72
+ * the lane (the node's, resolved through override ownership and merges) or
73
+ * inside the lane itself. */
74
+ export declare function ownsLane(lane: OptimisticLane, owner: Computed<any>): boolean;
37
75
  /**
38
76
  * Merge two lanes when their dependency graphs overlap.
39
77
  */
@@ -43,10 +81,6 @@ export declare function mergeLanes(lane1: OptimisticLane, lane2: OptimisticLane)
43
81
  */
44
82
  export declare function resolveLane(el: Signal<any> | Computed<any>): OptimisticLane | undefined;
45
83
  export declare function resolveTransition(el: Signal<any> | Computed<any>): Transition | null | undefined;
46
- /**
47
- * Check if a node has an active optimistic override.
48
- */
49
- export declare function hasActiveOverride(el: Signal<any> | Computed<any>): boolean;
50
84
  /**
51
85
  * Assign or merge a lane onto a node. At convergence points (node already has
52
86
  * a different active lane), merge unless the node has an active override.
@@ -3,12 +3,20 @@ import { activeLanes, assignOrMergeLane, findLane, type OptimisticLane } from ".
3
3
  import type { Computed, Signal } from "./types.js";
4
4
  export { activeLanes, assignOrMergeLane, findLane };
5
5
  export { getOrCreateLane, hasActiveOverride, mergeLanes, resolveLane } from "./lanes.js";
6
+ export declare const transitions: Set<Transition>;
6
7
  export declare const dirtyQueue: Heap;
7
8
  export declare const zombieQueue: Heap;
8
9
  export declare let clock: number;
9
10
  export declare let activeTransition: Transition | null;
10
11
  export declare let projectionWriteActive: boolean;
12
+ /** > 0 while an action's generator body is on the stack (the synchronous
13
+ * slice between yields). Maintained by action.ts around `it.next()`. */
14
+ export declare let actionStepDepth: number;
15
+ export declare function enterActionStep(): void;
16
+ export declare function exitActionStep(): void;
11
17
  export declare let _hitUnhandledAsync: boolean;
18
+ /** Slot hook's deferral: release this node when its carried state resolves. */
19
+ export declare function deferSlotRelease(node: Signal<any>): void;
12
20
  /**
13
21
  * Consume the unhandled-async hit. Returns whether this is the first report
14
22
  * of the current enforcement window — the caller warns only then.
@@ -40,9 +48,18 @@ export interface Transition {
40
48
  _affectsNodes: OptimisticNode[];
41
49
  _optimisticStores: Set<any>;
42
50
  _actions: Array<Generator<any, any, any> | AsyncGenerator<any, any, any>>;
51
+ /** An action ran in this transaction (#3427, set by action()): once
52
+ * `_actions` drains, its bodies are OVER — as opposed to a transaction that
53
+ * never had one, whose bare optimistic writes live until it settles. */
54
+ _acted?: boolean;
43
55
  _queueStash: QueueStub;
44
56
  _done: boolean | Transition;
45
57
  _gatedSubs: Set<Computed<any>>;
58
+ /** Effects whose single value slot was written under this transaction AND
59
+ * another live one (#3322). Re-dirtied at commit, ahead of the effect
60
+ * phase, so the run publishes a value derived from the committed world
61
+ * rather than whichever transaction's staged view wrote last. */
62
+ _contested: Computed<any>[] | null;
46
63
  }
47
64
  /**
48
65
  * Flip-entanglement (#3164 follow-up): `until()` is a declaration of
@@ -63,11 +80,44 @@ export interface Transition {
63
80
  */
64
81
  export declare function entangleConfirmingTransitions(obs: Computed<any>, target: Transition): void;
65
82
  export declare function schedule(): void;
83
+ /**
84
+ * Parked transactions whose reporter set changed without a write. A
85
+ * transaction completes when nothing live reports a flight it waits on, but
86
+ * the flush only judges the ACTIVE transaction: a parked one is re-entered by
87
+ * a stamped node's landing or an action's resume. A reporter that stops
88
+ * counting for another reason — its loading boundary flipped to the fallback
89
+ * (#3375), or it was disposed by ambient work (#3372) — is neither: the
90
+ * pruning in `reporterBlocksSource` would drop it at the next check, but no
91
+ * check comes, and the writes held with it stay staged. Such sites record the
92
+ * transaction here (deduped: one idle pass per transaction, however many
93
+ * reporters changed); the flush re-enters it on an otherwise idle pass, so
94
+ * the re-evaluation adopts no unrelated ambient work.
95
+ */
96
+ export declare const wokenTransitions: Transition[];
97
+ /** Wake every parked transaction — for a site that knows a reporter stopped
98
+ * counting but not whose (a boundary reset). */
99
+ export declare function wakeParked(): void;
100
+ /** Transactions a mainline tick has PROPOSED against (A34, #3494): a write to a
101
+ * node one of them holds — the same value or another — is a second proposal
102
+ * on a contested node, and the tick reveals with the hold ("both are
103
+ * suggesting a value; if one finished before the other that would be odd").
104
+ * Entered at the next flush's start, where the ambient batch is adopted;
105
+ * never from the write itself, which left `activeTransition` set across the
106
+ * caller's block and made creation after the write the transaction's (A29). */
107
+ export declare const batchJoins: Transition[];
66
108
  /**
67
109
  * Permanently halts the reactive system. Called when a user error escapes
68
110
  * every boundary — app state is undefined at that point, so scheduling stops
69
111
  * entirely rather than limping along with a half-applied update.
70
112
  */
113
+ /**
114
+ * The key a root owner carries its client error hook under (`render`'s
115
+ * `onError`) — registered, so a runtime writes it with no import of the hook
116
+ * module (core/error-hooks.ts) and no property mangling in the way. Defined
117
+ * HERE, not there: a runtime that only writes the key must not retain the
118
+ * hook machinery (pay-for-use).
119
+ */
120
+ export declare const ROOT_ERROR_HOOK: unique symbol;
71
121
  export declare function haltReactivity(cause?: unknown): void;
72
122
  /** @internal Test/dev-reload hook. Revives scheduling after a halt. */
73
123
  export declare function resetErrorHalt(): void;
@@ -81,6 +131,11 @@ export interface IQueue {
81
131
  stashQueues(stub: QueueStub): void;
82
132
  restoreQueues(stub: QueueStub): void;
83
133
  _parent: IQueue | null;
134
+ /** Loading/error boundary queues (boundaries.ts): the status dimension the
135
+ * queue consumes, and whether it currently shows content (initialized) or
136
+ * its fallback (collecting). Read by `reporterBlocksSource`. */
137
+ _collectionType?: number;
138
+ _initialized?: boolean;
84
139
  }
85
140
  export declare class Queue implements IQueue {
86
141
  _parent: IQueue | null;
@@ -131,6 +186,11 @@ export declare class GlobalQueue extends Queue {
131
186
  static _drainPatchOptimistic: (() => void) | null;
132
187
  static _gatedRead: ((el: Signal<any>, owner: OptimisticNode, c: Computed<any>) => boolean) | null;
133
188
  static _laneSuspends: ((owner: OptimisticNode) => boolean) | null;
189
+ /** Is the node routed through a LIVE lane (`resolveLane`)? read()'s reveal
190
+ * carve-out asks before showing a foreign-held pending node's committed
191
+ * value: a lane-derived flight's inputs are already revealed through the
192
+ * lane (#3334). Gated on CONFIG_HAS_LANE, which only the engine sets. */
193
+ static _laneLive: ((el: Computed<any>) => boolean) | null;
134
194
  static _laneReadsCommitted: ((el: OptimisticNode, owner: OptimisticNode, c: Computed<any>) => boolean) | null;
135
195
  static _recomputeLane: ((el: Computed<any>, own: boolean) => OptimisticLane | null | false) | null;
136
196
  static _laneAsyncPending: ((el: Computed<any>) => void) | null;
@@ -140,6 +200,44 @@ export declare class GlobalQueue extends Queue {
140
200
  * the gate holds (#3303). */
141
201
  static _notifyAuthoritativeObservers: ((el: Signal<any> | Computed<any>) => void) | null;
142
202
  static _laneAsyncSettled: ((el: Computed<any>) => void) | null;
203
+ /** A18 supersession (#3331): own-source truth `value` landed under an active
204
+ * override. The engine decides whether the graph re-derives — the value
205
+ * differs from the override and is not a stale (older-action) answer (mark
206
+ * the node, demote its lane cascade, notify), or returns to it after an
207
+ * earlier differing arrival (clear the mark, notify) — and owns the
208
+ * authoritative-observer wake for a silent confirm. Installed with the
209
+ * optimistic engine; only reachable on a node that has an override. */
210
+ static _supersedeOverride: ((el: Signal<any> | Computed<any>, value: unknown) => void) | null;
211
+ /** The flush's pre-verdict step (#3427): once the transaction's action
212
+ * bodies have all ended and nothing authoritative is left in flight, the
213
+ * engine supersedes every override still in force with the truth it
214
+ * reverts to, so the graph re-derives from it now, as the transaction's
215
+ * held work, instead of after the flights the overrides fed have landed.
216
+ * True when it superseded something: the caller re-runs the heap ahead of
217
+ * the verdict. The engine owns every gate (acted, actions drained, has
218
+ * overrides, no store edits, no authoritative flight); null without it. */
219
+ static _endOptimism: ((transition: Transition) => boolean) | null;
220
+ /** read()'s value for a TRACKED reader of a superseded node (#3331): the
221
+ * staged truth, unless the reader is a stale (render) reader of another
222
+ * transaction — then the displayed override, as it keeps a foreign
223
+ * transaction's committed value over its staged write. */
224
+ /** A tracked read of an active override: the lane outside-view rule
225
+ * (#3460) and the A18 supersession selection (#3331) — see optimistic.ts. */
226
+ static _overrideRead: ((el: Computed<any>, c: Computed<any>) => unknown) | null;
227
+ /** A lane pass's publish for a memo (#3479, lanes stage): the speculative
228
+ * result becomes a DERIVED override, `_value` stays committed — see
229
+ * optimistic.ts laneOverride. Set with the engine, which a lane implies. */
230
+ static _laneOverride: ((el: Computed<any>, value: unknown, lane: OptimisticLane) => void) | null;
231
+ /** Verdict-layer recompute in progress (companion creation, latest()/
232
+ * isPending() pulls): never born held — see core.ts enterStagedRead. */
233
+ static _verdictPull: boolean;
234
+ /** setSignal's authoritative (projection-write) landing on an override-
235
+ * covered node (#3331 store twin): stage the truth for its transaction's
236
+ * commit whatever its relation to the committed value — a landing equal to
237
+ * committed still differs from the override — then _supersedeOverride
238
+ * decides. Installed with the optimistic engine; only reachable on a node
239
+ * that has an override. */
240
+ static _landOnOverride: (<T>(el: Signal<T> | Computed<T>, v: T | ((prev: T) => T)) => T) | null;
143
241
  static _trackOptimisticStore: ((store: any) => void) | null;
144
242
  flush(): void;
145
243
  notify(node: Computed<any>, mask: number, flags: number, error?: any): boolean;
@@ -154,6 +252,21 @@ export declare let reaskArmed: boolean;
154
252
  export declare let notifyEpoch: number;
155
253
  export declare function bumpNotifyEpoch(): void;
156
254
  export declare function armReaskClear(): void;
255
+ /** Provenance of the work currently running (A18 supersession, #3331): the
256
+ * invocation sequence of the action whose ambient window this is — set by
257
+ * action() for each slice; the flush that ends the window clears it — or,
258
+ * inside an async landing, the sequence captured when that flight was
259
+ * registered (asyncWrite sets it for the landing's synchronous propagation,
260
+ * so a sync recompute downstream of the landing — an optimistic wrapper over
261
+ * the async source — derives under the flight's provenance, and flights it
262
+ * registers inherit it). 0 is mainline: no action, always the current
263
+ * question. An override stamps this at its write (`_overrideStamp`); an
264
+ * answer whose flight an OLDER action issued is a stale question the user
265
+ * has since changed — it holds silently to commit instead of superseding. A
266
+ * slow source must not leak back in over a newer intent. Transactions merge,
267
+ * so the transition object cannot say WHICH action asked; this can. */
268
+ export declare let origin: number;
269
+ export declare function setOrigin(seq: number): number;
157
270
  export declare function insertSubs(node: Signal<any> | Computed<any>, optimistic?: boolean): void;
158
271
  export declare let storeCommitHook: (() => void) | null;
159
272
  export declare function setStoreCommitHook(fn: () => void): void;
@@ -165,6 +278,15 @@ export declare function setStoreCommitHook(fn: () => void): void;
165
278
  * storeCommitHook to stay tree-shakeable. */
166
279
  export declare let patchCommitHook: ((batch: Transition) => void) | null;
167
280
  export declare function setPatchCommitHook(fn: (batch: Transition) => void): void;
281
+ /** Unchanged passes with a stale dependency tail, waiting on this flush's
282
+ * verdict (A30, #3469). A pass that changed nothing replaced nothing either —
283
+ * and cannot know at its own tail whether the flush that ran it will park:
284
+ * parked, its inputs are held and the committed frame still derives from the
285
+ * tail (`b() ? b() : a()` computed `1` from the held `b`, equal to the `1` it
286
+ * had from `a` — with `a` trimmed, the mainline `a = 2` never reached it).
287
+ * Trimmed when the flush commits; dropped with a park, the tail stays linked
288
+ * until a committing pass trims it (one spurious recompute at most). */
289
+ export declare const heldTrims: Computed<any>[];
168
290
  export declare function finalizePureQueue(completingTransition?: Transition | null, incomplete?: boolean): void;
169
291
  /**
170
292
  * Count of live `affects()` registrations across the system (including
@@ -214,12 +336,43 @@ export declare const globalQueue: GlobalQueue;
214
336
  */
215
337
  export declare function flush(): void;
216
338
  export declare function flush<T>(fn: () => T): T;
339
+ /**
340
+ * Does a live reporter of `transition` still observe `source` pending? Dead
341
+ * reporters (disposed, behind a fallback, no longer reading the source) are
342
+ * pruned as they are found, and the source's entry with them. Shared by the
343
+ * settle verdict and the lane's hold check (`waitingTransition`): a live
344
+ * action parks its transaction without a verdict, so this prune is the only
345
+ * one an optimistic lane whose last async reader unmounted mid-action ever
346
+ * gets — without it the lane held on the dead reporter's registration until
347
+ * the flight it no longer observed landed (#3426).
348
+ */
349
+ export declare function sourceObserved(transition: Transition, source: Computed<any>, verdict?: Transition): boolean;
217
350
  /** A fresh, unentered transaction (#3146): the optimistic store's truth
218
351
  * flight DECLARES an owned transaction instead of relying on whatever the
219
352
  * ambient adoption machinery stamped on its firewall. Activate it with
220
353
  * initTransition; it is a plain batch until then. */
221
354
  export declare function createTransition(): Transition;
222
355
  export declare function currentTransition(transition: Transition): Transition;
356
+ /**
357
+ * The live transition blocked on `source` — the one whose render reader
358
+ * observed it pending (INV-3 records the observation in whichever transaction
359
+ * was active when the reader was notified). The observation is a fact about
360
+ * the node, so a hold check must not assume it was recorded in the transaction
361
+ * it happens to hold — lanes merge across transactions (#2912), and a merged
362
+ * root's transaction knows nothing of the async its members' transactions
363
+ * observed (#3335). Null when nobody is waiting — a registration whose every
364
+ * reporter has since died is nobody (#3426).
365
+ */
366
+ export declare function waitingTransition(source: Computed<any>): Transition | null;
367
+ /** A landing enters EVERY parked transaction still waiting on `source`, folding
368
+ * them into the active one (A15: each reveal that discovered the flight
369
+ * completes at its landing). The fold used to happen as the waiters' stamped
370
+ * readers recomputed under the landing — recompute re-entering an effect's
371
+ * stamp — which also folded in writes those readers merely shared a hole
372
+ * with (#3407); effects no longer re-enter, so the landing folds explicitly.
373
+ * Live iteration is safe: a merge deletes the outgoing (active) entry and
374
+ * re-adds the visited one. */
375
+ export declare function enterWaiting(source: Computed<any>): void;
223
376
  export declare function setActiveTransition(transition: Transition | null): void;
224
377
  export declare function runInTransition<T>(transition: Transition, fn: () => T): T;
225
378
  /** Run `fn` with `transition` as BOTH the ambient transaction and the
@@ -68,6 +68,19 @@ export interface NodeExtension {
68
68
  * layer's STORE_OPTIMISTIC_OWNERS stamps (#2899). `null` = ambient write.
69
69
  */
70
70
  _overrideOwner: Transition | null | undefined;
71
+ /** `clock` at the active override's write. A sync recompute in the same
72
+ * tick derives from inputs that predate the override and does not
73
+ * supersede it (A18 supersession ordering, #3331). */
74
+ _overrideTime: number;
75
+ /** A28: the staged value the last flush left on a HELD node that has since
76
+ * been rewritten (latest() keeps answering with it); NOT_PENDING otherwise. */
77
+ _flushedStaged: unknown;
78
+ /** Provenance of the active override's write: the scheduler's `origin` (the
79
+ * asking action's invocation sequence; 0 = mainline). An arriving answer
80
+ * whose flight an older action issued asked a question the override has
81
+ * since changed: it holds to commit instead of superseding (A18
82
+ * supersession provenance, #3331). */
83
+ _overrideStamp: number;
71
84
  _optimisticLane: OptimisticLane | undefined;
72
85
  _pendingSignal: Signal<boolean> | undefined;
73
86
  _latestValueComputed: Computed<any> | undefined;
@@ -112,13 +125,19 @@ export interface NodeExtension {
112
125
  export interface RawSignal<T> {
113
126
  _subs: Link | null;
114
127
  _subsTail: Link | null;
128
+ _value: T;
115
129
  /**
116
- * DEV-only live subscriber count. Maintained by `link`/`unlinkSubs` for
117
- * graph-size diagnostics; undefined in production.
130
+ * Observe-tier label (`name` option, or the node kind: `signal`,
131
+ * `computed`, `effect`…). A slot in the observe/dev literals — never a
132
+ * post-construction write — and absent from the prod literals entirely.
118
133
  */
119
- _subCount?: number;
120
- _value: T;
121
134
  _name?: string;
135
+ /**
136
+ * Observe-tier: the owner in scope when a user-facing signal was created
137
+ * (`registerGraph`), so diagnostics about the signal get an owner path.
138
+ * A slot in the observe/dev `signal()` literal; absent from prod.
139
+ */
140
+ _owner?: Owner | null;
122
141
  _equals: false | ((a: T, b: T) => boolean);
123
142
  _config: number;
124
143
  _time: number;
@@ -137,7 +156,10 @@ export interface RawSignal<T> {
137
156
  }
138
157
  export interface FirewallSignal<T> extends RawSignal<T> {
139
158
  _firewall: Computed<any>;
159
+ /** Doubly-linked child chain on the firewall's extension (`_x._child` is
160
+ * the head): released leaves unlink in O(1) (#3351). */
140
161
  _nextChild: FirewallSignal<unknown> | null;
162
+ _prevChild: FirewallSignal<unknown> | null;
141
163
  }
142
164
  export type Signal<T> = RawSignal<T> | FirewallSignal<T>;
143
165
  export interface Owner {
@@ -156,15 +178,16 @@ export interface Owner {
156
178
  _prevSibling: Owner | null;
157
179
  /** Cold extension — see NodeExtension (owners use the zombie-pair slots). */
158
180
  _x: NodeExtension | null;
181
+ /**
182
+ * Observe-tier label: the `name` option, the node kind (`computed`,
183
+ * `effect`…), or the component label the rendering layer writes on a root
184
+ * (`<App>`). A slot in the observe/dev literals; absent from prod.
185
+ */
186
+ _name?: string;
159
187
  }
160
188
  export interface Computed<T> extends RawSignal<T>, Owner {
161
189
  _deps: Link | null;
162
190
  _depsTail: Link | null;
163
- /**
164
- * DEV-only live source count. Maintained by `link`/`unlinkSubs` for
165
- * graph-size diagnostics; undefined in production.
166
- */
167
- _depCount?: number;
168
191
  /** Recompute-pass counter; bumped when dep revalidation starts. */
169
192
  _depGen: number;
170
193
  _flags: number;
@@ -1,7 +1,14 @@
1
- export { $REFRESH, ContextNotFoundError, NoOwnerError, NotReadyError, TimeoutError, action, createContext, createOwner, createRoot, runWithOwner, flush, getNextChildId, peekNextChildId, getContext, setContext, getOwner, isDisposed, getObserver, isEqual, untrack, isPending, latest, SUPPORTS_PROXY, setSnapshotCapture, markSnapshotScope, releaseSnapshotScope, clearSnapshots, enforceLoadingBoundary, enableExternalSource, resetErrorHalt } from "./core/index.js";
2
- import { type Dev } from "./core/index.js";
1
+ export { $REFRESH, ContextNotFoundError, NoOwnerError, NotReadyError, TimeoutError, action, createContext, createOwner, createRoot, runWithOwner, flush, getNextChildId, peekNextChildId, getContext, setContext, getOwner, isDisposed, getObserver, isEqual, untrack, isPending, latest, SUPPORTS_PROXY, setSnapshotCapture, markSnapshotScope, releaseSnapshotScope, clearSnapshots, enforceLoadingBoundary, enableExternalSource, resetErrorHalt, ownerPath, configureClientErrors, ROOT_ERROR_HOOK } from "./core/index.js";
2
+ import { type Dev, type Observe } from "./core/index.js";
3
+ /**
4
+ * Observe tier (diagnostics channel, attribution hook slot + interaction
5
+ * frame): dev and observe builds. The attribution engine itself is the
6
+ * `@solidjs/signals/attribution` entry.
7
+ */
8
+ export declare const OBSERVE: Observe | undefined;
9
+ /** Dev tier (devtools hooks, graph traversal, console reporting): dev builds only. */
3
10
  export declare const DEV: Dev | undefined;
4
- export type { Owner, Context, ContextRecord, IQueue, ExternalSourceFactory, ExternalSource, ExternalSourceConfig, Refreshable, Dev, DevHooks, DiagnosticCapture, DiagnosticCode, DiagnosticEvent, DiagnosticKind, Diagnostics, DiagnosticSeverity } from "./core/index.js";
11
+ export type { Owner, Context, ContextRecord, IQueue, ExternalSourceFactory, ExternalSource, ExternalSourceConfig, Refreshable, AttributionHooks, AttributionSlot, ClientErrorContext, ClientErrorHook, ClientErrorsConfig, InteractionRef, NavigationRef, OriginRef, Dev, Observe, ServerObserve, Records, RecordTypes, HostRecordTypes, RecordType, RecordEvent, RecordLive, RecordListener, DevHooks, DiagnosticCapture, DiagnosticCode, DiagnosticEvent, DiagnosticKind, DiagnosticListener, Diagnostics, DiagnosticSeverity, DiagnosticSubject } from "./core/index.js";
5
12
  export { createSignal, createMemo, createEffect, createRenderEffect, createTrackedEffect, createReaction, createOptimistic, refresh, resolve, until, onSettled, onCleanup } from "./signals.js";
6
13
  export type { Truthy, UntilOptions, Accessor, SourceAccessor, Setter, Signal, ComputeFunction, EffectFunction, EffectBundle, EffectOptions, SignalOptions, MemoOptions, NoInfer } from "./signals.js";
7
14
  export { affects } from "./affects.js";
@@ -47,6 +47,8 @@ export declare function mapArray<Item, MappedItem>(list: Accessor<Maybe<readonly
47
47
  fallback?: Accessor<any>;
48
48
  name?: string;
49
49
  }): Accessor<MappedItem[]>;
50
+ /** @internal */
51
+ export declare function __smallMoveHits(): number;
50
52
  /**
51
53
  * Reactively renders a callback `count` times, reusing previously-rendered
52
54
  * entries when only the count changes. Underlying helper for `<Repeat>`.
@@ -582,12 +582,20 @@ export interface UntilOptions {
582
582
  *
583
583
  * Must be called *outside* a tracking scope.
584
584
  *
585
+ * Inside an action, call it from a step: after an `await`, put a bare `yield`
586
+ * before `yield until(...)`. The runtime cannot hook an async generator's
587
+ * `await` continuation, so the `until(...)` expression — which CREATES the
588
+ * predicate's reader — would otherwise run outside the transaction; created
589
+ * there it is born held (A29) and replays only at the commit its own promise
590
+ * holds open (#3482). See {@link action}.
591
+ *
585
592
  * @example
586
593
  * ```ts
587
594
  * const send = action(async function* (text: string) {
588
595
  * const clientId = crypto.randomUUID();
589
596
  * setMessages(m => { m.push({ clientId, text, pending: true }); }); // optimistic
590
597
  * await socket.send({ clientId, text }); // fire-and-forget transport
598
+ * yield; // re-enter the transaction after the await
591
599
  * // Hold until the live source echoes the write (authoritative view —
592
600
  * // the optimistic row above cannot satisfy this):
593
601
  * yield until(() => messages.some(m => m.clientId === clientId), { timeout: 10_000 });
@@ -1,6 +1,8 @@
1
1
  export type { Store, StoreReturn, ProjectionStoreReturn, StoreSetter, StoreNode, StoreOptions, ProjectionOptions, NotWrappable, SolidStore } from "./store.js";
2
2
  export type { Merge, Omit } from "./utils.js";
3
3
  export { isWrappable, $TRACK, $PROXY, $TARGET } from "./store.js";
4
+ export { mergeSources, mergeView, viewOf, omitView, sourceKeys, sourceHas, sourceGet, hasStaticKeys, isStatic, resolvedTable, OmitView, MergeView, SOURCE_PLAIN, SOURCE_OMIT, SOURCE_PROXY, SOURCE_MEMO, SOURCE_MERGE, sourceOwners } from "./utils.js";
5
+ export type { SourceKind } from "./utils.js";
4
6
  import type { NoFn, ProjectionOptions, Store, StoreOptions, StoreSetter } from "./store.js";
5
7
  import type { Refreshable } from "../core/index.js";
6
8
  export { createProjectionNext as createProjection } from "./next/projection.js";
@@ -22,4 +22,4 @@ export declare function notifyOptimisticWrites(t: StoreNextTarget, pb: Record<Pr
22
22
  * Authoritative-view reads (until()'s predicate) skip composition entirely:
23
23
  * the predicate observes authoritative truth, never the caller's tentative
24
24
  * overlay. (Write-side emission callers never run under such a compute.) */
25
- export declare function optimisticView(t: StoreNextTarget, src: Record<PropertyKey, any>): Record<PropertyKey, any>;
25
+ export declare function optimisticView(t: StoreNextTarget, src: Record<PropertyKey, any>, draft?: boolean): Record<PropertyKey, any>;
@@ -1,3 +1,4 @@
1
+ import { hasActiveOverride, visibleOverride } from "../../core/core.js";
1
2
  import type { Signal } from "../../core/types.js";
2
3
  import { type StoreNextFamily, type StoreNextTarget } from "./target.js";
3
4
  export declare function wrapNext<T extends Record<PropertyKey, any>>(value: T, parent?: StoreNextTarget | null, parentKey?: PropertyKey | null, fam?: StoreNextFamily | null): T;
@@ -15,6 +16,11 @@ export declare function bumpDeep(t: StoreNextTarget): void;
15
16
  * the clone path. Consumers that need a complete container (reconcile's
16
17
  * diff walks, drafts escaping into other storage) call this. */
17
18
  export declare function materializePB(target: StoreNextTarget): void;
19
+ /** Resolve the held committed view (#3074): answers the masked old backing
20
+ * while the hold is live, and lazily clears a hold whose transition has
21
+ * committed (transitions merge — resolve through currentTransition, same as
22
+ * foldHeld's node stamps). */
23
+ export declare function heldMaskView(t: StoreNextTarget): Record<PropertyKey, any> | null;
18
24
  /**
19
25
  * Adoption (2026-08-16c): the incoming object becomes the committed backing
20
26
  * IMMEDIATELY — reconcile is eagerly visible to every reader (shipped
@@ -60,9 +66,7 @@ export declare function notifyFold(t: StoreNextTarget, old: Record<PropertyKey,
60
66
  * share the instance core reads — cross-module live-binding writes from other
61
67
  * store modules were observed not to propagate under the test transform). */
62
68
  export declare function runAuthoritative<T>(fn: () => T): T;
63
- /** Active optimistic override on an armed node (armed slot idles at
64
- * NOT_PENDING; undefined = unarmed plain node). */
65
- export declare function hasActiveOverride(node: Signal<any>): boolean;
69
+ export { hasActiveOverride, visibleOverride };
66
70
  /** The reading computation is until()'s authoritative-view predicate — same
67
71
  * source of truth as core read()'s A17 carve-out (`context`, which persists
68
72
  * under untrack). optimisticView()'s composition gate consults exactly this:
@@ -81,8 +85,10 @@ export declare function authoritativeServe(): boolean;
81
85
  export type SetStoreNextFunction<T> = (fn: (draft: T) => T | void) => void;
82
86
  /** Low-level setter primitive: opens write mode on a next proxy, runs `fn`,
83
87
  * emits write-time notifications at outermost exit, applies returned
84
- * replacements as adoptions. `guard=false` skips the owned-scope dev guard —
85
- * projection recomputes legitimately write from inside their computed. */
88
+ * replacements as adoptions. `guard=false` skips the dev guards (owned-scope
89
+ * write, thenable result) — projection recomputes legitimately write from
90
+ * inside their computed, and their async derive is handled by the recompute,
91
+ * not returned through here. */
86
92
  export declare function storeSetterNext<T>(proxy: T, fn: (draft: T) => T | void, guard?: boolean): void;
87
93
  export declare function createStoreNext<T extends Record<PropertyKey, any>>(initialValue: T, shallow?: boolean): [T, SetStoreNextFunction<T>];
88
94
  /** True when `proxy` is a SHALLOW store (children served verbatim, slots