@buoy-gg/network 7.0.13 → 7.0.14

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 (123) hide show
  1. package/lib/commonjs/index.js +39 -0
  2. package/lib/commonjs/network/components/NetworkEventDetailView.js +30 -3
  3. package/lib/commonjs/network/components/NetworkEventItemCompact.js +4 -0
  4. package/lib/commonjs/network/components/NetworkHeaderLive.js +26 -6
  5. package/lib/commonjs/network/components/NetworkHeaderMenu.js +183 -0
  6. package/lib/commonjs/network/components/NetworkListScreen.js +126 -5
  7. package/lib/commonjs/network/components/NetworkModal.js +136 -29
  8. package/lib/commonjs/network/components/NetworkNumberPrompt.js +178 -0
  9. package/lib/commonjs/network/components/NetworkOverrideEditor.js +797 -0
  10. package/lib/commonjs/network/components/NetworkOverrideHeaderButton.js +102 -0
  11. package/lib/commonjs/network/components/NetworkOverridesButton.js +88 -0
  12. package/lib/commonjs/network/components/NetworkOverridesScreen.js +489 -0
  13. package/lib/commonjs/network/components/response-editor/Explorer.js +973 -0
  14. package/lib/commonjs/network/components/response-editor/deleteNestedDataByPath.js +56 -0
  15. package/lib/commonjs/network/components/response-editor/editorContext.js +33 -0
  16. package/lib/commonjs/network/components/response-editor/updateNestedDataByPath.js +61 -0
  17. package/lib/commonjs/network/hooks/useOverrideRules.js +36 -0
  18. package/lib/commonjs/network/overrides/applyToFetch.js +80 -0
  19. package/lib/commonjs/network/overrides/applyToXhr.js +190 -0
  20. package/lib/commonjs/network/overrides/engine.js +70 -0
  21. package/lib/commonjs/network/overrides/matchRule.js +81 -0
  22. package/lib/commonjs/network/overrides/overrideRulesStore.js +550 -0
  23. package/lib/commonjs/network/overrides/presets.js +70 -0
  24. package/lib/commonjs/network/overrides/resolveOverride.js +158 -0
  25. package/lib/commonjs/network/overrides/types.js +85 -0
  26. package/lib/commonjs/network/sync/networkSyncAdapter.js +230 -1
  27. package/lib/commonjs/network/types/index.js +5 -1
  28. package/lib/commonjs/network/utils/networkEventStore.js +52 -6
  29. package/lib/commonjs/network/utils/networkListener.js +90 -10
  30. package/lib/commonjs/preset.js +11 -0
  31. package/lib/module/index.js +15 -0
  32. package/lib/module/network/components/NetworkEventDetailView.js +31 -4
  33. package/lib/module/network/components/NetworkEventItemCompact.js +5 -1
  34. package/lib/module/network/components/NetworkHeaderLive.js +26 -6
  35. package/lib/module/network/components/NetworkHeaderMenu.js +177 -0
  36. package/lib/module/network/components/NetworkListScreen.js +127 -6
  37. package/lib/module/network/components/NetworkModal.js +138 -31
  38. package/lib/module/network/components/NetworkNumberPrompt.js +174 -0
  39. package/lib/module/network/components/NetworkOverrideEditor.js +794 -0
  40. package/lib/module/network/components/NetworkOverrideHeaderButton.js +99 -0
  41. package/lib/module/network/components/NetworkOverridesButton.js +85 -0
  42. package/lib/module/network/components/NetworkOverridesScreen.js +485 -0
  43. package/lib/module/network/components/response-editor/Explorer.js +972 -0
  44. package/lib/module/network/components/response-editor/deleteNestedDataByPath.js +51 -0
  45. package/lib/module/network/components/response-editor/editorContext.js +29 -0
  46. package/lib/module/network/components/response-editor/updateNestedDataByPath.js +56 -0
  47. package/lib/module/network/hooks/useOverrideRules.js +32 -0
  48. package/lib/module/network/overrides/applyToFetch.js +72 -0
  49. package/lib/module/network/overrides/applyToXhr.js +185 -0
  50. package/lib/module/network/overrides/engine.js +64 -0
  51. package/lib/module/network/overrides/matchRule.js +75 -0
  52. package/lib/module/network/overrides/overrideRulesStore.js +547 -0
  53. package/lib/module/network/overrides/presets.js +65 -0
  54. package/lib/module/network/overrides/resolveOverride.js +152 -0
  55. package/lib/module/network/overrides/types.js +80 -0
  56. package/lib/module/network/sync/networkSyncAdapter.js +230 -1
  57. package/lib/module/network/types/index.js +3 -1
  58. package/lib/module/network/utils/networkEventStore.js +52 -6
  59. package/lib/module/network/utils/networkListener.js +91 -10
  60. package/lib/module/preset.js +13 -1
  61. package/lib/typescript/index.d.ts +8 -0
  62. package/lib/typescript/index.d.ts.map +1 -1
  63. package/lib/typescript/network/components/NetworkEventDetailView.d.ts.map +1 -1
  64. package/lib/typescript/network/components/NetworkEventItemCompact.d.ts +6 -0
  65. package/lib/typescript/network/components/NetworkEventItemCompact.d.ts.map +1 -1
  66. package/lib/typescript/network/components/NetworkHeaderLive.d.ts +8 -1
  67. package/lib/typescript/network/components/NetworkHeaderLive.d.ts.map +1 -1
  68. package/lib/typescript/network/components/NetworkHeaderMenu.d.ts +46 -0
  69. package/lib/typescript/network/components/NetworkHeaderMenu.d.ts.map +1 -0
  70. package/lib/typescript/network/components/NetworkListScreen.d.ts.map +1 -1
  71. package/lib/typescript/network/components/NetworkModal.d.ts.map +1 -1
  72. package/lib/typescript/network/components/NetworkNumberPrompt.d.ts +33 -0
  73. package/lib/typescript/network/components/NetworkNumberPrompt.d.ts.map +1 -0
  74. package/lib/typescript/network/components/NetworkOverrideEditor.d.ts +17 -0
  75. package/lib/typescript/network/components/NetworkOverrideEditor.d.ts.map +1 -0
  76. package/lib/typescript/network/components/NetworkOverrideHeaderButton.d.ts +27 -0
  77. package/lib/typescript/network/components/NetworkOverrideHeaderButton.d.ts.map +1 -0
  78. package/lib/typescript/network/components/NetworkOverridesButton.d.ts +17 -0
  79. package/lib/typescript/network/components/NetworkOverridesButton.d.ts.map +1 -0
  80. package/lib/typescript/network/components/NetworkOverridesScreen.d.ts +29 -0
  81. package/lib/typescript/network/components/NetworkOverridesScreen.d.ts.map +1 -0
  82. package/lib/typescript/network/components/response-editor/Explorer.d.ts +17 -0
  83. package/lib/typescript/network/components/response-editor/Explorer.d.ts.map +1 -0
  84. package/lib/typescript/network/components/response-editor/deleteNestedDataByPath.d.ts +9 -0
  85. package/lib/typescript/network/components/response-editor/deleteNestedDataByPath.d.ts.map +1 -0
  86. package/lib/typescript/network/components/response-editor/editorContext.d.ts +29 -0
  87. package/lib/typescript/network/components/response-editor/editorContext.d.ts.map +1 -0
  88. package/lib/typescript/network/components/response-editor/updateNestedDataByPath.d.ts +10 -0
  89. package/lib/typescript/network/components/response-editor/updateNestedDataByPath.d.ts.map +1 -0
  90. package/lib/typescript/network/hooks/useOverrideRules.d.ts +29 -0
  91. package/lib/typescript/network/hooks/useOverrideRules.d.ts.map +1 -0
  92. package/lib/typescript/network/overrides/__tests__/applyToFetch.test.d.ts +16 -0
  93. package/lib/typescript/network/overrides/__tests__/applyToFetch.test.d.ts.map +1 -0
  94. package/lib/typescript/network/overrides/__tests__/applyToXhr.test.d.ts +19 -0
  95. package/lib/typescript/network/overrides/__tests__/applyToXhr.test.d.ts.map +1 -0
  96. package/lib/typescript/network/overrides/__tests__/resolveOverride.test.d.ts +22 -0
  97. package/lib/typescript/network/overrides/__tests__/resolveOverride.test.d.ts.map +1 -0
  98. package/lib/typescript/network/overrides/applyToFetch.d.ts +50 -0
  99. package/lib/typescript/network/overrides/applyToFetch.d.ts.map +1 -0
  100. package/lib/typescript/network/overrides/applyToXhr.d.ts +43 -0
  101. package/lib/typescript/network/overrides/applyToXhr.d.ts.map +1 -0
  102. package/lib/typescript/network/overrides/engine.d.ts +47 -0
  103. package/lib/typescript/network/overrides/engine.d.ts.map +1 -0
  104. package/lib/typescript/network/overrides/matchRule.d.ts +22 -0
  105. package/lib/typescript/network/overrides/matchRule.d.ts.map +1 -0
  106. package/lib/typescript/network/overrides/overrideRulesStore.d.ts +205 -0
  107. package/lib/typescript/network/overrides/overrideRulesStore.d.ts.map +1 -0
  108. package/lib/typescript/network/overrides/presets.d.ts +38 -0
  109. package/lib/typescript/network/overrides/presets.d.ts.map +1 -0
  110. package/lib/typescript/network/overrides/resolveOverride.d.ts +46 -0
  111. package/lib/typescript/network/overrides/resolveOverride.d.ts.map +1 -0
  112. package/lib/typescript/network/overrides/types.d.ts +169 -0
  113. package/lib/typescript/network/overrides/types.d.ts.map +1 -0
  114. package/lib/typescript/network/sync/networkSyncAdapter.d.ts +73 -0
  115. package/lib/typescript/network/sync/networkSyncAdapter.d.ts.map +1 -1
  116. package/lib/typescript/network/types/index.d.ts +10 -0
  117. package/lib/typescript/network/types/index.d.ts.map +1 -1
  118. package/lib/typescript/network/utils/networkEventStore.d.ts +14 -0
  119. package/lib/typescript/network/utils/networkEventStore.d.ts.map +1 -1
  120. package/lib/typescript/network/utils/networkListener.d.ts +3 -0
  121. package/lib/typescript/network/utils/networkListener.d.ts.map +1 -1
  122. package/lib/typescript/preset.d.ts.map +1 -1
  123. package/package.json +2 -2
