@solidjs/signals 2.0.0-rc.8 → 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 +1399 -285
- package/dist/dev.attribution.js +459 -307
- package/dist/dev.js +1864 -435
- package/dist/observe/affects.js +3 -1
- package/dist/observe/attribution.js +7 -1
- package/dist/observe/boundaries.js +209 -154
- package/dist/observe/core/action.js +18 -8
- package/dist/observe/core/async.js +220 -110
- 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 +23 -1
- package/dist/observe/core/attribution-queries.js +28 -0
- package/dist/observe/core/attribution.js +262 -485
- package/dist/observe/core/constants.js +34 -1
- package/dist/observe/core/context.js +3 -3
- package/dist/observe/core/core.js +867 -367
- package/dist/observe/core/dev.js +78 -17
- package/dist/observe/core/effect.js +67 -51
- package/dist/observe/core/error-hooks.js +71 -0
- package/dist/observe/core/external.js +4 -4
- package/dist/observe/core/graph.js +37 -37
- package/dist/observe/core/heap.js +45 -45
- package/dist/observe/core/invariants.js +2 -0
- package/dist/observe/core/lanes.js +86 -49
- package/dist/observe/core/optimistic.js +242 -95
- package/dist/observe/core/owner.js +98 -84
- package/dist/observe/core/scheduler.js +543 -305
- package/dist/observe/core/verdict.js +247 -129
- package/dist/observe/index.js +7 -3
- package/dist/observe/map.js +126 -124
- package/dist/observe/signals.js +33 -17
- package/dist/observe/store/index.js +2 -0
- package/dist/observe/store/next/optimistic.js +141 -132
- package/dist/observe/store/next/projection.js +34 -21
- package/dist/observe/store/next/reconcile.js +58 -56
- package/dist/observe/store/next/store.js +260 -146
- package/dist/observe/store/store.js +5 -3
- package/dist/observe/store/utils.js +948 -135
- package/dist/prod/attribution.js +26 -17
- package/dist/prod/boundaries.js +128 -76
- package/dist/prod/core/action.js +16 -8
- package/dist/prod/core/async.js +251 -143
- package/dist/prod/core/constants.js +34 -1
- package/dist/prod/core/context.js +3 -3
- package/dist/prod/core/core.js +843 -347
- package/dist/prod/core/dev.js +17 -1
- package/dist/prod/core/effect.js +48 -34
- 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 +45 -45
- package/dist/prod/core/lanes.js +90 -53
- package/dist/prod/core/optimistic.js +247 -100
- package/dist/prod/core/owner.js +57 -45
- package/dist/prod/core/scheduler.js +543 -305
- package/dist/prod/core/verdict.js +245 -127
- package/dist/prod/index.js +7 -3
- package/dist/prod/map.js +112 -112
- package/dist/prod/signals.js +28 -12
- package/dist/prod/store/next/optimistic.js +135 -128
- package/dist/prod/store/next/projection.js +31 -20
- package/dist/prod/store/next/store.js +325 -252
- package/dist/prod/store/store.js +2 -2
- package/dist/prod/store/utils.js +946 -135
- package/dist/types/attribution.d.ts +7 -2
- package/dist/types/attribution.prod.d.ts +10 -1
- package/dist/types/boundaries.d.ts +10 -1
- package/dist/types/core/action.d.ts +12 -5
- 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 +28 -3
- package/dist/types/core/attribution-queries.d.ts +10 -0
- package/dist/types/core/attribution.d.ts +51 -172
- package/dist/types/core/constants.d.ts +33 -0
- package/dist/types/core/core.d.ts +186 -5
- package/dist/types/core/dev.d.ts +129 -9
- package/dist/types/core/error-hooks.d.ts +71 -0
- package/dist/types/core/index.d.ts +3 -1
- package/dist/types/core/invariants.d.ts +4 -0
- package/dist/types/core/lanes.d.ts +31 -4
- package/dist/types/core/scheduler.d.ts +95 -2
- package/dist/types/core/types.d.ts +3 -0
- package/dist/types/index.d.ts +2 -2
- package/dist/types/signals.d.ts +8 -0
- package/dist/types/store/index.d.ts +2 -1
- package/dist/types/store/next/optimistic.d.ts +1 -1
- package/dist/types/store/next/store.d.ts +6 -5
- package/dist/types/store/next/target.d.ts +1 -1
- package/dist/types/store/utils.d.ts +177 -6
- package/package.json +1 -1
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { registerFold, rootsOf } from "./attribution.js";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* `costs()` — the cost tables: scopes ranked by the self-time they burn,
|
|
5
|
+
* root writes ranked by the downstream re-run time they cause. Folded from
|
|
6
|
+
* every `RerunEvent` as the engine records it.
|
|
7
|
+
*
|
|
8
|
+
* Its own module on purpose: the tables register with the engine's fold seam
|
|
9
|
+
* when this module is evaluated, so an observe-tier consumer that only
|
|
10
|
+
* subscribes to records (an APM adapter) never ships the accumulation or the
|
|
11
|
+
* tables; a consumer that imports `costs` gets both. Reset with the engine on
|
|
12
|
+
* `enable()`/`disable()`.
|
|
13
|
+
*/ const scopeCosts = new Map;
|
|
14
|
+
|
|
15
|
+
const writeCosts = new Map;
|
|
16
|
+
|
|
17
|
+
function recordCosts(s, o) {
|
|
18
|
+
let t = scopeCosts.get(s);
|
|
19
|
+
if (t === undefined) {
|
|
20
|
+
t = {
|
|
21
|
+
name: o.nodeName,
|
|
22
|
+
kind: o.nodeKind,
|
|
23
|
+
runs: 0,
|
|
24
|
+
selfMs: 0,
|
|
25
|
+
wastedMs: 0,
|
|
26
|
+
overlayMs: 0
|
|
27
|
+
};
|
|
28
|
+
scopeCosts.set(s, t);
|
|
29
|
+
}
|
|
30
|
+
t.runs++;
|
|
31
|
+
t.selfMs += o.selfMs;
|
|
32
|
+
if (o.phase !== "plain") t.overlayMs += o.selfMs; else if (!o.changed && !o.held) t.wastedMs += o.selfMs;
|
|
33
|
+
const e = new Set;
|
|
34
|
+
rootsOf(o.causes, e);
|
|
35
|
+
for (const s of e) {
|
|
36
|
+
let t = writeCosts.get(s);
|
|
37
|
+
if (t === undefined) writeCosts.set(s, t = {
|
|
38
|
+
name: s,
|
|
39
|
+
runs: 0,
|
|
40
|
+
downstreamMs: 0
|
|
41
|
+
});
|
|
42
|
+
t.runs++;
|
|
43
|
+
t.downstreamMs += o.selfMs;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
registerFold({
|
|
48
|
+
rerun: recordCosts,
|
|
49
|
+
reset() {
|
|
50
|
+
scopeCosts.clear();
|
|
51
|
+
writeCosts.clear();
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Aggregated cost tables since `enable()`: `scopes` ranked by self-time
|
|
57
|
+
* (with `wastedMs` = time spent on unchanged-value runs), `writes` ranked by
|
|
58
|
+
* total downstream re-run time each root write caused.
|
|
59
|
+
*/ function costs() {
|
|
60
|
+
return {
|
|
61
|
+
scopes: [ ...scopeCosts.values() ].sort((s, o) => o.selfMs - s.selfMs),
|
|
62
|
+
writes: [ ...writeCosts.values() ].sort((s, o) => o.downstreamMs - s.downstreamMs)
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export { costs };
|
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
import { registerFold, now, isSilentHold, isLongHold, formatOrigin, nodeName } from "./attribution.js";
|
|
2
|
+
|
|
3
|
+
import { ownerPath } from "./dev.js";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* `feedback()` — what the user waited on, as ranked tables. Folded from the
|
|
7
|
+
* records the engine already keeps (holds, the interaction on each re-run,
|
|
8
|
+
* navigations) and two censuses the engine reports as they happen (flights
|
|
9
|
+
* started/landed/abandoned per async source; fallback shows per boundary).
|
|
10
|
+
*
|
|
11
|
+
* Its own module on purpose: the tables register with the engine's fold seam
|
|
12
|
+
* when this module is evaluated, so an observe-tier consumer that only
|
|
13
|
+
* subscribes to records never ships them. Reset with the engine on
|
|
14
|
+
* `enable()`/`disable()`.
|
|
15
|
+
*/ const feedbackSources = new Map;
|
|
16
|
+
|
|
17
|
+
const feedbackInteractions = new Map;
|
|
18
|
+
|
|
19
|
+
const feedbackNavigations = new Map;
|
|
20
|
+
|
|
21
|
+
const flightStats = new Map;
|
|
22
|
+
|
|
23
|
+
const fallbackStats = new Map;
|
|
24
|
+
|
|
25
|
+
const FALLBACK_FLASH_MS = 150;
|
|
26
|
+
|
|
27
|
+
function flightBucket(e) {
|
|
28
|
+
let n = flightStats.get(e);
|
|
29
|
+
if (n === undefined) {
|
|
30
|
+
n = {
|
|
31
|
+
source: nodeName(e),
|
|
32
|
+
flights: 0,
|
|
33
|
+
landed: 0,
|
|
34
|
+
abandoned: 0,
|
|
35
|
+
landedMs: 0,
|
|
36
|
+
worstMs: 0
|
|
37
|
+
};
|
|
38
|
+
flightStats.set(e, n);
|
|
39
|
+
}
|
|
40
|
+
return n;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function trackFallback(e, n, t) {
|
|
44
|
+
let i = fallbackStats.get(e);
|
|
45
|
+
if (i === undefined) {
|
|
46
|
+
i = {
|
|
47
|
+
row: {
|
|
48
|
+
boundary: "boundary",
|
|
49
|
+
shows: 0,
|
|
50
|
+
shownMs: 0,
|
|
51
|
+
worstMs: 0,
|
|
52
|
+
flashes: 0
|
|
53
|
+
},
|
|
54
|
+
shownAt: null
|
|
55
|
+
};
|
|
56
|
+
fallbackStats.set(e, i);
|
|
57
|
+
}
|
|
58
|
+
// The first show can fire before the subtree exists; name on first sight.
|
|
59
|
+
if (i.row.boundary === "boundary" && n !== undefined) {
|
|
60
|
+
const e = ownerPath(n);
|
|
61
|
+
if (e !== undefined) i.row.boundary = e.join(" › ");
|
|
62
|
+
}
|
|
63
|
+
if (t) {
|
|
64
|
+
if (i.shownAt === null) {
|
|
65
|
+
i.shownAt = now();
|
|
66
|
+
i.row.shows++;
|
|
67
|
+
}
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
if (i.shownAt === null) return;
|
|
71
|
+
const s = now() - i.shownAt;
|
|
72
|
+
i.shownAt = null;
|
|
73
|
+
i.row.shownMs += s;
|
|
74
|
+
if (s > i.row.worstMs) i.row.worstMs = s;
|
|
75
|
+
if (s < FALLBACK_FLASH_MS) i.row.flashes++;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function interactionBucket(e) {
|
|
79
|
+
const n = formatOrigin(e);
|
|
80
|
+
let t = feedbackInteractions.get(n);
|
|
81
|
+
if (t === undefined) {
|
|
82
|
+
t = {
|
|
83
|
+
row: {
|
|
84
|
+
interaction: n,
|
|
85
|
+
dispatches: 0,
|
|
86
|
+
runs: 0,
|
|
87
|
+
selfMs: 0,
|
|
88
|
+
worstDispatchMs: 0,
|
|
89
|
+
holds: 0,
|
|
90
|
+
heldMs: 0,
|
|
91
|
+
silentMs: 0,
|
|
92
|
+
worstHoldMs: 0
|
|
93
|
+
},
|
|
94
|
+
dispatches: new Map
|
|
95
|
+
};
|
|
96
|
+
feedbackInteractions.set(n, t);
|
|
97
|
+
}
|
|
98
|
+
const i = e.at ?? 0;
|
|
99
|
+
if (!t.dispatches.has(i)) {
|
|
100
|
+
t.dispatches.set(i, 0);
|
|
101
|
+
t.row.dispatches++;
|
|
102
|
+
}
|
|
103
|
+
return t;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function recordFeedbackRun(e) {
|
|
107
|
+
if (e.interaction === undefined) return;
|
|
108
|
+
const n = interactionBucket(e.interaction);
|
|
109
|
+
n.row.runs++;
|
|
110
|
+
n.row.selfMs += e.selfMs;
|
|
111
|
+
const t = e.interaction.at ?? 0;
|
|
112
|
+
const i = n.dispatches.get(t) + e.selfMs;
|
|
113
|
+
n.dispatches.set(t, i);
|
|
114
|
+
if (i > n.row.worstDispatchMs) n.row.worstDispatchMs = i;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function recordFeedbackHold(e) {
|
|
118
|
+
const n = [ ...e.blockers ].sort();
|
|
119
|
+
const t = n.join("\0");
|
|
120
|
+
let i = feedbackSources.get(t);
|
|
121
|
+
if (i === undefined) {
|
|
122
|
+
i = {
|
|
123
|
+
row: {
|
|
124
|
+
sources: n,
|
|
125
|
+
holds: 0,
|
|
126
|
+
heldMs: 0,
|
|
127
|
+
worstMs: 0,
|
|
128
|
+
silent: 0,
|
|
129
|
+
silentMs: 0,
|
|
130
|
+
latestOnly: 0,
|
|
131
|
+
long: 0,
|
|
132
|
+
longMs: 0,
|
|
133
|
+
acknowledgedBy: [],
|
|
134
|
+
interactions: [],
|
|
135
|
+
writes: [],
|
|
136
|
+
actions: 0
|
|
137
|
+
},
|
|
138
|
+
acks: new Map,
|
|
139
|
+
interactions: new Map,
|
|
140
|
+
writes: new Set
|
|
141
|
+
};
|
|
142
|
+
feedbackSources.set(t, i);
|
|
143
|
+
}
|
|
144
|
+
const s = i.row;
|
|
145
|
+
const o = isSilentHold(e);
|
|
146
|
+
s.holds++;
|
|
147
|
+
s.heldMs += e.holdMs;
|
|
148
|
+
if (e.holdMs > s.worstMs) s.worstMs = e.holdMs;
|
|
149
|
+
if (o) {
|
|
150
|
+
s.silent++;
|
|
151
|
+
s.silentMs += e.holdMs;
|
|
152
|
+
} else if (e.acknowledgements.length > 0 && e.acknowledgements.every(e => e.kind === "latest")) s.latestOnly++;
|
|
153
|
+
if (isLongHold(e)) {
|
|
154
|
+
s.long++;
|
|
155
|
+
s.longMs += e.tailMs;
|
|
156
|
+
}
|
|
157
|
+
if (e.action) s.actions++;
|
|
158
|
+
for (const n of e.acknowledgements) {
|
|
159
|
+
const e = `${n.kind}:${n.source}`;
|
|
160
|
+
i.acks.set(e, (i.acks.get(e) ?? 0) + 1);
|
|
161
|
+
}
|
|
162
|
+
for (const n of e.heldWrites) i.writes.add(n.name);
|
|
163
|
+
if (e.interaction !== undefined) {
|
|
164
|
+
const n = formatOrigin(e.interaction);
|
|
165
|
+
i.interactions.set(n, (i.interactions.get(n) ?? 0) + 1);
|
|
166
|
+
const t = interactionBucket(e.interaction);
|
|
167
|
+
t.row.holds++;
|
|
168
|
+
t.row.heldMs += e.holdMs;
|
|
169
|
+
if (o) t.row.silentMs += e.holdMs;
|
|
170
|
+
if (e.holdMs > t.row.worstHoldMs) t.row.worstHoldMs = e.holdMs;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
function recordFeedbackNavigation(e) {
|
|
175
|
+
const n = e.name ?? e.to;
|
|
176
|
+
if (n === undefined) return;
|
|
177
|
+
let t = feedbackNavigations.get(n);
|
|
178
|
+
if (t === undefined) {
|
|
179
|
+
t = {
|
|
180
|
+
name: n,
|
|
181
|
+
navigations: 0,
|
|
182
|
+
settledMs: 0,
|
|
183
|
+
worstMs: 0,
|
|
184
|
+
held: 0,
|
|
185
|
+
heldMs: 0,
|
|
186
|
+
silent: 0,
|
|
187
|
+
superseded: 0,
|
|
188
|
+
redirected: 0
|
|
189
|
+
};
|
|
190
|
+
feedbackNavigations.set(n, t);
|
|
191
|
+
}
|
|
192
|
+
t.navigations++;
|
|
193
|
+
if (e.redirects !== undefined) t.redirected++;
|
|
194
|
+
if (e.outcome === "superseded") {
|
|
195
|
+
t.superseded++;
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
198
|
+
const i = e.settledMs;
|
|
199
|
+
t.settledMs += i;
|
|
200
|
+
if (i > t.worstMs) t.worstMs = i;
|
|
201
|
+
if (e.outcome === "held") {
|
|
202
|
+
t.held++;
|
|
203
|
+
t.heldMs += e.hold?.holdMs ?? i;
|
|
204
|
+
if (e.hold !== undefined && isSilentHold(e.hold)) t.silent++;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
function rankedCounts(e, n) {
|
|
209
|
+
return [ ...e ].sort((e, n) => n[1] - e[1]).map(([e, t]) => ({
|
|
210
|
+
[n]: e,
|
|
211
|
+
holds: t
|
|
212
|
+
}));
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
registerFold({
|
|
216
|
+
rerun: (e, n) => recordFeedbackRun(n),
|
|
217
|
+
hold: recordFeedbackHold,
|
|
218
|
+
navigation: recordFeedbackNavigation,
|
|
219
|
+
flightStart(e, n) {
|
|
220
|
+
const t = flightBucket(e);
|
|
221
|
+
t.flights++;
|
|
222
|
+
if (n) t.abandoned++;
|
|
223
|
+
},
|
|
224
|
+
flightLanded(e, n) {
|
|
225
|
+
const t = flightBucket(e);
|
|
226
|
+
t.landed++;
|
|
227
|
+
t.landedMs += n;
|
|
228
|
+
if (n > t.worstMs) t.worstMs = n;
|
|
229
|
+
},
|
|
230
|
+
fallback: trackFallback,
|
|
231
|
+
reset() {
|
|
232
|
+
feedbackSources.clear();
|
|
233
|
+
feedbackInteractions.clear();
|
|
234
|
+
feedbackNavigations.clear();
|
|
235
|
+
flightStats.clear();
|
|
236
|
+
fallbackStats.clear();
|
|
237
|
+
}
|
|
238
|
+
});
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* What the user waited on, folded from holds and the interaction on each
|
|
242
|
+
* re-run: `sources` ranks async sources by the silent time writes spent held
|
|
243
|
+
* behind them (with which affordances answered, how often, and which
|
|
244
|
+
* interactions were held); `interactions` ranks user events by the total time
|
|
245
|
+
* they cost — re-run work caused (long-flush hazard) beside time held
|
|
246
|
+
* (silent-hold hazard). Facts at every duration; SILENT_HOLD is the
|
|
247
|
+
* thresholded verdict. Three more tables round out the picture: `navigations`
|
|
248
|
+
* ranks routes by the time spent held navigating to them (folded from settled
|
|
249
|
+
* navigations), `flights` counts each async source's flights and how many
|
|
250
|
+
* were abandoned before landing (the re-ask storm), and `fallbacks` measures
|
|
251
|
+
* how long each loading boundary showed its fallback and how often that was a
|
|
252
|
+
* flash.
|
|
253
|
+
*/ function feedback() {
|
|
254
|
+
const e = [ ...feedbackNavigations.values() ].map(e => ({
|
|
255
|
+
...e
|
|
256
|
+
})).sort((e, n) => n.heldMs - e.heldMs || n.settledMs - e.settledMs);
|
|
257
|
+
const n = [ ...flightStats.values() ].map(e => ({
|
|
258
|
+
...e
|
|
259
|
+
})).sort((e, n) => n.abandoned - e.abandoned || n.flights - e.flights);
|
|
260
|
+
const t = [ ...fallbackStats.values() ].map(e => ({
|
|
261
|
+
...e.row
|
|
262
|
+
})).sort((e, n) => n.flashes - e.flashes || n.shownMs - e.shownMs);
|
|
263
|
+
const i = [ ...feedbackSources.values() ].map(e => ({
|
|
264
|
+
...e.row,
|
|
265
|
+
acknowledgedBy: rankedCounts(e.acks, "by"),
|
|
266
|
+
interactions: rankedCounts(e.interactions, "interaction"),
|
|
267
|
+
writes: [ ...e.writes ]
|
|
268
|
+
})).sort((e, n) => n.silentMs - e.silentMs || n.heldMs - e.heldMs);
|
|
269
|
+
// Ranked by the total time the user spent on it: held plus synchronous work.
|
|
270
|
+
const s = [ ...feedbackInteractions.values() ].map(e => ({
|
|
271
|
+
...e.row
|
|
272
|
+
})).sort((e, n) => n.heldMs + n.selfMs - (e.heldMs + e.selfMs));
|
|
273
|
+
return {
|
|
274
|
+
sources: i,
|
|
275
|
+
interactions: s,
|
|
276
|
+
navigations: e,
|
|
277
|
+
flights: n,
|
|
278
|
+
fallbacks: t
|
|
279
|
+
};
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
export { feedback };
|
|
@@ -1,7 +1,17 @@
|
|
|
1
1
|
let attrHooks = null;
|
|
2
2
|
|
|
3
|
+
/**
|
|
4
|
+
* The installed engine, registered on `globalThis` as well (the records
|
|
5
|
+
* channel's reason, see `Records`): a wire layer bundled without a framework
|
|
6
|
+
* import — `@solidjs/web`'s server-function client — stamps the records it
|
|
7
|
+
* emits through the engine's `currentOrigin`, and this is its reach. The
|
|
8
|
+
* module binding stays the core's own read (one null check per hook site);
|
|
9
|
+
* the registration mirrors it.
|
|
10
|
+
*/ const INSTALLED = Symbol.for("@solidjs/signals/observe/attribution");
|
|
11
|
+
|
|
3
12
|
function setAttributionHooks(t) {
|
|
4
13
|
attrHooks = t;
|
|
14
|
+
globalThis[INSTALLED] = t ?? undefined;
|
|
5
15
|
}
|
|
6
16
|
|
|
7
17
|
/**
|
|
@@ -57,4 +67,16 @@ function setAttributionHooks(t) {
|
|
|
57
67
|
}
|
|
58
68
|
}
|
|
59
69
|
|
|
60
|
-
|
|
70
|
+
/**
|
|
71
|
+
* The provenance a root write performed now would carry, as the installed
|
|
72
|
+
* engine sees it (`AttributionHooks.currentOrigin`); `undefined` with no
|
|
73
|
+
* engine, or when nothing is in effect. Reachable as
|
|
74
|
+
* `OBSERVE.attribution.currentOrigin` — how a runtime stamps a fact of its
|
|
75
|
+
* own (a server-function call) with the interaction or navigation it ran
|
|
76
|
+
* for, so an observer joins the two by identity.
|
|
77
|
+
*/ function currentOrigin() {
|
|
78
|
+
const t = attrHooks;
|
|
79
|
+
return t === null ? undefined : t.currentOrigin();
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export { attrHooks, currentOrigin, setAttributionHooks, withInteraction, withOrigin };
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { nodeName, attribution } from "./attribution.js";
|
|
2
|
+
|
|
3
|
+
import { $REFRESH } from "./constants.js";
|
|
4
|
+
|
|
5
|
+
import { subjectOf } from "./dev.js";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Point queries over the engine's live state — the devtools/console view of
|
|
9
|
+
* one scope. Their own module so a records-only consumer never ships them;
|
|
10
|
+
* they read the engine's ring buffer and the graph, and register nothing.
|
|
11
|
+
*/
|
|
12
|
+
/** The node behind a memo/effect accessor, or the raw node passed through. */ function nodeOf(t) {
|
|
13
|
+
return t?.[$REFRESH] ?? t;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/** Re-run history for one node — pass a memo/effect accessor or raw node. */ function why(t) {
|
|
17
|
+
const n = nodeOf(t);
|
|
18
|
+
return attribution.history().filter(t => subjectOf(t) === n);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/** Current dependency names of one scope — the devtools subscription view. */ function subscriptions(t) {
|
|
22
|
+
const n = nodeOf(t);
|
|
23
|
+
const o = [];
|
|
24
|
+
for (let t = n?.ee ?? null; t !== null; t = t.te) o.push(nodeName(t.re));
|
|
25
|
+
return o;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export { subscriptions, why };
|