@buoy-gg/impersonate 7.0.35 → 7.0.38

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/README.md CHANGED
@@ -2,9 +2,9 @@
2
2
 
3
3
  [![npm version](https://img.shields.io/npm/v/@buoy-gg/impersonate?style=flat-square&labelColor=1c1c1c&color=10B981)](https://www.npmjs.com/package/@buoy-gg/impersonate) [![npm downloads](https://img.shields.io/npm/dm/@buoy-gg/impersonate?style=flat-square&labelColor=1c1c1c&color=10B981)](https://www.npmjs.com/package/@buoy-gg/impersonate)
4
4
 
5
- **Test your app as any user, role, or flag combination — without logging out, switching accounts, or rebuilding.**
5
+ Connect your app’s user-switching flow to Buoy so testers can switch test accounts, roles, or flags without rebuilding.
6
6
 
7
- Part of [Buoy](https://github.com/Buoy-gg/buoy) — devtools that live inside your React Native app. Install it and it auto-appears in the floating menu from [`@buoy-gg/core`](https://www.npmjs.com/package/@buoy-gg/core).
7
+ Part of [Buoy](https://github.com/Buoy-gg/buoy). Install the package, complete account setup, and follow the integration steps below.
8
8
 
9
9
  ## Install
10
10
 
@@ -12,6 +12,24 @@ Part of [Buoy](https://github.com/Buoy-gg/buoy) — devtools that live inside yo
12
12
  npm install @buoy-gg/core @buoy-gg/impersonate
13
13
  ```
14
14
 
15
+ ## Before you start
16
+
17
+ Use a development build with `@buoy-gg/core` and a Free or Pro Buoy account key. From your app’s directory, sign in:
18
+
19
+ ```bash
20
+ npx --package=@buoy-gg/core buoy login
21
+ ```
22
+
23
+ For Expo, initialize Buoy before rendering the menu:
24
+
25
+ ```tsx
26
+ import { Buoy } from "@buoy-gg/core";
27
+
28
+ Buoy.init({ licenseKey: process.env.EXPO_PUBLIC_BUOY_KEY });
29
+ ```
30
+
31
+ The login command writes the Expo key to `.env.local`. For React Native CLI, pass the key from your app’s environment configuration; React Native does not load `.env.local` automatically. Mount `FloatingDevTools` inside the same providers as your screens and restart the development server after installation. The [Quick Start](https://buoy.gg/buoy/latest/docs/quick-start) shows the complete root component setup.
32
+
15
33
  ## Quick start
16
34
 
17
35
  Unlike most Buoy tools, this one needs a little config — it has to know how to search *your* users:
@@ -42,13 +60,17 @@ export default function App() {
42
60
  }
43
61
  ```
44
62
 
45
- While impersonating, every outgoing `fetch` and `XMLHttpRequest` carries `x-impersonate-user-id: <id>` (header name configurable via `defaults.headerKey`). Your backend checks the header — after verifying the caller is an admin — and returns data for that user instead.
63
+ While impersonating, requests passing through the patched global `fetch` and `XMLHttpRequest` carries `x-impersonate-user-id: <id>` (header name configurable via `defaults.headerKey`). Your backend checks the header — after verifying the caller is an admin — and returns data for that user instead.
64
+
65
+ ## Check the integration
66
+
67
+ Switch between two test accounts and confirm both the visible identity and subsequent authenticated requests. Your backend must authorize the switch. Redux clearing requires a reducer that handles `@@RESET` or your own reset callback; Buoy cannot infer your app’s reset behavior.
46
68
 
47
69
  ## What you get
48
70
 
49
- - **Header injection everywhere** — patches `fetch` and XHR at startup, so even requests fired during app boot carry the impersonation header
50
- - **Auto data clearing** — detects `@tanstack/react-query` and `react-redux` and clears the query cache / resets the store on every user switch, no callbacks needed (AsyncStorage/MMKV clearing via optional callbacks)
51
- - **Floating banner** — appears automatically whenever impersonation is active, so you can never forget whose eyes you're looking through
71
+ - **Header injection** — adds the configured header through patched global fetch and XHR paths while impersonation is active
72
+ - **Data clearing** — supports query-cache clearing and Redux reset integration. Your reducer must handle `@@RESET`, or provide a reset callback. Storage clearing uses optional callbacks
73
+ - **Floating banner** — identifies the active impersonation when the banner is enabled
52
74
  - **Pause vs stop** — the banner's power button pauses header injection for instant A/B against your real account; X stops the session and triggers data clearing
53
75
  - **History** — quick-switch between your last 10 impersonated users, persisted across app restarts
54
76
  - **Developer defaults** — ship team-wide defaults for header name, banner, and clearing behavior; the Settings tab exports your current config as paste-ready code
@@ -56,11 +78,11 @@ While impersonating, every outgoing `fetch` and `XMLHttpRequest` carries `x-impe
56
78
 
57
79
  ## Desktop & AI
58
80
 
59
- The same live session streams to [Buoy Desktop](https://github.com/Buoy-gg/Buoy-Desktop) (free, macOS/Windows/Linux) and to Claude Code or Cursor via the [Buoy MCP server](https://buoy.gg/buoy/latest/docs/mcp).
81
+ To connect a React Native app to [Buoy Desktop](https://github.com/Buoy-gg/Buoy-Desktop) or MCP, install `@buoy-gg/external-sync` and follow the [Desktop connection guide](https://buoy.gg/buoy/latest/docs/desktop). Sign in to Desktop separately. [MCP setup](https://buoy.gg/buoy/latest/docs/mcp) also requires a process account and Pro access. Available remote actions depend on the tool and app integration.
60
82
 
61
- ## Free vs Pro
83
+ ## Account and plan requirements
62
84
 
63
- Every tool is free. [Pro](https://buoy.gg/pricing) unlocks production builds, the MCP server, and unlimited capture. Every weekend, Pro features unlock free for anyone holding a key — including a free one (`npx buoy login`).
85
+ Use a Free or Pro Buoy account. History limits and paid features vary by tool; see [pricing](https://buoy.gg/pricing). Production access requires Pro where supported. Development-only hooks and actions remain unavailable in release builds.
64
86
 
65
87
  ---
66
88
 
@@ -52,13 +52,13 @@ function UserCard({
52
52
  style: [styles.name, isActive && styles.activeName],
53
53
  numberOfLines: 1,
54
54
  children: displayName
55
- }), role && /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
55
+ }), role ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
56
56
  style: styles.roleBadge,
57
57
  children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
58
58
  style: styles.roleBadgeText,
59
59
  children: role.toUpperCase()
60
60
  })
61
- })]
61
+ }) : null]
62
62
  }), showEmail && /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
63
63
  style: styles.email,
64
64
  numberOfLines: 1,
@@ -93,10 +93,10 @@ function UserCard({
93
93
  color: _sharedUi.night.color.textTertiary
94
94
  })
95
95
  })]
96
- }), lastUsedTime && /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
96
+ }), lastUsedTime ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
97
97
  style: styles.lastUsed,
98
98
  children: lastUsedTime
99
- })]
99
+ }) : null]
100
100
  });
101
101
  }
102
102
  const styles = _reactNative.StyleSheet.create({
@@ -68,7 +68,7 @@ function UserSearchView({
68
68
  style: styles.loadingText,
69
69
  children: "Searching users..."
70
70
  })]
71
- }), searchError && /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
71
+ }), searchError ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
72
72
  style: styles.section,
73
73
  children: /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
74
74
  style: styles.errorCard,
@@ -80,7 +80,7 @@ function UserSearchView({
80
80
  children: searchError
81
81
  })]
82
82
  })
83
- }), searchResults.length > 0 && /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
83
+ }) : null, searchResults.length > 0 && /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
84
84
  style: styles.resultsSection,
85
85
  children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_sharedUi.SectionHeader, {
86
86
  children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.SectionHeader.Title, {
@@ -98,7 +98,7 @@ function UserSearchView({
98
98
  contentContainerStyle: styles.listContent,
99
99
  showsVerticalScrollIndicator: false
100
100
  })]
101
- }), searchQuery && !isSearching && searchResults.length === 0 && !searchError && /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
101
+ }), !!searchQuery && !isSearching && searchResults.length === 0 && !searchError && /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
102
102
  style: styles.emptyStateContainer,
103
103
  children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
104
104
  style: styles.emptyStateIcon,
@@ -4,6 +4,7 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.impersonateStore = void 0;
7
+ var _sharedUi = require("@buoy-gg/shared-ui");
7
8
  var _impersonateListener = require("./impersonateListener");
8
9
  /**
9
10
  * Impersonate Store - State Management with Persistence
@@ -110,6 +111,13 @@ class ImpersonateStore {
110
111
  constructor() {
111
112
  // Try to load persisted state synchronously
112
113
  this.loadFromStorage();
114
+ Promise.resolve().then(() => {
115
+ const reconcile = () => {
116
+ if (!(0, _sharedUi.hasAccountAccess)()) this.disposeAccountSession();
117
+ };
118
+ (0, _sharedUi.subscribeAccountAccess)(reconcile);
119
+ reconcile();
120
+ });
113
121
 
114
122
  // Check if localStorage is available (web) - if so, storage is ready
115
123
  if (typeof localStorage !== "undefined") {
@@ -350,6 +358,7 @@ class ImpersonateStore {
350
358
  * the visual symptom of "I clicked a user and nothing changed."
351
359
  */
352
360
  async startImpersonation(user) {
361
+ (0, _sharedUi.assertAccountAccess)();
353
362
  if (this.remoteHandler) {
354
363
  this.remoteHandler("startImpersonation", {
355
364
  user
@@ -436,6 +445,7 @@ class ImpersonateStore {
436
445
  * Resume impersonation (start injecting headers again)
437
446
  */
438
447
  async resumeImpersonation() {
448
+ (0, _sharedUi.assertAccountAccess)();
439
449
  if (this.remoteHandler) {
440
450
  this.remoteHandler("resumeImpersonation");
441
451
  return;
@@ -578,9 +588,22 @@ class ImpersonateStore {
578
588
  /**
579
589
  * Sync current state with the impersonateListener
580
590
  */
591
+ /** Remove only the active header override. Sign-out must not nuke host caches. */
592
+ disposeAccountSession() {
593
+ if (this.remoteHandler || !this.state.isActive) return;
594
+ this.state = {
595
+ ...this.state,
596
+ isActive: false,
597
+ isPaused: false,
598
+ currentUser: null
599
+ };
600
+ this.syncWithListener();
601
+ this.notify();
602
+ void this.persist();
603
+ }
581
604
  syncWithListener() {
582
605
  // When paused, don't inject headers (pass null userId)
583
- const shouldInject = this.state.isActive && !this.state.isPaused;
606
+ const shouldInject = (0, _sharedUi.hasAccountAccess)() && this.state.isActive && !this.state.isPaused;
584
607
  (0, _impersonateListener.setImpersonateConfig)({
585
608
  headerKey: this.state.headerKey,
586
609
  userId: shouldInject ? this.state.currentUser?.id ?? null : null,
@@ -190,9 +190,10 @@ function createImpersonateTool(config) {
190
190
  description,
191
191
  slot: "both",
192
192
  icon: ({
193
- size
193
+ size,
194
+ slot
194
195
  }) => /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.ImpersonateIcon, {
195
- size: size,
196
+ size: slot === "dial" ? size * 1.5 : size,
196
197
  color: _sharedUi.IMPERSONATE_ICON_COLOR
197
198
  }),
198
199
  component: props => /*#__PURE__*/(0, _jsxRuntime.jsx)(_ImpersonateModal.ImpersonateModal, {
@@ -148,6 +148,7 @@ function createImpersonateSyncAdapter({
148
148
  * reports a descriptive error to the dashboard.
149
149
  */
150
150
  const impersonateSyncAdapter = exports.impersonateSyncAdapter = {
151
+ dispose: () => _impersonateStore.impersonateStore.disposeAccountSession(),
151
152
  version: 1,
152
153
  getSnapshot: () => toWireState(_impersonateStore.impersonateStore.getState()),
153
154
  subscribe: onChange => _impersonateStore.impersonateStore.subscribe(onChange),
@@ -47,13 +47,13 @@ export function UserCard({
47
47
  style: [styles.name, isActive && styles.activeName],
48
48
  numberOfLines: 1,
49
49
  children: displayName
50
- }), role && /*#__PURE__*/_jsx(View, {
50
+ }), role ? /*#__PURE__*/_jsx(View, {
51
51
  style: styles.roleBadge,
52
52
  children: /*#__PURE__*/_jsx(Text, {
53
53
  style: styles.roleBadgeText,
54
54
  children: role.toUpperCase()
55
55
  })
56
- })]
56
+ }) : null]
57
57
  }), showEmail && /*#__PURE__*/_jsx(Text, {
58
58
  style: styles.email,
59
59
  numberOfLines: 1,
@@ -88,10 +88,10 @@ export function UserCard({
88
88
  color: night.color.textTertiary
89
89
  })
90
90
  })]
91
- }), lastUsedTime && /*#__PURE__*/_jsx(Text, {
91
+ }), lastUsedTime ? /*#__PURE__*/_jsx(Text, {
92
92
  style: styles.lastUsed,
93
93
  children: lastUsedTime
94
- })]
94
+ }) : null]
95
95
  });
96
96
  }
97
97
  const styles = StyleSheet.create({
@@ -63,7 +63,7 @@ export function UserSearchView({
63
63
  style: styles.loadingText,
64
64
  children: "Searching users..."
65
65
  })]
66
- }), searchError && /*#__PURE__*/_jsx(View, {
66
+ }), searchError ? /*#__PURE__*/_jsx(View, {
67
67
  style: styles.section,
68
68
  children: /*#__PURE__*/_jsxs(View, {
69
69
  style: styles.errorCard,
@@ -75,7 +75,7 @@ export function UserSearchView({
75
75
  children: searchError
76
76
  })]
77
77
  })
78
- }), searchResults.length > 0 && /*#__PURE__*/_jsxs(View, {
78
+ }) : null, searchResults.length > 0 && /*#__PURE__*/_jsxs(View, {
79
79
  style: styles.resultsSection,
80
80
  children: [/*#__PURE__*/_jsxs(SectionHeader, {
81
81
  children: [/*#__PURE__*/_jsx(SectionHeader.Title, {
@@ -93,7 +93,7 @@ export function UserSearchView({
93
93
  contentContainerStyle: styles.listContent,
94
94
  showsVerticalScrollIndicator: false
95
95
  })]
96
- }), searchQuery && !isSearching && searchResults.length === 0 && !searchError && /*#__PURE__*/_jsxs(View, {
96
+ }), !!searchQuery && !isSearching && searchResults.length === 0 && !searchError && /*#__PURE__*/_jsxs(View, {
97
97
  style: styles.emptyStateContainer,
98
98
  children: [/*#__PURE__*/_jsx(View, {
99
99
  style: styles.emptyStateIcon,
@@ -1,5 +1,6 @@
1
1
  "use strict";
2
2
 
3
+ import { assertAccountAccess, hasAccountAccess, subscribeAccountAccess } from "@buoy-gg/shared-ui";
3
4
  /**
4
5
  * Impersonate Store - State Management with Persistence
5
6
  *
@@ -107,6 +108,13 @@ class ImpersonateStore {
107
108
  constructor() {
108
109
  // Try to load persisted state synchronously
109
110
  this.loadFromStorage();
111
+ Promise.resolve().then(() => {
112
+ const reconcile = () => {
113
+ if (!hasAccountAccess()) this.disposeAccountSession();
114
+ };
115
+ subscribeAccountAccess(reconcile);
116
+ reconcile();
117
+ });
110
118
 
111
119
  // Check if localStorage is available (web) - if so, storage is ready
112
120
  if (typeof localStorage !== "undefined") {
@@ -347,6 +355,7 @@ class ImpersonateStore {
347
355
  * the visual symptom of "I clicked a user and nothing changed."
348
356
  */
349
357
  async startImpersonation(user) {
358
+ assertAccountAccess();
350
359
  if (this.remoteHandler) {
351
360
  this.remoteHandler("startImpersonation", {
352
361
  user
@@ -433,6 +442,7 @@ class ImpersonateStore {
433
442
  * Resume impersonation (start injecting headers again)
434
443
  */
435
444
  async resumeImpersonation() {
445
+ assertAccountAccess();
436
446
  if (this.remoteHandler) {
437
447
  this.remoteHandler("resumeImpersonation");
438
448
  return;
@@ -575,9 +585,22 @@ class ImpersonateStore {
575
585
  /**
576
586
  * Sync current state with the impersonateListener
577
587
  */
588
+ /** Remove only the active header override. Sign-out must not nuke host caches. */
589
+ disposeAccountSession() {
590
+ if (this.remoteHandler || !this.state.isActive) return;
591
+ this.state = {
592
+ ...this.state,
593
+ isActive: false,
594
+ isPaused: false,
595
+ currentUser: null
596
+ };
597
+ this.syncWithListener();
598
+ this.notify();
599
+ void this.persist();
600
+ }
578
601
  syncWithListener() {
579
602
  // When paused, don't inject headers (pass null userId)
580
- const shouldInject = this.state.isActive && !this.state.isPaused;
603
+ const shouldInject = hasAccountAccess() && this.state.isActive && !this.state.isPaused;
581
604
  setImpersonateConfig({
582
605
  headerKey: this.state.headerKey,
583
606
  userId: shouldInject ? this.state.currentUser?.id ?? null : null,
@@ -174,9 +174,10 @@ export function createImpersonateTool(config) {
174
174
  description,
175
175
  slot: "both",
176
176
  icon: ({
177
- size
177
+ size,
178
+ slot
178
179
  }) => /*#__PURE__*/_jsx(ImpersonateIcon, {
179
- size: size,
180
+ size: slot === "dial" ? size * 1.5 : size,
180
181
  color: IMPERSONATE_ICON_COLOR
181
182
  }),
182
183
  component: props => /*#__PURE__*/_jsx(ImpersonateModal, {
@@ -140,6 +140,7 @@ export function createImpersonateSyncAdapter({
140
140
  * reports a descriptive error to the dashboard.
141
141
  */
142
142
  export const impersonateSyncAdapter = {
143
+ dispose: () => impersonateStore.disposeAccountSession(),
143
144
  version: 1,
144
145
  getSnapshot: () => toWireState(impersonateStore.getState()),
145
146
  subscribe: onChange => impersonateStore.subscribe(onChange),
@@ -147,6 +147,8 @@ declare class ImpersonateStore {
147
147
  /**
148
148
  * Sync current state with the impersonateListener
149
149
  */
150
+ /** Remove only the active header override. Sign-out must not nuke host caches. */
151
+ disposeAccountSession(): void;
150
152
  private syncWithListener;
151
153
  /**
152
154
  * Persist state to storage
@@ -1 +1 @@
1
- {"version":3,"file":"impersonateStore.d.ts","sourceRoot":"","sources":["../../../../src/impersonate/utils/impersonateStore.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"impersonateStore.d.ts","sourceRoot":"","sources":["../../../../src/impersonate/utils/impersonateStore.ts"],"names":[],"mappings":"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"}
@@ -66,8 +66,9 @@ export declare function createImpersonateTool(config: ImpersonateToolConfig): {
66
66
  name: string;
67
67
  description: string;
68
68
  slot: "both";
69
- icon: ({ size }: {
69
+ icon: ({ size, slot }: {
70
70
  size: number;
71
+ slot?: string;
71
72
  }) => React.JSX.Element;
72
73
  component: (props: {
73
74
  visible: boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"preset.d.ts","sourceRoot":"","sources":["../../src/preset.tsx"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,EAAE,iBAAiB,EAAE,MAAM,4CAA4C,CAAC;AAI/E,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAyEjE;;;;;;;GAOG;AACH,OAAO,EAAE,eAAe,EAAE,sBAAsB,EAAE,MAAM,oBAAoB,CAAC;AAE7E,OAAO,EAAE,eAAe,EAAE,sBAAsB,EAAE,CAAC;AAWnD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2CG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,qBAAqB;;;;;qBAkC9C;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE;uBAGd;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,OAAO,EAAE,MAAM,IAAI,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;QAAC,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAA;KAAE;;;;;EAmB3H"}
1
+ {"version":3,"file":"preset.d.ts","sourceRoot":"","sources":["../../src/preset.tsx"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,EAAE,iBAAiB,EAAE,MAAM,4CAA4C,CAAC;AAI/E,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAyEjE;;;;;;;GAOG;AACH,OAAO,EAAE,eAAe,EAAE,sBAAsB,EAAE,MAAM,oBAAoB,CAAC;AAE7E,OAAO,EAAE,eAAe,EAAE,sBAAsB,EAAE,CAAC;AAWnD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2CG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,qBAAqB;;;;;2BAkCxC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE;uBAGnC;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,OAAO,EAAE,MAAM,IAAI,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;QAAC,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAA;KAAE;;;;;EAmB3H"}
@@ -53,6 +53,7 @@ export declare function createImpersonateSyncAdapter({ onSearchUsers, }: CreateI
53
53
  * reports a descriptive error to the dashboard.
54
54
  */
55
55
  export declare const impersonateSyncAdapter: {
56
+ dispose: () => void;
56
57
  version: number;
57
58
  getSnapshot: () => ImpersonationState;
58
59
  subscribe: (onChange: () => void) => () => 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;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"}
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;;;uBAGhB,kBAAkB;0BACb,MAAM,IAAI;;8BA1EF,OAAO;sCAQC,OAAO;;;;;;;kCAajB,OAAO;qCAQJ,OAAO;;;CAsDvC,CAAC"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@buoy-gg/impersonate",
3
- "version": "7.0.35",
4
- "description": "Test your React Native app as any user, role, or flag combo — without logging out or rebuilding. Part of Buoy devtools.",
3
+ "version": "7.0.38",
4
+ "description": "Configure impersonation headers for supported app requests. Your backend must authenticate and authorize user changes.",
5
5
  "main": "lib/commonjs/index.js",
6
6
  "module": "lib/module/index.js",
7
7
  "types": "lib/typescript/index.d.ts",
@@ -26,7 +26,7 @@
26
26
  ],
27
27
  "sideEffects": false,
28
28
  "dependencies": {
29
- "@buoy-gg/shared-ui": "^7.0.35"
29
+ "@buoy-gg/shared-ui": "^7.0.38"
30
30
  },
31
31
  "peerDependencies": {
32
32
  "react": "*",