@buoy-gg/network 7.0.14 → 7.0.16

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.
Files changed (107) hide show
  1. package/lib/commonjs/index.web.js +395 -0
  2. package/lib/commonjs/network/components/DataViewer.web.js +879 -0
  3. package/lib/commonjs/network/components/NetworkCopyScreen.web.js +48 -0
  4. package/lib/commonjs/network/components/NetworkCopySettingsView.web.js +1242 -0
  5. package/lib/commonjs/network/components/NetworkDetailScreen.web.js +101 -0
  6. package/lib/commonjs/network/components/NetworkDetailStepper.web.js +296 -0
  7. package/lib/commonjs/network/components/NetworkEventDetailView.web.js +1498 -0
  8. package/lib/commonjs/network/components/NetworkEventItemCompact.web.js +802 -0
  9. package/lib/commonjs/network/components/NetworkFilterScreen.web.js +55 -0
  10. package/lib/commonjs/network/components/NetworkFilterViewV3.web.js +1310 -0
  11. package/lib/commonjs/network/components/NetworkHeaderLive.web.js +604 -0
  12. package/lib/commonjs/network/components/NetworkListScreen.js +2 -1
  13. package/lib/commonjs/network/components/NetworkListScreen.web.js +607 -0
  14. package/lib/commonjs/network/components/NetworkModal.js +12 -3
  15. package/lib/commonjs/network/components/NetworkNumberPrompt.web.js +232 -0
  16. package/lib/commonjs/network/components/NetworkOverrideEditor.web.js +942 -0
  17. package/lib/commonjs/network/components/NetworkOverrideHeaderButton.web.js +133 -0
  18. package/lib/commonjs/network/components/NetworkOverridesButton.web.js +143 -0
  19. package/lib/commonjs/network/components/NetworkOverridesScreen.js +160 -126
  20. package/lib/commonjs/network/components/NetworkOverridesScreen.web.js +830 -0
  21. package/lib/commonjs/network/components/NetworkSavedScreen.web.js +459 -0
  22. package/lib/commonjs/network/components/response-editor/Explorer.web.js +1136 -0
  23. package/lib/commonjs/network/hooks/useNetworkEventList.js +12 -2
  24. package/lib/commonjs/network/overrides/applyToXhr.js +276 -15
  25. package/lib/commonjs/network/utils/generateNetworkCopyText.js +32 -5
  26. package/lib/commonjs/network/utils/networkEventStore.js +12 -4
  27. package/lib/commonjs/network/utils/networkListener.js +1 -16
  28. package/lib/module/index.web.js +81 -0
  29. package/lib/module/network/components/DataViewer.web.js +875 -0
  30. package/lib/module/network/components/NetworkCopyScreen.web.js +44 -0
  31. package/lib/module/network/components/NetworkCopySettingsView.web.js +1237 -0
  32. package/lib/module/network/components/NetworkDetailScreen.web.js +97 -0
  33. package/lib/module/network/components/NetworkDetailStepper.web.js +294 -0
  34. package/lib/module/network/components/NetworkEventDetailView.web.js +1496 -0
  35. package/lib/module/network/components/NetworkEventItemCompact.web.js +800 -0
  36. package/lib/module/network/components/NetworkFilterScreen.web.js +51 -0
  37. package/lib/module/network/components/NetworkFilterViewV3.web.js +1306 -0
  38. package/lib/module/network/components/NetworkHeaderLive.web.js +598 -0
  39. package/lib/module/network/components/NetworkListScreen.js +2 -1
  40. package/lib/module/network/components/NetworkListScreen.web.js +605 -0
  41. package/lib/module/network/components/NetworkModal.js +12 -3
  42. package/lib/module/network/components/NetworkNumberPrompt.web.js +230 -0
  43. package/lib/module/network/components/NetworkOverrideEditor.web.js +939 -0
  44. package/lib/module/network/components/NetworkOverrideHeaderButton.web.js +131 -0
  45. package/lib/module/network/components/NetworkOverridesButton.web.js +141 -0
  46. package/lib/module/network/components/NetworkOverridesScreen.js +161 -127
  47. package/lib/module/network/components/NetworkOverridesScreen.web.js +826 -0
  48. package/lib/module/network/components/NetworkSavedScreen.web.js +457 -0
  49. package/lib/module/network/components/response-editor/Explorer.web.js +1133 -0
  50. package/lib/module/network/hooks/useNetworkEventList.js +12 -2
  51. package/lib/module/network/overrides/applyToXhr.js +275 -15
  52. package/lib/module/network/utils/generateNetworkCopyText.js +28 -1
  53. package/lib/module/network/utils/networkEventStore.js +12 -4
  54. package/lib/module/network/utils/networkListener.js +1 -16
  55. package/lib/typescript/index.web.d.ts +56 -0
  56. package/lib/typescript/index.web.d.ts.map +1 -0
  57. package/lib/typescript/network/components/DataViewer.web.d.ts +78 -0
  58. package/lib/typescript/network/components/DataViewer.web.d.ts.map +1 -0
  59. package/lib/typescript/network/components/NetworkCopyScreen.web.d.ts +27 -0
  60. package/lib/typescript/network/components/NetworkCopyScreen.web.d.ts.map +1 -0
  61. package/lib/typescript/network/components/NetworkCopySettingsView.web.d.ts +68 -0
  62. package/lib/typescript/network/components/NetworkCopySettingsView.web.d.ts.map +1 -0
  63. package/lib/typescript/network/components/NetworkDetailScreen.web.d.ts +45 -0
  64. package/lib/typescript/network/components/NetworkDetailScreen.web.d.ts.map +1 -0
  65. package/lib/typescript/network/components/NetworkDetailStepper.web.d.ts +40 -0
  66. package/lib/typescript/network/components/NetworkDetailStepper.web.d.ts.map +1 -0
  67. package/lib/typescript/network/components/NetworkEventDetailView.web.d.ts +67 -0
  68. package/lib/typescript/network/components/NetworkEventDetailView.web.d.ts.map +1 -0
  69. package/lib/typescript/network/components/NetworkEventItemCompact.web.d.ts +58 -0
  70. package/lib/typescript/network/components/NetworkEventItemCompact.web.d.ts.map +1 -0
  71. package/lib/typescript/network/components/NetworkFilterScreen.web.d.ts +28 -0
  72. package/lib/typescript/network/components/NetworkFilterScreen.web.d.ts.map +1 -0
  73. package/lib/typescript/network/components/NetworkFilterViewV3.web.d.ts +74 -0
  74. package/lib/typescript/network/components/NetworkFilterViewV3.web.d.ts.map +1 -0
  75. package/lib/typescript/network/components/NetworkHeaderLive.web.d.ts +112 -0
  76. package/lib/typescript/network/components/NetworkHeaderLive.web.d.ts.map +1 -0
  77. package/lib/typescript/network/components/NetworkListScreen.d.ts.map +1 -1
  78. package/lib/typescript/network/components/NetworkListScreen.web.d.ts +63 -0
  79. package/lib/typescript/network/components/NetworkListScreen.web.d.ts.map +1 -0
  80. package/lib/typescript/network/components/NetworkModal.d.ts.map +1 -1
  81. package/lib/typescript/network/components/NetworkNumberPrompt.web.d.ts +38 -0
  82. package/lib/typescript/network/components/NetworkNumberPrompt.web.d.ts.map +1 -0
  83. package/lib/typescript/network/components/NetworkOverrideEditor.web.d.ts +43 -0
  84. package/lib/typescript/network/components/NetworkOverrideEditor.web.d.ts.map +1 -0
  85. package/lib/typescript/network/components/NetworkOverrideHeaderButton.web.d.ts +32 -0
  86. package/lib/typescript/network/components/NetworkOverrideHeaderButton.web.d.ts.map +1 -0
  87. package/lib/typescript/network/components/NetworkOverridesButton.web.d.ts +26 -0
  88. package/lib/typescript/network/components/NetworkOverridesButton.web.d.ts.map +1 -0
  89. package/lib/typescript/network/components/NetworkOverridesScreen.d.ts +9 -0
  90. package/lib/typescript/network/components/NetworkOverridesScreen.d.ts.map +1 -1
  91. package/lib/typescript/network/components/NetworkOverridesScreen.web.d.ts +69 -0
  92. package/lib/typescript/network/components/NetworkOverridesScreen.web.d.ts.map +1 -0
  93. package/lib/typescript/network/components/NetworkSavedScreen.web.d.ts +67 -0
  94. package/lib/typescript/network/components/NetworkSavedScreen.web.d.ts.map +1 -0
  95. package/lib/typescript/network/components/response-editor/Explorer.web.d.ts +56 -0
  96. package/lib/typescript/network/components/response-editor/Explorer.web.d.ts.map +1 -0
  97. package/lib/typescript/network/hooks/useNetworkEventList.d.ts +10 -0
  98. package/lib/typescript/network/hooks/useNetworkEventList.d.ts.map +1 -1
  99. package/lib/typescript/network/overrides/__tests__/applyToXhr.test.d.ts.map +1 -1
  100. package/lib/typescript/network/overrides/applyToXhr.d.ts +40 -14
  101. package/lib/typescript/network/overrides/applyToXhr.d.ts.map +1 -1
  102. package/lib/typescript/network/utils/generateNetworkCopyText.d.ts +34 -1
  103. package/lib/typescript/network/utils/generateNetworkCopyText.d.ts.map +1 -1
  104. package/lib/typescript/network/utils/networkEventStore.d.ts.map +1 -1
  105. package/lib/typescript/network/utils/networkListener.d.ts +0 -1
  106. package/lib/typescript/network/utils/networkListener.d.ts.map +1 -1
  107. package/package.json +2 -2
