@buoy-gg/network 7.0.15 → 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.
- package/lib/commonjs/index.web.js +395 -0
- package/lib/commonjs/network/components/DataViewer.web.js +879 -0
- package/lib/commonjs/network/components/NetworkCopyScreen.web.js +48 -0
- package/lib/commonjs/network/components/NetworkCopySettingsView.web.js +1242 -0
- package/lib/commonjs/network/components/NetworkDetailScreen.web.js +101 -0
- package/lib/commonjs/network/components/NetworkDetailStepper.web.js +296 -0
- package/lib/commonjs/network/components/NetworkEventDetailView.web.js +1498 -0
- package/lib/commonjs/network/components/NetworkEventItemCompact.web.js +802 -0
- package/lib/commonjs/network/components/NetworkFilterScreen.web.js +55 -0
- package/lib/commonjs/network/components/NetworkFilterViewV3.web.js +1310 -0
- package/lib/commonjs/network/components/NetworkHeaderLive.web.js +604 -0
- package/lib/commonjs/network/components/NetworkListScreen.js +2 -1
- package/lib/commonjs/network/components/NetworkListScreen.web.js +607 -0
- package/lib/commonjs/network/components/NetworkModal.js +12 -3
- package/lib/commonjs/network/components/NetworkNumberPrompt.web.js +232 -0
- package/lib/commonjs/network/components/NetworkOverrideEditor.web.js +942 -0
- package/lib/commonjs/network/components/NetworkOverrideHeaderButton.web.js +133 -0
- package/lib/commonjs/network/components/NetworkOverridesButton.web.js +143 -0
- package/lib/commonjs/network/components/NetworkOverridesScreen.js +160 -126
- package/lib/commonjs/network/components/NetworkOverridesScreen.web.js +830 -0
- package/lib/commonjs/network/components/NetworkSavedScreen.web.js +459 -0
- package/lib/commonjs/network/components/response-editor/Explorer.web.js +1136 -0
- package/lib/commonjs/network/hooks/useNetworkEventList.js +12 -2
- package/lib/commonjs/network/overrides/applyToXhr.js +276 -15
- package/lib/commonjs/network/utils/generateNetworkCopyText.js +32 -5
- package/lib/commonjs/network/utils/networkEventStore.js +12 -4
- package/lib/commonjs/network/utils/networkListener.js +1 -16
- package/lib/module/index.web.js +81 -0
- package/lib/module/network/components/DataViewer.web.js +875 -0
- package/lib/module/network/components/NetworkCopyScreen.web.js +44 -0
- package/lib/module/network/components/NetworkCopySettingsView.web.js +1237 -0
- package/lib/module/network/components/NetworkDetailScreen.web.js +97 -0
- package/lib/module/network/components/NetworkDetailStepper.web.js +294 -0
- package/lib/module/network/components/NetworkEventDetailView.web.js +1496 -0
- package/lib/module/network/components/NetworkEventItemCompact.web.js +800 -0
- package/lib/module/network/components/NetworkFilterScreen.web.js +51 -0
- package/lib/module/network/components/NetworkFilterViewV3.web.js +1306 -0
- package/lib/module/network/components/NetworkHeaderLive.web.js +598 -0
- package/lib/module/network/components/NetworkListScreen.js +2 -1
- package/lib/module/network/components/NetworkListScreen.web.js +605 -0
- package/lib/module/network/components/NetworkModal.js +12 -3
- package/lib/module/network/components/NetworkNumberPrompt.web.js +230 -0
- package/lib/module/network/components/NetworkOverrideEditor.web.js +939 -0
- package/lib/module/network/components/NetworkOverrideHeaderButton.web.js +131 -0
- package/lib/module/network/components/NetworkOverridesButton.web.js +141 -0
- package/lib/module/network/components/NetworkOverridesScreen.js +161 -127
- package/lib/module/network/components/NetworkOverridesScreen.web.js +826 -0
- package/lib/module/network/components/NetworkSavedScreen.web.js +457 -0
- package/lib/module/network/components/response-editor/Explorer.web.js +1133 -0
- package/lib/module/network/hooks/useNetworkEventList.js +12 -2
- package/lib/module/network/overrides/applyToXhr.js +275 -15
- package/lib/module/network/utils/generateNetworkCopyText.js +28 -1
- package/lib/module/network/utils/networkEventStore.js +12 -4
- package/lib/module/network/utils/networkListener.js +1 -16
- package/lib/typescript/index.web.d.ts +56 -0
- package/lib/typescript/index.web.d.ts.map +1 -0
- package/lib/typescript/network/components/DataViewer.web.d.ts +78 -0
- package/lib/typescript/network/components/DataViewer.web.d.ts.map +1 -0
- package/lib/typescript/network/components/NetworkCopyScreen.web.d.ts +27 -0
- package/lib/typescript/network/components/NetworkCopyScreen.web.d.ts.map +1 -0
- package/lib/typescript/network/components/NetworkCopySettingsView.web.d.ts +68 -0
- package/lib/typescript/network/components/NetworkCopySettingsView.web.d.ts.map +1 -0
- package/lib/typescript/network/components/NetworkDetailScreen.web.d.ts +45 -0
- package/lib/typescript/network/components/NetworkDetailScreen.web.d.ts.map +1 -0
- package/lib/typescript/network/components/NetworkDetailStepper.web.d.ts +40 -0
- package/lib/typescript/network/components/NetworkDetailStepper.web.d.ts.map +1 -0
- package/lib/typescript/network/components/NetworkEventDetailView.web.d.ts +67 -0
- package/lib/typescript/network/components/NetworkEventDetailView.web.d.ts.map +1 -0
- package/lib/typescript/network/components/NetworkEventItemCompact.web.d.ts +58 -0
- package/lib/typescript/network/components/NetworkEventItemCompact.web.d.ts.map +1 -0
- package/lib/typescript/network/components/NetworkFilterScreen.web.d.ts +28 -0
- package/lib/typescript/network/components/NetworkFilterScreen.web.d.ts.map +1 -0
- package/lib/typescript/network/components/NetworkFilterViewV3.web.d.ts +74 -0
- package/lib/typescript/network/components/NetworkFilterViewV3.web.d.ts.map +1 -0
- package/lib/typescript/network/components/NetworkHeaderLive.web.d.ts +112 -0
- package/lib/typescript/network/components/NetworkHeaderLive.web.d.ts.map +1 -0
- package/lib/typescript/network/components/NetworkListScreen.d.ts.map +1 -1
- package/lib/typescript/network/components/NetworkListScreen.web.d.ts +63 -0
- package/lib/typescript/network/components/NetworkListScreen.web.d.ts.map +1 -0
- package/lib/typescript/network/components/NetworkModal.d.ts.map +1 -1
- package/lib/typescript/network/components/NetworkNumberPrompt.web.d.ts +38 -0
- package/lib/typescript/network/components/NetworkNumberPrompt.web.d.ts.map +1 -0
- package/lib/typescript/network/components/NetworkOverrideEditor.web.d.ts +43 -0
- package/lib/typescript/network/components/NetworkOverrideEditor.web.d.ts.map +1 -0
- package/lib/typescript/network/components/NetworkOverrideHeaderButton.web.d.ts +32 -0
- package/lib/typescript/network/components/NetworkOverrideHeaderButton.web.d.ts.map +1 -0
- package/lib/typescript/network/components/NetworkOverridesButton.web.d.ts +26 -0
- package/lib/typescript/network/components/NetworkOverridesButton.web.d.ts.map +1 -0
- package/lib/typescript/network/components/NetworkOverridesScreen.d.ts +9 -0
- package/lib/typescript/network/components/NetworkOverridesScreen.d.ts.map +1 -1
- package/lib/typescript/network/components/NetworkOverridesScreen.web.d.ts +69 -0
- package/lib/typescript/network/components/NetworkOverridesScreen.web.d.ts.map +1 -0
- package/lib/typescript/network/components/NetworkSavedScreen.web.d.ts +67 -0
- package/lib/typescript/network/components/NetworkSavedScreen.web.d.ts.map +1 -0
- package/lib/typescript/network/components/response-editor/Explorer.web.d.ts +56 -0
- package/lib/typescript/network/components/response-editor/Explorer.web.d.ts.map +1 -0
- package/lib/typescript/network/hooks/useNetworkEventList.d.ts +10 -0
- package/lib/typescript/network/hooks/useNetworkEventList.d.ts.map +1 -1
- package/lib/typescript/network/overrides/__tests__/applyToXhr.test.d.ts.map +1 -1
- package/lib/typescript/network/overrides/applyToXhr.d.ts +40 -14
- package/lib/typescript/network/overrides/applyToXhr.d.ts.map +1 -1
- package/lib/typescript/network/utils/generateNetworkCopyText.d.ts +34 -1
- package/lib/typescript/network/utils/generateNetworkCopyText.d.ts.map +1 -1
- package/lib/typescript/network/utils/networkEventStore.d.ts.map +1 -1
- package/lib/typescript/network/utils/networkListener.d.ts +0 -1
- package/lib/typescript/network/utils/networkListener.d.ts.map +1 -1
- package/package.json +2 -2
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.NetworkOverrideHeaderButton = NetworkOverrideHeaderButton;
|
|
7
|
+
var _useOverrideRules = require("../hooks/useOverrideRules");
|
|
8
|
+
var _useNetworkSelection = require("../hooks/useNetworkSelection");
|
|
9
|
+
var _matchRule = require("../overrides/matchRule");
|
|
10
|
+
var _presets = require("../overrides/presets");
|
|
11
|
+
var _networkEventStore = require("../utils/networkEventStore");
|
|
12
|
+
var _networkSavedStore = require("../utils/networkSavedStore");
|
|
13
|
+
var _jsxRuntime = require("react/jsx-runtime");
|
|
14
|
+
/**
|
|
15
|
+
* NetworkOverrideHeaderButton.web — DOM twin of
|
|
16
|
+
* NetworkOverrideHeaderButton.tsx.
|
|
17
|
+
*
|
|
18
|
+
* The Override action, in the request-detail header. A labelled word rather
|
|
19
|
+
* than an icon — it's the least familiar action in the tool, and "Override"
|
|
20
|
+
* spelled out is the entire explanation. A self-subscribing leaf: the
|
|
21
|
+
* selected id and the rule list are subscribed HERE so stepping between
|
|
22
|
+
* requests doesn't rebuild the header around a new prop.
|
|
23
|
+
*
|
|
24
|
+
* It lights up while a rule covers the request you're looking at — the same
|
|
25
|
+
* warning tint the OVERRIDDEN strip and the toolbar flask use. Tapping it
|
|
26
|
+
* goes straight to the Overrides screen with the rule open: a new one
|
|
27
|
+
* prefilled from this request (`draftFromEvent`), or the existing one if
|
|
28
|
+
* something already covers it (first enabled match wins, so stacking a
|
|
29
|
+
* second rule the first would shadow is never offered). (Native comments.)
|
|
30
|
+
*
|
|
31
|
+
* REUSED, not forked (all platform-free): `useOverrideRules`,
|
|
32
|
+
* `useSelectedNetworkEventId`, `ruleMatches`, `draftFromEvent`,
|
|
33
|
+
* `networkEventStore`, `networkSavedStore`.
|
|
34
|
+
*
|
|
35
|
+
* shared-ui RN chrome is replicated as DOM with provenance:
|
|
36
|
+
* - `macOSColors` — inlined verbatim subset from
|
|
37
|
+
* shared/src/ui/gameUI/constants/macOSDesignSystemColors.ts.
|
|
38
|
+
*
|
|
39
|
+
* @platform React DOM Web
|
|
40
|
+
*/
|
|
41
|
+
|
|
42
|
+
/** macOSColors subset — shared/src/ui/gameUI/constants/macOSDesignSystemColors.ts, verbatim. */const macOSColors = {
|
|
43
|
+
background: {
|
|
44
|
+
input: "#26262A"
|
|
45
|
+
},
|
|
46
|
+
border: {
|
|
47
|
+
input: "#3D3D42"
|
|
48
|
+
},
|
|
49
|
+
text: {
|
|
50
|
+
primary: "#F5F5F7"
|
|
51
|
+
},
|
|
52
|
+
semantic: {
|
|
53
|
+
warning: "#FFEB3B",
|
|
54
|
+
warningBackground: "rgba(255, 235, 59, 0.15)"
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
function NetworkOverrideHeaderButton({
|
|
58
|
+
onOpen
|
|
59
|
+
}) {
|
|
60
|
+
const eventId = (0, _useNetworkSelection.useSelectedNetworkEventId)();
|
|
61
|
+
const {
|
|
62
|
+
rules,
|
|
63
|
+
isRuleSpent
|
|
64
|
+
} = (0, _useOverrideRules.useOverrideRules)();
|
|
65
|
+
|
|
66
|
+
// Resolved here rather than held as a prop: the live store has the fresh
|
|
67
|
+
// copy while a request is in flight, and the saved store is the only copy
|
|
68
|
+
// once it has been cleared or aged out. (Native comment.)
|
|
69
|
+
const event = eventId ? _networkEventStore.networkEventStore.getEvents().find(e => e.id === eventId) ?? _networkSavedStore.networkSavedStore.getEventById(eventId) : null;
|
|
70
|
+
const existing = event ? rules.find(rule => rule.enabled && !isRuleSpent(rule) && (0, _matchRule.ruleMatches)(rule, event.url, String(event.method || "GET"))) ?? null : null;
|
|
71
|
+
const active = existing !== null;
|
|
72
|
+
const handlePress = () => {
|
|
73
|
+
if (!event) return;
|
|
74
|
+
if (existing) {
|
|
75
|
+
// Editing what's already there, rather than stacking a second rule the
|
|
76
|
+
// first would shadow — first enabled match wins.
|
|
77
|
+
const {
|
|
78
|
+
id,
|
|
79
|
+
hits: _h,
|
|
80
|
+
seen: _s,
|
|
81
|
+
createdAt: _c,
|
|
82
|
+
...draft
|
|
83
|
+
} = existing;
|
|
84
|
+
onOpen(draft, id);
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
onOpen((0, _presets.draftFromEvent)(event));
|
|
88
|
+
};
|
|
89
|
+
return /*#__PURE__*/(0, _jsxRuntime.jsx)("button", {
|
|
90
|
+
type: "button",
|
|
91
|
+
onClick: handlePress,
|
|
92
|
+
"aria-label": active ? "Edit the override on this request" : "Override this request",
|
|
93
|
+
style: {
|
|
94
|
+
...styles.button,
|
|
95
|
+
...(active ? styles.buttonActive : null)
|
|
96
|
+
},
|
|
97
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
|
|
98
|
+
style: {
|
|
99
|
+
...styles.label,
|
|
100
|
+
...(active ? styles.labelActive : null)
|
|
101
|
+
},
|
|
102
|
+
children: "Override"
|
|
103
|
+
})
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// Values mirror the native StyleSheet block 1:1.
|
|
108
|
+
const styles = {
|
|
109
|
+
button: {
|
|
110
|
+
display: "inline-flex",
|
|
111
|
+
alignItems: "center",
|
|
112
|
+
padding: "6px 10px",
|
|
113
|
+
borderRadius: 6,
|
|
114
|
+
border: `1px solid ${macOSColors.border.input}`,
|
|
115
|
+
backgroundColor: macOSColors.background.input,
|
|
116
|
+
cursor: "pointer",
|
|
117
|
+
margin: 0,
|
|
118
|
+
boxSizing: "border-box"
|
|
119
|
+
},
|
|
120
|
+
buttonActive: {
|
|
121
|
+
border: `1px solid ${macOSColors.semantic.warning}77`,
|
|
122
|
+
backgroundColor: macOSColors.semantic.warningBackground
|
|
123
|
+
},
|
|
124
|
+
label: {
|
|
125
|
+
fontSize: 11,
|
|
126
|
+
fontWeight: 700,
|
|
127
|
+
color: macOSColors.text.primary,
|
|
128
|
+
fontFamily: "inherit"
|
|
129
|
+
},
|
|
130
|
+
labelActive: {
|
|
131
|
+
color: macOSColors.semantic.warning
|
|
132
|
+
}
|
|
133
|
+
};
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.NetworkOverridesButton = NetworkOverridesButton;
|
|
7
|
+
var _useOverrideRules = require("../hooks/useOverrideRules");
|
|
8
|
+
var _jsxRuntime = require("react/jsx-runtime");
|
|
9
|
+
/**
|
|
10
|
+
* NetworkOverridesButton.web — DOM twin of NetworkOverridesButton.tsx.
|
|
11
|
+
*
|
|
12
|
+
* Header button for the Overrides screen, and the always-visible "overrides
|
|
13
|
+
* are active" indicator. A self-subscribing LEAF, like the other live header
|
|
14
|
+
* pieces — the rule list changes on its own schedule (every hit bumps a
|
|
15
|
+
* counter) and the modal shell has no business re-rendering for it.
|
|
16
|
+
*
|
|
17
|
+
* The active tint is not decoration: a rule left enabled from yesterday makes
|
|
18
|
+
* the app behave wrongly in a way that looks exactly like a real bug, so the
|
|
19
|
+
* tool keeps saying so from the top level. (Native comment.)
|
|
20
|
+
*
|
|
21
|
+
* REUSED, not forked: `useOverrideRules` (platform-free).
|
|
22
|
+
*
|
|
23
|
+
* shared-ui RN chrome is replicated as DOM with provenance:
|
|
24
|
+
* - `macOSColors` — inlined verbatim subset from
|
|
25
|
+
* shared/src/ui/gameUI/constants/macOSDesignSystemColors.ts.
|
|
26
|
+
* - `FlaskConical` — inline lucide SVG (shared-ui icons are lucide
|
|
27
|
+
* re-exports).
|
|
28
|
+
*
|
|
29
|
+
* @platform React DOM Web
|
|
30
|
+
*/
|
|
31
|
+
|
|
32
|
+
/** macOSColors subset — shared/src/ui/gameUI/constants/macOSDesignSystemColors.ts, verbatim. */const macOSColors = {
|
|
33
|
+
background: {
|
|
34
|
+
base: "#0A0A0C",
|
|
35
|
+
hover: "#1D1D1F"
|
|
36
|
+
},
|
|
37
|
+
border: {
|
|
38
|
+
default: "#2D2D2F"
|
|
39
|
+
},
|
|
40
|
+
text: {
|
|
41
|
+
secondary: "#A1A1A6"
|
|
42
|
+
},
|
|
43
|
+
semantic: {
|
|
44
|
+
warning: "#FFEB3B",
|
|
45
|
+
warningBackground: "rgba(255, 235, 59, 0.15)"
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
const FlaskConical = ({
|
|
49
|
+
size = 14,
|
|
50
|
+
color
|
|
51
|
+
}) => /*#__PURE__*/(0, _jsxRuntime.jsxs)("svg", {
|
|
52
|
+
width: size,
|
|
53
|
+
height: size,
|
|
54
|
+
viewBox: "0 0 24 24",
|
|
55
|
+
fill: "none",
|
|
56
|
+
stroke: color,
|
|
57
|
+
strokeWidth: 2,
|
|
58
|
+
strokeLinecap: "round",
|
|
59
|
+
strokeLinejoin: "round",
|
|
60
|
+
style: {
|
|
61
|
+
flexShrink: 0,
|
|
62
|
+
display: "block"
|
|
63
|
+
},
|
|
64
|
+
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)("path", {
|
|
65
|
+
d: "M10 2v7.527a2 2 0 0 1-.211.896L4.72 20.55a1 1 0 0 0 .9 1.45h12.76a1 1 0 0 0 .9-1.45l-5.069-10.127A2 2 0 0 1 14 9.527V2"
|
|
66
|
+
}), /*#__PURE__*/(0, _jsxRuntime.jsx)("path", {
|
|
67
|
+
d: "M8.5 2h7"
|
|
68
|
+
}), /*#__PURE__*/(0, _jsxRuntime.jsx)("path", {
|
|
69
|
+
d: "M7 16h10"
|
|
70
|
+
})]
|
|
71
|
+
});
|
|
72
|
+
function NetworkOverridesButton({
|
|
73
|
+
onPress
|
|
74
|
+
}) {
|
|
75
|
+
const {
|
|
76
|
+
activeCount
|
|
77
|
+
} = (0, _useOverrideRules.useOverrideRules)();
|
|
78
|
+
const active = activeCount > 0;
|
|
79
|
+
return /*#__PURE__*/(0, _jsxRuntime.jsxs)("button", {
|
|
80
|
+
type: "button",
|
|
81
|
+
onClick: onPress,
|
|
82
|
+
style: {
|
|
83
|
+
...styles.button,
|
|
84
|
+
...(active ? styles.buttonActive : null)
|
|
85
|
+
},
|
|
86
|
+
"aria-label": active ? `Response overrides — ${activeCount} active` : "Response overrides",
|
|
87
|
+
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(FlaskConical, {
|
|
88
|
+
size: 14,
|
|
89
|
+
color: active ? macOSColors.semantic.warning : macOSColors.text.secondary
|
|
90
|
+
}), active ? /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
|
|
91
|
+
style: styles.badge,
|
|
92
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
|
|
93
|
+
style: styles.badgeText,
|
|
94
|
+
children: activeCount
|
|
95
|
+
})
|
|
96
|
+
}) : null]
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// Values mirror the native StyleSheet block 1:1: the header's standard 32×32
|
|
101
|
+
// action box; active fills the whole box the way the power toggle goes green,
|
|
102
|
+
// with the count badge INSIDE the box.
|
|
103
|
+
const styles = {
|
|
104
|
+
button: {
|
|
105
|
+
position: "relative",
|
|
106
|
+
display: "inline-flex",
|
|
107
|
+
width: 32,
|
|
108
|
+
height: 32,
|
|
109
|
+
boxSizing: "border-box",
|
|
110
|
+
borderRadius: 8,
|
|
111
|
+
alignItems: "center",
|
|
112
|
+
justifyContent: "center",
|
|
113
|
+
backgroundColor: macOSColors.background.hover,
|
|
114
|
+
border: `1px solid ${macOSColors.border.default}`,
|
|
115
|
+
cursor: "pointer",
|
|
116
|
+
padding: 0,
|
|
117
|
+
margin: 0
|
|
118
|
+
},
|
|
119
|
+
buttonActive: {
|
|
120
|
+
backgroundColor: macOSColors.semantic.warningBackground,
|
|
121
|
+
border: `1px solid ${macOSColors.semantic.warning}77`
|
|
122
|
+
},
|
|
123
|
+
badge: {
|
|
124
|
+
position: "absolute",
|
|
125
|
+
top: 1,
|
|
126
|
+
right: 1,
|
|
127
|
+
minWidth: 12,
|
|
128
|
+
height: 12,
|
|
129
|
+
borderRadius: 6,
|
|
130
|
+
padding: "0 3px",
|
|
131
|
+
boxSizing: "border-box",
|
|
132
|
+
display: "inline-flex",
|
|
133
|
+
alignItems: "center",
|
|
134
|
+
justifyContent: "center",
|
|
135
|
+
backgroundColor: macOSColors.semantic.warning
|
|
136
|
+
},
|
|
137
|
+
badgeText: {
|
|
138
|
+
fontSize: 8,
|
|
139
|
+
fontWeight: 800,
|
|
140
|
+
color: macOSColors.background.base,
|
|
141
|
+
lineHeight: 1
|
|
142
|
+
}
|
|
143
|
+
};
|
|
@@ -41,101 +41,111 @@ function toDraft(rule) {
|
|
|
41
41
|
return draft;
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
-
/** Plain-language names for statuses, so a row never reads as a bare number. */
|
|
45
|
-
const STATUS_NAMES = {
|
|
46
|
-
200: "Success",
|
|
47
|
-
201: "Created",
|
|
48
|
-
400: "Bad request",
|
|
49
|
-
401: "Unauthorized",
|
|
50
|
-
403: "Forbidden",
|
|
51
|
-
404: "Not found",
|
|
52
|
-
429: "Rate limited",
|
|
53
|
-
500: "Server error",
|
|
54
|
-
503: "Unavailable"
|
|
55
|
-
};
|
|
56
|
-
|
|
57
|
-
/** What the rule DOES, in the same words the editor uses. */
|
|
58
|
-
function outcomeLine(rule) {
|
|
59
|
-
const parts = [];
|
|
60
|
-
if (rule.kind === "respond") {
|
|
61
|
-
const status = rule.status ?? 200;
|
|
62
|
-
const name = STATUS_NAMES[status];
|
|
63
|
-
parts.push(name ? `${name} ${status}` : String(status));
|
|
64
|
-
} else if (rule.kind === "fail") {
|
|
65
|
-
parts.push(rule.failKind === "timeout" ? "Timeout" : "Offline");
|
|
66
|
-
} else {
|
|
67
|
-
parts.push("Real response");
|
|
68
|
-
}
|
|
69
|
-
if (rule.delayMs) parts.push(`${rule.delayMs / 1000}s`);
|
|
70
|
-
if (rule.alternate) parts.push("every other");else if (rule.times === 1) parts.push("once");else if (typeof rule.times === "number") parts.push(`${rule.times}×`);
|
|
71
|
-
return parts.join(" · ");
|
|
72
|
-
}
|
|
73
|
-
|
|
74
44
|
/**
|
|
75
45
|
* Where the rule applies — PATH only, not the whole URL.
|
|
76
46
|
*
|
|
77
47
|
* The host is the same for every rule in a typical app, so showing it pushes
|
|
78
|
-
* the part that differs off the end of the line.
|
|
48
|
+
* the part that differs off the end of the line. Same reasoning as the request
|
|
49
|
+
* row's `displayUrl`.
|
|
79
50
|
*/
|
|
80
|
-
function
|
|
81
|
-
const
|
|
82
|
-
let path = rule.urlPattern;
|
|
51
|
+
function patternPath(rule) {
|
|
52
|
+
const path = rule.urlPattern;
|
|
83
53
|
const schemeEnd = path.indexOf("://");
|
|
84
|
-
if (schemeEnd
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
54
|
+
if (schemeEnd === -1) return path;
|
|
55
|
+
const slash = path.indexOf("/", schemeEnd + 3);
|
|
56
|
+
return slash === -1 ? path.slice(schemeEnd + 3) : path.slice(slash);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/** Delay and lifetime, in the editor's own words. Empty for a plain rule. */
|
|
60
|
+
function extrasLine(rule) {
|
|
61
|
+
const parts = [];
|
|
62
|
+
if (rule.delayMs) parts.push(`${rule.delayMs / 1000}s delay`);
|
|
63
|
+
if (rule.alternate) parts.push("every other");else if (rule.times === 1) parts.push("once");else if (typeof rule.times === "number") parts.push(`${rule.times}×`);
|
|
64
|
+
return parts.join(" · ");
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/** The outcome's color, on the request list's status scale — a forced 500
|
|
68
|
+
* should look exactly like a real one. */
|
|
69
|
+
function ruleAccent(rule) {
|
|
70
|
+
if (rule.kind === "fail") return _sharedUi.macOSColors.semantic.error;
|
|
71
|
+
if (rule.kind === "delay") return _sharedUi.macOSColors.semantic.info;
|
|
72
|
+
const status = rule.status ?? 200;
|
|
73
|
+
if (status >= 200 && status < 300) return _sharedUi.macOSColors.semantic.success;
|
|
74
|
+
if (status >= 300 && status < 400) return _sharedUi.macOSColors.semantic.info;
|
|
75
|
+
return _sharedUi.macOSColors.semantic.error;
|
|
89
76
|
}
|
|
90
77
|
|
|
91
78
|
/**
|
|
92
|
-
* One rule
|
|
93
|
-
*
|
|
94
|
-
*
|
|
95
|
-
*
|
|
96
|
-
*
|
|
97
|
-
*
|
|
79
|
+
* One rule, in the request row's visual language — the same card, method badge,
|
|
80
|
+
* monospace path and status colors as `NetworkEventItemCompact`, so a rule
|
|
81
|
+
* reads as "the request it will produce". What's different is what a rule
|
|
82
|
+
* needs: a trash instead of the type chip and chevron, and the outcome color
|
|
83
|
+
* only floods the left edge while the rule is live. There's no per-rule
|
|
84
|
+
* on/off — a rule you don't want anymore gets deleted, and pausing everything
|
|
85
|
+
* is the master bar's job.
|
|
98
86
|
*/
|
|
99
87
|
function RuleRow({
|
|
100
88
|
rule,
|
|
101
89
|
spent,
|
|
102
|
-
|
|
103
|
-
|
|
90
|
+
onEdit,
|
|
91
|
+
onDelete
|
|
104
92
|
}) {
|
|
105
93
|
const live = rule.enabled && !spent;
|
|
106
|
-
const accent =
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
}]
|
|
121
|
-
})
|
|
122
|
-
}), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.TouchableOpacity, {
|
|
123
|
-
onPress: onEdit,
|
|
124
|
-
"sentry-label": "ignore edit override rule",
|
|
125
|
-
style: styles.rowBody,
|
|
94
|
+
const accent = ruleAccent(rule);
|
|
95
|
+
const extras = extrasLine(rule);
|
|
96
|
+
const method = rule.methods?.length ? rule.methods.join("/") : "ANY";
|
|
97
|
+
return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_sharedUi.DevToolsCard, {
|
|
98
|
+
onPress: onEdit,
|
|
99
|
+
style: styles.cardWrapper,
|
|
100
|
+
contentStyle: [styles.card, {
|
|
101
|
+
borderLeftColor: live ? accent : "transparent"
|
|
102
|
+
}],
|
|
103
|
+
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.MethodBadge, {
|
|
104
|
+
method: method,
|
|
105
|
+
size: "small"
|
|
106
|
+
}), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
|
107
|
+
style: styles.cardMiddle,
|
|
126
108
|
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
127
|
-
style: [styles.
|
|
128
|
-
numberOfLines:
|
|
129
|
-
children:
|
|
130
|
-
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
131
|
-
style: styles.
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
})]
|
|
109
|
+
style: [styles.urlText, !live && styles.urlTextOff],
|
|
110
|
+
numberOfLines: 2,
|
|
111
|
+
children: patternPath(rule)
|
|
112
|
+
}), extras ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
113
|
+
style: styles.extrasText,
|
|
114
|
+
children: extras
|
|
115
|
+
}) : null]
|
|
135
116
|
}), rule.hits > 0 ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
136
117
|
style: styles.rowHits,
|
|
137
118
|
children: rule.hits
|
|
138
|
-
}) : null
|
|
119
|
+
}) : null, rule.kind === "fail" ? /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
|
120
|
+
style: styles.failBadge,
|
|
121
|
+
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.AlertCircle, {
|
|
122
|
+
size: 10,
|
|
123
|
+
color: _sharedUi.macOSColors.semantic.error
|
|
124
|
+
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
125
|
+
style: styles.failText,
|
|
126
|
+
children: rule.failKind === "timeout" ? "TIMEOUT" : "OFFLINE"
|
|
127
|
+
})]
|
|
128
|
+
}) : /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
129
|
+
style: [styles.statusText, {
|
|
130
|
+
color: accent
|
|
131
|
+
}],
|
|
132
|
+
children: rule.kind === "delay" ? "PASS" : String(rule.status ?? 200)
|
|
133
|
+
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
|
|
134
|
+
onPress: onDelete,
|
|
135
|
+
"sentry-label": "ignore delete override rule",
|
|
136
|
+
accessibilityLabel: "Delete rule",
|
|
137
|
+
hitSlop: {
|
|
138
|
+
top: 8,
|
|
139
|
+
bottom: 8,
|
|
140
|
+
left: 4,
|
|
141
|
+
right: 4
|
|
142
|
+
},
|
|
143
|
+
style: styles.rowDelete,
|
|
144
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.Trash2, {
|
|
145
|
+
size: 13,
|
|
146
|
+
color: _sharedUi.macOSColors.text.muted
|
|
147
|
+
})
|
|
148
|
+
})]
|
|
139
149
|
});
|
|
140
150
|
}
|
|
141
151
|
/**
|
|
@@ -159,6 +169,7 @@ function OverridesBody({
|
|
|
159
169
|
onUpgradePress,
|
|
160
170
|
pendingDraft,
|
|
161
171
|
onPendingConsumed,
|
|
172
|
+
backHandlerRef,
|
|
162
173
|
applySafeAreaInset
|
|
163
174
|
}) {
|
|
164
175
|
const {
|
|
@@ -180,6 +191,20 @@ function OverridesBody({
|
|
|
180
191
|
_overrideRulesStore.overrideRulesStore.noteHealthyLaunch();
|
|
181
192
|
}, []);
|
|
182
193
|
|
|
194
|
+
// Back while editing means "back to the rule list", not "leave overrides" —
|
|
195
|
+
// see the prop's comment. Cleared on unmount so a hidden screen can't
|
|
196
|
+
// swallow back presses.
|
|
197
|
+
(0, _react.useEffect)(() => {
|
|
198
|
+
if (!backHandlerRef) return;
|
|
199
|
+
backHandlerRef.current = editing ? () => {
|
|
200
|
+
setEditing(null);
|
|
201
|
+
return true;
|
|
202
|
+
} : null;
|
|
203
|
+
return () => {
|
|
204
|
+
backHandlerRef.current = null;
|
|
205
|
+
};
|
|
206
|
+
}, [backHandlerRef, editing]);
|
|
207
|
+
|
|
183
208
|
/**
|
|
184
209
|
* Open a rule for editing, pulling its body over if this surface doesn't have
|
|
185
210
|
* it.
|
|
@@ -255,8 +280,12 @@ function OverridesBody({
|
|
|
255
280
|
};
|
|
256
281
|
const handleSave = () => {
|
|
257
282
|
if (!editing) return;
|
|
283
|
+
// Saving always arms the rule. With no per-rule toggle, this is the ONLY
|
|
284
|
+
// way back on for a rule the free tier disabled or that used itself up —
|
|
285
|
+
// and nobody edits a rule they want to stay inert.
|
|
258
286
|
const draft = {
|
|
259
287
|
...editing.draft,
|
|
288
|
+
enabled: true,
|
|
260
289
|
urlPattern: editing.draft.urlPattern.trim()
|
|
261
290
|
};
|
|
262
291
|
if (!draft.urlPattern) return;
|
|
@@ -264,21 +293,14 @@ function OverridesBody({
|
|
|
264
293
|
...draft,
|
|
265
294
|
id: editing.id
|
|
266
295
|
});
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
setEnabled(true);
|
|
274
|
-
}
|
|
296
|
+
enforceFreeTier(saved?.id ?? editing.id);
|
|
297
|
+
// Arm the master switch. Deliberately creating a rule and having it sit
|
|
298
|
+
// inert because overrides happen to be paused is the silent-failure this
|
|
299
|
+
// feature can least afford — the preset path already does this, and the
|
|
300
|
+
// manager disagreeing with it was just a gap.
|
|
301
|
+
setEnabled(true);
|
|
275
302
|
setEditing(null);
|
|
276
303
|
};
|
|
277
|
-
const handleToggle = rule => {
|
|
278
|
-
const next = !rule.enabled;
|
|
279
|
-
setRuleEnabled(rule.id, next);
|
|
280
|
-
if (next) enforceFreeTier(rule.id);
|
|
281
|
-
};
|
|
282
304
|
if (editing) {
|
|
283
305
|
return /*#__PURE__*/(0, _jsxRuntime.jsx)(_NetworkOverrideEditor.NetworkOverrideEditor, {
|
|
284
306
|
draft: editing.draft,
|
|
@@ -348,12 +370,12 @@ function OverridesBody({
|
|
|
348
370
|
children: [rules.map(rule => /*#__PURE__*/(0, _jsxRuntime.jsx)(RuleRow, {
|
|
349
371
|
rule: rule,
|
|
350
372
|
spent: isRuleSpent(rule),
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
}, rule.id)), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
373
|
+
onEdit: () => openRule(rule),
|
|
374
|
+
onDelete: () => removeRule(rule.id)
|
|
375
|
+
}, rule.id)), !isPro ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
354
376
|
style: styles.footNote,
|
|
355
|
-
children:
|
|
356
|
-
})]
|
|
377
|
+
children: "Free: one override at a time. Pro: up to 50."
|
|
378
|
+
}) : null]
|
|
357
379
|
})]
|
|
358
380
|
});
|
|
359
381
|
}
|
|
@@ -430,54 +452,66 @@ const styles = _reactNative.StyleSheet.create({
|
|
|
430
452
|
padding: 10,
|
|
431
453
|
gap: 6
|
|
432
454
|
},
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
paddingVertical: 10,
|
|
439
|
-
borderRadius: 6,
|
|
440
|
-
borderWidth: 1,
|
|
441
|
-
borderColor: _sharedUi.macOSColors.border.default,
|
|
442
|
-
backgroundColor: _sharedUi.macOSColors.background.card
|
|
455
|
+
// The list already spaces rows via `listContent` gap — zero out the card's
|
|
456
|
+
// own margins so the two don't stack.
|
|
457
|
+
cardWrapper: {
|
|
458
|
+
marginHorizontal: 0,
|
|
459
|
+
marginVertical: 0
|
|
443
460
|
},
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
height: 22,
|
|
447
|
-
borderRadius: 11,
|
|
448
|
-
borderWidth: 1,
|
|
449
|
-
borderColor: _sharedUi.macOSColors.border.default,
|
|
461
|
+
card: {
|
|
462
|
+
flexDirection: "row",
|
|
450
463
|
alignItems: "center",
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
width: 8,
|
|
455
|
-
height: 8,
|
|
456
|
-
borderRadius: 4
|
|
464
|
+
gap: 8,
|
|
465
|
+
borderLeftWidth: 3,
|
|
466
|
+
borderLeftColor: "transparent"
|
|
457
467
|
},
|
|
458
|
-
|
|
468
|
+
cardMiddle: {
|
|
459
469
|
flex: 1
|
|
460
470
|
},
|
|
461
|
-
|
|
471
|
+
// Same type as the request row's URL.
|
|
472
|
+
urlText: {
|
|
462
473
|
fontSize: 12,
|
|
463
|
-
|
|
464
|
-
|
|
474
|
+
color: _sharedUi.macOSColors.text.primary,
|
|
475
|
+
lineHeight: 16,
|
|
476
|
+
fontFamily: "monospace"
|
|
465
477
|
},
|
|
466
|
-
|
|
478
|
+
urlTextOff: {
|
|
467
479
|
color: _sharedUi.macOSColors.text.muted
|
|
468
480
|
},
|
|
469
|
-
|
|
481
|
+
extrasText: {
|
|
470
482
|
fontSize: 10,
|
|
471
|
-
fontFamily: "monospace",
|
|
472
483
|
color: _sharedUi.macOSColors.text.secondary,
|
|
473
484
|
marginTop: 2
|
|
474
485
|
},
|
|
486
|
+
statusText: {
|
|
487
|
+
fontSize: 11,
|
|
488
|
+
fontWeight: "600"
|
|
489
|
+
},
|
|
490
|
+
failBadge: {
|
|
491
|
+
flexDirection: "row",
|
|
492
|
+
alignItems: "center",
|
|
493
|
+
gap: 2,
|
|
494
|
+
paddingHorizontal: 4,
|
|
495
|
+
paddingVertical: 1,
|
|
496
|
+
backgroundColor: _sharedUi.macOSColors.semantic.error + "26",
|
|
497
|
+
borderRadius: 3
|
|
498
|
+
},
|
|
499
|
+
failText: {
|
|
500
|
+
fontSize: 10,
|
|
501
|
+
color: _sharedUi.macOSColors.semantic.error,
|
|
502
|
+
fontWeight: "600"
|
|
503
|
+
},
|
|
475
504
|
rowHits: {
|
|
476
505
|
fontSize: 11,
|
|
477
506
|
fontWeight: "700",
|
|
478
|
-
color: _sharedUi.macOSColors.semantic.warning
|
|
479
|
-
|
|
480
|
-
|
|
507
|
+
color: _sharedUi.macOSColors.semantic.warning
|
|
508
|
+
},
|
|
509
|
+
rowDelete: {
|
|
510
|
+
padding: 5,
|
|
511
|
+
borderRadius: 5,
|
|
512
|
+
borderWidth: 1,
|
|
513
|
+
borderColor: _sharedUi.macOSColors.border.default,
|
|
514
|
+
backgroundColor: _sharedUi.macOSColors.background.base
|
|
481
515
|
},
|
|
482
516
|
footNote: {
|
|
483
517
|
fontSize: 10,
|