@flotrace/runtime 2.0.0 → 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.js +57 -2
- package/dist/index.mjs +60 -3
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -579,6 +579,19 @@ function safeTrackerOp(name, op) {
|
|
|
579
579
|
console.error(`[FloTrace] ${name}:`, error);
|
|
580
580
|
}
|
|
581
581
|
}
|
|
582
|
+
function deriveWebAppName() {
|
|
583
|
+
if (typeof document !== "undefined") {
|
|
584
|
+
const metaName = document.querySelector('meta[name="application-name"]')?.getAttribute("content")?.trim();
|
|
585
|
+
if (metaName) return metaName;
|
|
586
|
+
const title = document.title?.trim();
|
|
587
|
+
if (title) return title;
|
|
588
|
+
}
|
|
589
|
+
if (typeof location !== "undefined" && location.hostname) return location.hostname;
|
|
590
|
+
return import_runtime_core3.DEFAULT_CONFIG.appName;
|
|
591
|
+
}
|
|
592
|
+
function deriveWebAppId() {
|
|
593
|
+
return typeof location !== "undefined" && location.origin ? location.origin : "web-app";
|
|
594
|
+
}
|
|
582
595
|
var FloTraceContext = (0, import_react.createContext)(null);
|
|
583
596
|
function useFloTrace() {
|
|
584
597
|
return (0, import_react.useContext)(FloTraceContext);
|
|
@@ -590,13 +603,20 @@ function FloTraceProvider({ children, config = {}, stores, reduxStore, queryClie
|
|
|
590
603
|
);
|
|
591
604
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, { children });
|
|
592
605
|
}
|
|
606
|
+
const framework = (0, import_runtime_core3.detectWebFramework)();
|
|
593
607
|
const mergedConfig = {
|
|
594
608
|
...import_runtime_core3.DEFAULT_CONFIG,
|
|
595
609
|
// Web default: expose the current page URL as the `appUrl` in runtime:ready.
|
|
596
610
|
// Runtime-core defaults this to undefined so it stays platform-agnostic.
|
|
597
611
|
getAppUrl: () => typeof window !== "undefined" ? window.location.href : void 0,
|
|
598
612
|
platform: "web",
|
|
599
|
-
...config
|
|
613
|
+
...config,
|
|
614
|
+
// Derived values fill in only when the user didn't supply a static one.
|
|
615
|
+
// Placed AFTER `...config` so explicit user values still win via `??`.
|
|
616
|
+
appName: config.appName ?? deriveWebAppName(),
|
|
617
|
+
appId: config.appId ?? deriveWebAppId(),
|
|
618
|
+
frameworkName: config.frameworkName ?? framework.frameworkName,
|
|
619
|
+
frameworkVersion: config.frameworkVersion ?? framework.frameworkVersion
|
|
600
620
|
};
|
|
601
621
|
const [connected, setConnected] = import_react.default.useState(false);
|
|
602
622
|
const trackingOptionsRef = (0, import_react.useRef)({});
|
|
@@ -631,8 +651,12 @@ function FloTraceProvider({ children, config = {}, stores, reduxStore, queryClie
|
|
|
631
651
|
const unsubMessage = client3.onMessage((message) => {
|
|
632
652
|
try {
|
|
633
653
|
switch (message.type) {
|
|
654
|
+
// Heartbeat liveness is handled by the dedicated `runtime:pong` path
|
|
655
|
+
// in websocketClient. We intentionally do NOT re-send `runtime:ready`
|
|
656
|
+
// on every `ext:ping` — a truncated ready (only appName, no appId /
|
|
657
|
+
// platform / versions) would clobber the server's client registry
|
|
658
|
+
// metadata on every 5s tick. The initial `onopen` ready is authoritative.
|
|
634
659
|
case "ext:ping":
|
|
635
|
-
client3.sendImmediate({ type: "runtime:ready", appName: mergedConfig.appName });
|
|
636
660
|
break;
|
|
637
661
|
case "ext:startTracking":
|
|
638
662
|
trackingOptionsRef.current = message.options || {};
|
|
@@ -730,6 +754,37 @@ function FloTraceProvider({ children, config = {}, stores, reduxStore, queryClie
|
|
|
730
754
|
}
|
|
731
755
|
break;
|
|
732
756
|
}
|
|
757
|
+
// Value Lineage — resolve the origin chain for a prop or hook value.
|
|
758
|
+
case "ext:traceValue": {
|
|
759
|
+
try {
|
|
760
|
+
const trace = (0, import_runtime_core3.resolveValueTrace)({
|
|
761
|
+
nodeId: message.nodeId,
|
|
762
|
+
propPath: message.propPath,
|
|
763
|
+
hookPath: message.hookPath
|
|
764
|
+
});
|
|
765
|
+
client3.sendImmediate({
|
|
766
|
+
type: "runtime:valueTrace",
|
|
767
|
+
trace: { requestId: message.requestId, ...trace },
|
|
768
|
+
timestamp: Date.now()
|
|
769
|
+
});
|
|
770
|
+
} catch (error) {
|
|
771
|
+
console.error("[FloTrace] resolveValueTrace threw:", error);
|
|
772
|
+
client3.sendImmediate({
|
|
773
|
+
type: "runtime:valueTrace",
|
|
774
|
+
trace: {
|
|
775
|
+
requestId: message.requestId,
|
|
776
|
+
rootNodeId: message.nodeId,
|
|
777
|
+
rootPropPath: message.propPath,
|
|
778
|
+
rootHookPath: message.hookPath,
|
|
779
|
+
steps: [],
|
|
780
|
+
resolvedAtMs: Date.now(),
|
|
781
|
+
error: "value-not-found"
|
|
782
|
+
},
|
|
783
|
+
timestamp: Date.now()
|
|
784
|
+
});
|
|
785
|
+
}
|
|
786
|
+
break;
|
|
787
|
+
}
|
|
733
788
|
case "ext:startNetworkCapture":
|
|
734
789
|
safeTrackerOp("Network capture start", () => installNetworkTracker(client3));
|
|
735
790
|
break;
|
package/dist/index.mjs
CHANGED
|
@@ -25,7 +25,9 @@ import {
|
|
|
25
25
|
uninstallTanStackQueryTracker,
|
|
26
26
|
installTimelineTracker,
|
|
27
27
|
uninstallTimelineTracker,
|
|
28
|
-
getTimeline
|
|
28
|
+
getTimeline,
|
|
29
|
+
detectWebFramework,
|
|
30
|
+
resolveValueTrace
|
|
29
31
|
} from "@flotrace/runtime-core";
|
|
30
32
|
|
|
31
33
|
// src/routerTracker.ts
|
|
@@ -566,6 +568,19 @@ function safeTrackerOp(name, op) {
|
|
|
566
568
|
console.error(`[FloTrace] ${name}:`, error);
|
|
567
569
|
}
|
|
568
570
|
}
|
|
571
|
+
function deriveWebAppName() {
|
|
572
|
+
if (typeof document !== "undefined") {
|
|
573
|
+
const metaName = document.querySelector('meta[name="application-name"]')?.getAttribute("content")?.trim();
|
|
574
|
+
if (metaName) return metaName;
|
|
575
|
+
const title = document.title?.trim();
|
|
576
|
+
if (title) return title;
|
|
577
|
+
}
|
|
578
|
+
if (typeof location !== "undefined" && location.hostname) return location.hostname;
|
|
579
|
+
return DEFAULT_CONFIG.appName;
|
|
580
|
+
}
|
|
581
|
+
function deriveWebAppId() {
|
|
582
|
+
return typeof location !== "undefined" && location.origin ? location.origin : "web-app";
|
|
583
|
+
}
|
|
569
584
|
var FloTraceContext = createContext(null);
|
|
570
585
|
function useFloTrace() {
|
|
571
586
|
return useContext(FloTraceContext);
|
|
@@ -577,13 +592,20 @@ function FloTraceProvider({ children, config = {}, stores, reduxStore, queryClie
|
|
|
577
592
|
);
|
|
578
593
|
return /* @__PURE__ */ jsx(Fragment, { children });
|
|
579
594
|
}
|
|
595
|
+
const framework = detectWebFramework();
|
|
580
596
|
const mergedConfig = {
|
|
581
597
|
...DEFAULT_CONFIG,
|
|
582
598
|
// Web default: expose the current page URL as the `appUrl` in runtime:ready.
|
|
583
599
|
// Runtime-core defaults this to undefined so it stays platform-agnostic.
|
|
584
600
|
getAppUrl: () => typeof window !== "undefined" ? window.location.href : void 0,
|
|
585
601
|
platform: "web",
|
|
586
|
-
...config
|
|
602
|
+
...config,
|
|
603
|
+
// Derived values fill in only when the user didn't supply a static one.
|
|
604
|
+
// Placed AFTER `...config` so explicit user values still win via `??`.
|
|
605
|
+
appName: config.appName ?? deriveWebAppName(),
|
|
606
|
+
appId: config.appId ?? deriveWebAppId(),
|
|
607
|
+
frameworkName: config.frameworkName ?? framework.frameworkName,
|
|
608
|
+
frameworkVersion: config.frameworkVersion ?? framework.frameworkVersion
|
|
587
609
|
};
|
|
588
610
|
const [connected, setConnected] = React.useState(false);
|
|
589
611
|
const trackingOptionsRef = useRef({});
|
|
@@ -618,8 +640,12 @@ function FloTraceProvider({ children, config = {}, stores, reduxStore, queryClie
|
|
|
618
640
|
const unsubMessage = client3.onMessage((message) => {
|
|
619
641
|
try {
|
|
620
642
|
switch (message.type) {
|
|
643
|
+
// Heartbeat liveness is handled by the dedicated `runtime:pong` path
|
|
644
|
+
// in websocketClient. We intentionally do NOT re-send `runtime:ready`
|
|
645
|
+
// on every `ext:ping` — a truncated ready (only appName, no appId /
|
|
646
|
+
// platform / versions) would clobber the server's client registry
|
|
647
|
+
// metadata on every 5s tick. The initial `onopen` ready is authoritative.
|
|
621
648
|
case "ext:ping":
|
|
622
|
-
client3.sendImmediate({ type: "runtime:ready", appName: mergedConfig.appName });
|
|
623
649
|
break;
|
|
624
650
|
case "ext:startTracking":
|
|
625
651
|
trackingOptionsRef.current = message.options || {};
|
|
@@ -717,6 +743,37 @@ function FloTraceProvider({ children, config = {}, stores, reduxStore, queryClie
|
|
|
717
743
|
}
|
|
718
744
|
break;
|
|
719
745
|
}
|
|
746
|
+
// Value Lineage — resolve the origin chain for a prop or hook value.
|
|
747
|
+
case "ext:traceValue": {
|
|
748
|
+
try {
|
|
749
|
+
const trace = resolveValueTrace({
|
|
750
|
+
nodeId: message.nodeId,
|
|
751
|
+
propPath: message.propPath,
|
|
752
|
+
hookPath: message.hookPath
|
|
753
|
+
});
|
|
754
|
+
client3.sendImmediate({
|
|
755
|
+
type: "runtime:valueTrace",
|
|
756
|
+
trace: { requestId: message.requestId, ...trace },
|
|
757
|
+
timestamp: Date.now()
|
|
758
|
+
});
|
|
759
|
+
} catch (error) {
|
|
760
|
+
console.error("[FloTrace] resolveValueTrace threw:", error);
|
|
761
|
+
client3.sendImmediate({
|
|
762
|
+
type: "runtime:valueTrace",
|
|
763
|
+
trace: {
|
|
764
|
+
requestId: message.requestId,
|
|
765
|
+
rootNodeId: message.nodeId,
|
|
766
|
+
rootPropPath: message.propPath,
|
|
767
|
+
rootHookPath: message.hookPath,
|
|
768
|
+
steps: [],
|
|
769
|
+
resolvedAtMs: Date.now(),
|
|
770
|
+
error: "value-not-found"
|
|
771
|
+
},
|
|
772
|
+
timestamp: Date.now()
|
|
773
|
+
});
|
|
774
|
+
}
|
|
775
|
+
break;
|
|
776
|
+
}
|
|
720
777
|
case "ext:startNetworkCapture":
|
|
721
778
|
safeTrackerOp("Network capture start", () => installNetworkTracker(client3));
|
|
722
779
|
break;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@flotrace/runtime",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.2.1",
|
|
4
4
|
"description": "Runtime package for FloTrace - enables real-time render tracking in your React app",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"module": "./dist/index.mjs",
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
"release:major": "npm version major && npm publish"
|
|
27
27
|
},
|
|
28
28
|
"dependencies": {
|
|
29
|
-
"@flotrace/runtime-core": "2.
|
|
29
|
+
"@flotrace/runtime-core": "2.2.1"
|
|
30
30
|
},
|
|
31
31
|
"peerDependencies": {
|
|
32
32
|
"react": ">=16.9.0",
|