@buoy-gg/network 7.0.3 → 7.0.5
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 +3 -2
- package/lib/commonjs/index.js +85 -0
- package/lib/commonjs/network/components/NetworkEventDetailView.js +201 -40
- package/lib/commonjs/network/components/NetworkEventItemCompact.js +52 -5
- package/lib/commonjs/network/components/NetworkHeaderLive.js +132 -0
- package/lib/commonjs/network/components/NetworkListScreen.js +134 -56
- package/lib/commonjs/network/components/NetworkModal.js +154 -36
- package/lib/commonjs/network/components/NetworkSavedScreen.js +245 -0
- package/lib/commonjs/network/components/NetworkUpgradeBanner.js +76 -0
- package/lib/commonjs/network/hooks/useLiveNetworkEvent.js +62 -0
- package/lib/commonjs/network/hooks/useNetworkSaved.js +38 -0
- package/lib/commonjs/network/index.js +84 -0
- package/lib/commonjs/network/sync/networkSyncAdapter.js +85 -7
- package/lib/commonjs/network/utils/generateCurl.js +71 -0
- package/lib/commonjs/network/utils/networkEventStore.js +10 -1
- package/lib/commonjs/network/utils/networkListener.js +54 -1
- package/lib/commonjs/network/utils/networkSavedStore.js +575 -0
- package/lib/commonjs/network/utils/withPinnedFirst.js +32 -0
- package/lib/module/index.js +17 -1
- package/lib/module/network/components/NetworkEventDetailView.js +204 -41
- package/lib/module/network/components/NetworkEventItemCompact.js +53 -6
- package/lib/module/network/components/NetworkHeaderLive.js +132 -2
- package/lib/module/network/components/NetworkListScreen.js +136 -58
- package/lib/module/network/components/NetworkModal.js +156 -39
- package/lib/module/network/components/NetworkSavedScreen.js +241 -0
- package/lib/module/network/components/NetworkUpgradeBanner.js +72 -0
- package/lib/module/network/hooks/useLiveNetworkEvent.js +58 -0
- package/lib/module/network/hooks/useNetworkSaved.js +34 -0
- package/lib/module/network/index.js +7 -1
- package/lib/module/network/sync/networkSyncAdapter.js +85 -7
- package/lib/module/network/utils/generateCurl.js +67 -0
- package/lib/module/network/utils/networkEventStore.js +10 -1
- package/lib/module/network/utils/networkListener.js +54 -1
- package/lib/module/network/utils/networkSavedStore.js +569 -0
- package/lib/module/network/utils/withPinnedFirst.js +28 -0
- package/lib/typescript/index.d.ts +13 -1
- package/lib/typescript/index.d.ts.map +1 -1
- package/lib/typescript/network/components/NetworkEventDetailView.d.ts.map +1 -1
- package/lib/typescript/network/components/NetworkEventItemCompact.d.ts +12 -0
- package/lib/typescript/network/components/NetworkEventItemCompact.d.ts.map +1 -1
- package/lib/typescript/network/components/NetworkHeaderLive.d.ts +28 -0
- package/lib/typescript/network/components/NetworkHeaderLive.d.ts.map +1 -1
- package/lib/typescript/network/components/NetworkListScreen.d.ts.map +1 -1
- package/lib/typescript/network/components/NetworkModal.d.ts +34 -0
- package/lib/typescript/network/components/NetworkModal.d.ts.map +1 -1
- package/lib/typescript/network/components/NetworkSavedScreen.d.ts +29 -0
- package/lib/typescript/network/components/NetworkSavedScreen.d.ts.map +1 -0
- package/lib/typescript/network/components/NetworkUpgradeBanner.d.ts +17 -0
- package/lib/typescript/network/components/NetworkUpgradeBanner.d.ts.map +1 -0
- package/lib/typescript/network/hooks/useLiveNetworkEvent.d.ts +19 -0
- package/lib/typescript/network/hooks/useLiveNetworkEvent.d.ts.map +1 -0
- package/lib/typescript/network/hooks/useNetworkSaved.d.ts +21 -0
- package/lib/typescript/network/hooks/useNetworkSaved.d.ts.map +1 -0
- package/lib/typescript/network/index.d.ts +8 -1
- package/lib/typescript/network/index.d.ts.map +1 -1
- package/lib/typescript/network/sync/networkSyncAdapter.d.ts +52 -3
- package/lib/typescript/network/sync/networkSyncAdapter.d.ts.map +1 -1
- package/lib/typescript/network/types/index.d.ts +43 -0
- package/lib/typescript/network/types/index.d.ts.map +1 -1
- package/lib/typescript/network/utils/generateCurl.d.ts +3 -0
- package/lib/typescript/network/utils/generateCurl.d.ts.map +1 -0
- package/lib/typescript/network/utils/networkEventStore.d.ts.map +1 -1
- package/lib/typescript/network/utils/networkListener.d.ts +4 -0
- package/lib/typescript/network/utils/networkListener.d.ts.map +1 -1
- package/lib/typescript/network/utils/networkSavedStore.d.ts +186 -0
- package/lib/typescript/network/utils/networkSavedStore.d.ts.map +1 -0
- package/lib/typescript/network/utils/withPinnedFirst.d.ts +24 -0
- package/lib/typescript/network/utils/withPinnedFirst.d.ts.map +1 -0
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -39,8 +39,9 @@ Want a different label or color? Build the tool with `createNetworkTool({ name,
|
|
|
39
39
|
- **GraphQL gets special treatment** — operation names are extracted from queries, mutations, and subscriptions and shown with variables in arrow notation: `GetUser › 123`. No more guessing which `/graphql` request is which.
|
|
40
40
|
- **Full request detail** — request/response headers, payloads, HTTP status, and duration for every call, with status-colored rows.
|
|
41
41
|
- **Filter and search** — narrow by status code, HTTP method, or URL pattern; search captured events; pause/resume capture; clear history.
|
|
42
|
+
- **Pin the one that failed** — pin a request to hold it at the top of the list (ignoring your filters), or save it to a separate favorites list. Both keep a full snapshot, so it survives Clear, the 500-request cap, and an app restart. Long-press a row, or use the buttons in the request detail header.
|
|
42
43
|
- **Ignore the noise** — a shared ignored-domains/URL filter (`useIgnoredPatterns`) hides endpoints you never want to see, shared with the Events tool.
|
|
43
|
-
- **Hooks for custom UIs** — `useNetworkEvents`, `useNetworkEventList`, and `
|
|
44
|
+
- **Hooks for custom UIs** — `useNetworkEvents`, `useNetworkEventList`, `useNetworkBadgeCounts`, and `useNetworkSaved` expose the capture stream with narrow per-consumer subscriptions.
|
|
44
45
|
|
|
45
46
|
## Desktop & AI
|
|
46
47
|
|
|
@@ -50,7 +51,7 @@ The same live session streams to [Buoy Desktop](https://github.com/Buoy-gg/Buoy-
|
|
|
50
51
|
|
|
51
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 everyone.
|
|
52
53
|
|
|
53
|
-
> 🎯 **Flutter (beta):** Buoy is now
|
|
54
|
+
> 🎯 **Flutter (beta):** Buoy is now a full suite for Flutter — `flutter pub add buoy`. Network, storage, console, env, routes, images, Riverpod, events, and a live perf HUD, all streaming to the same desktop dashboard and MCP server. [Details →](https://buoy.gg/flutter)
|
|
54
55
|
|
|
55
56
|
---
|
|
56
57
|
|
package/lib/commonjs/index.js
CHANGED
|
@@ -3,12 +3,36 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", {
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
|
+
Object.defineProperty(exports, "FREE_TIER_SAVED_LIMIT", {
|
|
7
|
+
enumerable: true,
|
|
8
|
+
get: function () {
|
|
9
|
+
return _networkSavedStore.FREE_TIER_SAVED_LIMIT;
|
|
10
|
+
}
|
|
11
|
+
});
|
|
12
|
+
Object.defineProperty(exports, "MAX_PINNED", {
|
|
13
|
+
enumerable: true,
|
|
14
|
+
get: function () {
|
|
15
|
+
return _networkSavedStore.MAX_PINNED;
|
|
16
|
+
}
|
|
17
|
+
});
|
|
18
|
+
Object.defineProperty(exports, "MAX_SAVED", {
|
|
19
|
+
enumerable: true,
|
|
20
|
+
get: function () {
|
|
21
|
+
return _networkSavedStore.MAX_SAVED;
|
|
22
|
+
}
|
|
23
|
+
});
|
|
6
24
|
Object.defineProperty(exports, "NetworkBodyResolverProvider", {
|
|
7
25
|
enumerable: true,
|
|
8
26
|
get: function () {
|
|
9
27
|
return _networkBodyResolver.NetworkBodyResolverProvider;
|
|
10
28
|
}
|
|
11
29
|
});
|
|
30
|
+
Object.defineProperty(exports, "NetworkDetailPinActions", {
|
|
31
|
+
enumerable: true,
|
|
32
|
+
get: function () {
|
|
33
|
+
return _NetworkHeaderLive.NetworkDetailPinActions;
|
|
34
|
+
}
|
|
35
|
+
});
|
|
12
36
|
Object.defineProperty(exports, "NetworkEventDetailView", {
|
|
13
37
|
enumerable: true,
|
|
14
38
|
get: function () {
|
|
@@ -27,6 +51,24 @@ Object.defineProperty(exports, "NetworkModal", {
|
|
|
27
51
|
return _NetworkModal.NetworkModal;
|
|
28
52
|
}
|
|
29
53
|
});
|
|
54
|
+
Object.defineProperty(exports, "NetworkSavedButton", {
|
|
55
|
+
enumerable: true,
|
|
56
|
+
get: function () {
|
|
57
|
+
return _NetworkHeaderLive.NetworkSavedButton;
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
Object.defineProperty(exports, "NetworkSavedScreen", {
|
|
61
|
+
enumerable: true,
|
|
62
|
+
get: function () {
|
|
63
|
+
return _NetworkSavedScreen.NetworkSavedScreen;
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
Object.defineProperty(exports, "NetworkToolView", {
|
|
67
|
+
enumerable: true,
|
|
68
|
+
get: function () {
|
|
69
|
+
return _NetworkModal.NetworkToolView;
|
|
70
|
+
}
|
|
71
|
+
});
|
|
30
72
|
Object.defineProperty(exports, "TickProvider", {
|
|
31
73
|
enumerable: true,
|
|
32
74
|
get: function () {
|
|
@@ -45,6 +87,12 @@ Object.defineProperty(exports, "createNetworkTool", {
|
|
|
45
87
|
return _preset.createNetworkTool;
|
|
46
88
|
}
|
|
47
89
|
});
|
|
90
|
+
Object.defineProperty(exports, "flagsForEventId", {
|
|
91
|
+
enumerable: true,
|
|
92
|
+
get: function () {
|
|
93
|
+
return _networkSavedStore.flagsForEventId;
|
|
94
|
+
}
|
|
95
|
+
});
|
|
48
96
|
Object.defineProperty(exports, "formatBytes", {
|
|
49
97
|
enumerable: true,
|
|
50
98
|
get: function () {
|
|
@@ -63,6 +111,12 @@ Object.defineProperty(exports, "formatHttpStatus", {
|
|
|
63
111
|
return _formatting.formatHttpStatus;
|
|
64
112
|
}
|
|
65
113
|
});
|
|
114
|
+
Object.defineProperty(exports, "generateCurl", {
|
|
115
|
+
enumerable: true,
|
|
116
|
+
get: function () {
|
|
117
|
+
return _generateCurl.generateCurl;
|
|
118
|
+
}
|
|
119
|
+
});
|
|
66
120
|
Object.defineProperty(exports, "ignoredPatternsStore", {
|
|
67
121
|
enumerable: true,
|
|
68
122
|
get: function () {
|
|
@@ -87,6 +141,12 @@ Object.defineProperty(exports, "networkListener", {
|
|
|
87
141
|
return _networkListener.networkListener;
|
|
88
142
|
}
|
|
89
143
|
});
|
|
144
|
+
Object.defineProperty(exports, "networkSavedStore", {
|
|
145
|
+
enumerable: true,
|
|
146
|
+
get: function () {
|
|
147
|
+
return _networkSavedStore.networkSavedStore;
|
|
148
|
+
}
|
|
149
|
+
});
|
|
90
150
|
Object.defineProperty(exports, "networkSyncAdapter", {
|
|
91
151
|
enumerable: true,
|
|
92
152
|
get: function () {
|
|
@@ -105,6 +165,12 @@ Object.defineProperty(exports, "removeAllNetworkListeners", {
|
|
|
105
165
|
return _networkListener.removeAllNetworkListeners;
|
|
106
166
|
}
|
|
107
167
|
});
|
|
168
|
+
Object.defineProperty(exports, "splitPinned", {
|
|
169
|
+
enumerable: true,
|
|
170
|
+
get: function () {
|
|
171
|
+
return _withPinnedFirst.splitPinned;
|
|
172
|
+
}
|
|
173
|
+
});
|
|
108
174
|
Object.defineProperty(exports, "urlMatchesIgnoredPattern", {
|
|
109
175
|
enumerable: true,
|
|
110
176
|
get: function () {
|
|
@@ -117,6 +183,12 @@ Object.defineProperty(exports, "useIgnoredPatterns", {
|
|
|
117
183
|
return _sharedUi.useIgnoredPatterns;
|
|
118
184
|
}
|
|
119
185
|
});
|
|
186
|
+
Object.defineProperty(exports, "useLiveNetworkEvent", {
|
|
187
|
+
enumerable: true,
|
|
188
|
+
get: function () {
|
|
189
|
+
return _useLiveNetworkEvent.useLiveNetworkEvent;
|
|
190
|
+
}
|
|
191
|
+
});
|
|
120
192
|
Object.defineProperty(exports, "useNetworkBadgeCounts", {
|
|
121
193
|
enumerable: true,
|
|
122
194
|
get: function () {
|
|
@@ -135,6 +207,12 @@ Object.defineProperty(exports, "useNetworkEvents", {
|
|
|
135
207
|
return _useNetworkEvents.useNetworkEvents;
|
|
136
208
|
}
|
|
137
209
|
});
|
|
210
|
+
Object.defineProperty(exports, "useNetworkSaved", {
|
|
211
|
+
enumerable: true,
|
|
212
|
+
get: function () {
|
|
213
|
+
return _useNetworkSaved.useNetworkSaved;
|
|
214
|
+
}
|
|
215
|
+
});
|
|
138
216
|
Object.defineProperty(exports, "useTickEveryMinute", {
|
|
139
217
|
enumerable: true,
|
|
140
218
|
get: function () {
|
|
@@ -145,13 +223,20 @@ var _preset = require("./preset");
|
|
|
145
223
|
var _NetworkModal = require("./network/components/NetworkModal");
|
|
146
224
|
var _NetworkEventDetailView = require("./network/components/NetworkEventDetailView");
|
|
147
225
|
var _NetworkEventItemCompact = require("./network/components/NetworkEventItemCompact");
|
|
226
|
+
var _NetworkSavedScreen = require("./network/components/NetworkSavedScreen");
|
|
227
|
+
var _NetworkHeaderLive = require("./network/components/NetworkHeaderLive");
|
|
148
228
|
var _useNetworkEvents = require("./network/hooks/useNetworkEvents");
|
|
149
229
|
var _useNetworkEventList = require("./network/hooks/useNetworkEventList");
|
|
230
|
+
var _useLiveNetworkEvent = require("./network/hooks/useLiveNetworkEvent");
|
|
150
231
|
var _useNetworkBadgeCounts = require("./network/hooks/useNetworkBadgeCounts");
|
|
232
|
+
var _useNetworkSaved = require("./network/hooks/useNetworkSaved");
|
|
233
|
+
var _withPinnedFirst = require("./network/utils/withPinnedFirst");
|
|
151
234
|
var _useTickEveryMinute = require("./network/hooks/useTickEveryMinute");
|
|
152
235
|
var _formatting = require("./network/utils/formatting");
|
|
153
236
|
var _sharedUi = require("@buoy-gg/shared-ui");
|
|
154
237
|
var _networkSyncAdapter = require("./network/sync/networkSyncAdapter");
|
|
155
238
|
var _networkBodyResolver = require("./network/sync/networkBodyResolver");
|
|
156
239
|
var _networkEventStore = require("./network/utils/networkEventStore");
|
|
240
|
+
var _networkSavedStore = require("./network/utils/networkSavedStore");
|
|
241
|
+
var _generateCurl = require("./network/utils/generateCurl");
|
|
157
242
|
var _networkListener = require("./network/utils/networkListener");
|
|
@@ -12,12 +12,83 @@ var _dataViewer = require("@buoy-gg/shared-ui/dataViewer");
|
|
|
12
12
|
var _formatGraphQLVariables = require("../utils/formatGraphQLVariables");
|
|
13
13
|
var _networkBodyResolver = require("../sync/networkBodyResolver");
|
|
14
14
|
var _jsxRuntime = require("react/jsx-runtime");
|
|
15
|
+
/**
|
|
16
|
+
* Colour for the icons that merely LABEL a section (Sent/Received, the JSON
|
|
17
|
+
* body glyphs). The Lock/Unlock pair keeps its colour because
|
|
18
|
+
* secure-vs-insecure is a genuine signal, as does the status pill.
|
|
19
|
+
*/const NEUTRAL_ICON = _sharedUi.macOSColors.semantic.success;
|
|
20
|
+
/**
|
|
21
|
+
* The measurable slice of a request's lifetime, as proportional bars.
|
|
22
|
+
*
|
|
23
|
+
* Renders NOTHING when the interceptor couldn't measure it — an older device
|
|
24
|
+
* talking to a newer dashboard, or a request that died before headers. A phase
|
|
25
|
+
* row reading `0ms` would claim we measured zero, which is a different and
|
|
26
|
+
* false statement from "we didn't measure this".
|
|
27
|
+
*
|
|
28
|
+
* Only two phases, on purpose. Queueing / DNS / TLS / request-send all happen
|
|
29
|
+
* below the JS layer with nothing to read them from — see NetworkTimings. The
|
|
30
|
+
* design this came from shows five, but derives the other three by multiplying
|
|
31
|
+
* the total by fixed fractions, i.e. they are invented. Two real ones are worth
|
|
32
|
+
* more than five where three are decoration.
|
|
33
|
+
*/
|
|
34
|
+
const TimingPhases = ({
|
|
35
|
+
timings,
|
|
36
|
+
total
|
|
37
|
+
}) => {
|
|
38
|
+
// Guard the divisor: a sub-millisecond request would otherwise divide by 0.
|
|
39
|
+
const span = Math.max(1, total);
|
|
40
|
+
const phases = [{
|
|
41
|
+
// Deliberately NOT called "server time". Measured from JS, this includes
|
|
42
|
+
// queueing, DNS, TLS and sending the request — everything before the
|
|
43
|
+
// headers land. The subtitle says so rather than implying Chrome-grade
|
|
44
|
+
// precision we don't have.
|
|
45
|
+
label: "Waiting (TTFB)",
|
|
46
|
+
hint: "incl. queue, DNS, TLS",
|
|
47
|
+
value: timings.ttfb,
|
|
48
|
+
color: _sharedUi.macOSColors.semantic.warning
|
|
49
|
+
}, {
|
|
50
|
+
label: "Content download",
|
|
51
|
+
hint: undefined,
|
|
52
|
+
value: timings.download,
|
|
53
|
+
color: _sharedUi.macOSColors.semantic.success
|
|
54
|
+
}];
|
|
55
|
+
return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
|
|
56
|
+
style: styles.phaseList,
|
|
57
|
+
children: phases.map(phase => /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
|
58
|
+
style: styles.phaseRow,
|
|
59
|
+
children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
|
60
|
+
style: styles.phaseLabelGroup,
|
|
61
|
+
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
62
|
+
style: styles.phaseLabel,
|
|
63
|
+
children: phase.label
|
|
64
|
+
}), phase.hint ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
65
|
+
style: styles.phaseHint,
|
|
66
|
+
children: phase.hint
|
|
67
|
+
}) : null]
|
|
68
|
+
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
|
|
69
|
+
style: styles.phaseTrack,
|
|
70
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
|
|
71
|
+
style: [styles.phaseBar, {
|
|
72
|
+
backgroundColor: phase.color,
|
|
73
|
+
// A floor so a 1ms phase is still a visible tick.
|
|
74
|
+
width: `${Math.max(1, phase.value / span * 100)}%`
|
|
75
|
+
}]
|
|
76
|
+
})
|
|
77
|
+
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
78
|
+
style: styles.phaseValue,
|
|
79
|
+
children: (0, _formatting.formatDuration)(phase.value)
|
|
80
|
+
})]
|
|
81
|
+
}, phase.label))
|
|
82
|
+
});
|
|
83
|
+
};
|
|
84
|
+
|
|
15
85
|
// Component for collapsible sections matching Sentry style
|
|
16
86
|
const CollapsibleSection = ({
|
|
17
87
|
title,
|
|
18
88
|
icon,
|
|
19
89
|
children,
|
|
20
|
-
defaultOpen = false
|
|
90
|
+
defaultOpen = false,
|
|
91
|
+
count
|
|
21
92
|
}) => {
|
|
22
93
|
const [isOpen, setIsOpen] = (0, _react.useState)(defaultOpen);
|
|
23
94
|
return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
|
@@ -30,7 +101,10 @@ const CollapsibleSection = ({
|
|
|
30
101
|
children: [icon, /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
31
102
|
style: styles.collapsibleTitleText,
|
|
32
103
|
children: title
|
|
33
|
-
})
|
|
104
|
+
}), count !== undefined ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
105
|
+
style: styles.collapsibleCount,
|
|
106
|
+
children: count
|
|
107
|
+
}) : null]
|
|
34
108
|
}), isOpen ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.ChevronUp, {
|
|
35
109
|
size: 16,
|
|
36
110
|
color: _sharedUi.macOSColors.text.secondary
|
|
@@ -98,7 +172,23 @@ const UrlBreakdown = ({
|
|
|
98
172
|
};
|
|
99
173
|
}
|
|
100
174
|
};
|
|
101
|
-
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* MUST be memoized. `parseUrl` builds a fresh `params` object every call, and
|
|
178
|
+
* that object is handed to `DataViewer` as its `data` prop — whose flattening
|
|
179
|
+
* effect keys on `data` by IDENTITY. Computed inline, every render of this
|
|
180
|
+
* component produced a new object, so the effect re-fired and re-entered
|
|
181
|
+
* "Processing data…" forever. The detail view re-renders constantly on the
|
|
182
|
+
* dashboard (it tracks the live event as the device pushes snapshots ~4×/sec),
|
|
183
|
+
* so this pinned the query-parameter viewer in a permanent processing loop.
|
|
184
|
+
*
|
|
185
|
+
* `url` is a string, so this is stable by value.
|
|
186
|
+
*/
|
|
187
|
+
const urlParts = (0, _react.useMemo)(() => parseUrl(url),
|
|
188
|
+
// parseUrl closes over the graphql/operation props, which are what change
|
|
189
|
+
// the derived pathname.
|
|
190
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
191
|
+
[url, requestClient, operationName, graphqlVariables]);
|
|
102
192
|
const [showParams, setShowParams] = (0, _react.useState)(false);
|
|
103
193
|
return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
|
104
194
|
style: styles.urlBreakdown,
|
|
@@ -147,6 +237,9 @@ const UrlBreakdown = ({
|
|
|
147
237
|
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
148
238
|
style: styles.queryParamsToggleText,
|
|
149
239
|
children: "Query Parameters"
|
|
240
|
+
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
241
|
+
style: styles.collapsibleCount,
|
|
242
|
+
children: Object.keys(urlParts.params).length
|
|
150
243
|
}), showParams ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.ChevronUp, {
|
|
151
244
|
size: 14,
|
|
152
245
|
color: _sharedUi.macOSColors.text.secondary
|
|
@@ -362,34 +455,41 @@ ${JSON.stringify(requestDetails.responseData, null, 2)}
|
|
|
362
455
|
}), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.Text, {
|
|
363
456
|
style: styles.timingExact,
|
|
364
457
|
children: ["(", new Date(event.timestamp).toLocaleTimeString(), ")"]
|
|
365
|
-
})
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
})
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
})]
|
|
458
|
+
}), event.requestSize || event.responseSize ? /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
|
459
|
+
style: styles.sizeRow,
|
|
460
|
+
children: [event.requestSize !== undefined ? /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
|
461
|
+
style: styles.sizeItem,
|
|
462
|
+
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.Upload, {
|
|
463
|
+
size: 10,
|
|
464
|
+
color: _sharedUi.macOSColors.semantic.info
|
|
465
|
+
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
466
|
+
style: styles.sizeLabel,
|
|
467
|
+
children: "Sent:"
|
|
468
|
+
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
469
|
+
style: styles.sizeValue,
|
|
470
|
+
children: (0, _formatting.formatBytes)(event.requestSize)
|
|
471
|
+
})]
|
|
472
|
+
}) : null, event.responseSize !== undefined ? /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
|
473
|
+
style: styles.sizeItem,
|
|
474
|
+
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.Download, {
|
|
475
|
+
size: 10,
|
|
476
|
+
color: NEUTRAL_ICON
|
|
477
|
+
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
478
|
+
style: styles.sizeLabel,
|
|
479
|
+
children: "Received:"
|
|
480
|
+
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
481
|
+
style: styles.sizeValue,
|
|
482
|
+
children: (0, _formatting.formatBytes)(event.responseSize)
|
|
483
|
+
})]
|
|
484
|
+
}) : null]
|
|
392
485
|
}) : null]
|
|
486
|
+
}), event.timings ? /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, {
|
|
487
|
+
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
|
|
488
|
+
style: styles.phaseDivider
|
|
489
|
+
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(TimingPhases, {
|
|
490
|
+
timings: event.timings,
|
|
491
|
+
total: event.duration ?? event.timings.ttfb + event.timings.download
|
|
492
|
+
})]
|
|
393
493
|
}) : null]
|
|
394
494
|
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(CollapsibleSection, {
|
|
395
495
|
title: "Request Headers",
|
|
@@ -398,6 +498,7 @@ ${JSON.stringify(requestDetails.responseData, null, 2)}
|
|
|
398
498
|
color: _sharedUi.macOSColors.semantic.info
|
|
399
499
|
}),
|
|
400
500
|
defaultOpen: false,
|
|
501
|
+
count: Object.keys(event.requestHeaders).length,
|
|
401
502
|
children: Object.keys(event.requestHeaders).length > 0 ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
|
|
402
503
|
style: styles.dataViewerContainer,
|
|
403
504
|
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_dataViewer.DataViewer, {
|
|
@@ -416,9 +517,10 @@ ${JSON.stringify(requestDetails.responseData, null, 2)}
|
|
|
416
517
|
title: "Response Headers",
|
|
417
518
|
icon: /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.Download, {
|
|
418
519
|
size: 14,
|
|
419
|
-
color:
|
|
520
|
+
color: NEUTRAL_ICON
|
|
420
521
|
}),
|
|
421
522
|
defaultOpen: false,
|
|
523
|
+
count: Object.keys(event.responseHeaders).length,
|
|
422
524
|
children: Object.keys(event.responseHeaders).length > 0 ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
|
|
423
525
|
style: styles.dataViewerContainer,
|
|
424
526
|
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_dataViewer.DataViewer, {
|
|
@@ -466,9 +568,12 @@ ${JSON.stringify(requestDetails.responseData, null, 2)}
|
|
|
466
568
|
title: "Response Body",
|
|
467
569
|
icon: /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.FileJson, {
|
|
468
570
|
size: 14,
|
|
469
|
-
color:
|
|
470
|
-
})
|
|
471
|
-
|
|
571
|
+
color: NEUTRAL_ICON
|
|
572
|
+
})
|
|
573
|
+
// The body is what you opened the row FOR — the design has it
|
|
574
|
+
// expanded on arrival, everything else closed.
|
|
575
|
+
,
|
|
576
|
+
defaultOpen: true,
|
|
472
577
|
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
|
|
473
578
|
style: styles.dataViewerContainer,
|
|
474
579
|
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_dataViewer.DataViewer, {
|
|
@@ -484,7 +589,7 @@ ${JSON.stringify(requestDetails.responseData, null, 2)}
|
|
|
484
589
|
title: "Response Body",
|
|
485
590
|
icon: /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.FileJson, {
|
|
486
591
|
size: 14,
|
|
487
|
-
color:
|
|
592
|
+
color: NEUTRAL_ICON
|
|
488
593
|
}),
|
|
489
594
|
defaultOpen: true,
|
|
490
595
|
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
@@ -710,6 +815,7 @@ const styles = _reactNative.StyleSheet.create({
|
|
|
710
815
|
marginBottom: 8
|
|
711
816
|
},
|
|
712
817
|
queryParamsToggleText: {
|
|
818
|
+
flexGrow: 0,
|
|
713
819
|
color: _sharedUi.macOSColors.text.primary,
|
|
714
820
|
fontSize: 12,
|
|
715
821
|
fontWeight: "600",
|
|
@@ -728,7 +834,10 @@ const styles = _reactNative.StyleSheet.create({
|
|
|
728
834
|
timingRow: {
|
|
729
835
|
flexDirection: "row",
|
|
730
836
|
alignItems: "center",
|
|
731
|
-
gap: 6
|
|
837
|
+
gap: 6,
|
|
838
|
+
// Wraps rather than squashing when the card is narrow (a phone, or a
|
|
839
|
+
// half-width panel) — the sizes drop to their own line there.
|
|
840
|
+
flexWrap: "wrap"
|
|
732
841
|
},
|
|
733
842
|
timingLabel: {
|
|
734
843
|
color: _sharedUi.macOSColors.text.secondary,
|
|
@@ -746,11 +855,11 @@ const styles = _reactNative.StyleSheet.create({
|
|
|
746
855
|
},
|
|
747
856
|
sizeRow: {
|
|
748
857
|
flexDirection: "row",
|
|
858
|
+
alignItems: "center",
|
|
749
859
|
gap: 16,
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
borderTopColor: _sharedUi.macOSColors.border.default
|
|
860
|
+
// Pushed to the far end of the Started row. No top border/padding — it is
|
|
861
|
+
// no longer a separate strip.
|
|
862
|
+
marginLeft: "auto"
|
|
754
863
|
},
|
|
755
864
|
sizeItem: {
|
|
756
865
|
flexDirection: "row",
|
|
@@ -767,6 +876,50 @@ const styles = _reactNative.StyleSheet.create({
|
|
|
767
876
|
fontFamily: "monospace",
|
|
768
877
|
fontWeight: "600"
|
|
769
878
|
},
|
|
879
|
+
/* ---- Timing phases ---- */
|
|
880
|
+
phaseDivider: {
|
|
881
|
+
height: 1,
|
|
882
|
+
backgroundColor: _sharedUi.macOSColors.border.default,
|
|
883
|
+
marginTop: 12,
|
|
884
|
+
marginBottom: 12
|
|
885
|
+
},
|
|
886
|
+
phaseList: {
|
|
887
|
+
gap: 8
|
|
888
|
+
},
|
|
889
|
+
phaseRow: {
|
|
890
|
+
flexDirection: "row",
|
|
891
|
+
alignItems: "center",
|
|
892
|
+
gap: 14
|
|
893
|
+
},
|
|
894
|
+
phaseLabelGroup: {
|
|
895
|
+
width: 150
|
|
896
|
+
},
|
|
897
|
+
phaseLabel: {
|
|
898
|
+
fontSize: 12,
|
|
899
|
+
color: _sharedUi.macOSColors.text.secondary
|
|
900
|
+
},
|
|
901
|
+
phaseHint: {
|
|
902
|
+
fontSize: 10,
|
|
903
|
+
color: _sharedUi.macOSColors.text.muted
|
|
904
|
+
},
|
|
905
|
+
phaseTrack: {
|
|
906
|
+
flex: 1,
|
|
907
|
+
height: 7,
|
|
908
|
+
borderRadius: 4,
|
|
909
|
+
backgroundColor: _sharedUi.macOSColors.background.hover,
|
|
910
|
+
justifyContent: "center"
|
|
911
|
+
},
|
|
912
|
+
phaseBar: {
|
|
913
|
+
height: 7,
|
|
914
|
+
borderRadius: 4
|
|
915
|
+
},
|
|
916
|
+
phaseValue: {
|
|
917
|
+
width: 72,
|
|
918
|
+
textAlign: "right",
|
|
919
|
+
fontSize: 12,
|
|
920
|
+
fontFamily: "monospace",
|
|
921
|
+
color: _sharedUi.macOSColors.text.primary
|
|
922
|
+
},
|
|
770
923
|
// Collapsible section styles
|
|
771
924
|
collapsibleSection: {
|
|
772
925
|
marginHorizontal: 12,
|
|
@@ -782,6 +935,8 @@ const styles = _reactNative.StyleSheet.create({
|
|
|
782
935
|
alignItems: "center",
|
|
783
936
|
justifyContent: "space-between",
|
|
784
937
|
padding: 12,
|
|
938
|
+
// `background.hover` is the SELECTION grey — heavy enough here that every
|
|
939
|
+
// section header read as a toolbar. The design uses a near-white strip.
|
|
785
940
|
backgroundColor: _sharedUi.macOSColors.background.hover
|
|
786
941
|
},
|
|
787
942
|
collapsibleTitle: {
|
|
@@ -794,6 +949,12 @@ const styles = _reactNative.StyleSheet.create({
|
|
|
794
949
|
fontSize: 13,
|
|
795
950
|
fontWeight: "600"
|
|
796
951
|
},
|
|
952
|
+
/** The "how much is in here" number beside a section title. */
|
|
953
|
+
collapsibleCount: {
|
|
954
|
+
color: _sharedUi.macOSColors.text.muted,
|
|
955
|
+
fontSize: 11.5,
|
|
956
|
+
fontFamily: "monospace"
|
|
957
|
+
},
|
|
797
958
|
collapsibleContent: {
|
|
798
959
|
padding: 12
|
|
799
960
|
},
|
|
@@ -35,6 +35,39 @@ function getContentTypeBadge(headers) {
|
|
|
35
35
|
return null;
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
+
/**
|
|
39
|
+
* The transport chip (`fetch` / `GQL` / `gRPC` / `XHR`), one brand colour each.
|
|
40
|
+
*/
|
|
41
|
+
function getClientChipColors(requestClient) {
|
|
42
|
+
switch (requestClient) {
|
|
43
|
+
case "fetch":
|
|
44
|
+
return {
|
|
45
|
+
backgroundColor: "rgba(74, 144, 226, 0.15)",
|
|
46
|
+
color: "#4A90E2"
|
|
47
|
+
};
|
|
48
|
+
case "graphql":
|
|
49
|
+
return {
|
|
50
|
+
backgroundColor: "rgba(229, 53, 171, 0.15)",
|
|
51
|
+
color: "#E535AB"
|
|
52
|
+
};
|
|
53
|
+
case "grpc-web":
|
|
54
|
+
return {
|
|
55
|
+
backgroundColor: "rgba(16, 185, 129, 0.15)",
|
|
56
|
+
color: "#10B981"
|
|
57
|
+
};
|
|
58
|
+
case "xhr":
|
|
59
|
+
return {
|
|
60
|
+
backgroundColor: "rgba(245, 158, 11, 0.15)",
|
|
61
|
+
color: "#F59E0B"
|
|
62
|
+
};
|
|
63
|
+
default:
|
|
64
|
+
return {
|
|
65
|
+
backgroundColor: "rgba(147, 51, 234, 0.15)",
|
|
66
|
+
color: "#9333EA"
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
38
71
|
// Decomposed components following rule3 - Component Composition
|
|
39
72
|
|
|
40
73
|
// Status indicator component - single responsibility
|
|
@@ -137,7 +170,10 @@ const NetworkEventItemCompact = exports.NetworkEventItemCompact = /*#__PURE__*/(
|
|
|
137
170
|
// renders to this component instead of a compiled anonymous name.
|
|
138
171
|
function NetworkEventItemCompact({
|
|
139
172
|
event,
|
|
140
|
-
onPress
|
|
173
|
+
onPress,
|
|
174
|
+
pinned = false,
|
|
175
|
+
saved = false,
|
|
176
|
+
onLongPress
|
|
141
177
|
}) {
|
|
142
178
|
const statusColor = getStatusColor(event.status, event.error);
|
|
143
179
|
const isPending = !event.status && !event.error;
|
|
@@ -162,23 +198,30 @@ function NetworkEventItemCompact({
|
|
|
162
198
|
}
|
|
163
199
|
return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_sharedUi.DevToolsCard, {
|
|
164
200
|
onPress: () => onPress(event),
|
|
201
|
+
onLongPress: onLongPress ? () => onLongPress(event) : undefined,
|
|
165
202
|
style: styles.cardWrapper,
|
|
166
203
|
contentStyle: [styles.container, {
|
|
167
204
|
borderLeftColor: statusColor
|
|
168
205
|
}],
|
|
169
206
|
children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
|
170
207
|
style: styles.topRightContainer,
|
|
171
|
-
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(
|
|
208
|
+
children: [pinned ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.Pin, {
|
|
209
|
+
size: 10,
|
|
210
|
+
color: _sharedUi.macOSColors.semantic.info
|
|
211
|
+
}) : null, saved ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.Bookmark, {
|
|
212
|
+
size: 10,
|
|
213
|
+
color: _sharedUi.macOSColors.semantic.debug
|
|
214
|
+
}) : null, /*#__PURE__*/(0, _jsxRuntime.jsx)(StatusIndicator, {
|
|
172
215
|
event: event,
|
|
173
216
|
isPending: isPending,
|
|
174
217
|
statusColor: statusColor
|
|
175
218
|
}), event.requestClient ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
|
|
176
219
|
style: [styles.topRightBadge, {
|
|
177
|
-
backgroundColor:
|
|
220
|
+
backgroundColor: getClientChipColors(event.requestClient).backgroundColor
|
|
178
221
|
}],
|
|
179
222
|
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
180
223
|
style: [styles.clientText, {
|
|
181
|
-
color: event.requestClient
|
|
224
|
+
color: getClientChipColors(event.requestClient).color
|
|
182
225
|
}],
|
|
183
226
|
children: event.requestClient === "graphql" ? "GQL" : event.requestClient === "grpc-web" ? "gRPC" : event.requestClient === "xhr" ? "XHR" : event.requestClient
|
|
184
227
|
})
|
|
@@ -223,13 +266,17 @@ function NetworkEventItemCompact({
|
|
|
223
266
|
NetworkEventItemCompact.displayName = "NetworkEventItemCompact";
|
|
224
267
|
const styles = _reactNative.StyleSheet.create({
|
|
225
268
|
cardWrapper: {
|
|
269
|
+
// Overrides DevToolsCard's own wrapper margin, so it has to opt into the
|
|
270
|
+
// edge-to-edge chat layout too or the rows keep their gutter.
|
|
226
271
|
marginHorizontal: 8
|
|
227
272
|
},
|
|
228
273
|
container: {
|
|
229
274
|
flexDirection: "row",
|
|
230
275
|
alignItems: "center",
|
|
231
276
|
borderLeftWidth: 3,
|
|
232
|
-
borderLeftColor: "transparent"
|
|
277
|
+
borderLeftColor: "transparent",
|
|
278
|
+
// One hairline per row — the same value DevToolsCard's border uses.
|
|
279
|
+
borderBottomWidth: 1
|
|
233
280
|
},
|
|
234
281
|
leftSection: {
|
|
235
282
|
marginRight: 8,
|