@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.
- package/dist/dev-shared.js +6357 -0
- package/dist/dev.attribution.js +2485 -0
- package/dist/dev.js +2851 -7027
- package/dist/observe/affects.js +129 -0
- package/dist/observe/attribution.js +7 -0
- package/dist/observe/boundaries.js +641 -0
- package/dist/observe/core/action.js +177 -0
- package/dist/observe/core/async.js +846 -0
- package/dist/observe/core/attribution-costs.js +66 -0
- package/dist/observe/core/attribution-feedback.js +282 -0
- package/dist/observe/core/attribution-hooks.js +82 -0
- package/dist/observe/core/attribution-queries.js +28 -0
- package/dist/observe/core/attribution.js +2095 -0
- package/dist/observe/core/constants.js +248 -0
- package/dist/{types-cjs/core/context.d.cts → observe/core/context.js} +37 -12
- package/dist/observe/core/core.js +1789 -0
- package/dist/observe/core/dev.js +293 -0
- package/dist/observe/core/effect.js +195 -0
- package/dist/observe/core/error-hooks.js +71 -0
- package/dist/observe/core/error.js +80 -0
- package/dist/observe/core/external.js +98 -0
- package/dist/observe/core/graph.js +155 -0
- package/dist/observe/core/heap.js +147 -0
- package/dist/observe/core/invariants.js +45 -0
- package/dist/observe/core/lanes.js +205 -0
- package/dist/observe/core/optimistic.js +585 -0
- package/dist/observe/core/owner.js +322 -0
- package/dist/observe/core/scheduler.js +1428 -0
- package/dist/observe/core/verdict.js +669 -0
- package/dist/observe/index.js +59 -0
- package/dist/observe/map.js +484 -0
- package/dist/{types-cjs/signals.d.cts → observe/signals.js} +311 -317
- package/dist/observe/store/index.js +40 -0
- package/dist/observe/store/next/optimistic.js +660 -0
- package/dist/observe/store/next/projection.js +255 -0
- package/dist/observe/store/next/reconcile.js +375 -0
- package/dist/observe/store/next/store.js +2327 -0
- package/dist/observe/store/next/target.js +51 -0
- package/dist/observe/store/store.js +325 -0
- package/dist/observe/store/storePath.js +103 -0
- package/dist/observe/store/utils.js +1023 -0
- package/dist/prod/attribution.js +41 -0
- package/dist/prod/boundaries.js +128 -76
- package/dist/prod/core/action.js +65 -37
- package/dist/prod/core/async.js +324 -172
- package/dist/prod/core/constants.js +57 -1
- package/dist/prod/core/context.js +3 -3
- package/dist/prod/core/core.js +1003 -364
- package/dist/prod/core/dev.js +17 -1
- package/dist/prod/core/effect.js +76 -42
- package/dist/prod/core/error-hooks.js +71 -0
- package/dist/prod/core/external.js +4 -4
- package/dist/prod/core/graph.js +37 -37
- package/dist/prod/core/heap.js +61 -56
- package/dist/prod/core/lanes.js +107 -63
- package/dist/prod/core/optimistic.js +374 -93
- package/dist/prod/core/owner.js +62 -46
- package/dist/prod/core/scheduler.js +653 -286
- package/dist/prod/core/verdict.js +245 -127
- package/dist/prod/index.js +15 -5
- package/dist/prod/map.js +292 -141
- package/dist/prod/signals.js +29 -16
- package/dist/prod/store/next/optimistic.js +77 -55
- package/dist/prod/store/next/projection.js +31 -20
- package/dist/prod/store/next/reconcile.js +87 -84
- package/dist/prod/store/next/store.js +718 -401
- package/dist/prod/store/next/target.js +32 -10
- package/dist/prod/store/store.js +12 -14
- package/dist/prod/store/utils.js +950 -130
- package/dist/types/attribution.d.ts +20 -0
- package/dist/types/attribution.prod.d.ts +22 -0
- package/dist/types/boundaries.d.ts +10 -1
- package/dist/types/core/action.d.ts +12 -5
- package/dist/types/core/async.d.ts +1 -1
- package/dist/types/core/attribution-costs.d.ts +35 -0
- package/dist/types/core/attribution-feedback.d.ts +133 -0
- package/dist/types/core/attribution-hooks.d.ts +147 -9
- package/dist/types/core/attribution-queries.d.ts +10 -0
- package/dist/types/core/attribution.d.ts +216 -182
- package/dist/types/core/constants.d.ts +56 -0
- package/dist/types/core/core.d.ts +190 -2
- package/dist/types/core/dev.d.ts +246 -28
- package/dist/types/core/effect.d.ts +8 -1
- package/dist/types/core/error-hooks.d.ts +71 -0
- package/dist/types/core/index.d.ts +4 -1
- package/dist/types/core/invariants.d.ts +4 -0
- package/dist/types/core/lanes.d.ts +39 -5
- package/dist/types/core/scheduler.d.ts +153 -0
- package/dist/types/core/types.d.ts +32 -9
- package/dist/types/index.d.ts +10 -3
- package/dist/types/map.d.ts +2 -0
- package/dist/types/signals.d.ts +8 -0
- package/dist/types/store/index.d.ts +2 -0
- package/dist/types/store/next/optimistic.d.ts +1 -1
- package/dist/types/store/next/store.d.ts +11 -5
- package/dist/types/store/next/target.d.ts +37 -10
- package/dist/types/store/utils.d.ts +178 -0
- package/package.json +21 -17
- package/dist/node.cjs +0 -10541
- package/dist/node.dev.cjs +0 -13724
- package/dist/types-cjs/affects.d.cts +0 -47
- package/dist/types-cjs/boundaries.d.cts +0 -175
- package/dist/types-cjs/core/action.d.cts +0 -64
- package/dist/types-cjs/core/async.d.cts +0 -23
- package/dist/types-cjs/core/attribution-hooks.d.cts +0 -127
- package/dist/types-cjs/core/attribution.d.cts +0 -495
- package/dist/types-cjs/core/constants.d.cts +0 -159
- package/dist/types-cjs/core/core.d.cts +0 -185
- package/dist/types-cjs/core/dev.d.cts +0 -136
- package/dist/types-cjs/core/effect.d.cts +0 -30
- package/dist/types-cjs/core/error.d.cts +0 -56
- package/dist/types-cjs/core/external.d.cts +0 -15
- package/dist/types-cjs/core/graph.d.cts +0 -28
- package/dist/types-cjs/core/heap.d.cts +0 -24
- package/dist/types-cjs/core/index.d.cts +0 -13
- package/dist/types-cjs/core/invariants.d.cts +0 -59
- package/dist/types-cjs/core/lanes.d.cts +0 -54
- package/dist/types-cjs/core/optimistic.d.cts +0 -6
- package/dist/types-cjs/core/owner.d.cts +0 -124
- package/dist/types-cjs/core/scheduler.d.cts +0 -236
- package/dist/types-cjs/core/types.d.cts +0 -204
- package/dist/types-cjs/core/verdict.d.cts +0 -2
- package/dist/types-cjs/index.d.cts +0 -10
- package/dist/types-cjs/map.d.cts +0 -69
- package/dist/types-cjs/package.json +0 -3
- package/dist/types-cjs/store/index.d.cts +0 -18
- package/dist/types-cjs/store/next/optimistic.d.cts +0 -25
- package/dist/types-cjs/store/next/projection.d.cts +0 -8
- package/dist/types-cjs/store/next/reconcile.d.cts +0 -10
- package/dist/types-cjs/store/next/store.d.cts +0 -121
- package/dist/types-cjs/store/next/target.d.cts +0 -166
- package/dist/types-cjs/store/store.d.cts +0 -143
- package/dist/types-cjs/store/storePath.d.cts +0 -58
- package/dist/types-cjs/store/utils.d.cts +0 -74
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { type OptimisticLane } from "./lanes.js";
|
|
2
|
+
import type { Transition } from "./scheduler.js";
|
|
2
3
|
import type { Computed, FirewallSignal, NodeExtension, NodeOptions, Owner, Signal } from "./types.js";
|
|
3
4
|
export declare const PRIMITIVE_IN_FORBIDDEN_SCOPE_MESSAGE = "[PRIMITIVE_IN_FORBIDDEN_SCOPE] Cannot create reactive primitives inside createTrackedEffect or owner-backed onSettled";
|
|
4
5
|
export declare const REACTIVE_WRITE_IN_OWNED_SCOPE_SIGNAL_MESSAGE: string;
|
|
5
6
|
export declare const REACTIVE_WRITE_IN_OWNED_SCOPE_REFRESH_MESSAGE: string;
|
|
7
|
+
export declare const ASYNC_STORE_SETTER_MESSAGE: string;
|
|
6
8
|
export declare let tracking: boolean;
|
|
7
9
|
/** @internal verdict-module glue */
|
|
8
10
|
export declare function setPendingCheckActive(v: boolean): void;
|
|
@@ -60,6 +62,14 @@ export declare function signal<T>(v: T, options?: NodeOptions<T>, firewall?: Com
|
|
|
60
62
|
export declare let slotUnobservedHook: (node: Signal<any>) => void;
|
|
61
63
|
/** Install the shared slot-node unobserved handler (store module, once). */
|
|
62
64
|
export declare function setSlotUnobserved(fn: (node: Signal<any>) => void): void;
|
|
65
|
+
/** Release a firewall child the store no longer addresses (unobserved sweep
|
|
66
|
+
* dropped it from its target's cache): unlink it from the chain so the
|
|
67
|
+
* projection stops retaining it and its last value. The node keeps its own
|
|
68
|
+
* `_nextChild` so a walk that is mid-chain on it still terminates. It also
|
|
69
|
+
* leaves `_companionChildren` (#3503): the companions themselves are
|
|
70
|
+
* permanent on the node, but the node is unreachable through the store, so
|
|
71
|
+
* the set would only retain it and its last value. */
|
|
72
|
+
export declare function unlinkFirewallChild(node: Signal<any>): void;
|
|
63
73
|
export declare function slotSignal<T>(v: T, equals: (a: T, b: T) => boolean, host: object, key: PropertyKey, acc: boolean, firewall?: Computed<unknown> | null): Signal<T>;
|
|
64
74
|
export declare function optimisticSignal<T>(v: T, options?: NodeOptions<T>): Signal<T>;
|
|
65
75
|
export declare function optimisticComputed<T>(fn: (prev?: T) => T | PromiseLike<T> | AsyncIterable<T>, options?: NodeOptions<T>): Computed<T>;
|
|
@@ -93,6 +103,23 @@ export declare function setStrictRead(v: string | false): string | false;
|
|
|
93
103
|
* ```
|
|
94
104
|
*/
|
|
95
105
|
export declare function untrack<T>(fn: () => T, strictReadLabel?: string | false): T;
|
|
106
|
+
/**
|
|
107
|
+
* Set while runtime bookkeeping evaluates a user accessor inside another
|
|
108
|
+
* node's pass (a loading boundary's `on` key, read from `notify` while the
|
|
109
|
+
* node that went pending is still recomputing). `context` is that node, but
|
|
110
|
+
* the read is nobody's: the value is compared, never derived from, so the
|
|
111
|
+
* untracked-pending re-run link (`read`, `!tracking`) must not be recorded on
|
|
112
|
+
* it — it made the key's source a dependency of an unrelated async memo
|
|
113
|
+
* (#3528: `isPending(m2)` through a memo in `on()` linked the memo into `m2`,
|
|
114
|
+
* a cycle that re-derived `m2` on every pending mark and never converged).
|
|
115
|
+
*/
|
|
116
|
+
export declare let spectating: boolean;
|
|
117
|
+
/**
|
|
118
|
+
* Evaluates `fn` untracked and without recording a dependency for the
|
|
119
|
+
* untracked-pending re-run rule on the current `context`. For bookkeeping
|
|
120
|
+
* reads made mid-propagation on behalf of no node — see `spectating`.
|
|
121
|
+
*/
|
|
122
|
+
export declare function spectate<T>(fn: () => T): T;
|
|
96
123
|
/**
|
|
97
124
|
* Bring a computed to a readable state: lazy/disposed nodes are (re)computed;
|
|
98
125
|
* an isPending() probe (`refresh`) additionally pulls the node fully up to
|
|
@@ -128,16 +155,177 @@ export declare function notifyAuthoritativeObservers(el: Signal<any> | Computed<
|
|
|
128
155
|
* the gating bit is only ever set by such a read, so the `!` call sites are
|
|
129
156
|
* safe once every setter installs, #3303). */
|
|
130
157
|
export declare function installAuthoritativeRead(): void;
|
|
158
|
+
/**
|
|
159
|
+
* Stale-reader term of the value selections below: a render effect reading a
|
|
160
|
+
* node some OTHER live transaction has staged sees the committed value. The
|
|
161
|
+
* commit is silent — the staging walk was the notification — so a reader
|
|
162
|
+
* that linked AFTER that walk (an effect created during the hold, a store
|
|
163
|
+
* key first read under it) would show the old value past the reveal: record
|
|
164
|
+
* it for the transaction's commit replay (the `_gatedSubs` contract lanes
|
|
165
|
+
* already use). An effect the transaction itself computed re-derives at its
|
|
166
|
+
* commit on its own (parked run, or the contested re-derive, #3322) and is
|
|
167
|
+
* not recorded — replaying it too would publish the frame twice.
|
|
168
|
+
*
|
|
169
|
+
* Flight twin (the pending-branch carve-out): the reader is served the
|
|
170
|
+
* node's committed, pre-flight value and now observes that flight — A15:
|
|
171
|
+
* async work observed by a reader settles as one unit with the writes that
|
|
172
|
+
* asked it — so it joins the transaction's reporters for the node. The
|
|
173
|
+
* reporter the transaction recorded when the flight started may be gone (a
|
|
174
|
+
* keyed remount disposed it, #3374); a completion check that found no live
|
|
175
|
+
* reporter committed the writes ahead of the answer, tearing the new
|
|
176
|
+
* reader's frame (`Count: 1` beside `Details: 0`). Joins an entry the
|
|
177
|
+
* transaction already holds; a flight nobody had observed yet has none (the
|
|
178
|
+
* reader is its first observer — a conditional that just revealed it, #3458)
|
|
179
|
+
* and is notified up the reader's own queue chain under that transaction,
|
|
180
|
+
* the one sanctioned registration site (INV-3): a collecting boundary above
|
|
181
|
+
* the reader consumes it as it would any pending, an unboundaried reader
|
|
182
|
+
* opens the entry — and the transaction, judged complete on its other
|
|
183
|
+
* flights, revealed the inputs beside the reader's pre-flight value
|
|
184
|
+
* otherwise (`Count: 1 | A: 1` beside `B: 0`). A staged signal or a settled
|
|
185
|
+
* node registers nothing. Every reporter dies with its reader
|
|
186
|
+
* (reporterBlocksSource: the read linked it as a dep). The node's own entry
|
|
187
|
+
* is the only one that can matter: a chain's intermediate memo is re-pulled
|
|
188
|
+
* by the read (updateIfNecessary's retry) and enters the transaction, so the
|
|
189
|
+
* reader holds through the normal path; a node with its own flight that is
|
|
190
|
+
* also pending on an upstream re-ask blocks through that flight until it
|
|
191
|
+
* lands, and its landing re-runs the reader into the normal path.
|
|
192
|
+
*/
|
|
193
|
+
/** The replay half of the stale-of-foreign clause (A15 / A26): a stale reader
|
|
194
|
+
* served the committed value because `txn` holds what it read re-runs at
|
|
195
|
+
* txn's commit, when the value it was denied becomes the frame — unless its
|
|
196
|
+
* own last value already came from that transaction. One registration for
|
|
197
|
+
* the node path (heldFromStale) and the store's backing paths, which have
|
|
198
|
+
* no node to carry the hold (heldFromReader, the adoption hold view). */
|
|
199
|
+
export declare function recordStaleReplay(txn: Transition, c: Computed<any>): void;
|
|
200
|
+
/**
|
|
201
|
+
* The ownership relation (DESIGN-CONSOLIDATION §6, ruled 2026-09-17): is
|
|
202
|
+
* `hold` part of the running pass's world? A plain reader's world is the
|
|
203
|
+
* transaction it runs under, through merges. A lane reader's world is its
|
|
204
|
+
* lane AND the transition that owns the lane — the one asymmetry between a
|
|
205
|
+
* lane and a separate transaction (a lane sees what lands from its parent as
|
|
206
|
+
* its own; a separate transaction would wait for the parent to settle) —
|
|
207
|
+
* see `ownsLane` in lanes.ts, built on this. One relation for the
|
|
208
|
+
* stale-of-foreign clause (heldFromStale), the lane arm (readsHeldCommitted)
|
|
209
|
+
* and the store's backing holds (foreignHold); `serve` has no lane arm of
|
|
210
|
+
* its own, the lane's extra visibility lives here.
|
|
211
|
+
*/
|
|
212
|
+
export declare function ownsHold(hold: Transition): boolean;
|
|
213
|
+
export declare function enterStagedRead(el: Signal<any> | Computed<any> | null, t?: Transition | null | undefined): void;
|
|
214
|
+
/**
|
|
215
|
+
* Rule 1 (value selection), the full arm: does this reader see a STAGED
|
|
216
|
+
* node's COMMITTED value? One implementation of the rule the fast paths
|
|
217
|
+
* (readNodeFast, read's fast block) carry as their trivial ternary and that
|
|
218
|
+
* every slow site — read's tail, the store's backing selection, the lane and
|
|
219
|
+
* verdict arms — used to restate by hand (docs/DESIGN-CONSOLIDATION.md, move 3b). In order:
|
|
220
|
+
* - no reader at all (an untracked read) — the committed frame;
|
|
221
|
+
* - a reader under an optimistic lane the engine says reads committed
|
|
222
|
+
* (laneReadsCommitted: another lane's hold, #3460);
|
|
223
|
+
* - nothing staged;
|
|
224
|
+
* - a children-forbidden reader (createTrackedEffect / onSettled: the frame,
|
|
225
|
+
* never the graph — A32);
|
|
226
|
+
* - a stale reader (render effect) of a FOREIGN transaction's staged write —
|
|
227
|
+
* committed, no entanglement (heldFromStale registers the replay; a node
|
|
228
|
+
* born held has no committed frame to fall back to, `noCommitted`);
|
|
229
|
+
* - A17 for HELD truth (#3164, CONFIG_HELD_TRUTH): staged confirming truth —
|
|
230
|
+
* fold-staged onto an armed family, or entangle-stolen by an awaited
|
|
231
|
+
* until() — is masked from ordinary readers until its transaction's
|
|
232
|
+
* reveal, the retaining transaction's own speculative recomputes included
|
|
233
|
+
* (partial override coverage would otherwise compose override + staged
|
|
234
|
+
* truth into a state no timeline contains). Authoritative readers
|
|
235
|
+
* (until()'s predicate) and latest() see the staged truth — the tunnel that
|
|
236
|
+
* keeps the hold deadlock-free.
|
|
237
|
+
* False means the reader derives from the staged value and enters its
|
|
238
|
+
* transaction (enterStagedRead, A29).
|
|
239
|
+
*/
|
|
240
|
+
export declare function readerSeesCommitted(el: Signal<any> | Computed<any>, c: Computed<any> | null, owner: Signal<any> | Computed<any>, noCommitted: boolean): boolean;
|
|
241
|
+
/** A28 — set when a node is staged (queuePendingNode) or a held node rewritten
|
|
242
|
+
* (stashHeldRewrite) OUTSIDE a flush; cleared when the next flush begins. The
|
|
243
|
+
* read sites test this one module boolean instead of `globalQueue._running`:
|
|
244
|
+
* inside a flush it is false and the A28 arm costs nothing; outside, only a
|
|
245
|
+
* tick with unflushed writes pays the staged-node check. */
|
|
246
|
+
export declare let unflushedStaged: boolean;
|
|
247
|
+
export declare function markUnflushedStaged(): void;
|
|
248
|
+
/** A28 — a write becomes visible at flush. Outside a flush, a node holding an
|
|
249
|
+
* AMBIENT staged value (no transaction stamp) was written since the last
|
|
250
|
+
* flush: ambient staging commits at flush end, so nothing else leaves a node
|
|
251
|
+
* in this state; a stamped value is the flushed held world, which A28 says
|
|
252
|
+
* latest() serves. Inside a flush the rule does not apply (A28 (4): promoted
|
|
253
|
+
* within the round). Structural — no marker on the write path. */
|
|
254
|
+
export declare function unflushed(el: Signal<any> | Computed<any>): boolean;
|
|
255
|
+
/** The value an unflushed node serves — the committed value for an ambient
|
|
256
|
+
* write, the flushed staged value for a rewrite of a held node — or
|
|
257
|
+
* NOT_PENDING when nothing is unflushed. Exempt: owned-write nodes (A28 (4):
|
|
258
|
+
* a write issued inside a recompute is promoted at that recompute's end —
|
|
259
|
+
* boundary and loading machinery, until()'s internals, signals declared for
|
|
260
|
+
* in-computation writes) and engine companions (the isPending() verdict
|
|
261
|
+
* signal, the latest() shadow: the system's own writes, made at the source's
|
|
262
|
+
* write to mirror it, installing eagerly — A28, A8). */
|
|
263
|
+
export declare function unflushedValue(el: Signal<any> | Computed<any>, committed?: any): unknown;
|
|
264
|
+
/** A28 (5): an optimistic write becomes the ACTIVE override at the flush that
|
|
265
|
+
* carries it. `_overrideTime` is stamped with `clock` at the write and `clock`
|
|
266
|
+
* advances after every flush, so "this tick, outside a flush" is unflushed. */
|
|
267
|
+
export declare function unflushedOverride(el: Signal<any> | Computed<any>): boolean;
|
|
268
|
+
/** Active optimistic override on an armed node (an armed slot idles at
|
|
269
|
+
* NOT_PENDING; undefined = unarmed plain node). The writer's own channels —
|
|
270
|
+
* the draft, `in`/keys inside the setter — compose on this regardless of
|
|
271
|
+
* flush state. */
|
|
272
|
+
export declare function hasActiveOverride(el: Signal<any> | Computed<any>): boolean;
|
|
273
|
+
/** The override a READER sees: installed, and carried by a flush (A28 (5) —
|
|
274
|
+
* an optimistic write is a write; until its flush no reader sees it). One
|
|
275
|
+
* implementation for read()'s override arm, the verdict channels
|
|
276
|
+
* (latestRead, computePendingState) and the store's selection
|
|
277
|
+
* (docs/DESIGN-CONSOLIDATION.md, move 3b). */
|
|
278
|
+
export declare function visibleOverride(el: Signal<any> | Computed<any>): boolean;
|
|
279
|
+
/** A derivation served the committed value because of an unflushed write
|
|
280
|
+
* (A28) must run again in the flush that carries it — the late-linker case
|
|
281
|
+
* (#3337's reason to defer the walk): it linked after the write walked. */
|
|
282
|
+
export declare function markLateLinker(c: Computed<any>): true;
|
|
283
|
+
/** Companion-bearing nodes written outside a flush (setSignal); the flush
|
|
284
|
+
* that carries their writes re-syncs their companions (A28). */
|
|
285
|
+
export declare const unflushedCompanions: Array<Signal<any> | Computed<any>>;
|
|
286
|
+
export declare function resyncUnflushedCompanions(): void;
|
|
131
287
|
export declare function readNodeFast<T>(el: Signal<T>): T | typeof READ_SLOW;
|
|
132
288
|
export declare function read<T>(el: Signal<T> | Computed<T>): T;
|
|
289
|
+
/**
|
|
290
|
+
* Rule 1, the one slow implementation (DESIGN-CONSOLIDATION move 3b, step
|
|
291
|
+
* 6c): the value a reader `c` (null = untracked, no pass) is served from
|
|
292
|
+
* `el`, whose committed value is `committed` — the node's own `_value` for
|
|
293
|
+
* a signal or memo, the BACKING for a store property node (single-home rule,
|
|
294
|
+
* O6: committed truth lives in the backing and a node's `_value` is never
|
|
295
|
+
* served for one). Called by read()'s slow tail and by the store's untracked
|
|
296
|
+
* node path (nodeValue); the fast paths (readNodeFast, read's fast block)
|
|
297
|
+
* keep their trivial ternary by design (perf, see the doc). Arms, in order:
|
|
298
|
+
* - the override (A17), routed through the engine for a tracked reader under
|
|
299
|
+
* a lane or a supersession (A18), an authoritative reader marked instead;
|
|
300
|
+
* - the lane entanglement gate (committed, recorded for replay);
|
|
301
|
+
* - a node born held has nothing for an untracked reader (A19 exception 1);
|
|
302
|
+
* - an unflushed write serves committed and re-runs the reader in the
|
|
303
|
+
* carrying flush (A28);
|
|
304
|
+
* - readerSeesCommitted, else the staged value and the transaction (A29).
|
|
305
|
+
*/
|
|
306
|
+
export declare function serve(el: Signal<any> | Computed<any>, c: Computed<any> | null, owner: Signal<any> | Computed<any>, committed: unknown): unknown;
|
|
133
307
|
/**
|
|
134
308
|
* Store-rewrite setter guard: the rewrite parks writes in a pending backing
|
|
135
309
|
* (no setSignal at write time), so the owned-scope write protection must
|
|
136
|
-
* fire at the setter entry instead.
|
|
310
|
+
* fire at the setter entry instead. Exactly setSignal's guard condition
|
|
137
311
|
* minus the node-specific exemptions (ownedWrite/firewall), which don't
|
|
138
|
-
* apply to plain store setters.
|
|
312
|
+
* apply to plain store setters. Roots are NOT exempt (#3500): a root body is
|
|
313
|
+
* tree construction — every dev component body, every context Provider, the
|
|
314
|
+
* top of `render()`, and the whole SSR pass run directly under one — and a
|
|
315
|
+
* write there re-runs what already read the old value (or on the server,
|
|
316
|
+
* can't). Same rule as setSignal, which never exempted roots.
|
|
139
317
|
*/
|
|
140
318
|
export declare function devGuardStoreSetterWrite(): void;
|
|
319
|
+
/**
|
|
320
|
+
* Store setter result guard: the callback's return has one meaning — a
|
|
321
|
+
* replacement root to adopt — and a thenable can never be that. It is the
|
|
322
|
+
* signature of `setStore(async d => …)` (or a sync arrow whose helper is
|
|
323
|
+
* async): only the writes before the first `await` were in the transaction;
|
|
324
|
+
* the rest land on a closed draft and vanish. Setters are synchronous
|
|
325
|
+
* transactions; async orchestration is `action()`'s job. Store-specific —
|
|
326
|
+
* a signal may legitimately hold a promise, so its setter has no such rule.
|
|
327
|
+
*/
|
|
328
|
+
export declare function devGuardStoreSetterResult(result: unknown): void;
|
|
141
329
|
export declare function setSignal<T>(el: Signal<T> | Computed<T>, v: T | ((prev: T) => T)): T;
|
|
142
330
|
/**
|
|
143
331
|
* Suppresses automatic recomputation of `el` until the scheduler drains. Used
|
package/dist/types/core/dev.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { type
|
|
2
|
-
import type {
|
|
1
|
+
import { type AttributionHooks, type InteractionRef, type OriginRef } from "./attribution-hooks.js";
|
|
2
|
+
import type { ChangeOrigin, RerunEvent } from "./attribution.js";
|
|
3
|
+
import type { Computed, Owner, Signal } from "./types.js";
|
|
3
4
|
export interface DevHooks {
|
|
4
5
|
onOwner?: (owner: Owner) => void;
|
|
5
6
|
onGraph?: (value: any, owner: Owner | null) => void;
|
|
@@ -13,13 +14,19 @@ export interface DevHooks {
|
|
|
13
14
|
* `warn`/`error` as failures unless they opt in to `info`.
|
|
14
15
|
*/
|
|
15
16
|
export type DiagnosticSeverity = "info" | "warn" | "error";
|
|
16
|
-
export type DiagnosticCode = "STRICT_READ_UNTRACKED" | "PENDING_ASYNC_UNTRACKED_READ" | "PENDING_ASYNC_FORBIDDEN_SCOPE" | "REACTIVE_WRITE_IN_OWNED_SCOPE" | "ACTION_CALLED_IN_OWNED_SCOPE" | "RUN_WITH_DISPOSED_OWNER" | "NO_OWNER_CLEANUP" | "CLEANUP_IN_FORBIDDEN_SCOPE" | "SETTLED_CLEANUP_UNOWNED" | "SETTLE_WALK_UNINITIALIZED_SOURCE" | "FLUSH_IN_EFFECT_CALLBACK" | "PRIMITIVE_IN_FORBIDDEN_SCOPE" | "NO_OWNER_EFFECT" | "NO_OWNER_BOUNDARY" | "ASYNC_OUTSIDE_LOADING_BOUNDARY" | "INVALID_REFRESH_TARGET" | "INVALID_AFFECTS_TARGET" | "MISSING_EFFECT_FN" | "SYNC_NODE_RECEIVED_ASYNC" | "REACTIVITY_HALTED" | "INVARIANT_VIOLATION" | "HUGE_FAN_OUT" | "HUGE_FAN_IN" | "HOT_SCOPE_RERUNS" | "HOT_SCOPE_TIME" | "WIDE_SCOPE_DEPS" | "UNSTABLE_MEMO_OUTPUT" | "WIDE_WRITE" | "ASYNC_WATERFALL" | "HOT_SCOPE_FANOUT" | "SILENT_HOLD" | "LONG_HOLD" | "EFFECT_WRITES_OWN_SOURCE" | "EFFECT_RELAY_TEAR" | "IMMUTABLE_UPDATE_IN_STORE" | "UNSTABLE_LIST_IDENTITY";
|
|
17
|
+
export type DiagnosticCode = "STRICT_READ_UNTRACKED" | "PENDING_ASYNC_UNTRACKED_READ" | "PENDING_ASYNC_FORBIDDEN_SCOPE" | "REACTIVE_WRITE_IN_OWNED_SCOPE" | "ASYNC_STORE_SETTER" | "ACTION_CALLED_IN_OWNED_SCOPE" | "RUN_WITH_DISPOSED_OWNER" | "NO_OWNER_CLEANUP" | "CLEANUP_IN_FORBIDDEN_SCOPE" | "SETTLED_CLEANUP_UNOWNED" | "SETTLE_WALK_UNINITIALIZED_SOURCE" | "FLUSH_IN_EFFECT_CALLBACK" | "PRIMITIVE_IN_FORBIDDEN_SCOPE" | "NO_OWNER_EFFECT" | "NO_OWNER_BOUNDARY" | "ASYNC_OUTSIDE_LOADING_BOUNDARY" | "INVALID_REFRESH_TARGET" | "INVALID_AFFECTS_TARGET" | "MISSING_EFFECT_FN" | "SYNC_NODE_RECEIVED_ASYNC" | "REACTIVITY_HALTED" | "INVARIANT_VIOLATION" | "HUGE_FAN_OUT" | "HUGE_FAN_IN" | "HOT_SCOPE_RERUNS" | "HOT_SCOPE_TIME" | "WIDE_SCOPE_DEPS" | "UNSTABLE_MEMO_OUTPUT" | "WIDE_WRITE" | "ASYNC_WATERFALL" | "HOT_SCOPE_FANOUT" | "SILENT_HOLD" | "LONG_HOLD" | "EFFECT_WRITES_OWN_SOURCE" | "EFFECT_RELAY_TEAR" | "IMMUTABLE_UPDATE_IN_STORE" | "UNSTABLE_LIST_IDENTITY" | "SSR_RENDER_ERROR_CONTAINED" | "SSR_SUBTREE_ABANDONED" | "SSR_STREAM_ABANDONED" | "SSR_CLIENT_CONTENT_MASKED" | "LATE_HEADER_WRITE" | "SERVER_FN_ERROR_SANITIZED" | "SSR_ERROR_SANITIZED" | "SERVER_WRITE" | "REVEAL_IN_RENDER_TO_STRING" | "LAZY_ASSET_UNMAPPED" | "PRELOAD_DESCRIPTOR_INVALID" | "HEAD_TAG_INVALID" | "UNRECOGNIZED_INSERT_VALUE" | "BEHAVIOR_CLAIM_DROPPED" | "FRAME_MARKER_CORRUPTED";
|
|
17
18
|
export type DiagnosticKind = "strict-read" | "async" | "write" | "lifecycle" | "owner" | "error" | "perf" | "graph"
|
|
18
19
|
/** Perceived responsiveness: the runtime behaved correctly but the user saw no feedback. */
|
|
19
|
-
| "responsiveness"
|
|
20
|
-
/**
|
|
20
|
+
| "responsiveness"
|
|
21
|
+
/** Server rendering: boundaries, fragments, the stream, the server-function wire. */
|
|
22
|
+
| "ssr"
|
|
23
|
+
/** The response head: `<head>` tags, preload descriptors, HTTP headers. */
|
|
24
|
+
| "head"
|
|
25
|
+
/** The renderer's insert positions, on either platform: a value it has no rendering for. */
|
|
26
|
+
| "render";
|
|
27
|
+
/** First warning when a change reaches (or a pass tracks) this many edges. */
|
|
21
28
|
export declare const GRAPH_SIZE_WARN_AT = 2000;
|
|
22
|
-
/**
|
|
29
|
+
/** Re-warn once the count has grown by this much since the last warning. */
|
|
23
30
|
export declare const GRAPH_SIZE_WARN_EVERY = 500;
|
|
24
31
|
export interface DiagnosticEvent {
|
|
25
32
|
sequence: number;
|
|
@@ -51,27 +58,218 @@ export interface Diagnostics {
|
|
|
51
58
|
subscribe(listener: DiagnosticListener): () => void;
|
|
52
59
|
capture(): DiagnosticCapture;
|
|
53
60
|
/**
|
|
54
|
-
*
|
|
55
|
-
*
|
|
56
|
-
*
|
|
57
|
-
*
|
|
58
|
-
*
|
|
59
|
-
* for an event suppresses the footer. Passing undefined unregisters and
|
|
60
|
-
* resets the once-per-code memory.
|
|
61
|
+
* Records an event on the channel from outside the reactive core — a host
|
|
62
|
+
* runtime reporting its own findings (hydration mismatches, server render
|
|
63
|
+
* faults) so consumers see one stream. `subject` locates it like the
|
|
64
|
+
* internal sites do; a host whose owners are not signals' owners passes
|
|
65
|
+
* `ownerPath` on the event instead and it is used as-is.
|
|
61
66
|
*/
|
|
62
|
-
|
|
67
|
+
emit(event: Omit<DiagnosticEvent, "sequence">, subject?: DiagnosticSubject | null): DiagnosticEvent;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* The core's side of attribution: the hook slot an engine installs into, and
|
|
71
|
+
* the interaction frame the rendering runtime opens around event dispatch.
|
|
72
|
+
* The engine itself — "why did this run", costs, holds, feedback — is
|
|
73
|
+
* `@solidjs/signals/attribution`, a separate entry so an observe build pays
|
|
74
|
+
* for it only when something imports it.
|
|
75
|
+
*/
|
|
76
|
+
export interface AttributionSlot {
|
|
77
|
+
/**
|
|
78
|
+
* Installs `hooks` as the engine the core reports facts to (`null`
|
|
79
|
+
* uninstalls). One engine at a time; the built-in engine's `enable()` calls
|
|
80
|
+
* this, and an external consumer (devtools) may install its own instead.
|
|
81
|
+
*/
|
|
82
|
+
install(hooks: AttributionHooks | null): void;
|
|
83
|
+
/** The installed engine's hooks, or `null` when none is installed. */
|
|
84
|
+
readonly installed: AttributionHooks | null;
|
|
85
|
+
/**
|
|
86
|
+
* Run `fn` as a user interaction's handler: root writes inside stamp it as
|
|
87
|
+
* their origin, and actions/effects/flights it causes carry it. The web
|
|
88
|
+
* runtime wraps every event dispatch in this; custom renderers and test
|
|
89
|
+
* harnesses call it themselves. `fn()` when no engine is installed.
|
|
90
|
+
*/
|
|
91
|
+
withInteraction<T>(ref: InteractionRef, fn: () => T): T;
|
|
92
|
+
/**
|
|
93
|
+
* Run `fn` as a declared unit of work — a router's navigation, described
|
|
94
|
+
* by the parametrized route it matched: root writes inside are attributed
|
|
95
|
+
* to it (under the enclosing interaction, if any), so the hold behind the
|
|
96
|
+
* route's data, the re-runs and the verdicts carry the route's name. Any
|
|
97
|
+
* router calls this around its location write; nothing else is
|
|
98
|
+
* router-specific. `fn()` when no engine is installed.
|
|
99
|
+
*/
|
|
100
|
+
withOrigin<T>(ref: OriginRef, fn: () => T): T;
|
|
101
|
+
/**
|
|
102
|
+
* The provenance a root write performed now would be stamped with — the
|
|
103
|
+
* interaction whose handler is running, the navigation or effect or action
|
|
104
|
+
* frame open, or inside a recompute the origin of the change that caused
|
|
105
|
+
* it — as the installed engine sees it; `undefined` with no engine, or when
|
|
106
|
+
* nothing is in effect (external). For a runtime recording a fact of its
|
|
107
|
+
* own beside the engine's records: `@solidjs/web` stamps its `"call"`
|
|
108
|
+
* record with this, so a server-function call joins the interaction or
|
|
109
|
+
* navigation it ran for by the identity of the object, not by time.
|
|
110
|
+
*/
|
|
111
|
+
currentOrigin(): ChangeOrigin | undefined;
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* The records the runtimes deliver on `OBSERVE.records`, by type — each
|
|
115
|
+
* entry `{ event, live }`: the serializable record and the live handles
|
|
116
|
+
* (a thrown error, a request) an in-process consumer may want beside it.
|
|
117
|
+
* The core emits none and declares none; the runtimes that emit declare
|
|
118
|
+
* theirs by augmentation, and the union of record types is whatever the
|
|
119
|
+
* loaded runtimes declared. `solid-js` augments THIS interface (its
|
|
120
|
+
* `"boundary"` record); the runtimes above it — `@solidjs/web`'s
|
|
121
|
+
* `"invocation"`, `"frame"` and `"call"`, a router's — augment
|
|
122
|
+
* `HostRecordTypes`, reached through the `solid-js` re-export, which this
|
|
123
|
+
* interface extends so the channel sees one catalogue.
|
|
124
|
+
*
|
|
125
|
+
* Two interfaces, one augmenter each, by design: TypeScript merges an
|
|
126
|
+
* augmentation into a re-exported interface by following the alias, and
|
|
127
|
+
* two augmentations reaching the same interface through DIFFERENT aliases
|
|
128
|
+
* (`"@solidjs/signals"` from solid-js, `"solid-js"` from web) merge
|
|
129
|
+
* order-dependently — one set is lost. So each layer augments an interface
|
|
130
|
+
* of its own, through one module name.
|
|
131
|
+
*/
|
|
132
|
+
export interface RecordTypes extends HostRecordTypes {
|
|
133
|
+
}
|
|
134
|
+
/** The record types host runtimes declare — see `RecordTypes`. */
|
|
135
|
+
export interface HostRecordTypes {
|
|
136
|
+
}
|
|
137
|
+
export type RecordType = keyof RecordTypes & string;
|
|
138
|
+
export type RecordEvent<K extends RecordType> = RecordTypes[K] extends {
|
|
139
|
+
event: infer E;
|
|
140
|
+
} ? E : never;
|
|
141
|
+
export type RecordLive<K extends RecordType> = RecordTypes[K] extends {
|
|
142
|
+
live: infer L;
|
|
143
|
+
} ? L : never;
|
|
144
|
+
export type RecordListener<K extends RecordType> = (event: RecordEvent<K>, live: RecordLive<K>) => void;
|
|
145
|
+
/**
|
|
146
|
+
* The records channel — `OBSERVE.records`, on either platform: one place a
|
|
147
|
+
* consumer (an APM adapter's `init()`, devtools, the diagnostics harness)
|
|
148
|
+
* subscribes to the completed, serializable summaries of the things the
|
|
149
|
+
* runtimes did — a `<Loading>` boundary that waited on the server, a
|
|
150
|
+
* server-function execution or call, a frame stream produced or applied —
|
|
151
|
+
* each delivered synchronously the moment it is complete, with its live
|
|
152
|
+
* handles passed BESIDE it. Any number of listeners; none can alter what it
|
|
153
|
+
* observes; one that throws is reported and the rest run. (Reactive
|
|
154
|
+
* attribution — re-runs, holds, interactions — is the attribution engine's
|
|
155
|
+
* `subscribe`, a separate entry the observe build pays for only when
|
|
156
|
+
* imported.)
|
|
157
|
+
*
|
|
158
|
+
* The object is created once per PROCESS under a registered symbol, so a
|
|
159
|
+
* subscription made before the emitting runtime has loaded, or from a
|
|
160
|
+
* second bundled copy of the core, reaches the same listener set. Absent in
|
|
161
|
+
* prod with the rest of `OBSERVE`.
|
|
162
|
+
*/
|
|
163
|
+
export interface Records {
|
|
164
|
+
/** Deliver `type` records as they complete; returns the unsubscribe. */
|
|
165
|
+
subscribe<K extends RecordType>(type: K, listener: RecordListener<K>): () => void;
|
|
166
|
+
/**
|
|
167
|
+
* Whether anything is subscribed to `type` — an emitter's pre-check, so
|
|
168
|
+
* a record nobody will hear costs nothing to not build (no clock read).
|
|
169
|
+
*/
|
|
170
|
+
observed(type: RecordType): boolean;
|
|
171
|
+
/**
|
|
172
|
+
* Delivers a completed record to `type`'s listeners, synchronously: how a
|
|
173
|
+
* runtime publishes. Snapshot iteration — a listener unsubscribing
|
|
174
|
+
* mid-delivery neither skips nor double-calls anyone this round.
|
|
175
|
+
*/
|
|
176
|
+
emit<K extends RecordType>(type: K, event: RecordEvent<K>, live: RecordLive<K>): void;
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* The server runtime's observe surface — where a server-side consumer
|
|
180
|
+
* installs what only the server has: the trace-context provider slot.
|
|
181
|
+
* Declared EMPTY here and typed by the runtime that owns the surface:
|
|
182
|
+
* `solid-js`'s server entry augments this interface with `trace:
|
|
183
|
+
* ServerTrace`, an interface of its own that `@solidjs/web`'s server
|
|
184
|
+
* entries fill in (`provide`) — so the core never learns that shape and
|
|
185
|
+
* the consumer still finds it on the one `OBSERVE`. One augmenter per
|
|
186
|
+
* interface: see `RecordTypes` for why.
|
|
187
|
+
*
|
|
188
|
+
* The OBJECT behind it is not the core's either: the core has one artifact
|
|
189
|
+
* per tier for both platforms, and the client would carry it for nothing.
|
|
190
|
+
* `solid-js`'s server entry replaces this empty literal with the
|
|
191
|
+
* process-wide slot the moment it evaluates (see `serverSlots` in
|
|
192
|
+
* solid-js/src/server/observe.ts), so a consumer that imports only
|
|
193
|
+
* `solid-js` can provide before the web runtime that reads it has loaded,
|
|
194
|
+
* and from a second copy when a host bundles one. On the client this stays
|
|
195
|
+
* `{}`.
|
|
196
|
+
*/
|
|
197
|
+
export interface ServerObserve {
|
|
63
198
|
}
|
|
199
|
+
/**
|
|
200
|
+
* The observe tier: the structured channel and the attribution wiring —
|
|
201
|
+
* everything a production observability consumer needs, and nothing that
|
|
202
|
+
* assumes a developer at a console. Present in dev and observe builds
|
|
203
|
+
* (`__OBSERVE__`); `undefined` in prod.
|
|
204
|
+
*/
|
|
205
|
+
export interface Observe {
|
|
206
|
+
diagnostics: Diagnostics;
|
|
207
|
+
/** Completed records from the runtimes, by type — see `Records`. */
|
|
208
|
+
records: Records;
|
|
209
|
+
/** The attribution hook slot and interaction frame — see `AttributionSlot`. */
|
|
210
|
+
attribution: AttributionSlot;
|
|
211
|
+
/** The server runtime's surface — see `ServerObserve`. */
|
|
212
|
+
server: ServerObserve;
|
|
213
|
+
/**
|
|
214
|
+
* The live node an emitted record was about, when the emitter knew it.
|
|
215
|
+
* Records are serializable and never carry the node — a diagnostic event
|
|
216
|
+
* names its subject by `ownerPath`/`nodeName`, a re-run record by
|
|
217
|
+
* `nodeId` — so consumers that run in-process (devtools, the console
|
|
218
|
+
* reporter, `attribution.subscriptions(OBSERVE.subjectOf(run))`) look the
|
|
219
|
+
* node up here. Answers for `DiagnosticEvent`s and the attribution
|
|
220
|
+
* engine's `RerunEvent`s; `undefined` for anything else, and for a record
|
|
221
|
+
* that has left the process and come back.
|
|
222
|
+
*/
|
|
223
|
+
subjectOf(record: DiagnosticEvent | RerunEvent): DiagnosticSubject | undefined;
|
|
224
|
+
/**
|
|
225
|
+
* Marks `owner`'s subtree as the observer's own. A consumer that renders
|
|
226
|
+
* inside the app it watches — an APM adapter's panel, devtools — would
|
|
227
|
+
* otherwise see its own effects, stores and holds reported as findings about
|
|
228
|
+
* the app. Under an excluded owner: diagnostics whose subject sits in the
|
|
229
|
+
* subtree are neither delivered nor reported (the entry is still built, so
|
|
230
|
+
* a site that throws its message still throws), and the attribution engine
|
|
231
|
+
* records no runs for its computations. Mark the root as it is created
|
|
232
|
+
* (`createRoot(() => { OBSERVE.exclude(getOwner()!); … })`); the signals
|
|
233
|
+
* and stores created under it are excluded subjects wherever their writes
|
|
234
|
+
* come from (a click handler, an adapter callback), so writes need no
|
|
235
|
+
* `runWithOwner` — and must not use one: a write under an owner is a write
|
|
236
|
+
* in an owned scope (REACTIVE_WRITE_IN_OWNED_SCOPE). Irrevocable for the
|
|
237
|
+
* owner's lifetime.
|
|
238
|
+
*/
|
|
239
|
+
exclude(owner: Owner): void;
|
|
240
|
+
/** Whether `subject` sits under an excluded owner (itself included). */
|
|
241
|
+
isExcluded(subject: DiagnosticSubject | null | undefined): boolean;
|
|
242
|
+
}
|
|
243
|
+
/**
|
|
244
|
+
* The dev tier: devtools hooks, graph traversal, and the console face of the
|
|
245
|
+
* diagnostics channel. Present only in dev builds (`__DEV__`).
|
|
246
|
+
*/
|
|
64
247
|
export interface Dev {
|
|
65
248
|
hooks: DevHooks;
|
|
66
|
-
diagnostics: Diagnostics;
|
|
67
|
-
/** "Why did this run" re-run attribution — see attribution.ts. */
|
|
68
|
-
attribution: Attribution;
|
|
69
249
|
getChildren: typeof getChildren;
|
|
70
250
|
getSignals: typeof getSignals;
|
|
71
251
|
getParent: typeof getParent;
|
|
72
252
|
getSources: typeof getSources;
|
|
73
253
|
getObservers: typeof getObservers;
|
|
254
|
+
/** Console face of an emitted event — see `reportDiagnostic`. */
|
|
255
|
+
report(entry: DiagnosticEvent): void;
|
|
256
|
+
/**
|
|
257
|
+
* Registers a console footer appended to the first console report of
|
|
258
|
+
* each diagnostic code — a discovery pointer to deeper guidance (e.g.
|
|
259
|
+
* solid-js registers its shipped repair skill). Reported events carry
|
|
260
|
+
* it as trailing lines of the same console entry; events that surface as
|
|
261
|
+
* a thrown error instead get it as a follow-up line. Returning undefined
|
|
262
|
+
* for an event suppresses the footer. Passing undefined unregisters and
|
|
263
|
+
* resets the once-per-code memory.
|
|
264
|
+
*/
|
|
265
|
+
setConsoleFooter(footer: ((event: DiagnosticEvent) => string | undefined) | undefined): void;
|
|
74
266
|
}
|
|
267
|
+
export declare const OBSERVE: Observe;
|
|
268
|
+
export declare function isExcluded(subject: DiagnosticSubject | null | undefined): boolean;
|
|
269
|
+
/** For engines that cache the verdict per node: is anything excluded at all? */
|
|
270
|
+
export declare function anyExcluded(): boolean;
|
|
271
|
+
/** Was `entry` built for an excluded subject? Once-per-key reporters must not spend their slot on it. */
|
|
272
|
+
export declare function isSuppressed(entry: DiagnosticEvent): boolean;
|
|
75
273
|
export declare const DEV: Dev;
|
|
76
274
|
/**
|
|
77
275
|
* Dev-mode internal consistency check. A failure means the reactive system
|
|
@@ -96,9 +294,15 @@ export declare function ownerPath(subject: DiagnosticSubject | null | undefined)
|
|
|
96
294
|
* default (right for the synchronous rule checks — they fire inside the
|
|
97
295
|
* scope that misbehaved); pass the node for scheduler-time findings whose
|
|
98
296
|
* ambient context is the flush, or `null` for events that have no location
|
|
99
|
-
* by nature.
|
|
297
|
+
* by nature. An `ownerPath` already on the event wins over the subject walk
|
|
298
|
+
* (hosts whose owners are not signals' owners compute their own). Console
|
|
299
|
+
* output is a separate, dev-tier step — see `reportDiagnostic`.
|
|
100
300
|
*/
|
|
101
|
-
export declare function emitDiagnostic(event: Omit<DiagnosticEvent, "sequence"
|
|
301
|
+
export declare function emitDiagnostic(event: Omit<DiagnosticEvent, "sequence">, subject?: DiagnosticSubject | null | undefined): DiagnosticEvent;
|
|
302
|
+
/** Register `subject` as what `record` was about — see `Observe.subjectOf`. */
|
|
303
|
+
export declare function recordSubject(record: object, subject: DiagnosticSubject): void;
|
|
304
|
+
/** The live subject `record` was about, if its emitter registered one. */
|
|
305
|
+
export declare function subjectOf(record: object): DiagnosticSubject | undefined;
|
|
102
306
|
/**
|
|
103
307
|
* The console face of a diagnostic — ONE entry per finding: the message, the
|
|
104
308
|
* owner path (`in <App> › <TodoRow> › effect`) so a human can locate it, the
|
|
@@ -107,7 +311,9 @@ export declare function emitDiagnostic(event: Omit<DiagnosticEvent, "sequence" |
|
|
|
107
311
|
* second console argument (hover highlights it, click jumps to Elements).
|
|
108
312
|
* Severity picks the console method. Call sites report the entry
|
|
109
313
|
* `emitDiagnostic` returned so the structured and console channels never
|
|
110
|
-
* disagree.
|
|
314
|
+
* disagree. Dev-tier: in an observe build this is a no-op, so wiring paths
|
|
315
|
+
* that both emit and report (graph-size warnings) reach the channel only —
|
|
316
|
+
* production observability never writes to the console.
|
|
111
317
|
*/
|
|
112
318
|
export declare function reportDiagnostic(entry: DiagnosticEvent): void;
|
|
113
319
|
/**
|
|
@@ -117,6 +323,11 @@ export declare function reportDiagnostic(entry: DiagnosticEvent): void;
|
|
|
117
323
|
*/
|
|
118
324
|
export declare function throwPendingUntrackedRead(strictReadLabel: string, fields?: Partial<Omit<DiagnosticEvent, "sequence" | "data" | "ownerPath">>): never;
|
|
119
325
|
export declare function warnStrictReadUntracked(strictReadLabel: string, fields?: Partial<Omit<DiagnosticEvent, "sequence" | "ownerPath">>): void;
|
|
326
|
+
/**
|
|
327
|
+
* Observe-tier: stamp a signal with its creating owner so `ownerPath` can
|
|
328
|
+
* locate signal subjects. The per-owner `_signals` list and the devtools
|
|
329
|
+
* `onGraph` hook are dev-tier — the observe build pays one property write.
|
|
330
|
+
*/
|
|
120
331
|
export declare function registerGraph(value: any, owner: Owner | null): void;
|
|
121
332
|
export declare function clearSignals(node: Owner): void;
|
|
122
333
|
export declare function getChildren(owner: Owner): Owner[];
|
|
@@ -125,12 +336,19 @@ export declare function getParent(owner: Owner): Owner | null;
|
|
|
125
336
|
export declare function getSources(computation: Computed<any>): (Signal<any> | Computed<any>)[];
|
|
126
337
|
export declare function getObservers(node: Signal<any> | Computed<any>): Computed<any>[];
|
|
127
338
|
/**
|
|
128
|
-
*
|
|
129
|
-
*
|
|
130
|
-
* fan-
|
|
131
|
-
*
|
|
132
|
-
*
|
|
339
|
+
* Observe-tier: a committed change on `node` is about to re-run `count`
|
|
340
|
+
* subscribers (the notify walk in `insertSubs` counted them as it went —
|
|
341
|
+
* fan-out costs exactly one local increment in a loop that already visits
|
|
342
|
+
* every edge, and nothing at link time). Fires from GRAPH_SIZE_WARN_AT up,
|
|
343
|
+
* on the write rather than the link: a fan-out that is never written costs
|
|
344
|
+
* nothing, and one that is re-runs every subscriber this flush. Always-on
|
|
345
|
+
* wherever the channel exists — unlike the opt-in attribution engine, a
|
|
346
|
+
* graph-size pathology should surface without asking.
|
|
347
|
+
*/
|
|
348
|
+
export declare function noteFanOut(node: Signal<any> | Computed<any>, count: number): void;
|
|
349
|
+
/**
|
|
350
|
+
* Observe-tier: a recompute pass of `node` tracked `count` distinct sources
|
|
351
|
+
* (its trimmed dep list, walked once at the end of the pass — see recompute;
|
|
352
|
+
* no per-link work, no pass bracket). Fires from GRAPH_SIZE_WARN_AT up.
|
|
133
353
|
*/
|
|
134
|
-
export declare function
|
|
135
|
-
/** DEV-only: drop live edge counts when a link is removed. */
|
|
136
|
-
export declare function unnoteGraphLink(link: Link): void;
|
|
354
|
+
export declare function noteFanIn(node: Computed<any>, count: number): void;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type Transition } from "./scheduler.js";
|
|
1
2
|
import type { Computed, NodeOptions, Owner } from "./types.js";
|
|
2
3
|
export interface Effect<T> extends Computed<T>, Owner {
|
|
3
4
|
_effectFn: (val: T, prev: T | undefined) => void | (() => void);
|
|
@@ -5,7 +6,13 @@ export interface Effect<T> extends Computed<T>, Owner {
|
|
|
5
6
|
_modified: boolean;
|
|
6
7
|
_prevValue: T | undefined;
|
|
7
8
|
_type: number;
|
|
8
|
-
_boundRunEffect?: () => void;
|
|
9
|
+
_boundRunEffect?: (type: number) => void;
|
|
10
|
+
/** The transaction whose staged view produced `_value` (null = committed
|
|
11
|
+
* view). Effects have one value slot and do not entangle transactions, so
|
|
12
|
+
* a second transaction recomputing the same effect overwrites a value the
|
|
13
|
+
* first one still owes a run for; see the contested-effect arm of recompute
|
|
14
|
+
* (#3322). */
|
|
15
|
+
_valueTransition: Transition | null;
|
|
9
16
|
}
|
|
10
17
|
/**
|
|
11
18
|
* Effects are the leaf nodes of our reactive graph. When their sources change, they are
|