@buoy-gg/impersonate 7.0.32 → 7.0.34
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/impersonate/components/DataNukeSettings.js +30 -71
- package/lib/commonjs/impersonate/components/ImpersonateHistoryList.js +8 -15
- package/lib/commonjs/impersonate/components/ImpersonateModal.js +23 -60
- package/lib/commonjs/sync/impersonateSyncAdapter.js +34 -1
- package/lib/module/impersonate/components/DataNukeSettings.js +32 -73
- package/lib/module/impersonate/components/ImpersonateHistoryList.js +9 -16
- package/lib/module/impersonate/components/ImpersonateModal.js +25 -62
- package/lib/module/sync/impersonateSyncAdapter.js +34 -1
- package/lib/typescript/impersonate/components/DataNukeSettings.d.ts.map +1 -1
- package/lib/typescript/impersonate/components/ImpersonateHistoryList.d.ts.map +1 -1
- package/lib/typescript/impersonate/components/ImpersonateModal.d.ts.map +1 -1
- package/lib/typescript/sync/impersonateSyncAdapter.d.ts +8 -2
- package/lib/typescript/sync/impersonateSyncAdapter.d.ts.map +1 -1
- package/package.json +2 -2
|
@@ -39,51 +39,40 @@ function ToggleRow({
|
|
|
39
39
|
dangerous,
|
|
40
40
|
detected
|
|
41
41
|
}) {
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
}), detected !== undefined && /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
|
52
|
-
style: [styles.detectedBadge, detected ? styles.detectedBadgeActive : styles.detectedBadgeInactive],
|
|
53
|
-
children: [detected ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.Check, {
|
|
54
|
-
size: 10,
|
|
55
|
-
color: _sharedUi.buoyColors.success
|
|
56
|
-
}) : /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.X, {
|
|
57
|
-
size: 10,
|
|
58
|
-
color: _sharedUi.night.color.textTertiary
|
|
59
|
-
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
60
|
-
style: [styles.detectedText, detected ? styles.detectedTextActive : styles.detectedTextInactive],
|
|
61
|
-
children: detected ? "Detected" : "Not Detected"
|
|
62
|
-
})]
|
|
63
|
-
}), recommended && detected !== false && /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
|
64
|
-
style: styles.recommendedBadge,
|
|
65
|
-
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.Zap, {
|
|
66
|
-
size: 10,
|
|
67
|
-
color: _sharedUi.night.color.accent
|
|
68
|
-
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
69
|
-
style: styles.recommendedText,
|
|
70
|
-
children: "Recommended"
|
|
71
|
-
})]
|
|
72
|
-
})]
|
|
42
|
+
const accessory = /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, {
|
|
43
|
+
children: [detected !== undefined && /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
|
44
|
+
style: [styles.detectedBadge, detected ? styles.detectedBadgeActive : styles.detectedBadgeInactive],
|
|
45
|
+
children: [detected ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.Check, {
|
|
46
|
+
size: 10,
|
|
47
|
+
color: _sharedUi.buoyColors.success
|
|
48
|
+
}) : /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.X, {
|
|
49
|
+
size: 10,
|
|
50
|
+
color: _sharedUi.night.color.textTertiary
|
|
73
51
|
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
74
|
-
style: styles.
|
|
75
|
-
children:
|
|
52
|
+
style: [styles.detectedText, detected ? styles.detectedTextActive : styles.detectedTextInactive],
|
|
53
|
+
children: detected ? "Detected" : "Not Detected"
|
|
54
|
+
})]
|
|
55
|
+
}), recommended && detected !== false && /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
|
56
|
+
style: styles.recommendedBadge,
|
|
57
|
+
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.Zap, {
|
|
58
|
+
size: 10,
|
|
59
|
+
color: _sharedUi.night.color.accent
|
|
60
|
+
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
61
|
+
style: styles.recommendedText,
|
|
62
|
+
children: "Recommended"
|
|
76
63
|
})]
|
|
77
|
-
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Switch, {
|
|
78
|
-
value: value,
|
|
79
|
-
onValueChange: onChange,
|
|
80
|
-
trackColor: {
|
|
81
|
-
false: _sharedUi.night.color.border,
|
|
82
|
-
true: dangerous ? _sharedUi.night.color.warning + "50" : _sharedUi.night.color.accent + "50"
|
|
83
|
-
},
|
|
84
|
-
thumbColor: value ? dangerous ? _sharedUi.night.color.warning : _sharedUi.night.color.accent : _sharedUi.night.color.knob
|
|
85
64
|
})]
|
|
86
65
|
});
|
|
66
|
+
return /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.ToggleRow, {
|
|
67
|
+
variant: "plain",
|
|
68
|
+
label: label,
|
|
69
|
+
description: description,
|
|
70
|
+
value: value,
|
|
71
|
+
onValueChange: onChange,
|
|
72
|
+
tone: dangerous ? "warning" : "accent",
|
|
73
|
+
emphasizeLabel: dangerous,
|
|
74
|
+
accessory: accessory
|
|
75
|
+
});
|
|
87
76
|
}
|
|
88
77
|
function DataNukeSettings({
|
|
89
78
|
headerKey,
|
|
@@ -560,31 +549,6 @@ const styles = _reactNative.StyleSheet.create({
|
|
|
560
549
|
color: _sharedUi.night.color.accent,
|
|
561
550
|
fontWeight: "500"
|
|
562
551
|
},
|
|
563
|
-
toggleRow: {
|
|
564
|
-
flexDirection: "row",
|
|
565
|
-
alignItems: "center",
|
|
566
|
-
justifyContent: "space-between",
|
|
567
|
-
paddingVertical: 12,
|
|
568
|
-
paddingHorizontal: 12
|
|
569
|
-
},
|
|
570
|
-
toggleInfo: {
|
|
571
|
-
flex: 1,
|
|
572
|
-
marginRight: 12
|
|
573
|
-
},
|
|
574
|
-
toggleHeader: {
|
|
575
|
-
flexDirection: "row",
|
|
576
|
-
alignItems: "center",
|
|
577
|
-
gap: 8,
|
|
578
|
-
marginBottom: 3
|
|
579
|
-
},
|
|
580
|
-
toggleLabel: {
|
|
581
|
-
fontSize: 14,
|
|
582
|
-
fontWeight: "500",
|
|
583
|
-
color: _sharedUi.night.color.text
|
|
584
|
-
},
|
|
585
|
-
dangerousLabel: {
|
|
586
|
-
color: _sharedUi.night.color.warning
|
|
587
|
-
},
|
|
588
552
|
recommendedBadge: {
|
|
589
553
|
flexDirection: "row",
|
|
590
554
|
alignItems: "center",
|
|
@@ -623,11 +587,6 @@ const styles = _reactNative.StyleSheet.create({
|
|
|
623
587
|
detectedTextInactive: {
|
|
624
588
|
color: _sharedUi.night.color.textTertiary
|
|
625
589
|
},
|
|
626
|
-
toggleDescription: {
|
|
627
|
-
fontSize: 12,
|
|
628
|
-
color: _sharedUi.night.color.textTertiary,
|
|
629
|
-
lineHeight: 16
|
|
630
|
-
},
|
|
631
590
|
divider: {
|
|
632
591
|
height: 1,
|
|
633
592
|
backgroundColor: _sharedUi.night.color.separator,
|
|
@@ -59,21 +59,14 @@ function ImpersonateHistoryList({
|
|
|
59
59
|
});
|
|
60
60
|
}, [currentUserId, onSelectUser, onStopImpersonation, onRemoveFromHistory]);
|
|
61
61
|
if (history.length === 0) {
|
|
62
|
-
return /*#__PURE__*/(0, _jsxRuntime.
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
71
|
-
style: styles.emptyTitle,
|
|
72
|
-
children: "No History"
|
|
73
|
-
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
74
|
-
style: styles.emptyDescription,
|
|
75
|
-
children: "Users you impersonate will appear here for quick access"
|
|
76
|
-
})]
|
|
62
|
+
return /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.ToolEmptyState, {
|
|
63
|
+
testID: "buoy-impersonate-history-empty"
|
|
64
|
+
// disguise = "impersonating another user" — the tool's own state,
|
|
65
|
+
// with nothing worn yet.
|
|
66
|
+
,
|
|
67
|
+
otto: "disguise",
|
|
68
|
+
title: "No History",
|
|
69
|
+
message: "Users you impersonate will appear here for quick access"
|
|
77
70
|
});
|
|
78
71
|
}
|
|
79
72
|
return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
|
@@ -64,6 +64,12 @@ function ImpersonateModal({
|
|
|
64
64
|
const tabs = showSettingsTab ? ALL_TABS : TABS_WITHOUT_SETTINGS;
|
|
65
65
|
const [activeTab, setActiveTab] = (0, _react.useState)("search");
|
|
66
66
|
const [isSearchActive, setIsSearchActive] = (0, _react.useState)(false);
|
|
67
|
+
// True while the header's clear ✕ is being pressed. With a mouse, pressing
|
|
68
|
+
// the ✕ blurs the input FIRST, and the blur handler closes search — which
|
|
69
|
+
// unmounts the ✕ before its own press can fire, so the query was never
|
|
70
|
+
// cleared (desktop). Press-in lands before the blur, so the blur handler can
|
|
71
|
+
// tell this dismissal apart from a click elsewhere.
|
|
72
|
+
const clearPressRef = (0, _react.useRef)(false);
|
|
67
73
|
const [searchText, setSearchText] = (0, _react.useState)("");
|
|
68
74
|
const searchInputRef = (0, _react.useRef)(null);
|
|
69
75
|
|
|
@@ -171,42 +177,23 @@ function ImpersonateModal({
|
|
|
171
177
|
onBack: onBack
|
|
172
178
|
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.ModalHeader.Content, {
|
|
173
179
|
title: "",
|
|
174
|
-
children: isSearchActive ? /*#__PURE__*/(0, _jsxRuntime.
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
returnKeyType: "search"
|
|
192
|
-
}), searchText.length > 0 ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
|
|
193
|
-
onPress: () => {
|
|
194
|
-
setSearchText("");
|
|
195
|
-
setIsSearchActive(false);
|
|
196
|
-
},
|
|
197
|
-
style: styles.headerSearchClear,
|
|
198
|
-
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.X, {
|
|
199
|
-
size: 14,
|
|
200
|
-
color: _sharedUi.night.color.textSecondary
|
|
201
|
-
})
|
|
202
|
-
}) : /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
|
|
203
|
-
onPress: () => setIsSearchActive(false),
|
|
204
|
-
style: styles.headerSearchClear,
|
|
205
|
-
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.X, {
|
|
206
|
-
size: 14,
|
|
207
|
-
color: _sharedUi.night.color.textTertiary
|
|
208
|
-
})
|
|
209
|
-
})]
|
|
180
|
+
children: isSearchActive ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.ModalHeader.Search, {
|
|
181
|
+
value: searchText,
|
|
182
|
+
onChangeText: handleSearchTextChange
|
|
183
|
+
// ✕ clears and closes; with no text it simply closes.
|
|
184
|
+
,
|
|
185
|
+
onCancel: () => {
|
|
186
|
+
setSearchText("");
|
|
187
|
+
setIsSearchActive(false);
|
|
188
|
+
},
|
|
189
|
+
onDismiss: () => setIsSearchActive(false),
|
|
190
|
+
dismissOnBlur: true,
|
|
191
|
+
placeholder: "Search by email, name, or ID...",
|
|
192
|
+
iconSize: 14,
|
|
193
|
+
testID: "buoy-impersonate-search-input",
|
|
194
|
+
inputProps: {
|
|
195
|
+
onSubmitEditing: handleSubmitSearch
|
|
196
|
+
}
|
|
210
197
|
}) : /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.TabSelector, {
|
|
211
198
|
tabs: tabs,
|
|
212
199
|
activeTab: activeTab,
|
|
@@ -321,30 +308,6 @@ const styles = _reactNative.StyleSheet.create({
|
|
|
321
308
|
container: {
|
|
322
309
|
flex: 1
|
|
323
310
|
},
|
|
324
|
-
headerSearchContainer: {
|
|
325
|
-
flexDirection: "row",
|
|
326
|
-
alignItems: "center",
|
|
327
|
-
backgroundColor: _sharedUi.night.color.surfaceElevated,
|
|
328
|
-
borderRadius: 6,
|
|
329
|
-
borderWidth: 1,
|
|
330
|
-
borderColor: _sharedUi.night.color.border,
|
|
331
|
-
paddingHorizontal: 12,
|
|
332
|
-
paddingVertical: 8,
|
|
333
|
-
marginTop: 8,
|
|
334
|
-
flex: 1,
|
|
335
|
-
marginBottom: 2
|
|
336
|
-
},
|
|
337
|
-
headerSearchInput: {
|
|
338
|
-
flex: 1,
|
|
339
|
-
color: _sharedUi.night.color.text,
|
|
340
|
-
fontSize: 13,
|
|
341
|
-
marginLeft: 6,
|
|
342
|
-
paddingVertical: 2
|
|
343
|
-
},
|
|
344
|
-
headerSearchClear: {
|
|
345
|
-
marginLeft: 6,
|
|
346
|
-
padding: 4
|
|
347
|
-
},
|
|
348
311
|
headerActionButton: {
|
|
349
312
|
width: 28,
|
|
350
313
|
height: 28,
|
|
@@ -71,14 +71,47 @@ function toWireState(state) {
|
|
|
71
71
|
}))
|
|
72
72
|
};
|
|
73
73
|
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Users this device has actually seen — search results from the app's own
|
|
77
|
+
* directory. `startImpersonation` refuses anything else: a live eval showed
|
|
78
|
+
* the model INVENTING a plausible user object when search returned nothing,
|
|
79
|
+
* and impersonating a fabricated user is a silent half-state (headers patched
|
|
80
|
+
* for a person who does not exist). History and the current user also count,
|
|
81
|
+
* so the desktop's re-impersonate-from-history flow keeps working.
|
|
82
|
+
*/
|
|
83
|
+
const seenUserIds = new Set();
|
|
84
|
+
function rememberUsers(users) {
|
|
85
|
+
for (const u of users) {
|
|
86
|
+
if (u && typeof u === "object" && u.id) seenUserIds.add(String(u.id));
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
function isKnownUser(user) {
|
|
90
|
+
if (!user || typeof user !== "object" || !user.id) return false;
|
|
91
|
+
if (seenUserIds.has(String(user.id))) return true;
|
|
92
|
+
const state = _impersonateStore.impersonateStore.getState();
|
|
93
|
+
if (state.currentUser?.id === user.id) return true;
|
|
94
|
+
return state.history.some(entry => entry.user.id === user.id);
|
|
95
|
+
}
|
|
74
96
|
function buildActions(onSearchUsers) {
|
|
75
97
|
return {
|
|
76
98
|
searchUsers: async params => {
|
|
77
99
|
const query = String(params?.query ?? "");
|
|
78
100
|
const users = await onSearchUsers(query);
|
|
101
|
+
if (Array.isArray(users)) rememberUsers(users);
|
|
79
102
|
return Array.isArray(users) ? users.map(toWireUser) : users;
|
|
80
103
|
},
|
|
81
|
-
startImpersonation: params =>
|
|
104
|
+
startImpersonation: async params => {
|
|
105
|
+
const user = params?.user;
|
|
106
|
+
if (!isKnownUser(user)) {
|
|
107
|
+
throw new Error("That user isn't in this app's directory. Call searchUsers and impersonate one of its results — a user object that didn't come from search impersonates nobody.");
|
|
108
|
+
}
|
|
109
|
+
await _impersonateStore.impersonateStore.startImpersonation(user);
|
|
110
|
+
return {
|
|
111
|
+
ok: true,
|
|
112
|
+
userId: user.id
|
|
113
|
+
};
|
|
114
|
+
},
|
|
82
115
|
stopImpersonation: () => _impersonateStore.impersonateStore.stopImpersonation(),
|
|
83
116
|
pauseImpersonation: () => _impersonateStore.impersonateStore.pauseImpersonation(),
|
|
84
117
|
resumeImpersonation: () => _impersonateStore.impersonateStore.resumeImpersonation(),
|
|
@@ -8,8 +8,8 @@
|
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
import React, { useState, useEffect, useMemo } from "react";
|
|
11
|
-
import { View, Text, TextInput, StyleSheet,
|
|
12
|
-
import { CollapsibleSection, buoyColors, night, Settings, AlertTriangle, Info, Zap, RefreshCw, Check, X, Copy, Eye, copyToClipboard } from "@buoy-gg/shared-ui";
|
|
11
|
+
import { View, Text, TextInput, StyleSheet, ScrollView, TouchableOpacity } from "react-native";
|
|
12
|
+
import { CollapsibleSection, buoyColors, night, Settings, AlertTriangle, Info, Zap, RefreshCw, Check, X, Copy, Eye, copyToClipboard, ToggleRow as SharedToggleRow } from "@buoy-gg/shared-ui";
|
|
13
13
|
import { DataViewer } from "@buoy-gg/shared-ui/dataViewer";
|
|
14
14
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
15
15
|
const DEFAULT_HEADER_KEY = "x-impersonate-user-id";
|
|
@@ -34,51 +34,40 @@ function ToggleRow({
|
|
|
34
34
|
dangerous,
|
|
35
35
|
detected
|
|
36
36
|
}) {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
}), detected !== undefined && /*#__PURE__*/_jsxs(View, {
|
|
47
|
-
style: [styles.detectedBadge, detected ? styles.detectedBadgeActive : styles.detectedBadgeInactive],
|
|
48
|
-
children: [detected ? /*#__PURE__*/_jsx(Check, {
|
|
49
|
-
size: 10,
|
|
50
|
-
color: buoyColors.success
|
|
51
|
-
}) : /*#__PURE__*/_jsx(X, {
|
|
52
|
-
size: 10,
|
|
53
|
-
color: night.color.textTertiary
|
|
54
|
-
}), /*#__PURE__*/_jsx(Text, {
|
|
55
|
-
style: [styles.detectedText, detected ? styles.detectedTextActive : styles.detectedTextInactive],
|
|
56
|
-
children: detected ? "Detected" : "Not Detected"
|
|
57
|
-
})]
|
|
58
|
-
}), recommended && detected !== false && /*#__PURE__*/_jsxs(View, {
|
|
59
|
-
style: styles.recommendedBadge,
|
|
60
|
-
children: [/*#__PURE__*/_jsx(Zap, {
|
|
61
|
-
size: 10,
|
|
62
|
-
color: night.color.accent
|
|
63
|
-
}), /*#__PURE__*/_jsx(Text, {
|
|
64
|
-
style: styles.recommendedText,
|
|
65
|
-
children: "Recommended"
|
|
66
|
-
})]
|
|
67
|
-
})]
|
|
37
|
+
const accessory = /*#__PURE__*/_jsxs(_Fragment, {
|
|
38
|
+
children: [detected !== undefined && /*#__PURE__*/_jsxs(View, {
|
|
39
|
+
style: [styles.detectedBadge, detected ? styles.detectedBadgeActive : styles.detectedBadgeInactive],
|
|
40
|
+
children: [detected ? /*#__PURE__*/_jsx(Check, {
|
|
41
|
+
size: 10,
|
|
42
|
+
color: buoyColors.success
|
|
43
|
+
}) : /*#__PURE__*/_jsx(X, {
|
|
44
|
+
size: 10,
|
|
45
|
+
color: night.color.textTertiary
|
|
68
46
|
}), /*#__PURE__*/_jsx(Text, {
|
|
69
|
-
style: styles.
|
|
70
|
-
children:
|
|
47
|
+
style: [styles.detectedText, detected ? styles.detectedTextActive : styles.detectedTextInactive],
|
|
48
|
+
children: detected ? "Detected" : "Not Detected"
|
|
49
|
+
})]
|
|
50
|
+
}), recommended && detected !== false && /*#__PURE__*/_jsxs(View, {
|
|
51
|
+
style: styles.recommendedBadge,
|
|
52
|
+
children: [/*#__PURE__*/_jsx(Zap, {
|
|
53
|
+
size: 10,
|
|
54
|
+
color: night.color.accent
|
|
55
|
+
}), /*#__PURE__*/_jsx(Text, {
|
|
56
|
+
style: styles.recommendedText,
|
|
57
|
+
children: "Recommended"
|
|
71
58
|
})]
|
|
72
|
-
}), /*#__PURE__*/_jsx(Switch, {
|
|
73
|
-
value: value,
|
|
74
|
-
onValueChange: onChange,
|
|
75
|
-
trackColor: {
|
|
76
|
-
false: night.color.border,
|
|
77
|
-
true: dangerous ? night.color.warning + "50" : night.color.accent + "50"
|
|
78
|
-
},
|
|
79
|
-
thumbColor: value ? dangerous ? night.color.warning : night.color.accent : night.color.knob
|
|
80
59
|
})]
|
|
81
60
|
});
|
|
61
|
+
return /*#__PURE__*/_jsx(SharedToggleRow, {
|
|
62
|
+
variant: "plain",
|
|
63
|
+
label: label,
|
|
64
|
+
description: description,
|
|
65
|
+
value: value,
|
|
66
|
+
onValueChange: onChange,
|
|
67
|
+
tone: dangerous ? "warning" : "accent",
|
|
68
|
+
emphasizeLabel: dangerous,
|
|
69
|
+
accessory: accessory
|
|
70
|
+
});
|
|
82
71
|
}
|
|
83
72
|
export function DataNukeSettings({
|
|
84
73
|
headerKey,
|
|
@@ -555,31 +544,6 @@ const styles = StyleSheet.create({
|
|
|
555
544
|
color: night.color.accent,
|
|
556
545
|
fontWeight: "500"
|
|
557
546
|
},
|
|
558
|
-
toggleRow: {
|
|
559
|
-
flexDirection: "row",
|
|
560
|
-
alignItems: "center",
|
|
561
|
-
justifyContent: "space-between",
|
|
562
|
-
paddingVertical: 12,
|
|
563
|
-
paddingHorizontal: 12
|
|
564
|
-
},
|
|
565
|
-
toggleInfo: {
|
|
566
|
-
flex: 1,
|
|
567
|
-
marginRight: 12
|
|
568
|
-
},
|
|
569
|
-
toggleHeader: {
|
|
570
|
-
flexDirection: "row",
|
|
571
|
-
alignItems: "center",
|
|
572
|
-
gap: 8,
|
|
573
|
-
marginBottom: 3
|
|
574
|
-
},
|
|
575
|
-
toggleLabel: {
|
|
576
|
-
fontSize: 14,
|
|
577
|
-
fontWeight: "500",
|
|
578
|
-
color: night.color.text
|
|
579
|
-
},
|
|
580
|
-
dangerousLabel: {
|
|
581
|
-
color: night.color.warning
|
|
582
|
-
},
|
|
583
547
|
recommendedBadge: {
|
|
584
548
|
flexDirection: "row",
|
|
585
549
|
alignItems: "center",
|
|
@@ -618,11 +582,6 @@ const styles = StyleSheet.create({
|
|
|
618
582
|
detectedTextInactive: {
|
|
619
583
|
color: night.color.textTertiary
|
|
620
584
|
},
|
|
621
|
-
toggleDescription: {
|
|
622
|
-
fontSize: 12,
|
|
623
|
-
color: night.color.textTertiary,
|
|
624
|
-
lineHeight: 16
|
|
625
|
-
},
|
|
626
585
|
divider: {
|
|
627
586
|
height: 1,
|
|
628
587
|
backgroundColor: night.color.separator,
|
|
@@ -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 { night,
|
|
12
|
+
import { night, Trash2, useRelativeTime, ToolEmptyState } 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 */
|
|
@@ -54,21 +54,14 @@ export function ImpersonateHistoryList({
|
|
|
54
54
|
});
|
|
55
55
|
}, [currentUserId, onSelectUser, onStopImpersonation, onRemoveFromHistory]);
|
|
56
56
|
if (history.length === 0) {
|
|
57
|
-
return /*#__PURE__*/
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
}), /*#__PURE__*/_jsx(Text, {
|
|
66
|
-
style: styles.emptyTitle,
|
|
67
|
-
children: "No History"
|
|
68
|
-
}), /*#__PURE__*/_jsx(Text, {
|
|
69
|
-
style: styles.emptyDescription,
|
|
70
|
-
children: "Users you impersonate will appear here for quick access"
|
|
71
|
-
})]
|
|
57
|
+
return /*#__PURE__*/_jsx(ToolEmptyState, {
|
|
58
|
+
testID: "buoy-impersonate-history-empty"
|
|
59
|
+
// disguise = "impersonating another user" — the tool's own state,
|
|
60
|
+
// with nothing worn yet.
|
|
61
|
+
,
|
|
62
|
+
otto: "disguise",
|
|
63
|
+
title: "No History",
|
|
64
|
+
message: "Users you impersonate will appear here for quick access"
|
|
72
65
|
});
|
|
73
66
|
}
|
|
74
67
|
return /*#__PURE__*/_jsxs(View, {
|
|
@@ -8,8 +8,8 @@
|
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
import React, { useState, useCallback, useRef, useEffect } from "react";
|
|
11
|
-
import { View, StyleSheet, TouchableOpacity
|
|
12
|
-
import { JsModal as JsModalBase, TabSelector, ModalHeader, buoyColors, night, Search,
|
|
11
|
+
import { View, StyleSheet, TouchableOpacity } from "react-native";
|
|
12
|
+
import { JsModal as JsModalBase, TabSelector, ModalHeader, buoyColors, night, Search, TickProvider, windowDragProps } 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";
|
|
@@ -59,6 +59,12 @@ export function ImpersonateModal({
|
|
|
59
59
|
const tabs = showSettingsTab ? ALL_TABS : TABS_WITHOUT_SETTINGS;
|
|
60
60
|
const [activeTab, setActiveTab] = useState("search");
|
|
61
61
|
const [isSearchActive, setIsSearchActive] = useState(false);
|
|
62
|
+
// True while the header's clear ✕ is being pressed. With a mouse, pressing
|
|
63
|
+
// the ✕ blurs the input FIRST, and the blur handler closes search — which
|
|
64
|
+
// unmounts the ✕ before its own press can fire, so the query was never
|
|
65
|
+
// cleared (desktop). Press-in lands before the blur, so the blur handler can
|
|
66
|
+
// tell this dismissal apart from a click elsewhere.
|
|
67
|
+
const clearPressRef = useRef(false);
|
|
62
68
|
const [searchText, setSearchText] = useState("");
|
|
63
69
|
const searchInputRef = useRef(null);
|
|
64
70
|
|
|
@@ -166,42 +172,23 @@ export function ImpersonateModal({
|
|
|
166
172
|
onBack: onBack
|
|
167
173
|
}), /*#__PURE__*/_jsx(ModalHeader.Content, {
|
|
168
174
|
title: "",
|
|
169
|
-
children: isSearchActive ? /*#__PURE__*/
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
returnKeyType: "search"
|
|
187
|
-
}), searchText.length > 0 ? /*#__PURE__*/_jsx(TouchableOpacity, {
|
|
188
|
-
onPress: () => {
|
|
189
|
-
setSearchText("");
|
|
190
|
-
setIsSearchActive(false);
|
|
191
|
-
},
|
|
192
|
-
style: styles.headerSearchClear,
|
|
193
|
-
children: /*#__PURE__*/_jsx(X, {
|
|
194
|
-
size: 14,
|
|
195
|
-
color: night.color.textSecondary
|
|
196
|
-
})
|
|
197
|
-
}) : /*#__PURE__*/_jsx(TouchableOpacity, {
|
|
198
|
-
onPress: () => setIsSearchActive(false),
|
|
199
|
-
style: styles.headerSearchClear,
|
|
200
|
-
children: /*#__PURE__*/_jsx(X, {
|
|
201
|
-
size: 14,
|
|
202
|
-
color: night.color.textTertiary
|
|
203
|
-
})
|
|
204
|
-
})]
|
|
175
|
+
children: isSearchActive ? /*#__PURE__*/_jsx(ModalHeader.Search, {
|
|
176
|
+
value: searchText,
|
|
177
|
+
onChangeText: handleSearchTextChange
|
|
178
|
+
// ✕ clears and closes; with no text it simply closes.
|
|
179
|
+
,
|
|
180
|
+
onCancel: () => {
|
|
181
|
+
setSearchText("");
|
|
182
|
+
setIsSearchActive(false);
|
|
183
|
+
},
|
|
184
|
+
onDismiss: () => setIsSearchActive(false),
|
|
185
|
+
dismissOnBlur: true,
|
|
186
|
+
placeholder: "Search by email, name, or ID...",
|
|
187
|
+
iconSize: 14,
|
|
188
|
+
testID: "buoy-impersonate-search-input",
|
|
189
|
+
inputProps: {
|
|
190
|
+
onSubmitEditing: handleSubmitSearch
|
|
191
|
+
}
|
|
205
192
|
}) : /*#__PURE__*/_jsx(TabSelector, {
|
|
206
193
|
tabs: tabs,
|
|
207
194
|
activeTab: activeTab,
|
|
@@ -316,30 +303,6 @@ const styles = StyleSheet.create({
|
|
|
316
303
|
container: {
|
|
317
304
|
flex: 1
|
|
318
305
|
},
|
|
319
|
-
headerSearchContainer: {
|
|
320
|
-
flexDirection: "row",
|
|
321
|
-
alignItems: "center",
|
|
322
|
-
backgroundColor: night.color.surfaceElevated,
|
|
323
|
-
borderRadius: 6,
|
|
324
|
-
borderWidth: 1,
|
|
325
|
-
borderColor: night.color.border,
|
|
326
|
-
paddingHorizontal: 12,
|
|
327
|
-
paddingVertical: 8,
|
|
328
|
-
marginTop: 8,
|
|
329
|
-
flex: 1,
|
|
330
|
-
marginBottom: 2
|
|
331
|
-
},
|
|
332
|
-
headerSearchInput: {
|
|
333
|
-
flex: 1,
|
|
334
|
-
color: night.color.text,
|
|
335
|
-
fontSize: 13,
|
|
336
|
-
marginLeft: 6,
|
|
337
|
-
paddingVertical: 2
|
|
338
|
-
},
|
|
339
|
-
headerSearchClear: {
|
|
340
|
-
marginLeft: 6,
|
|
341
|
-
padding: 4
|
|
342
|
-
},
|
|
343
306
|
headerActionButton: {
|
|
344
307
|
width: 28,
|
|
345
308
|
height: 28,
|
|
@@ -63,14 +63,47 @@ function toWireState(state) {
|
|
|
63
63
|
}))
|
|
64
64
|
};
|
|
65
65
|
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Users this device has actually seen — search results from the app's own
|
|
69
|
+
* directory. `startImpersonation` refuses anything else: a live eval showed
|
|
70
|
+
* the model INVENTING a plausible user object when search returned nothing,
|
|
71
|
+
* and impersonating a fabricated user is a silent half-state (headers patched
|
|
72
|
+
* for a person who does not exist). History and the current user also count,
|
|
73
|
+
* so the desktop's re-impersonate-from-history flow keeps working.
|
|
74
|
+
*/
|
|
75
|
+
const seenUserIds = new Set();
|
|
76
|
+
function rememberUsers(users) {
|
|
77
|
+
for (const u of users) {
|
|
78
|
+
if (u && typeof u === "object" && u.id) seenUserIds.add(String(u.id));
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
function isKnownUser(user) {
|
|
82
|
+
if (!user || typeof user !== "object" || !user.id) return false;
|
|
83
|
+
if (seenUserIds.has(String(user.id))) return true;
|
|
84
|
+
const state = impersonateStore.getState();
|
|
85
|
+
if (state.currentUser?.id === user.id) return true;
|
|
86
|
+
return state.history.some(entry => entry.user.id === user.id);
|
|
87
|
+
}
|
|
66
88
|
function buildActions(onSearchUsers) {
|
|
67
89
|
return {
|
|
68
90
|
searchUsers: async params => {
|
|
69
91
|
const query = String(params?.query ?? "");
|
|
70
92
|
const users = await onSearchUsers(query);
|
|
93
|
+
if (Array.isArray(users)) rememberUsers(users);
|
|
71
94
|
return Array.isArray(users) ? users.map(toWireUser) : users;
|
|
72
95
|
},
|
|
73
|
-
startImpersonation: params =>
|
|
96
|
+
startImpersonation: async params => {
|
|
97
|
+
const user = params?.user;
|
|
98
|
+
if (!isKnownUser(user)) {
|
|
99
|
+
throw new Error("That user isn't in this app's directory. Call searchUsers and impersonate one of its results — a user object that didn't come from search impersonates nobody.");
|
|
100
|
+
}
|
|
101
|
+
await impersonateStore.startImpersonation(user);
|
|
102
|
+
return {
|
|
103
|
+
ok: true,
|
|
104
|
+
userId: user.id
|
|
105
|
+
};
|
|
106
|
+
},
|
|
74
107
|
stopImpersonation: () => impersonateStore.stopImpersonation(),
|
|
75
108
|
pauseImpersonation: () => impersonateStore.pauseImpersonation(),
|
|
76
109
|
resumeImpersonation: () => impersonateStore.resumeImpersonation(),
|
|
@@ -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;
|
|
1
|
+
{"version":3,"file":"DataNukeSettings.d.ts","sourceRoot":"","sources":["../../../../src/impersonate/components/DataNukeSettings.tsx"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAuC,MAAM,OAAO,CAAC;AA2B5D,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;AAgED,wBAAgB,gBAAgB,CAAC,EAC/B,SAAS,EACT,QAAQ,EACR,UAAU,EACV,MAAM,EACN,kBAAkB,EAClB,eAAe,GAChB,EAAE,qBAAqB,qBAkVvB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ImpersonateHistoryList.d.ts","sourceRoot":"","sources":["../../../../src/impersonate/components/ImpersonateHistoryList.tsx"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAsB,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"ImpersonateHistoryList.d.ts","sourceRoot":"","sources":["../../../../src/impersonate/components/ImpersonateHistoryList.tsx"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAsB,MAAM,OAAO,CAAC;AAgB3C,OAAO,KAAK,EAAE,IAAI,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAgCnD,MAAM,WAAW,2BAA2B;IAC1C,0CAA0C;IAC1C,OAAO,EAAE,YAAY,EAAE,CAAC;IACxB,iEAAiE;IACjE,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,uDAAuD;IACvD,YAAY,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,IAAI,CAAC;IACnC,wDAAwD;IACxD,mBAAmB,CAAC,EAAE,MAAM,IAAI,CAAC;IACjC,2CAA2C;IAC3C,mBAAmB,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IAC/C,kCAAkC;IAClC,cAAc,CAAC,EAAE,MAAM,IAAI,CAAC;CAC7B;AAED,wBAAgB,sBAAsB,CAAC,EACrC,OAAO,EACP,aAAa,EACb,YAAY,EACZ,mBAAmB,EACnB,mBAAmB,EACnB,cAAc,GACf,EAAE,2BAA2B,qBA+D7B"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ImpersonateModal.d.ts","sourceRoot":"","sources":["../../../../src/impersonate/components/ImpersonateModal.tsx"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAmD,MAAM,OAAO,CAAC;AAmBxE,OAAO,KAAK,EAAE,qBAAqB,EAA0B,MAAM,UAAU,CAAC;AAgC9E,wBAAgB,gBAAgB,CAAC,EAC/B,OAAO,EACP,OAAO,EACP,MAAM,EACN,UAAU,EACV,aAAa,EACb,iBAAiB,EACjB,YAAY,EACZ,mBAAmB,EACnB,WAAW,EACX,eAAsB,EACtB,MAAc,GACf,EAAE,qBAAqB,
|
|
1
|
+
{"version":3,"file":"ImpersonateModal.d.ts","sourceRoot":"","sources":["../../../../src/impersonate/components/ImpersonateModal.tsx"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAmD,MAAM,OAAO,CAAC;AAmBxE,OAAO,KAAK,EAAE,qBAAqB,EAA0B,MAAM,UAAU,CAAC;AAgC9E,wBAAgB,gBAAgB,CAAC,EAC/B,OAAO,EACP,OAAO,EACP,MAAM,EACN,UAAU,EACV,aAAa,EACb,iBAAiB,EACjB,YAAY,EACZ,mBAAmB,EACnB,WAAW,EACX,eAAsB,EACtB,MAAc,GACf,EAAE,qBAAqB,4BA6OvB;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,IAAI,CAAC,qBAAqB,EAAE,SAAS,GAAG,SAAS,GAAG,QAAQ,CAAC,qBAGrE"}
|
|
@@ -34,7 +34,10 @@ export declare function createImpersonateSyncAdapter({ onSearchUsers, }: CreateI
|
|
|
34
34
|
subscribe: (onChange: () => void) => () => void;
|
|
35
35
|
actions: {
|
|
36
36
|
searchUsers: (params: unknown) => Promise<User[]>;
|
|
37
|
-
startImpersonation: (params?: unknown) => Promise<
|
|
37
|
+
startImpersonation: (params?: unknown) => Promise<{
|
|
38
|
+
ok: boolean;
|
|
39
|
+
userId: string;
|
|
40
|
+
}>;
|
|
38
41
|
stopImpersonation: () => Promise<void>;
|
|
39
42
|
pauseImpersonation: () => Promise<void>;
|
|
40
43
|
resumeImpersonation: () => Promise<void>;
|
|
@@ -55,7 +58,10 @@ export declare const impersonateSyncAdapter: {
|
|
|
55
58
|
subscribe: (onChange: () => void) => () => void;
|
|
56
59
|
actions: {
|
|
57
60
|
searchUsers: (params: unknown) => Promise<User[]>;
|
|
58
|
-
startImpersonation: (params?: unknown) => Promise<
|
|
61
|
+
startImpersonation: (params?: unknown) => Promise<{
|
|
62
|
+
ok: boolean;
|
|
63
|
+
userId: string;
|
|
64
|
+
}>;
|
|
59
65
|
stopImpersonation: () => Promise<void>;
|
|
60
66
|
pauseImpersonation: () => Promise<void>;
|
|
61
67
|
resumeImpersonation: () => Promise<void>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"impersonateSyncAdapter.d.ts","sourceRoot":"","sources":["../../../src/sync/impersonateSyncAdapter.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,IAAI,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAErE,KAAK,kBAAkB,GAAG,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC;AAO7D,8EAA8E;AAC9E,wBAAgB,8BAA8B,CAC5C,OAAO,EAAE,kBAAkB,GAAG,IAAI,GACjC,IAAI,CAEN;AAED;;;;;GAKG;AACH,eAAO,MAAM,yBAAyB,QAAW,CAAC;AAClD,eAAO,MAAM,8BAA8B,QAAY,CAAC;AAQxD,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAUrE;
|
|
1
|
+
{"version":3,"file":"impersonateSyncAdapter.d.ts","sourceRoot":"","sources":["../../../src/sync/impersonateSyncAdapter.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,IAAI,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAErE,KAAK,kBAAkB,GAAG,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC;AAO7D,8EAA8E;AAC9E,wBAAgB,8BAA8B,CAC5C,OAAO,EAAE,kBAAkB,GAAG,IAAI,GACjC,IAAI,CAEN;AAED;;;;;GAKG;AACH,eAAO,MAAM,yBAAyB,QAAW,CAAC;AAClD,eAAO,MAAM,8BAA8B,QAAY,CAAC;AAQxD,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAUrE;AA4FD,UAAU,mCAAmC;IAC3C;;;OAGG;IACH,aAAa,EAAE,kBAAkB,CAAC;CACnC;AAED;;;;;;;;;GASG;AACH,wBAAgB,4BAA4B,CAAC,EAC3C,aAAa,GACd,EAAE,mCAAmC;;uBAGjB,kBAAkB;0BACb,MAAM,IAAI;;8BA3DJ,OAAO;sCAQC,OAAO;;;;;;;kCAajB,OAAO;qCAQJ,OAAO;;;EAiCvC;AAED;;;;;GAKG;AACH,eAAO,MAAM,sBAAsB;;uBAEhB,kBAAkB;0BACb,MAAM,IAAI;;8BAzEF,OAAO;sCAQC,OAAO;;;;;;;kCAajB,OAAO;qCAQJ,OAAO;;;CAqDvC,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@buoy-gg/impersonate",
|
|
3
|
-
"version": "7.0.
|
|
3
|
+
"version": "7.0.34",
|
|
4
4
|
"description": "Test your React Native app as any user, role, or flag combo — without logging out or rebuilding. Part of Buoy devtools.",
|
|
5
5
|
"main": "lib/commonjs/index.js",
|
|
6
6
|
"module": "lib/module/index.js",
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
],
|
|
27
27
|
"sideEffects": false,
|
|
28
28
|
"dependencies": {
|
|
29
|
-
"@buoy-gg/shared-ui": "^7.0.
|
|
29
|
+
"@buoy-gg/shared-ui": "^7.0.34"
|
|
30
30
|
},
|
|
31
31
|
"peerDependencies": {
|
|
32
32
|
"react": "*",
|