@flotrace/runtime-core 2.0.0 → 2.2.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/dist/index.js CHANGED
@@ -1,7 +1,9 @@
1
1
  "use strict";
2
+ var __create = Object.create;
2
3
  var __defProp = Object.defineProperty;
3
4
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
5
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
5
7
  var __hasOwnProp = Object.prototype.hasOwnProperty;
6
8
  var __export = (target, all) => {
7
9
  for (var name in all)
@@ -15,6 +17,14 @@ var __copyProps = (to, from, except, desc) => {
15
17
  }
16
18
  return to;
17
19
  };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
18
28
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
29
 
20
30
  // src/index.ts
@@ -25,6 +35,7 @@ __export(index_exports, {
25
35
  buildAncestorChain: () => buildAncestorChain,
26
36
  clearFetchOriginTags: () => clearFetchOriginTags,
27
37
  detectServerComponent: () => detectServerComponent,
38
+ detectWebFramework: () => detectWebFramework,
28
39
  disposeWebSocketClient: () => disposeWebSocketClient,
29
40
  findFetchOrigin: () => findFetchOrigin,
30
41
  getChangedKeys: () => getChangedKeys,
@@ -35,8 +46,11 @@ __export(index_exports, {
35
46
  getNodeEffects: () => getNodeEffects,
36
47
  getNodeHooks: () => getNodeHooks,
37
48
  getNodeProps: () => getNodeProps,
49
+ getReduxSnapshot: () => getReduxSnapshot,
50
+ getTanstackSnapshot: () => getTanstackSnapshot,
38
51
  getTimeline: () => getTimeline,
39
52
  getWebSocketClient: () => getWebSocketClient,
53
+ getZustandSnapshot: () => getZustandSnapshot,
40
54
  hasActiveTags: () => hasActiveTags,
41
55
  inspectEffects: () => inspectEffects,
42
56
  inspectHooks: () => inspectHooks,
@@ -53,6 +67,7 @@ __export(index_exports, {
53
67
  requestFullSnapshot: () => requestFullSnapshot,
54
68
  requestTreeSnapshot: () => requestTreeSnapshot,
55
69
  resetNextjsDetection: () => resetNextjsDetection,
70
+ resolveValueTrace: () => resolveValueTrace,
56
71
  serializeProps: () => serializeProps,
57
72
  serializeValue: () => serializeValue,
58
73
  tagFetchData: () => tagFetchData,
@@ -243,6 +258,7 @@ function getChangedKeys(prev, next) {
243
258
  }
244
259
 
245
260
  // src/websocketClient.ts
261
+ var import_react = __toESM(require("react"));
246
262
  var _FloTraceWebSocketClient = class _FloTraceWebSocketClient {
247
263
  constructor(config = {}) {
248
264
  this.ws = null;
@@ -290,7 +306,10 @@ var _FloTraceWebSocketClient = class _FloTraceWebSocketClient {
290
306
  appUrl: this.config.getAppUrl?.(),
291
307
  platform: this.config.platform,
292
308
  appId: this.config.appId,
293
- appVersion: this.config.appVersion
309
+ appVersion: this.config.appVersion,
310
+ frameworkName: this.config.frameworkName,
311
+ frameworkVersion: this.config.frameworkVersion,
312
+ reactNativeVersion: this.config.reactNativeVersion
294
313
  });
295
314
  this.flush();
296
315
  };
@@ -474,12 +493,17 @@ var _FloTraceWebSocketClient = class _FloTraceWebSocketClient {
474
493
  return this.ws !== null && this.ws.readyState === WebSocket.OPEN;
475
494
  }
476
495
  /**
477
- * Get React version if available
496
+ * Get React version if available.
497
+ *
498
+ * Historical note: an earlier implementation read `globalThis.React?.version` —
499
+ * but React is an ES-module import in modern bundles (Vite/webpack/Next.js) and
500
+ * is never placed on `globalThis`, so the probe returned undefined for every
501
+ * typical bundled app. Reading `React.version` via a direct import is
502
+ * authoritative across web (both CJS and ESM bundles), React Native, and SSR.
478
503
  */
479
504
  getReactVersion() {
480
505
  try {
481
- const React = globalThis.React;
482
- return React?.version;
506
+ return import_react.default.version;
483
507
  } catch {
484
508
  return void 0;
485
509
  }
@@ -1609,8 +1633,8 @@ function runAnalysis(tree, fiberRefMap2) {
1609
1633
  }
1610
1634
  function schedulePropDrillingAnalysis(tree, fiberRefMap2, client2) {
1611
1635
  if (analyzeTimer) clearTimeout(analyzeTimer);
1612
- const now = Date.now();
1613
- const elapsed = now - lastAnalysisTime;
1636
+ const now2 = Date.now();
1637
+ const elapsed = now2 - lastAnalysisTime;
1614
1638
  const delay = elapsed >= ANALYZE_INTERVAL_MS ? 0 : ANALYZE_INTERVAL_MS - elapsed;
1615
1639
  analyzeTimer = setTimeout(() => {
1616
1640
  analyzeTimer = null;
@@ -2637,7 +2661,7 @@ function executeSnapshot(root) {
2637
2661
  }
2638
2662
  previousFlatTree = currentFlatTree;
2639
2663
  if (pendingLocalStateCorrelations.length > 0) {
2640
- const now = Date.now();
2664
+ const now2 = Date.now();
2641
2665
  const toSend = pendingLocalStateCorrelations.splice(0);
2642
2666
  for (const corr of toSend) {
2643
2667
  try {
@@ -2646,7 +2670,7 @@ function executeSnapshot(root) {
2646
2670
  requestId: corr.requestId,
2647
2671
  componentName: corr.componentName,
2648
2672
  hookIndex: corr.hookIndex,
2649
- timestamp: now
2673
+ timestamp: now2
2650
2674
  });
2651
2675
  } catch {
2652
2676
  }
@@ -3091,6 +3115,7 @@ var activeUnsubscribers = [];
3091
3115
  var isInstalled4 = false;
3092
3116
  var debounceTimers = /* @__PURE__ */ new Map();
3093
3117
  var DEBOUNCE_MS = 200;
3118
+ var trackedStores = /* @__PURE__ */ new Map();
3094
3119
  function installZustandTracker(stores, client2) {
3095
3120
  if (isInstalled4) {
3096
3121
  console.warn("[FloTrace] Zustand tracker already installed, reinstalling");
@@ -3106,6 +3131,7 @@ function installZustandTracker(stores, client2) {
3106
3131
  continue;
3107
3132
  }
3108
3133
  try {
3134
+ trackedStores.set(storeName, store);
3109
3135
  const initialState = store.getState();
3110
3136
  sendStoreUpdate(storeName, initialState, Object.keys(initialState), client2);
3111
3137
  const unsubscribe = store.subscribe((newState, prevState) => {
@@ -3135,9 +3161,20 @@ function uninstallZustandTracker() {
3135
3161
  }
3136
3162
  }
3137
3163
  activeUnsubscribers = [];
3164
+ trackedStores.clear();
3138
3165
  isInstalled4 = false;
3139
3166
  console.log("[FloTrace] Zustand tracker uninstalled");
3140
3167
  }
3168
+ function getZustandSnapshot() {
3169
+ const snapshot = /* @__PURE__ */ new Map();
3170
+ for (const [name, store] of trackedStores) {
3171
+ try {
3172
+ snapshot.set(name, store.getState());
3173
+ } catch {
3174
+ }
3175
+ }
3176
+ return snapshot;
3177
+ }
3141
3178
  function scheduleStoreUpdate(storeName, prevState, newState, client2) {
3142
3179
  let changedKeys;
3143
3180
  try {
@@ -3176,6 +3213,7 @@ var isInstalled5 = false;
3176
3213
  var debounceTimer = null;
3177
3214
  var previousState = null;
3178
3215
  var DEBOUNCE_MS2 = 200;
3216
+ var trackedStore = null;
3179
3217
  function isReduxStore(obj) {
3180
3218
  return typeof obj === "object" && obj !== null && typeof obj.getState === "function" && typeof obj.subscribe === "function" && typeof obj.dispatch === "function";
3181
3219
  }
@@ -3187,6 +3225,7 @@ function installReduxTracker(store, client2) {
3187
3225
  isInstalled5 = true;
3188
3226
  console.log("[FloTrace] Installing Redux tracker");
3189
3227
  try {
3228
+ trackedStore = store;
3190
3229
  const initialState = store.getState();
3191
3230
  previousState = initialState;
3192
3231
  sendReduxUpdate(initialState, Object.keys(initialState), client2);
@@ -3218,9 +3257,18 @@ function uninstallReduxTracker() {
3218
3257
  activeUnsubscribe = null;
3219
3258
  }
3220
3259
  previousState = null;
3260
+ trackedStore = null;
3221
3261
  isInstalled5 = false;
3222
3262
  console.log("[FloTrace] Redux tracker uninstalled");
3223
3263
  }
3264
+ function getReduxSnapshot() {
3265
+ if (!trackedStore) return null;
3266
+ try {
3267
+ return trackedStore.getState();
3268
+ } catch {
3269
+ return null;
3270
+ }
3271
+ }
3224
3272
  function scheduleReduxUpdate(newState, client2) {
3225
3273
  let changedKeys;
3226
3274
  try {
@@ -3258,6 +3306,7 @@ var queryUnsubscribe = null;
3258
3306
  var mutationUnsubscribe = null;
3259
3307
  var debounceTimer2 = null;
3260
3308
  var DEBOUNCE_MS3 = 300;
3309
+ var trackedClient = null;
3261
3310
  var MAX_EVENTS_PER_QUERY = 50;
3262
3311
  var queryTracking = /* @__PURE__ */ new Map();
3263
3312
  var CORRELATION_WINDOW_MS = 500;
@@ -3280,6 +3329,7 @@ function installTanStackQueryTracker(queryClient, client2) {
3280
3329
  isInstalled6 = true;
3281
3330
  console.log("[FloTrace] Installing TanStack Query tracker");
3282
3331
  try {
3332
+ trackedClient = queryClient;
3283
3333
  const queryCache = queryClient.getQueryCache();
3284
3334
  const mutationCache = queryClient.getMutationCache();
3285
3335
  for (const query of queryCache.getAll()) {
@@ -3344,9 +3394,24 @@ function uninstallTanStackQueryTracker() {
3344
3394
  clearTimeout(pending.timeoutId);
3345
3395
  }
3346
3396
  pendingCorrelations.clear();
3397
+ trackedClient = null;
3347
3398
  isInstalled6 = false;
3348
3399
  console.log("[FloTrace] TanStack Query tracker uninstalled");
3349
3400
  }
3401
+ function getTanstackSnapshot() {
3402
+ const snapshot = /* @__PURE__ */ new Map();
3403
+ if (!trackedClient) return snapshot;
3404
+ try {
3405
+ const queryCache = trackedClient.getQueryCache();
3406
+ for (const query of queryCache.getAll()) {
3407
+ if (query.state.data !== void 0) {
3408
+ snapshot.set(query.queryHash, { queryKey: query.queryKey, data: query.state.data });
3409
+ }
3410
+ }
3411
+ } catch {
3412
+ }
3413
+ return snapshot;
3414
+ }
3350
3415
  function computeDataHash(data) {
3351
3416
  if (data === null || data === void 0) return "__null__";
3352
3417
  try {
@@ -3409,11 +3474,11 @@ function updateQueryTracking(query, eventType) {
3409
3474
  }
3410
3475
  }
3411
3476
  if (tracking.prevFetchStatus === "idle" && currentFetchStatus === "fetching") {
3412
- const now = Date.now();
3477
+ const now2 = Date.now();
3413
3478
  for (const pending of pendingCorrelations.values()) {
3414
3479
  if (pending.idleQueryHashes.has(query.queryHash)) {
3415
3480
  pending.affectedQueries.set(query.queryHash, {
3416
- fetchStartedAt: now,
3481
+ fetchStartedAt: now2,
3417
3482
  queryKey: query.queryKey
3418
3483
  });
3419
3484
  }
@@ -3425,7 +3490,7 @@ function updateQueryTracking(query, eventType) {
3425
3490
  }
3426
3491
  function openCorrelationWindow(mutation, queryCache, mutationCache, client2) {
3427
3492
  const correlationId = `corr-${++correlationCounter}`;
3428
- const now = Date.now();
3493
+ const now2 = Date.now();
3429
3494
  const idleQueryHashes = /* @__PURE__ */ new Set();
3430
3495
  for (const query of queryCache.getAll()) {
3431
3496
  if (query.state.fetchStatus === "idle") {
@@ -3439,7 +3504,7 @@ function openCorrelationWindow(mutation, queryCache, mutationCache, client2) {
3439
3504
  correlationId,
3440
3505
  mutationId: mutation.mutationId,
3441
3506
  mutationKey: mutation.options.mutationKey,
3442
- completedAt: now,
3507
+ completedAt: now2,
3443
3508
  idleQueryHashes,
3444
3509
  affectedQueries: /* @__PURE__ */ new Map(),
3445
3510
  timeoutId
@@ -3638,6 +3703,337 @@ function safeCall(fn, fallback) {
3638
3703
  return fallback;
3639
3704
  }
3640
3705
  }
3706
+
3707
+ // src/valueTraceResolver.ts
3708
+ var FIBER_TAG_CONTEXT_PROVIDER = 10;
3709
+ var BUDGET_MS = 50;
3710
+ var SCAN_DEPTH = 3;
3711
+ var MAX_PROP_CHAIN_DEPTH = 30;
3712
+ function now() {
3713
+ return typeof performance !== "undefined" && typeof performance.now === "function" ? performance.now() : Date.now();
3714
+ }
3715
+ function walkPath(root, path) {
3716
+ let cur = root;
3717
+ for (const key of path) {
3718
+ if (cur === null || cur === void 0 || typeof cur !== "object") return void 0;
3719
+ cur = cur[key];
3720
+ }
3721
+ return cur;
3722
+ }
3723
+ function getHookValueAt(fiber, hookIndex) {
3724
+ let hook = fiber.memoizedState;
3725
+ let i = 0;
3726
+ while (hook && i < hookIndex) {
3727
+ hook = hook.next;
3728
+ i++;
3729
+ }
3730
+ if (!hook) return void 0;
3731
+ return hook.memoizedState;
3732
+ }
3733
+ function valuesMatch(target, targetFp, candidate) {
3734
+ const targetIsObject = target !== null && typeof target === "object";
3735
+ const candidateIsObject = candidate !== null && typeof candidate === "object";
3736
+ if (targetIsObject && candidateIsObject && target === candidate) return "exact";
3737
+ if (!shouldFlagRename(target) || !shouldFlagRename(candidate)) return null;
3738
+ if (valueFingerprint(candidate) === targetFp) return "fingerprint-match";
3739
+ return null;
3740
+ }
3741
+ function findMatchingPathInObject(target, targetFp, container, currentPath, depth, deadline) {
3742
+ if (now() > deadline) return null;
3743
+ if (depth > SCAN_DEPTH) return null;
3744
+ if (container === null || typeof container !== "object") return null;
3745
+ const selfMatch = valuesMatch(target, targetFp, container);
3746
+ if (selfMatch) return { path: [...currentPath], confidence: selfMatch };
3747
+ if (Array.isArray(container)) {
3748
+ for (let i = 0; i < Math.min(container.length, 50); i++) {
3749
+ const child = container[i];
3750
+ const directMatch = valuesMatch(target, targetFp, child);
3751
+ if (directMatch) return { path: [...currentPath, String(i)], confidence: directMatch };
3752
+ const nested = findMatchingPathInObject(target, targetFp, child, [...currentPath, String(i)], depth + 1, deadline);
3753
+ if (nested) return nested;
3754
+ }
3755
+ } else {
3756
+ for (const key of Object.keys(container)) {
3757
+ const child = container[key];
3758
+ const directMatch = valuesMatch(target, targetFp, child);
3759
+ if (directMatch) return { path: [...currentPath, key], confidence: directMatch };
3760
+ const nested = findMatchingPathInObject(target, targetFp, child, [...currentPath, key], depth + 1, deadline);
3761
+ if (nested) return nested;
3762
+ }
3763
+ }
3764
+ return null;
3765
+ }
3766
+ function buildFiberToNodeIdMap() {
3767
+ const reverse = /* @__PURE__ */ new Map();
3768
+ for (const [nodeId, fiber] of getFiberRefMap()) {
3769
+ reverse.set(fiber, nodeId);
3770
+ }
3771
+ return reverse;
3772
+ }
3773
+ function resolveValueTrace(input) {
3774
+ const startedAt = now();
3775
+ const deadline = startedAt + BUDGET_MS;
3776
+ const steps = [];
3777
+ const base = {
3778
+ rootNodeId: input.nodeId,
3779
+ rootPropPath: input.propPath,
3780
+ rootHookPath: input.hookPath,
3781
+ steps,
3782
+ resolvedAtMs: now()
3783
+ };
3784
+ const fiber = getFiberRefMap().get(input.nodeId);
3785
+ if (!fiber) {
3786
+ return { ...base, error: "no-fiber", resolvedAtMs: now() };
3787
+ }
3788
+ let rootValue;
3789
+ if (input.propPath && input.propPath.length > 0) {
3790
+ if (!fiber.memoizedProps) return { ...base, error: "value-not-found", resolvedAtMs: now() };
3791
+ rootValue = walkPath(fiber.memoizedProps, input.propPath);
3792
+ } else if (input.hookPath) {
3793
+ const hookValue = getHookValueAt(fiber, input.hookPath.hookIndex);
3794
+ rootValue = input.hookPath.subPath && input.hookPath.subPath.length > 0 ? walkPath(hookValue, input.hookPath.subPath) : hookValue;
3795
+ } else {
3796
+ return { ...base, error: "value-not-found", resolvedAtMs: now() };
3797
+ }
3798
+ if (rootValue === void 0) {
3799
+ return { ...base, error: "value-not-found", resolvedAtMs: now() };
3800
+ }
3801
+ const rootFp = valueFingerprint(rootValue);
3802
+ const fiberToNodeId = buildFiberToNodeIdMap();
3803
+ const rootComponentName = getComponentNameFromFiber(fiber) ?? "Unknown";
3804
+ if (input.propPath) {
3805
+ steps.push({
3806
+ kind: "prop",
3807
+ nodeId: input.nodeId,
3808
+ componentName: rootComponentName,
3809
+ propPath: input.propPath,
3810
+ confidence: "exact"
3811
+ });
3812
+ } else if (input.hookPath) {
3813
+ steps.push({
3814
+ kind: "hook-state",
3815
+ nodeId: input.nodeId,
3816
+ componentName: rootComponentName,
3817
+ hookIndex: input.hookPath.hookIndex,
3818
+ hookType: "unknown",
3819
+ // Cheap: full hook classification is expensive; caller can fetch separately.
3820
+ subPath: input.hookPath.subPath,
3821
+ confidence: "exact"
3822
+ });
3823
+ }
3824
+ if (input.propPath) {
3825
+ let current = fiber.return;
3826
+ let hops = 0;
3827
+ while (current && hops < MAX_PROP_CHAIN_DEPTH) {
3828
+ if (now() > deadline) return { ...base, steps, truncated: true, resolvedAtMs: now() };
3829
+ if (current.tag !== FIBER_TAG_CONTEXT_PROVIDER) {
3830
+ const props = current.memoizedProps;
3831
+ if (props) {
3832
+ const match = findMatchingPathInObject(rootValue, rootFp, props, [], 0, deadline);
3833
+ if (match) {
3834
+ const ancestorNodeId = fiberToNodeId.get(current);
3835
+ const ancestorName = getComponentNameFromFiber(current) ?? "Unknown";
3836
+ if (ancestorNodeId) {
3837
+ steps.push({
3838
+ kind: "prop",
3839
+ nodeId: ancestorNodeId,
3840
+ componentName: ancestorName,
3841
+ propPath: match.path,
3842
+ confidence: match.confidence
3843
+ });
3844
+ }
3845
+ }
3846
+ }
3847
+ }
3848
+ current = current.return;
3849
+ hops++;
3850
+ }
3851
+ }
3852
+ if (input.hookPath) {
3853
+ const origin = findFetchOrigin(rootValue);
3854
+ if (origin) {
3855
+ steps.push({
3856
+ kind: "api",
3857
+ requestId: origin,
3858
+ method: "UNKNOWN",
3859
+ urlPath: "",
3860
+ ageMs: 0
3861
+ });
3862
+ return { ...base, steps, resolvedAtMs: now() };
3863
+ }
3864
+ }
3865
+ const derivedMatch = findDerivationMatch(fiber, rootValue, rootFp, rootComponentName);
3866
+ if (derivedMatch) {
3867
+ steps.push({ ...derivedMatch, nodeId: input.nodeId });
3868
+ return { ...base, steps, resolvedAtMs: now() };
3869
+ }
3870
+ const contextMatch = findContextMatch(fiber, rootValue, rootFp, fiberToNodeId);
3871
+ if (contextMatch) {
3872
+ steps.push(contextMatch.step);
3873
+ const providerStoreMatch = findStoreMatch(contextMatch.providerValue, valueFingerprint(contextMatch.providerValue), deadline);
3874
+ if (providerStoreMatch) {
3875
+ steps.push({
3876
+ kind: "store",
3877
+ source: providerStoreMatch.source,
3878
+ storeName: providerStoreMatch.storeName,
3879
+ keyPath: providerStoreMatch.keyPath,
3880
+ confidence: providerStoreMatch.confidence
3881
+ });
3882
+ const origin = findFetchOrigin(providerStoreMatch.matchedValue);
3883
+ if (origin) {
3884
+ steps.push({ kind: "api", requestId: origin, method: "UNKNOWN", urlPath: "", ageMs: 0 });
3885
+ }
3886
+ } else {
3887
+ const origin = findFetchOrigin(contextMatch.providerValue);
3888
+ if (origin) {
3889
+ steps.push({ kind: "api", requestId: origin, method: "UNKNOWN", urlPath: "", ageMs: 0 });
3890
+ }
3891
+ }
3892
+ return { ...base, steps, resolvedAtMs: now() };
3893
+ }
3894
+ const storeMatch = findStoreMatch(rootValue, rootFp, deadline);
3895
+ if (storeMatch) {
3896
+ steps.push({
3897
+ kind: "store",
3898
+ source: storeMatch.source,
3899
+ storeName: storeMatch.storeName,
3900
+ keyPath: storeMatch.keyPath,
3901
+ confidence: storeMatch.confidence
3902
+ });
3903
+ const origin = findFetchOrigin(storeMatch.matchedValue);
3904
+ if (origin) {
3905
+ steps.push({
3906
+ kind: "api",
3907
+ requestId: origin,
3908
+ method: "UNKNOWN",
3909
+ urlPath: "",
3910
+ ageMs: 0
3911
+ });
3912
+ }
3913
+ }
3914
+ return { ...base, steps, resolvedAtMs: now() };
3915
+ }
3916
+ function findContextMatch(consumer, target, targetFp, fiberToNodeId) {
3917
+ const deps = consumer.dependencies?.firstContext;
3918
+ if (!deps) return null;
3919
+ let dep = deps;
3920
+ while (dep) {
3921
+ const match = valuesMatch(target, targetFp, dep.memoizedValue);
3922
+ if (match) {
3923
+ const provider = findNearestProvider(consumer, dep.context);
3924
+ const step = {
3925
+ kind: "context",
3926
+ contextName: dep.context.displayName || "Context",
3927
+ providerNodeId: provider ? fiberToNodeId.get(provider) : void 0,
3928
+ confidence: match
3929
+ };
3930
+ const providerValue = provider?.memoizedProps?.value ?? dep.memoizedValue;
3931
+ return { step, providerValue };
3932
+ }
3933
+ dep = dep.next;
3934
+ }
3935
+ return null;
3936
+ }
3937
+ function findDerivationMatch(fiber, target, targetFp, componentName) {
3938
+ let hook = fiber.memoizedState;
3939
+ let index = 0;
3940
+ while (hook) {
3941
+ const ms = hook.memoizedState;
3942
+ if (Array.isArray(ms) && ms.length === 2 && Array.isArray(ms[1])) {
3943
+ const [computed, deps] = ms;
3944
+ const match = valuesMatch(target, targetFp, computed);
3945
+ if (match) {
3946
+ const hookType = typeof computed === "function" ? "useCallback" : "useMemo";
3947
+ return {
3948
+ kind: "derived",
3949
+ nodeId: "",
3950
+ componentName,
3951
+ hookIndex: index,
3952
+ hookType,
3953
+ depCount: deps.length,
3954
+ confidence: match
3955
+ };
3956
+ }
3957
+ }
3958
+ hook = hook.next;
3959
+ index++;
3960
+ }
3961
+ return null;
3962
+ }
3963
+ function findNearestProvider(consumer, contextObj) {
3964
+ let current = consumer.return;
3965
+ let hops = 0;
3966
+ while (current && hops < MAX_PROP_CHAIN_DEPTH) {
3967
+ if (current.tag === FIBER_TAG_CONTEXT_PROVIDER) {
3968
+ const providerType = current.type;
3969
+ if (providerType && providerType._context === contextObj) return current;
3970
+ }
3971
+ current = current.return;
3972
+ hops++;
3973
+ }
3974
+ return null;
3975
+ }
3976
+ function findStoreMatch(target, targetFp, deadline) {
3977
+ for (const [storeName, state] of getZustandSnapshot()) {
3978
+ if (now() > deadline) return null;
3979
+ const hit = findMatchingPathInObject(target, targetFp, state, [], 0, deadline);
3980
+ if (hit) {
3981
+ return {
3982
+ source: "zustand",
3983
+ storeName,
3984
+ keyPath: hit.path,
3985
+ confidence: hit.confidence,
3986
+ matchedValue: walkPath(state, hit.path)
3987
+ };
3988
+ }
3989
+ }
3990
+ const redux = getReduxSnapshot();
3991
+ if (redux) {
3992
+ if (now() > deadline) return null;
3993
+ const hit = findMatchingPathInObject(target, targetFp, redux, [], 0, deadline);
3994
+ if (hit) {
3995
+ return {
3996
+ source: "redux",
3997
+ storeName: "redux",
3998
+ keyPath: hit.path,
3999
+ confidence: hit.confidence,
4000
+ matchedValue: walkPath(redux, hit.path)
4001
+ };
4002
+ }
4003
+ }
4004
+ for (const [queryHash, entry] of getTanstackSnapshot()) {
4005
+ if (now() > deadline) return null;
4006
+ const hit = findMatchingPathInObject(target, targetFp, entry.data, [], 0, deadline);
4007
+ if (hit) {
4008
+ return {
4009
+ source: "tanstack-query",
4010
+ storeName: queryHash,
4011
+ keyPath: hit.path,
4012
+ confidence: hit.confidence,
4013
+ matchedValue: walkPath(entry.data, hit.path)
4014
+ };
4015
+ }
4016
+ }
4017
+ return null;
4018
+ }
4019
+
4020
+ // src/frameworkDetect.ts
4021
+ function detectWebFramework() {
4022
+ if (typeof document === "undefined") return {};
4023
+ const hasNextData = !!globalThis.__NEXT_DATA__ || !!document.querySelector("script#__NEXT_DATA__");
4024
+ if (!hasNextData) return { frameworkName: "plain-react" };
4025
+ let version;
4026
+ try {
4027
+ const req = globalThis.require;
4028
+ if (typeof req === "function") {
4029
+ const id = "next/package.json";
4030
+ const pkg = req(id);
4031
+ version = pkg?.version;
4032
+ }
4033
+ } catch {
4034
+ }
4035
+ return { frameworkName: "next", frameworkVersion: version };
4036
+ }
3641
4037
  // Annotate the CommonJS export names for ESM import in node:
3642
4038
  0 && (module.exports = {
3643
4039
  DEFAULT_CONFIG,
@@ -3645,6 +4041,7 @@ function safeCall(fn, fallback) {
3645
4041
  buildAncestorChain,
3646
4042
  clearFetchOriginTags,
3647
4043
  detectServerComponent,
4044
+ detectWebFramework,
3648
4045
  disposeWebSocketClient,
3649
4046
  findFetchOrigin,
3650
4047
  getChangedKeys,
@@ -3655,8 +4052,11 @@ function safeCall(fn, fallback) {
3655
4052
  getNodeEffects,
3656
4053
  getNodeHooks,
3657
4054
  getNodeProps,
4055
+ getReduxSnapshot,
4056
+ getTanstackSnapshot,
3658
4057
  getTimeline,
3659
4058
  getWebSocketClient,
4059
+ getZustandSnapshot,
3660
4060
  hasActiveTags,
3661
4061
  inspectEffects,
3662
4062
  inspectHooks,
@@ -3673,6 +4073,7 @@ function safeCall(fn, fallback) {
3673
4073
  requestFullSnapshot,
3674
4074
  requestTreeSnapshot,
3675
4075
  resetNextjsDetection,
4076
+ resolveValueTrace,
3676
4077
  serializeProps,
3677
4078
  serializeValue,
3678
4079
  tagFetchData,