@solidjs/signals 2.0.0-rc.1 → 2.0.0-rc.10

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 (150) hide show
  1. package/dist/dev-shared.js +7138 -0
  2. package/dist/dev.attribution.js +3307 -0
  3. package/dist/dev.js +5691 -4491
  4. package/dist/observe/affects.js +129 -0
  5. package/dist/observe/attribution.js +7 -0
  6. package/dist/observe/boundaries.js +793 -0
  7. package/dist/observe/core/action.js +177 -0
  8. package/dist/observe/core/async.js +849 -0
  9. package/dist/observe/core/attribution-costs.js +66 -0
  10. package/dist/observe/core/attribution-feedback.js +280 -0
  11. package/dist/observe/core/attribution-hooks.js +83 -0
  12. package/dist/observe/core/attribution-queries.js +43 -0
  13. package/dist/observe/core/attribution.js +2904 -0
  14. package/dist/observe/core/constants.js +283 -0
  15. package/dist/{types-cjs/core/context.d.cts → observe/core/context.js} +37 -12
  16. package/dist/observe/core/core.js +1999 -0
  17. package/dist/observe/core/dev.js +343 -0
  18. package/dist/observe/core/effect.js +200 -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 +627 -0
  27. package/dist/observe/core/owner.js +353 -0
  28. package/dist/observe/core/scheduler.js +1547 -0
  29. package/dist/observe/core/verdict.js +674 -0
  30. package/dist/observe/index.js +59 -0
  31. package/dist/observe/map.js +484 -0
  32. package/dist/observe/signals.js +731 -0
  33. package/dist/observe/store/index.js +44 -0
  34. package/dist/observe/store/next/optimistic.js +717 -0
  35. package/dist/observe/store/next/projection.js +266 -0
  36. package/dist/observe/store/next/reconcile.js +375 -0
  37. package/dist/observe/store/next/store.js +2480 -0
  38. package/dist/observe/store/next/target.js +51 -0
  39. package/dist/observe/store/store.js +331 -0
  40. package/dist/observe/store/storePath.js +103 -0
  41. package/dist/observe/store/utils.js +1070 -0
  42. package/dist/prod/affects.js +10 -9
  43. package/dist/prod/attribution.js +45 -0
  44. package/dist/prod/boundaries.js +388 -178
  45. package/dist/prod/core/action.js +65 -37
  46. package/dist/prod/core/async.js +378 -163
  47. package/dist/prod/core/attribution-hooks.js +3 -0
  48. package/dist/prod/core/constants.js +186 -1
  49. package/dist/prod/core/context.js +10 -16
  50. package/dist/prod/core/core.js +1546 -416
  51. package/dist/prod/core/dev.js +18 -1
  52. package/dist/prod/core/effect.js +119 -79
  53. package/dist/prod/core/error-hooks.js +71 -0
  54. package/dist/prod/core/error.js +13 -1
  55. package/dist/prod/core/external.js +4 -4
  56. package/dist/prod/core/graph.js +105 -54
  57. package/dist/prod/core/heap.js +72 -65
  58. package/dist/prod/core/invariants.js +3 -2
  59. package/dist/prod/core/lanes.js +117 -52
  60. package/dist/prod/core/optimistic.js +458 -104
  61. package/dist/prod/core/owner.js +131 -84
  62. package/dist/prod/core/scheduler.js +998 -241
  63. package/dist/prod/core/verdict.js +417 -112
  64. package/dist/prod/index.js +20 -8
  65. package/dist/prod/map.js +312 -151
  66. package/dist/prod/signals.js +363 -32
  67. package/dist/prod/store/index.js +2 -0
  68. package/dist/prod/store/next/optimistic.js +530 -197
  69. package/dist/prod/store/next/projection.js +142 -57
  70. package/dist/prod/store/next/reconcile.js +149 -103
  71. package/dist/prod/store/next/store.js +1470 -346
  72. package/dist/prod/store/next/target.js +40 -9
  73. package/dist/prod/store/store.js +23 -19
  74. package/dist/prod/store/utils.js +997 -130
  75. package/dist/types/attribution.d.ts +19 -0
  76. package/dist/types/attribution.prod.d.ts +22 -0
  77. package/dist/types/boundaries.d.ts +78 -5
  78. package/dist/types/core/action.d.ts +12 -5
  79. package/dist/types/core/async.d.ts +3 -1
  80. package/dist/types/core/attribution-costs.d.ts +35 -0
  81. package/dist/types/core/attribution-feedback.d.ts +133 -0
  82. package/dist/types/core/attribution-hooks.d.ts +304 -0
  83. package/dist/types/core/attribution-queries.d.ts +24 -0
  84. package/dist/types/core/attribution.d.ts +892 -0
  85. package/dist/types/core/constants.d.ts +179 -0
  86. package/dist/types/core/core.d.ts +299 -25
  87. package/dist/types/core/dev.d.ts +421 -8
  88. package/dist/types/core/effect.d.ts +8 -1
  89. package/dist/types/core/error-hooks.d.ts +71 -0
  90. package/dist/types/core/error.d.ts +9 -0
  91. package/dist/types/core/graph.d.ts +23 -0
  92. package/dist/types/core/heap.d.ts +5 -3
  93. package/dist/types/core/index.d.ts +6 -3
  94. package/dist/types/core/invariants.d.ts +5 -1
  95. package/dist/types/core/lanes.d.ts +51 -19
  96. package/dist/types/core/owner.d.ts +15 -3
  97. package/dist/types/core/scheduler.d.ts +248 -1
  98. package/dist/types/core/types.d.ts +124 -41
  99. package/dist/types/index.d.ts +18 -5
  100. package/dist/types/map.d.ts +2 -0
  101. package/dist/types/signals.d.ts +145 -13
  102. package/dist/types/store/index.d.ts +7 -6
  103. package/dist/types/store/next/optimistic.d.ts +18 -13
  104. package/dist/types/store/next/projection.d.ts +5 -2
  105. package/dist/types/store/next/reconcile.d.ts +7 -0
  106. package/dist/types/store/next/store.d.ts +83 -11
  107. package/dist/types/store/next/target.d.ts +108 -11
  108. package/dist/types/store/store.d.ts +20 -11
  109. package/dist/types/store/utils.d.ts +188 -0
  110. package/package.json +31 -26
  111. package/dist/node.cjs +0 -8137
  112. package/dist/types/store/optimistic.d.ts +0 -45
  113. package/dist/types/store/projection.d.ts +0 -70
  114. package/dist/types/store/reconcile.d.ts +0 -46
  115. package/dist/types-cjs/affects.d.cts +0 -47
  116. package/dist/types-cjs/boundaries.d.cts +0 -175
  117. package/dist/types-cjs/core/action.d.cts +0 -64
  118. package/dist/types-cjs/core/async.d.cts +0 -21
  119. package/dist/types-cjs/core/constants.d.cts +0 -71
  120. package/dist/types-cjs/core/core.d.cts +0 -156
  121. package/dist/types-cjs/core/dev.d.cts +0 -64
  122. package/dist/types-cjs/core/effect.d.cts +0 -30
  123. package/dist/types-cjs/core/error.d.cts +0 -47
  124. package/dist/types-cjs/core/external.d.cts +0 -15
  125. package/dist/types-cjs/core/graph.d.cts +0 -5
  126. package/dist/types-cjs/core/heap.d.cts +0 -22
  127. package/dist/types-cjs/core/index.d.cts +0 -13
  128. package/dist/types-cjs/core/invariants.d.cts +0 -59
  129. package/dist/types-cjs/core/lanes.d.cts +0 -56
  130. package/dist/types-cjs/core/optimistic.d.cts +0 -6
  131. package/dist/types-cjs/core/owner.d.cts +0 -124
  132. package/dist/types-cjs/core/scheduler.d.cts +0 -172
  133. package/dist/types-cjs/core/types.d.cts +0 -148
  134. package/dist/types-cjs/core/verdict.d.cts +0 -2
  135. package/dist/types-cjs/index.d.cts +0 -10
  136. package/dist/types-cjs/map.d.cts +0 -69
  137. package/dist/types-cjs/package.json +0 -3
  138. package/dist/types-cjs/signals.d.cts +0 -624
  139. package/dist/types-cjs/store/index.d.cts +0 -19
  140. package/dist/types-cjs/store/next/optimistic.d.cts +0 -20
  141. package/dist/types-cjs/store/next/projection.d.cts +0 -24
  142. package/dist/types-cjs/store/next/reconcile.d.cts +0 -3
  143. package/dist/types-cjs/store/next/store.d.cts +0 -71
  144. package/dist/types-cjs/store/next/target.d.cts +0 -99
  145. package/dist/types-cjs/store/optimistic.d.cts +0 -45
  146. package/dist/types-cjs/store/projection.d.cts +0 -70
  147. package/dist/types-cjs/store/reconcile.d.cts +0 -46
  148. package/dist/types-cjs/store/store.d.cts +0 -138
  149. package/dist/types-cjs/store/storePath.d.cts +0 -58
  150. package/dist/types-cjs/store/utils.d.cts +0 -74
