@buoy-gg/route-events 7.0.36 → 7.0.38

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
@@ -2,7 +2,7 @@
2
2
 
3
3
  [![npm version](https://img.shields.io/npm/v/@buoy-gg/route-events?style=flat-square&labelColor=1c1c1c&color=10B981)](https://www.npmjs.com/package/@buoy-gg/route-events) [![npm downloads](https://img.shields.io/npm/dm/@buoy-gg/route-events?style=flat-square&labelColor=1c1c1c&color=10B981)](https://www.npmjs.com/package/@buoy-gg/route-events)
4
4
 
5
- **See every route in your app, watch navigation happen in real time, and jump to any screen from a full sitemap.**
5
+ Inspect observed navigation events, browse supported routes, and navigate using the parameters your app requires.
6
6
 
7
7
  Part of [Buoy](https://github.com/Buoy-gg/buoy) — devtools that live inside your React Native app. Install it and it auto-appears in the floating menu from [`@buoy-gg/core`](https://www.npmjs.com/package/@buoy-gg/core).
8
8
 
@@ -14,6 +14,24 @@ Part of [Buoy](https://github.com/Buoy-gg/buoy) — devtools that live inside yo
14
14
  npm install @buoy-gg/core @buoy-gg/route-events
15
15
  ```
16
16
 
17
+ ## Before you start
18
+
19
+ Use a development build with `@buoy-gg/core` and a Free or Pro Buoy account key. From your app’s directory, sign in:
20
+
21
+ ```bash
22
+ npx --package=@buoy-gg/core buoy login
23
+ ```
24
+
25
+ For Expo, initialize Buoy before rendering the menu:
26
+
27
+ ```tsx
28
+ import { Buoy } from "@buoy-gg/core";
29
+
30
+ Buoy.init({ licenseKey: process.env.EXPO_PUBLIC_BUOY_KEY });
31
+ ```
32
+
33
+ The login command writes the Expo key to `.env.local`. For React Native CLI, pass the key from your app’s environment configuration; React Native does not load `.env.local` automatically. Mount `FloatingDevTools` inside the same providers as your screens and restart the development server after installation. The [Quick Start](https://buoy.gg/buoy/latest/docs/quick-start) shows the complete root component setup.
34
+
17
35
  ## Quick start
18
36
 
19
37
  ```tsx
@@ -31,25 +49,25 @@ export default function RootLayout() {
31
49
  }
32
50
  ```
33
51
 
34
- That's it. `FloatingDevTools` detects the package, mounts the route tracker for you, and the ROUTES tool shows up in the menu. It auto-detects whether you're on Expo Router or React Navigation and adapts.
52
+ After account setup, open Routes and navigate between two known screens. Check their paths and parameters. Keep your existing navigator and providers; supported data differs between Expo Router and React Navigation. The event duration is time since the previous navigation, not screen render time.
35
53
 
36
54
  ## What you get
37
55
 
38
- - **Full sitemap** — browse every route in your app, searchable, with route types (static, dynamic, layout) labeled
39
- - **Jump to any screen** — tap a route in the sitemap and navigate straight to it, params and all
56
+ - **Sitemap** — browse discovered routes, searchable, with route types (static, dynamic, layout) labeled
57
+ - **Navigate** — select a supported route and supply its required parameters. App navigation guards still apply
40
58
  - **Live navigation stack** — watch the stack push, pop, and replace as you move through the app
41
59
  - **Navigation event timeline** — every navigation logged with path, params, timestamp, and time since the previous one
42
60
  - **Filtering & search** — filter events by pathname pattern, search across routes
43
- - **Zero setup** — no `<RouteTracker />` to place, no config; the core menu wires it automatically
61
+ - **Tracker integration** — the core menu mounts the package’s route tracker
44
62
  - **Hooks for custom UIs** — `useRouteEvents`, `useRouteSitemap`, and `useNavigationStack` if you want the data without the modal
45
63
 
46
64
  ## Desktop & AI
47
65
 
48
- The same live session streams to [Buoy Desktop](https://github.com/Buoy-gg/Buoy-Desktop) (free, macOS/Windows/Linux) and to Claude Code or Cursor via the [Buoy MCP server](https://buoy.gg/buoy/latest/docs/mcp).
66
+ To connect a React Native app to [Buoy Desktop](https://github.com/Buoy-gg/Buoy-Desktop) or MCP, install `@buoy-gg/external-sync` and follow the [Desktop connection guide](https://buoy.gg/buoy/latest/docs/desktop). Sign in to Desktop separately. [MCP setup](https://buoy.gg/buoy/latest/docs/mcp) also requires a process account and Pro access. Available remote actions depend on the tool and app integration.
49
67
 
50
- ## Free vs Pro
68
+ ## Account and plan requirements
51
69
 
52
- Every tool is free. [Pro](https://buoy.gg/pricing) unlocks production builds, the MCP server, and unlimited capture. Every weekend, Pro features unlock free for anyone holding a key — including a free one (`npx buoy login`).
70
+ Use a Free or Pro Buoy account. History limits and paid features vary by tool; see [pricing](https://buoy.gg/pricing). Production access requires Pro where supported. Development-only hooks and actions remain unavailable in release builds.
53
71
 
54
72
  ---
55
73
 
@@ -10,6 +10,7 @@ var _useRouteObserver = require("./useRouteObserver");
10
10
  var _useRouteObserverReactNavigation = require("./useRouteObserverReactNavigation");
11
11
  var _useNavigationStack = require("./useNavigationStack");
12
12
  var _navigationStackStore = require("./stores/navigationStackStore");
13
+ var _routeEventStore = require("./stores/routeEventStore");
13
14
  var _jsxRuntime = require("react/jsx-runtime");
14
15
  /**
15
16
  * RouteTracker - A component to place inside your navigation tree
@@ -52,11 +53,20 @@ var _jsxRuntime = require("react/jsx-runtime");
52
53
  * ```
53
54
  */
54
55
 
56
+ // Mounted at boot by FloatingDevTools, so this is where capture starts —
57
+ // routeEventStore.hydrateBootCapture explains why the store needs it.
58
+ function useBootCapture() {
59
+ (0, _react.useEffect)(() => {
60
+ _routeEventStore.routeEventStore.hydrateBootCapture();
61
+ }, []);
62
+ }
55
63
  function ExpoRouteTracker() {
64
+ useBootCapture();
56
65
  (0, _useRouteObserver.useRouteObserver)();
57
66
  return null;
58
67
  }
59
68
  function ReactNavigationRouteTracker() {
69
+ useBootCapture();
60
70
  (0, _useRouteObserverReactNavigation.useRouteObserverReactNavigation)();
61
71
  return null;
62
72
  }
@@ -131,43 +131,30 @@ const RouteEventItemCompact = exports.RouteEventItemCompact = /*#__PURE__*/(0, _
131
131
  });
132
132
  }, [isExpanded, event, visitNumber, routeTemplate]);
133
133
 
134
- // Custom badge shows Go button (and badge text if present) when onNavigate is provided
135
- const customBadge = (0, _react.useMemo)(() => {
134
+ // The Go button lives beside the row, not inside its touchable (see
135
+ // CompactRow.trailingAction), so a press never opens the row as well.
136
+ const goButton = (0, _react.useMemo)(() => {
136
137
  if (!onNavigate) return undefined;
137
- return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
138
- style: styles.badgeContainer,
139
- children: [badgeText && /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
140
- style: [styles.badgeText, {
141
- color: statusColor
142
- }],
143
- testID: `${testID}-badge`,
144
- children: badgeText
145
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
146
- style: styles.goButton,
147
- onPress: e => {
148
- e.stopPropagation();
149
- onNavigate(event.pathname);
150
- },
151
- testID: `${testID}-go`,
152
- accessibilityRole: "button",
153
- accessibilityLabel: `Go to ${event.pathname}`,
154
- children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
155
- style: styles.goButtonText,
156
- children: "Go"
157
- })
158
- })]
138
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
139
+ style: styles.goButton,
140
+ onPress: () => onNavigate(event.pathname),
141
+ testID: `${testID}-go`,
142
+ accessibilityRole: "button",
143
+ accessibilityLabel: `Go to ${event.pathname}`,
144
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
145
+ style: styles.goButtonText,
146
+ children: "Go"
147
+ })
159
148
  });
