@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 +26 -8
- package/lib/commonjs/RouteTracker.js +10 -0
- package/lib/commonjs/components/RouteEventItemCompact.js +17 -35
- package/lib/commonjs/components/RouteEventsModalWithTabs.js +8 -0
- package/lib/commonjs/stores/routeEventStore.js +39 -0
- package/lib/module/RouteTracker.js +11 -0
- package/lib/module/components/RouteEventItemCompact.js +19 -37
- package/lib/module/components/RouteEventsModalWithTabs.js +8 -0
- package/lib/module/stores/routeEventStore.js +40 -1
- package/lib/typescript/RouteTracker.d.ts.map +1 -1
- package/lib/typescript/components/RouteEventItemCompact.d.ts.map +1 -1
- package/lib/typescript/components/RouteEventsModalWithTabs.d.ts.map +1 -1
- package/lib/typescript/stores/routeEventStore.d.ts +21 -0
- package/lib/typescript/stores/routeEventStore.d.ts.map +1 -1
- package/package.json +6 -7
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
[](https://www.npmjs.com/package/@buoy-gg/route-events) [](https://www.npmjs.com/package/@buoy-gg/route-events)
|
|
4
4
|
|
|
5
|
-
|
|
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
|
-
|
|
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
|
-
- **
|
|
39
|
-
- **
|
|
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
|
-
- **
|
|
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
|
-
|
|
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
|
-
##
|
|
68
|
+
## Account and plan requirements
|
|
51
69
|
|
|
52
|
-
|
|
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
|
-
//
|
|
135
|
-
|
|
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.
|
|
138
|
-
style: styles.
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
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,
|
|
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
|
-
|
|
167
|
-
,
|
|
168
|
-
badgeText: onNavigate ? undefined : badgeText,
|
|
154
|
+
primaryText: event.pathname,
|
|
155
|
+
badgeText: badgeText,
|
|
169
156
|
badgeColor: statusColor,
|
|
170
|
-
|
|
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 {
|
|
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
|
|
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
|
-
//
|
|
131
|
-
|
|
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__*/
|
|
134
|
-
style: styles.
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
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,
|
|
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
|
-
|
|
163
|
-
,
|
|
164
|
-
badgeText: onNavigate ? undefined : badgeText,
|
|
150
|
+
primaryText: event.pathname,
|
|
151
|
+
badgeText: badgeText,
|
|
165
152
|
badgeColor: statusColor,
|
|
166
|
-
|
|
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;
|
|
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,
|
|
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,
|
|
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,
|
|
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.
|
|
4
|
-
"description": "
|
|
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/
|
|
30
|
-
"@buoy-gg/
|
|
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.
|
|
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.
|
|
54
|
+
"@buoy-gg/license": "^7.0.38"
|
|
56
55
|
},
|
|
57
56
|
"react-native-builder-bob": {
|
|
58
57
|
"source": "src",
|