@@ -27,6 +27,15 @@ export interface NodeOptions<T> {
27
27
  ownedWrite?: boolean;
28
28
  /** Exclude this signal from snapshot capture (internal — not part of public API) */
29
29
  _noSnapshot?: boolean;
30
+ /** Extra CONFIG_* bits OR'd into the node's config at creation (internal —
31
+ * not part of public API). Used by resolve()/until() for
32
+ * CONFIG_DIRECT_COMMIT / CONFIG_AUTHORITATIVE_READ, keeping the per-flag
33
+ * option arms out of the core creation path. */
34
+ _extraConfig?: number;
35
+ /** Observe tiers: framework plumbing — no name, no owner-path segment, no
36
+ * attribution records of its own; its children stay observed (internal —
37
+ * not part of public API; see CONFIG_PLUMBING). */
38
+ _plumbing?: boolean;
30
39
  unobserved?: () => void;
31
40
  lazy?: boolean;
32
41
  sync?: boolean;
@@ -41,19 +50,19 @@ export interface NodeOptions<T> {
41
50
  */
42
51
  loadingValue?: T;
43
52
  }
44
- export interface RawSignal<T> {
45
- _subs: Link | null;
46
- _subsTail: Link | null;
47
- _value: T;
48
- _snapshotValue?: any;
49
- _name?: string;
50
- _equals: false | ((a: T, b: T) => boolean);
51
- _config: number;
52
- _unobserved?: () => void;
53
- _time: number;
54
- _transition: Transition | null;
55
- _pendingValue: T | typeof NOT_PENDING;
56
- _overrideValue?: T | typeof NOT_PENDING;
53
+ /**
54
+ * Cold node extension (stage-3 §12): optional machinery that most nodes
55
+ * never touch lives one hop away so the CORE node literal stays under V8's
56
+ * in-object property boundary (~39 fields measured: past it, every literal
57
+ * allocation spills to an out-of-object backing store and creation cost
58
+ * roughly quadruples — the create0to1 cliff). Allocated lazily by `ext()`
59
+ * on first installer write; ONE shape shared by signals and computeds so
60
+ * `_x` access stays monomorphic. Presence bits on `_config`
61
+ * (CONFIG_OPTIMISTIC / HAS_COMPANIONS / HAS_LANE / HAS_SNAPSHOT) remain the
62
+ * hot-path gates — a bit says "consult _x", never the reverse.
63
+ */
64
+ export interface NodeExtension {
65
+ _overrideValue: unknown | typeof NOT_PENDING;
57
66
  /**
58
67
  * The transaction that owns the active override (stamped at optimistic
59
68
  * write, cleared at settle). Ownership must live on the node: a lane's
@@ -62,25 +71,99 @@ export interface RawSignal<T> {
62
71
  * revert another action's live override. Node-level sibling of the store
63
72
  * layer's STORE_OPTIMISTIC_OWNERS stamps (#2899). `null` = ambient write.
64
73
  */
65
- _overrideOwner?: Transition | null;
66
- _optimisticLane?: OptimisticLane;
67
- _pendingSignal?: Signal<boolean>;
68
- _latestValueComputed?: Computed<T>;
69
- _parentSource?: Signal<any> | Computed<any>;
74
+ _overrideOwner: Transition | null | undefined;
75
+ /** `clock` at the active override's write. A sync recompute in the same
76
+ * tick derives from inputs that predate the override and does not
77
+ * supersede it (A18 supersession ordering, #3331). */
78
+ _overrideTime: number;
79
+ /** A28: the staged value the last flush left on a HELD node that has since
80
+ * been rewritten (latest() keeps answering with it); NOT_PENDING otherwise. */
81
+ _flushedStaged: unknown;
82
+ /** Provenance of the active override's write: the scheduler's `origin` (the
83
+ * asking action's invocation sequence; 0 = mainline). An arriving answer
84
+ * whose flight an older action issued asked a question the override has
85
+ * since changed: it holds to commit instead of superseding (A18
86
+ * supersession provenance, #3331). */
87
+ _overrideStamp: number;
88
+ _optimisticLane: OptimisticLane | undefined;
89
+ _pendingSignal: Signal<boolean> | undefined;
90
+ _latestValueComputed: Computed<any> | undefined;
91
+ _parentSource: Signal<any> | Computed<any> | undefined;
70
92
  /**
71
93
  * Live `affects()` marks on this node (refcount). Non-zero is declared
72
- * motion: the node — and, via the verdict layer's dep-graph coverage walk,
73
- * everything derived from it — reads pending regardless of graph state,
74
- * until every declaring transaction settles/reverts and releases its mark.
75
- * This count is the mark's ONLY graph state: the dedicated channel stores
76
- * nothing downstream and never touches status flags, errors, or pending
77
- * sources.
94
+ * motion — see affects(); the count is the mark's only graph state.
95
+ */
96
+ _affectsCount: number;
97
+ _inFlight: PromiseLike<any> | AsyncIterable<any> | null;
98
+ /** Cancellation for the CURRENT iterator flight (#3122): closes the
99
+ * iterator (`it.return()`), idempotent. Fired at the sites that release
100
+ * `_inFlight` so a superseded stream stops at supersede time — its owner
101
+ * cleanup registration may ride the zombie-disposal channel, which a held
102
+ * transition defers until the SUPERSEDING flight settles. Null for plain
103
+ * promise flights (no cancellation hook exists). */
104
+ _flightTeardown: (() => void) | null;
105
+ _error: unknown;
106
+ _blocked: boolean | undefined;
107
+ _pendingSources: Set<Computed<any>> | undefined;
108
+ _notifyStatus: ((status?: number, error?: any) => void) | undefined;
109
+ /** Question-scoped re-ask classification of the current pending window
110
+ * (see the former Computed._x?._reask doc): set by recompute from
111
+ * REACTIVE_REASK, cleared on landing; meaningless while not pending. */
112
+ _reask: boolean;
113
+ _child: FirewallSignal<any> | null;
114
+ _unobserved: (() => void) | undefined;
115
+ _snapshotValue: any;
116
+ /** Zombie staging (staged disposal): a recompute of an owner that HAS
117
+ * children/disposal parks them here until the flush commits (or a
118
+ * transition reverts). Childless nodes — the common case — never write
119
+ * these. */
120
+ _pendingDisposal: Disposable | Disposable[] | null;
121
+ _pendingFirstChild: Owner | null;
122
+ /** #3038: the firewall children that actually carry isPending()/latest()
123
+ * companions. The post-recompute companion snap iterates THIS set —
124
+ * O(companions asked for) — never the full `_child` chain (one entry per
125
+ * materialized leaf). Populated at companion creation; entries live as
126
+ * long as their companions (which are permanent once created). */
127
+ _companionChildren: Set<FirewallSignal<any>> | undefined;
128
+ }
129
+ export interface RawSignal<T> {
130
+ _subs: Link | null;
131
+ _subsTail: Link | null;
132
+ _value: T;
133
+ /**
134
+ * Observe-tier label (`name` option, or the node kind: `signal`,
135
+ * `computed`, `effect`…). A slot in the observe/dev literals — never a
136
+ * post-construction write — and absent from the prod literals entirely.
78
137
  */
79
- _affectsCount?: number;
138
+ _name?: string;
139
+ /**
140
+ * Observe-tier: the owner in scope when a user-facing signal was created
141
+ * (`registerGraph`), so diagnostics about the signal get an owner path.
142
+ * A slot in the observe/dev `signal()` literal; absent from prod.
143
+ */
144
+ _owner?: Owner | null;
145
+ _equals: false | ((a: T, b: T) => boolean);
146
+ _config: number;
147
+ _time: number;
148
+ /** IN CORE, not the extension (stage-3 §12c): consulted on EVERY write
149
+ * (setSignal's transition-init check) and on recompute scheduling — the
150
+ * per-write extension chase measurably taxed propagation chains. */
151
+ _transition: Transition | null;
152
+ /** Notify-epoch stamp of the last subscriber walk (§12d). A re-write to an
153
+ * already-staged node whose stamp still equals the global epoch skips the
154
+ * whole walk — marking is idempotent, and the epoch bumps on every
155
+ * recompute and new subscriber edge (either can invalidate the skip). */
156
+ _notifiedAt: number;
157
+ _pendingValue: T | typeof NOT_PENDING;
158
+ /** Cold extension — see NodeExtension. */
159
+ _x: NodeExtension | null;
80
160
  }
81
161
  export interface FirewallSignal<T> extends RawSignal<T> {
82
162
  _firewall: Computed<any>;
163
+ /** Doubly-linked child chain on the firewall's extension (`_x._child` is
164
+ * the head): released leaves unlink in O(1) (#3351). */
83
165
  _nextChild: FirewallSignal<unknown> | null;
166
+ _prevChild: FirewallSignal<unknown> | null;
84
167
  }
85
168
  export type Signal<T> = RawSignal<T> | FirewallSignal<T>;
86
169
  export interface Owner {
@@ -97,8 +180,14 @@ export interface Owner {
97
180
  _firstChild: Owner | null;
98
181
  _nextSibling: Owner | null;
99
182
  _prevSibling: Owner | null;
100
- _pendingDisposal: Disposable | Disposable[] | null;
101
- _pendingFirstChild: Owner | null;
183
+ /** Cold extension — see NodeExtension (owners use the zombie-pair slots). */
184
+ _x: NodeExtension | null;
185
+ /**
186
+ * Observe-tier label: the `name` option, the node kind (`computed`,
187
+ * `effect`…), or the component label the rendering layer writes on a root
188
+ * (`<App>`). A slot in the observe/dev literals; absent from prod.
189
+ */
190
+ _name?: string;
102
191
  }
103
192
  export interface Computed<T> extends RawSignal<T>, Owner {
104
193
  _deps: Link | null;
@@ -106,26 +195,19 @@ export interface Computed<T> extends RawSignal<T>, Owner {
106
195
  /** Recompute-pass counter; bumped when dep revalidation starts. */
107
196
  _depGen: number;
108
197
  _flags: number;
109
- _blocked?: boolean;
110
- _pendingSources?: Set<Computed<any>>;
111
- _error?: unknown;
112
198
  _statusFlags: number;
113
199
  _height: number;
114
200
  _nextHeap: Computed<any> | undefined;
115
201
  _prevHeap: Computed<any>;
116
202
  _fn: (prev?: T) => T;
117
- _inFlight: PromiseLike<T> | AsyncIterable<T> | null;
118
- _child: FirewallSignal<any> | null;
119
- _notifyStatus?: (status?: number, error?: any) => void;
120
203
  /**
121
- * Question-scoped pending classification of the node's CURRENT pending
122
- * window: `true` means the in-flight recompute is a re-ask of the same
123
- * question (refresh/poll/confirm — no tracked input changed value), so the
124
- * shown answer still answers the question and the node reads NOT pending.
125
- * Set by `recompute` from `REACTIVE_REASK`, cleared on landing
126
- * (`clearStatus`). Meaningless while not STATUS_PENDING.
204
+ * Clock tick at which REACTIVE_MANUAL_WRITE was last applied
205
+ * (`suppressComputedRecompute`). Lets `refresh()` distinguish a same-tick
206
+ * manual write (which wins over the refresh, #2692) from a mask carried
207
+ * across ticks by a transaction (which an explicit refresh lifts, #3026).
208
+ * Only meaningful while REACTIVE_MANUAL_WRITE is set.
127
209
  */
128
- _reask: boolean;
210
+ _manualWriteTime?: number;
129
211
  /**
130
212
  * True while a `loadingValue` node's first real answer hasn't landed: the
131
213
  * node was born committed (commit #0 = the loading value) and `handleAsync`
@@ -137,7 +219,8 @@ export interface Computed<T> extends RawSignal<T>, Owner {
137
219
  * return, sync-resolved promise, first iterator yield, async settle); a
138
220
  * real error leaves it set — errors answer reads but don't enter the value
139
221
  * lineage, so a retry serves the loading value again. Once cleared, normal
140
- * pending/refetch semantics apply forever.
222
+ * pending/refetch semantics apply forever. (Stays in CORE: written
223
+ * unconditionally by recompute and every commit.)
141
224
  */
142
225
  _loading: boolean;
143
226
  }
@@ -1,9 +1,22 @@
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
- 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, configureClientErrors, ROOT_ERROR_HOOK } from "./core/index.js";
2
+ /**
3
+ * @internal The dev console footer seam — registered by `solid-js`, which
4
+ * owns the repair skill the footer points at. Not part of `DEV`; a no-op
5
+ * outside dev builds.
6
+ */
7
+ export { setConsoleFooter } from "./core/index.js";
8
+ import { type Dev, type Observe } from "./core/index.js";
9
+ /**
10
+ * Observe tier (diagnostics channel, attribution hook slot + interaction
11
+ * frame): dev and observe builds. The attribution engine itself is the
12
+ * `@solidjs/signals/attribution` entry.
13
+ */
14
+ export declare const OBSERVE: Observe | undefined;
15
+ /** Dev tier (devtools hooks, graph traversal, console reporting): dev builds only. */
3
16
  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";
5
- export { createSignal, createMemo, createEffect, createRenderEffect, createTrackedEffect, createReaction, createOptimistic, resolve, onSettled, onCleanup } from "./signals.js";
6
- export type { Accessor, SourceAccessor, Setter, Signal, ComputeFunction, EffectFunction, EffectBundle, EffectOptions, SignalOptions, MemoOptions, NoInfer } from "./signals.js";
17
+ export type { Owner, Context, ContextRecord, IQueue, ExternalSourceFactory, ExternalSource, ExternalSourceConfig, Refreshable, AttributionSlot, ClientErrorContext, ClientErrorHook, ClientErrorsConfig, InteractionRef, NavigationRef, Dev, Observe, ServerObserve, Records, RecordTypes, HostRecordTypes, RecordType, RecordEvent, RecordLive, RecordListener, DevHooks, DiagnosticCapture, DiagnosticCode, DiagnosticEvent, DiagnosticKind, DiagnosticListener, Diagnostics, DiagnosticSeverity, DiagnosticSubject } from "./core/index.js";
18
+ export { createSignal, createMemo, createEffect, createRenderEffect, createTrackedEffect, createReaction, createOptimistic, refresh, resolve, until, onSettled, onCleanup } from "./signals.js";
19
+ export type { Truthy, UntilOptions, Accessor, SourceAccessor, Setter, Signal, ComputeFunction, EffectFunction, EffectBundle, EffectOptions, SignalOptions, MemoOptions, NoInfer } from "./signals.js";
7
20
  export { affects } from "./affects.js";
8
21
  export { mapArray, repeat, type Maybe } from "./map.js";
9
22
  export * from "./store/index.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>`.
@@ -26,6 +26,12 @@ import type { Disposable, Refreshable } from "./core/index.js";
26
26
  * Cannot be used inside `createTrackedEffect` or `onSettled` — return a
27
27
  * cleanup function from the callback body instead.
28
28
  *
29
+ * Cleanups run in unwind order: an owner's children are disposed before its
30
+ * own cleanups, and within one owner later registrations run before earlier
31
+ * ones. In production a component body shares its enclosing owner, so
32
+ * register cleanup before creating children when the order between them
33
+ * matters.
34
+ *
29
35
  * @example
30
36
  * ```ts
31
37
  * // Library shape: thread a resource's disposal into a *captured* owner
@@ -169,6 +175,13 @@ export interface MemoOptions<T> {
169
175
  * the full semantics. No-op outside hydration.
170
176
  */
171
177
  transparent?: boolean;
178
+ /**
179
+ * @internal Framework plumbing (the `solid-js/refresh` HMR memo): in the
180
+ * observe tiers the memo has no name, is no owner-path segment, and the
181
+ * attribution engine records nothing about it, while what it owns stays
182
+ * observed. Not part of the public API.
183
+ */
184
+ _plumbing?: boolean;
172
185
  /**
173
186
  * Custom equality function, or `false` to always notify subscribers.
174
187
  * Defaults to reference equality (`isEqual`). Pass a comparator (e.g.
@@ -251,10 +264,14 @@ export type NoInfer<T extends any> = [T][T extends any ? 0 : never];
251
264
  *
252
265
  * @example
253
266
  * ```ts
254
- * // Writable memo: starts as `fn()`, can be locally overwritten by setter.
267
+ * // Writable memo: derives from `fn()` and can be written like a signal.
255
268
  * const [user, setUser] = createSignal(() => fetchUser(userId()));
256
269
  *
257
- * setUser({ ...user(), name: "Alice" }); // optimistic local edit
270
+ * // Within the frame the write wins over a same-tick recompute; the next
271
+ * // change to `userId` re-derives (the compute receives the written value
272
+ * // as `prev`). While a transaction holds a re-derived value, a write from
273
+ * // outside it does not replace that derivation — it becomes its `prev`.
274
+ * setUser({ ...user(), name: "Alice" });
258
275
  * ```
259
276
  *
260
277
  * @description https://docs.solidjs.com/reference/basic-reactivity/create-signal
@@ -365,17 +382,6 @@ export declare function createMemo<T>(compute: ComputeFunction<undefined | NoInf
365
382
  * @description https://docs.solidjs.com/reference/basic-reactivity/create-effect
366
383
  */
367
384
  export declare function createEffect<T>(compute: ComputeFunction<undefined | NoInfer<T>, T>, effectFn: EffectFunction<NoInfer<T>, T> | EffectBundle<NoInfer<T>, T>, options?: EffectOptions): void;
368
- /**
369
- * @deprecated `createEffect(compute)` (single argument) is no longer supported.
370
- * Pass a separate effect function as the second argument:
371
- * `createEffect(compute, effect)`. See [MISSING_EFFECT_FN].
372
- *
373
- * - For a side effect that reacts to changes, split the work:
374
- * `createEffect(() => signal(), value => doWork(value))`.
375
- * - For a derived value, use `createMemo(() => signal())`.
376
- * - For a one-shot side effect at construction time, just call the function.
377
- */
378
- export declare function createEffect<T>(compute: ComputeFunction<undefined | NoInfer<T>, T>): never;
379
385
  /**
380
386
  * Creates a reactive computation that runs during the render phase as DOM elements
381
387
  * are created and updated but not necessarily connected.
@@ -410,6 +416,16 @@ export declare function createRenderEffect<T>(compute: ComputeFunction<undefined
410
416
  * Creates a tracked reactive effect where dependency tracking and side effects happen
411
417
  * in the same scope.
412
418
  *
419
+ * @deprecated Do not use in new code. For a side effect that follows reactive
420
+ * state, use `createEffect(compute, effect)` — it separates tracking from the
421
+ * side effect, knows its dependencies before it runs, and participates in
422
+ * async and transitions. For one-time DOM work after render (measuring,
423
+ * attaching third-party widgets to a ref), use `onSettled`. Tracking from
424
+ * inside the effect phase — the only thing this primitive adds — is retained
425
+ * solely to ease 1.x migration: it runs beside user-effect callbacks after
426
+ * values commit, never holds a transition, and cannot observe a write staged
427
+ * earlier in the same flush by a signal it has not read yet.
428
+ *
413
429
  * WARNING: Because tracking and effects happen in the same scope, this primitive
414
430
  * may run multiple times for a single change or show tearing (reading inconsistent
415
431
  * state). Use only when dynamic subscription patterns require same-scope tracking.
@@ -491,6 +507,122 @@ export declare function createReaction(effectFn: EffectFunction<undefined> | Eff
491
507
  * @param fn a reactive expression to resolve
492
508
  */
493
509
  export declare function resolve<T>(fn: () => T): Promise<T>;
510
+ /**
511
+ * Invalidates one reactive source, forcing it to re-execute even if its inputs
512
+ * haven't changed, and returns a promise for the target's NEXT QUIESCENT
513
+ * STATE — the re-ask (and anything that supersedes it) has settled.
514
+ *
515
+ * Pass either a Solid-created accessor or a projected store created from
516
+ * `createStore(fn, ...)` / `createProjection(...)`. `refresh()` is a
517
+ * write-like invalidation operation: it does not read the target's value, and
518
+ * refreshing a plain signal accessor is a no-op that resolves immediately.
519
+ *
520
+ * The returned promise is safe to ignore (fire-and-forget refresh is
521
+ * unchanged, and a failed refetch will not surface an unhandled rejection).
522
+ * Awaiting it gives imperative flows the settle point without a reactive
523
+ * read:
524
+ * - Accessor targets resolve with the settled value; store targets resolve
525
+ * with the store node passed (reads through it are fresh after the await).
526
+ * - A failed re-ask rejects with the error (inside an action's generator,
527
+ * `yield refresh(x)` throws back at the yield point and the action reverts
528
+ * like any other failure).
529
+ * - Semantics are quiescence, not flight identity: if another refresh (or
530
+ * any invalidation) supersedes this one mid-flight, the promise waits for
531
+ * — and delivers — whatever finally lands.
532
+ * - Inside an action, truth landing into the held transaction is STAGED;
533
+ * the promise still settles then (matching `resolve()`/`until()`, #2930)
534
+ * and delivers the staged value — the caller's own optimistic override is
535
+ * never the delivered value.
536
+ * - The re-ask itself stays verdict-quiet exactly as before: `isPending`
537
+ * does not flip for a bare refresh (pair with `affects()` for a visible
538
+ * pending window).
539
+ *
540
+ * @example
541
+ * ```ts
542
+ * const user = createMemo(async () => fetch(`/users/${id()}`).then(r => r.json()));
543
+ *
544
+ * // Fire-and-forget re-fetch
545
+ * <button onClick={() => refresh(user)}>Reload</button>;
546
+ *
547
+ * // Imperative settle point
548
+ * const fresh = await refresh(user);
549
+ * ```
550
+ */
551
+ export declare function refresh<T>(target: Refreshable<T>): Promise<T extends (...args: any) => infer V ? V : T>;
552
+ /** Falsy values a truthy predicate result is narrowed against. */
553
+ export type Truthy<T> = Exclude<T, false | 0 | 0n | "" | null | undefined>;
554
+ export interface UntilOptions {
555
+ /** Reject with `TimeoutError` if the predicate has not turned truthy within
556
+ * this many milliseconds. Strongly recommended when the confirming truth
557
+ * arrives over a transport that can drop (sockets, subscriptions). */
558
+ timeout?: number;
559
+ /** Reject with `signal.reason` on abort. */
560
+ signal?: AbortSignal;
561
+ }
562
+ /**
563
+ * Awaits a reactive predicate and resolves the first time it settles *truthy*,
564
+ * with that (narrowed) value. Falsy results and pending async reads both mean
565
+ * "not yet": the subscription stays live and re-evaluates as sources change.
566
+ * If the predicate settles with an error — a throw, or an async source that
567
+ * rejects — the promise rejects with it, as do timeout and abort.
568
+ *
569
+ * Where {@link resolve} answers "what is this value" (first settled value,
570
+ * whatever it is), `until` answers "when does the world confirm this
571
+ * condition". The difference matters inside an `action()`: `yield until(...)`
572
+ * holds the action's transaction — and any optimistic state riding it — open
573
+ * until the condition is independently true.
574
+ *
575
+ * To make that sound, `until`'s predicate reads the AUTHORITATIVE view — and
576
+ * this is the one read-semantics difference from `resolve`, which reads the
577
+ * normal (transaction's own) view where overrides are visible:
578
+ *
579
+ * - **Optimistic overrides are invisible** to the predicate. Your own
580
+ * tentative write can never satisfy your own ack, even on the
581
+ * single-primitive shape where the optimistic store IS the live-fed store.
582
+ * (Derived computeds serve their normal cached values — express the
583
+ * condition over sources of truth, not derived views of the overlay.)
584
+ * - **Everything else reads normally, including uncommitted transition-staged
585
+ * data.** Real data is real wherever it currently lives. This is
586
+ * load-bearing, not a loophole: truth that arrives *into* the open
587
+ * transaction (a `refresh()` this action issued, an entangled landing)
588
+ * stages and cannot commit until the hold releases — a predicate that
589
+ * refused staged reads would deadlock on the very data it is waiting for.
590
+ *
591
+ * This is the acknowledgment mechanism for mutations confirmed on a live data
592
+ * channel (sockets, subscriptions, live queries) rather than by the mutation's
593
+ * own response: correlate by a client-generated id or version in the predicate,
594
+ * and let truth arrive however it arrives — push, refetch, or another tab.
595
+ *
596
+ * Failure composes with action semantics: a rejection is thrown back into the
597
+ * generator at the `yield` point — catchable there, or the action fails and
598
+ * its optimistic state reverts.
599
+ *
600
+ * Must be called *outside* a tracking scope.
601
+ *
602
+ * Inside an action, call it from a step: after an `await`, put a bare `yield`
603
+ * before `yield until(...)`. The runtime cannot hook an async generator's
604
+ * `await` continuation, so the `until(...)` expression — which CREATES the
605
+ * predicate's reader — would otherwise run outside the transaction; created
606
+ * there it is born held (A29) and replays only at the commit its own promise
607
+ * holds open (#3482). See {@link action}.
608
+ *
609
+ * @example
610
+ * ```ts
611
+ * const send = action(async function* (text: string) {
612
+ * const clientId = crypto.randomUUID();
613
+ * setMessages(m => { m.push({ clientId, text, pending: true }); }); // optimistic
614
+ * await socket.send({ clientId, text }); // fire-and-forget transport
615
+ * yield; // re-enter the transaction after the await
616
+ * // Hold until the live source echoes the write (authoritative view —
617
+ * // the optimistic row above cannot satisfy this):
618
+ * yield until(() => messages.some(m => m.clientId === clientId), { timeout: 10_000 });
619
+ * });
620
+ * ```
621
+ *
622
+ * @param fn a reactive predicate over authoritative state
623
+ * @param options optional `timeout` (ms) and abort `signal`
624
+ */
625
+ export declare function until<T>(fn: () => T, options?: UntilOptions): Promise<Truthy<T>>;
494
626
  /**
495
627
  * Creates an optimistic signal that can be used to optimistically update a value
496
628
  * and then revert it back to the previous value at end of transition.
@@ -1,16 +1,17 @@
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
- export { isWrappable, $TRACK, $PROXY, $TARGET } from "./store.js";
3
+ export { isWrappable, $TRACK, $PROXY, $TARGET, $RECORD } 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";
9
+ export { storeIsShallow, storeHasFamily, storeHasOptimisticFamily } from "./next/store.js";
7
10
  export { createOptimisticStoreNext as createOptimisticStore } from "./next/optimistic.js";
8
- /** Public createStore: plain form `(init, options?)` and derived writable
11
+ /** Public createStore: plain form `(initialValue, options?)` and derived writable
9
12
  * form `(fn, seed, options?)`. */
10
- export declare function createStore<T extends object = {}>(store: NoFn<T> | Store<NoFn<T>>, options?: StoreOptions & {
11
- shallow?: boolean;
12
- }): [get: Store<T>, set: StoreSetter<T>];
13
- export declare function createStore<T extends object = {}>(fn: (store: T) => void | T | Promise<void | T> | AsyncIterable<void | T>, store: Partial<T> | Store<NoFn<T>>, options?: ProjectionOptions): [get: Refreshable<Store<T>>, set: StoreSetter<T>];
13
+ export declare function createStore<T extends object = {}>(initialValue: NoFn<T> | Store<NoFn<T>>, options?: StoreOptions): [get: Store<T>, set: StoreSetter<T>];
14
+ export declare function createStore<T extends object = {}>(fn: (draft: T) => void | T | Promise<void | T> | AsyncIterable<void | T>, seed: Partial<T> | Store<NoFn<T>>, options?: ProjectionOptions): [get: Refreshable<Store<T>>, set: StoreSetter<T>];
14
15
  export declare function reconcile<T extends U, U>(value: T, key?: string | ((item: NonNullable<any>) => any) | null): (state: U) => T;
15
16
  export declare function snapshot<T>(value: T): T;
16
17
  export declare function deep<T>(value: T): T;
@@ -1,20 +1,25 @@
1
- import { type NoFn, type ProjectionOptions, type Store, type StoreSetter } from "../store.js";
2
- import type { StoreNextFamily, StoreNextTarget } from "./target.js";
3
- export declare function createOptimisticStoreNext<T extends object = {}>(first: T | ((store: T) => void | T | Promise<void | T> | AsyncIterable<void | T>), second?: NoFn<T> | Store<NoFn<T>>, options?: ProjectionOptions): [get: Store<T>, set: StoreSetter<T>];
1
+ import { type Refreshable } from "../../core/index.js";
2
+ import { type Transition } from "../../core/scheduler.js";
3
+ import { type NoFn, type ProjectionOptions, type Store, type StoreOptions, type StoreSetter } from "../store.js";
4
+ import type { StoreNextTarget } from "./target.js";
5
+ /** #3164 fold: a stamped truth is HELD (masked from ordinary readers until
6
+ * the reveal) only while its transition is live AND retaining optimism —
7
+ * overrides are what make partial-coverage composition a tear. A plain
8
+ * async transition carries no overrides, so downstream computes must see
9
+ * staged values to converge (normal speculation). Resolves merges first:
10
+ * merge unions optimistic nodes/stores into the target. */
11
+ export declare function transitionHoldsOptimism(transition: Transition): boolean;
12
+ export declare function createOptimisticStoreNext<T extends object = {}>(initialValue: NoFn<T> | Store<NoFn<T>>, options?: StoreOptions): [get: Store<T>, set: StoreSetter<T>];
13
+ export declare function createOptimisticStoreNext<T extends object = {}>(fn: (draft: T) => void | T | Promise<void | T> | AsyncIterable<void | T>, seed: Partial<T> | Store<NoFn<T>>, options?: ProjectionOptions): [get: Refreshable<Store<T>>, set: StoreSetter<T>];
4
14
  /** Diff the draft against the current OPTIMISTIC VIEW (committed + active
5
15
  * overrides — the same view the draft was seeded from) and emit engine writes
6
16
  * for exactly the changed keys. Visible-view diffing keeps no-op writes from
7
17
  * entangling lanes (RUL-10 / opt R38). */
8
18
  export declare function notifyOptimisticWrites(t: StoreNextTarget, pb: Record<PropertyKey, any>): void;
9
- /**
10
- * Landing consumption (RUL-2): fresh authoritative data supersedes every
11
- * tentative override in the family. Mirrors legacy clearProjectionOverride —
12
- * drop the override, clear lane/ownership, notify subscribers whose visible
13
- * value changes (reversion effects go to regular queues via the projection
14
- * write posture the caller holds).
15
- */
16
- export declare function consumeOverridesNext(fam: StoreNextFamily): void;
17
19
  /** Optimistic-view composition for snapshot/deep (O1: snapshot is the CURRENT
18
20
  * view, lane values included; a fresh copy per call during pending windows —
19
- * RUL-12). Returns `src` untouched when no override is active on `t`. */
20
- export declare function optimisticView(t: StoreNextTarget, src: Record<PropertyKey, any>): Record<PropertyKey, any>;
21
+ * RUL-12). Returns `src` untouched when no override is active on `t`.
22
+ * Authoritative-view reads (until()'s predicate) skip composition entirely:
23
+ * the predicate observes authoritative truth, never the caller's tentative
24
+ * overlay. (Write-side emission callers never run under such a compute.) */
25
+ export declare function optimisticView(t: StoreNextTarget, src: Record<PropertyKey, any>, draft?: boolean): Record<PropertyKey, any>;
@@ -19,6 +19,9 @@ import { type NoFn, type ProjectionOptions, type Store } from "../store.js";
19
19
  export declare function createProjectionNext<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>>;
20
20
  /** Derived writable store (legacy parity): a projection whose public setter
21
21
  * masks the recompute for the tick (core R31 — the manual write wins over a
22
- * same-flush dependency change). */
22
+ * same-flush dependency change). Across a hold the write is not a proposal:
23
+ * a leaf another transaction holds as the fold's result re-runs the fold
24
+ * under it, the write being the draft's prior state (A34 amendment, #3612;
25
+ * core derivedWrite). */
23
26
  export declare function createStoreDerivedNext<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>>, (f: (draft: T) => T | void) => void];
24
- export declare function runProjectionComputedNext<T extends object>(wrappedStore: Store<T>, fn: (draft: T) => void | T | Promise<void | T> | AsyncIterable<void | T>, key: string | ((item: NonNullable<any>) => any) | null, wrapCommit?: (write: () => void) => void, onDraftWrite?: () => void): Computed<void | T>;
27
+ export declare function runProjectionComputedNext<T extends object>(wrappedStore: Store<T>, fn: (draft: T) => void | T | Promise<void | T> | AsyncIterable<void | T>, key: string | ((item: NonNullable<any>) => any) | null, wrapCommit?: (write: () => void, value: T) => void, aroundDraftWrite?: (op: () => void) => void): Computed<void | T>;
@@ -1,3 +1,10 @@
1
1
  type KeyFn = (item: any) => any;
2
2
  export declare function reconcileNextState(value: any, state: any, key: string | KeyFn | null | undefined, replace?: boolean): void;
3
+ /** Setter-channel row ops (the fold site calls this for array targets with
4
+ * ops consumers): structural mutation through the setter — push/splice/index
5
+ /** Key equality for EVERY key comparison in this module (re-audit 2, P1-5):
6
+ * SameValueZero, matching the adoption window's Map-based matcher — NaN keys
7
+ * are equal to themselves, so aligned NaN rows stay aligned in the prefix
8
+ * walk instead of forever misaligning. */
9
+ export declare function sameKey(a: any, b: any): boolean;
3
10
  export {};