160
- }, [onNavigate, event.pathname, badgeText, statusColor, testID]);
149
+ }, [onNavigate, event.pathname, testID]);
161
150
  return /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.CompactRow, {
162
151
  statusDotColor: statusColor,
163
152
  statusLabel: statusLabel,
164
153
  statusSublabel: statusSublabel,
165
- primaryText: event.pathname
166
- // Use badgeText when no customBadge, otherwise badge is inside customBadge
167
- ,
168
- badgeText: onNavigate ? undefined : badgeText,
154
+ primaryText: event.pathname,
155
+ badgeText: badgeText,
169
156
  badgeColor: statusColor,
170
- customBadge: customBadge,
157
+ trailingAction: goButton,
171
158
  bottomRightText: /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.RelativeTime, {
172
159
  timestamp: event.timestamp
173
160
  }),
@@ -183,11 +170,6 @@ const RouteEventItemCompact = exports.RouteEventItemCompact = /*#__PURE__*/(0, _
183
170
  });
184
171
  });
185
172
  const styles = _reactNative.StyleSheet.create({
186
- badgeContainer: {
187
- flexDirection: "row",
188
- alignItems: "center",
189
- gap: 6
190
- },
191
173
  badgeText: {
192
174
  fontSize: 11,
193
175
  fontWeight: "600",
@@ -11,6 +11,7 @@ var _safeReactNavigation = require("../utils/safeReactNavigation");
11
11
  var _sharedUi = require("@buoy-gg/shared-ui");
12
12
  var _license = require("@buoy-gg/license");
13
13
  var _useRouteEvents = require("../hooks/useRouteEvents");
14
+ var _routeEventStore = require("../stores/routeEventStore");
14
15
  var _RouteEventDetail = require("./RouteEventDetail");
15
16
  var _RouteFilterViewV = require("./RouteFilterViewV2");
16
17
  var _RoutesSitemap = require("./RoutesSitemap");
@@ -138,6 +139,13 @@ function RouteEventsModalWithTabs({
138
139
 
139
140
  // isListening = enabled and store is listening
140
141
  const isListening = isListeningEnabled && isStoreListening;
142
+
143
+ // The switch above only governs THIS component's subscription; the store
144
+ // also holds one of its own from boot (routeEventStore.setBootCapture), so
145
+ // pausing here has to release that too or capture would never stop.
146
+ (0, _react.useEffect)(() => {
147
+ _routeEventStore.routeEventStore.setBootCapture(isListeningEnabled);
148
+ }, [isListeningEnabled]);
141
149
  const [showFilters, setShowFilters] = (0, _react.useState)(false);
142
150
  // Selected event drives the full-screen detail view (parity with the Events
143
151
  // tool). null = list view. visitNumber feeds the "Visited N times" section.
@@ -40,6 +40,45 @@ var _RouteObserver = require("../RouteObserver");
40
40
  class RouteEventStore extends _sharedUi.BaseEventStore {
41
41
  // Unsubscribe function for routeObserver
42
42
  routeObserverUnsubscribe = null;
43
+ // The store's own subscription — see setBootCapture.
44
+ bootCaptureRelease = null;
45
+ bootCaptureHydrated = false;
46
+
47
+ /**
48
+ * Capture from app launch, not from the first open of the tool.
49
+ *
50
+ * A BaseEventStore only listens while something subscribes to it, and for
51
+ * routes that was the open modal or a watching desktop — so every
52
+ * navigation before the tool was first opened was simply never recorded,
53
+ * and the Events tab opened on "No route events yet" after a session of
54
+ * navigating. (It looked fine on any machine with Buoy Desktop running,
55
+ * because the desktop's watch subscribed at boot.) Network and storage both
56
+ * capture from launch; this holds a subscription of the store's own so
57
+ * routes does too.
58
+ *
59
+ * The hold follows the tool's persisted monitoring switch: the modal calls
60
+ * this on every toggle, and `hydrateBootCapture` reads the persisted value
61
+ * at boot so a paused tool stays paused across a relaunch.
62
+ */
63
+ setBootCapture(enabled) {
64
+ if (enabled && !this.bootCaptureRelease) {
65
+ this.bootCaptureRelease = this.subscribeToEvents(() => {});
66
+ } else if (!enabled && this.bootCaptureRelease) {
67
+ this.bootCaptureRelease();
68
+ this.bootCaptureRelease = null;
69
+ }
70
+ }
71
+
72
+ /** Arm boot capture from the persisted monitoring switch (default on). */
73
+ hydrateBootCapture() {
74
+ if (this.bootCaptureHydrated) return;
75
+ this.bootCaptureHydrated = true;
76
+ void _sharedUi.persistentStorage.getItem(_sharedUi.devToolsStorageKeys.routeEvents.isMonitoring()).then(raw => {
77
+ // The modal may already have decided while the read was in flight.
78
+ if (this.bootCaptureRelease) return;
79
+ this.setBootCapture(raw !== "false");
80
+ }).catch(() => this.setBootCapture(true));
81
+ }
43
82
  constructor() {
44
83
  super({
45
84
  storeName: "route-events",
@@ -47,12 +47,23 @@ import { useRouteObserver } from "./useRouteObserver";
47
47
  import { useRouteObserverReactNavigation } from "./useRouteObserverReactNavigation";
48
48
  import { useNavigationStack } from "./useNavigationStack";
49
49
  import { navigationStackStore } from "./stores/navigationStackStore";
50
+ import { routeEventStore } from "./stores/routeEventStore";
51
+
52
+ // Mounted at boot by FloatingDevTools, so this is where capture starts —
53
+ // routeEventStore.hydrateBootCapture explains why the store needs it.
50
54
  import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
55
+ function useBootCapture() {
56
+ useEffect(() => {
57
+ routeEventStore.hydrateBootCapture();
58
+ }, []);
59
+ }
51
60
  function ExpoRouteTracker() {
61
+ useBootCapture();
52
62
  useRouteObserver();
53
63
  return null;
54
64
  }
55
65
  function ReactNavigationRouteTracker() {
66
+ useBootCapture();
56
67
  useRouteObserverReactNavigation();
57
68
  return null;
58
69
  }
@@ -7,14 +7,14 @@
7
7
  */
8
8
 
9
9
  import { memo, useMemo } from "react";
10
- import { View, Text, TouchableOpacity, StyleSheet } from "react-native";
10
+ import { Text, TouchableOpacity, StyleSheet } from "react-native";
11
11
  import { CompactRow, RelativeTime, buoyColors, night, monoFont } from "@buoy-gg/shared-ui";
12
12
  import { RouteEventExpandedContent } from "./RouteEventExpandedContent";
13
13
  import { getRouteTemplate } from "../utils/routeTemplate";
14
14
  import { eventRowTestID } from "../utils/testIDs";
15
15
 
16
16
  // Route type for color coding
17
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
17
+ import { jsx as _jsx } from "react/jsx-runtime";
18
18
  // Get route type for color coding
19
19
  function getRouteType(event) {
20
20
  if (event.pathname === "/") {
@@ -127,43 +127,30 @@ export const RouteEventItemCompact = /*#__PURE__*/memo(function RouteEventItemCo
127
127
  });
128
128
  }, [isExpanded, event, visitNumber, routeTemplate]);
129
129
 
130
- // Custom badge shows Go button (and badge text if present) when onNavigate is provided
131
- const customBadge = useMemo(() => {
130
+ // The Go button lives beside the row, not inside its touchable (see
131
+ // CompactRow.trailingAction), so a press never opens the row as well.
132
+ const goButton = useMemo(() => {
132
133
  if (!onNavigate) return undefined;
133
- return /*#__PURE__*/_jsxs(View, {
134
- style: styles.badgeContainer,
135
- children: [badgeText && /*#__PURE__*/_jsx(Text, {
136
- style: [styles.badgeText, {
137
- color: statusColor
138
- }],
139
- testID: `${testID}-badge`,
140
- children: badgeText
141
- }), /*#__PURE__*/_jsx(TouchableOpacity, {
142
- style: styles.goButton,
143
- onPress: e => {
144
- e.stopPropagation();
145
- onNavigate(event.pathname);
146
- },
147
- testID: `${testID}-go`,
148
- accessibilityRole: "button",
149
- accessibilityLabel: `Go to ${event.pathname}`,
150
- children: /*#__PURE__*/_jsx(Text, {
151
- style: styles.goButtonText,
152
- children: "Go"
153
- })
154
- })]
134
+ return /*#__PURE__*/_jsx(TouchableOpacity, {
135
+ style: styles.goButton,
136
+ onPress: () => onNavigate(event.pathname),
137
+ testID: `${testID}-go`,
138
+ accessibilityRole: "button",
139
+ accessibilityLabel: `Go to ${event.pathname}`,
140
+ children: /*#__PURE__*/_jsx(Text, {
141
+ style: styles.goButtonText,
142
+ children: "Go"
143
+ })
155
144
  });
156
- }, [onNavigate, event.pathname, badgeText, statusColor, testID]);
145
+ }, [onNavigate, event.pathname, testID]);
157
146
  return /*#__PURE__*/_jsx(CompactRow, {
158
147
  statusDotColor: statusColor,
159
148
  statusLabel: statusLabel,
160
149
  statusSublabel: statusSublabel,
161
- primaryText: event.pathname
162
- // Use badgeText when no customBadge, otherwise badge is inside customBadge
163
- ,
164
- badgeText: onNavigate ? undefined : badgeText,
150
+ primaryText: event.pathname,
151
+ badgeText: badgeText,
165
152
  badgeColor: statusColor,
166
- customBadge: customBadge,
153
+ trailingAction: goButton,
167
154
  bottomRightText: /*#__PURE__*/_jsx(RelativeTime, {
168
155
  timestamp: event.timestamp
169
156
  }),
@@ -179,11 +166,6 @@ export const RouteEventItemCompact = /*#__PURE__*/memo(function RouteEventItemCo
179
166
  });
180
167
  });
181
168
  const styles = StyleSheet.create({
182
- badgeContainer: {
183
- flexDirection: "row",
184
- alignItems: "center",
185
- gap: 6
186
- },
187
169
  badgeText: {
188
170
  fontSize: 11,
189
171
  fontWeight: "600",
@@ -15,6 +15,7 @@ import { useIsPro } from "@buoy-gg/license";
15
15
  // Free tier limit for route events
16
16
 
17
17
  import { useRouteEvents } from "../hooks/useRouteEvents";
18
+ import { routeEventStore } from "../stores/routeEventStore";
18
19
  import { RouteEventDetail } from "./RouteEventDetail";
19
20
  import { RouteFilterViewV2 } from "./RouteFilterViewV2";
20
21
  import { RoutesSitemap } from "./RoutesSitemap";
@@ -135,6 +136,13 @@ export function RouteEventsModalWithTabs({
135
136
 
136
137
  // isListening = enabled and store is listening
137
138
  const isListening = isListeningEnabled && isStoreListening;
139
+
140
+ // The switch above only governs THIS component's subscription; the store
141
+ // also holds one of its own from boot (routeEventStore.setBootCapture), so
142
+ // pausing here has to release that too or capture would never stop.
143
+ useEffect(() => {
144
+ routeEventStore.setBootCapture(isListeningEnabled);
145
+ }, [isListeningEnabled]);
138
146
  const [showFilters, setShowFilters] = useState(false);
139
147
  // Selected event drives the full-screen detail view (parity with the Events
140
148
  // tool). null = list view. visitNumber feeds the "Visited N times" section.
@@ -21,7 +21,7 @@
21
21
  * ```
22
22
  */
23
23
 
24
- import { BaseEventStore } from "@buoy-gg/shared-ui";
24
+ import { BaseEventStore, devToolsStorageKeys, persistentStorage } from "@buoy-gg/shared-ui";
25
25
  import { routeObserver } from "../RouteObserver";
26
26
 
27
27
  // Re-export types for convenience
@@ -37,6 +37,45 @@ import { routeObserver } from "../RouteObserver";
37
37
  class RouteEventStore extends BaseEventStore {
38
38
  // Unsubscribe function for routeObserver
39
39
  routeObserverUnsubscribe = null;
40
+ // The store's own subscription — see setBootCapture.
41
+ bootCaptureRelease = null;
42
+ bootCaptureHydrated = false;
43
+
44
+ /**
45
+ * Capture from app launch, not from the first open of the tool.
46
+ *
47
+ * A BaseEventStore only listens while something subscribes to it, and for
48
+ * routes that was the open modal or a watching desktop — so every
49
+ * navigation before the tool was first opened was simply never recorded,
50
+ * and the Events tab opened on "No route events yet" after a session of
51
+ * navigating. (It looked fine on any machine with Buoy Desktop running,
52
+ * because the desktop's watch subscribed at boot.) Network and storage both
53
+ * capture from launch; this holds a subscription of the store's own so
54
+ * routes does too.
55
+ *
56
+ * The hold follows the tool's persisted monitoring switch: the modal calls
57
+ * this on every toggle, and `hydrateBootCapture` reads the persisted value
58
+ * at boot so a paused tool stays paused across a relaunch.
59
+ */
60
+ setBootCapture(enabled) {
61
+ if (enabled && !this.bootCaptureRelease) {
62
+ this.bootCaptureRelease = this.subscribeToEvents(() => {});
63
+ } else if (!enabled && this.bootCaptureRelease) {
64
+ this.bootCaptureRelease();
65
+ this.bootCaptureRelease = null;
66
+ }
67
+ }
68
+
69
+ /** Arm boot capture from the persisted monitoring switch (default on). */
70
+ hydrateBootCapture() {
71
+ if (this.bootCaptureHydrated) return;
72
+ this.bootCaptureHydrated = true;
73
+ void persistentStorage.getItem(devToolsStorageKeys.routeEvents.isMonitoring()).then(raw => {
74
+ // The modal may already have decided while the read was in flight.
75
+ if (this.bootCaptureRelease) return;
76
+ this.setBootCapture(raw !== "false");
77
+ }).catch(() => this.setBootCapture(true));
78
+ }
40
79
  constructor() {
41
80
  super({
42
81
  storeName: "route-events",
@@ -1 +1 @@
1
- {"version":3,"file":"RouteTracker.d.ts","sourceRoot":"","sources":["../../src/RouteTracker.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AAiDH,wBAAgB,YAAY,gCAQ3B"}
1
+ {"version":3,"file":"RouteTracker.d.ts","sourceRoot":"","sources":["../../src/RouteTracker.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AA4DH,wBAAgB,YAAY,gCAQ3B"}
@@ -1 +1 @@
1
- {"version":3,"file":"RouteEventItemCompact.d.ts","sourceRoot":"","sources":["../../../src/components/RouteEventItemCompact.tsx"],"names":[],"mappings":"AAAA;;;;GAIG;AAKH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAKzD,MAAM,WAAW,0BAA0B;IACzC,KAAK,EAAE,gBAAgB,CAAC;IACxB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,OAAO,CAAC;IACpB;0DACsD;IACtD,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACjC,UAAU,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;CACzC;AA6FD,eAAO,MAAM,qBAAqB,kEA0FhC,CAAC"}
1
+ {"version":3,"file":"RouteEventItemCompact.d.ts","sourceRoot":"","sources":["../../../src/components/RouteEventItemCompact.tsx"],"names":[],"mappings":"AAAA;;;;GAIG;AAKH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAKzD,MAAM,WAAW,0BAA0B;IACzC,KAAK,EAAE,gBAAgB,CAAC;IACxB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,OAAO,CAAC;IACpB;0DACsD;IACtD,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACjC,UAAU,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;CACzC;AA6FD,eAAO,MAAM,qBAAqB,kEA6EhC,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"RouteEventsModalWithTabs.d.ts","sourceRoot":"","sources":["../../../src/components/RouteEventsModalWithTabs.tsx"],"names":[],"mappings":"AA0DA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAGhD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAC9D,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,mBAAmB,CAAC;AAGnE,MAAM,WAAW,6BAA6B;IAC5C,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;IACpB,UAAU,CAAC,EAAE,CAAC,UAAU,EAAE,GAAG,KAAK,IAAI,CAAC;IACvC,2BAA2B,CAAC,EAAE,OAAO,CAAC;IACtC;;;;;OAKG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB;;;;;OAKG;IACH,MAAM,CAAC,EAAE;QACP,OAAO,CAAC,EAAE;YACR,MAAM,CAAC,EAAE,SAAS,EAAE,CAAC;YACrB,MAAM,CAAC,EAAE,OAAO,GAAG,KAAK,GAAG,IAAI,CAAC;YAChC,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;SAC/B,CAAC;QACF,KAAK,CAAC,EAAE,gBAAgB,EAAE,CAAC;QAC3B;;;;WAIG;QACH,eAAe,CAAC,EAAE,CAAC,KAAK,EAAE,SAAS,KAAK,IAAI,CAAC;QAC7C;;;;;WAKG;QACH,cAAc,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;QAC5C,2EAA2E;QAC3E,aAAa,CAAC,EAAE,CACd,MAAM,EAAE,yBAAyB,EACjC,OAAO,CAAC,EAAE;YAAE,KAAK,CAAC,EAAE,MAAM,CAAA;SAAE,KACzB,IAAI,CAAC;KACX,CAAC;CACH;AAgED,wBAAgB,wBAAwB,CAAC,EACvC,OAAO,EACP,OAAO,EACP,MAAM,EACN,UAAU,EACV,2BAAmC,EACnC,MAAc,EACd,MAAM,GACP,EAAE,6BAA6B,sCAqmB/B;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAC5B,KAAK,GAAE,IAAI,CAAC,6BAA6B,EAAE,SAAS,GAAG,SAAS,GAAG,QAAQ,CAAM,+BAKlF"}
1
+ {"version":3,"file":"RouteEventsModalWithTabs.d.ts","sourceRoot":"","sources":["../../../src/components/RouteEventsModalWithTabs.tsx"],"names":[],"mappings":"AA0DA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAGhD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAC9D,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,mBAAmB,CAAC;AAGnE,MAAM,WAAW,6BAA6B;IAC5C,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;IACpB,UAAU,CAAC,EAAE,CAAC,UAAU,EAAE,GAAG,KAAK,IAAI,CAAC;IACvC,2BAA2B,CAAC,EAAE,OAAO,CAAC;IACtC;;;;;OAKG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB;;;;;OAKG;IACH,MAAM,CAAC,EAAE;QACP,OAAO,CAAC,EAAE;YACR,MAAM,CAAC,EAAE,SAAS,EAAE,CAAC;YACrB,MAAM,CAAC,EAAE,OAAO,GAAG,KAAK,GAAG,IAAI,CAAC;YAChC,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;SAC/B,CAAC;QACF,KAAK,CAAC,EAAE,gBAAgB,EAAE,CAAC;QAC3B;;;;WAIG;QACH,eAAe,CAAC,EAAE,CAAC,KAAK,EAAE,SAAS,KAAK,IAAI,CAAC;QAC7C;;;;;WAKG;QACH,cAAc,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;QAC5C,2EAA2E;QAC3E,aAAa,CAAC,EAAE,CACd,MAAM,EAAE,yBAAyB,EACjC,OAAO,CAAC,EAAE;YAAE,KAAK,CAAC,EAAE,MAAM,CAAA;SAAE,KACzB,IAAI,CAAC;KACX,CAAC;CACH;AAgED,wBAAgB,wBAAwB,CAAC,EACvC,OAAO,EACP,OAAO,EACP,MAAM,EACN,UAAU,EACV,2BAAmC,EACnC,MAAc,EACd,MAAM,GACP,EAAE,6BAA6B,sCA4mB/B;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAC5B,KAAK,GAAE,IAAI,CAAC,6BAA6B,EAAE,SAAS,GAAG,SAAS,GAAG,QAAQ,CAAM,+BAKlF"}
@@ -31,6 +31,27 @@ export type RouteEventListener = (events: RouteChangeEvent[]) => void;
31
31
  export type RouteEventCallback = (event: RouteChangeEvent) => void;
32
32
  declare class RouteEventStore extends BaseEventStore<RouteChangeEvent> {
33
33
  private routeObserverUnsubscribe;
34
+ private bootCaptureRelease;
35
+ private bootCaptureHydrated;
36
+ /**
37
+ * Capture from app launch, not from the first open of the tool.
38
+ *
39
+ * A BaseEventStore only listens while something subscribes to it, and for
40
+ * routes that was the open modal or a watching desktop — so every
41
+ * navigation before the tool was first opened was simply never recorded,
42
+ * and the Events tab opened on "No route events yet" after a session of
43
+ * navigating. (It looked fine on any machine with Buoy Desktop running,
44
+ * because the desktop's watch subscribed at boot.) Network and storage both
45
+ * capture from launch; this holds a subscription of the store's own so
46
+ * routes does too.
47
+ *
48
+ * The hold follows the tool's persisted monitoring switch: the modal calls
49
+ * this on every toggle, and `hydrateBootCapture` reads the persisted value
50
+ * at boot so a paused tool stays paused across a relaunch.
51
+ */
52
+ setBootCapture(enabled: boolean): void;
53
+ /** Arm boot capture from the persisted monitoring switch (default on). */
54
+ hydrateBootCapture(): void;
34
55
  constructor();
35
56
  /**
36
57
  * Start listening to route changes from routeObserver
@@ -1 +1 @@
1
- {"version":3,"file":"routeEventStore.d.ts","sourceRoot":"","sources":["../../../src/stores/routeEventStore.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,EAAiB,KAAK,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAGxE,YAAY,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAEzD;;GAEG;AACH,MAAM,MAAM,kBAAkB,GAAG,CAAC,MAAM,EAAE,gBAAgB,EAAE,KAAK,IAAI,CAAC;AAEtE;;GAEG;AACH,MAAM,MAAM,kBAAkB,GAAG,CAAC,KAAK,EAAE,gBAAgB,KAAK,IAAI,CAAC;AAEnE,cAAM,eAAgB,SAAQ,cAAc,CAAC,gBAAgB,CAAC;IAE5D,OAAO,CAAC,wBAAwB,CAA6B;;IAS7D;;OAEG;IACH,SAAS,CAAC,cAAc,IAAI,IAAI;IAQhC;;OAEG;IACH,SAAS,CAAC,aAAa,IAAI,IAAI;IAO/B;;OAEG;IACH,WAAW,IAAI,OAAO;IAKtB,WAAW,IAAI,OAAO;CAGvB;AAGD,eAAO,MAAM,eAAe,iBAAwB,CAAC;AAGrD,eAAO,MAAM,sBAAsB,GAAI,UAAU,kBAAkB,eACtB,CAAC;AAC9C,eAAO,MAAM,YAAY,GAAI,UAAU,kBAAkB,eACtB,CAAC;AACpC,eAAO,MAAM,cAAc,0BAAoC,CAAC;AAChE,eAAO,MAAM,gBAAgB,YAAsC,CAAC;AACpE,eAAO,MAAM,gBAAgB,eAAsC,CAAC"}
1
+ {"version":3,"file":"routeEventStore.d.ts","sourceRoot":"","sources":["../../../src/stores/routeEventStore.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,EACL,cAAc,EAGf,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAiB,KAAK,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAGxE,YAAY,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAEzD;;GAEG;AACH,MAAM,MAAM,kBAAkB,GAAG,CAAC,MAAM,EAAE,gBAAgB,EAAE,KAAK,IAAI,CAAC;AAEtE;;GAEG;AACH,MAAM,MAAM,kBAAkB,GAAG,CAAC,KAAK,EAAE,gBAAgB,KAAK,IAAI,CAAC;AAEnE,cAAM,eAAgB,SAAQ,cAAc,CAAC,gBAAgB,CAAC;IAE5D,OAAO,CAAC,wBAAwB,CAA6B;IAE7D,OAAO,CAAC,kBAAkB,CAA6B;IACvD,OAAO,CAAC,mBAAmB,CAAS;IAEpC;;;;;;;;;;;;;;;OAeG;IACH,cAAc,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI;IAStC,0EAA0E;IAC1E,kBAAkB,IAAI,IAAI;;IAoB1B;;OAEG;IACH,SAAS,CAAC,cAAc,IAAI,IAAI;IAQhC;;OAEG;IACH,SAAS,CAAC,aAAa,IAAI,IAAI;IAO/B;;OAEG;IACH,WAAW,IAAI,OAAO;IAKtB,WAAW,IAAI,OAAO;CAGvB;AAGD,eAAO,MAAM,eAAe,iBAAwB,CAAC;AAGrD,eAAO,MAAM,sBAAsB,GAAI,UAAU,kBAAkB,eACtB,CAAC;AAC9C,eAAO,MAAM,YAAY,GAAI,UAAU,kBAAkB,eACtB,CAAC;AACpC,eAAO,MAAM,cAAc,0BAAoC,CAAC;AAChE,eAAO,MAAM,gBAAgB,YAAsC,CAAC;AACpE,eAAO,MAAM,gBAAgB,eAAsC,CAAC"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@buoy-gg/route-events",
3
- "version": "7.0.36",
4
- "description": "Navigation devtool for React Native — live stack, full sitemap, jump to any screen. Expo Router & React Navigation. Part of Buoy devtools.",
3
+ "version": "7.0.38",
4
+ "description": "Inspect reported navigation state and supported route actions in React Native apps using Expo Router or React Navigation.",
5
5
  "main": "lib/commonjs/index.js",
6
6
  "module": "lib/module/index.js",
7
7
  "types": "lib/typescript/index.d.ts",
@@ -26,12 +26,11 @@
26
26
  ],
27
27
  "sideEffects": false,
28
28
  "dependencies": {
29
- "@buoy-gg/shared-ui": "^7.0.36",
30
- "@buoy-gg/floating-tools-core": "^7.0.36"
29
+ "@buoy-gg/floating-tools-core": "^7.0.38",
30
+ "@buoy-gg/shared-ui": "^7.0.38"
31
31
  },
32
32
  "peerDependencies": {
33
- "@buoy-gg/license": "7.0.36",
34
- "@react-native-async-storage/async-storage": "^2.0.0 || ^3.1.0",
33
+ "@buoy-gg/license": "7.0.38",
35
34
  "@react-navigation/native": "*",
36
35
  "expo-router": "*",
37
36
  "react": "*",
@@ -52,7 +51,7 @@
52
51
  "@types/react-native": "^0.73.0",
53
52
  "expo-router": "~5.0.7",
54
53
  "typescript": "~5.8.3",
55
- "@buoy-gg/license": "^7.0.36"
54
+ "@buoy-gg/license": "^7.0.38"
56
55
  },
57
56
  "react-native-builder-bob": {
58
57
  "source": "src",