@buoy-gg/impersonate 7.0.41 → 7.0.43

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.
Files changed (78) hide show
  1. package/README.md +12 -80
  2. package/lib/commonjs/impersonate/components/DataNukeSettings.js +8 -675
  3. package/lib/commonjs/impersonate/components/ImpersonateBanner.js +1 -221
  4. package/lib/commonjs/impersonate/components/ImpersonateHistoryList.js +1 -181
  5. package/lib/commonjs/impersonate/components/ImpersonateModal.js +1 -319
  6. package/lib/commonjs/impersonate/components/ImpersonateOverlay.js +1 -26
  7. package/lib/commonjs/impersonate/components/ImpersonateStatusBar.js +1 -130
  8. package/lib/commonjs/impersonate/components/UserAvatar.js +1 -146
  9. package/lib/commonjs/impersonate/components/UserCard.js +1 -201
  10. package/lib/commonjs/impersonate/components/UserSearchView.js +1 -227
  11. package/lib/commonjs/impersonate/hooks/asyncStoragePeer.js +1 -17
  12. package/lib/commonjs/impersonate/hooks/asyncStoragePeer.web.js +1 -11
  13. package/lib/commonjs/impersonate/hooks/useAutoClearAsyncStorage.js +1 -134
  14. package/lib/commonjs/impersonate/hooks/useAutoClearReactQuery.js +1 -155
  15. package/lib/commonjs/impersonate/hooks/useAutoClearReactQuery.web.js +1 -20
  16. package/lib/commonjs/impersonate/hooks/useAutoClearRedux.js +1 -188
  17. package/lib/commonjs/impersonate/hooks/useAutoClearRedux.web.js +1 -27
  18. package/lib/commonjs/impersonate/hooks/useImpersonate.js +1 -215
  19. package/lib/commonjs/impersonate/hooks/useImpersonateHistory.js +1 -56
  20. package/lib/commonjs/impersonate/types/index.js +1 -16
  21. package/lib/commonjs/impersonate/types/types.js +1 -1
  22. package/lib/commonjs/impersonate/utils/impersonateListener.js +1 -350
  23. package/lib/commonjs/impersonate/utils/impersonateStore.js +1 -689
  24. package/lib/commonjs/index.js +1 -150
  25. package/lib/commonjs/preset.js +1 -232
  26. package/lib/commonjs/sync/impersonateSyncAdapter.js +1 -170
  27. package/lib/module/impersonate/components/DataNukeSettings.js +8 -670
  28. package/lib/module/impersonate/components/ImpersonateBanner.js +1 -215
  29. package/lib/module/impersonate/components/ImpersonateHistoryList.js +1 -176
  30. package/lib/module/impersonate/components/ImpersonateModal.js +1 -314
  31. package/lib/module/impersonate/components/ImpersonateOverlay.js +1 -21
  32. package/lib/module/impersonate/components/ImpersonateStatusBar.js +1 -125
  33. package/lib/module/impersonate/components/UserAvatar.js +1 -140
  34. package/lib/module/impersonate/components/UserCard.js +1 -196
  35. package/lib/module/impersonate/components/UserSearchView.js +1 -222
  36. package/lib/module/impersonate/hooks/asyncStoragePeer.js +1 -13
  37. package/lib/module/impersonate/hooks/asyncStoragePeer.web.js +1 -6
  38. package/lib/module/impersonate/hooks/useAutoClearAsyncStorage.js +1 -130
  39. package/lib/module/impersonate/hooks/useAutoClearReactQuery.js +1 -151
  40. package/lib/module/impersonate/hooks/useAutoClearReactQuery.web.js +1 -16
  41. package/lib/module/impersonate/hooks/useAutoClearRedux.js +1 -183
  42. package/lib/module/impersonate/hooks/useAutoClearRedux.web.js +1 -22
  43. package/lib/module/impersonate/hooks/useImpersonate.js +1 -212
  44. package/lib/module/impersonate/hooks/useImpersonateHistory.js +1 -52
  45. package/lib/module/impersonate/types/index.js +1 -3
  46. package/lib/module/impersonate/types/types.js +1 -1
  47. package/lib/module/impersonate/utils/impersonateListener.js +1 -341
  48. package/lib/module/impersonate/utils/impersonateStore.js +1 -686
  49. package/lib/module/index.js +1 -117
  50. package/lib/module/preset.js +1 -216
  51. package/lib/module/sync/impersonateSyncAdapter.js +1 -162
  52. package/lib/web/index.mjs +7 -8
  53. package/package.json +3 -6
  54. package/lib/typescript/impersonate/components/DataNukeSettings.d.ts.map +0 -1
  55. package/lib/typescript/impersonate/components/ImpersonateBanner.d.ts.map +0 -1
  56. package/lib/typescript/impersonate/components/ImpersonateHistoryList.d.ts.map +0 -1
  57. package/lib/typescript/impersonate/components/ImpersonateModal.d.ts.map +0 -1
  58. package/lib/typescript/impersonate/components/ImpersonateOverlay.d.ts.map +0 -1
  59. package/lib/typescript/impersonate/components/ImpersonateStatusBar.d.ts.map +0 -1
  60. package/lib/typescript/impersonate/components/UserAvatar.d.ts.map +0 -1
  61. package/lib/typescript/impersonate/components/UserCard.d.ts.map +0 -1
  62. package/lib/typescript/impersonate/components/UserSearchView.d.ts.map +0 -1
  63. package/lib/typescript/impersonate/hooks/asyncStoragePeer.d.ts.map +0 -1
  64. package/lib/typescript/impersonate/hooks/asyncStoragePeer.web.d.ts.map +0 -1
  65. package/lib/typescript/impersonate/hooks/useAutoClearAsyncStorage.d.ts.map +0 -1
  66. package/lib/typescript/impersonate/hooks/useAutoClearReactQuery.d.ts.map +0 -1
  67. package/lib/typescript/impersonate/hooks/useAutoClearReactQuery.web.d.ts.map +0 -1
  68. package/lib/typescript/impersonate/hooks/useAutoClearRedux.d.ts.map +0 -1
  69. package/lib/typescript/impersonate/hooks/useAutoClearRedux.web.d.ts.map +0 -1
  70. package/lib/typescript/impersonate/hooks/useImpersonate.d.ts.map +0 -1
  71. package/lib/typescript/impersonate/hooks/useImpersonateHistory.d.ts.map +0 -1
  72. package/lib/typescript/impersonate/types/index.d.ts.map +0 -1
  73. package/lib/typescript/impersonate/types/types.d.ts.map +0 -1
  74. package/lib/typescript/impersonate/utils/impersonateListener.d.ts.map +0 -1
  75. package/lib/typescript/impersonate/utils/impersonateStore.d.ts.map +0 -1
  76. package/lib/typescript/index.d.ts.map +0 -1
  77. package/lib/typescript/preset.d.ts.map +0 -1
  78. package/lib/typescript/sync/impersonateSyncAdapter.d.ts.map +0 -1
