@buoy-gg/impersonate 7.0.26 → 7.0.28

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.
@@ -9,7 +9,7 @@
9
9
 
10
10
  import React, { useCallback } from "react";
11
11
  import { View, Text, TouchableOpacity, StyleSheet, FlatList } from "react-native";
12
- import { buoyColors, Clock, Trash2, useRelativeTime } from "@buoy-gg/shared-ui";
12
+ import { night, Clock, Trash2, useRelativeTime } from "@buoy-gg/shared-ui";
13
13
  import { UserCard } from "./UserCard";
14
14
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
15
15
  /** Wrapper to use the useRelativeTime hook per history item */
@@ -60,7 +60,7 @@ export function ImpersonateHistoryList({
60
60
  style: styles.emptyIcon,
61
61
  children: /*#__PURE__*/_jsx(Clock, {
62
62
  size: 28,
63
- color: buoyColors.textMuted
63
+ color: night.color.textTertiary
64
64
  })
65
65
  }), /*#__PURE__*/_jsx(Text, {
66
66
  style: styles.emptyTitle,
@@ -92,7 +92,7 @@ export function ImpersonateHistoryList({
92
92
  activeOpacity: 0.7,
93
93
  children: /*#__PURE__*/_jsx(Trash2, {
94
94
  size: 12,
95
- color: buoyColors.textMuted
95
+ color: night.color.textTertiary
96
96
  })
97
97
  })]
98
98
  }), /*#__PURE__*/_jsx(FlatList, {
@@ -121,12 +121,12 @@ const styles = StyleSheet.create({
121
121
  headerTitle: {
122
122
  fontSize: 12,
123
123
  fontWeight: "600",
124
- color: buoyColors.textMuted,
124
+ color: night.color.textTertiary,
125
125
  textTransform: "uppercase",
126
126
  letterSpacing: 0.5
127
127
  },
128
128
  headerBadge: {
129
- backgroundColor: buoyColors.hover,
129
+ backgroundColor: night.color.surfaceElevated,
130
130
  paddingHorizontal: 6,
131
131
  paddingVertical: 2,
132
132
  borderRadius: 4
@@ -134,7 +134,7 @@ const styles = StyleSheet.create({
134
134
  headerBadgeText: {
135
135
  fontSize: 10,
136
136
  fontWeight: "600",
137
- color: buoyColors.textMuted
137
+ color: night.color.textTertiary
138
138
  },
139
139
  headerSpacer: {
140
140
  flex: 1
@@ -144,7 +144,7 @@ const styles = StyleSheet.create({
144
144
  height: 24,
145
145
  alignItems: "center",
146
146
  justifyContent: "center",
147
- backgroundColor: buoyColors.hover,
147
+ backgroundColor: night.color.surfaceElevated,
148
148
  borderRadius: 4
149
149
  },
150
150
  listContent: {
@@ -164,7 +164,7 @@ const styles = StyleSheet.create({
164
164
  width: 56,
165
165
  height: 56,
166
166
  borderRadius: 28,
167
- backgroundColor: buoyColors.hover,
167
+ backgroundColor: night.color.surfaceElevated,
168
168
  alignItems: "center",
169
169
  justifyContent: "center",
170
170
  marginBottom: 16
@@ -172,12 +172,12 @@ const styles = StyleSheet.create({
172
172
  emptyTitle: {
173
173
  fontSize: 16,
174
174
  fontWeight: "600",
175
- color: buoyColors.text,
175
+ color: night.color.text,
176
176
  marginBottom: 6
177
177
  },
178
178
  emptyDescription: {
179
179
  fontSize: 14,
180
- color: buoyColors.textSecondary,
180
+ color: night.color.textSecondary,
181
181
  textAlign: "center"
182
182
  }
183
183
  });
@@ -9,7 +9,7 @@
9
9
 
10
10
  import React, { useState, useCallback, useRef, useEffect } from "react";
11
11
  import { View, StyleSheet, TouchableOpacity, TextInput } from "react-native";
12
- import { JsModal as JsModalBase, TabSelector, ModalHeader, buoyColors, macOSColors, Search, X, TickProvider } from "@buoy-gg/shared-ui";
12
+ import { JsModal as JsModalBase, TabSelector, ModalHeader, buoyColors, night, Search, X, TickProvider } from "@buoy-gg/shared-ui";
13
13
  import { useImpersonate } from "../hooks/useImpersonate";
14
14
  import { useAutoClearReactQuery } from "../hooks/useAutoClearReactQuery";
15
15
  import { useAutoClearRedux } from "../hooks/useAutoClearRedux";
@@ -170,13 +170,13 @@ export function ImpersonateModal({
170
170
  style: styles.headerSearchContainer,
171
171
  children: [/*#__PURE__*/_jsx(Search, {
172
172
  size: 14,
173
- color: macOSColors.text.secondary
173
+ color: night.color.textSecondary
174
174
  }), /*#__PURE__*/_jsx(TextInput, {
175
175
  ref: searchInputRef,
176
176
  testID: "buoy-impersonate-search-input",
177
177
  style: styles.headerSearchInput,
178
178
  placeholder: "Search by email, name, or ID...",
179
- placeholderTextColor: macOSColors.text.muted,
179
+ placeholderTextColor: night.color.placeholder,
180
180
  value: searchText,
181
181
  onChangeText: handleSearchTextChange,
182
182
  onSubmitEditing: handleSubmitSearch,
@@ -192,14 +192,14 @@ export function ImpersonateModal({
192
192
  style: styles.headerSearchClear,
193
193
  children: /*#__PURE__*/_jsx(X, {
194
194
  size: 14,
195
- color: macOSColors.text.secondary
195
+ color: night.color.textSecondary
196
196
  })
197
197
  }) : /*#__PURE__*/_jsx(TouchableOpacity, {
198
198
  onPress: () => setIsSearchActive(false),
199
199
  style: styles.headerSearchClear,
200
200
  children: /*#__PURE__*/_jsx(X, {
201
201
  size: 14,
202
- color: macOSColors.text.muted
202
+ color: night.color.textTertiary
203
203
  })
204
204
  })]
205
205
  }) : /*#__PURE__*/_jsx(TabSelector, {
@@ -214,7 +214,7 @@ export function ImpersonateModal({
214
214
  style: styles.headerActionButton,
215
215
  children: /*#__PURE__*/_jsx(Search, {
216
216
  size: 14,
217
- color: macOSColors.text.secondary
217
+ color: night.color.textSecondary
218
218
  })
219
219
  })
220
220
  })]
@@ -300,7 +300,9 @@ const styles = StyleSheet.create({
300
300
  inlineRoot: {
301
301
  flex: 1,
302
302
  minHeight: 0,
303
- backgroundColor: buoyColors.base
303
+ // Transparent so the desktop workbench's hoisted sky (one field spanning
304
+ // sidebar + panel) shows through — the shell paints its base beneath it.
305
+ backgroundColor: "transparent"
304
306
  },
305
307
  inlineHeader: {
306
308
  paddingHorizontal: 12,
@@ -315,10 +317,10 @@ const styles = StyleSheet.create({
315
317
  headerSearchContainer: {
316
318
  flexDirection: "row",
317
319
  alignItems: "center",
318
- backgroundColor: macOSColors.background.input,
320
+ backgroundColor: night.color.surfaceElevated,
319
321
  borderRadius: 6,
320
322
  borderWidth: 1,
321
- borderColor: macOSColors.border.input,
323
+ borderColor: night.color.border,
322
324
  paddingHorizontal: 12,
323
325
  paddingVertical: 8,
324
326
  marginTop: 8,
@@ -327,7 +329,7 @@ const styles = StyleSheet.create({
327
329
  },
328
330
  headerSearchInput: {
329
331
  flex: 1,
330
- color: macOSColors.text.primary,
332
+ color: night.color.text,
331
333
  fontSize: 13,
332
334
  marginLeft: 6,
333
335
  paddingVertical: 2
@@ -340,7 +342,7 @@ const styles = StyleSheet.create({
340
342
  width: 28,
341
343
  height: 28,
342
344
  borderRadius: 6,
343
- backgroundColor: macOSColors.background.hover,
345
+ backgroundColor: night.color.buttonSurface,
344
346
  justifyContent: "center",
345
347
  alignItems: "center"
346
348
  }
@@ -9,7 +9,7 @@
9
9
 
10
10
  import React from "react";
11
11
  import { View, Text, TouchableOpacity, StyleSheet } from "react-native";
12
- import { buoyColors, X } from "@buoy-gg/shared-ui";
12
+ import { buoyColors, night, X } from "@buoy-gg/shared-ui";
13
13
  import { UserAvatar } from "./UserAvatar";
14
14
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
15
15
  export function ImpersonateStatusBar({
@@ -48,7 +48,7 @@ export function ImpersonateStatusBar({
48
48
  activeOpacity: 0.7,
49
49
  children: [/*#__PURE__*/_jsx(X, {
50
50
  size: 12,
51
- color: buoyColors.error
51
+ color: night.color.danger
52
52
  }), /*#__PURE__*/_jsx(Text, {
53
53
  style: styles.stopButtonText,
54
54
  children: "Stop"
@@ -82,7 +82,7 @@ const styles = StyleSheet.create({
82
82
  userName: {
83
83
  fontSize: 14,
84
84
  fontWeight: "600",
85
- color: buoyColors.text
85
+ color: night.color.text
86
86
  },
87
87
  statusPill: {
88
88
  flexDirection: "row",
@@ -112,14 +112,14 @@ const styles = StyleSheet.create({
112
112
  gap: 4,
113
113
  paddingHorizontal: 12,
114
114
  paddingVertical: 6,
115
- backgroundColor: buoyColors.error + "15",
115
+ backgroundColor: night.color.dangerSoft,
116
116
  borderRadius: 6,
117
117
  borderWidth: 1,
118
- borderColor: buoyColors.error + "30"
118
+ borderColor: night.color.danger + "30"
119
119
  },
120
120
  stopButtonText: {
121
121
  fontSize: 12,
122
122
  fontWeight: "600",
123
- color: buoyColors.error
123
+ color: night.color.danger
124
124
  }
125
125
  });
@@ -9,7 +9,7 @@
9
9
 
10
10
  import React, { useMemo } from "react";
11
11
  import { View, Text, StyleSheet } from "react-native";
12
- import { buoyColors } from "@buoy-gg/shared-ui";
12
+ import { buoyColors, night } from "@buoy-gg/shared-ui";
13
13
 
14
14
  // Avatar background colors - deterministic based on user ID
15
15
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
@@ -132,7 +132,7 @@ const styles = StyleSheet.create({
132
132
  position: "absolute",
133
133
  backgroundColor: buoyColors.success,
134
134
  borderWidth: 2,
135
- borderColor: buoyColors.card
135
+ borderColor: night.color.surface
136
136
  }
137
137
  });
138
138
 
@@ -9,7 +9,7 @@
9
9
 
10
10
  import React from "react";
11
11
  import { View, Text, TouchableOpacity, StyleSheet } from "react-native";
12
- import { buoyColors, Play, X, PowerToggleButton } from "@buoy-gg/shared-ui";
12
+ import { buoyColors, night, Play, X, PowerToggleButton } from "@buoy-gg/shared-ui";
13
13
  import { UserAvatar } from "./UserAvatar";
14
14
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
15
15
  export function UserCard({
@@ -77,7 +77,7 @@ export function UserCard({
77
77
  activeOpacity: 0.7,
78
78
  children: /*#__PURE__*/_jsx(Play, {
79
79
  size: 14,
80
- color: "#FFFFFF"
80
+ color: night.color.onAccent
81
81
  })
82
82
  }), showRemoveButton && onRemove && !isActive && /*#__PURE__*/_jsx(TouchableOpacity, {
83
83
  style: styles.removeButton,
@@ -85,7 +85,7 @@ export function UserCard({
85
85
  activeOpacity: 0.7,
86
86
  children: /*#__PURE__*/_jsx(X, {
87
87
  size: 12,
88
- color: buoyColors.textMuted
88
+ color: night.color.textTertiary
89
89
  })
90
90
  })]
91
91
  }), lastUsedTime && /*#__PURE__*/_jsx(Text, {
@@ -98,10 +98,10 @@ const styles = StyleSheet.create({
98
98
  container: {
99
99
  flexDirection: "row",
100
100
  alignItems: "center",
101
- backgroundColor: buoyColors.card,
101
+ backgroundColor: night.color.surface,
102
102
  borderRadius: 10,
103
103
  borderWidth: 1,
104
- borderColor: buoyColors.border,
104
+ borderColor: night.color.border,
105
105
  padding: 12,
106
106
  gap: 12
107
107
  },
@@ -129,14 +129,14 @@ const styles = StyleSheet.create({
129
129
  name: {
130
130
  fontSize: 15,
131
131
  fontWeight: "600",
132
- color: buoyColors.text,
132
+ color: night.color.text,
133
133
  flexShrink: 1
134
134
  },
135
135
  activeName: {
136
136
  color: buoyColors.success
137
137
  },
138
138
  roleBadge: {
139
- backgroundColor: buoyColors.hover,
139
+ backgroundColor: night.color.surfaceElevated,
140
140
  paddingHorizontal: 6,
141
141
  paddingVertical: 2,
142
142
  borderRadius: 4
@@ -144,12 +144,12 @@ const styles = StyleSheet.create({
144
144
  roleBadgeText: {
145
145
  fontSize: 9,
146
146
  fontWeight: "700",
147
- color: buoyColors.textMuted,
147
+ color: night.color.textTertiary,
148
148
  letterSpacing: 0.5
149
149
  },
150
150
  email: {
151
151
  fontSize: 13,
152
- color: buoyColors.textSecondary,
152
+ color: night.color.textSecondary,
153
153
  marginBottom: 4
154
154
  },
155
155
  metadataRow: {
@@ -159,7 +159,7 @@ const styles = StyleSheet.create({
159
159
  },
160
160
  userId: {
161
161
  fontSize: 11,
162
- color: buoyColors.textMuted,
162
+ color: night.color.textTertiary,
163
163
  fontFamily: "monospace"
164
164
  },
165
165
  lastUsed: {
@@ -167,7 +167,7 @@ const styles = StyleSheet.create({
167
167
  bottom: 8,
168
168
  right: 10,
169
169
  fontSize: 10,
170
- color: buoyColors.textMuted
170
+ color: night.color.textTertiary
171
171
  },
172
172
  actions: {
173
173
  flexDirection: "row",
@@ -179,7 +179,7 @@ const styles = StyleSheet.create({
179
179
  width: 36,
180
180
  height: 36,
181
181
  borderRadius: 8,
182
- backgroundColor: buoyColors.primary,
182
+ backgroundColor: night.color.accent,
183
183
  alignItems: "center",
184
184
  justifyContent: "center"
185
185
  },
@@ -187,9 +187,9 @@ const styles = StyleSheet.create({
187
187
  width: 28,
188
188
  height: 28,
189
189
  borderRadius: 6,
190
- backgroundColor: buoyColors.hover,
190
+ backgroundColor: night.color.surfaceElevated,
191
191
  borderWidth: 1,
192
- borderColor: buoyColors.border,
192
+ borderColor: night.color.border,
193
193
  alignItems: "center",
194
194
  justifyContent: "center"
195
195
  }
@@ -10,7 +10,7 @@
10
10
 
11
11
  import React, { useCallback } from "react";
12
12
  import { View, Text, StyleSheet, FlatList, ActivityIndicator } from "react-native";
13
- import { SectionHeader, EmptyState, buoyColors, Search, AlertTriangle, Users } from "@buoy-gg/shared-ui";
13
+ import { SectionHeader, EmptyState, night, Search, AlertTriangle, Users } from "@buoy-gg/shared-ui";
14
14
  import { UserCard } from "./UserCard";
15
15
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
16
16
  export function UserSearchView({
@@ -42,7 +42,7 @@ export function UserSearchView({
42
42
  style: styles.warningCard,
43
43
  children: [/*#__PURE__*/_jsx(AlertTriangle, {
44
44
  size: 18,
45
- color: buoyColors.warning
45
+ color: night.color.warning
46
46
  }), /*#__PURE__*/_jsxs(View, {
47
47
  style: styles.warningContent,
48
48
  children: [/*#__PURE__*/_jsx(Text, {
@@ -58,7 +58,7 @@ export function UserSearchView({
58
58
  style: styles.loadingContainer,
59
59
  children: [/*#__PURE__*/_jsx(ActivityIndicator, {
60
60
  size: "small",
61
- color: buoyColors.primary
61
+ color: night.color.accent
62
62
  }), /*#__PURE__*/_jsx(Text, {
63
63
  style: styles.loadingText,
64
64
  children: "Searching users..."
@@ -69,7 +69,7 @@ export function UserSearchView({
69
69
  style: styles.errorCard,
70
70
  children: [/*#__PURE__*/_jsx(AlertTriangle, {
71
71
  size: 16,
72
- color: buoyColors.error
72
+ color: night.color.danger
73
73
  }), /*#__PURE__*/_jsx(Text, {
74
74
  style: styles.errorText,
75
75
  children: searchError
@@ -99,7 +99,7 @@ export function UserSearchView({
99
99
  style: styles.emptyStateIcon,
100
100
  children: /*#__PURE__*/_jsx(Users, {
101
101
  size: 28,
102
- color: buoyColors.textMuted
102
+ color: night.color.textTertiary
103
103
  })
104
104
  }), /*#__PURE__*/_jsx(Text, {
105
105
  style: styles.emptyStateTitle,
@@ -136,7 +136,7 @@ const styles = StyleSheet.create({
136
136
  },
137
137
  loadingText: {
138
138
  fontSize: 13,
139
- color: buoyColors.textSecondary
139
+ color: night.color.textSecondary
140
140
  },
141
141
  resultsSection: {
142
142
  flex: 1,
@@ -152,10 +152,10 @@ const styles = StyleSheet.create({
152
152
  flexDirection: "row",
153
153
  alignItems: "flex-start",
154
154
  gap: 12,
155
- backgroundColor: buoyColors.warning + "12",
155
+ backgroundColor: night.color.warningSoft,
156
156
  borderRadius: 10,
157
157
  borderWidth: 1,
158
- borderColor: buoyColors.warning + "25",
158
+ borderColor: night.color.warning + "25",
159
159
  padding: 14
160
160
  },
161
161
  warningContent: {
@@ -164,28 +164,28 @@ const styles = StyleSheet.create({
164
164
  warningTitle: {
165
165
  fontSize: 14,
166
166
  fontWeight: "600",
167
- color: buoyColors.warning,
167
+ color: night.color.warning,
168
168
  marginBottom: 4
169
169
  },
170
170
  warningText: {
171
171
  fontSize: 13,
172
- color: buoyColors.textSecondary,
172
+ color: night.color.textSecondary,
173
173
  lineHeight: 18
174
174
  },
175
175
  errorCard: {
176
176
  flexDirection: "row",
177
177
  alignItems: "center",
178
178
  gap: 10,
179
- backgroundColor: buoyColors.error + "12",
179
+ backgroundColor: night.color.dangerSoft,
180
180
  borderRadius: 10,
181
181
  borderWidth: 1,
182
- borderColor: buoyColors.error + "25",
182
+ borderColor: night.color.danger + "25",
183
183
  padding: 12
184
184
  },
185
185
  errorText: {
186
186
  flex: 1,
187
187
  fontSize: 13,
188
- color: buoyColors.error
188
+ color: night.color.danger
189
189
  },
190
190
  emptyStateContainer: {
191
191
  flex: 1,
@@ -198,7 +198,7 @@ const styles = StyleSheet.create({
198
198
  width: 56,
199
199
  height: 56,
200
200
  borderRadius: 28,
201
- backgroundColor: buoyColors.hover,
201
+ backgroundColor: night.color.surfaceElevated,
202
202
  alignItems: "center",
203
203
  justifyContent: "center",
204
204
  marginBottom: 16
@@ -206,17 +206,17 @@ const styles = StyleSheet.create({
206
206
  emptyStateTitle: {
207
207
  fontSize: 16,
208
208
  fontWeight: "600",
209
- color: buoyColors.text,
209
+ color: night.color.text,
210
210
  marginBottom: 6
211
211
  },
212
212
  emptyStateDescription: {
213
213
  fontSize: 14,
214
- color: buoyColors.textSecondary,
214
+ color: night.color.textSecondary,
215
215
  textAlign: "center",
216
216
  marginBottom: 8
217
217
  },
218
218
  emptyStateHint: {
219
219
  fontSize: 12,
220
- color: buoyColors.textMuted
220
+ color: night.color.textTertiary
221
221
  }
222
222
  });
@@ -47,11 +47,33 @@ const DEFAULT_IGNORE_PATTERNS = [/\/symbolicate$/, /\/logs$/, /\/debugger-proxy/
47
47
  * listener.stopListening();
48
48
  * ```
49
49
  */
50
+ /**
51
+ * Cooperating-interceptor protocol with @buoy-gg/network: its interceptors
52
+ * carry `__buoy*` marker properties, and it re-installs itself whenever the
53
+ * marker disappears from the live global (that's how it survives being
54
+ * clobbered by Expo/DevTools re-assigning fetch). We wrap its functions, so
55
+ * the markers must ride along on our wrappers — otherwise the network tool
56
+ * would conclude it lost interception and stack a fresh patch on every check.
57
+ */
58
+ function carryBuoyMarkers(wrapper, wrapped) {
59
+ for (const key of Object.keys(wrapped)) {
60
+ if (key.startsWith("__buoy")) {
61
+ wrapper[key] = wrapped[key];
62
+ }
63
+ }
64
+ }
50
65
  class ImpersonateListener {
51
66
  isListeningFlag = false;
52
67
 
53
68
  // Store original methods - MUST be captured before other tools patch
54
69
 
70
+ /**
71
+ * The wrappers this instance installed, for identity checks — stopListening
72
+ * only restores globals that are still literally ours (see there).
73
+ */
74
+ patchedFetch = null;
75
+ patchedXHROpen = null;
76
+ patchedXHRSend = null;
55
77
  constructor() {
56
78
  // Initialize with current fetch - will be re-captured in startListening
57
79
  this.originalFetch = globalThis.fetch.bind(globalThis);
@@ -136,15 +158,24 @@ class ImpersonateListener {
136
158
  // CRITICAL: Re-capture fetch/XHR NOW, not at construction time
137
159
  // This ensures we patch OVER any existing interceptors (like @buoy-gg/network)
138
160
  // so our modifications are visible to them
139
- this.originalFetch = globalThis.fetch.bind(globalThis);
140
- this.originalXHROpen = XMLHttpRequest.prototype.open;
141
- this.originalXHRSend = XMLHttpRequest.prototype.send;
161
+ //
162
+ // Keep the UNBOUND functions too: @buoy-gg/network stamps `__buoy*` marker
163
+ // properties on its interceptors and re-installs when the marker vanishes
164
+ // from the live global — and `.bind()` drops own properties, so the
165
+ // markers must be read off the unbound originals and carried forward onto
166
+ // our wrappers (see below).
167
+ const wrappedFetch = globalThis.fetch;
168
+ const wrappedXHROpen = XMLHttpRequest.prototype.open;
169
+ const wrappedXHRSend = XMLHttpRequest.prototype.send;
170
+ this.originalFetch = wrappedFetch.bind(globalThis);
171
+ this.originalXHROpen = wrappedXHROpen;
172
+ this.originalXHRSend = wrappedXHRSend;
142
173
  const self = this;
143
174
 
144
175
  // =======================================================================
145
176
  // PATCH FETCH
146
177
  // =======================================================================
147
- globalThis.fetch = async function (input, init) {
178
+ const patchedFetch = async function (input, init) {
148
179
  const url = self.extractUrl(input);
149
180
  if (self.shouldInjectHeader(url)) {
150
181
  // Create new headers with impersonation header added
@@ -162,13 +193,16 @@ class ImpersonateListener {
162
193
  // Not injecting - call original fetch as-is
163
194
  return self.originalFetch(input, init);
164
195
  };
196
+ carryBuoyMarkers(patchedFetch, wrappedFetch);
197
+ this.patchedFetch = patchedFetch;
198
+ globalThis.fetch = this.patchedFetch;
165
199
 
166
200
  // =======================================================================
167
201
  // PATCH XMLHttpRequest
168
202
  // =======================================================================
169
203
 
170
204
  // Patch open() to store the URL for later use in send()
171
- XMLHttpRequest.prototype.open = function (method, url, async = true, username, password) {
205
+ const patchedOpen = function (method, url, async = true, username, password) {
172
206
  const xhr = this;
173
207
  xhr._impersonateUrl = typeof url === "string" ? url : url.href;
174
208
  const urlStr = typeof url === "string" ? url : url.toString();
@@ -176,7 +210,7 @@ class ImpersonateListener {
176
210
  };
177
211
 
178
212
  // Patch send() to inject header before sending
179
- XMLHttpRequest.prototype.send = function (body) {
213
+ const patchedSend = function (body) {
180
214
  const xhr = this;
181
215
  if (xhr._impersonateUrl && self.shouldInjectHeader(xhr._impersonateUrl)) {
182
216
  // Inject the impersonation header
@@ -184,6 +218,12 @@ class ImpersonateListener {
184
218
  }
185
219
  return self.originalXHRSend.call(this, body);
186
220
  };
221
+ carryBuoyMarkers(patchedOpen, wrappedXHROpen);
222
+ carryBuoyMarkers(patchedSend, wrappedXHRSend);
223
+ this.patchedXHROpen = patchedOpen;
224
+ this.patchedXHRSend = patchedSend;
225
+ XMLHttpRequest.prototype.open = this.patchedXHROpen;
226
+ XMLHttpRequest.prototype.send = this.patchedXHRSend;
187
227
  this.isListeningFlag = true;
188
228
  }
189
229
 
@@ -198,9 +238,24 @@ class ImpersonateListener {
198
238
  if (!this.isListeningFlag) {
199
239
  return;
200
240
  }
201
- globalThis.fetch = this.originalFetch;
202
- XMLHttpRequest.prototype.open = this.originalXHROpen;
203
- XMLHttpRequest.prototype.send = this.originalXHRSend;
241
+
242
+ // Restore ONLY what is still literally ours: if another interceptor
243
+ // patched after us (the network tool re-asserting itself, a debugger),
244
+ // assigning our saved originals would silently wipe its patch. Leaving our
245
+ // wrapper in a foreign chain is safe — with no userId configured it is a
246
+ // pure pass-through.
247
+ if (this.patchedFetch && globalThis.fetch === this.patchedFetch) {
248
+ globalThis.fetch = this.originalFetch;
249
+ }
250
+ if (this.patchedXHROpen && XMLHttpRequest.prototype.open === this.patchedXHROpen) {
251
+ XMLHttpRequest.prototype.open = this.originalXHROpen;
252
+ }
253
+ if (this.patchedXHRSend && XMLHttpRequest.prototype.send === this.patchedXHRSend) {
254
+ XMLHttpRequest.prototype.send = this.originalXHRSend;
255
+ }
256
+ this.patchedFetch = null;
257
+ this.patchedXHROpen = null;
258
+ this.patchedXHRSend = null;
204
259
  this.isListeningFlag = false;
205
260
  }
206
261
 
@@ -1 +1 @@
1
- {"version":3,"file":"DataNukeSettings.d.ts","sourceRoot":"","sources":["../../../../src/impersonate/components/DataNukeSettings.tsx"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAuC,MAAM,OAAO,CAAC;AAyB5D,OAAO,KAAK,EAAE,gBAAgB,IAAI,oBAAoB,EAAE,MAAM,UAAU,CAAC;AAWzE;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,oDAAoD;IACpD,UAAU,EAAE,OAAO,CAAC;IACpB,8CAA8C;IAC9C,KAAK,EAAE,OAAO,CAAC;IACf,qDAAqD;IACrD,YAAY,EAAE,OAAO,CAAC;IACtB,6CAA6C;IAC7C,IAAI,EAAE,OAAO,CAAC;CACf;AAED,MAAM,WAAW,qBAAqB;IACpC,yBAAyB;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,iCAAiC;IACjC,QAAQ,EAAE,oBAAoB,CAAC;IAC/B,0CAA0C;IAC1C,UAAU,EAAE,OAAO,CAAC;IACpB,kCAAkC;IAClC,MAAM,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,oBAAoB,EAAE,UAAU,EAAE,OAAO,KAAK,IAAI,CAAC;IACzF,2EAA2E;IAC3E,kBAAkB,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IAC5C,4CAA4C;IAC5C,eAAe,CAAC,EAAE,eAAe,CAAC;CACnC;AAgFD,wBAAgB,gBAAgB,CAAC,EAC/B,SAAS,EACT,QAAQ,EACR,UAAU,EACV,MAAM,EACN,kBAAkB,EAClB,eAAe,GAChB,EAAE,qBAAqB,qBAkVvB"}
1
+ {"version":3,"file":"DataNukeSettings.d.ts","sourceRoot":"","sources":["../../../../src/impersonate/components/DataNukeSettings.tsx"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAuC,MAAM,OAAO,CAAC;AA0B5D,OAAO,KAAK,EAAE,gBAAgB,IAAI,oBAAoB,EAAE,MAAM,UAAU,CAAC;AAWzE;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,oDAAoD;IACpD,UAAU,EAAE,OAAO,CAAC;IACpB,8CAA8C;IAC9C,KAAK,EAAE,OAAO,CAAC;IACf,qDAAqD;IACrD,YAAY,EAAE,OAAO,CAAC;IACtB,6CAA6C;IAC7C,IAAI,EAAE,OAAO,CAAC;CACf;AAED,MAAM,WAAW,qBAAqB;IACpC,yBAAyB;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,iCAAiC;IACjC,QAAQ,EAAE,oBAAoB,CAAC;IAC/B,0CAA0C;IAC1C,UAAU,EAAE,OAAO,CAAC;IACpB,kCAAkC;IAClC,MAAM,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,oBAAoB,EAAE,UAAU,EAAE,OAAO,KAAK,IAAI,CAAC;IACzF,2EAA2E;IAC3E,kBAAkB,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IAC5C,4CAA4C;IAC5C,eAAe,CAAC,EAAE,eAAe,CAAC;CACnC;AAgFD,wBAAgB,gBAAgB,CAAC,EAC/B,SAAS,EACT,QAAQ,EACR,UAAU,EACV,MAAM,EACN,kBAAkB,EAClB,eAAe,GAChB,EAAE,qBAAqB,qBAkVvB"}
@@ -6,39 +6,19 @@
6
6
  * as @buoy-gg/network's networkListener.
7
7
  */
8
8
  import type { ImpersonateListenerConfig } from "../types";
9
- /**
10
- * Impersonation header injector for network requests
11
- *
12
- * This class monkey-patches fetch and XMLHttpRequest to inject the
13
- * impersonation header on all outgoing requests when impersonation is active.
14
- *
15
- * @example
16
- * ```typescript
17
- * // Get the singleton instance
18
- * const listener = impersonateListener();
19
- *
20
- * // Configure impersonation
21
- * listener.setConfig({
22
- * headerKey: 'x-impersonate-user-id',
23
- * userId: '12345',
24
- * ignorePatterns: [/\/health/]
25
- * });
26
- *
27
- * // Start injecting headers
28
- * listener.startListening();
29
- *
30
- * // All fetch/XHR requests will now include the header
31
- *
32
- * // Stop injecting when done
33
- * listener.stopListening();
34
- * ```
35
- */
36
9
  declare class ImpersonateListener {
37
10
  private config;
38
11
  private isListeningFlag;
39
12
  private originalFetch;
40
13
  private originalXHROpen;
41
14
  private originalXHRSend;
15
+ /**
16
+ * The wrappers this instance installed, for identity checks — stopListening
17
+ * only restores globals that are still literally ours (see there).
18
+ */
19
+ private patchedFetch;
20
+ private patchedXHROpen;
21
+ private patchedXHRSend;
42
22
  constructor();
43
23
  /**
44
24
  * Update impersonation config without restarting listener
@@ -1 +1 @@
1
- {"version":3,"file":"impersonateListener.d.ts","sourceRoot":"","sources":["../../../../src/impersonate/utils/impersonateListener.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,UAAU,CAAC;AAwB1D;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,cAAM,mBAAmB;IACvB,OAAO,CAAC,MAAM,CAA4B;IAC1C,OAAO,CAAC,eAAe,CAAS;IAGhC,OAAO,CAAC,aAAa,CAAe;IACpC,OAAO,CAAC,eAAe,CAAuC;IAC9D,OAAO,CAAC,eAAe,CAAuC;;IAe9D;;;;;OAKG;IACH,SAAS,CAAC,OAAO,EAAE,OAAO,CAAC,yBAAyB,CAAC,GAAG,IAAI;IAY5D;;OAEG;IACH,SAAS,IAAI,yBAAyB;IAItC;;;;;;OAMG;IACH,OAAO,CAAC,kBAAkB;IAU1B;;OAEG;IACH,OAAO,CAAC,UAAU;IAWlB;;;;;OAKG;IACH,cAAc,IAAI,IAAI;IAkFtB;;;;;;OAMG;IACH,aAAa,IAAI,IAAI;IAYrB;;OAEG;IACH,IAAI,WAAW,IAAI,OAAO,CAEzB;IAED;;OAEG;IACH,IAAI,eAAe,IAAI,OAAO,CAE7B;CACF;AAQD;;GAEG;AACH,wBAAgB,mBAAmB,IAAI,mBAAmB,CAKzD;AAED;;GAEG;AACH,wBAAgB,wBAAwB,IAAI,IAAI,CAE/C;AAED;;GAEG;AACH,wBAAgB,uBAAuB,IAAI,IAAI,CAE9C;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,OAAO,CAAC,yBAAyB,CAAC,GACzC,IAAI,CAEN;AAED;;GAEG;AACH,wBAAgB,eAAe,IAAI,OAAO,CAEzC;AAED;;GAEG;AACH,wBAAgB,qBAAqB,IAAI,MAAM,GAAG,IAAI,CAErD"}
1
+ {"version":3,"file":"impersonateListener.d.ts","sourceRoot":"","sources":["../../../../src/impersonate/utils/impersonateListener.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,UAAU,CAAC;AAqE1D,cAAM,mBAAmB;IACvB,OAAO,CAAC,MAAM,CAA4B;IAC1C,OAAO,CAAC,eAAe,CAAS;IAGhC,OAAO,CAAC,aAAa,CAAe;IACpC,OAAO,CAAC,eAAe,CAAuC;IAC9D,OAAO,CAAC,eAAe,CAAuC;IAE9D;;;OAGG;IACH,OAAO,CAAC,YAAY,CAA6B;IACjD,OAAO,CAAC,cAAc,CAAqD;IAC3E,OAAO,CAAC,cAAc,CAAqD;;IAe3E;;;;;OAKG;IACH,SAAS,CAAC,OAAO,EAAE,OAAO,CAAC,yBAAyB,CAAC,GAAG,IAAI;IAY5D;;OAEG;IACH,SAAS,IAAI,yBAAyB;IAItC;;;;;;OAMG;IACH,OAAO,CAAC,kBAAkB;IAU1B;;OAEG;IACH,OAAO,CAAC,UAAU;IAWlB;;;;;OAKG;IACH,cAAc,IAAI,IAAI;IAsGtB;;;;;;OAMG;IACH,aAAa,IAAI,IAAI;IAgCrB;;OAEG;IACH,IAAI,WAAW,IAAI,OAAO,CAEzB;IAED;;OAEG;IACH,IAAI,eAAe,IAAI,OAAO,CAE7B;CACF;AAQD;;GAEG;AACH,wBAAgB,mBAAmB,IAAI,mBAAmB,CAKzD;AAED;;GAEG;AACH,wBAAgB,wBAAwB,IAAI,IAAI,CAE/C;AAED;;GAEG;AACH,wBAAgB,uBAAuB,IAAI,IAAI,CAE9C;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,OAAO,CAAC,yBAAyB,CAAC,GACzC,IAAI,CAEN;AAED;;GAEG;AACH,wBAAgB,eAAe,IAAI,OAAO,CAEzC;AAED;;GAEG;AACH,wBAAgB,qBAAqB,IAAI,MAAM,GAAG,IAAI,CAErD"}