@@ -9,12 +9,24 @@ Object.defineProperty(exports, "DEFAULT_SETTLE_MS", {
9
9
  return _networkSelectionStore.DEFAULT_SETTLE_MS;
10
10
  }
11
11
  });
12
+ Object.defineProperty(exports, "FREE_TIER_OVERRIDE_LIMIT", {
13
+ enumerable: true,
14
+ get: function () {
15
+ return _types.FREE_TIER_RULE_LIMIT;
16
+ }
17
+ });
12
18
  Object.defineProperty(exports, "FREE_TIER_SAVED_LIMIT", {
13
19
  enumerable: true,
14
20
  get: function () {
15
21
  return _networkSavedStore.FREE_TIER_SAVED_LIMIT;
16
22
  }
17
23
  });
24
+ Object.defineProperty(exports, "MAX_OVERRIDE_RULES", {
25
+ enumerable: true,
26
+ get: function () {
27
+ return _types.MAX_RULES;
28
+ }
29
+ });
18
30
  Object.defineProperty(exports, "MAX_PINNED", {
19
31
  enumerable: true,
20
32
  get: function () {
@@ -75,6 +87,18 @@ Object.defineProperty(exports, "NetworkToolView", {
75
87
  return _NetworkModal.NetworkToolView;
76
88
  }
77
89
  });
90
+ Object.defineProperty(exports, "OVERRIDE_STATUS_MAX", {
91
+ enumerable: true,
92
+ get: function () {
93
+ return _types.STATUS_MAX;
94
+ }
95
+ });
96
+ Object.defineProperty(exports, "OVERRIDE_STATUS_MIN", {
97
+ enumerable: true,
98
+ get: function () {
99
+ return _types.STATUS_MIN;
100
+ }
101
+ });
78
102
  Object.defineProperty(exports, "TickProvider", {
79
103
  enumerable: true,
80
104
  get: function () {
@@ -93,6 +117,12 @@ Object.defineProperty(exports, "createNetworkTool", {
93
117
  return _preset.createNetworkTool;
94
118
  }
95
119
  });
120
+ Object.defineProperty(exports, "draftFromEvent", {
121
+ enumerable: true,
122
+ get: function () {
123
+ return _presets.draftFromEvent;
124
+ }
125
+ });
96
126
  Object.defineProperty(exports, "flagsForEventId", {
97
127
  enumerable: true,
98
128
  get: function () {
@@ -171,6 +201,12 @@ Object.defineProperty(exports, "networkToolPreset", {
171
201
  return _preset.networkToolPreset;
172
202
  }
173
203
  });
204
+ Object.defineProperty(exports, "overrideRulesStore", {
205
+ enumerable: true,
206
+ get: function () {
207
+ return _overrideRulesStore.overrideRulesStore;
208
+ }
209
+ });
174
210
  Object.defineProperty(exports, "removeAllNetworkListeners", {
175
211
  enumerable: true,
176
212
  get: function () {
@@ -246,6 +282,9 @@ var _withPinnedFirst = require("./network/utils/withPinnedFirst");
246
282
  var _networkSelectionStore = require("./network/utils/networkSelectionStore");
247
283
  var _useTickEveryMinute = require("./network/hooks/useTickEveryMinute");
248
284
  var _formatting = require("./network/utils/formatting");
285
+ var _overrideRulesStore = require("./network/overrides/overrideRulesStore");
286
+ var _presets = require("./network/overrides/presets");
287
+ var _types = require("./network/overrides/types");
249
288
  var _sharedUi = require("@buoy-gg/shared-ui");
250
289
  var _networkSyncAdapter = require("./network/sync/networkSyncAdapter");
251
290
  var _networkBodyResolver = require("./network/sync/networkBodyResolver");
@@ -74,8 +74,11 @@ const TimingPhases = ({
74
74
  children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
75
75
  style: [styles.phaseBar, {
76
76
  backgroundColor: phase.color,
77
- // A floor so a 1ms phase is still a visible tick.
78
- width: `${Math.max(1, phase.value / span * 100)}%`
77
+ // A floor so a 1ms phase is still a visible tick, and a
78
+ // ceiling because `total` and the phases are measured at
79
+ // different points — ttfb can exceed event.duration, which
80
+ // would push the bar past its track and over the label.
81
+ width: `${Math.min(100, Math.max(1, phase.value / span * 100))}%`
79
82
  }]
80
83
  })
81
84
  }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
@@ -443,6 +446,15 @@ ${JSON.stringify(requestDetails.responseData, null, 2)}
443
446
  style: styles.httpDurationText,
444
447
  children: (0, _formatting.formatDuration)(event.duration)
445
448
  })]
449
+ }) : null, event.override ? /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
450
+ style: styles.overrideBadge,
451
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.FlaskConical, {
452
+ size: 10,
453
+ color: _sharedUi.macOSColors.semantic.warning
454
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
455
+ style: styles.overrideBadgeText,
456
+ children: event.override.ruleName || "Overridden"
457
+ })]
446
458
  }) : null, isPro ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.InlineCopyButton