@@ -1,150 +1 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- Object.defineProperty(exports, "DataNukeSettingsComponent", {
7
- enumerable: true,
8
- get: function () {
9
- return _DataNukeSettings.DataNukeSettings;
10
- }
11
- });
12
- Object.defineProperty(exports, "ImpersonateBanner", {
13
- enumerable: true,
14
- get: function () {
15
- return _ImpersonateBanner.ImpersonateBanner;
16
- }
17
- });
18
- Object.defineProperty(exports, "ImpersonateBannerMinimal", {
19
- enumerable: true,
20
- get: function () {
21
- return _ImpersonateBanner.ImpersonateBannerMinimal;
22
- }
23
- });
24
- Object.defineProperty(exports, "ImpersonateHistoryList", {
25
- enumerable: true,
26
- get: function () {
27
- return _ImpersonateHistoryList.ImpersonateHistoryList;
28
- }
29
- });
30
- Object.defineProperty(exports, "ImpersonateIcon", {
31
- enumerable: true,
32
- get: function () {
33
- return _preset.ImpersonateIcon;
34
- }
35
- });
36
- Object.defineProperty(exports, "ImpersonateModal", {
37
- enumerable: true,
38
- get: function () {
39
- return _ImpersonateModal.ImpersonateModal;
40
- }
41
- });
42
- Object.defineProperty(exports, "ImpersonateOverlay", {
43
- enumerable: true,
44
- get: function () {
45
- return _ImpersonateOverlay.ImpersonateOverlay;
46
- }
47
- });
48
- Object.defineProperty(exports, "ImpersonateStatusBar", {
49
- enumerable: true,
50
- get: function () {
51
- return _ImpersonateStatusBar.ImpersonateStatusBar;
52
- }
53
- });
54
- Object.defineProperty(exports, "ImpersonateToolView", {
55
- enumerable: true,
56
- get: function () {
57
- return _ImpersonateModal.ImpersonateToolView;
58
- }
59
- });
60
- Object.defineProperty(exports, "UserSearchView", {
61
- enumerable: true,
62
- get: function () {
63
- return _UserSearchView.UserSearchView;
64
- }
65
- });
66
- Object.defineProperty(exports, "createImpersonateSyncAdapter", {
67
- enumerable: true,
68
- get: function () {
69
- return _impersonateSyncAdapter.createImpersonateSyncAdapter;
70
- }
71
- });
72
- Object.defineProperty(exports, "createImpersonateTool", {
73
- enumerable: true,
74
- get: function () {
75
- return _preset.createImpersonateTool;
76
- }
77
- });
78
- Object.defineProperty(exports, "getImpersonatedUserId", {
79
- enumerable: true,
80
- get: function () {
81
- return _impersonateListener.getImpersonatedUserId;
82
- }
83
- });
84
- Object.defineProperty(exports, "impersonateListener", {
85
- enumerable: true,
86
- get: function () {
87
- return _impersonateListener.impersonateListener;
88
- }
89
- });
90
- Object.defineProperty(exports, "impersonateStore", {
91
- enumerable: true,
92
- get: function () {
93
- return _impersonateStore.impersonateStore;
94
- }
95
- });
96
- Object.defineProperty(exports, "impersonateSyncAdapter", {
97
- enumerable: true,
98
- get: function () {
99
- return _impersonateSyncAdapter.impersonateSyncAdapter;
100
- }
101
- });
102
- Object.defineProperty(exports, "isImpersonating", {
103
- enumerable: true,
104
- get: function () {
105
- return _impersonateListener.isImpersonating;
106
- }
107
- });
108
- Object.defineProperty(exports, "setImpersonateConfig", {
109
- enumerable: true,
110
- get: function () {
111
- return _impersonateListener.setImpersonateConfig;
112
- }
113
- });
114
- Object.defineProperty(exports, "startImpersonateListener", {
115
- enumerable: true,
116
- get: function () {
117
- return _impersonateListener.startImpersonateListener;
118
- }
119
- });
120
- Object.defineProperty(exports, "stopImpersonateListener", {
121
- enumerable: true,
122
- get: function () {
123
- return _impersonateListener.stopImpersonateListener;
124
- }
125
- });
126
- Object.defineProperty(exports, "useImpersonate", {
127
- enumerable: true,
128
- get: function () {
129
- return _useImpersonate.useImpersonate;
130
- }
131
- });
132
- Object.defineProperty(exports, "useImpersonateHistory", {
133
- enumerable: true,
134
- get: function () {
135
- return _useImpersonateHistory.useImpersonateHistory;
136
- }
137
- });
138
- var _preset = require("./preset");
139
- var _impersonateSyncAdapter = require("./sync/impersonateSyncAdapter");
140
- var _ImpersonateModal = require("./impersonate/components/ImpersonateModal");
141
- var _ImpersonateBanner = require("./impersonate/components/ImpersonateBanner");
142
- var _ImpersonateOverlay = require("./impersonate/components/ImpersonateOverlay");
143
- var _UserSearchView = require("./impersonate/components/UserSearchView");
144
- var _DataNukeSettings = require("./impersonate/components/DataNukeSettings");
145
- var _ImpersonateHistoryList = require("./impersonate/components/ImpersonateHistoryList");
146
- var _ImpersonateStatusBar = require("./impersonate/components/ImpersonateStatusBar");
147
- var _useImpersonate = require("./impersonate/hooks/useImpersonate");
148
- var _useImpersonateHistory = require("./impersonate/hooks/useImpersonateHistory");
149
- var _impersonateStore = require("./impersonate/utils/impersonateStore");
150
- var _impersonateListener = require("./impersonate/utils/impersonateListener");
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});Object.defineProperty(exports,"DataNukeSettingsComponent",{enumerable:true,get:function(){return _DataNukeSettings.DataNukeSettings}});Object.defineProperty(exports,"ImpersonateBanner",{enumerable:true,get:function(){return _ImpersonateBanner.ImpersonateBanner}});Object.defineProperty(exports,"ImpersonateBannerMinimal",{enumerable:true,get:function(){return _ImpersonateBanner.ImpersonateBannerMinimal}});Object.defineProperty(exports,"ImpersonateHistoryList",{enumerable:true,get:function(){return _ImpersonateHistoryList.ImpersonateHistoryList}});Object.defineProperty(exports,"ImpersonateIcon",{enumerable:true,get:function(){return _preset.ImpersonateIcon}});Object.defineProperty(exports,"ImpersonateModal",{enumerable:true,get:function(){return _ImpersonateModal.ImpersonateModal}});Object.defineProperty(exports,"ImpersonateOverlay",{enumerable:true,get:function(){return _ImpersonateOverlay.ImpersonateOverlay}});Object.defineProperty(exports,"ImpersonateStatusBar",{enumerable:true,get:function(){return _ImpersonateStatusBar.ImpersonateStatusBar}});Object.defineProperty(exports,"ImpersonateToolView",{enumerable:true,get:function(){return _ImpersonateModal.ImpersonateToolView}});Object.defineProperty(exports,"UserSearchView",{enumerable:true,get:function(){return _UserSearchView.UserSearchView}});Object.defineProperty(exports,"createImpersonateSyncAdapter",{enumerable:true,get:function(){return _impersonateSyncAdapter.createImpersonateSyncAdapter}});Object.defineProperty(exports,"createImpersonateTool",{enumerable:true,get:function(){return _preset.createImpersonateTool}});Object.defineProperty(exports,"getImpersonatedUserId",{enumerable:true,get:function(){return _impersonateListener.getImpersonatedUserId}});Object.defineProperty(exports,"impersonateListener",{enumerable:true,get:function(){return _impersonateListener.impersonateListener}});Object.defineProperty(exports,"impersonateStore",{enumerable:true,get:function(){return _impersonateStore.impersonateStore}});Object.defineProperty(exports,"impersonateSyncAdapter",{enumerable:true,get:function(){return _impersonateSyncAdapter.impersonateSyncAdapter}});Object.defineProperty(exports,"isImpersonating",{enumerable:true,get:function(){return _impersonateListener.isImpersonating}});Object.defineProperty(exports,"setImpersonateConfig",{enumerable:true,get:function(){return _impersonateListener.setImpersonateConfig}});Object.defineProperty(exports,"startImpersonateListener",{enumerable:true,get:function(){return _impersonateListener.startImpersonateListener}});Object.defineProperty(exports,"stopImpersonateListener",{enumerable:true,get:function(){return _impersonateListener.stopImpersonateListener}});Object.defineProperty(exports,"useImpersonate",{enumerable:true,get:function(){return _useImpersonate.useImpersonate}});Object.defineProperty(exports,"useImpersonateHistory",{enumerable:true,get:function(){return _useImpersonateHistory.useImpersonateHistory}});var _preset=require("./preset");var _impersonateSyncAdapter=require("./sync/impersonateSyncAdapter");var _ImpersonateModal=require("./impersonate/components/ImpersonateModal");var _ImpersonateBanner=require("./impersonate/components/ImpersonateBanner");var _ImpersonateOverlay=require("./impersonate/components/ImpersonateOverlay");var _UserSearchView=require("./impersonate/components/UserSearchView");var _DataNukeSettings=require("./impersonate/components/DataNukeSettings");var _ImpersonateHistoryList=require("./impersonate/components/ImpersonateHistoryList");var _ImpersonateStatusBar=require("./impersonate/components/ImpersonateStatusBar");var _useImpersonate=require("./impersonate/hooks/useImpersonate");var _useImpersonateHistory=require("./impersonate/hooks/useImpersonateHistory");var _impersonateStore=require("./impersonate/utils/impersonateStore");var _impersonateListener=require("./impersonate/utils/impersonateListener");
@@ -1,232 +1 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- Object.defineProperty(exports, "IMPERSONATE_ICON_COLOR", {
7
- enumerable: true,
8
- get: function () {
9
- return _sharedUi.IMPERSONATE_ICON_COLOR;
10
- }
11
- });
12
- Object.defineProperty(exports, "ImpersonateIcon", {
13
- enumerable: true,
14
- get: function () {
15
- return _sharedUi.ImpersonateIcon;
16
- }
17
- });
18
- exports.createImpersonateTool = createImpersonateTool;
19
- var _asyncStoragePeer = require("./impersonate/hooks/asyncStoragePeer");
20
- var _react = _interopRequireDefault(require("react"));
21
- var _ImpersonateModal = require("./impersonate/components/ImpersonateModal");
22
- var _ImpersonateBanner = require("./impersonate/components/ImpersonateBanner");
23
- var _impersonateStore = require("./impersonate/utils/impersonateStore");
24
- var _impersonateListener = require("./impersonate/utils/impersonateListener");
25
- var _impersonateSyncAdapter = require("./sync/impersonateSyncAdapter");
26
- var _sharedUi = require("@buoy-gg/shared-ui");
27
- var _jsxRuntime = require("react/jsx-runtime");
28
- function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
29
- /**
30
- * Impersonate Tool Preset
31
- *
32
- * Factory function to create a configured impersonate tool for FloatingDevTools.
33
- * No default preset is exported because configuration (onSearchUsers) is required.
34
- */
35
-
36
- // =============================================================================
37
- // EAGER BOOTSTRAP
38
- // =============================================================================
39
- // Patch fetch/XHR and restore persisted state the moment createImpersonateTool
40
- // runs (typically at module load in the host app). If we waited until the
41
- // modal mounts (the original lazy design), every request fired during app
42
- // boot — bridge polls, user-data fetches, etc. — goes out without the
43
- // impersonation header, even when the user already had impersonation active
44
- // from a previous session. React Query then caches the real-account response,
45
- // so even after the listener does eventually patch, no refetch happens.
46
- //
47
- // Side effect: any later fetch interceptor (e.g. @buoy-gg/network) installed
48
- // AFTER us will wrap our wrapper, so its captured init.headers won't show the
49
- // impersonation header. The wire request still includes it.
50
-
51
- let bootstrapStarted = false;
52
- async function bootstrapImpersonate() {
53
- if (typeof window === 'undefined' || bootstrapStarted) return;
54
- bootstrapStarted = true;
55
-
56
- // eslint-disable-next-line no-console
57
- console.log("[impersonate] bootstrap: start");
58
-
59
- // Patch fetch/XHR synchronously so any request between now and the async
60
- // storage load goes through our wrapper. The wrapper is a no-op until
61
- // userId is set (which happens once initializeAsync resolves).
62
- if (!(0, _impersonateListener.impersonateListener)().isListening) {
63
- (0, _impersonateListener.impersonateListener)().startListening();
64
- }
65
-
66
- // React Native: require AsyncStorage. require() is more reliable under
67
- // Metro than dynamic import(); on web this throws and the store falls
68
- // back to localStorage handled synchronously in its constructor.
69
- try {
70
- // eslint-disable-next-line @typescript-eslint/no-require-imports
71
- const AsyncStorage = (0, _asyncStoragePeer.getAsyncStorage)();
72
- if (!AsyncStorage || typeof AsyncStorage.getItem !== "function") {
73
- // eslint-disable-next-line no-console
74
- console.warn("[impersonate] bootstrap: AsyncStorage shape unexpected", Object.keys(AsyncStorage ?? {}));
75
- return;
76
- }
77
- const adapter = {
78
- getItem: key => AsyncStorage.getItem(key),
79
- setItem: (key, value) => AsyncStorage.setItem(key, value)
80
- };
81
- _impersonateStore.impersonateStore.setAsyncStorage(adapter);
82
- // eslint-disable-next-line no-console
83
- console.log("[impersonate] bootstrap: AsyncStorage adapter installed");
84
- await _impersonateStore.impersonateStore.initializeAsync(adapter);
85
- // eslint-disable-next-line no-console
86
- console.log("[impersonate] bootstrap: initializeAsync done");
87
- } catch (e) {
88
- // eslint-disable-next-line no-console
89
- console.warn("[impersonate] bootstrap: failed", e);
90
- }
91
- }
92
-
93
- // =============================================================================
94
- // ICON COMPONENT
95
- // =============================================================================
96
-
97
- /**
98
- * Impersonate tool icon — a masked figure with a second identity behind it.
99
- *
100
- * The artwork lives in shared/icons/impersonate.json (Buoy Icon Format) and is
101
- * generated into @buoy-gg/floating-tools-core, so React Native, the desktop
102
- * dashboard and Flutter all render the same drawing. Edit the JSON, then
103
- * `pnpm icons`.
104
- */
105
-
106
- // =============================================================================
107
- // WRAPPER COMPONENT
108
- // =============================================================================
109
-
110
- // =============================================================================
111
- // FACTORY FUNCTION
112
- // =============================================================================
113
-
114
- /**
115
- * Create an impersonate tool with custom configuration
116
- *
117
- * The tool automatically displays a floating banner when impersonation is active.
118
- * This can be toggled in the Settings tab or via developer defaults.
119
- *
120
- * @example
121
- * ```tsx
122
- * import { createImpersonateTool } from '@buoy-gg/impersonate';
123
- * import { queryClient } from './queryClient';
124
- *
125
- * const impersonateTool = createImpersonateTool({
126
- * onSearchUsers: async (query) => {
127
- * const response = await api.searchUsers({ email: query });
128
- * return response.users.map(u => ({
129
- * id: u.id,
130
- * displayName: u.name,
131
- * email: u.email,
132
- * metadata: { role: u.role, createdAt: u.createdAt }
133
- * }));
134
- * },
135
- * onClearReactQuery: () => queryClient.clear(),
136
- * onClearRedux: () => store.dispatch({ type: 'RESET' }),
137
- *
138
- * // Optional: Developer defaults (override hardcoded, overridden by persisted)
139
- * defaults: {
140
- * headerKey: 'x-admin-impersonate',
141
- * showBanner: true, // Show floating banner when impersonating
142
- * dataNukeSettings: {
143
- * reactQuery: true,
144
- * redux: false,
145
- * },
146
- * },
147
- *
148
- * // Optional: Hide settings tab for simple testing
149
- * showSettingsTab: true,
150
- * });
151
- *
152
- * // In your app — mount the banner globally (outside FloatingDevTools)
153
- * // so it survives reloads and stays visible after the modal is closed.
154
- * <FloatingDevTools apps={[impersonateTool]} />
155
- * <ImpersonateBanner position="top" offset={50} />
156
- * ```
157
- */
158
- function createImpersonateTool(config) {
159
- const {
160
- id = "impersonate",
161
- name = "IMPERSONATE",
162
- description = "User impersonation for admin testing",
163
- defaults,
164
- showSettingsTab = true,
165
- onSearchUsers,
166
- onClearReactQuery,
167
- onClearRedux,
168
- onClearAsyncStorage,
169
- onClearMMKV
170
- } = config;
171
-
172
- // Initialize store with developer defaults if provided
173
- if (defaults) {
174
- _impersonateStore.impersonateStore.setDeveloperDefaults(defaults);
175
- }
176
-
177
- // Make the app's user search available to the zero-config external-sync
178
- // adapter (FloatingDevTools auto-sync), so the desktop dashboard can proxy
179
- // searches without separate wiring.
180
- (0, _impersonateSyncAdapter.registerImpersonateSearchUsers)(onSearchUsers ?? null);
181
-
182
- // Patch fetch and restore persisted impersonation state up-front. Fire and
183
- // forget — bootstrapImpersonate guards itself against double-invocation.
184
- void bootstrapImpersonate();
185
-
186
- // Create the tool configuration object
187
- const tool = {
188
- id,
189
- name,
190
- description,
191
- slot: "both",
192
- icon: ({
193
- size,
194
- slot
195
- }) => /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.ImpersonateIcon, {
196
- size: slot === "dial" ? size * 1.5 : size,
197
- color: _sharedUi.IMPERSONATE_ICON_COLOR
198
- }),
199
- component: props => /*#__PURE__*/(0, _jsxRuntime.jsx)(_ImpersonateModal.ImpersonateModal, {
200
- ...props,
201
- onSearchUsers: onSearchUsers,
202
- onClearReactQuery: onClearReactQuery,
203
- onClearRedux: onClearRedux,
204
- onClearAsyncStorage: onClearAsyncStorage,
205
- onClearMMKV: onClearMMKV,
206
- showSettingsTab: showSettingsTab
207
- }),
208
- props: {
209
- enableSharedModalDimensions: false
210
- },
211
- // Export banner component for host app to use
212
- Banner: _ImpersonateBanner.ImpersonateBanner
213
- };
214
- return tool;
215
- }
216
-
217
- // =============================================================================
218
- // STYLES
219
- // =============================================================================
220
-
221
- // =============================================================================
222
- // NOTE: No default preset export
223
- // =============================================================================
224
- // Unlike other tools, the impersonate tool REQUIRES configuration
225
- // (specifically the onSearchUsers callback). Therefore, we don't export
226
- // a default preset. Users must call createImpersonateTool() with their config.
227
- //
228
- // If you want a basic preset for testing without search:
229
- //
230
- // export const impersonateToolPresetBasic = createImpersonateTool({
231
- // onSearchUsers: async () => [],
232
- // });
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});Object.defineProperty(exports,"IMPERSONATE_ICON_COLOR",{enumerable:true,get:function(){return _sharedUi.IMPERSONATE_ICON_COLOR}});Object.defineProperty(exports,"ImpersonateIcon",{enumerable:true,get:function(){return _sharedUi.ImpersonateIcon}});exports.createImpersonateTool=createImpersonateTool;var _asyncStoragePeer=require("./impersonate/hooks/asyncStoragePeer");var _react=_interopRequireDefault(require("react"));var _ImpersonateModal=require("./impersonate/components/ImpersonateModal");var _ImpersonateBanner=require("./impersonate/components/ImpersonateBanner");var _impersonateStore=require("./impersonate/utils/impersonateStore");var _impersonateListener=require("./impersonate/utils/impersonateListener");var _impersonateSyncAdapter=require("./sync/impersonateSyncAdapter");var _sharedUi=require("@buoy-gg/shared-ui");var _jsxRuntime=require("react/jsx-runtime");function _interopRequireDefault(e){return e&&e.__esModule?e:{default:e}}let bootstrapStarted=false;async function bootstrapImpersonate(){if(typeof window==="undefined"||bootstrapStarted)return;bootstrapStarted=true;console.log("[impersonate] bootstrap: start");if(!(0,_impersonateListener.impersonateListener)().isListening){(0,_impersonateListener.impersonateListener)().startListening()}try{const e=(0,_asyncStoragePeer.getAsyncStorage)();if(!e||typeof e.getItem!=="function"){console.warn("[impersonate] bootstrap: AsyncStorage shape unexpected",Object.keys(e??{}));return}const t={getItem:r=>e.getItem(r),setItem:(r,n)=>e.setItem(r,n)};_impersonateStore.impersonateStore.setAsyncStorage(t);console.log("[impersonate] bootstrap: AsyncStorage adapter installed");await _impersonateStore.impersonateStore.initializeAsync(t);console.log("[impersonate] bootstrap: initializeAsync done")}catch(e){console.warn("[impersonate] bootstrap: failed",e)}}function createImpersonateTool(e){const{id:t="impersonate",name:r="IMPERSONATE",description:n="User impersonation for admin testing",defaults:a,showSettingsTab:i=true,onSearchUsers:s,onClearReactQuery:p,onClearRedux:c,onClearAsyncStorage:m,onClearMMKV:u}=e;if(a){_impersonateStore.impersonateStore.setDeveloperDefaults(a)}(0,_impersonateSyncAdapter.registerImpersonateSearchUsers)(s??null);void bootstrapImpersonate();const l={id:t,name:r,description:n,slot:"both",icon:({size:o,slot:d})=>(0,_jsxRuntime.jsx)(_sharedUi.ImpersonateIcon,{size:d==="dial"?o*1.5:o,color:_sharedUi.IMPERSONATE_ICON_COLOR}),component:o=>(0,_jsxRuntime.jsx)(_ImpersonateModal.ImpersonateModal,{...o,onSearchUsers:s,onClearReactQuery:p,onClearRedux:c,onClearAsyncStorage:m,onClearMMKV:u,showSettingsTab:i}),props:{enableSharedModalDimensions:false},Banner:_ImpersonateBanner.ImpersonateBanner};return l}
@@ -1,170 +1 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- exports.SNAPSHOT_URI_INLINE_LIMIT = exports.SNAPSHOT_METADATA_INLINE_LIMIT = void 0;
7
- exports.createImpersonateSyncAdapter = createImpersonateSyncAdapter;
8
- exports.impersonateSyncAdapter = void 0;
9
- exports.registerImpersonateSearchUsers = registerImpersonateSearchUsers;
10
- exports.toWireUri = toWireUri;
11
- var _sharedUi = require("@buoy-gg/shared-ui");
12
- var _impersonateStore = require("../impersonate/utils/impersonateStore");
13
- // Registered by createImpersonateTool, so the zero-config adapter (see
14
- // FloatingDevTools' auto external sync) can proxy the dashboard's user
15
- // search without the app wiring anything twice.
16
- let registeredSearchUsers = null;
17
-
18
- /** @internal Called by createImpersonateTool with the app's onSearchUsers. */
19
- function registerImpersonateSearchUsers(handler) {
20
- registeredSearchUsers = handler;
21
- }
22
-
23
- /**
24
- * `data:` avatar URLs (and any URL over this) are NOT copied onto the
25
- * snapshot. UserCard renders initials, not the image, but apps still put
26
- * base64 photos on `avatarUrl` / dump the API user into `metadata`. Ten
27
- * history entries of those blow the 2MB emit budget and drop the panel.
28
- */
29
- const SNAPSHOT_URI_INLINE_LIMIT = exports.SNAPSHOT_URI_INLINE_LIMIT = 2 * 1024;
30
- const SNAPSHOT_METADATA_INLINE_LIMIT = exports.SNAPSHOT_METADATA_INLINE_LIMIT = 16 * 1024;
31
- const METADATA_ON_DEVICE = Object.freeze({
32
- __buoyOmitted: "user-metadata",
33
- note: "User metadata stays on the device."
34
- });
35
- function toWireUri(uri) {
36
- if (!uri) return uri;
37
- if (uri.startsWith("data:")) {
38
- const comma = uri.indexOf(",");
39
- const header = comma >= 0 ? uri.slice(0, Math.min(comma + 1, 64)) : "data:";
40
- return `${header}[${uri.length} chars]`;
41
- }
42
- if (uri.length <= SNAPSHOT_URI_INLINE_LIMIT) return uri;
43
- return `${uri.slice(0, SNAPSHOT_URI_INLINE_LIMIT)}… [${uri.length - SNAPSHOT_URI_INLINE_LIMIT} more]`;
44
- }
45
- function toWireMetadata(metadata) {
46
- if (!metadata) return metadata;
47
- const role = typeof metadata.role === "string" ? metadata.role : undefined;
48
- if (!(0, _sharedUi.isOverWireBudget)(metadata, SNAPSHOT_METADATA_INLINE_LIMIT)) return metadata;
49
- // Keep `role` so UserCard still badges the impersonated user.
50
- return role ? {
51
- role,
52
- ...METADATA_ON_DEVICE
53
- } : {
54
- ...METADATA_ON_DEVICE
55
- };
56
- }
57
- function toWireUser(user) {
58
- return {
59
- ...user,
60
- avatarUrl: toWireUri(user.avatarUrl),
61
- metadata: toWireMetadata(user.metadata)
62
- };
63
- }
64
- function toWireState(state) {
65
- return {
66
- ...state,
67
- currentUser: state.currentUser ? toWireUser(state.currentUser) : null,
68
- history: state.history.map(entry => ({
69
- ...entry,
70
- user: toWireUser(entry.user)
71
- }))
72
- };
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
- }
96
- function buildActions(onSearchUsers) {
97
- return {
98
- searchUsers: async params => {
99
- const query = String(params?.query ?? "");
100
- const users = await onSearchUsers(query);
101
- if (Array.isArray(users)) rememberUsers(users);
102
- return Array.isArray(users) ? users.map(toWireUser) : users;
103
- },
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
- },
115
- stopImpersonation: () => _impersonateStore.impersonateStore.stopImpersonation(),
116
- pauseImpersonation: () => _impersonateStore.impersonateStore.pauseImpersonation(),
117
- resumeImpersonation: () => _impersonateStore.impersonateStore.resumeImpersonation(),
118
- updateSettings: params => {
119
- // The documented shape is { settings: {...} }, but the flat patch is the
120
- // obvious guess and used to crash with "Cannot read property 'headerKey'
121
- // of undefined". Accept both; refuse anything else by name.
122
-
123
- const p = params ?? {};
124
- const settings = p.settings ?? (["headerKey", "ignorePatterns", "showBanner", "dataNukeSettings"].some(k => k in p) ? p : undefined);
125
- if (!settings) throw new Error("updateSettings needs { settings: { headerKey?, ignorePatterns?, showBanner?, dataNukeSettings? } }.");
126
- return _impersonateStore.impersonateStore.updateSettings(settings);
127
- },
128
- removeFromHistory: params => _impersonateStore.impersonateStore.removeFromHistory(params.userId),
129
- clearHistory: () => _impersonateStore.impersonateStore.clearHistory()
130
- };
131
- }
132
- /**
133
- * Create a sync adapter for the impersonate tool, consumed by
134
- * @buoy-gg/external-sync's `useExternalSync` (structurally matches its
135
- * ToolSyncAdapter interface so this package doesn't need a dependency on it).
136
- *
137
- * The dashboard mirrors the impersonation state and forwards every mutation
138
- * back as an action — header patching, data nuking and persistence all run
139
- * on the device, so impersonating from the desktop behaves exactly like
140
- * tapping the modal on the phone.
141
- */
142
- function createImpersonateSyncAdapter({
143
- onSearchUsers
144
- }) {
145
- return {
146
- version: 1,
147
- getSnapshot: () => toWireState(_impersonateStore.impersonateStore.getState()),
148
- subscribe: onChange => _impersonateStore.impersonateStore.subscribe(onChange),
149
- actions: buildActions(onSearchUsers)
150
- };
151
- }
152
-
153
- /**
154
- * Zero-config variant used by FloatingDevTools' auto external sync. User
155
- * search proxies to the onSearchUsers the app passed to
156
- * createImpersonateTool; if the tool was never configured, the search action
157
- * reports a descriptive error to the dashboard.
158
- */
159
- const impersonateSyncAdapter = exports.impersonateSyncAdapter = {
160
- dispose: () => _impersonateStore.impersonateStore.disposeAccountSession(),
161
- version: 1,
162
- getSnapshot: () => toWireState(_impersonateStore.impersonateStore.getState()),
163
- subscribe: onChange => _impersonateStore.impersonateStore.subscribe(onChange),
164
- actions: buildActions(query => {
165
- if (!registeredSearchUsers) {
166
- throw new Error("No onSearchUsers configured — pass it to createImpersonateTool()");
167
- }
168
- return registeredSearchUsers(query);
169
- })
170
- };
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.SNAPSHOT_URI_INLINE_LIMIT=exports.SNAPSHOT_METADATA_INLINE_LIMIT=void 0;exports.createImpersonateSyncAdapter=createImpersonateSyncAdapter;exports.impersonateSyncAdapter=void 0;exports.registerImpersonateSearchUsers=registerImpersonateSearchUsers;exports.toWireUri=toWireUri;var _sharedUi=require("@buoy-gg/shared-ui");var _impersonateStore=require("../impersonate/utils/impersonateStore");let registeredSearchUsers=null;function registerImpersonateSearchUsers(e){registeredSearchUsers=e}const SNAPSHOT_URI_INLINE_LIMIT=exports.SNAPSHOT_URI_INLINE_LIMIT=2*1024;const SNAPSHOT_METADATA_INLINE_LIMIT=exports.SNAPSHOT_METADATA_INLINE_LIMIT=16*1024;const METADATA_ON_DEVICE=Object.freeze({__buoyOmitted:"user-metadata",note:"User metadata stays on the device."});function toWireUri(e){if(!e)return e;if(e.startsWith("data:")){const r=e.indexOf(",");const t=r>=0?e.slice(0,Math.min(r+1,64)):"data:";return`${t}[${e.length} chars]`}if(e.length<=SNAPSHOT_URI_INLINE_LIMIT)return e;return`${e.slice(0,SNAPSHOT_URI_INLINE_LIMIT)}\u2026 [${e.length-SNAPSHOT_URI_INLINE_LIMIT} more]`}function toWireMetadata(e){if(!e)return e;const r=typeof e.role==="string"?e.role:void 0;if(!(0,_sharedUi.isOverWireBudget)(e,SNAPSHOT_METADATA_INLINE_LIMIT))return e;return r?{role:r,...METADATA_ON_DEVICE}:{...METADATA_ON_DEVICE}}function toWireUser(e){return{...e,avatarUrl:toWireUri(e.avatarUrl),metadata:toWireMetadata(e.metadata)}}function toWireState(e){return{...e,currentUser:e.currentUser?toWireUser(e.currentUser):null,history:e.history.map(r=>({...r,user:toWireUser(r.user)}))}}const seenUserIds=new Set;function rememberUsers(e){for(const r of e){if(r&&typeof r==="object"&&r.id)seenUserIds.add(String(r.id))}}function isKnownUser(e){if(!e||typeof e!=="object"||!e.id)return false;if(seenUserIds.has(String(e.id)))return true;const r=_impersonateStore.impersonateStore.getState();if(r.currentUser?.id===e.id)return true;return r.history.some(t=>t.user.id===e.id)}function buildActions(e){return{searchUsers:async r=>{const t=String(r?.query??"");const s=await e(t);if(Array.isArray(s))rememberUsers(s);return Array.isArray(s)?s.map(toWireUser):s},startImpersonation:async r=>{const t=r?.user;if(!isKnownUser(t)){throw new Error("That user isn't in this app's directory. Call searchUsers and impersonate one of its results \u2014 a user object that didn't come from search impersonates nobody.")}await _impersonateStore.impersonateStore.startImpersonation(t);return{ok:true,userId:t.id}},stopImpersonation:()=>_impersonateStore.impersonateStore.stopImpersonation(),pauseImpersonation:()=>_impersonateStore.impersonateStore.pauseImpersonation(),resumeImpersonation:()=>_impersonateStore.impersonateStore.resumeImpersonation(),updateSettings:r=>{const t=r??{};const s=t.settings??(["headerKey","ignorePatterns","showBanner","dataNukeSettings"].some(o=>o in t)?t:void 0);if(!s)throw new Error("updateSettings needs { settings: { headerKey?, ignorePatterns?, showBanner?, dataNukeSettings? } }.");return _impersonateStore.impersonateStore.updateSettings(s)},removeFromHistory:r=>_impersonateStore.impersonateStore.removeFromHistory(r.userId),clearHistory:()=>_impersonateStore.impersonateStore.clearHistory()}}function createImpersonateSyncAdapter({onSearchUsers:e}){return{version:1,getSnapshot:()=>toWireState(_impersonateStore.impersonateStore.getState()),subscribe:r=>_impersonateStore.impersonateStore.subscribe(r),actions:buildActions(e)}}const impersonateSyncAdapter=exports.impersonateSyncAdapter={dispose:()=>_impersonateStore.impersonateStore.disposeAccountSession(),version:1,getSnapshot:()=>toWireState(_impersonateStore.impersonateStore.getState()),subscribe:e=>_impersonateStore.impersonateStore.subscribe(e),actions:buildActions(e=>{if(!registeredSearchUsers){throw new Error("No onSearchUsers configured \u2014 pass it to createImpersonateTool()")}return registeredSearchUsers(e)})};