@@ -0,0 +1,604 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.NetworkClearButton = NetworkClearButton;
7
+ exports.NetworkDetailPinActions = NetworkDetailPinActions;
8
+ exports.NetworkHeaderBadges = NetworkHeaderBadges;
9
+ exports.NetworkHeaderCopyButton = NetworkHeaderCopyButton;
10
+ exports.NetworkSavedButton = NetworkSavedButton;
11
+ var _react = require("react");
12
+ var _networkEventStore = require("../utils/networkEventStore");
13
+ var _networkSavedStore = require("../utils/networkSavedStore");
14
+ var _useNetworkSaved = require("../hooks/useNetworkSaved");
15
+ var _useNetworkSelection = require("../hooks/useNetworkSelection");
16
+ var _useNetworkBadgeCounts = require("../hooks/useNetworkBadgeCounts");
17
+ var _useNetworkHasMatches = require("../hooks/useNetworkHasMatches");
18
+ var _generateNetworkCopyText = require("../utils/generateNetworkCopyText");
19
+ var _filterNetworkEvents = require("../utils/filterNetworkEvents");
20
+ var _jsxRuntime = require("react/jsx-runtime");
21
+ /**
22
+ * NetworkHeaderLive.web — DOM twin of NetworkHeaderLive.tsx.
23
+ *
24
+ * The header pieces that consume LIVE event data, each its own narrow store
25
+ * subscriber (same decomposition + hooks as native — `useNetworkBadgeCounts`,
26
+ * `useNetworkHasEvents`, `useNetworkSaved` are platform-free and reused, not
27
+ * forked):
28
+ *
29
+ * - `NetworkHeaderBadges` — success/error/pending count chips (tap toggles
30
+ * the status filter)
31
+ * - `NetworkClearButton` — trash button, enabled while the store has events
32
+ * - `NetworkSavedButton` — Saved-screen entry point with its live count
33
+ * - `NetworkDetailPinActions` — pin + save toggles for the request-DETAIL
34
+ * header (ported with the F3 detail-view feature; same flagsForEventId /
35
+ * cap logic and press-time event resolution as native)
36
+ * - `NetworkHeaderCopyButton` — copy-all button / labelled ⋯-menu row
37
+ * (ported with the F5 saved+copy feature; the copy text is the SAME
38
+ * platform-free `generateNetworkCopyText`, resolved lazily at press time
39
+ * from a live store read, exactly like native)
40
+ *
41
+ * shared-ui RN chrome is replicated as DOM with provenance (web consumers
42
+ * resolve `@buoy-gg/shared-ui` to a minimal shim):
43
+ * - `macOSColors` — inlined verbatim subset from
44
+ * shared/src/ui/gameUI/constants/macOSDesignSystemColors.ts.
45
+ * - Icons — inline lucide SVGs (shared-ui's icons are lucide re-exports).
46
+ * - The active chip's native shadow (shadowOffset 0/1, opacity 0.08,
47
+ * radius 2) → an equivalent CSS box-shadow.
48
+ * - shared-ui `CopyButton` (the Pro branch of the copy button) — inlined
49
+ * labelled DOM twin below: same idle/success/error icon set, 1500ms
50
+ * feedback, lazy function value, and label-follows-labelStyle behavior.
51
+ *
52
+ * Intentional deviations (all logged):
53
+ * - shared-ui CopyButton's ClipboardHintBanner and internal
54
+ * @buoy-gg/license Pro modal are not ported — license gating isn't part
55
+ * of the web port; the explicit `isPro` prop branch (native's own outer
56
+ * gate) still routes free users to `onUpgradePress`.
57
+ * - `CopySettings` is imported from the platform-free
58
+ * `generateNetworkCopyText` module (the native file imports it from
59
+ * NetworkCopySettingsView.tsx, which would drag react-native in).
60
+ *
61
+ * @platform React DOM Web
62
+ */
63
+
64
+ // =============================
65
+ // Native palette (provenance)
66
+ // =============================
67
+
68
+ /** macOSColors subset — shared/src/ui/gameUI/constants/macOSDesignSystemColors.ts, verbatim. */const macOSColors = {
69
+ background: {
70
+ hover: "#1D1D1F"
71
+ },
72
+ border: {
73
+ default: "#2D2D2F"
74
+ },
75
+ text: {
76
+ primary: "#F5F5F7",
77
+ secondary: "#A1A1A6",
78
+ muted: "#8E8E93",
79
+ disabled: "#9E9EA0"
80
+ },
81
+ semantic: {
82
+ success: "#34C759",
83
+ error: "#FF453A",
84
+ warning: "#FFEB3B",
85
+ info: "#00B8E6",
86
+ infoBackground: "rgba(0, 184, 230, 0.1)",
87
+ debug: "#BF5AF2"
88
+ }
89
+ };
90
+
91
+ // =============================
92
+ // Inline lucide icons (shared-ui icons are lucide re-exports)
93
+ // =============================
94
+
95
+ function Svg({
96
+ size = 14,
97
+ color = "currentColor",
98
+ children
99
+ }) {
100
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)("svg", {
101
+ width: size,
102
+ height: size,
103
+ viewBox: "0 0 24 24",
104
+ fill: "none",
105
+ stroke: color,
106
+ strokeWidth: 2,
107
+ strokeLinecap: "round",
108
+ strokeLinejoin: "round",
109
+ style: {
110
+ flexShrink: 0,
111
+ display: "block"
112
+ },
113
+ children: children
114
+ });
115
+ }
116
+ const CheckCircle = p => /*#__PURE__*/(0, _jsxRuntime.jsxs)(Svg, {
117
+ ...p,
118
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)("path", {
119
+ d: "M21.801 10A10 10 0 1 1 17 3.335"
120
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)("path", {
121
+ d: "m9 11 3 3L22 4"
122
+ })]
123
+ });
124
+ const XCircle = p => /*#__PURE__*/(0, _jsxRuntime.jsxs)(Svg, {
125
+ ...p,
126
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)("circle", {
127
+ cx: "12",
128
+ cy: "12",
129
+ r: "10"
130
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)("path", {
131
+ d: "m15 9-6 6"
132
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)("path", {
133
+ d: "m9 9 6 6"
134
+ })]
135
+ });
136
+ const Clock = p => /*#__PURE__*/(0, _jsxRuntime.jsxs)(Svg, {
137
+ ...p,
138
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)("circle", {
139
+ cx: "12",
140
+ cy: "12",
141
+ r: "10"
142
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)("polyline", {
143
+ points: "12 6 12 12 16 14"
144
+ })]
145
+ });
146
+ const Trash2 = p => /*#__PURE__*/(0, _jsxRuntime.jsxs)(Svg, {
147
+ ...p,
148
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)("path", {
149
+ d: "M3 6h18"
150
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)("path", {
151
+ d: "M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6"
152
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)("path", {
153
+ d: "M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"
154
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)("line", {
155
+ x1: "10",
156
+ x2: "10",
157
+ y1: "11",
158
+ y2: "17"
159
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)("line", {
160
+ x1: "14",
161
+ x2: "14",
162
+ y1: "11",
163
+ y2: "17"
164
+ })]
165
+ });
166
+ const Bookmark = p => /*#__PURE__*/(0, _jsxRuntime.jsx)(Svg, {
167
+ ...p,
168
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)("path", {
169
+ d: "m19 21-7-4-7 4V5a2 2 0 0 1 2-2h10a2 2 0 0 1 2 2v16z"
170
+ })
171
+ });
172
+ const Pin = p => /*#__PURE__*/(0, _jsxRuntime.jsxs)(Svg, {
173
+ ...p,
174
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)("path", {
175
+ d: "M12 17v5"
176
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)("path", {
177
+ d: "M9 10.76a2 2 0 0 1-1.11 1.79l-1.78.9A2 2 0 0 0 5 15.24V16a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1v-.76a2 2 0 0 0-1.11-1.79l-1.78-.9A2 2 0 0 1 15 10.76V6h1a2 2 0 0 0 0-4H8a2 2 0 0 0 0 4h1z"
178
+ })]
179
+ });
180
+ const Copy = p => /*#__PURE__*/(0, _jsxRuntime.jsxs)(Svg, {
181
+ ...p,
182
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)("rect", {
183
+ width: "14",
184
+ height: "14",
185
+ x: "8",
186
+ y: "8",
187
+ rx: "2",
188
+ ry: "2"
189
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)("path", {
190
+ d: "M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2"
191
+ })]
192
+ });
193
+ const CheckCircle2 = p => /*#__PURE__*/(0, _jsxRuntime.jsxs)(Svg, {
194
+ ...p,
195
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)("circle", {
196
+ cx: "12",
197
+ cy: "12",
198
+ r: "10"
199
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)("path", {
200
+ d: "m9 12 2 2 4-4"
201
+ })]
202
+ });
203
+ const AlertTriangle = p => /*#__PURE__*/(0, _jsxRuntime.jsxs)(Svg, {
204
+ ...p,
205
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)("path", {
206
+ d: "m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3"
207
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)("path", {
208
+ d: "M12 9v4"
209
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)("path", {
210
+ d: "M12 17h.01"
211
+ })]
212
+ });
213
+ /** Success / error / pending chips — tap to toggle the status filter. */
214
+ function NetworkHeaderBadges({
215
+ activeStatus,
216
+ onToggleStatus,
217
+ ignoredPatterns,
218
+ paused
219
+ }) {
220
+ const counts = (0, _useNetworkBadgeCounts.useNetworkBadgeCounts)({
221
+ ignoredPatterns,
222
+ paused
223
+ });
224
+ return /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
225
+ style: styles.headerChipRow,
226
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)("button", {
227
+ type: "button",
228
+ style: {
229
+ ...styles.headerChip,
230
+ ...(activeStatus === "success" ? styles.headerChipActive : null)
231
+ },
232
+ onClick: () => onToggleStatus("success"),
233
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(CheckCircle, {
234
+ size: 12,
235
+ color: macOSColors.semantic.success
236
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
237
+ style: {
238
+ ...styles.headerChipValue,
239
+ color: macOSColors.semantic.success
240
+ },
241
+ children: counts.successful
242
+ })]
243
+ }), /*#__PURE__*/(0, _jsxRuntime.jsxs)("button", {
244
+ type: "button",
245
+ style: {
246
+ ...styles.headerChip,
247
+ ...(activeStatus === "error" ? styles.headerChipActive : null)
248
+ },
249
+ onClick: () => onToggleStatus("error"),
250
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(XCircle, {
251
+ size: 12,
252
+ color: macOSColors.semantic.error
253
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
254
+ style: {
255
+ ...styles.headerChipValue,
256
+ color: macOSColors.semantic.error
257
+ },
258
+ children: counts.failed
259
+ })]
260
+ }), /*#__PURE__*/(0, _jsxRuntime.jsxs)("button", {
261
+ type: "button",
262
+ style: {
263
+ ...styles.headerChip,
264
+ ...(activeStatus === "pending" ? styles.headerChipActive : null)
265
+ },
266
+ onClick: () => onToggleStatus("pending"),
267
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(Clock, {
268
+ size: 12,
269
+ color: macOSColors.semantic.warning
270
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
271
+ style: {
272
+ ...styles.headerChipValue,
273
+ color: macOSColors.semantic.warning
274
+ },
275
+ children: counts.pending
276
+ })]
277
+ })]
278
+ });
279
+ }
280
+ /** Trash button — handler co-located; enabled while the store has events.
281
+ * Subscribes to a flip-guarded boolean, so it renders when the store goes
282
+ * empty↔non-empty, not on every count change. */
283
+ function NetworkClearButton({
284
+ paused
285
+ }) {
286
+ const hasEvents = (0, _useNetworkHasMatches.useNetworkHasEvents)({
287
+ paused
288
+ });
289
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)("button", {
290
+ type: "button",
291
+ "aria-label": "Clear events",
292
+ onClick: () => _networkEventStore.networkEventStore.clearEvents(),
293
+ style: {
294
+ ...styles.headerActionButton,
295
+ ...(!hasEvents ? styles.headerActionButtonDisabled : null)
296
+ },
297
+ disabled: !hasEvents,
298
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(Trash2, {
299
+ size: 14,
300
+ color: hasEvents ? macOSColors.text.muted : macOSColors.text.disabled
301
+ })
302
+ });
303
+ }
304
+ /**
305
+ * Entry point to the Saved screen, with its count. A self-subscribing leaf so
306
+ * the badge tracks the store without the modal header re-rendering.
307
+ */
308
+ function NetworkSavedButton({
309
+ onPress
310
+ }) {
311
+ const {
312
+ savedRecords
313
+ } = (0, _useNetworkSaved.useNetworkSaved)();
314
+ const count = savedRecords.length;
315
+ return /*#__PURE__*/(0, _jsxRuntime.jsxs)("button", {
316
+ type: "button",
317
+ onClick: onPress,
318
+ "aria-label": "Saved requests",
319
+ style: styles.headerActionButton,
320
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(Bookmark, {
321
+ size: 14,
322
+ color: count > 0 ? macOSColors.semantic.debug : macOSColors.text.muted
323
+ }), count > 0 ? /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
324
+ style: styles.savedBadge,
325
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
326
+ style: styles.savedBadgeText,
327
+ children: count > 99 ? "99+" : count
328
+ })
329
+ }) : null]
330
+ });
331
+ }
332
+ /**
333
+ * Pin + Save toggles for the request-detail header — same self-subscribing
334
+ * leaf as native, for the same two reasons: the host root stays free of
335
+ * subscriptions, and these buttons deliberately do NOT live inside
336
+ * `NetworkEventDetailView` (the Events tool renders that same detail view
337
+ * with no saved store behind it).
338
+ *
339
+ * The event object is resolved at PRESS time (live store first, then the
340
+ * saved snapshot), and the selected id is SUBSCRIBED here rather than passed
341
+ * down, so stepping through requests doesn't rebuild the host header.
342
+ */
343
+ function NetworkDetailPinActions({
344
+ isPro,
345
+ onUpgradePress
346
+ }) {
347
+ const eventId = (0, _useNetworkSelection.useSelectedNetworkEventId)();
348
+ const state = (0, _useNetworkSaved.useNetworkSaved)();
349
+ const {
350
+ pinned,
351
+ saved
352
+ } = (0, _networkSavedStore.flagsForEventId)(state, eventId);
353
+ const savedLimit = isPro ? _networkSavedStore.MAX_SAVED : _networkSavedStore.FREE_TIER_SAVED_LIMIT;
354
+ const atPinCap = !pinned && state.pinnedEvents.length >= _networkSavedStore.MAX_PINNED;
355
+ const atSavedCap = !saved && state.savedRecords.length >= savedLimit;
356
+ const resolveEvent = () => {
357
+ if (!eventId) return null;
358
+ return _networkEventStore.networkEventStore.getEvents().find(event => event.id === eventId) ?? _networkSavedStore.networkSavedStore.getEventById(eventId);
359
+ };
360
+ const handlePin = () => {
361
+ const event = resolveEvent();
362
+ if (event) state.togglePin(event);
363
+ };
364
+ const handleSave = () => {
365
+ // Hitting the free ceiling is an upgrade moment, not a dead button.
366
+ if (atSavedCap && !isPro) {
367
+ onUpgradePress();
368
+ return;
369
+ }
370
+ const event = resolveEvent();
371
+ if (event) state.toggleSave(event);
372
+ };
373
+ return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, {
374
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)("button", {
375
+ type: "button",
376
+ onClick: handlePin,
377
+ disabled: atPinCap,
378
+ "aria-label": pinned ? "Unpin request" : "Pin request",
379
+ title: atPinCap ? `Pin limit reached (${_networkSavedStore.MAX_PINNED})` : undefined,
380
+ style: {
381
+ ...styles.headerActionButton,
382
+ ...(pinned ? styles.headerActionButtonActive : null),
383
+ ...(atPinCap ? styles.headerActionButtonDisabled : null)
384
+ },
385
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(Pin, {
386
+ size: 14,
387
+ color: pinned ? macOSColors.semantic.info : atPinCap ? macOSColors.text.disabled : macOSColors.text.secondary
388
+ })
389
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)("button", {
390
+ type: "button",
391
+ onClick: handleSave,
392
+ disabled: atSavedCap && isPro,
393
+ "aria-label": saved ? "Remove from saved" : "Save request",
394
+ title: atSavedCap && isPro ? `Saved limit reached (${_networkSavedStore.MAX_SAVED})` : undefined,
395
+ style: {
396
+ ...styles.headerActionButton,
397
+ ...(saved ? styles.headerActionButtonSaved : null),
398
+ ...(atSavedCap && isPro ? styles.headerActionButtonDisabled : null)
399
+ },
400
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(Bookmark, {
401
+ size: 14,
402
+ color: saved ? macOSColors.semantic.debug : atSavedCap && isPro ? macOSColors.text.disabled : macOSColors.text.secondary
403
+ })
404
+ })]
405
+ });
406
+ }
407
+ /**
408
+ * Copy-all-requests button. Subscribes to a flip-guarded boolean (its
409
+ * enabled state); the copy text is generated at PRESS time from a live
410
+ * store read, so there's no per-event work and no stale closure.
411
+ *
412
+ * The Pro branch inlines shared-ui CopyButton's copy/feedback loop (same
413
+ * icon set, 1500ms feedback, label keeps its own color while the icon
414
+ * follows the state — native's `labelStyle` wins over the state color).
415
+ */
416
+ function NetworkHeaderCopyButton({
417
+ isPro,
418
+ filter,
419
+ ignoredPatterns,
420
+ copySettings,
421
+ paused,
422
+ onUpgradePress,
423
+ label
424
+ }) {
425
+ const hasEvents = (0, _useNetworkHasMatches.useNetworkHasMatches)({
426
+ filter,
427
+ ignoredPatterns,
428
+ paused
429
+ });
430
+ const [copyState, setCopyState] = (0, _react.useState)("idle");
431
+ const timeoutRef = (0, _react.useRef)(null);
432
+ (0, _react.useEffect)(() => () => {
433
+ if (timeoutRef.current) clearTimeout(timeoutRef.current);
434
+ }, []);
435
+ if (!isPro) {
436
+ return /*#__PURE__*/(0, _jsxRuntime.jsxs)("button", {
437
+ type: "button",
438
+ onClick: onUpgradePress,
439
+ style: {
440
+ ...(label ? styles.copyMenuRow : styles.headerActionButton),
441
+ ...(!hasEvents ? styles.headerActionButtonDisabled : null)
442
+ },
443
+ disabled: !hasEvents,
444
+ "aria-label": label ?? "Copy requests",
445
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(Copy, {
446
+ size: 14,
447
+ color: hasEvents ? macOSColors.text.secondary : macOSColors.text.disabled
448
+ }), label ? /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
449
+ style: styles.copyMenuLabel,
450
+ children: label
451
+ }) : null]
452
+ });
453
+ }
454
+ const settle = state => {
455
+ setCopyState(state);
456
+ if (timeoutRef.current) clearTimeout(timeoutRef.current);
457
+ // 1500ms — shared-ui CopyButton's `feedbackDuration` default.
458
+ timeoutRef.current = setTimeout(() => {
459
+ setCopyState("idle");
460
+ timeoutRef.current = null;
461
+ }, 1500);
462
+ };
463
+ const handleCopy = async () => {
464
+ try {
465
+ // Lazy value: resolved at copy time from the LIVE store — no per-event
466
+ // work, no staleness (native's CopyButton function-value contract).
467
+ const text = (0, _generateNetworkCopyText.generateNetworkCopyText)((0, _filterNetworkEvents.filterNetworkEvents)((0, _filterNetworkEvents.applyIgnoredPatterns)(_networkEventStore.networkEventStore.getEvents(), ignoredPatterns), filter), copySettings);
468
+ await navigator.clipboard.writeText(text);
469
+ settle("success");
470
+ } catch {
471
+ settle("error");
472
+ }
473
+ };
474
+ const iconColor = copyState === "success" ? macOSColors.semantic.success : copyState === "error" ? macOSColors.semantic.error : hasEvents ? macOSColors.text.secondary : macOSColors.text.disabled;
475
+ return /*#__PURE__*/(0, _jsxRuntime.jsxs)("button", {
476
+ type: "button",
477
+ onClick: copyState === "idle" ? handleCopy : undefined,
478
+ style: {
479
+ ...(label ? styles.copyMenuRow : styles.headerActionButton),
480
+ ...(!hasEvents ? styles.headerActionButtonDisabled : null)
481
+ },
482
+ disabled: !hasEvents,
483
+ "aria-label": copyState === "idle" ? label ?? "Copy to clipboard" : copyState === "success" ? "Copied to clipboard" : "Failed to copy",
484
+ children: [copyState === "success" ? /*#__PURE__*/(0, _jsxRuntime.jsx)(CheckCircle2, {
485
+ size: 14,
486
+ color: iconColor
487
+ }) : copyState === "error" ? /*#__PURE__*/(0, _jsxRuntime.jsx)(AlertTriangle, {
488
+ size: 14,
489
+ color: iconColor
490
+ }) : /*#__PURE__*/(0, _jsxRuntime.jsx)(Copy, {
491
+ size: 14,
492
+ color: iconColor
493
+ }), label ? /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
494
+ style: styles.copyMenuLabel,
495
+ children: label
496
+ }) : null]
497
+ });
498
+ }
499
+
500
+ // Values mirror the native StyleSheet block 1:1.
501
+ const styles = {
502
+ /** The overflow-menu variant: a full-width row, matching the other items. */
503
+ copyMenuRow: {
504
+ display: "flex",
505
+ width: "100%",
506
+ boxSizing: "border-box",
507
+ flexDirection: "row",
508
+ alignItems: "center",
509
+ gap: 10,
510
+ padding: "11px 6px",
511
+ justifyContent: "flex-start",
512
+ background: "none",
513
+ border: "none",
514
+ cursor: "pointer",
515
+ margin: 0,
516
+ fontFamily: "inherit",
517
+ textAlign: "left"
518
+ },
519
+ copyMenuLabel: {
520
+ fontSize: 13,
521
+ fontWeight: 600,
522
+ color: macOSColors.text.primary
523
+ },
524
+ headerChipRow: {
525
+ display: "flex",
526
+ flexDirection: "row",
527
+ alignItems: "center",
528
+ gap: 8
529
+ },
530
+ /**
531
+ * Counter chips and toolbar buttons carry a permanent outline; the fill
532
+ * marks the active filter.
533
+ */
534
+ headerChip: {
535
+ display: "inline-flex",
536
+ flexDirection: "row",
537
+ alignItems: "center",
538
+ gap: 4,
539
+ backgroundColor: macOSColors.background.hover,
540
+ padding: "5px 10px",
541
+ borderRadius: 12,
542
+ border: `1px solid ${macOSColors.border.default}`,
543
+ cursor: "pointer",
544
+ margin: 0
545
+ },
546
+ headerChipActive: {
547
+ backgroundColor: macOSColors.semantic.infoBackground,
548
+ border: `1px solid ${macOSColors.semantic.info}50`,
549
+ // Native: shadowColor info, offset 0/1, opacity 0.08, radius 2.
550
+ boxShadow: "0 1px 2px rgba(0, 184, 230, 0.08)"
551
+ },
552
+ headerChipValue: {
553
+ fontSize: 12,
554
+ fontWeight: 600,
555
+ fontFamily: "ui-monospace, Menlo, monospace"
556
+ },
557
+ headerActionButton: {
558
+ position: "relative",
559
+ display: "inline-flex",
560
+ width: 32,
561
+ height: 32,
562
+ boxSizing: "border-box",
563
+ borderRadius: 8,
564
+ backgroundColor: macOSColors.background.hover,
565
+ border: `1px solid ${macOSColors.border.default}`,
566
+ alignItems: "center",
567
+ justifyContent: "center",
568
+ cursor: "pointer",
569
+ padding: 0,
570
+ margin: 0
571
+ },
572
+ headerActionButtonDisabled: {
573
+ opacity: 0.55,
574
+ cursor: "default"
575
+ },
576
+ headerActionButtonActive: {
577
+ backgroundColor: macOSColors.semantic.infoBackground,
578
+ border: `1px solid ${macOSColors.semantic.info}50`
579
+ },
580
+ headerActionButtonSaved: {
581
+ backgroundColor: `${macOSColors.semantic.debug}1A`,
582
+ border: `1px solid ${macOSColors.semantic.debug}50`
583
+ },
584
+ savedBadge: {
585
+ position: "absolute",
586
+ top: -3,
587
+ right: -3,
588
+ minWidth: 14,
589
+ height: 14,
590
+ boxSizing: "border-box",
591
+ padding: "0 3px",
592
+ borderRadius: 7,
593
+ backgroundColor: macOSColors.semantic.debug,
594
+ display: "inline-flex",
595
+ alignItems: "center",
596
+ justifyContent: "center"
597
+ },
598
+ savedBadgeText: {
599
+ color: "#FFFFFF",
600
+ fontSize: 9,
601
+ fontWeight: 700,
602
+ fontFamily: "ui-monospace, Menlo, monospace"
603
+ }
604
+ };
@@ -166,7 +166,8 @@ function NetworkListScreen({
166
166
  } = (0, _useNetworkEventList.useNetworkEventList)({
167
167
  filter,
168
168
  ignoredPatterns,
169
- paused: paused || !visible,
169
+ paused,
170
+ visible,
170
171
  isPro
171
172
  });
172
173