447
459
  // LAZY, not `getFullRequestDetails()`. CopyButton resolves a
448
460
  // function value at press time; calling it here instead
@@ -796,6 +808,20 @@ const styles = _reactNative.StyleSheet.create({
796
808
  color: _sharedUi.macOSColors.text.secondary,
797
809
  fontSize: 11
798
810
  },
811
+ overrideBadge: {
812
+ flexDirection: "row",
813
+ alignItems: "center",
814
+ gap: 4,
815
+ paddingHorizontal: 6,
816
+ paddingVertical: 3,
817
+ borderRadius: 4,
818
+ backgroundColor: _sharedUi.macOSColors.semantic.warningBackground
819
+ },
820
+ overrideBadgeText: {
821
+ color: _sharedUi.macOSColors.semantic.warning,
822
+ fontSize: 10,
823
+ fontWeight: "700"
824
+ },
799
825
  copyFullButton: {
800
826
  marginLeft: "auto",
801
827
  flexShrink: 0,
@@ -948,7 +974,8 @@ const styles = _reactNative.StyleSheet.create({
948
974
  height: 7,
949
975
  borderRadius: 4,
950
976
  backgroundColor: _sharedUi.macOSColors.background.hover,
951
- justifyContent: "center"
977
+ justifyContent: "center",
978
+ overflow: "hidden"
952
979
  },
953
980
  phaseBar: {
954
981
  height: 7,
@@ -173,6 +173,7 @@ function NetworkEventItemCompact({
173
173
  onPress,
174
174
  pinned = false,
175
175
  saved = false,
176
+ overridden = false,
176
177
  onLongPress
177
178
  }) {
178
179
  const statusColor = getStatusColor(event.status, event.error);
@@ -211,6 +212,9 @@ function NetworkEventItemCompact({
211
212
  }) : null, saved ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.Bookmark, {
212
213
  size: 10,
213
214
  color: _sharedUi.macOSColors.semantic.debug
215
+ }) : null, overridden || event.override ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.FlaskConical, {
216
+ size: 10,
217
+ color: _sharedUi.macOSColors.semantic.warning
214
218
  }) : null, /*#__PURE__*/(0, _jsxRuntime.jsx)(StatusIndicator, {
215
219
  event: event,
216
220
  isPending: isPending,
@@ -222,7 +222,8 @@ function NetworkHeaderCopyButton({
222
222
  ignoredPatterns,
223
223
  copySettings,
224
224
  paused,
225
- onUpgradePress
225
+ onUpgradePress,
226
+ label
226
227
  }) {
227
228
  const hasEvents = (0, _useNetworkHasMatches.useNetworkHasMatches)({
228
229
  filter,
@@ -230,15 +231,18 @@ function NetworkHeaderCopyButton({
230
231
  paused
231
232
  });
232
233
  if (!isPro) {
233
- return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
234
+ return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.TouchableOpacity, {
234
235
  "sentry-label": "ignore copy pro",
235
236
  onPress: onUpgradePress,
236
- style: [styles.headerActionButton, !hasEvents && styles.headerActionButtonDisabled],
237
+ style: [label ? styles.copyMenuRow : styles.headerActionButton, !hasEvents && styles.headerActionButtonDisabled],
237
238
  disabled: !hasEvents,
238
- children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.Copy, {
239
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.Copy, {
239
240
  size: 14,
240
241
  color: hasEvents ? _sharedUi.macOSColors.text.secondary : _sharedUi.macOSColors.text.disabled
241
- })
242
+ }), label ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
243
+ style: styles.copyMenuLabel,
244
+ children: label
245
+ }) : null]
242
246
  });
243
247
  }
244
248
  return /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.CopyButton
@@ -247,7 +251,9 @@ function NetworkHeaderCopyButton({
247
251
  , {
248
252
  value: () => (0, _generateNetworkCopyText.generateNetworkCopyText)((0, _filterNetworkEvents.filterNetworkEvents)((0, _filterNetworkEvents.applyIgnoredPatterns)(_networkEventStore.networkEventStore.getEvents(), ignoredPatterns), filter), copySettings),
249
253
  size: 14,
250
- buttonStyle: styles.headerActionButton,
254
+ label: label,
255
+ buttonStyle: label ? styles.copyMenuRow : styles.headerActionButton,
256
+ labelStyle: styles.copyMenuLabel,
251
257
  colors: {
252
258
  idle: hasEvents ? _sharedUi.macOSColors.text.secondary : _sharedUi.macOSColors.text.disabled,
253
259
  success: _sharedUi.macOSColors.semantic.success,
@@ -257,6 +263,20 @@ function NetworkHeaderCopyButton({
257
263
  });
258
264
  }
259
265
  const styles = _reactNative.StyleSheet.create({
266
+ /** The overflow-menu variant: a full-width row, matching the other items. */
267
+ copyMenuRow: {
268
+ flexDirection: "row",
269
+ alignItems: "center",
270
+ gap: 10,
271
+ paddingHorizontal: 6,
272
+ paddingVertical: 11,
273
+ justifyContent: "flex-start"
274
+ },
275
+ copyMenuLabel: {
276
+ fontSize: 13,
277
+ fontWeight: "600",
278
+ color: _sharedUi.macOSColors.text.primary
279
+ },
260
280
  headerChipRow: {
261
281
  flexDirection: "row",
262
282
  alignItems: "center",
@@ -0,0 +1,183 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.NetworkHeaderMenu = NetworkHeaderMenu;
7
+ exports.NetworkHeaderMenuButton = NetworkHeaderMenuButton;
8
+ exports.NetworkHeaderMenuItem = NetworkHeaderMenuItem;
9
+ var _reactNative = require("react-native");
10
+ var _sharedUi = require("@buoy-gg/shared-ui");
11
+ var _jsxRuntime = require("react/jsx-runtime");
12
+ /**
13
+ * The header's overflow menu.
14
+ *
15
+ * The toolbar had grown to three status badges and six icon buttons, which on a
16
+ * 402pt screen meant the pending badge was being overlapped by the search
17
+ * button. Something had to leave, and the rule for deciding what is:
18
+ *
19
+ * **A control that COMMUNICATES STATE stays visible. A destination or a rare
20
+ * action goes in the menu.**
21
+ *
22
+ * That keeps the power toggle (are we capturing?), the overrides flask (is the
23
+ * app being lied to, and how many rules?), the status badges (what happened)
24
+ * and Clear (the reproduce loop is clear → repro → read, and burying the first
25
+ * step doubles it). Search stays because it's the only way through 500 rows.
26
+ *
27
+ * Filters, Saved and Copy leave. Filters is the interesting one — it does show
28
+ * state, so the ⋯ carries a dot when a filter is applied rather than hiding
29
+ * that fact.
30
+ */
31
+
32
+ function NetworkHeaderMenuButton({
33
+ onPress,
34
+ isOpen,
35
+ hasIndicator
36
+ }) {
37
+ return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.TouchableOpacity, {
38
+ onPress: onPress,
39
+ "sentry-label": "ignore toggle header menu",
40
+ accessibilityLabel: isOpen ? "Close menu" : "More actions",
41
+ style: [styles.button, isOpen && styles.buttonOpen],
42
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
43
+ style: styles.dots,
44
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
45
+ style: [styles.dot, isOpen && styles.dotOpen]
46
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
47
+ style: [styles.dot, isOpen && styles.dotOpen]
48
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
49
+ style: [styles.dot, isOpen && styles.dotOpen]
50
+ })]
51
+ }), hasIndicator ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
52
+ style: styles.indicator
53
+ }) : null]
54
+ });
55
+ }
56
+ /**
57
+ * The dropdown itself, rendered in the modal BODY rather than the header —
58
+ * the header is a fixed-height row and anything overflowing it is clipped, so
59
+ * a panel anchored to the top-right of the body lands exactly where a dropdown
60
+ * from the ⋯ should appear.
61
+ */
62
+ function NetworkHeaderMenu({
63
+ onClose,
64
+ children
65
+ }) {
66
+ return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
67
+ style: styles.overlay,
68
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
69
+ style: styles.backdrop,
70
+ activeOpacity: 1,
71
+ onPress: onClose,
72
+ "sentry-label": "ignore dismiss header menu"
73
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
74
+ style: styles.panel,
75
+ children: children
76
+ })]
77
+ });
78
+ }
79
+ function NetworkHeaderMenuItem({
80
+ icon,
81
+ label,
82
+ detail,
83
+ onPress
84
+ }) {
85
+ return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.TouchableOpacity, {
86
+ onPress: onPress,
87
+ "sentry-label": "ignore header menu item",
88
+ style: styles.item,
89
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
90
+ style: styles.itemIcon,
91
+ children: icon
92
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
93
+ style: styles.itemLabel,
94
+ children: label
95
+ }), detail ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
96
+ style: styles.itemDetail,
97
+ children: detail
98
+ }) : null]
99
+ });
100
+ }
101
+ const styles = _reactNative.StyleSheet.create({
102
+ // The same 32×32 box every other header action uses, minus the fill and
103
+ // border. Padding alone gave a 3pt-wide hit area AND a shorter box than its
104
+ // neighbours, which is why the dots sat high in the row; a fixed square
105
+ // centres the glyph on the same baseline as the search/power/clear icons.
106
+ button: {
107
+ width: 32,
108
+ height: 32,
109
+ borderRadius: 8,
110
+ alignItems: "center",
111
+ justifyContent: "center"
112
+ },
113
+ // Only lit while the menu is down — the button is the one thing not covered
114
+ // by the backdrop, so it has to look like the thing that is currently open.
115
+ buttonOpen: {
116
+ backgroundColor: _sharedUi.macOSColors.background.hover
117
+ },
118
+ dots: {
119
+ flexDirection: "column",
120
+ gap: 2.5,
121
+ alignItems: "center"
122
+ },
123
+ dot: {
124
+ width: 3,
125
+ height: 3,
126
+ borderRadius: 2,
127
+ backgroundColor: _sharedUi.macOSColors.text.secondary
128
+ },
129
+ dotOpen: {
130
+ backgroundColor: _sharedUi.macOSColors.text.primary
131
+ },
132
+ indicator: {
133
+ position: "absolute",
134
+ // Sits just up-and-right of the top dot. Anchored to the 32pt box's corner
135
+ // it would float off on its own, since the dot column is only 3pt wide.
136
+ top: 6,
137
+ right: 8,
138
+ width: 6,
139
+ height: 6,
140
+ borderRadius: 3,
141
+ backgroundColor: _sharedUi.macOSColors.semantic.info
142
+ },
143
+ overlay: {
144
+ ..._sharedUi.absoluteFill,
145
+ zIndex: 50
146
+ },
147
+ backdrop: {
148
+ ..._sharedUi.absoluteFill,
149
+ backgroundColor: "rgba(0,0,0,0.5)"
150
+ },
151
+ panel: {
152
+ position: "absolute",
153
+ top: 6,
154
+ right: 8,
155
+ minWidth: 196,
156
+ paddingVertical: 4,
157
+ borderRadius: 8,
158
+ borderWidth: 1,
159
+ borderColor: _sharedUi.macOSColors.border.hover,
160
+ backgroundColor: _sharedUi.macOSColors.background.card
161
+ },
162
+ item: {
163
+ flexDirection: "row",
164
+ alignItems: "center",
165
+ gap: 10,
166
+ paddingHorizontal: 12,
167
+ paddingVertical: 11
168
+ },
169
+ itemIcon: {
170
+ width: 16,
171
+ alignItems: "center"
172
+ },
173
+ itemLabel: {
174
+ flex: 1,
175
+ fontSize: 13,
176
+ fontWeight: "600",
177
+ color: _sharedUi.macOSColors.text.primary
178
+ },
179
+ itemDetail: {
180
+ fontSize: 11,
181
+ color: _sharedUi.macOSColors.text.muted
182
+ }
183
+ });
@@ -11,6 +11,8 @@ var _NetworkEventItemCompact = require("./NetworkEventItemCompact");
11
11
  var _NetworkUpgradeBanner = require("./NetworkUpgradeBanner");
