@buoy-gg/impersonate 7.0.31 → 7.0.33

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.
@@ -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.jsxs)(_reactNative.View, {
63
- style: styles.emptyContainer,
64
- children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
65
- style: styles.emptyIcon,
66
- children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.Clock, {
67
- size: 28,
68
- color: _sharedUi.night.color.textTertiary
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
 
@@ -185,11 +191,23 @@ function ImpersonateModal({
185
191
  value: searchText,
186
192
  onChangeText: handleSearchTextChange,
187
193
  onSubmitEditing: handleSubmitSearch,
188
- onBlur: () => setIsSearchActive(false),
194
+ onBlur: () => {
195
+ if (!clearPressRef.current) setIsSearchActive(false);
196
+ },
189
197
  autoCapitalize: "none",
190
198
  autoCorrect: false,
191
199
  returnKeyType: "search"
192
- }), searchText.length > 0 ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
200
+ }), searchText.length > 0 ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity
201
+ // react-native-web delays press-in ~50ms by default (native
202
+ // fires it immediately), which would put it AFTER the blur.
203
+ , {
204
+ delayPressIn: 0,
205
+ onPressIn: () => {
206
+ clearPressRef.current = true;
207
+ },
208
+ onPressOut: () => {
209
+ clearPressRef.current = false;
210
+ },
193
211
  onPress: () => {
194
212
  setSearchText("");
195
213
  setIsSearchActive(false);
@@ -265,6 +283,7 @@ function ImpersonateModal({
265
283
  style: styles.inlineRoot,
266
284
  children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
267
285
  style: styles.inlineHeader,
286
+ ..._sharedUi.windowDragProps,
268
287
  children: renderHeaderContent()
269
288
  }), body]
270
289
  })
@@ -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 => _impersonateStore.impersonateStore.startImpersonation(params.user),
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(),
@@ -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, Clock, Trash2, useRelativeTime } from "@buoy-gg/shared-ui";
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__*/_jsxs(View, {
58
- style: styles.emptyContainer,
59
- children: [/*#__PURE__*/_jsx(View, {
60
- style: styles.emptyIcon,
61
- children: /*#__PURE__*/_jsx(Clock, {
62
- size: 28,
63
- color: night.color.textTertiary
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, {
@@ -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, night, Search, X, TickProvider } from "@buoy-gg/shared-ui";
12
+ import { JsModal as JsModalBase, TabSelector, ModalHeader, buoyColors, night, Search, X, 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
 
@@ -180,11 +186,23 @@ export function ImpersonateModal({
180
186
  value: searchText,
181
187
  onChangeText: handleSearchTextChange,
182
188
  onSubmitEditing: handleSubmitSearch,
183
- onBlur: () => setIsSearchActive(false),
189
+ onBlur: () => {
190
+ if (!clearPressRef.current) setIsSearchActive(false);
191
+ },
184
192
  autoCapitalize: "none",
185
193
  autoCorrect: false,
186
194
  returnKeyType: "search"
187
- }), searchText.length > 0 ? /*#__PURE__*/_jsx(TouchableOpacity, {
195
+ }), searchText.length > 0 ? /*#__PURE__*/_jsx(TouchableOpacity
196
+ // react-native-web delays press-in ~50ms by default (native
197
+ // fires it immediately), which would put it AFTER the blur.
198
+ , {
199
+ delayPressIn: 0,
200
+ onPressIn: () => {
201
+ clearPressRef.current = true;
202
+ },
203
+ onPressOut: () => {
204
+ clearPressRef.current = false;
205
+ },
188
206
  onPress: () => {
189
207
  setSearchText("");
190
208
  setIsSearchActive(false);
@@ -260,6 +278,7 @@ export function ImpersonateModal({
260
278
  style: styles.inlineRoot,
261
279
  children: [/*#__PURE__*/_jsx(View, {
262
280
  style: styles.inlineHeader,
281
+ ...windowDragProps,
263
282
  children: renderHeaderContent()
264
283
  }), body]
265
284
  })
@@ -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 => impersonateStore.startImpersonation(params.user),
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":"ImpersonateHistoryList.d.ts","sourceRoot":"","sources":["../../../../src/impersonate/components/ImpersonateHistoryList.tsx"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAsB,MAAM,OAAO,CAAC;AAe3C,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,qBAgE7B"}
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;AAiBxE,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,4BA2PvB;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,IAAI,CAAC,qBAAqB,EAAE,SAAS,GAAG,SAAS,GAAG,QAAQ,CAAC,qBAGrE"}
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,4BA4QvB;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<void>;
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<void>;
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;AA2DD,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;;8BAlDJ,OAAO;sCAOL,OAAO;;;;kCAKX,OAAO;qCAQJ,OAAO;;;EAiCvC;AAED;;;;;GAKG;AACH,eAAO,MAAM,sBAAsB;;uBAEhB,kBAAkB;0BACb,MAAM,IAAI;;8BAhEF,OAAO;sCAOL,OAAO;;;;kCAKX,OAAO;qCAQJ,OAAO;;;CAqDvC,CAAC"}
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.31",
3
+ "version": "7.0.33",
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.31"
29
+ "@buoy-gg/shared-ui": "^7.0.33"
30
30
  },
31
31
  "peerDependencies": {
32
32
  "react": "*",