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