@flotrace/runtime-core 2.0.1 → 2.2.1
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/index.d.mts +173 -2
- package/dist/index.d.ts +173 -2
- package/dist/index.js +370 -8
- package/dist/index.mjs +366 -8
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -1551,8 +1551,8 @@ function runAnalysis(tree, fiberRefMap2) {
|
|
|
1551
1551
|
}
|
|
1552
1552
|
function schedulePropDrillingAnalysis(tree, fiberRefMap2, client2) {
|
|
1553
1553
|
if (analyzeTimer) clearTimeout(analyzeTimer);
|
|
1554
|
-
const
|
|
1555
|
-
const elapsed =
|
|
1554
|
+
const now2 = Date.now();
|
|
1555
|
+
const elapsed = now2 - lastAnalysisTime;
|
|
1556
1556
|
const delay = elapsed >= ANALYZE_INTERVAL_MS ? 0 : ANALYZE_INTERVAL_MS - elapsed;
|
|
1557
1557
|
analyzeTimer = setTimeout(() => {
|
|
1558
1558
|
analyzeTimer = null;
|
|
@@ -2579,7 +2579,7 @@ function executeSnapshot(root) {
|
|
|
2579
2579
|
}
|
|
2580
2580
|
previousFlatTree = currentFlatTree;
|
|
2581
2581
|
if (pendingLocalStateCorrelations.length > 0) {
|
|
2582
|
-
const
|
|
2582
|
+
const now2 = Date.now();
|
|
2583
2583
|
const toSend = pendingLocalStateCorrelations.splice(0);
|
|
2584
2584
|
for (const corr of toSend) {
|
|
2585
2585
|
try {
|
|
@@ -2588,7 +2588,7 @@ function executeSnapshot(root) {
|
|
|
2588
2588
|
requestId: corr.requestId,
|
|
2589
2589
|
componentName: corr.componentName,
|
|
2590
2590
|
hookIndex: corr.hookIndex,
|
|
2591
|
-
timestamp:
|
|
2591
|
+
timestamp: now2
|
|
2592
2592
|
});
|
|
2593
2593
|
} catch {
|
|
2594
2594
|
}
|
|
@@ -3033,6 +3033,7 @@ var activeUnsubscribers = [];
|
|
|
3033
3033
|
var isInstalled4 = false;
|
|
3034
3034
|
var debounceTimers = /* @__PURE__ */ new Map();
|
|
3035
3035
|
var DEBOUNCE_MS = 200;
|
|
3036
|
+
var trackedStores = /* @__PURE__ */ new Map();
|
|
3036
3037
|
function installZustandTracker(stores, client2) {
|
|
3037
3038
|
if (isInstalled4) {
|
|
3038
3039
|
console.warn("[FloTrace] Zustand tracker already installed, reinstalling");
|
|
@@ -3048,6 +3049,7 @@ function installZustandTracker(stores, client2) {
|
|
|
3048
3049
|
continue;
|
|
3049
3050
|
}
|
|
3050
3051
|
try {
|
|
3052
|
+
trackedStores.set(storeName, store);
|
|
3051
3053
|
const initialState = store.getState();
|
|
3052
3054
|
sendStoreUpdate(storeName, initialState, Object.keys(initialState), client2);
|
|
3053
3055
|
const unsubscribe = store.subscribe((newState, prevState) => {
|
|
@@ -3077,9 +3079,20 @@ function uninstallZustandTracker() {
|
|
|
3077
3079
|
}
|
|
3078
3080
|
}
|
|
3079
3081
|
activeUnsubscribers = [];
|
|
3082
|
+
trackedStores.clear();
|
|
3080
3083
|
isInstalled4 = false;
|
|
3081
3084
|
console.log("[FloTrace] Zustand tracker uninstalled");
|
|
3082
3085
|
}
|
|
3086
|
+
function getZustandSnapshot() {
|
|
3087
|
+
const snapshot = /* @__PURE__ */ new Map();
|
|
3088
|
+
for (const [name, store] of trackedStores) {
|
|
3089
|
+
try {
|
|
3090
|
+
snapshot.set(name, store.getState());
|
|
3091
|
+
} catch {
|
|
3092
|
+
}
|
|
3093
|
+
}
|
|
3094
|
+
return snapshot;
|
|
3095
|
+
}
|
|
3083
3096
|
function scheduleStoreUpdate(storeName, prevState, newState, client2) {
|
|
3084
3097
|
let changedKeys;
|
|
3085
3098
|
try {
|
|
@@ -3118,6 +3131,7 @@ var isInstalled5 = false;
|
|
|
3118
3131
|
var debounceTimer = null;
|
|
3119
3132
|
var previousState = null;
|
|
3120
3133
|
var DEBOUNCE_MS2 = 200;
|
|
3134
|
+
var trackedStore = null;
|
|
3121
3135
|
function isReduxStore(obj) {
|
|
3122
3136
|
return typeof obj === "object" && obj !== null && typeof obj.getState === "function" && typeof obj.subscribe === "function" && typeof obj.dispatch === "function";
|
|
3123
3137
|
}
|
|
@@ -3129,6 +3143,7 @@ function installReduxTracker(store, client2) {
|
|
|
3129
3143
|
isInstalled5 = true;
|
|
3130
3144
|
console.log("[FloTrace] Installing Redux tracker");
|
|
3131
3145
|
try {
|
|
3146
|
+
trackedStore = store;
|
|
3132
3147
|
const initialState = store.getState();
|
|
3133
3148
|
previousState = initialState;
|
|
3134
3149
|
sendReduxUpdate(initialState, Object.keys(initialState), client2);
|
|
@@ -3160,9 +3175,18 @@ function uninstallReduxTracker() {
|
|
|
3160
3175
|
activeUnsubscribe = null;
|
|
3161
3176
|
}
|
|
3162
3177
|
previousState = null;
|
|
3178
|
+
trackedStore = null;
|
|
3163
3179
|
isInstalled5 = false;
|
|
3164
3180
|
console.log("[FloTrace] Redux tracker uninstalled");
|
|
3165
3181
|
}
|
|
3182
|
+
function getReduxSnapshot() {
|
|
3183
|
+
if (!trackedStore) return null;
|
|
3184
|
+
try {
|
|
3185
|
+
return trackedStore.getState();
|
|
3186
|
+
} catch {
|
|
3187
|
+
return null;
|
|
3188
|
+
}
|
|
3189
|
+
}
|
|
3166
3190
|
function scheduleReduxUpdate(newState, client2) {
|
|
3167
3191
|
let changedKeys;
|
|
3168
3192
|
try {
|
|
@@ -3200,6 +3224,7 @@ var queryUnsubscribe = null;
|
|
|
3200
3224
|
var mutationUnsubscribe = null;
|
|
3201
3225
|
var debounceTimer2 = null;
|
|
3202
3226
|
var DEBOUNCE_MS3 = 300;
|
|
3227
|
+
var trackedClient = null;
|
|
3203
3228
|
var MAX_EVENTS_PER_QUERY = 50;
|
|
3204
3229
|
var queryTracking = /* @__PURE__ */ new Map();
|
|
3205
3230
|
var CORRELATION_WINDOW_MS = 500;
|
|
@@ -3222,6 +3247,7 @@ function installTanStackQueryTracker(queryClient, client2) {
|
|
|
3222
3247
|
isInstalled6 = true;
|
|
3223
3248
|
console.log("[FloTrace] Installing TanStack Query tracker");
|
|
3224
3249
|
try {
|
|
3250
|
+
trackedClient = queryClient;
|
|
3225
3251
|
const queryCache = queryClient.getQueryCache();
|
|
3226
3252
|
const mutationCache = queryClient.getMutationCache();
|
|
3227
3253
|
for (const query of queryCache.getAll()) {
|
|
@@ -3286,9 +3312,24 @@ function uninstallTanStackQueryTracker() {
|
|
|
3286
3312
|
clearTimeout(pending.timeoutId);
|
|
3287
3313
|
}
|
|
3288
3314
|
pendingCorrelations.clear();
|
|
3315
|
+
trackedClient = null;
|
|
3289
3316
|
isInstalled6 = false;
|
|
3290
3317
|
console.log("[FloTrace] TanStack Query tracker uninstalled");
|
|
3291
3318
|
}
|
|
3319
|
+
function getTanstackSnapshot() {
|
|
3320
|
+
const snapshot = /* @__PURE__ */ new Map();
|
|
3321
|
+
if (!trackedClient) return snapshot;
|
|
3322
|
+
try {
|
|
3323
|
+
const queryCache = trackedClient.getQueryCache();
|
|
3324
|
+
for (const query of queryCache.getAll()) {
|
|
3325
|
+
if (query.state.data !== void 0) {
|
|
3326
|
+
snapshot.set(query.queryHash, { queryKey: query.queryKey, data: query.state.data });
|
|
3327
|
+
}
|
|
3328
|
+
}
|
|
3329
|
+
} catch {
|
|
3330
|
+
}
|
|
3331
|
+
return snapshot;
|
|
3332
|
+
}
|
|
3292
3333
|
function computeDataHash(data) {
|
|
3293
3334
|
if (data === null || data === void 0) return "__null__";
|
|
3294
3335
|
try {
|
|
@@ -3351,11 +3392,11 @@ function updateQueryTracking(query, eventType) {
|
|
|
3351
3392
|
}
|
|
3352
3393
|
}
|
|
3353
3394
|
if (tracking.prevFetchStatus === "idle" && currentFetchStatus === "fetching") {
|
|
3354
|
-
const
|
|
3395
|
+
const now2 = Date.now();
|
|
3355
3396
|
for (const pending of pendingCorrelations.values()) {
|
|
3356
3397
|
if (pending.idleQueryHashes.has(query.queryHash)) {
|
|
3357
3398
|
pending.affectedQueries.set(query.queryHash, {
|
|
3358
|
-
fetchStartedAt:
|
|
3399
|
+
fetchStartedAt: now2,
|
|
3359
3400
|
queryKey: query.queryKey
|
|
3360
3401
|
});
|
|
3361
3402
|
}
|
|
@@ -3367,7 +3408,7 @@ function updateQueryTracking(query, eventType) {
|
|
|
3367
3408
|
}
|
|
3368
3409
|
function openCorrelationWindow(mutation, queryCache, mutationCache, client2) {
|
|
3369
3410
|
const correlationId = `corr-${++correlationCounter}`;
|
|
3370
|
-
const
|
|
3411
|
+
const now2 = Date.now();
|
|
3371
3412
|
const idleQueryHashes = /* @__PURE__ */ new Set();
|
|
3372
3413
|
for (const query of queryCache.getAll()) {
|
|
3373
3414
|
if (query.state.fetchStatus === "idle") {
|
|
@@ -3381,7 +3422,7 @@ function openCorrelationWindow(mutation, queryCache, mutationCache, client2) {
|
|
|
3381
3422
|
correlationId,
|
|
3382
3423
|
mutationId: mutation.mutationId,
|
|
3383
3424
|
mutationKey: mutation.options.mutationKey,
|
|
3384
|
-
completedAt:
|
|
3425
|
+
completedAt: now2,
|
|
3385
3426
|
idleQueryHashes,
|
|
3386
3427
|
affectedQueries: /* @__PURE__ */ new Map(),
|
|
3387
3428
|
timeoutId
|
|
@@ -3581,6 +3622,319 @@ function safeCall(fn, fallback) {
|
|
|
3581
3622
|
}
|
|
3582
3623
|
}
|
|
3583
3624
|
|
|
3625
|
+
// src/valueTraceResolver.ts
|
|
3626
|
+
var FIBER_TAG_CONTEXT_PROVIDER = 10;
|
|
3627
|
+
var BUDGET_MS = 50;
|
|
3628
|
+
var SCAN_DEPTH = 3;
|
|
3629
|
+
var MAX_PROP_CHAIN_DEPTH = 30;
|
|
3630
|
+
function now() {
|
|
3631
|
+
return typeof performance !== "undefined" && typeof performance.now === "function" ? performance.now() : Date.now();
|
|
3632
|
+
}
|
|
3633
|
+
function walkPath(root, path) {
|
|
3634
|
+
let cur = root;
|
|
3635
|
+
for (const key of path) {
|
|
3636
|
+
if (cur === null || cur === void 0 || typeof cur !== "object") return void 0;
|
|
3637
|
+
cur = cur[key];
|
|
3638
|
+
}
|
|
3639
|
+
return cur;
|
|
3640
|
+
}
|
|
3641
|
+
function getHookValueAt(fiber, hookIndex) {
|
|
3642
|
+
let hook = fiber.memoizedState;
|
|
3643
|
+
let i = 0;
|
|
3644
|
+
while (hook && i < hookIndex) {
|
|
3645
|
+
hook = hook.next;
|
|
3646
|
+
i++;
|
|
3647
|
+
}
|
|
3648
|
+
if (!hook) return void 0;
|
|
3649
|
+
return hook.memoizedState;
|
|
3650
|
+
}
|
|
3651
|
+
function valuesMatch(target, targetFp, candidate) {
|
|
3652
|
+
const targetIsObject = target !== null && typeof target === "object";
|
|
3653
|
+
const candidateIsObject = candidate !== null && typeof candidate === "object";
|
|
3654
|
+
if (targetIsObject && candidateIsObject && target === candidate) return "exact";
|
|
3655
|
+
if (!shouldFlagRename(target) || !shouldFlagRename(candidate)) return null;
|
|
3656
|
+
if (valueFingerprint(candidate) === targetFp) return "fingerprint-match";
|
|
3657
|
+
return null;
|
|
3658
|
+
}
|
|
3659
|
+
function findMatchingPathInObject(target, targetFp, container, currentPath, depth, deadline) {
|
|
3660
|
+
if (now() > deadline) return null;
|
|
3661
|
+
if (depth > SCAN_DEPTH) return null;
|
|
3662
|
+
if (container === null || typeof container !== "object") return null;
|
|
3663
|
+
const selfMatch = valuesMatch(target, targetFp, container);
|
|
3664
|
+
if (selfMatch) return { path: [...currentPath], confidence: selfMatch };
|
|
3665
|
+
if (Array.isArray(container)) {
|
|
3666
|
+
for (let i = 0; i < Math.min(container.length, 50); i++) {
|
|
3667
|
+
const child = container[i];
|
|
3668
|
+
const directMatch = valuesMatch(target, targetFp, child);
|
|
3669
|
+
if (directMatch) return { path: [...currentPath, String(i)], confidence: directMatch };
|
|
3670
|
+
const nested = findMatchingPathInObject(target, targetFp, child, [...currentPath, String(i)], depth + 1, deadline);
|
|
3671
|
+
if (nested) return nested;
|
|
3672
|
+
}
|
|
3673
|
+
} else {
|
|
3674
|
+
for (const key of Object.keys(container)) {
|
|
3675
|
+
const child = container[key];
|
|
3676
|
+
const directMatch = valuesMatch(target, targetFp, child);
|
|
3677
|
+
if (directMatch) return { path: [...currentPath, key], confidence: directMatch };
|
|
3678
|
+
const nested = findMatchingPathInObject(target, targetFp, child, [...currentPath, key], depth + 1, deadline);
|
|
3679
|
+
if (nested) return nested;
|
|
3680
|
+
}
|
|
3681
|
+
}
|
|
3682
|
+
return null;
|
|
3683
|
+
}
|
|
3684
|
+
function buildFiberToNodeIdMap() {
|
|
3685
|
+
const reverse = /* @__PURE__ */ new Map();
|
|
3686
|
+
for (const [nodeId, fiber] of getFiberRefMap()) {
|
|
3687
|
+
reverse.set(fiber, nodeId);
|
|
3688
|
+
}
|
|
3689
|
+
return reverse;
|
|
3690
|
+
}
|
|
3691
|
+
function resolveValueTrace(input) {
|
|
3692
|
+
const startedAt = now();
|
|
3693
|
+
const deadline = startedAt + BUDGET_MS;
|
|
3694
|
+
const steps = [];
|
|
3695
|
+
const base = {
|
|
3696
|
+
rootNodeId: input.nodeId,
|
|
3697
|
+
rootPropPath: input.propPath,
|
|
3698
|
+
rootHookPath: input.hookPath,
|
|
3699
|
+
steps,
|
|
3700
|
+
resolvedAtMs: now()
|
|
3701
|
+
};
|
|
3702
|
+
const fiber = getFiberRefMap().get(input.nodeId);
|
|
3703
|
+
if (!fiber) {
|
|
3704
|
+
return { ...base, error: "no-fiber", resolvedAtMs: now() };
|
|
3705
|
+
}
|
|
3706
|
+
let rootValue;
|
|
3707
|
+
if (input.propPath && input.propPath.length > 0) {
|
|
3708
|
+
if (!fiber.memoizedProps) return { ...base, error: "value-not-found", resolvedAtMs: now() };
|
|
3709
|
+
rootValue = walkPath(fiber.memoizedProps, input.propPath);
|
|
3710
|
+
} else if (input.hookPath) {
|
|
3711
|
+
const hookValue = getHookValueAt(fiber, input.hookPath.hookIndex);
|
|
3712
|
+
rootValue = input.hookPath.subPath && input.hookPath.subPath.length > 0 ? walkPath(hookValue, input.hookPath.subPath) : hookValue;
|
|
3713
|
+
} else {
|
|
3714
|
+
return { ...base, error: "value-not-found", resolvedAtMs: now() };
|
|
3715
|
+
}
|
|
3716
|
+
if (rootValue === void 0) {
|
|
3717
|
+
return { ...base, error: "value-not-found", resolvedAtMs: now() };
|
|
3718
|
+
}
|
|
3719
|
+
const rootFp = valueFingerprint(rootValue);
|
|
3720
|
+
const fiberToNodeId = buildFiberToNodeIdMap();
|
|
3721
|
+
const rootComponentName = getComponentNameFromFiber(fiber) ?? "Unknown";
|
|
3722
|
+
if (input.propPath) {
|
|
3723
|
+
steps.push({
|
|
3724
|
+
kind: "prop",
|
|
3725
|
+
nodeId: input.nodeId,
|
|
3726
|
+
componentName: rootComponentName,
|
|
3727
|
+
propPath: input.propPath,
|
|
3728
|
+
confidence: "exact"
|
|
3729
|
+
});
|
|
3730
|
+
} else if (input.hookPath) {
|
|
3731
|
+
steps.push({
|
|
3732
|
+
kind: "hook-state",
|
|
3733
|
+
nodeId: input.nodeId,
|
|
3734
|
+
componentName: rootComponentName,
|
|
3735
|
+
hookIndex: input.hookPath.hookIndex,
|
|
3736
|
+
hookType: "unknown",
|
|
3737
|
+
// Cheap: full hook classification is expensive; caller can fetch separately.
|
|
3738
|
+
subPath: input.hookPath.subPath,
|
|
3739
|
+
confidence: "exact"
|
|
3740
|
+
});
|
|
3741
|
+
}
|
|
3742
|
+
if (input.propPath) {
|
|
3743
|
+
let current = fiber.return;
|
|
3744
|
+
let hops = 0;
|
|
3745
|
+
while (current && hops < MAX_PROP_CHAIN_DEPTH) {
|
|
3746
|
+
if (now() > deadline) return { ...base, steps, truncated: true, resolvedAtMs: now() };
|
|
3747
|
+
if (current.tag !== FIBER_TAG_CONTEXT_PROVIDER) {
|
|
3748
|
+
const props = current.memoizedProps;
|
|
3749
|
+
if (props) {
|
|
3750
|
+
const match = findMatchingPathInObject(rootValue, rootFp, props, [], 0, deadline);
|
|
3751
|
+
if (match) {
|
|
3752
|
+
const ancestorNodeId = fiberToNodeId.get(current);
|
|
3753
|
+
const ancestorName = getComponentNameFromFiber(current) ?? "Unknown";
|
|
3754
|
+
if (ancestorNodeId) {
|
|
3755
|
+
steps.push({
|
|
3756
|
+
kind: "prop",
|
|
3757
|
+
nodeId: ancestorNodeId,
|
|
3758
|
+
componentName: ancestorName,
|
|
3759
|
+
propPath: match.path,
|
|
3760
|
+
confidence: match.confidence
|
|
3761
|
+
});
|
|
3762
|
+
}
|
|
3763
|
+
}
|
|
3764
|
+
}
|
|
3765
|
+
}
|
|
3766
|
+
current = current.return;
|
|
3767
|
+
hops++;
|
|
3768
|
+
}
|
|
3769
|
+
}
|
|
3770
|
+
if (input.hookPath) {
|
|
3771
|
+
const origin = findFetchOrigin(rootValue);
|
|
3772
|
+
if (origin) {
|
|
3773
|
+
steps.push({
|
|
3774
|
+
kind: "api",
|
|
3775
|
+
requestId: origin,
|
|
3776
|
+
method: "UNKNOWN",
|
|
3777
|
+
urlPath: "",
|
|
3778
|
+
ageMs: 0
|
|
3779
|
+
});
|
|
3780
|
+
return { ...base, steps, resolvedAtMs: now() };
|
|
3781
|
+
}
|
|
3782
|
+
}
|
|
3783
|
+
const derivedMatch = findDerivationMatch(fiber, rootValue, rootFp, rootComponentName);
|
|
3784
|
+
if (derivedMatch) {
|
|
3785
|
+
steps.push({ ...derivedMatch, nodeId: input.nodeId });
|
|
3786
|
+
return { ...base, steps, resolvedAtMs: now() };
|
|
3787
|
+
}
|
|
3788
|
+
const contextMatch = findContextMatch(fiber, rootValue, rootFp, fiberToNodeId);
|
|
3789
|
+
if (contextMatch) {
|
|
3790
|
+
steps.push(contextMatch.step);
|
|
3791
|
+
const providerStoreMatch = findStoreMatch(contextMatch.providerValue, valueFingerprint(contextMatch.providerValue), deadline);
|
|
3792
|
+
if (providerStoreMatch) {
|
|
3793
|
+
steps.push({
|
|
3794
|
+
kind: "store",
|
|
3795
|
+
source: providerStoreMatch.source,
|
|
3796
|
+
storeName: providerStoreMatch.storeName,
|
|
3797
|
+
keyPath: providerStoreMatch.keyPath,
|
|
3798
|
+
confidence: providerStoreMatch.confidence
|
|
3799
|
+
});
|
|
3800
|
+
const origin = findFetchOrigin(providerStoreMatch.matchedValue);
|
|
3801
|
+
if (origin) {
|
|
3802
|
+
steps.push({ kind: "api", requestId: origin, method: "UNKNOWN", urlPath: "", ageMs: 0 });
|
|
3803
|
+
}
|
|
3804
|
+
} else {
|
|
3805
|
+
const origin = findFetchOrigin(contextMatch.providerValue);
|
|
3806
|
+
if (origin) {
|
|
3807
|
+
steps.push({ kind: "api", requestId: origin, method: "UNKNOWN", urlPath: "", ageMs: 0 });
|
|
3808
|
+
}
|
|
3809
|
+
}
|
|
3810
|
+
return { ...base, steps, resolvedAtMs: now() };
|
|
3811
|
+
}
|
|
3812
|
+
const storeMatch = findStoreMatch(rootValue, rootFp, deadline);
|
|
3813
|
+
if (storeMatch) {
|
|
3814
|
+
steps.push({
|
|
3815
|
+
kind: "store",
|
|
3816
|
+
source: storeMatch.source,
|
|
3817
|
+
storeName: storeMatch.storeName,
|
|
3818
|
+
keyPath: storeMatch.keyPath,
|
|
3819
|
+
confidence: storeMatch.confidence
|
|
3820
|
+
});
|
|
3821
|
+
const origin = findFetchOrigin(storeMatch.matchedValue);
|
|
3822
|
+
if (origin) {
|
|
3823
|
+
steps.push({
|
|
3824
|
+
kind: "api",
|
|
3825
|
+
requestId: origin,
|
|
3826
|
+
method: "UNKNOWN",
|
|
3827
|
+
urlPath: "",
|
|
3828
|
+
ageMs: 0
|
|
3829
|
+
});
|
|
3830
|
+
}
|
|
3831
|
+
}
|
|
3832
|
+
return { ...base, steps, resolvedAtMs: now() };
|
|
3833
|
+
}
|
|
3834
|
+
function findContextMatch(consumer, target, targetFp, fiberToNodeId) {
|
|
3835
|
+
const deps = consumer.dependencies?.firstContext;
|
|
3836
|
+
if (!deps) return null;
|
|
3837
|
+
let dep = deps;
|
|
3838
|
+
while (dep) {
|
|
3839
|
+
const match = valuesMatch(target, targetFp, dep.memoizedValue);
|
|
3840
|
+
if (match) {
|
|
3841
|
+
const provider = findNearestProvider(consumer, dep.context);
|
|
3842
|
+
const step = {
|
|
3843
|
+
kind: "context",
|
|
3844
|
+
contextName: dep.context.displayName || "Context",
|
|
3845
|
+
providerNodeId: provider ? fiberToNodeId.get(provider) : void 0,
|
|
3846
|
+
confidence: match
|
|
3847
|
+
};
|
|
3848
|
+
const providerValue = provider?.memoizedProps?.value ?? dep.memoizedValue;
|
|
3849
|
+
return { step, providerValue };
|
|
3850
|
+
}
|
|
3851
|
+
dep = dep.next;
|
|
3852
|
+
}
|
|
3853
|
+
return null;
|
|
3854
|
+
}
|
|
3855
|
+
function findDerivationMatch(fiber, target, targetFp, componentName) {
|
|
3856
|
+
let hook = fiber.memoizedState;
|
|
3857
|
+
let index = 0;
|
|
3858
|
+
while (hook) {
|
|
3859
|
+
const ms = hook.memoizedState;
|
|
3860
|
+
if (Array.isArray(ms) && ms.length === 2 && Array.isArray(ms[1])) {
|
|
3861
|
+
const [computed, deps] = ms;
|
|
3862
|
+
const match = valuesMatch(target, targetFp, computed);
|
|
3863
|
+
if (match) {
|
|
3864
|
+
const hookType = typeof computed === "function" ? "useCallback" : "useMemo";
|
|
3865
|
+
return {
|
|
3866
|
+
kind: "derived",
|
|
3867
|
+
nodeId: "",
|
|
3868
|
+
componentName,
|
|
3869
|
+
hookIndex: index,
|
|
3870
|
+
hookType,
|
|
3871
|
+
depCount: deps.length,
|
|
3872
|
+
confidence: match
|
|
3873
|
+
};
|
|
3874
|
+
}
|
|
3875
|
+
}
|
|
3876
|
+
hook = hook.next;
|
|
3877
|
+
index++;
|
|
3878
|
+
}
|
|
3879
|
+
return null;
|
|
3880
|
+
}
|
|
3881
|
+
function findNearestProvider(consumer, contextObj) {
|
|
3882
|
+
let current = consumer.return;
|
|
3883
|
+
let hops = 0;
|
|
3884
|
+
while (current && hops < MAX_PROP_CHAIN_DEPTH) {
|
|
3885
|
+
if (current.tag === FIBER_TAG_CONTEXT_PROVIDER) {
|
|
3886
|
+
const providerType = current.type;
|
|
3887
|
+
if (providerType && providerType._context === contextObj) return current;
|
|
3888
|
+
}
|
|
3889
|
+
current = current.return;
|
|
3890
|
+
hops++;
|
|
3891
|
+
}
|
|
3892
|
+
return null;
|
|
3893
|
+
}
|
|
3894
|
+
function findStoreMatch(target, targetFp, deadline) {
|
|
3895
|
+
for (const [storeName, state] of getZustandSnapshot()) {
|
|
3896
|
+
if (now() > deadline) return null;
|
|
3897
|
+
const hit = findMatchingPathInObject(target, targetFp, state, [], 0, deadline);
|
|
3898
|
+
if (hit) {
|
|
3899
|
+
return {
|
|
3900
|
+
source: "zustand",
|
|
3901
|
+
storeName,
|
|
3902
|
+
keyPath: hit.path,
|
|
3903
|
+
confidence: hit.confidence,
|
|
3904
|
+
matchedValue: walkPath(state, hit.path)
|
|
3905
|
+
};
|
|
3906
|
+
}
|
|
3907
|
+
}
|
|
3908
|
+
const redux = getReduxSnapshot();
|
|
3909
|
+
if (redux) {
|
|
3910
|
+
if (now() > deadline) return null;
|
|
3911
|
+
const hit = findMatchingPathInObject(target, targetFp, redux, [], 0, deadline);
|
|
3912
|
+
if (hit) {
|
|
3913
|
+
return {
|
|
3914
|
+
source: "redux",
|
|
3915
|
+
storeName: "redux",
|
|
3916
|
+
keyPath: hit.path,
|
|
3917
|
+
confidence: hit.confidence,
|
|
3918
|
+
matchedValue: walkPath(redux, hit.path)
|
|
3919
|
+
};
|
|
3920
|
+
}
|
|
3921
|
+
}
|
|
3922
|
+
for (const [queryHash, entry] of getTanstackSnapshot()) {
|
|
3923
|
+
if (now() > deadline) return null;
|
|
3924
|
+
const hit = findMatchingPathInObject(target, targetFp, entry.data, [], 0, deadline);
|
|
3925
|
+
if (hit) {
|
|
3926
|
+
return {
|
|
3927
|
+
source: "tanstack-query",
|
|
3928
|
+
storeName: queryHash,
|
|
3929
|
+
keyPath: hit.path,
|
|
3930
|
+
confidence: hit.confidence,
|
|
3931
|
+
matchedValue: walkPath(entry.data, hit.path)
|
|
3932
|
+
};
|
|
3933
|
+
}
|
|
3934
|
+
}
|
|
3935
|
+
return null;
|
|
3936
|
+
}
|
|
3937
|
+
|
|
3584
3938
|
// src/frameworkDetect.ts
|
|
3585
3939
|
function detectWebFramework() {
|
|
3586
3940
|
if (typeof document === "undefined") return {};
|
|
@@ -3615,8 +3969,11 @@ export {
|
|
|
3615
3969
|
getNodeEffects,
|
|
3616
3970
|
getNodeHooks,
|
|
3617
3971
|
getNodeProps,
|
|
3972
|
+
getReduxSnapshot,
|
|
3973
|
+
getTanstackSnapshot,
|
|
3618
3974
|
getTimeline,
|
|
3619
3975
|
getWebSocketClient,
|
|
3976
|
+
getZustandSnapshot,
|
|
3620
3977
|
hasActiveTags,
|
|
3621
3978
|
inspectEffects,
|
|
3622
3979
|
inspectHooks,
|
|
@@ -3633,6 +3990,7 @@ export {
|
|
|
3633
3990
|
requestFullSnapshot,
|
|
3634
3991
|
requestTreeSnapshot,
|
|
3635
3992
|
resetNextjsDetection,
|
|
3993
|
+
resolveValueTrace,
|
|
3636
3994
|
serializeProps,
|
|
3637
3995
|
serializeValue,
|
|
3638
3996
|
tagFetchData,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@flotrace/runtime-core",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.2.1",
|
|
4
4
|
"description": "Platform-agnostic core for FloTrace runtime — fiber walker, analyzers, trackers. Shared by @flotrace/runtime (web) and @flotrace/runtime-native (React Native).",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"module": "./dist/index.mjs",
|