@solidjs/signals 2.0.0-rc.7 → 2.0.0-rc.8
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 +5243 -0
- package/dist/dev.attribution.js +2333 -0
- package/dist/dev.js +1229 -6834
- package/dist/observe/affects.js +127 -0
- package/dist/observe/attribution.js +1 -0
- package/dist/observe/boundaries.js +586 -0
- package/dist/observe/core/action.js +167 -0
- package/dist/observe/core/async.js +736 -0
- package/dist/observe/core/attribution-hooks.js +60 -0
- package/dist/observe/core/attribution.js +2318 -0
- package/dist/{types-cjs/core/constants.d.cts → observe/core/constants.js} +129 -73
- package/dist/{types-cjs/core/context.d.cts → observe/core/context.js} +37 -12
- package/dist/observe/core/core.js +1289 -0
- package/dist/observe/core/dev.js +232 -0
- package/dist/observe/core/effect.js +179 -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 +43 -0
- package/dist/observe/core/lanes.js +168 -0
- package/dist/observe/core/optimistic.js +438 -0
- package/dist/observe/core/owner.js +308 -0
- package/dist/observe/core/scheduler.js +1190 -0
- package/dist/observe/core/verdict.js +551 -0
- package/dist/observe/index.js +55 -0
- package/dist/observe/map.js +482 -0
- package/dist/{types-cjs/signals.d.cts → observe/signals.js} +295 -317
- package/dist/observe/store/index.js +38 -0
- package/dist/observe/store/next/optimistic.js +651 -0
- package/dist/observe/store/next/projection.js +242 -0
- package/dist/observe/store/next/reconcile.js +373 -0
- package/dist/observe/store/next/store.js +2213 -0
- package/dist/observe/store/next/target.js +51 -0
- package/dist/observe/store/store.js +323 -0
- package/dist/observe/store/storePath.js +103 -0
- package/dist/observe/store/utils.js +210 -0
- package/dist/prod/attribution.js +32 -0
- package/dist/prod/core/action.js +52 -32
- package/dist/prod/core/async.js +171 -127
- package/dist/prod/core/constants.js +24 -1
- package/dist/prod/core/context.js +3 -3
- package/dist/prod/core/core.js +434 -291
- package/dist/prod/core/effect.js +54 -34
- package/dist/prod/core/external.js +2 -2
- package/dist/prod/core/graph.js +32 -32
- package/dist/prod/core/heap.js +49 -44
- package/dist/prod/core/lanes.js +45 -38
- package/dist/prod/core/optimistic.js +207 -73
- package/dist/prod/core/owner.js +43 -39
- package/dist/prod/core/scheduler.js +319 -190
- package/dist/prod/core/verdict.js +67 -67
- package/dist/prod/index.js +9 -3
- package/dist/prod/map.js +292 -141
- package/dist/prod/signals.js +7 -10
- package/dist/prod/store/next/optimistic.js +140 -125
- package/dist/prod/store/next/projection.js +3 -3
- package/dist/prod/store/next/reconcile.js +87 -84
- package/dist/prod/store/next/store.js +524 -280
- package/dist/prod/store/next/target.js +32 -10
- package/dist/prod/store/store.js +12 -14
- package/dist/prod/store/utils.js +36 -27
- package/dist/types/attribution.d.ts +15 -0
- package/dist/types/attribution.prod.d.ts +13 -0
- package/dist/types/core/async.d.ts +1 -1
- package/dist/types/core/attribution-hooks.d.ts +119 -6
- package/dist/types/core/attribution.d.ts +208 -53
- package/dist/types/core/constants.d.ts +23 -0
- package/dist/types/core/core.d.ts +7 -0
- package/dist/types/core/dev.d.ts +124 -26
- package/dist/types/core/effect.d.ts +8 -1
- package/dist/types/core/index.d.ts +2 -1
- package/dist/types/core/lanes.d.ts +8 -1
- package/dist/types/core/scheduler.d.ts +60 -0
- package/dist/types/core/types.d.ts +29 -9
- package/dist/types/index.d.ts +9 -2
- package/dist/types/map.d.ts +2 -0
- package/dist/types/store/index.d.ts +1 -0
- package/dist/types/store/next/store.d.ts +5 -0
- package/dist/types/store/next/target.d.ts +36 -9
- package/dist/types/store/utils.d.ts +7 -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/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,6 +1,7 @@
|
|
|
1
1
|
import type { Computed } from "./types.js";
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
3
|
+
* "Why did this run" attribution — the engine behind
|
|
4
|
+
* `@solidjs/signals/attribution`.
|
|
4
5
|
*
|
|
5
6
|
* The runtime already knows the full dependency set of every scope; this
|
|
6
7
|
* module surfaces it. Every value commit stamps its node with a ChangeRecord
|
|
@@ -15,11 +16,13 @@ import type { Computed } from "./types.js";
|
|
|
15
16
|
*
|
|
16
17
|
* This module is the attribution ENGINE: all semantics live here, and it is
|
|
17
18
|
* decoupled from the core. `enable()` installs it into the core's narrow
|
|
18
|
-
*
|
|
19
|
-
* call those hooks with true facts. Disabled cost is one null check per
|
|
20
|
-
* site; prod builds fold the sites out entirely.
|
|
21
|
-
*
|
|
22
|
-
*
|
|
19
|
+
* observe-tier hook points (attribution-hooks.ts); core's only obligation is
|
|
20
|
+
* to call those hooks with true facts. Disabled cost is one null check per
|
|
21
|
+
* hook site; prod builds fold the sites out entirely. Nothing in the core
|
|
22
|
+
* imports this module — it is reachable only through the package's
|
|
23
|
+
* `./attribution` entry, so an observe build that never imports it never
|
|
24
|
+
* ships it. The same hook surface is the intended substrate for external
|
|
25
|
+
* consumers (devtools) — one mechanism, two front-ends.
|
|
23
26
|
*/
|
|
24
27
|
export type ChangeKind = "write" | "derived" | "async" | "refresh";
|
|
25
28
|
/**
|
|
@@ -36,30 +39,32 @@ export type ChangeKind = "write" | "derived" | "async" | "refresh";
|
|
|
36
39
|
* name, when it has one). Writes after an `await` (not a `yield`) run in a
|
|
37
40
|
* bare microtask and stamp `external` — the documented escape.
|
|
38
41
|
* - `async` — an async landing (`name` = the node whose flight landed).
|
|
42
|
+
* - `navigation` — a router's navigation, declared via `withOrigin` around
|
|
43
|
+
* the location write (`name` = the matched route pattern `/users/:id`;
|
|
44
|
+
* `to`/`from` the concrete paths; `params` what the pattern bound; `at`
|
|
45
|
+
* when it was requested). The router-agnostic seam: any router that wraps
|
|
46
|
+
* its write gets navigations named by route in every hold, re-run and
|
|
47
|
+
* verdict, with no per-router knowledge anywhere in the engine.
|
|
39
48
|
* - `external` — none of the above: timers, sockets, promise callbacks, setup.
|
|
40
49
|
*
|
|
41
50
|
* `interaction` on a non-interaction frame is the user event the frame runs
|
|
42
51
|
* under — an action started by a click, an effect whose run was caused by a
|
|
43
|
-
* click's write, a landing whose flight a click started
|
|
44
|
-
* every downstream cost be keyed by the
|
|
52
|
+
* click's write, a landing whose flight a click started, a navigation a link
|
|
53
|
+
* click performed. It is what lets every downstream cost be keyed by the
|
|
54
|
+
* interaction that paid for it.
|
|
45
55
|
*/
|
|
46
56
|
export interface ChangeOrigin {
|
|
47
|
-
kind: "interaction" | "effect" | "action" | "async" | "external";
|
|
57
|
+
kind: "interaction" | "effect" | "action" | "async" | "navigation" | "external";
|
|
48
58
|
name?: string;
|
|
49
59
|
target?: string;
|
|
50
60
|
at?: number;
|
|
51
61
|
interaction?: ChangeOrigin;
|
|
52
62
|
/** `effect` only: the `RerunEvent.run` of the compute run this callback belongs to. */
|
|
53
63
|
run?: number;
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
type: string;
|
|
59
|
-
/** The element hit, e.g. `button#next "Next →"`. */
|
|
60
|
-
target?: string;
|
|
61
|
-
/** Dispatch time on the `performance.now()` clock; defaults to now. */
|
|
62
|
-
at?: number;
|
|
64
|
+
/** `navigation` only: concrete destination and departure paths, and the bound params. */
|
|
65
|
+
to?: string;
|
|
66
|
+
from?: string;
|
|
67
|
+
params?: Readonly<Record<string, string | undefined>>;
|
|
63
68
|
}
|
|
64
69
|
export interface ChangeRecord {
|
|
65
70
|
/** Global monotonic change sequence — orders causes across the app. */
|
|
@@ -81,6 +86,8 @@ export interface ChangeRecord {
|
|
|
81
86
|
export interface RerunEvent {
|
|
82
87
|
/** Global monotonic run sequence. */
|
|
83
88
|
run: number;
|
|
89
|
+
/** When the run started (`performance.now()` clock). */
|
|
90
|
+
at: number;
|
|
84
91
|
/** How many times this node has re-run since attribution was enabled. */
|
|
85
92
|
nodeRuns: number;
|
|
86
93
|
nodeKind: "effect" | "memo";
|
|
@@ -178,14 +185,11 @@ export interface AttributionOptions {
|
|
|
178
185
|
/**
|
|
179
186
|
* Written-fan-out warning: emit a diagnostic when a committed root
|
|
180
187
|
* invalidation (write, refresh, async landing) reaches a node with at
|
|
181
|
-
* least this many subscribers (default 250).
|
|
182
|
-
* HUGE_FAN_OUT graph-size warning,
|
|
183
|
-
*
|
|
184
|
-
*
|
|
185
|
-
*
|
|
186
|
-
* anything when the node actually changes. Once per node, re-warning only
|
|
187
|
-
* on 2x subscriber growth, so the two never spam the same node. `false`
|
|
188
|
-
* disables.
|
|
188
|
+
* least this many subscribers (default 250). The lower-bar, opt-in sibling
|
|
189
|
+
* of the always-on HUGE_FAN_OUT graph-size warning, which fires on the
|
|
190
|
+
* same kind of write from GRAPH_SIZE_WARN_AT (2000) up; this one hands
|
|
191
|
+
* over to it there, so a write never carries both. Once per node,
|
|
192
|
+
* re-warning only on 2x subscriber growth. `false` disables.
|
|
189
193
|
*/
|
|
190
194
|
wideWrites?: number | false;
|
|
191
195
|
/**
|
|
@@ -243,6 +247,19 @@ export interface AttributionOptions {
|
|
|
243
247
|
warnMs: number;
|
|
244
248
|
} | false;
|
|
245
249
|
}
|
|
250
|
+
/**
|
|
251
|
+
* The records the engine delivers, by `subscribe(type, …)` name. Every one is
|
|
252
|
+
* delivered synchronously at the moment it is complete — a re-run when its
|
|
253
|
+
* recompute ends, an interaction / hold / navigation when it settles — so a
|
|
254
|
+
* consumer never polls the ring buffers to learn that something finished.
|
|
255
|
+
*/
|
|
256
|
+
export interface AttributionRecords {
|
|
257
|
+
rerun: RerunEvent;
|
|
258
|
+
interaction: InteractionEvent;
|
|
259
|
+
hold: HoldEvent;
|
|
260
|
+
navigation: NavigationEvent;
|
|
261
|
+
}
|
|
262
|
+
export type AttributionRecordType = keyof AttributionRecords;
|
|
246
263
|
export interface ScopeCost {
|
|
247
264
|
name: string;
|
|
248
265
|
kind: "effect" | "memo";
|
|
@@ -266,20 +283,21 @@ export interface WriteCost {
|
|
|
266
283
|
/** Summed self-time of every downstream re-run it caused. */
|
|
267
284
|
downstreamMs: number;
|
|
268
285
|
}
|
|
269
|
-
/**
|
|
270
|
-
* Run `fn` as the handler of a user interaction: every root write it performs
|
|
271
|
-
* (and every action step or effect the write causes) carries the interaction
|
|
272
|
-
* as provenance. The web runtime wraps event dispatch in this; it is dev-only
|
|
273
|
-
* and safe to call with no engine enabled.
|
|
274
|
-
*/
|
|
275
|
-
export declare function withInteraction<T>(ref: InteractionRef, fn: () => T): T;
|
|
276
|
-
/** `click on button#next "Next →"`, `effect "syncTitle"`, `action "save"`, … */
|
|
286
|
+
/** `click on button#next "Next →"`, `effect "syncTitle"`, `action "save"`, `navigation to /users/:id`, … */
|
|
277
287
|
export declare function formatOrigin(origin: ChangeOrigin): string;
|
|
278
288
|
export declare function formatRerun(event: RerunEvent): string;
|
|
279
289
|
export interface Attribution {
|
|
280
290
|
enable(opts?: AttributionOptions): void;
|
|
281
291
|
disable(): void;
|
|
292
|
+
/**
|
|
293
|
+
* Deliver records as they complete — see `AttributionRecords`. The bare
|
|
294
|
+
* form is `subscribe("rerun", …)`. Records are the same objects the ring
|
|
295
|
+
* buffers hold (`history()`, `interactions()`, `holds()`, `navigations()`),
|
|
296
|
+
* delivered synchronously from the engine, so a listener must not write
|
|
297
|
+
* signals. All subscriptions are dropped by `disable()`.
|
|
298
|
+
*/
|
|
282
299
|
subscribe(listener: (event: RerunEvent) => void): () => void;
|
|
300
|
+
subscribe<K extends AttributionRecordType>(type: K, listener: (record: AttributionRecords[K]) => void): () => void;
|
|
283
301
|
history(): readonly RerunEvent[];
|
|
284
302
|
/** Re-run history for one node — pass a memo/effect accessor or raw node. */
|
|
285
303
|
why(target: unknown): RerunEvent[];
|
|
@@ -308,6 +326,26 @@ export interface Attribution {
|
|
|
308
326
|
* the thresholded, unacknowledged subset.
|
|
309
327
|
*/
|
|
310
328
|
holds(): readonly HoldEvent[];
|
|
329
|
+
/**
|
|
330
|
+
* Every navigation a router declared via `withOrigin` since enable()
|
|
331
|
+
* (ring-buffered like history()), settled or not: what route, under which
|
|
332
|
+
* interaction, how many writes, and — once its writes are through — how
|
|
333
|
+
* long that took and how (`committed` in a plain drain, `held` behind
|
|
334
|
+
* route data with the HoldEvent attached, or `superseded` by a later
|
|
335
|
+
* navigation before it landed). Facts for any consumer that wants
|
|
336
|
+
* navigation spans named by route: no router integration needed.
|
|
337
|
+
*/
|
|
338
|
+
navigations(): readonly NavigationEvent[];
|
|
339
|
+
/**
|
|
340
|
+
* Every user interaction a runtime declared via `withInteraction` since
|
|
341
|
+
* enable() (ring-buffered like history()), settled or not: what was
|
|
342
|
+
* dispatched, when, what it wrote, the re-runs and creations it caused,
|
|
343
|
+
* the holds its writes waited in and the navigations it performed — and,
|
|
344
|
+
* once all of that is through, how long the person waited (`settledMs`)
|
|
345
|
+
* and how it ended (`idle` / `committed` / `held`). The per-dispatch
|
|
346
|
+
* record `feedback().interactions` folds by name.
|
|
347
|
+
*/
|
|
348
|
+
interactions(): readonly InteractionEvent[];
|
|
311
349
|
/**
|
|
312
350
|
* What the user waited on, folded from holds() and the interaction on each
|
|
313
351
|
* re-run: `sources` ranks async sources by the silent time writes spent
|
|
@@ -315,10 +353,12 @@ export interface Attribution {
|
|
|
315
353
|
* interactions were held); `interactions` ranks user events by the total
|
|
316
354
|
* time they cost — re-run work caused (long-flush hazard) beside time held
|
|
317
355
|
* (silent-hold hazard). Facts at every duration; SILENT_HOLD is the
|
|
318
|
-
* thresholded verdict.
|
|
319
|
-
*
|
|
320
|
-
*
|
|
321
|
-
*
|
|
356
|
+
* thresholded verdict. Three more tables round out the picture:
|
|
357
|
+
* `navigations` ranks routes by the time spent held navigating to them
|
|
358
|
+
* (folded from navigations()), `flights` counts each async source's
|
|
359
|
+
* flights and how many were abandoned before landing (the re-ask storm),
|
|
360
|
+
* and `fallbacks` measures how long each loading boundary showed its
|
|
361
|
+
* fallback and how often that was a flash.
|
|
322
362
|
*/
|
|
323
363
|
feedback(): AttributionFeedbackTables;
|
|
324
364
|
/**
|
|
@@ -330,16 +370,9 @@ export interface Attribution {
|
|
|
330
370
|
* is then judged against the real start — work already in the air when its
|
|
331
371
|
* upstream landed is parallel, never a waterfall link. Callable while
|
|
332
372
|
* attribution is disabled (marks made at navigation time must survive a
|
|
333
|
-
* later enable()).
|
|
373
|
+
* later enable()).
|
|
334
374
|
*/
|
|
335
375
|
markFlight(flight: object, startedAt?: number): void;
|
|
336
|
-
/**
|
|
337
|
-
* Run `fn` as a user interaction's handler: root writes inside stamp it as
|
|
338
|
-
* their origin, and actions/effects/flights it causes carry it. The web
|
|
339
|
-
* runtime wraps every event dispatch in this; custom renderers and test
|
|
340
|
-
* harnesses call it themselves. Callable while attribution is disabled.
|
|
341
|
-
*/
|
|
342
|
-
withInteraction: typeof withInteraction;
|
|
343
376
|
format: typeof formatRerun;
|
|
344
377
|
formatOrigin: typeof formatOrigin;
|
|
345
378
|
}
|
|
@@ -362,10 +395,13 @@ export interface HeldWrite {
|
|
|
362
395
|
}
|
|
363
396
|
export interface HoldEvent {
|
|
364
397
|
/**
|
|
365
|
-
*
|
|
366
|
-
* writes when one is known (`interaction.at`) or the
|
|
367
|
-
* parked them, whichever is earlier
|
|
398
|
+
* When the wait began (`performance.now()` clock): the interaction that
|
|
399
|
+
* performed the held writes when one is known (`interaction.at`) or the
|
|
400
|
+
* first flush that parked them, whichever is earlier. `at + holdMs` is the
|
|
401
|
+
* commit.
|
|
368
402
|
*/
|
|
403
|
+
at: number;
|
|
404
|
+
/** Wall time the user waited: `at` to the commit. */
|
|
369
405
|
holdMs: number;
|
|
370
406
|
/**
|
|
371
407
|
* The quiescent tail: from the LAST held write to join (the user's final
|
|
@@ -375,6 +411,13 @@ export interface HoldEvent {
|
|
|
375
411
|
tailMs: number;
|
|
376
412
|
/** The user interaction whose writes were held, when the stamp is known. */
|
|
377
413
|
interaction?: ChangeOrigin;
|
|
414
|
+
/**
|
|
415
|
+
* The declared unit of work the held writes belong to — the `navigation`
|
|
416
|
+
* a router described via `withOrigin` — when one is known. What names the
|
|
417
|
+
* hold by route (`navigation to /users/:id`) rather than by signal; the
|
|
418
|
+
* same object as `navigations()[].origin`, so the two join by identity.
|
|
419
|
+
*/
|
|
420
|
+
origin?: ChangeOrigin;
|
|
378
421
|
/** Flushes that ended with the hold still open. */
|
|
379
422
|
flushes: number;
|
|
380
423
|
/** Root signal writes staged behind the hold (the user's unanswered input). */
|
|
@@ -382,11 +425,12 @@ export interface HoldEvent {
|
|
|
382
425
|
/** Async nodes the hold waited on (union across its parked flushes). */
|
|
383
426
|
blockers: string[];
|
|
384
427
|
/**
|
|
385
|
-
* Feedback the graph provably rendered for this hold
|
|
386
|
-
*
|
|
387
|
-
*
|
|
428
|
+
* Feedback the graph provably rendered for this hold — an `isPending()`
|
|
429
|
+
* reader, a `latest()` shadow, an optimistic value, an `affects()` mark —
|
|
430
|
+
* one entry per affordance, in the order found. Empty and
|
|
431
|
+
* `paintedDuringHold === 0` is the SILENT_HOLD signature.
|
|
388
432
|
*/
|
|
389
|
-
|
|
433
|
+
acknowledgements: Acknowledgement[];
|
|
390
434
|
/**
|
|
391
435
|
* Effect callbacks that ran inside the hold's parked flushes. Mainline
|
|
392
436
|
* effects are stashed while a hold is open, so these are lane effects —
|
|
@@ -398,6 +442,93 @@ export interface HoldEvent {
|
|
|
398
442
|
/** The hold was opened (or joined) by an `action()`. */
|
|
399
443
|
action: boolean;
|
|
400
444
|
}
|
|
445
|
+
/**
|
|
446
|
+
* One way the screen acknowledged a hold. `reader` is where it was painted —
|
|
447
|
+
* the owner path of the first effect the census found reading the
|
|
448
|
+
* affordance (`["<App>", "<Feed>", "effect"]`), so a consumer can say WHICH
|
|
449
|
+
* screen answered, not only that one did. Absent when the affordance was
|
|
450
|
+
* registered but the census found no reader through the graph (an optimistic
|
|
451
|
+
* store: its readers are proxy traps, not nodes). `feedback()` ranks
|
|
452
|
+
* acknowledgements by `kind:source` (`isPending:posts`).
|
|
453
|
+
*/
|
|
454
|
+
export interface Acknowledgement {
|
|
455
|
+
kind: "isPending" | "latest" | "optimistic" | "affects";
|
|
456
|
+
/** The node the affordance hangs on — the async source for `isPending`/`latest`, the optimistic/affected node otherwise. */
|
|
457
|
+
source: string;
|
|
458
|
+
reader?: string[];
|
|
459
|
+
}
|
|
460
|
+
/** A destination a navigation abandoned when a redirect sent it elsewhere. */
|
|
461
|
+
export interface NavigationHop {
|
|
462
|
+
name?: string;
|
|
463
|
+
to?: string;
|
|
464
|
+
params?: Readonly<Record<string, string | undefined>>;
|
|
465
|
+
/** When the redirect away from it was declared (`performance.now()` clock). */
|
|
466
|
+
at: number;
|
|
467
|
+
}
|
|
468
|
+
export interface NavigationEvent {
|
|
469
|
+
/** The matched route pattern the router gave — `/users/:id`. After a redirect, the final one. */
|
|
470
|
+
name?: string;
|
|
471
|
+
to?: string;
|
|
472
|
+
from?: string;
|
|
473
|
+
params?: Readonly<Record<string, string | undefined>>;
|
|
474
|
+
/** When the navigation was requested (`performance.now()` clock). */
|
|
475
|
+
at: number;
|
|
476
|
+
/** The user interaction it ran under, when known — a link click. */
|
|
477
|
+
interaction?: ChangeOrigin;
|
|
478
|
+
/** Root writes the frame performed, redirect hops included. */
|
|
479
|
+
writes: number;
|
|
480
|
+
/** Destinations abandoned along the way, in order — present only when a redirect occurred. */
|
|
481
|
+
redirects?: NavigationHop[];
|
|
482
|
+
/**
|
|
483
|
+
* Wall time from the request to settle: the end of the drain that committed
|
|
484
|
+
* its writes, or the commit of the hold they waited in. `undefined` while
|
|
485
|
+
* unsettled.
|
|
486
|
+
*/
|
|
487
|
+
settledMs?: number;
|
|
488
|
+
outcome?: "committed" | "held" | "superseded";
|
|
489
|
+
/** The hold its writes waited in, when hold tracking recorded one. */
|
|
490
|
+
hold?: HoldEvent;
|
|
491
|
+
/**
|
|
492
|
+
* The frame object its writes were stamped with — `ChangeRecord.origin` on
|
|
493
|
+
* each, `HoldEvent.origin` on the hold. Join key, by identity.
|
|
494
|
+
*/
|
|
495
|
+
origin: ChangeOrigin;
|
|
496
|
+
}
|
|
497
|
+
export interface InteractionEvent {
|
|
498
|
+
/** Event type — `click`, `keydown`, `input`… */
|
|
499
|
+
name: string;
|
|
500
|
+
/** The element hit, as the runtime described it — `button#next "Next →"`. */
|
|
501
|
+
target?: string;
|
|
502
|
+
/** Dispatch time (`performance.now()` clock). */
|
|
503
|
+
at: number;
|
|
504
|
+
/** Wall time of the handler itself, dispatch to return. */
|
|
505
|
+
handlerMs: number;
|
|
506
|
+
/** Root writes attributed to the frame: the handler's, and those of frames it opened (a navigation). */
|
|
507
|
+
writes: number;
|
|
508
|
+
/** Re-runs traced back to this interaction while the record was open. */
|
|
509
|
+
runs: number;
|
|
510
|
+
/** Computations created in those runs or in the frame's flushes (the "create 1,000 rows" work). */
|
|
511
|
+
created: number;
|
|
512
|
+
/** Summed self-time of `runs` and `created` (ms). Quantized per run; `settledMs` is the wall clock. */
|
|
513
|
+
runMs: number;
|
|
514
|
+
/** Holds its writes waited in, in settle order. */
|
|
515
|
+
holds: HoldEvent[];
|
|
516
|
+
/** Navigations performed under it, in open order. */
|
|
517
|
+
navigations: NavigationEvent[];
|
|
518
|
+
/**
|
|
519
|
+
* Dispatch to settle: the handler's return when it wrote nothing, the end of
|
|
520
|
+
* the drain that committed its writes, or the commit of the last hold they
|
|
521
|
+
* waited in — whichever came last. `undefined` while unsettled.
|
|
522
|
+
*/
|
|
523
|
+
settledMs?: number;
|
|
524
|
+
outcome?: "idle" | "committed" | "held";
|
|
525
|
+
/**
|
|
526
|
+
* The frame object every downstream fact carries — `ChangeOrigin.interaction`
|
|
527
|
+
* on writes and frames, `RerunEvent.interaction`, `HoldEvent.interaction`,
|
|
528
|
+
* `NavigationEvent.interaction`. Join key, by identity.
|
|
529
|
+
*/
|
|
530
|
+
origin: ChangeOrigin;
|
|
531
|
+
}
|
|
401
532
|
export interface FeedbackSource {
|
|
402
533
|
/** The async nodes the holds waited on; empty when an action alone kept them open. */
|
|
403
534
|
sources: string[];
|
|
@@ -484,9 +615,33 @@ export interface FallbackStats {
|
|
|
484
615
|
*/
|
|
485
616
|
flashes: number;
|
|
486
617
|
}
|
|
618
|
+
/**
|
|
619
|
+
* Per route: what navigating to it cost, folded from settled
|
|
620
|
+
* `NavigationEvent`s — the route-level view a router integration used to
|
|
621
|
+
* have to build itself, from the runtime's own facts.
|
|
622
|
+
*/
|
|
623
|
+
export interface FeedbackNavigation {
|
|
624
|
+
/** The route pattern (`/users/:id`), or the concrete `to` when the router gave no pattern. */
|
|
625
|
+
name: string;
|
|
626
|
+
navigations: number;
|
|
627
|
+
/** Summed and worst request-to-settle time (ms) across settled navigations. */
|
|
628
|
+
settledMs: number;
|
|
629
|
+
worstMs: number;
|
|
630
|
+
/** Navigations whose writes waited in a hold, and the time they waited. */
|
|
631
|
+
held: number;
|
|
632
|
+
heldMs: number;
|
|
633
|
+
/** Held navigations the screen acknowledged nothing for — the SILENT_HOLD signature. */
|
|
634
|
+
silent: number;
|
|
635
|
+
/** Navigations overwritten by a later one before they landed. */
|
|
636
|
+
superseded: number;
|
|
637
|
+
/** Navigations a redirect sent elsewhere on the way (keyed by where they ended up). */
|
|
638
|
+
redirected: number;
|
|
639
|
+
}
|
|
487
640
|
export interface AttributionFeedbackTables {
|
|
488
641
|
sources: FeedbackSource[];
|
|
489
642
|
interactions: FeedbackInteraction[];
|
|
643
|
+
/** Routes ranked by the time spent held navigating to them, then by total settle time. */
|
|
644
|
+
navigations: FeedbackNavigation[];
|
|
490
645
|
/** Async sources ranked by abandoned flights, then by flights. */
|
|
491
646
|
flights: FlightStats[];
|
|
492
647
|
/** Loading boundaries ranked by flashes, then by time shown. */
|
|
@@ -113,6 +113,26 @@ export declare const CONFIG_HELD_TRUTH: number;
|
|
|
113
113
|
* unobserved closure, NodeExtension) were the measured create-floor bytes
|
|
114
114
|
* (warm dbmon profile: store node machinery ~36% + GC ~29%). */
|
|
115
115
|
export declare const CONFIG_SLOT_NODE: number;
|
|
116
|
+
/** Optimistic node whose own source arrived with a value DIFFERENT from its
|
|
117
|
+
* active override (A18 supersession, #3331). The override survives only as
|
|
118
|
+
* the displayed value — untracked reads and the applied frame keep it until
|
|
119
|
+
* the owning transaction commits — while the graph has already moved to the
|
|
120
|
+
* staged truth in `_pendingValue`: tracked readers see it and the corrected
|
|
121
|
+
* cascade is that transaction's held work. Set by the two own-source write
|
|
122
|
+
* paths (asyncWrite, transition-held recompute); cleared by a fresh optimistic
|
|
123
|
+
* write (a new override re-masks) and by the revert. */
|
|
124
|
+
export declare const CONFIG_OVERRIDE_SUPERSEDED: number;
|
|
125
|
+
/** In-flight async node whose inputs were PUBLISHED while it was pending: a
|
|
126
|
+
* batch or transaction committed with the node still `STATUS_PENDING` (an
|
|
127
|
+
* unobserved flight, #3305), so the inputs are on screen and the node's
|
|
128
|
+
* committed `_value` is stale against them. Governs read()'s reveal
|
|
129
|
+
* carve-out: a stale (render) reader in some OTHER transaction may show a
|
|
130
|
+
* foreign-held pending node's committed value — parallel transactions, no
|
|
131
|
+
* entanglement — only while that value is coherent with the visible frame,
|
|
132
|
+
* i.e. while the flight's inputs are themselves held (unpublished) and not
|
|
133
|
+
* lane-revealed. Set by `commitPendingNodes`; cleared when the node next
|
|
134
|
+
* enters pending fresh (a new flight from a settled state). */
|
|
135
|
+
export declare const CONFIG_INPUTS_PUBLISHED: number;
|
|
116
136
|
export declare const STATUS_NONE = 0;
|
|
117
137
|
export declare const STATUS_PENDING: number;
|
|
118
138
|
export declare const STATUS_ERROR: number;
|
|
@@ -121,6 +141,9 @@ export declare const EFFECT_PURE = 0;
|
|
|
121
141
|
export declare const EFFECT_RENDER = 1;
|
|
122
142
|
export declare const EFFECT_USER = 2;
|
|
123
143
|
export declare const EFFECT_TRACKED = 3;
|
|
144
|
+
/** OR-ed into the `type` a lane passes to its effect runners: lane runs
|
|
145
|
+
* apply ahead of their transaction and are exempt from ownership parking. */
|
|
146
|
+
export declare const LANE_RUN = 4;
|
|
124
147
|
export declare const NOT_PENDING: {};
|
|
125
148
|
export declare const NO_SNAPSHOT: {};
|
|
126
149
|
/**
|
|
@@ -60,6 +60,13 @@ export declare function signal<T>(v: T, options?: NodeOptions<T>, firewall?: Com
|
|
|
60
60
|
export declare let slotUnobservedHook: (node: Signal<any>) => void;
|
|
61
61
|
/** Install the shared slot-node unobserved handler (store module, once). */
|
|
62
62
|
export declare function setSlotUnobserved(fn: (node: Signal<any>) => void): void;
|
|
63
|
+
/** Release a firewall child the store no longer addresses (unobserved sweep
|
|
64
|
+
* dropped it from its target's cache): unlink it from the chain so the
|
|
65
|
+
* projection stops retaining it and its last value. The node keeps its own
|
|
66
|
+
* `_nextChild` so a walk that is mid-chain on it still terminates. Nodes in
|
|
67
|
+
* `_companionChildren` stay there — companions are permanent by contract
|
|
68
|
+
* and snap through that set, not the chain. */
|
|
69
|
+
export declare function unlinkFirewallChild(node: Signal<any>): void;
|
|
63
70
|
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
71
|
export declare function optimisticSignal<T>(v: T, options?: NodeOptions<T>): Signal<T>;
|
|
65
72
|
export declare function optimisticComputed<T>(fn: (prev?: T) => T | PromiseLike<T> | AsyncIterable<T>, options?: NodeOptions<T>): Computed<T>;
|
package/dist/types/core/dev.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { type
|
|
2
|
-
import type { Computed,
|
|
1
|
+
import { type AttributionHooks, type InteractionRef, type OriginRef } from "./attribution-hooks.js";
|
|
2
|
+
import type { Computed, Owner, Signal } from "./types.js";
|
|
3
3
|
export interface DevHooks {
|
|
4
4
|
onOwner?: (owner: Owner) => void;
|
|
5
5
|
onGraph?: (value: any, owner: Owner | null) => void;
|
|
@@ -17,9 +17,9 @@ export type DiagnosticCode = "STRICT_READ_UNTRACKED" | "PENDING_ASYNC_UNTRACKED_
|
|
|
17
17
|
export type DiagnosticKind = "strict-read" | "async" | "write" | "lifecycle" | "owner" | "error" | "perf" | "graph"
|
|
18
18
|
/** Perceived responsiveness: the runtime behaved correctly but the user saw no feedback. */
|
|
19
19
|
| "responsiveness";
|
|
20
|
-
/** First warning when a
|
|
20
|
+
/** First warning when a change reaches (or a pass tracks) this many edges. */
|
|
21
21
|
export declare const GRAPH_SIZE_WARN_AT = 2000;
|
|
22
|
-
/**
|
|
22
|
+
/** Re-warn once the count has grown by this much since the last warning. */
|
|
23
23
|
export declare const GRAPH_SIZE_WARN_EVERY = 500;
|
|
24
24
|
export interface DiagnosticEvent {
|
|
25
25
|
sequence: number;
|
|
@@ -51,27 +51,109 @@ export interface Diagnostics {
|
|
|
51
51
|
subscribe(listener: DiagnosticListener): () => void;
|
|
52
52
|
capture(): DiagnosticCapture;
|
|
53
53
|
/**
|
|
54
|
-
*
|
|
55
|
-
*
|
|
56
|
-
*
|
|
57
|
-
*
|
|
58
|
-
*
|
|
59
|
-
* for an event suppresses the footer. Passing undefined unregisters and
|
|
60
|
-
* resets the once-per-code memory.
|
|
54
|
+
* Records an event on the channel from outside the reactive core — a host
|
|
55
|
+
* runtime reporting its own findings (hydration mismatches, server render
|
|
56
|
+
* faults) so consumers see one stream. `subject` locates it like the
|
|
57
|
+
* internal sites do; a host whose owners are not signals' owners passes
|
|
58
|
+
* `ownerPath` on the event instead and it is used as-is.
|
|
61
59
|
*/
|
|
62
|
-
|
|
60
|
+
emit(event: Omit<DiagnosticEvent, "sequence">, subject?: DiagnosticSubject | null): DiagnosticEvent;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* The core's side of attribution: the hook slot an engine installs into, and
|
|
64
|
+
* the interaction frame the rendering runtime opens around event dispatch.
|
|
65
|
+
* The engine itself — "why did this run", costs, holds, feedback — is
|
|
66
|
+
* `@solidjs/signals/attribution`, a separate entry so an observe build pays
|
|
67
|
+
* for it only when something imports it.
|
|
68
|
+
*/
|
|
69
|
+
export interface AttributionSlot {
|
|
70
|
+
/**
|
|
71
|
+
* Installs `hooks` as the engine the core reports facts to (`null`
|
|
72
|
+
* uninstalls). One engine at a time; the built-in engine's `enable()` calls
|
|
73
|
+
* this, and an external consumer (devtools) may install its own instead.
|
|
74
|
+
*/
|
|
75
|
+
install(hooks: AttributionHooks | null): void;
|
|
76
|
+
/** The installed engine's hooks, or `null` when none is installed. */
|
|
77
|
+
readonly installed: AttributionHooks | null;
|
|
78
|
+
/**
|
|
79
|
+
* Run `fn` as a user interaction's handler: root writes inside stamp it as
|
|
80
|
+
* their origin, and actions/effects/flights it causes carry it. The web
|
|
81
|
+
* runtime wraps every event dispatch in this; custom renderers and test
|
|
82
|
+
* harnesses call it themselves. `fn()` when no engine is installed.
|
|
83
|
+
*/
|
|
84
|
+
withInteraction<T>(ref: InteractionRef, fn: () => T): T;
|
|
85
|
+
/**
|
|
86
|
+
* Run `fn` as a declared unit of work — a router's navigation, described
|
|
87
|
+
* by the parametrized route it matched: root writes inside are attributed
|
|
88
|
+
* to it (under the enclosing interaction, if any), so the hold behind the
|
|
89
|
+
* route's data, the re-runs and the verdicts carry the route's name. Any
|
|
90
|
+
* router calls this around its location write; nothing else is
|
|
91
|
+
* router-specific. `fn()` when no engine is installed.
|
|
92
|
+
*/
|
|
93
|
+
withOrigin<T>(ref: OriginRef, fn: () => T): T;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* The observe tier: the structured channel and the attribution wiring —
|
|
97
|
+
* everything a production observability consumer needs, and nothing that
|
|
98
|
+
* assumes a developer at a console. Present in dev and observe builds
|
|
99
|
+
* (`__OBSERVE__`); `undefined` in prod.
|
|
100
|
+
*/
|
|
101
|
+
export interface Observe {
|
|
102
|
+
diagnostics: Diagnostics;
|
|
103
|
+
/** The attribution hook slot and interaction frame — see `AttributionSlot`. */
|
|
104
|
+
attribution: AttributionSlot;
|
|
105
|
+
/**
|
|
106
|
+
* The live node an emitted event was about, when the emitter knew it.
|
|
107
|
+
* Events are serializable records and never carry the node; consumers that
|
|
108
|
+
* run in-process (devtools, the console reporter) look it up here.
|
|
109
|
+
*/
|
|
110
|
+
subjectOf(event: DiagnosticEvent): DiagnosticSubject | undefined;
|
|
111
|
+
/**
|
|
112
|
+
* Marks `owner`'s subtree as the observer's own. A consumer that renders
|
|
113
|
+
* inside the app it watches — an APM adapter's panel, devtools — would
|
|
114
|
+
* otherwise see its own effects, stores and holds reported as findings about
|
|
115
|
+
* the app. Under an excluded owner: diagnostics whose subject sits in the
|
|
116
|
+
* subtree are neither delivered nor reported (the entry is still built, so
|
|
117
|
+
* a site that throws its message still throws), and the attribution engine
|
|
118
|
+
* records no runs for its computations. Mark the root as it is created
|
|
119
|
+
* (`createRoot(() => { OBSERVE.exclude(getOwner()!); … })`) and perform
|
|
120
|
+
* writes from outside the graph under it (`runWithOwner`), so the writer's
|
|
121
|
+
* context is excluded too. Irrevocable for the owner's lifetime.
|
|
122
|
+
*/
|
|
123
|
+
exclude(owner: Owner): void;
|
|
124
|
+
/** Whether `subject` sits under an excluded owner (itself included). */
|
|
125
|
+
isExcluded(subject: DiagnosticSubject | null | undefined): boolean;
|
|
63
126
|
}
|
|
127
|
+
/**
|
|
128
|
+
* The dev tier: devtools hooks, graph traversal, and the console face of the
|
|
129
|
+
* diagnostics channel. Present only in dev builds (`__DEV__`).
|
|
130
|
+
*/
|
|
64
131
|
export interface Dev {
|
|
65
132
|
hooks: DevHooks;
|
|
66
|
-
diagnostics: Diagnostics;
|
|
67
|
-
/** "Why did this run" re-run attribution — see attribution.ts. */
|
|
68
|
-
attribution: Attribution;
|
|
69
133
|
getChildren: typeof getChildren;
|
|
70
134
|
getSignals: typeof getSignals;
|
|
71
135
|
getParent: typeof getParent;
|
|
72
136
|
getSources: typeof getSources;
|
|
73
137
|
getObservers: typeof getObservers;
|
|
138
|
+
/** Console face of an emitted event — see `reportDiagnostic`. */
|
|
139
|
+
report(entry: DiagnosticEvent): void;
|
|
140
|
+
/**
|
|
141
|
+
* Registers a console footer appended to the first console report of
|
|
142
|
+
* each diagnostic code — a discovery pointer to deeper guidance (e.g.
|
|
143
|
+
* solid-js registers its shipped repair skill). Reported events carry
|
|
144
|
+
* it as trailing lines of the same console entry; events that surface as
|
|
145
|
+
* a thrown error instead get it as a follow-up line. Returning undefined
|
|
146
|
+
* for an event suppresses the footer. Passing undefined unregisters and
|
|
147
|
+
* resets the once-per-code memory.
|
|
148
|
+
*/
|
|
149
|
+
setConsoleFooter(footer: ((event: DiagnosticEvent) => string | undefined) | undefined): void;
|
|
74
150
|
}
|
|
151
|
+
export declare const OBSERVE: Observe;
|
|
152
|
+
export declare function isExcluded(subject: DiagnosticSubject | null | undefined): boolean;
|
|
153
|
+
/** For engines that cache the verdict per node: is anything excluded at all? */
|
|
154
|
+
export declare function anyExcluded(): boolean;
|
|
155
|
+
/** Was `entry` built for an excluded subject? Once-per-key reporters must not spend their slot on it. */
|
|
156
|
+
export declare function isSuppressed(entry: DiagnosticEvent): boolean;
|
|
75
157
|
export declare const DEV: Dev;
|
|
76
158
|
/**
|
|
77
159
|
* Dev-mode internal consistency check. A failure means the reactive system
|
|
@@ -96,9 +178,11 @@ export declare function ownerPath(subject: DiagnosticSubject | null | undefined)
|
|
|
96
178
|
* default (right for the synchronous rule checks — they fire inside the
|
|
97
179
|
* scope that misbehaved); pass the node for scheduler-time findings whose
|
|
98
180
|
* ambient context is the flush, or `null` for events that have no location
|
|
99
|
-
* by nature.
|
|
181
|
+
* by nature. An `ownerPath` already on the event wins over the subject walk
|
|
182
|
+
* (hosts whose owners are not signals' owners compute their own). Console
|
|
183
|
+
* output is a separate, dev-tier step — see `reportDiagnostic`.
|
|
100
184
|
*/
|
|
101
|
-
export declare function emitDiagnostic(event: Omit<DiagnosticEvent, "sequence"
|
|
185
|
+
export declare function emitDiagnostic(event: Omit<DiagnosticEvent, "sequence">, subject?: DiagnosticSubject | null | undefined): DiagnosticEvent;
|
|
102
186
|
/**
|
|
103
187
|
* The console face of a diagnostic — ONE entry per finding: the message, the
|
|
104
188
|
* owner path (`in <App> › <TodoRow> › effect`) so a human can locate it, the
|
|
@@ -107,7 +191,9 @@ export declare function emitDiagnostic(event: Omit<DiagnosticEvent, "sequence" |
|
|
|
107
191
|
* second console argument (hover highlights it, click jumps to Elements).
|
|
108
192
|
* Severity picks the console method. Call sites report the entry
|
|
109
193
|
* `emitDiagnostic` returned so the structured and console channels never
|
|
110
|
-
* disagree.
|
|
194
|
+
* disagree. Dev-tier: in an observe build this is a no-op, so wiring paths
|
|
195
|
+
* that both emit and report (graph-size warnings) reach the channel only —
|
|
196
|
+
* production observability never writes to the console.
|
|
111
197
|
*/
|
|
112
198
|
export declare function reportDiagnostic(entry: DiagnosticEvent): void;
|
|
113
199
|
/**
|
|
@@ -117,6 +203,11 @@ export declare function reportDiagnostic(entry: DiagnosticEvent): void;
|
|
|
117
203
|
*/
|
|
118
204
|
export declare function throwPendingUntrackedRead(strictReadLabel: string, fields?: Partial<Omit<DiagnosticEvent, "sequence" | "data" | "ownerPath">>): never;
|
|
119
205
|
export declare function warnStrictReadUntracked(strictReadLabel: string, fields?: Partial<Omit<DiagnosticEvent, "sequence" | "ownerPath">>): void;
|
|
206
|
+
/**
|
|
207
|
+
* Observe-tier: stamp a signal with its creating owner so `ownerPath` can
|
|
208
|
+
* locate signal subjects. The per-owner `_signals` list and the devtools
|
|
209
|
+
* `onGraph` hook are dev-tier — the observe build pays one property write.
|
|
210
|
+
*/
|
|
120
211
|
export declare function registerGraph(value: any, owner: Owner | null): void;
|
|
121
212
|
export declare function clearSignals(node: Owner): void;
|
|
122
213
|
export declare function getChildren(owner: Owner): Owner[];
|
|
@@ -125,12 +216,19 @@ export declare function getParent(owner: Owner): Owner | null;
|
|
|
125
216
|
export declare function getSources(computation: Computed<any>): (Signal<any> | Computed<any>)[];
|
|
126
217
|
export declare function getObservers(node: Signal<any> | Computed<any>): Computed<any>[];
|
|
127
218
|
/**
|
|
128
|
-
*
|
|
129
|
-
*
|
|
130
|
-
* fan-
|
|
131
|
-
*
|
|
132
|
-
*
|
|
219
|
+
* Observe-tier: a committed change on `node` is about to re-run `count`
|
|
220
|
+
* subscribers (the notify walk in `insertSubs` counted them as it went —
|
|
221
|
+
* fan-out costs exactly one local increment in a loop that already visits
|
|
222
|
+
* every edge, and nothing at link time). Fires from GRAPH_SIZE_WARN_AT up,
|
|
223
|
+
* on the write rather than the link: a fan-out that is never written costs
|
|
224
|
+
* nothing, and one that is re-runs every subscriber this flush. Always-on
|
|
225
|
+
* wherever the channel exists — unlike the opt-in attribution engine, a
|
|
226
|
+
* graph-size pathology should surface without asking.
|
|
227
|
+
*/
|
|
228
|
+
export declare function noteFanOut(node: Signal<any> | Computed<any>, count: number): void;
|
|
229
|
+
/**
|
|
230
|
+
* Observe-tier: a recompute pass of `node` tracked `count` distinct sources
|
|
231
|
+
* (its trimmed dep list, walked once at the end of the pass — see recompute;
|
|
232
|
+
* no per-link work, no pass bracket). Fires from GRAPH_SIZE_WARN_AT up.
|
|
133
233
|
*/
|
|
134
|
-
export declare function
|
|
135
|
-
/** DEV-only: drop live edge counts when a link is removed. */
|
|
136
|
-
export declare function unnoteGraphLink(link: Link): void;
|
|
234
|
+
export declare function noteFanIn(node: Computed<any>, count: number): void;
|