@flareapp/react 2.10.0 → 2.12.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 CHANGED
@@ -115,6 +115,18 @@ under that ancestor, whose own span closed when it finished mounting. The tree i
115
115
  correct, but the waterfall shows the child starting after its parent ended. A page body
116
116
  swapped inside a persistent layout is the usual way to see this.
117
117
 
118
+ ### Self time
119
+
120
+ Every component span carries `flare.component.self_time_ns`: the span's duration minus the time its own
121
+ profiled children account for. Children that overlap in time are counted once, so the value never goes
122
+ below zero.
123
+
124
+ A child that mounts after its parent's span closed is not subtracted. Its work happened outside the
125
+ parent's window, so the parent keeps its full duration.
126
+
127
+ React starts every component during render and ends them all during commit, so sibling spans overlap in
128
+ time. The self times of one tree therefore add up to more than the root span's duration.
129
+
118
130
  **Import the main entry somewhere too.** `@flareapp/react/profiler` is deliberately dependency-free, so
119
131
  it does not register React as the framework. That identity (`flare.framework.name`) is what tells Flare a
120
132
  component span came from React, and importing `@flareapp/react` anywhere in the app sets it. An app that
@@ -4,25 +4,10 @@ import { Component, version } from "react";
4
4
  import { createFlareResolver } from "@flareapp/js/browser";
5
5
 
6
6
  //#region src/constants.ts
7
- /**
8
- * Chrome: `at ComponentName (http://localhost:5173/src/App.tsx:12:9)`; no source: `at div`.
9
- */
10
7
  const CHROMIUM_STACK_REGEX = /^at\s+(\S+)(?:\s+\((.+):(\d+):(\d+)\))?$/;
11
- /**
12
- * Firefox/Safari: `ComponentName@http://localhost:5173/src/App.tsx:12:9`; no source: `div`.
13
- */
14
8
  const FIREFOX_SAFARI_STACK_REGEX = /^(\S+?)@(.+):(\d+):(\d+)$/;
15
- /**
16
- * React 16/17/18 synthetic component stack: `in ComponentName (at App.jsx:10)`; with an optional
17
- * column `in ComponentName (at App.jsx:10:5)`; no source: `in ComponentName`. These versions usually
18
- * emit a line only, so the column capture group is optional. The file capture is lazy so the trailing
19
- * `:line(:column)` binds to the numeric tail even when the file path itself contains colons. Without
20
- * `__source` React names the owner instead (`in App (created by Root)`), so that suffix is matched and
21
- * discarded; the group is greedy because an owner name can carry brackets of its own (`Connect(Form)`).
22
- */
23
9
  const REACT_LEGACY_STACK_REGEX = /^in\s+(\S+)(?:\s+\(at\s+(.+?):(\d+)(?::(\d+))?\))?(?:\s+\(created by\s+.+\))?$/;
24
- /** Injected at build time via tsdown --env.PACKAGE_VERSION (reads package.json version). */
25
- const PACKAGE_VERSION = typeof process !== "undefined" && true ? "2.10.0" : "?";
10
+ const PACKAGE_VERSION = typeof process !== "undefined" && true ? "2.12.0" : "?";
26
11
 
27
12
  //#endregion
28
13
  //#region src/identify.ts
@@ -31,12 +16,10 @@ const tagger = createIdentityTagger({
31
16
  sdkVersion: PACKAGE_VERSION,
32
17
  frameworkName: FrameworkName.React
33
18
  });
34
- /** Web path: full identity on the default singleton (sdk + framework). */
35
19
  function registerReactSdkIdentity(flare) {
36
20
  tagger.registerSdkIdentity(flare);
37
21
  tagger.tagFramework(flare, React.version);
38
22
  }
39
- /** Injected path: framework tag only, never sdkInfo (would clobber the injected SDK name). */
40
23
  function tagReactFramework(flare) {
41
24
  tagger.tagFramework(flare, React.version);
42
25
  }