12
12
  var _useNetworkEventList = require("../hooks/useNetworkEventList");
13
13
  var _useNetworkSaved = require("../hooks/useNetworkSaved");
14
+ var _useOverrideRules = require("../hooks/useOverrideRules");
15
+ var _matchRule = require("../overrides/matchRule");
14
16
  var _withPinnedFirst = require("../utils/withPinnedFirst");
15
17
  var _jsxRuntime = require("react/jsx-runtime");
16
18
  /**
@@ -91,6 +93,62 @@ function PinnedSection({
91
93
  }, event.id))]
92
94
  });
93
95
  }
96
+
97
+ /**
98
+ * The OVERRIDDEN strip, above the pins.
99
+ *
100
+ * An overridden request is the one thing in this list that isn't true — the app
101
+ * got something the server never sent. That has to be impossible to miss, and a
102
+ * glyph on a row twenty scroll-positions down isn't. It sits ABOVE pins because
103
+ * a stale override explains a bug, whereas a pin only marks one.
104
+ *
105
+ * Rows are matched against the RULES rather than filtered on the `override`
106
+ * mark, so the request you built a rule from hoists immediately instead of
107
+ * waiting for the endpoint to be called again.
108
+ *
109
+ * The header button is PAUSE, not "Manage". Flipping overrides off and on is by
110
+ * far the most repeated action in a testing session — force the failure, check
111
+ * the UI, turn it off, check the happy path, turn it back on — and it used to
112
+ * cost a trip to another screen each way. The manager is still one tap away on
113
+ * the toolbar; it just isn't the thing you reach for twenty times an hour.
114
+ */
115
+ function OverriddenSection({
116
+ events,
117
+ onEventPress,
118
+ onLongPress,
119
+ savedLiveIds,
120
+ paused,
121
+ onTogglePaused
122
+ }) {
123
+ if (events.length === 0) return null;
124
+ return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
125
+ style: [styles.overriddenSection, paused && styles.overriddenSectionOff],
126
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
127
+ style: styles.overriddenHeader,
128
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.FlaskConical, {
129
+ size: 11,
130
+ color: paused ? _sharedUi.macOSColors.text.muted : _sharedUi.macOSColors.semantic.warning
131
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
132
+ style: [styles.overriddenTitle, paused && styles.overriddenTitleOff],
133
+ children: paused ? `PAUSED · ${events.length}` : `OVERRIDDEN · ${events.length}`
134
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
135
+ onPress: onTogglePaused,
136
+ "sentry-label": "ignore pause overrides",
137
+ style: styles.overriddenManage,
138
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
139
+ style: [styles.overriddenManageText, paused && styles.overriddenTitleOff],
140
+ children: paused ? "Resume" : "Pause"
141
+ })
142
+ })]
143
+ }), events.map(event => /*#__PURE__*/(0, _jsxRuntime.jsx)(_NetworkEventItemCompact.NetworkEventItemCompact, {
144
+ event: event,
145
+ onPress: onEventPress,
146
+ onLongPress: onLongPress,
147
+ overridden: true,
148
+ saved: savedLiveIds.has(event.id)
149
+ }, event.id))]
150
+ });
151
+ }
94
152
  function NetworkListScreen({
95
153
  visible,
96
154
  paused,
@@ -122,6 +180,15 @@ function NetworkListScreen({
122
180
  clearPinned
123
181
  } = (0, _useNetworkSaved.useNetworkSaved)();
124
182
 
183
+ // Which rules are live right now — the strip below reflects the rules, not
184
+ // the history, so it's correct the moment a rule is made or removed.
185
+ const {
186
+ rules,
187
+ enabled: overridesEnabled,
188
+ setEnabled,
189
+ isRuleSpent
190
+ } = (0, _useOverrideRules.useOverrideRules)();
191
+
125
192
  // Stable identity: handed to memoized rows.
126
193
  const handleLongPress = (0, _react.useCallback)(event => {
127
194
  togglePin(event);
@@ -136,6 +203,17 @@ function NetworkListScreen({
136
203
  pinned,
137
204
  rest
138
205
  } = (0, _withPinnedFirst.splitPinned)(visibleEvents, pinnedEvents, pinnedLiveIds);
206
+
207
+ // Hoist anything an active rule covers. Done after `splitPinned` so a request
208
+ // that is both pinned and overridden appears once, in the louder section.
209
+ // Paused rules still populate the strip — that's how you find the thing you
210
+ // paused in order to resume it. The header says PAUSED instead.
211
+ const activeRules = rules.filter(rule => rule.enabled && !isRuleSpent(rule));
212
+ const isOverridden = event => activeRules.some(rule => (0, _matchRule.ruleMatches)(rule, event.url, String(event.method || "GET")));
213
+ const overridden = activeRules.length ? [...pinned, ...rest].filter(isOverridden) : [];
214
+ const overriddenIds = new Set(overridden.map(event => event.id));
215
+ const pinnedRows = pinned.filter(event => !overriddenIds.has(event.id));
216
+ const restRows = overriddenIds.size ? rest.filter(event => !overriddenIds.has(event.id)) : rest;
139
217
  const isEnabled = !paused;
140
218
  const renderItem = ({
141
219
  item
@@ -167,14 +245,21 @@ function NetworkListScreen({
167
245
  style: styles.disabledText,
168
246
  children: "Network interception is disabled"
169
247
  })]
170
- }) : null, /*#__PURE__*/(0, _jsxRuntime.jsx)(PinnedSection, {
171
- events: pinned,
248
+ }) : null, /*#__PURE__*/(0, _jsxRuntime.jsx)(OverriddenSection, {
249
+ events: overridden,
250
+ onEventPress: onEventPress,
251
+ onLongPress: handleLongPress,
252
+ savedLiveIds: savedLiveIds,
253
+ paused: !overridesEnabled,
254
+ onTogglePaused: () => setEnabled(!overridesEnabled)
255
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(PinnedSection, {
256
+ events: pinnedRows,
172
257
  onEventPress: onEventPress,
173
258
  onLongPress: handleLongPress,
174
259
  savedLiveIds: savedLiveIds,
175
260
  onClearPinned: clearPinned
176
- }), rest.length > 0 || hasLockedEvents ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.FlatList, {
177
- data: rest,
261
+ }), restRows.length > 0 || hasLockedEvents ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.FlatList, {
262
+ data: restRows,
178
263
  renderItem: renderItem,
179
264
  keyExtractor: keyExtractor,
180
265
  contentContainerStyle: styles.listContent,
@@ -203,7 +288,7 @@ function NetworkListScreen({
203
288
  extraData: savedLiveIds,
204
289
  "sentry-label": "ignore network events list",
205
290
  ListFooterComponent: renderListFooter
206
- }) : pinned.length > 0 ? null : /*#__PURE__*/(0, _jsxRuntime.jsx)(EmptyState, {
291
+ }) : pinnedRows.length > 0 || overridden.length > 0 ? null : /*#__PURE__*/(0, _jsxRuntime.jsx)(EmptyState, {
207
292
  isEnabled: isEnabled
208
293
  })]
209
294
  });
@@ -218,6 +303,42 @@ const styles = _reactNative.StyleSheet.create({
218
303
  * these rows do NOT obey the filters, and the boundary is what tells the
219
304
  * user why a request they just filtered out is still on screen.
220
305
  */
306
+ overriddenSection: {
307
+ borderBottomWidth: 1,
308
+ borderBottomColor: _sharedUi.macOSColors.semantic.warning + "44",
309
+ backgroundColor: _sharedUi.macOSColors.semantic.warningBackground
310
+ },
311
+ overriddenSectionOff: {
312
+ borderBottomColor: _sharedUi.macOSColors.border.default,
313
+ backgroundColor: _sharedUi.macOSColors.background.card
314
+ },
315
+ overriddenTitleOff: {
316
+ color: _sharedUi.macOSColors.text.muted
317
+ },
318
+ overriddenHeader: {
319
+ flexDirection: "row",
320
+ alignItems: "center",
321
+ gap: 6,
322
+ paddingHorizontal: 12,
323
+ paddingTop: 8,
324
+ paddingBottom: 4
325
+ },
326
+ overriddenTitle: {
327
+ flex: 1,
328
+ fontSize: 10,
329
+ fontWeight: "700",
330
+ letterSpacing: 0.8,
331
+ color: _sharedUi.macOSColors.semantic.warning
332
+ },
333
+ overriddenManage: {
334
+ paddingHorizontal: 6,
335
+ paddingVertical: 2
336
+ },
337
+ overriddenManageText: {
338
+ fontSize: 10,
339
+ fontWeight: "600",
340
+ color: _sharedUi.macOSColors.semantic.warning
341
+ },
221
342
  pinnedSection: {
222
343
  borderBottomWidth: 1,
223
344
  borderBottomColor: _sharedUi.macOSColors.border.default,