@flotrace/runtime-core 2.2.3 → 2.3.0
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/README.md +94 -0
- package/dist/chunk-QLOJU5F2.mjs +181 -0
- package/dist/index.d.mts +380 -22
- package/dist/index.d.ts +380 -22
- package/dist/index.js +681 -106
- package/dist/index.mjs +557 -106
- package/dist/jsx-dev-runtime.d.mts +64 -0
- package/dist/jsx-dev-runtime.d.ts +64 -0
- package/dist/jsx-dev-runtime.js +179 -0
- package/dist/jsx-dev-runtime.mjs +46 -0
- package/dist/jsx-runtime.d.mts +1 -0
- package/dist/jsx-runtime.d.ts +1 -0
- package/dist/jsx-runtime.js +34 -0
- package/dist/jsx-runtime.mjs +7 -0
- package/package.json +12 -1
package/dist/index.js
CHANGED
|
@@ -31,13 +31,22 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
31
31
|
var index_exports = {};
|
|
32
32
|
__export(index_exports, {
|
|
33
33
|
DEFAULT_CONFIG: () => DEFAULT_CONFIG,
|
|
34
|
+
FLOTRACE_SOURCE: () => FLOTRACE_SOURCE,
|
|
34
35
|
FloTraceWebSocketClient: () => FloTraceWebSocketClient,
|
|
36
|
+
JSX_RUNTIME_ACTIVE_KEY: () => JSX_RUNTIME_ACTIVE_KEY,
|
|
35
37
|
buildAncestorChain: () => buildAncestorChain,
|
|
38
|
+
clearCallSiteRenders: () => clearCallSiteRenders,
|
|
36
39
|
clearFetchOriginTags: () => clearFetchOriginTags,
|
|
40
|
+
computeCallSiteId: () => computeCallSiteId,
|
|
41
|
+
computeCallSiteMetricsPayload: () => computeCallSiteMetricsPayload,
|
|
42
|
+
describeFiberType: () => describeFiberType,
|
|
43
|
+
detectInlineLiterals: () => detectInlineLiterals,
|
|
37
44
|
detectServerComponent: () => detectServerComponent,
|
|
38
45
|
detectWebFramework: () => detectWebFramework,
|
|
39
46
|
disposeWebSocketClient: () => disposeWebSocketClient,
|
|
40
47
|
findFetchOrigin: () => findFetchOrigin,
|
|
48
|
+
getCallSiteRenderRate: () => getCallSiteRenderRate,
|
|
49
|
+
getCallSiteRenders: () => getCallSiteRenders,
|
|
41
50
|
getChangedKeys: () => getChangedKeys,
|
|
42
51
|
getComponentNameFromFiber: () => getComponentNameFromFiber,
|
|
43
52
|
getCurrentRenderingFiber: () => getCurrentRenderingFiber,
|
|
@@ -60,9 +69,15 @@ __export(index_exports, {
|
|
|
60
69
|
installTanStackQueryTracker: () => installTanStackQueryTracker,
|
|
61
70
|
installTimelineTracker: () => installTimelineTracker,
|
|
62
71
|
installZustandTracker: () => installZustandTracker,
|
|
72
|
+
isJsxRuntimeActive: () => isJsxRuntimeActive,
|
|
63
73
|
isReduxStore: () => isReduxStore,
|
|
64
74
|
isTanStackQueryClient: () => isTanStackQueryClient,
|
|
75
|
+
logTreeSnapshot: () => logTreeSnapshot,
|
|
76
|
+
logTreeSummary: () => logTreeSummary,
|
|
77
|
+
markJsxRuntimeActive: () => markJsxRuntimeActive,
|
|
65
78
|
maybeEmitNextjsContext: () => maybeEmitNextjsContext,
|
|
79
|
+
normalizeJsxSourcePath: () => normalizeJsxSourcePath,
|
|
80
|
+
recordCallSiteRender: () => recordCallSiteRender,
|
|
66
81
|
recordTimelineEvent: () => recordTimelineEvent,
|
|
67
82
|
requestFullSnapshot: () => requestFullSnapshot,
|
|
68
83
|
requestTreeSnapshot: () => requestTreeSnapshot,
|
|
@@ -70,6 +85,8 @@ __export(index_exports, {
|
|
|
70
85
|
resolveValueTrace: () => resolveValueTrace,
|
|
71
86
|
serializeProps: () => serializeProps,
|
|
72
87
|
serializeValue: () => serializeValue,
|
|
88
|
+
setDuplicateKeyEmitter: () => setDuplicateKeyEmitter,
|
|
89
|
+
setFiberDebug: () => setFiberDebug,
|
|
73
90
|
tagFetchData: () => tagFetchData,
|
|
74
91
|
uninstallFiberTreeWalker: () => uninstallFiberTreeWalker,
|
|
75
92
|
uninstallReduxTracker: () => uninstallReduxTracker,
|
|
@@ -103,6 +120,130 @@ var DEFAULT_CONFIG = {
|
|
|
103
120
|
getAppUrl: void 0
|
|
104
121
|
};
|
|
105
122
|
|
|
123
|
+
// src/jsxRuntimeUtils.ts
|
|
124
|
+
var FLOTRACE_SOURCE = /* @__PURE__ */ Symbol.for("flotrace.source");
|
|
125
|
+
var JSX_RUNTIME_ACTIVE_KEY = /* @__PURE__ */ Symbol.for("flotrace.jsx-runtime-active");
|
|
126
|
+
function normalizeJsxSourcePath(fileName) {
|
|
127
|
+
let p = fileName;
|
|
128
|
+
if (p.startsWith("file://")) p = p.slice("file://".length);
|
|
129
|
+
if (p.startsWith("webpack-internal:///./")) p = p.slice("webpack-internal:///./".length);
|
|
130
|
+
if (p.startsWith("[project]/")) p = p.slice("[project]/".length);
|
|
131
|
+
if (p.startsWith("./")) p = p.slice(2);
|
|
132
|
+
if (/^\/[a-zA-Z]:[\\/]/.test(p)) p = p.slice(1);
|
|
133
|
+
if (/^[a-zA-Z]:[\\/]/.test(p)) p = p[0].toLowerCase() + p.slice(1);
|
|
134
|
+
return p;
|
|
135
|
+
}
|
|
136
|
+
function computeCallSiteId(source) {
|
|
137
|
+
const normPath = normalizeJsxSourcePath(source.fileName);
|
|
138
|
+
const key = `${normPath}:${source.lineNumber}:${source.columnNumber}`;
|
|
139
|
+
let hash = 2166136261;
|
|
140
|
+
for (let i = 0; i < key.length; i++) {
|
|
141
|
+
hash ^= key.charCodeAt(i);
|
|
142
|
+
hash = Math.imul(hash, 16777619);
|
|
143
|
+
}
|
|
144
|
+
return (hash >>> 0).toString(16).padStart(8, "0");
|
|
145
|
+
}
|
|
146
|
+
function readJsxSourceFromFiber(fiber) {
|
|
147
|
+
const props = fiber.memoizedProps;
|
|
148
|
+
if (!props) return void 0;
|
|
149
|
+
const raw = props[FLOTRACE_SOURCE];
|
|
150
|
+
if (!raw || typeof raw !== "object") return void 0;
|
|
151
|
+
const obj = raw;
|
|
152
|
+
if (typeof obj.fileName !== "string" || typeof obj.lineNumber !== "number" || typeof obj.columnNumber !== "number" || typeof obj.callSiteId !== "string") {
|
|
153
|
+
return void 0;
|
|
154
|
+
}
|
|
155
|
+
return raw;
|
|
156
|
+
}
|
|
157
|
+
var callSiteRenders = /* @__PURE__ */ new Map();
|
|
158
|
+
var RING_BUFFER_MAX = 60;
|
|
159
|
+
function recordCallSiteRender(callSiteId, now2 = performance.now()) {
|
|
160
|
+
const arr = callSiteRenders.get(callSiteId);
|
|
161
|
+
if (arr === void 0) {
|
|
162
|
+
callSiteRenders.set(callSiteId, [now2]);
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
arr.push(now2);
|
|
166
|
+
if (arr.length > RING_BUFFER_MAX) arr.shift();
|
|
167
|
+
}
|
|
168
|
+
function getCallSiteRenders(callSiteId) {
|
|
169
|
+
return callSiteRenders.get(callSiteId) ?? [];
|
|
170
|
+
}
|
|
171
|
+
function getCallSiteRenderRate(callSiteId, windowMs = 5e3, now2 = performance.now()) {
|
|
172
|
+
const arr = callSiteRenders.get(callSiteId);
|
|
173
|
+
if (!arr || arr.length === 0) return 0;
|
|
174
|
+
const cutoff = now2 - windowMs;
|
|
175
|
+
let count = 0;
|
|
176
|
+
for (let i = arr.length - 1; i >= 0; i--) {
|
|
177
|
+
if (arr[i] >= cutoff) count++;
|
|
178
|
+
else break;
|
|
179
|
+
}
|
|
180
|
+
return count / windowMs * 1e3;
|
|
181
|
+
}
|
|
182
|
+
function clearCallSiteRenders() {
|
|
183
|
+
callSiteRenders.clear();
|
|
184
|
+
}
|
|
185
|
+
function computeCallSiteMetricsPayload(windowMs = 5e3, now2 = performance.now()) {
|
|
186
|
+
let out = null;
|
|
187
|
+
const cutoff = now2 - windowMs;
|
|
188
|
+
for (const [callSiteId, arr] of callSiteRenders) {
|
|
189
|
+
if (arr.length === 0) continue;
|
|
190
|
+
let count = 0;
|
|
191
|
+
for (let i = arr.length - 1; i >= 0; i--) {
|
|
192
|
+
if (arr[i] >= cutoff) count++;
|
|
193
|
+
else break;
|
|
194
|
+
}
|
|
195
|
+
if (count > 0) {
|
|
196
|
+
(out ?? (out = {}))[callSiteId] = count / windowMs * 1e3;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
return out;
|
|
200
|
+
}
|
|
201
|
+
var duplicateKeyEmitter = null;
|
|
202
|
+
function setDuplicateKeyEmitter(emitter) {
|
|
203
|
+
duplicateKeyEmitter = emitter;
|
|
204
|
+
}
|
|
205
|
+
function markJsxRuntimeActive() {
|
|
206
|
+
globalThis[JSX_RUNTIME_ACTIVE_KEY] = true;
|
|
207
|
+
}
|
|
208
|
+
function isJsxRuntimeActive() {
|
|
209
|
+
return globalThis[JSX_RUNTIME_ACTIVE_KEY] === true;
|
|
210
|
+
}
|
|
211
|
+
var KNOWN_REACT_PROPS = /* @__PURE__ */ new Set(["key", "ref", "children", "className"]);
|
|
212
|
+
var REACT_ELEMENT_TYPEOF_LEGACY = /* @__PURE__ */ Symbol.for("react.element");
|
|
213
|
+
var REACT_ELEMENT_TYPEOF_R19 = /* @__PURE__ */ Symbol.for("react.transitional.element");
|
|
214
|
+
function isReactElement(v) {
|
|
215
|
+
const typeOf = v.$$typeof;
|
|
216
|
+
return typeOf === REACT_ELEMENT_TYPEOF_LEGACY || typeOf === REACT_ELEMENT_TYPEOF_R19;
|
|
217
|
+
}
|
|
218
|
+
function detectInlineLiterals(props) {
|
|
219
|
+
let out;
|
|
220
|
+
for (const k in props) {
|
|
221
|
+
if (KNOWN_REACT_PROPS.has(k)) continue;
|
|
222
|
+
const v = props[k];
|
|
223
|
+
if (typeof v === "function") {
|
|
224
|
+
if (!v.name) {
|
|
225
|
+
(out ?? (out = {}))[k] = "fn";
|
|
226
|
+
}
|
|
227
|
+
} else if (Array.isArray(v)) {
|
|
228
|
+
if (v.length > 0) {
|
|
229
|
+
(out ?? (out = {}))[k] = "arr";
|
|
230
|
+
}
|
|
231
|
+
} else if (v !== null && typeof v === "object" && // Skip elements processed by our own runtime (marker present).
|
|
232
|
+
!(FLOTRACE_SOURCE in v) && // Skip React elements processed by ANY runtime — `$$typeof` is set on
|
|
233
|
+
// every element regardless of which jsx-runtime created it, so this
|
|
234
|
+
// catches mixed-runtime codebases. Without this guard, an inline
|
|
235
|
+
// `<Outer child={<Inner/>} />` would false-positive on `child` when
|
|
236
|
+
// Inner went through a different jsxImportSource.
|
|
237
|
+
!isReactElement(v)) {
|
|
238
|
+
const proto = Object.getPrototypeOf(v);
|
|
239
|
+
if (proto === Object.prototype || proto === null) {
|
|
240
|
+
(out ?? (out = {}))[k] = "obj";
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
return out;
|
|
245
|
+
}
|
|
246
|
+
|
|
106
247
|
// src/serializer.ts
|
|
107
248
|
var MAX_DEPTH = 5;
|
|
108
249
|
var MAX_STRING_LENGTH = 500;
|
|
@@ -211,11 +352,7 @@ function serializeValue(value, depth = 0, seen = /* @__PURE__ */ new WeakSet())
|
|
|
211
352
|
for (let i = 0; i < Math.min(keys.length, MAX_OBJECT_KEYS); i++) {
|
|
212
353
|
const key = keys[i];
|
|
213
354
|
try {
|
|
214
|
-
result[key] = serializeValue(
|
|
215
|
-
value[key],
|
|
216
|
-
depth + 1,
|
|
217
|
-
seen
|
|
218
|
-
);
|
|
355
|
+
result[key] = serializeValue(value[key], depth + 1, seen);
|
|
219
356
|
} catch {
|
|
220
357
|
result[key] = { __type: "truncated", originalType: "error" };
|
|
221
358
|
}
|
|
@@ -316,7 +453,12 @@ var _FloTraceWebSocketClient = class _FloTraceWebSocketClient {
|
|
|
316
453
|
frameworkName: this.config.frameworkName,
|
|
317
454
|
frameworkVersion: this.config.frameworkVersion,
|
|
318
455
|
reactNativeVersion: this.config.reactNativeVersion,
|
|
319
|
-
runtimeVersion: this.config.runtimeVersion
|
|
456
|
+
runtimeVersion: this.config.runtimeVersion,
|
|
457
|
+
// P5: JSX runtime adoption signal — read at WS-open time so
|
|
458
|
+
// multiple fibers have already rendered by the moment we report.
|
|
459
|
+
// `isJsxRuntimeActive` reads `globalThis[Symbol.for('flotrace.jsx-runtime-active')]`,
|
|
460
|
+
// which the dev jsx-runtime sets on first jsxDEV call.
|
|
461
|
+
jsxRuntimeActive: isJsxRuntimeActive()
|
|
320
462
|
});
|
|
321
463
|
this.flush();
|
|
322
464
|
};
|
|
@@ -642,26 +784,31 @@ function classifyFromDebugLabel(state, index, effects, effectIdx, debugLabel) {
|
|
|
642
784
|
const ms = state.memoizedState;
|
|
643
785
|
const normalizedLabel = debugLabel.toLowerCase().replace(/\s/g, "");
|
|
644
786
|
const labelMap = {
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
787
|
+
usestate: "useState",
|
|
788
|
+
usereducer: "useReducer",
|
|
789
|
+
useref: "useRef",
|
|
790
|
+
usememo: "useMemo",
|
|
791
|
+
usecallback: "useCallback",
|
|
792
|
+
useeffect: "useEffect",
|
|
793
|
+
uselayouteffect: "useLayoutEffect",
|
|
794
|
+
useinsertioneffect: "useInsertionEffect",
|
|
795
|
+
usecontext: "useContext",
|
|
796
|
+
useimperativehandle: "useImperativeHandle",
|
|
797
|
+
usedebugvalue: "useDebugValue",
|
|
798
|
+
usetransition: "useTransition",
|
|
799
|
+
usedeferredvalue: "useDeferredValue",
|
|
800
|
+
useid: "useId",
|
|
801
|
+
usesyncexternalstore: "useSyncExternalStore",
|
|
802
|
+
useoptimistic: "useOptimistic",
|
|
803
|
+
useformstatus: "useFormStatus"
|
|
662
804
|
};
|
|
663
805
|
const hookType = labelMap[normalizedLabel] ?? "unknown";
|
|
664
|
-
const base = {
|
|
806
|
+
const base = {
|
|
807
|
+
index,
|
|
808
|
+
type: hookType,
|
|
809
|
+
value: serializeValue(ms, 0, /* @__PURE__ */ new WeakSet()),
|
|
810
|
+
debugLabel
|
|
811
|
+
};
|
|
665
812
|
if (hookType === "useEffect" || hookType === "useLayoutEffect" || hookType === "useInsertionEffect") {
|
|
666
813
|
if (effectIdx < effects.length) {
|
|
667
814
|
const effect = effects[effectIdx];
|
|
@@ -1128,7 +1275,13 @@ var ClassComponent = 1;
|
|
|
1128
1275
|
var ForwardRef = 11;
|
|
1129
1276
|
var MemoComponent = 14;
|
|
1130
1277
|
var SimpleMemoComponent = 15;
|
|
1131
|
-
var USER_TAGS = /* @__PURE__ */ new Set([
|
|
1278
|
+
var USER_TAGS = /* @__PURE__ */ new Set([
|
|
1279
|
+
FunctionComponent,
|
|
1280
|
+
ClassComponent,
|
|
1281
|
+
ForwardRef,
|
|
1282
|
+
MemoComponent,
|
|
1283
|
+
SimpleMemoComponent
|
|
1284
|
+
]);
|
|
1132
1285
|
function isMemoizedFiber(fiber) {
|
|
1133
1286
|
return fiber.tag === MemoComponent || fiber.tag === SimpleMemoComponent;
|
|
1134
1287
|
}
|
|
@@ -1212,13 +1365,15 @@ function buildCascadeTree(rootFiber, triggers) {
|
|
|
1212
1365
|
triggerByName.set(t.componentName, t);
|
|
1213
1366
|
}
|
|
1214
1367
|
}
|
|
1215
|
-
const stack = [
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1368
|
+
const stack = [
|
|
1369
|
+
{
|
|
1370
|
+
fiber: rootFiber,
|
|
1371
|
+
depth: 0,
|
|
1372
|
+
parentRerendered: false,
|
|
1373
|
+
parentNode: null,
|
|
1374
|
+
isRoot: true
|
|
1375
|
+
}
|
|
1376
|
+
];
|
|
1222
1377
|
while (stack.length > 0) {
|
|
1223
1378
|
const entry = stack.pop();
|
|
1224
1379
|
const { fiber, depth, parentRerendered, parentNode, isRoot } = entry;
|
|
@@ -1229,7 +1384,13 @@ function buildCascadeTree(rootFiber, triggers) {
|
|
|
1229
1384
|
if (isNewMount && !didRender) {
|
|
1230
1385
|
let child2 = fiber.child;
|
|
1231
1386
|
while (child2) {
|
|
1232
|
-
stack.push({
|
|
1387
|
+
stack.push({
|
|
1388
|
+
fiber: child2,
|
|
1389
|
+
depth: depth + 1,
|
|
1390
|
+
parentRerendered: false,
|
|
1391
|
+
parentNode,
|
|
1392
|
+
isRoot: false
|
|
1393
|
+
});
|
|
1233
1394
|
child2 = child2.sibling;
|
|
1234
1395
|
}
|
|
1235
1396
|
continue;
|
|
@@ -1237,7 +1398,13 @@ function buildCascadeTree(rootFiber, triggers) {
|
|
|
1237
1398
|
if (!USER_TAGS.has(fiber.tag)) {
|
|
1238
1399
|
let child2 = fiber.child;
|
|
1239
1400
|
while (child2) {
|
|
1240
|
-
stack.push({
|
|
1401
|
+
stack.push({
|
|
1402
|
+
fiber: child2,
|
|
1403
|
+
depth: depth + 1,
|
|
1404
|
+
parentRerendered: didRender || parentRerendered,
|
|
1405
|
+
parentNode,
|
|
1406
|
+
isRoot: false
|
|
1407
|
+
});
|
|
1241
1408
|
child2 = child2.sibling;
|
|
1242
1409
|
}
|
|
1243
1410
|
continue;
|
|
@@ -1246,7 +1413,13 @@ function buildCascadeTree(rootFiber, triggers) {
|
|
|
1246
1413
|
if (reason === null) {
|
|
1247
1414
|
let child2 = fiber.child;
|
|
1248
1415
|
while (child2) {
|
|
1249
|
-
stack.push({
|
|
1416
|
+
stack.push({
|
|
1417
|
+
fiber: child2,
|
|
1418
|
+
depth: depth + 1,
|
|
1419
|
+
parentRerendered: false,
|
|
1420
|
+
parentNode,
|
|
1421
|
+
isRoot: false
|
|
1422
|
+
});
|
|
1250
1423
|
child2 = child2.sibling;
|
|
1251
1424
|
}
|
|
1252
1425
|
continue;
|
|
@@ -1272,7 +1445,11 @@ function buildCascadeTree(rootFiber, triggers) {
|
|
|
1272
1445
|
triggerId,
|
|
1273
1446
|
children: [],
|
|
1274
1447
|
depth,
|
|
1275
|
-
isMemoized: isMemoizedFiber(fiber)
|
|
1448
|
+
isMemoized: isMemoizedFiber(fiber),
|
|
1449
|
+
// P6: JSX-runtime attribution — read from fiber.memoizedProps directly.
|
|
1450
|
+
// Same source the walker uses, so cascade nodes align with LiveTreeNode
|
|
1451
|
+
// attribution for the same user component.
|
|
1452
|
+
jsxSource: readJsxSourceFromFiber(fiber)
|
|
1276
1453
|
};
|
|
1277
1454
|
totalComponents++;
|
|
1278
1455
|
if (reason === "parent-cascade") {
|
|
@@ -1305,7 +1482,10 @@ function analyzeCascade(root, triggers) {
|
|
|
1305
1482
|
try {
|
|
1306
1483
|
const finishedLanes = getFinishedLanes(root);
|
|
1307
1484
|
const lane = classifyLanes(finishedLanes);
|
|
1308
|
-
const { rootCauses, totalComponents, avoidableCount, avoidableDuration } = buildCascadeTree(
|
|
1485
|
+
const { rootCauses, totalComponents, avoidableCount, avoidableDuration } = buildCascadeTree(
|
|
1486
|
+
root.current,
|
|
1487
|
+
triggers
|
|
1488
|
+
);
|
|
1309
1489
|
if (totalComponents === 0) return null;
|
|
1310
1490
|
const totalDuration = rootCauses.reduce((sum, n) => sum + n.subtreeDuration, 0);
|
|
1311
1491
|
const triggerIds = triggers.map((t) => t.triggerId);
|
|
@@ -1387,7 +1567,8 @@ function shouldFlagRename(value) {
|
|
|
1387
1567
|
if (value === null || value === void 0) return false;
|
|
1388
1568
|
if (typeof value !== "object") return false;
|
|
1389
1569
|
if (Array.isArray(value) && value.length === 0) return false;
|
|
1390
|
-
if (!Array.isArray(value) && Object.keys(value).length === 0)
|
|
1570
|
+
if (!Array.isArray(value) && Object.keys(value).length === 0)
|
|
1571
|
+
return false;
|
|
1391
1572
|
return true;
|
|
1392
1573
|
}
|
|
1393
1574
|
function computePropIntersectionRatio(nodeProps, childrenProps) {
|
|
@@ -1596,13 +1777,24 @@ function runAnalysis(tree, fiberRefMap2) {
|
|
|
1596
1777
|
propKey: p.propKey,
|
|
1597
1778
|
role,
|
|
1598
1779
|
hookCount: hookCounts.get(p.nodeId) ?? 0,
|
|
1599
|
-
hasContextHook: contextFlags.get(p.nodeId) ?? false
|
|
1780
|
+
hasContextHook: contextFlags.get(p.nodeId) ?? false,
|
|
1781
|
+
// P6: propagate JSX-runtime attribution from the tree node so the
|
|
1782
|
+
// drill-chain detail can render `(file:line)` per step + click-
|
|
1783
|
+
// to-IDE on each component along the chain. Undefined when the
|
|
1784
|
+
// user hasn't opted into the JSX runtime.
|
|
1785
|
+
jsxSource: n?.jsxSource
|
|
1600
1786
|
};
|
|
1601
1787
|
});
|
|
1602
1788
|
const passthroughCount = chainNodes.filter((n) => n.role === "passthrough").length;
|
|
1603
1789
|
const sourceNode = nodeMap.get(sourceId);
|
|
1604
1790
|
const renames = path.flatMap(
|
|
1605
|
-
(p, idx) => p.isRename ? [
|
|
1791
|
+
(p, idx) => p.isRename ? [
|
|
1792
|
+
{
|
|
1793
|
+
atNodeId: p.nodeId,
|
|
1794
|
+
fromKey: idx > 0 ? path[idx - 1].propKey : sourcePropName,
|
|
1795
|
+
toKey: p.propKey
|
|
1796
|
+
}
|
|
1797
|
+
] : []
|
|
1606
1798
|
);
|
|
1607
1799
|
chains.push({
|
|
1608
1800
|
chainId: makeChainId(sourceId, fp, consumerNodeId),
|
|
@@ -1697,10 +1889,7 @@ var SERVER_COMPONENT_PATTERNS = [
|
|
|
1697
1889
|
/[\\/]app[\\/].+[\\/]error\.[jt]sx?$/
|
|
1698
1890
|
// Next.js error UI
|
|
1699
1891
|
];
|
|
1700
|
-
var SERVER_REFERENCE_PATTERNS = [
|
|
1701
|
-
/_ServerReference$/,
|
|
1702
|
-
/^RSC_/
|
|
1703
|
-
];
|
|
1892
|
+
var SERVER_REFERENCE_PATTERNS = [/_ServerReference$/, /^RSC_/];
|
|
1704
1893
|
var detectionEmitted = false;
|
|
1705
1894
|
function maybeEmitNextjsContext(client2) {
|
|
1706
1895
|
if (detectionEmitted) return;
|
|
@@ -1794,7 +1983,9 @@ function scanActionStateChanges(fiberRefMap2, client2) {
|
|
|
1794
1983
|
for (const [nodeId, fiber] of fiberRefMap2) {
|
|
1795
1984
|
const entries = extractActionEntries(fiber);
|
|
1796
1985
|
if (!entries) continue;
|
|
1797
|
-
const snapshot = JSON.stringify(
|
|
1986
|
+
const snapshot = JSON.stringify(
|
|
1987
|
+
entries.map((e) => ({ i: e.hookIndex, p: e.isPending, s: e.state }))
|
|
1988
|
+
);
|
|
1798
1989
|
if (prevActionStateMap.get(nodeId) === snapshot) continue;
|
|
1799
1990
|
prevActionStateMap.set(nodeId, snapshot);
|
|
1800
1991
|
const componentName = nodeId.split("/").pop()?.replace(/-\d+$/, "") ?? "Unknown";
|
|
@@ -1904,7 +2095,8 @@ function tagFetchData(obj, requestId, depth = 0) {
|
|
|
1904
2095
|
const limit = Math.min(obj.length, FETCH_ORIGIN_TAG_ARRAY_LIMIT);
|
|
1905
2096
|
for (let i = 0; i < limit; i++) tagFetchData(obj[i], requestId, depth + 1);
|
|
1906
2097
|
} else {
|
|
1907
|
-
for (const val of Object.values(obj))
|
|
2098
|
+
for (const val of Object.values(obj))
|
|
2099
|
+
tagFetchData(val, requestId, depth + 1);
|
|
1908
2100
|
}
|
|
1909
2101
|
}
|
|
1910
2102
|
function hasActiveTags() {
|
|
@@ -1940,6 +2132,344 @@ function scanForOrigin(obj, depth, ignoreTTL) {
|
|
|
1940
2132
|
return void 0;
|
|
1941
2133
|
}
|
|
1942
2134
|
|
|
2135
|
+
// src/fiberDebugLogger.ts
|
|
2136
|
+
var MAX_FIBER_RECORDS = 500;
|
|
2137
|
+
var MAX_TREE_RECORDS = 50;
|
|
2138
|
+
var MAX_TOP_NAMES_PER_SNAPSHOT = 10;
|
|
2139
|
+
var MAX_CONTEXTS_PER_FIBER = 8;
|
|
2140
|
+
var totalFiberEvents = 0;
|
|
2141
|
+
var recordingStartedAt = null;
|
|
2142
|
+
var fiberRecords = /* @__PURE__ */ new Map();
|
|
2143
|
+
var treeRecords = [];
|
|
2144
|
+
function isRecording() {
|
|
2145
|
+
return Boolean(globalThis.__FT_DEBUG);
|
|
2146
|
+
}
|
|
2147
|
+
function setFiberDebug(enabled) {
|
|
2148
|
+
globalThis.__FT_DEBUG = enabled;
|
|
2149
|
+
if (enabled) {
|
|
2150
|
+
console.info(
|
|
2151
|
+
"%c[FT debug]%c recording started \u2014 call %c__ft.dump()%c to view, %c__ft.clear()%c to reset, %c__ft.download()%c to export",
|
|
2152
|
+
"background:#1e293b;color:#7dd3fc;padding:1px 6px;border-radius:3px;font-weight:600;",
|
|
2153
|
+
"color:#94a3b8;",
|
|
2154
|
+
"color:#a78bfa;font-weight:600;",
|
|
2155
|
+
"color:#94a3b8;",
|
|
2156
|
+
"color:#a78bfa;font-weight:600;",
|
|
2157
|
+
"color:#94a3b8;",
|
|
2158
|
+
"color:#a78bfa;font-weight:600;",
|
|
2159
|
+
"color:#94a3b8;"
|
|
2160
|
+
);
|
|
2161
|
+
}
|
|
2162
|
+
}
|
|
2163
|
+
function isFiberFunctionType(t) {
|
|
2164
|
+
return typeof t === "function";
|
|
2165
|
+
}
|
|
2166
|
+
function isFiberObjectType(t) {
|
|
2167
|
+
return typeof t === "object" && t !== null;
|
|
2168
|
+
}
|
|
2169
|
+
function isClassComponentType(t) {
|
|
2170
|
+
if (typeof t !== "function") return false;
|
|
2171
|
+
const proto = t.prototype;
|
|
2172
|
+
return typeof proto?.isReactComponent !== "undefined";
|
|
2173
|
+
}
|
|
2174
|
+
function describeFiberType(fiber) {
|
|
2175
|
+
const type = fiber.type;
|
|
2176
|
+
if (typeof type === "string") {
|
|
2177
|
+
return {
|
|
2178
|
+
kind: "host",
|
|
2179
|
+
name: type,
|
|
2180
|
+
displayName: void 0,
|
|
2181
|
+
resolved: type,
|
|
2182
|
+
looksMinified: false
|
|
2183
|
+
};
|
|
2184
|
+
}
|
|
2185
|
+
if (isFiberFunctionType(type)) {
|
|
2186
|
+
const isClass = isClassComponentType(type);
|
|
2187
|
+
const resolved = type.displayName ?? type.name ?? "Anonymous";
|
|
2188
|
+
return {
|
|
2189
|
+
kind: isClass ? "class" : "function",
|
|
2190
|
+
name: type.name,
|
|
2191
|
+
displayName: type.displayName,
|
|
2192
|
+
resolved,
|
|
2193
|
+
looksMinified: looksMinified(resolved)
|
|
2194
|
+
};
|
|
2195
|
+
}
|
|
2196
|
+
if (isFiberObjectType(type)) {
|
|
2197
|
+
if (type.render) {
|
|
2198
|
+
const resolved2 = type.render.displayName ?? type.render.name ?? "ForwardRef";
|
|
2199
|
+
return {
|
|
2200
|
+
kind: "forwardRef",
|
|
2201
|
+
name: type.render.name,
|
|
2202
|
+
displayName: type.render.displayName,
|
|
2203
|
+
resolved: resolved2,
|
|
2204
|
+
looksMinified: looksMinified(resolved2)
|
|
2205
|
+
};
|
|
2206
|
+
}
|
|
2207
|
+
if (type.type) {
|
|
2208
|
+
const resolved2 = type.type.displayName ?? type.type.name ?? "Memo";
|
|
2209
|
+
return {
|
|
2210
|
+
kind: "memo",
|
|
2211
|
+
name: type.type.name,
|
|
2212
|
+
displayName: type.type.displayName,
|
|
2213
|
+
resolved: resolved2,
|
|
2214
|
+
looksMinified: looksMinified(resolved2)
|
|
2215
|
+
};
|
|
2216
|
+
}
|
|
2217
|
+
const resolved = type.displayName ?? type.name ?? "Unknown";
|
|
2218
|
+
return {
|
|
2219
|
+
kind: "unknown",
|
|
2220
|
+
name: type.name,
|
|
2221
|
+
displayName: type.displayName,
|
|
2222
|
+
resolved,
|
|
2223
|
+
looksMinified: looksMinified(resolved)
|
|
2224
|
+
};
|
|
2225
|
+
}
|
|
2226
|
+
return {
|
|
2227
|
+
kind: "unknown",
|
|
2228
|
+
name: void 0,
|
|
2229
|
+
displayName: void 0,
|
|
2230
|
+
resolved: "Unknown",
|
|
2231
|
+
looksMinified: false
|
|
2232
|
+
};
|
|
2233
|
+
}
|
|
2234
|
+
function looksMinified(name) {
|
|
2235
|
+
return /^[a-z_$][a-z0-9_$]?$/i.test(name);
|
|
2236
|
+
}
|
|
2237
|
+
function logFiberType(fiber, context) {
|
|
2238
|
+
if (!isRecording()) return;
|
|
2239
|
+
const info = describeFiberType(fiber);
|
|
2240
|
+
const key = info.resolved;
|
|
2241
|
+
const now2 = Date.now();
|
|
2242
|
+
if (recordingStartedAt === null) recordingStartedAt = now2;
|
|
2243
|
+
totalFiberEvents += 1;
|
|
2244
|
+
const existing = fiberRecords.get(key);
|
|
2245
|
+
if (existing) {
|
|
2246
|
+
existing.count += 1;
|
|
2247
|
+
existing.lastSeen = now2;
|
|
2248
|
+
if (context && existing.contexts.size < MAX_CONTEXTS_PER_FIBER) {
|
|
2249
|
+
existing.contexts.add(context);
|
|
2250
|
+
}
|
|
2251
|
+
if (existing.exampleKey === void 0 && typeof fiber.key === "string") {
|
|
2252
|
+
existing.exampleKey = fiber.key;
|
|
2253
|
+
}
|
|
2254
|
+
return;
|
|
2255
|
+
}
|
|
2256
|
+
if (fiberRecords.size >= MAX_FIBER_RECORDS) {
|
|
2257
|
+
evictOldestFiber();
|
|
2258
|
+
}
|
|
2259
|
+
fiberRecords.set(key, {
|
|
2260
|
+
name: info.resolved,
|
|
2261
|
+
rawName: info.name,
|
|
2262
|
+
rawDisplayName: info.displayName,
|
|
2263
|
+
kind: info.kind,
|
|
2264
|
+
fiberTag: fiber.tag,
|
|
2265
|
+
looksMinified: info.looksMinified,
|
|
2266
|
+
count: 1,
|
|
2267
|
+
contexts: new Set(context ? [context] : []),
|
|
2268
|
+
firstSeen: now2,
|
|
2269
|
+
lastSeen: now2,
|
|
2270
|
+
source: fiber._debugSource ?? void 0,
|
|
2271
|
+
exampleKey: typeof fiber.key === "string" ? fiber.key : void 0
|
|
2272
|
+
});
|
|
2273
|
+
}
|
|
2274
|
+
function evictOldestFiber() {
|
|
2275
|
+
let oldestKey;
|
|
2276
|
+
let oldestTime = Infinity;
|
|
2277
|
+
for (const [key, rec] of fiberRecords) {
|
|
2278
|
+
if (rec.lastSeen < oldestTime) {
|
|
2279
|
+
oldestTime = rec.lastSeen;
|
|
2280
|
+
oldestKey = key;
|
|
2281
|
+
}
|
|
2282
|
+
}
|
|
2283
|
+
if (oldestKey) fiberRecords.delete(oldestKey);
|
|
2284
|
+
}
|
|
2285
|
+
function walkStats(node, depth, acc) {
|
|
2286
|
+
acc.total += 1;
|
|
2287
|
+
if (depth > acc.maxDepth) acc.maxDepth = depth;
|
|
2288
|
+
if (looksMinified(node.name)) acc.minifiedLike += 1;
|
|
2289
|
+
acc.byName.set(node.name, (acc.byName.get(node.name) ?? 0) + 1);
|
|
2290
|
+
for (const child of node.children) walkStats(child, depth + 1, acc);
|
|
2291
|
+
}
|
|
2292
|
+
function logTreeSnapshot(tree, context) {
|
|
2293
|
+
if (!isRecording() || !tree) return;
|
|
2294
|
+
const stats = { total: 0, minifiedLike: 0, byName: /* @__PURE__ */ new Map(), maxDepth: 0 };
|
|
2295
|
+
walkStats(tree, 0, stats);
|
|
2296
|
+
const topNames = [...stats.byName.entries()].sort((a, b) => b[1] - a[1]).slice(0, MAX_TOP_NAMES_PER_SNAPSHOT).map(([n, c]) => `${n}:${c}`).join(",");
|
|
2297
|
+
treeRecords.push({
|
|
2298
|
+
ts: Date.now(),
|
|
2299
|
+
ctx: context ?? "",
|
|
2300
|
+
rootName: tree.name,
|
|
2301
|
+
totalNodes: stats.total,
|
|
2302
|
+
maxDepth: stats.maxDepth,
|
|
2303
|
+
minifiedLike: stats.minifiedLike,
|
|
2304
|
+
topNames
|
|
2305
|
+
});
|
|
2306
|
+
if (treeRecords.length > MAX_TREE_RECORDS) treeRecords.shift();
|
|
2307
|
+
}
|
|
2308
|
+
var logTreeSummary = logTreeSnapshot;
|
|
2309
|
+
function installConsoleApi() {
|
|
2310
|
+
if (globalThis.__ft) return;
|
|
2311
|
+
const api = {
|
|
2312
|
+
dump() {
|
|
2313
|
+
const fiberRows = serializeFiberRecords();
|
|
2314
|
+
const snapRows = serializeTreeRecords();
|
|
2315
|
+
const minifiedCount = fiberRows.filter((r) => r.looksMinified).length;
|
|
2316
|
+
const elapsedSec = recordingStartedAt === null ? 0 : (Date.now() - recordingStartedAt) / 1e3;
|
|
2317
|
+
const summary = [
|
|
2318
|
+
{
|
|
2319
|
+
metric: "uniqueComponents",
|
|
2320
|
+
value: fiberRecords.size
|
|
2321
|
+
},
|
|
2322
|
+
{
|
|
2323
|
+
metric: "totalFiberEvents",
|
|
2324
|
+
value: totalFiberEvents
|
|
2325
|
+
},
|
|
2326
|
+
{
|
|
2327
|
+
metric: "minifiedLike",
|
|
2328
|
+
value: `${minifiedCount} / ${fiberRecords.size}`
|
|
2329
|
+
},
|
|
2330
|
+
{
|
|
2331
|
+
metric: "snapshots",
|
|
2332
|
+
value: treeRecords.length
|
|
2333
|
+
},
|
|
2334
|
+
{
|
|
2335
|
+
metric: "recordingSec",
|
|
2336
|
+
value: elapsedSec.toFixed(1)
|
|
2337
|
+
}
|
|
2338
|
+
];
|
|
2339
|
+
console.groupCollapsed(
|
|
2340
|
+
`%c[FT debug] dump%c \u2014 ${fiberRecords.size} components, ${totalFiberEvents} events, ${treeRecords.length} snapshots`,
|
|
2341
|
+
"background:#1e293b;color:#7dd3fc;padding:1px 6px;border-radius:3px;font-weight:600;",
|
|
2342
|
+
"color:#94a3b8;"
|
|
2343
|
+
);
|
|
2344
|
+
console.log("Summary:");
|
|
2345
|
+
console.table(summary, ["metric", "value"]);
|
|
2346
|
+
console.log("Fibers \u2014 every observed component (sorted by call count):");
|
|
2347
|
+
console.table(fiberRows, [
|
|
2348
|
+
"name",
|
|
2349
|
+
"rawName",
|
|
2350
|
+
"rawDisplayName",
|
|
2351
|
+
"kind",
|
|
2352
|
+
"fiberTag",
|
|
2353
|
+
"count",
|
|
2354
|
+
"looksMinified",
|
|
2355
|
+
"exampleKey",
|
|
2356
|
+
"contexts",
|
|
2357
|
+
"file",
|
|
2358
|
+
"line",
|
|
2359
|
+
"firstSeenAt",
|
|
2360
|
+
"lastSeenAt",
|
|
2361
|
+
"lastAgoSec"
|
|
2362
|
+
]);
|
|
2363
|
+
console.log("Tree snapshots \u2014 newest last:");
|
|
2364
|
+
console.table(snapRows, [
|
|
2365
|
+
"ts",
|
|
2366
|
+
"ctx",
|
|
2367
|
+
"rootName",
|
|
2368
|
+
"totalNodes",
|
|
2369
|
+
"maxDepth",
|
|
2370
|
+
"minifiedLike",
|
|
2371
|
+
"topNames"
|
|
2372
|
+
]);
|
|
2373
|
+
console.groupEnd();
|
|
2374
|
+
},
|
|
2375
|
+
fibers() {
|
|
2376
|
+
console.table(serializeFiberRecords(), [
|
|
2377
|
+
"name",
|
|
2378
|
+
"rawName",
|
|
2379
|
+
"rawDisplayName",
|
|
2380
|
+
"kind",
|
|
2381
|
+
"fiberTag",
|
|
2382
|
+
"count",
|
|
2383
|
+
"looksMinified",
|
|
2384
|
+
"exampleKey",
|
|
2385
|
+
"contexts",
|
|
2386
|
+
"file",
|
|
2387
|
+
"line",
|
|
2388
|
+
"firstSeenAt",
|
|
2389
|
+
"lastSeenAt",
|
|
2390
|
+
"lastAgoSec"
|
|
2391
|
+
]);
|
|
2392
|
+
},
|
|
2393
|
+
snapshots() {
|
|
2394
|
+
console.table(serializeTreeRecords());
|
|
2395
|
+
},
|
|
2396
|
+
tail(n = 20) {
|
|
2397
|
+
console.table(treeRecords.slice(-n));
|
|
2398
|
+
},
|
|
2399
|
+
clear() {
|
|
2400
|
+
fiberRecords.clear();
|
|
2401
|
+
treeRecords.length = 0;
|
|
2402
|
+
console.info("[FT debug] cleared");
|
|
2403
|
+
},
|
|
2404
|
+
size() {
|
|
2405
|
+
return { fibers: fiberRecords.size, snapshots: treeRecords.length };
|
|
2406
|
+
},
|
|
2407
|
+
export() {
|
|
2408
|
+
return { fibers: serializeFiberRecords(), snapshots: treeRecords.slice() };
|
|
2409
|
+
},
|
|
2410
|
+
download(filename) {
|
|
2411
|
+
const data = api.export();
|
|
2412
|
+
const json = JSON.stringify(data, null, 2);
|
|
2413
|
+
const docRef = globalThis.document;
|
|
2414
|
+
const URLRef = globalThis.URL;
|
|
2415
|
+
if (!docRef || !URLRef || typeof URLRef.createObjectURL !== "function") {
|
|
2416
|
+
console.warn(
|
|
2417
|
+
"[FT debug] download() requires a browser environment \u2014 printing JSON instead"
|
|
2418
|
+
);
|
|
2419
|
+
console.log(json);
|
|
2420
|
+
return;
|
|
2421
|
+
}
|
|
2422
|
+
const blob = new Blob([json], { type: "application/json" });
|
|
2423
|
+
const url = URLRef.createObjectURL(blob);
|
|
2424
|
+
const a = docRef.createElement("a");
|
|
2425
|
+
a.href = url;
|
|
2426
|
+
a.download = filename ?? `flotrace-debug-${Date.now()}.json`;
|
|
2427
|
+
a.click();
|
|
2428
|
+
URLRef.revokeObjectURL(url);
|
|
2429
|
+
}
|
|
2430
|
+
};
|
|
2431
|
+
globalThis.__ft = api;
|
|
2432
|
+
}
|
|
2433
|
+
installConsoleApi();
|
|
2434
|
+
function formatTime(ms) {
|
|
2435
|
+
const d = new Date(ms);
|
|
2436
|
+
const hh = String(d.getHours()).padStart(2, "0");
|
|
2437
|
+
const mm = String(d.getMinutes()).padStart(2, "0");
|
|
2438
|
+
const ss = String(d.getSeconds()).padStart(2, "0");
|
|
2439
|
+
const mss = String(d.getMilliseconds()).padStart(3, "0");
|
|
2440
|
+
return `${hh}:${mm}:${ss}.${mss}`;
|
|
2441
|
+
}
|
|
2442
|
+
function serializeFiberRecords() {
|
|
2443
|
+
const now2 = Date.now();
|
|
2444
|
+
return [...fiberRecords.values()].sort((a, b) => b.count - a.count).map((r) => ({
|
|
2445
|
+
name: r.name,
|
|
2446
|
+
rawName: r.rawName ?? "",
|
|
2447
|
+
rawDisplayName: r.rawDisplayName ?? "",
|
|
2448
|
+
kind: r.kind,
|
|
2449
|
+
fiberTag: r.fiberTag ?? "",
|
|
2450
|
+
count: r.count,
|
|
2451
|
+
looksMinified: r.looksMinified,
|
|
2452
|
+
exampleKey: r.exampleKey ?? "",
|
|
2453
|
+
contexts: [...r.contexts].join(","),
|
|
2454
|
+
file: r.source?.fileName ?? "",
|
|
2455
|
+
line: r.source?.lineNumber ?? "",
|
|
2456
|
+
firstSeenAt: formatTime(r.firstSeen),
|
|
2457
|
+
lastSeenAt: formatTime(r.lastSeen),
|
|
2458
|
+
lastAgoSec: ((now2 - r.lastSeen) / 1e3).toFixed(1)
|
|
2459
|
+
}));
|
|
2460
|
+
}
|
|
2461
|
+
function serializeTreeRecords() {
|
|
2462
|
+
return treeRecords.map((t) => ({
|
|
2463
|
+
ts: formatTime(t.ts),
|
|
2464
|
+
ctx: t.ctx,
|
|
2465
|
+
rootName: t.rootName,
|
|
2466
|
+
totalNodes: t.totalNodes,
|
|
2467
|
+
maxDepth: t.maxDepth,
|
|
2468
|
+
minifiedLike: t.minifiedLike,
|
|
2469
|
+
topNames: t.topNames
|
|
2470
|
+
}));
|
|
2471
|
+
}
|
|
2472
|
+
|
|
1943
2473
|
// src/fiberTreeWalker.ts
|
|
1944
2474
|
var FIBER_TAGS = {
|
|
1945
2475
|
FunctionComponent: 0,
|
|
@@ -2082,6 +2612,7 @@ function debugLog(...args) {
|
|
|
2082
2612
|
}
|
|
2083
2613
|
var fiberRefMap = /* @__PURE__ */ new Map();
|
|
2084
2614
|
function getComponentName2(fiber) {
|
|
2615
|
+
logFiberType(fiber, "getName");
|
|
2085
2616
|
const type = fiber.type;
|
|
2086
2617
|
if (!type) return "Unknown";
|
|
2087
2618
|
if (typeof type === "function") {
|
|
@@ -2207,6 +2738,8 @@ var FRAMEWORK_PATH_PATTERNS = [
|
|
|
2207
2738
|
/formik/
|
|
2208
2739
|
];
|
|
2209
2740
|
function resolveEffectiveSourcePath(fiber) {
|
|
2741
|
+
const jsxSrc = readJsxSourceFromFiber(fiber);
|
|
2742
|
+
if (jsxSrc) return jsxSrc.fileName;
|
|
2210
2743
|
if (fiber._debugSource?.fileName) return fiber._debugSource.fileName;
|
|
2211
2744
|
const ownerHit = walkAncestors(
|
|
2212
2745
|
fiber._debugOwner ?? null,
|
|
@@ -2222,6 +2755,14 @@ function resolveEffectiveSourcePath(fiber) {
|
|
|
2222
2755
|
}
|
|
2223
2756
|
return null;
|
|
2224
2757
|
}
|
|
2758
|
+
function resolveSourceConfidence(fiber, isFramework, isLibrary, precomputedJsxSource) {
|
|
2759
|
+
if (isFramework || isLibrary) return "package";
|
|
2760
|
+
const jsxSrc = precomputedJsxSource ?? readJsxSourceFromFiber(fiber);
|
|
2761
|
+
if (jsxSrc) return "exact";
|
|
2762
|
+
if (fiber._debugSource?.fileName) return "exact";
|
|
2763
|
+
if (resolveEffectiveSourcePath(fiber)) return "inferred";
|
|
2764
|
+
return "unknown";
|
|
2765
|
+
}
|
|
2225
2766
|
var STOP_WALK = /* @__PURE__ */ Symbol("stop-walk");
|
|
2226
2767
|
function walkAncestors(start, maxHops, next, visit) {
|
|
2227
2768
|
let cur = start;
|
|
@@ -2388,13 +2929,7 @@ function walkFiber(fiber, parentId, sharedNameCountMap, depth = 0, inSuspenseFal
|
|
|
2388
2929
|
{ reason: renderReason },
|
|
2389
2930
|
current.actualDuration
|
|
2390
2931
|
);
|
|
2391
|
-
const children = walkFiber(
|
|
2392
|
-
current.child,
|
|
2393
|
-
nodeId,
|
|
2394
|
-
void 0,
|
|
2395
|
-
depth + 1,
|
|
2396
|
-
inSuspenseFallback
|
|
2397
|
-
);
|
|
2932
|
+
const children = walkFiber(current.child, nodeId, void 0, depth + 1, inSuspenseFallback);
|
|
2398
2933
|
const truncatedChildren = children.length > MAX_CHILDREN_PER_NODE ? children.slice(0, MAX_CHILDREN_PER_NODE) : children;
|
|
2399
2934
|
const framework = isFrameworkComponent(current, name) || void 0;
|
|
2400
2935
|
const queryHashes = detectQueryObserverHashes(current);
|
|
@@ -2402,6 +2937,13 @@ function walkFiber(fiber, parentId, sharedNameCountMap, depth = 0, inSuspenseFal
|
|
|
2402
2937
|
const compilerStatus = detectCompilerStatus(current);
|
|
2403
2938
|
const isServerComponent = detectServerComponent(current) || void 0;
|
|
2404
2939
|
const libraryName = framework ? void 0 : detectLibraryName(current, name);
|
|
2940
|
+
const jsxSource = readJsxSourceFromFiber(current);
|
|
2941
|
+
const sourceConfidence = resolveSourceConfidence(
|
|
2942
|
+
current,
|
|
2943
|
+
framework === true,
|
|
2944
|
+
libraryName !== void 0,
|
|
2945
|
+
jsxSource
|
|
2946
|
+
);
|
|
2405
2947
|
const node = {
|
|
2406
2948
|
id: nodeId,
|
|
2407
2949
|
name,
|
|
@@ -2410,8 +2952,8 @@ function walkFiber(fiber, parentId, sharedNameCountMap, depth = 0, inSuspenseFal
|
|
|
2410
2952
|
renderPhase,
|
|
2411
2953
|
renderReason,
|
|
2412
2954
|
renderDuration: current.actualDuration,
|
|
2413
|
-
filePath: current._debugSource?.fileName,
|
|
2414
|
-
lineNumber: current._debugSource?.lineNumber,
|
|
2955
|
+
filePath: jsxSource?.fileName ?? current._debugSource?.fileName,
|
|
2956
|
+
lineNumber: jsxSource?.lineNumber ?? current._debugSource?.lineNumber,
|
|
2415
2957
|
isFramework: framework,
|
|
2416
2958
|
reactKey: resolveEffectiveReactKey(current),
|
|
2417
2959
|
queryHashes,
|
|
@@ -2422,7 +2964,9 @@ function walkFiber(fiber, parentId, sharedNameCountMap, depth = 0, inSuspenseFal
|
|
|
2422
2964
|
compilerStatus,
|
|
2423
2965
|
isServerComponent,
|
|
2424
2966
|
isLibrary: libraryName !== void 0 ? true : void 0,
|
|
2425
|
-
libraryName
|
|
2967
|
+
libraryName,
|
|
2968
|
+
jsxSource,
|
|
2969
|
+
sourceConfidence
|
|
2426
2970
|
};
|
|
2427
2971
|
if (!walkerOptions.pruneSubtree?.(node)) {
|
|
2428
2972
|
nodes.push(node);
|
|
@@ -2496,11 +3040,7 @@ function buildTreeFromFiberRoot(root) {
|
|
|
2496
3040
|
}
|
|
2497
3041
|
fiberRefMap.clear();
|
|
2498
3042
|
const topLevelNodes = walkFiber(rootFiber.child, "");
|
|
2499
|
-
debugLog(
|
|
2500
|
-
"[FloTrace] walkFiber found",
|
|
2501
|
-
topLevelNodes.length,
|
|
2502
|
-
"top-level nodes"
|
|
2503
|
-
);
|
|
3043
|
+
debugLog("[FloTrace] walkFiber found", topLevelNodes.length, "top-level nodes");
|
|
2504
3044
|
if (topLevelNodes.length === 1) {
|
|
2505
3045
|
return topLevelNodes[0];
|
|
2506
3046
|
}
|
|
@@ -2567,9 +3107,7 @@ function findFiberRootFromDOM() {
|
|
|
2567
3107
|
}
|
|
2568
3108
|
}
|
|
2569
3109
|
}
|
|
2570
|
-
console.warn(
|
|
2571
|
-
"[FloTrace] Could not find React fiber root from any DOM element"
|
|
2572
|
-
);
|
|
3110
|
+
console.warn("[FloTrace] Could not find React fiber root from any DOM element");
|
|
2573
3111
|
return null;
|
|
2574
3112
|
} catch (error) {
|
|
2575
3113
|
console.error("[FloTrace] Error finding fiber root from DOM:", error);
|
|
@@ -2631,9 +3169,7 @@ function executeSnapshot(root) {
|
|
|
2631
3169
|
adaptSnapshotInterval(nodeCount);
|
|
2632
3170
|
const client2 = getWebSocketClient();
|
|
2633
3171
|
if (!client2.connected) {
|
|
2634
|
-
console.warn(
|
|
2635
|
-
"[FloTrace] WebSocket not connected, cannot send tree snapshot"
|
|
2636
|
-
);
|
|
3172
|
+
console.warn("[FloTrace] WebSocket not connected, cannot send tree snapshot");
|
|
2637
3173
|
return;
|
|
2638
3174
|
}
|
|
2639
3175
|
const currentFlatTree = flattenTree2(tree);
|
|
@@ -2649,6 +3185,7 @@ function executeSnapshot(root) {
|
|
|
2649
3185
|
"nextInterval:",
|
|
2650
3186
|
snapshotIntervalMs + "ms"
|
|
2651
3187
|
);
|
|
3188
|
+
logTreeSnapshot(tree, `send seq=${snapshotCounter}`);
|
|
2652
3189
|
client2.sendImmediate({
|
|
2653
3190
|
type: "runtime:treeSnapshot",
|
|
2654
3191
|
tree,
|
|
@@ -2669,6 +3206,7 @@ function executeSnapshot(root) {
|
|
|
2669
3206
|
"updated:",
|
|
2670
3207
|
diff.updated.length
|
|
2671
3208
|
);
|
|
3209
|
+
logTreeSummary(tree, `diff seq=${diffSeq}`);
|
|
2672
3210
|
client2.sendImmediate({
|
|
2673
3211
|
type: "runtime:treeDiff",
|
|
2674
3212
|
seq: diffSeq,
|
|
@@ -2809,9 +3347,7 @@ function installFiberTreeWalker(options = {}) {
|
|
|
2809
3347
|
return () => uninstallFiberTreeWalker();
|
|
2810
3348
|
}
|
|
2811
3349
|
if (typeof window === "undefined") {
|
|
2812
|
-
console.warn(
|
|
2813
|
-
"[FloTrace] Not in browser environment, cannot install fiber tree walker"
|
|
2814
|
-
);
|
|
3350
|
+
console.warn("[FloTrace] Not in browser environment, cannot install fiber tree walker");
|
|
2815
3351
|
return () => {
|
|
2816
3352
|
};
|
|
2817
3353
|
}
|
|
@@ -2838,10 +3374,7 @@ function installFiberTreeWalker(options = {}) {
|
|
|
2838
3374
|
try {
|
|
2839
3375
|
originalOnCommitFiberRoot(rendererID, root, priority);
|
|
2840
3376
|
} catch (error) {
|
|
2841
|
-
console.error(
|
|
2842
|
-
"[FloTrace] Error in original onCommitFiberRoot:",
|
|
2843
|
-
error
|
|
2844
|
-
);
|
|
3377
|
+
console.error("[FloTrace] Error in original onCommitFiberRoot:", error);
|
|
2845
3378
|
}
|
|
2846
3379
|
}
|
|
2847
3380
|
if (hookedRendererID === null) {
|
|
@@ -2867,9 +3400,7 @@ function installFiberTreeWalker(options = {}) {
|
|
|
2867
3400
|
scheduleSnapshot(root);
|
|
2868
3401
|
};
|
|
2869
3402
|
activeStrategy = "devtools";
|
|
2870
|
-
console.log(
|
|
2871
|
-
"[FloTrace] Fiber tree walker installed (DevTools hook strategy)"
|
|
2872
|
-
);
|
|
3403
|
+
console.log("[FloTrace] Fiber tree walker installed (DevTools hook strategy)");
|
|
2873
3404
|
setTimeout(() => {
|
|
2874
3405
|
try {
|
|
2875
3406
|
const root = findFiberRootFromDOM();
|
|
@@ -2882,9 +3413,7 @@ function installFiberTreeWalker(options = {}) {
|
|
|
2882
3413
|
}, 100);
|
|
2883
3414
|
} else {
|
|
2884
3415
|
activeStrategy = "dom";
|
|
2885
|
-
console.log(
|
|
2886
|
-
"[FloTrace] Fiber tree walker installed (DOM fallback strategy)"
|
|
2887
|
-
);
|
|
3416
|
+
console.log("[FloTrace] Fiber tree walker installed (DOM fallback strategy)");
|
|
2888
3417
|
setTimeout(() => {
|
|
2889
3418
|
try {
|
|
2890
3419
|
const root = findFiberRootFromDOM();
|
|
@@ -3162,12 +3691,18 @@ function installZustandTracker(stores, client2) {
|
|
|
3162
3691
|
try {
|
|
3163
3692
|
scheduleStoreUpdate(storeName, prevState, newState, client2);
|
|
3164
3693
|
} catch (error) {
|
|
3165
|
-
console.error(
|
|
3694
|
+
console.error(
|
|
3695
|
+
`[FloTrace] Error in Zustand subscribe callback for "${storeName}":`,
|
|
3696
|
+
error
|
|
3697
|
+
);
|
|
3166
3698
|
}
|
|
3167
3699
|
});
|
|
3168
3700
|
activeUnsubscribers.push(unsubscribe);
|
|
3169
3701
|
} catch (error) {
|
|
3170
|
-
console.error(
|
|
3702
|
+
console.error(
|
|
3703
|
+
`[FloTrace] Failed to install tracker for Zustand store "${storeName}":`,
|
|
3704
|
+
error
|
|
3705
|
+
);
|
|
3171
3706
|
}
|
|
3172
3707
|
}
|
|
3173
3708
|
}
|
|
@@ -3210,10 +3745,13 @@ function scheduleStoreUpdate(storeName, prevState, newState, client2) {
|
|
|
3210
3745
|
if (changedKeys.length === 0) return;
|
|
3211
3746
|
const existing = debounceTimers.get(storeName);
|
|
3212
3747
|
if (existing) clearTimeout(existing);
|
|
3213
|
-
debounceTimers.set(
|
|
3214
|
-
|
|
3215
|
-
|
|
3216
|
-
|
|
3748
|
+
debounceTimers.set(
|
|
3749
|
+
storeName,
|
|
3750
|
+
setTimeout(() => {
|
|
3751
|
+
debounceTimers.delete(storeName);
|
|
3752
|
+
sendStoreUpdate(storeName, newState, changedKeys, client2);
|
|
3753
|
+
}, DEBOUNCE_MS)
|
|
3754
|
+
);
|
|
3217
3755
|
}
|
|
3218
3756
|
function sendStoreUpdate(storeName, state, changedKeys, client2) {
|
|
3219
3757
|
try {
|
|
@@ -3730,7 +4268,6 @@ function safeCall(fn, fallback) {
|
|
|
3730
4268
|
|
|
3731
4269
|
// src/valueTraceResolver.ts
|
|
3732
4270
|
var FIBER_TAG_CONTEXT_PROVIDER = 10;
|
|
3733
|
-
var BUDGET_MS = 100;
|
|
3734
4271
|
var SCAN_DEPTH = 3;
|
|
3735
4272
|
var MAX_PROP_CHAIN_DEPTH = 30;
|
|
3736
4273
|
function now() {
|
|
@@ -3777,8 +4314,7 @@ function findReferenceMatchAtTopLevel(target, container) {
|
|
|
3777
4314
|
}
|
|
3778
4315
|
return null;
|
|
3779
4316
|
}
|
|
3780
|
-
function findMatchingPathInObject(target, targetFp, container, currentPath, depth,
|
|
3781
|
-
if (now() > deadline) return null;
|
|
4317
|
+
function findMatchingPathInObject(target, targetFp, container, currentPath, depth, cache) {
|
|
3782
4318
|
if (depth > SCAN_DEPTH) return null;
|
|
3783
4319
|
if (container === null || typeof container !== "object") return null;
|
|
3784
4320
|
const selfMatch = valuesMatch(target, targetFp, container, cache);
|
|
@@ -3788,7 +4324,14 @@ function findMatchingPathInObject(target, targetFp, container, currentPath, dept
|
|
|
3788
4324
|
const child = container[i];
|
|
3789
4325
|
const directMatch = valuesMatch(target, targetFp, child, cache);
|
|
3790
4326
|
if (directMatch) return { path: [...currentPath, String(i)], confidence: directMatch };
|
|
3791
|
-
const nested = findMatchingPathInObject(
|
|
4327
|
+
const nested = findMatchingPathInObject(
|
|
4328
|
+
target,
|
|
4329
|
+
targetFp,
|
|
4330
|
+
child,
|
|
4331
|
+
[...currentPath, String(i)],
|
|
4332
|
+
depth + 1,
|
|
4333
|
+
cache
|
|
4334
|
+
);
|
|
3792
4335
|
if (nested) return nested;
|
|
3793
4336
|
}
|
|
3794
4337
|
} else {
|
|
@@ -3796,7 +4339,14 @@ function findMatchingPathInObject(target, targetFp, container, currentPath, dept
|
|
|
3796
4339
|
const child = container[key];
|
|
3797
4340
|
const directMatch = valuesMatch(target, targetFp, child, cache);
|
|
3798
4341
|
if (directMatch) return { path: [...currentPath, key], confidence: directMatch };
|
|
3799
|
-
const nested = findMatchingPathInObject(
|
|
4342
|
+
const nested = findMatchingPathInObject(
|
|
4343
|
+
target,
|
|
4344
|
+
targetFp,
|
|
4345
|
+
child,
|
|
4346
|
+
[...currentPath, key],
|
|
4347
|
+
depth + 1,
|
|
4348
|
+
cache
|
|
4349
|
+
);
|
|
3800
4350
|
if (nested) return nested;
|
|
3801
4351
|
}
|
|
3802
4352
|
}
|
|
@@ -3863,8 +4413,6 @@ function resolveOriginViaTagOrKeyPath(matchedValue, stateRoot, keyPath) {
|
|
|
3863
4413
|
return findFetchOrigin(matchedValue, { ignoreTTL: true }) ?? findFetchOriginUpKeyPath(stateRoot, keyPath);
|
|
3864
4414
|
}
|
|
3865
4415
|
function resolveValueTrace(input) {
|
|
3866
|
-
const startedAt = now();
|
|
3867
|
-
const deadline = startedAt + BUDGET_MS;
|
|
3868
4416
|
const steps = [];
|
|
3869
4417
|
const base = {
|
|
3870
4418
|
rootNodeId: input.nodeId,
|
|
@@ -3903,7 +4451,12 @@ function resolveValueTrace(input) {
|
|
|
3903
4451
|
nodeId: input.nodeId,
|
|
3904
4452
|
componentName: rootComponentName,
|
|
3905
4453
|
propPath: input.propPath,
|
|
3906
|
-
confidence: "exact"
|
|
4454
|
+
confidence: "exact",
|
|
4455
|
+
// P6: `fiber.memoizedProps[FLOTRACE_SOURCE]` is the JSX call site where
|
|
4456
|
+
// this fiber was created — i.e., the `<Consumer .../>` JSX in the
|
|
4457
|
+
// PARENT's source file. That's exactly the "drilled from `Parent.tsx:42`"
|
|
4458
|
+
// attribution the user wants on the leaf prop step.
|
|
4459
|
+
callSiteOfParentJsx: readJsxSourceFromFiber(fiber)
|
|
3907
4460
|
});
|
|
3908
4461
|
} else if (input.hookPath) {
|
|
3909
4462
|
steps.push({
|
|
@@ -3921,7 +4474,6 @@ function resolveValueTrace(input) {
|
|
|
3921
4474
|
let current = fiber.return;
|
|
3922
4475
|
let hops = 0;
|
|
3923
4476
|
while (current && hops < MAX_PROP_CHAIN_DEPTH) {
|
|
3924
|
-
if (now() > deadline) return { ...base, steps, truncated: true, resolvedAtMs: now() };
|
|
3925
4477
|
if (current.tag !== FIBER_TAG_CONTEXT_PROVIDER) {
|
|
3926
4478
|
const props = current.memoizedProps;
|
|
3927
4479
|
if (props) {
|
|
@@ -3929,7 +4481,7 @@ function resolveValueTrace(input) {
|
|
|
3929
4481
|
let matchPath = refKey !== null ? [refKey] : null;
|
|
3930
4482
|
let matchConfidence = "exact";
|
|
3931
4483
|
if (matchPath === null) {
|
|
3932
|
-
const match = findMatchingPathInObject(rootValue, rootFp, props, [], 0,
|
|
4484
|
+
const match = findMatchingPathInObject(rootValue, rootFp, props, [], 0, fpCache);
|
|
3933
4485
|
if (match) {
|
|
3934
4486
|
matchPath = match.path;
|
|
3935
4487
|
matchConfidence = match.confidence;
|
|
@@ -3944,7 +4496,12 @@ function resolveValueTrace(input) {
|
|
|
3944
4496
|
nodeId: ancestorNodeId,
|
|
3945
4497
|
componentName: ancestorName,
|
|
3946
4498
|
propPath: trailingSubPath.length > 0 ? [...matchPath, ...trailingSubPath] : matchPath,
|
|
3947
|
-
confidence: matchConfidence
|
|
4499
|
+
confidence: matchConfidence,
|
|
4500
|
+
// P6: attribute the parent JSX call site that drilled this
|
|
4501
|
+
// prop. When the user opted into the JSX runtime AND this
|
|
4502
|
+
// ancestor's fiber went through jsxDEV, the consumer sees
|
|
4503
|
+
// "drilled from `Parent.tsx:42:8`" with a click-to-IDE link.
|
|
4504
|
+
callSiteOfParentJsx: readJsxSourceFromFiber(current)
|
|
3948
4505
|
});
|
|
3949
4506
|
}
|
|
3950
4507
|
} else {
|
|
@@ -3993,7 +4550,11 @@ function resolveValueTrace(input) {
|
|
|
3993
4550
|
const contextMatch = findContextMatch(fiber, rootValue, rootFp, fiberToNodeId, fpCache);
|
|
3994
4551
|
if (contextMatch) {
|
|
3995
4552
|
steps.push(contextMatch.step);
|
|
3996
|
-
const providerStoreMatch = findStoreMatch(
|
|
4553
|
+
const providerStoreMatch = findStoreMatch(
|
|
4554
|
+
contextMatch.providerValue,
|
|
4555
|
+
cachedFp(contextMatch.providerValue, fpCache),
|
|
4556
|
+
fpCache
|
|
4557
|
+
);
|
|
3997
4558
|
if (providerStoreMatch) {
|
|
3998
4559
|
steps.push({
|
|
3999
4560
|
kind: "store",
|
|
@@ -4018,7 +4579,7 @@ function resolveValueTrace(input) {
|
|
|
4018
4579
|
}
|
|
4019
4580
|
return { ...base, steps, resolvedAtMs: now() };
|
|
4020
4581
|
}
|
|
4021
|
-
const storeMatch = findStoreMatch(rootValue, rootFp,
|
|
4582
|
+
const storeMatch = findStoreMatch(rootValue, rootFp, fpCache);
|
|
4022
4583
|
if (storeMatch) {
|
|
4023
4584
|
steps.push({
|
|
4024
4585
|
kind: "store",
|
|
@@ -4123,10 +4684,9 @@ function findNearestProvider(consumer, contextObj) {
|
|
|
4123
4684
|
}
|
|
4124
4685
|
return null;
|
|
4125
4686
|
}
|
|
4126
|
-
function findStoreMatch(target, targetFp,
|
|
4687
|
+
function findStoreMatch(target, targetFp, cache) {
|
|
4127
4688
|
for (const [storeName, state] of getZustandSnapshot()) {
|
|
4128
|
-
|
|
4129
|
-
const hit = findMatchingPathInObject(target, targetFp, state, [], 0, deadline, cache);
|
|
4689
|
+
const hit = findMatchingPathInObject(target, targetFp, state, [], 0, cache);
|
|
4130
4690
|
if (hit) {
|
|
4131
4691
|
return {
|
|
4132
4692
|
source: "zustand",
|
|
@@ -4140,8 +4700,7 @@ function findStoreMatch(target, targetFp, deadline, cache) {
|
|
|
4140
4700
|
}
|
|
4141
4701
|
const redux = getReduxSnapshot();
|
|
4142
4702
|
if (redux) {
|
|
4143
|
-
|
|
4144
|
-
const hit = findMatchingPathInObject(target, targetFp, redux, [], 0, deadline, cache);
|
|
4703
|
+
const hit = findMatchingPathInObject(target, targetFp, redux, [], 0, cache);
|
|
4145
4704
|
if (hit) {
|
|
4146
4705
|
return {
|
|
4147
4706
|
source: "redux",
|
|
@@ -4154,8 +4713,7 @@ function findStoreMatch(target, targetFp, deadline, cache) {
|
|
|
4154
4713
|
}
|
|
4155
4714
|
}
|
|
4156
4715
|
for (const [queryHash, entry] of getTanstackSnapshot()) {
|
|
4157
|
-
|
|
4158
|
-
const hit = findMatchingPathInObject(target, targetFp, entry.data, [], 0, deadline, cache);
|
|
4716
|
+
const hit = findMatchingPathInObject(target, targetFp, entry.data, [], 0, cache);
|
|
4159
4717
|
if (hit) {
|
|
4160
4718
|
return {
|
|
4161
4719
|
source: "tanstack-query",
|
|
@@ -4190,13 +4748,22 @@ function detectWebFramework() {
|
|
|
4190
4748
|
// Annotate the CommonJS export names for ESM import in node:
|
|
4191
4749
|
0 && (module.exports = {
|
|
4192
4750
|
DEFAULT_CONFIG,
|
|
4751
|
+
FLOTRACE_SOURCE,
|
|
4193
4752
|
FloTraceWebSocketClient,
|
|
4753
|
+
JSX_RUNTIME_ACTIVE_KEY,
|
|
4194
4754
|
buildAncestorChain,
|
|
4755
|
+
clearCallSiteRenders,
|
|
4195
4756
|
clearFetchOriginTags,
|
|
4757
|
+
computeCallSiteId,
|
|
4758
|
+
computeCallSiteMetricsPayload,
|
|
4759
|
+
describeFiberType,
|
|
4760
|
+
detectInlineLiterals,
|
|
4196
4761
|
detectServerComponent,
|
|
4197
4762
|
detectWebFramework,
|
|
4198
4763
|
disposeWebSocketClient,
|
|
4199
4764
|
findFetchOrigin,
|
|
4765
|
+
getCallSiteRenderRate,
|
|
4766
|
+
getCallSiteRenders,
|
|
4200
4767
|
getChangedKeys,
|
|
4201
4768
|
getComponentNameFromFiber,
|
|
4202
4769
|
getCurrentRenderingFiber,
|
|
@@ -4219,9 +4786,15 @@ function detectWebFramework() {
|
|
|
4219
4786
|
installTanStackQueryTracker,
|
|
4220
4787
|
installTimelineTracker,
|
|
4221
4788
|
installZustandTracker,
|
|
4789
|
+
isJsxRuntimeActive,
|
|
4222
4790
|
isReduxStore,
|
|
4223
4791
|
isTanStackQueryClient,
|
|
4792
|
+
logTreeSnapshot,
|
|
4793
|
+
logTreeSummary,
|
|
4794
|
+
markJsxRuntimeActive,
|
|
4224
4795
|
maybeEmitNextjsContext,
|
|
4796
|
+
normalizeJsxSourcePath,
|
|
4797
|
+
recordCallSiteRender,
|
|
4225
4798
|
recordTimelineEvent,
|
|
4226
4799
|
requestFullSnapshot,
|
|
4227
4800
|
requestTreeSnapshot,
|
|
@@ -4229,6 +4802,8 @@ function detectWebFramework() {
|
|
|
4229
4802
|
resolveValueTrace,
|
|
4230
4803
|
serializeProps,
|
|
4231
4804
|
serializeValue,
|
|
4805
|
+
setDuplicateKeyEmitter,
|
|
4806
|
+
setFiberDebug,
|
|
4232
4807
|
tagFetchData,
|
|
4233
4808
|
uninstallFiberTreeWalker,
|
|
4234
4809
|
uninstallReduxTracker,
|