@@ -53,12 +36,6 @@ function formatComponentStack(stack) {
53
36
 
54
37
  //#endregion
55
38
  //#region src/parseComponentStack.ts
56
- /**
57
- * Parse React's newline-separated `errorInfo.componentStack` into structured frames so the Flare UI
58
- * can render file/line links. The line format is browser-native in React 19 (Chromium / Firefox /
59
- * Safari shapes) and React-synthetic in 16-18 (`in X (at File:line)`). Unrecognised lines fall back
60
- * to component-name-only rather than being dropped.
61
- */
62
39
  function parseComponentStack(stack) {
63
40
  return stack.split(/\s*\n\s*/g).filter((line) => line.length > 0).map((line) => {
64
41
  const chromeMatch = line.match(CHROMIUM_STACK_REGEX);
@@ -31,25 +31,10 @@ react = __toESM(react);
31
31
  let _flareapp_js_browser = require("@flareapp/js/browser");
32
32
 
33
33
  //#region src/constants.ts
34
- /**
35
- * Chrome: `at ComponentName (http://localhost:5173/src/App.tsx:12:9)`; no source: `at div`.
36
- */
37
34
  const CHROMIUM_STACK_REGEX = /^at\s+(\S+)(?:\s+\((.+):(\d+):(\d+)\))?$/;
38
- /**
39
- * Firefox/Safari: `ComponentName@http://localhost:5173/src/App.tsx:12:9`; no source: `div`.
40
- */
41
35
  const FIREFOX_SAFARI_STACK_REGEX = /^(\S+?)@(.+):(\d+):(\d+)$/;
42
- /**
43
- * React 16/17/18 synthetic component stack: `in ComponentName (at App.jsx:10)`; with an optional
44
- * column `in ComponentName (at App.jsx:10:5)`; no source: `in ComponentName`. These versions usually
45
- * emit a line only, so the column capture group is optional. The file capture is lazy so the trailing
46
- * `:line(:column)` binds to the numeric tail even when the file path itself contains colons. Without
47
- * `__source` React names the owner instead (`in App (created by Root)`), so that suffix is matched and
48
- * discarded; the group is greedy because an owner name can carry brackets of its own (`Connect(Form)`).
49
- */
50
36
  const REACT_LEGACY_STACK_REGEX = /^in\s+(\S+)(?:\s+\(at\s+(.+?):(\d+)(?::(\d+))?\))?(?:\s+\(created by\s+.+\))?$/;
51
- /** Injected at build time via tsdown --env.PACKAGE_VERSION (reads package.json version). */
52
- const PACKAGE_VERSION = typeof process !== "undefined" && true ? "2.10.0" : "?";
37
+ const PACKAGE_VERSION = typeof process !== "undefined" && true ? "2.12.0" : "?";
53
38
 
54
39
  //#endregion
55
40
  //#region src/identify.ts
@@ -58,12 +43,10 @@ const tagger = (0, _flareapp_core.createIdentityTagger)({
58
43
  sdkVersion: PACKAGE_VERSION,
59
44
  frameworkName: _flareapp_core.FrameworkName.React
60
45
  });
61
- /** Web path: full identity on the default singleton (sdk + framework). */
62
46
  function registerReactSdkIdentity(flare) {
63
47
  tagger.registerSdkIdentity(flare);
64
48
  tagger.tagFramework(flare, react.version);
65
49
  }
66
- /** Injected path: framework tag only, never sdkInfo (would clobber the injected SDK name). */
67
50
  function tagReactFramework(flare) {
68
51
  tagger.tagFramework(flare, react.version);
69
52
  }
@@ -80,12 +63,6 @@ function formatComponentStack(stack) {
80
63
 
81
64
  //#endregion
82
65
  //#region src/parseComponentStack.ts
83
- /**
84
- * Parse React's newline-separated `errorInfo.componentStack` into structured frames so the Flare UI
85
- * can render file/line links. The line format is browser-native in React 19 (Chromium / Firefox /
86
- * Safari shapes) and React-synthetic in 16-18 (`in X (at File:line)`). Unrecognised lines fall back
87
- * to component-name-only rather than being dropped.
88
- */
89
66
  function parseComponentStack(stack) {
90
67
  return stack.split(/\s*\n\s*/g).filter((line) => line.length > 0).map((line) => {
91
68
  const chromeMatch = line.match(CHROMIUM_STACK_REGEX);
package/dist/index.cjs CHANGED
@@ -1,5 +1,5 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
- const require_flareReactErrorHandler = require('./flareReactErrorHandler-CnBAfhvX.cjs');
2
+ const require_flareReactErrorHandler = require('./flareReactErrorHandler-bT1t-xmg.cjs');
3
3
  let _flareapp_js = require("@flareapp/js");
4
4
 
5
5
  //#region src/index.ts
package/dist/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { i as registerReactSdkIdentity, n as FlareErrorBoundary, r as registerDefaultFlare, t as flareReactErrorHandler } from "./flareReactErrorHandler-C-ilc2tu.mjs";
1
+ import { i as registerReactSdkIdentity, n as FlareErrorBoundary, r as registerDefaultFlare, t as flareReactErrorHandler } from "./flareReactErrorHandler-B2XS2p8Z.mjs";
2
2
  import { flare } from "@flareapp/js";
3
3
 
4
4
  //#region src/index.ts
package/dist/inject.cjs CHANGED
@@ -1,5 +1,5 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
- const require_flareReactErrorHandler = require('./flareReactErrorHandler-CnBAfhvX.cjs');
2
+ const require_flareReactErrorHandler = require('./flareReactErrorHandler-bT1t-xmg.cjs');
3
3
 
4
4
  exports.FlareErrorBoundary = require_flareReactErrorHandler.FlareErrorBoundary;
5
5
  exports.flareReactErrorHandler = require_flareReactErrorHandler.flareReactErrorHandler;
package/dist/inject.mjs CHANGED
@@ -1,3 +1,3 @@
1
- import { n as FlareErrorBoundary, t as flareReactErrorHandler } from "./flareReactErrorHandler-C-ilc2tu.mjs";
1
+ import { n as FlareErrorBoundary, t as flareReactErrorHandler } from "./flareReactErrorHandler-B2XS2p8Z.mjs";
2
2
 
3
3
  export { FlareErrorBoundary, flareReactErrorHandler };
package/dist/profiler.cjs CHANGED
@@ -1,5 +1,5 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
- const require_flareReactErrorHandler = require('./flareReactErrorHandler-CnBAfhvX.cjs');
2
+ const require_flareReactErrorHandler = require('./flareReactErrorHandler-bT1t-xmg.cjs');
3
3
  let react = require("react");
4
4
  let _flareapp_js_browser = require("@flareapp/js/browser");
5
5
 
@@ -1,5 +1,5 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
- const require_flareReactErrorHandler = require('./flareReactErrorHandler-CnBAfhvX.cjs');
2
+ const require_flareReactErrorHandler = require('./flareReactErrorHandler-bT1t-xmg.cjs');
3
3
  let _flareapp_js_browser = require("@flareapp/js/browser");
4
4
 
5
5
  //#region src/react-router.ts
@@ -21,11 +21,9 @@ function routeNameFromMatches(matches) {
21
21
  return path.replace(/\/{2,}/g, "/");
22
22
  }
23
23
  /**
24
- * Trace a React Router v7 data router (createBrowserRouter / createHashRouter / createMemoryRouter):
25
- * name the browser_pageload root from the initial route, and open a parameterized, held
26
- * browser_navigation root per route change, named once the router settles. Returns a cleanup that
27
- * unsubscribes and unregisters. Safe to call before or after tracing is enabled; no-ops when off.
28
- * Calling it twice on the same router replaces the first instrumentation.
24
+ * Traces a React Router v7 data router: names the `browser_pageload` root from the initial route, then
25
+ * opens a held, parameterized `browser_navigation` root per route change once it settles. Safe to call
26
+ * before/after tracing is enabled, and to call twice (replaces the prior instrumentation).
29
27
  */
30
28
  function traceReactRouter(router) {
31
29
  if (typeof router?.subscribe !== "function") return () => {};
@@ -28,10 +28,6 @@ type ReactRouterStateLike = {
28
28
  type ReactRouterLike = {
29
29
  subscribe(cb: (state: ReactRouterStateLike) => void): () => void;
30
30
  state: ReactRouterStateLike;
31
- /**
32
- * Applies the router's `basename` (and, for a hash router, the `#` prefix) to a location.
33
- * `state.location.pathname` has both stripped. Optional so a hand-built router still types.
34
- */
35
31
  createHref?(location: ReactRouterLocationLike): string;
36
32
  };
37
33
  //#endregion
@@ -43,11 +39,9 @@ type ReactRouterLike = {
43
39
  */
44
40
  declare function routeNameFromMatches(matches: ReactRouterMatchLike[] | undefined): string | undefined;
45
41
  /**
46
- * Trace a React Router v7 data router (createBrowserRouter / createHashRouter / createMemoryRouter):
47
- * name the browser_pageload root from the initial route, and open a parameterized, held
48
- * browser_navigation root per route change, named once the router settles. Returns a cleanup that
49
- * unsubscribes and unregisters. Safe to call before or after tracing is enabled; no-ops when off.
50
- * Calling it twice on the same router replaces the first instrumentation.
42
+ * Traces a React Router v7 data router: names the `browser_pageload` root from the initial route, then
43
+ * opens a held, parameterized `browser_navigation` root per route change once it settles. Safe to call
44
+ * before/after tracing is enabled, and to call twice (replaces the prior instrumentation).
51
45
  */
52
46
  declare function traceReactRouter(router: ReactRouterLike): () => void;
53
47
  //#endregion
@@ -28,10 +28,6 @@ type ReactRouterStateLike = {
28
28
  type ReactRouterLike = {
29
29
  subscribe(cb: (state: ReactRouterStateLike) => void): () => void;
30
30
  state: ReactRouterStateLike;
31
- /**
32
- * Applies the router's `basename` (and, for a hash router, the `#` prefix) to a location.
33
- * `state.location.pathname` has both stripped. Optional so a hand-built router still types.
34
- */
35
31
  createHref?(location: ReactRouterLocationLike): string;
36
32
  };
37
33
  //#endregion
@@ -43,11 +39,9 @@ type ReactRouterLike = {
43
39
  */
44
40
  declare function routeNameFromMatches(matches: ReactRouterMatchLike[] | undefined): string | undefined;
45
41
  /**
46
- * Trace a React Router v7 data router (createBrowserRouter / createHashRouter / createMemoryRouter):
47
- * name the browser_pageload root from the initial route, and open a parameterized, held
48
- * browser_navigation root per route change, named once the router settles. Returns a cleanup that
49
- * unsubscribes and unregisters. Safe to call before or after tracing is enabled; no-ops when off.
50
- * Calling it twice on the same router replaces the first instrumentation.
42
+ * Traces a React Router v7 data router: names the `browser_pageload` root from the initial route, then
43
+ * opens a held, parameterized `browser_navigation` root per route change once it settles. Safe to call
44
+ * before/after tracing is enabled, and to call twice (replaces the prior instrumentation).
51
45
  */
52
46
  declare function traceReactRouter(router: ReactRouterLike): () => void;
53
47
  //#endregion
@@ -19,11 +19,9 @@ function routeNameFromMatches(matches) {
19
19
  return path.replace(/\/{2,}/g, "/");
20
20
  }
21
21
  /**
22
- * Trace a React Router v7 data router (createBrowserRouter / createHashRouter / createMemoryRouter):
23
- * name the browser_pageload root from the initial route, and open a parameterized, held
24
- * browser_navigation root per route change, named once the router settles. Returns a cleanup that
25
- * unsubscribes and unregisters. Safe to call before or after tracing is enabled; no-ops when off.
26
- * Calling it twice on the same router replaces the first instrumentation.
22
+ * Traces a React Router v7 data router: names the `browser_pageload` root from the initial route, then
23
+ * opens a held, parameterized `browser_navigation` root per route change once it settles. Safe to call
24
+ * before/after tracing is enabled, and to call twice (replaces the prior instrumentation).
27
25
  */
28
26
  function traceReactRouter(router) {
29
27
  if (typeof router?.subscribe !== "function") return () => {};
@@ -1,20 +1,13 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
- const require_flareReactErrorHandler = require('./flareReactErrorHandler-CnBAfhvX.cjs');
2
+ const require_flareReactErrorHandler = require('./flareReactErrorHandler-bT1t-xmg.cjs');
3
3
  let _flareapp_js_browser = require("@flareapp/js/browser");
4
4
 
5
5
  //#region src/tanstack-router.ts
6
- /**
7
- * How long a held navigation root waits for `onResolved` before settling itself. Exported so the suite
8
- * drives it instead of hardcoding the number; not part of the supported surface.
9
- */
10
6
  const STALE_NAVIGATION_TIMEOUT_MS = 5e3;
11
7
  /**
12
- * Trace a TanStack Router instance: name the `browser_pageload` root from the
13
- * initial route and open a parameterized `browser_navigation` root per route
14
- * change. Returns a cleanup that unsubscribes and unregisters. Safe to call
15
- * before or after tracing is enabled; no-ops when tracing is off. Calling it
16
- * twice on the same router replaces the first instrumentation rather than
17
- * stacking a second set of subscriptions.
8
+ * Traces a TanStack Router instance: names the `browser_pageload` root from the initial route, then
9
+ * opens a parameterized `browser_navigation` root per route change. Safe to call before/after tracing
10
+ * is enabled, and to call twice (replaces the prior instrumentation instead of stacking subscriptions).
18
11
  */
19
12
  function traceTanStackRouter(router) {
20
13
  if (typeof router?.subscribe !== "function") return () => {};
@@ -27,18 +27,11 @@ type TanStackRouterLike = {
27
27
  };
28
28
  //#endregion
29
29
  //#region src/tanstack-router.d.ts
30
- /**
31
- * How long a held navigation root waits for `onResolved` before settling itself. Exported so the suite
32
- * drives it instead of hardcoding the number; not part of the supported surface.
33
- */
34
30
  declare const STALE_NAVIGATION_TIMEOUT_MS = 5000;
35
31
  /**
36
- * Trace a TanStack Router instance: name the `browser_pageload` root from the
37
- * initial route and open a parameterized `browser_navigation` root per route
38
- * change. Returns a cleanup that unsubscribes and unregisters. Safe to call
39
- * before or after tracing is enabled; no-ops when tracing is off. Calling it
40
- * twice on the same router replaces the first instrumentation rather than
41
- * stacking a second set of subscriptions.
32
+ * Traces a TanStack Router instance: names the `browser_pageload` root from the initial route, then
33
+ * opens a parameterized `browser_navigation` root per route change. Safe to call before/after tracing
34
+ * is enabled, and to call twice (replaces the prior instrumentation instead of stacking subscriptions).
42
35
  */
43
36
  declare function traceTanStackRouter(router: TanStackRouterLike): () => void;
44
37
  //#endregion
@@ -27,18 +27,11 @@ type TanStackRouterLike = {
27
27
  };
28
28
  //#endregion
29
29
  //#region src/tanstack-router.d.ts
30
- /**
31
- * How long a held navigation root waits for `onResolved` before settling itself. Exported so the suite
32
- * drives it instead of hardcoding the number; not part of the supported surface.
33
- */
34
30
  declare const STALE_NAVIGATION_TIMEOUT_MS = 5000;
35
31
  /**
36
- * Trace a TanStack Router instance: name the `browser_pageload` root from the
37
- * initial route and open a parameterized `browser_navigation` root per route
38
- * change. Returns a cleanup that unsubscribes and unregisters. Safe to call
39
- * before or after tracing is enabled; no-ops when tracing is off. Calling it
40
- * twice on the same router replaces the first instrumentation rather than
41
- * stacking a second set of subscriptions.
32
+ * Traces a TanStack Router instance: names the `browser_pageload` root from the initial route, then
33
+ * opens a parameterized `browser_navigation` root per route change. Safe to call before/after tracing
34
+ * is enabled, and to call twice (replaces the prior instrumentation instead of stacking subscriptions).
42
35
  */
43
36
  declare function traceTanStackRouter(router: TanStackRouterLike): () => void;
44
37
  //#endregion
@@ -1,18 +1,11 @@
1
1
  import { instrumentOnce, insulate, registerNavigationSource, resolveHref, routeName } from "@flareapp/js/browser";
2
2
 
3
3
  //#region src/tanstack-router.ts
4
- /**
5
- * How long a held navigation root waits for `onResolved` before settling itself. Exported so the suite
6
- * drives it instead of hardcoding the number; not part of the supported surface.
7
- */
8
4
  const STALE_NAVIGATION_TIMEOUT_MS = 5e3;
9
5
  /**
10
- * Trace a TanStack Router instance: name the `browser_pageload` root from the
11
- * initial route and open a parameterized `browser_navigation` root per route
12
- * change. Returns a cleanup that unsubscribes and unregisters. Safe to call
13
- * before or after tracing is enabled; no-ops when tracing is off. Calling it
14
- * twice on the same router replaces the first instrumentation rather than
15
- * stacking a second set of subscriptions.
6
+ * Traces a TanStack Router instance: names the `browser_pageload` root from the initial route, then
7
+ * opens a parameterized `browser_navigation` root per route change. Safe to call before/after tracing
8
+ * is enabled, and to call twice (replaces the prior instrumentation instead of stacking subscriptions).
16
9
  */
17
10
  function traceTanStackRouter(router) {
18
11
  if (typeof router?.subscribe !== "function") return () => {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flareapp/react",
3
- "version": "2.10.0",
3
+ "version": "2.12.0",
4
4
  "description": "React client for flareapp.io",
5
5
  "homepage": "https://flareapp.io",
6
6
  "bugs": "https://github.com/spatie/flare-client-js/issues",
@@ -92,7 +92,7 @@
92
92
  "release": "release-it"
93
93
  },
94
94
  "dependencies": {
95
- "@flareapp/core": "2.10.0"
95
+ "@flareapp/core": "2.12.0"
96
96
  },
97
97
  "devDependencies": {
98
98
  "@flareapp/electron": "file:../electron",
@@ -111,7 +111,7 @@
111
111
  "vitest": "^4.0.0"
112
112
  },
113
113
  "peerDependencies": {
114
- "@flareapp/js": "^2.10.0",
114
+ "@flareapp/js": "^2.12.0",
115
115
  "@tanstack/react-router": ">=1.64.0 <2",
116
116
  "react": "^16.0.0||^17.0.0||^18.0.0||^19.0.0",
117
117
  "react-router": ">=7.0.0 <8"