@buoy-gg/impersonate 1.0.3-beta.0

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 (95) hide show
  1. package/LICENSE +58 -0
  2. package/lib/commonjs/impersonate/components/DataNukeSettings.js +715 -0
  3. package/lib/commonjs/impersonate/components/ImpersonateBanner.js +217 -0
  4. package/lib/commonjs/impersonate/components/ImpersonateHistoryList.js +173 -0
  5. package/lib/commonjs/impersonate/components/ImpersonateModal.js +304 -0
  6. package/lib/commonjs/impersonate/components/ImpersonateStatusBar.js +130 -0
  7. package/lib/commonjs/impersonate/components/UserAvatar.js +146 -0
  8. package/lib/commonjs/impersonate/components/UserCard.js +200 -0
  9. package/lib/commonjs/impersonate/components/UserSearchView.js +227 -0
  10. package/lib/commonjs/impersonate/components/index.js +85 -0
  11. package/lib/commonjs/impersonate/hooks/index.js +64 -0
  12. package/lib/commonjs/impersonate/hooks/useAutoClearAsyncStorage.js +144 -0
  13. package/lib/commonjs/impersonate/hooks/useAutoClearReactQuery.js +155 -0
  14. package/lib/commonjs/impersonate/hooks/useAutoClearRedux.js +188 -0
  15. package/lib/commonjs/impersonate/hooks/useImpersonate.js +215 -0
  16. package/lib/commonjs/impersonate/hooks/useImpersonateHistory.js +56 -0
  17. package/lib/commonjs/impersonate/index.js +49 -0
  18. package/lib/commonjs/impersonate/types/index.js +16 -0
  19. package/lib/commonjs/impersonate/types/types.js +1 -0
  20. package/lib/commonjs/impersonate/utils/impersonateListener.js +280 -0
  21. package/lib/commonjs/impersonate/utils/impersonateStore.js +607 -0
  22. package/lib/commonjs/impersonate/utils/index.js +49 -0
  23. package/lib/commonjs/index.js +118 -0
  24. package/lib/commonjs/package.json +1 -0
  25. package/lib/commonjs/preset.js +214 -0
  26. package/lib/module/impersonate/components/DataNukeSettings.js +710 -0
  27. package/lib/module/impersonate/components/ImpersonateBanner.js +211 -0
  28. package/lib/module/impersonate/components/ImpersonateHistoryList.js +168 -0
  29. package/lib/module/impersonate/components/ImpersonateModal.js +300 -0
  30. package/lib/module/impersonate/components/ImpersonateStatusBar.js +125 -0
  31. package/lib/module/impersonate/components/UserAvatar.js +140 -0
  32. package/lib/module/impersonate/components/UserCard.js +195 -0
  33. package/lib/module/impersonate/components/UserSearchView.js +222 -0
  34. package/lib/module/impersonate/components/index.js +11 -0
  35. package/lib/module/impersonate/hooks/index.js +7 -0
  36. package/lib/module/impersonate/hooks/useAutoClearAsyncStorage.js +140 -0
  37. package/lib/module/impersonate/hooks/useAutoClearReactQuery.js +151 -0
  38. package/lib/module/impersonate/hooks/useAutoClearRedux.js +183 -0
  39. package/lib/module/impersonate/hooks/useImpersonate.js +212 -0
  40. package/lib/module/impersonate/hooks/useImpersonateHistory.js +52 -0
  41. package/lib/module/impersonate/index.js +13 -0
  42. package/lib/module/impersonate/types/index.js +3 -0
  43. package/lib/module/impersonate/types/types.js +1 -0
  44. package/lib/module/impersonate/utils/impersonateListener.js +271 -0
  45. package/lib/module/impersonate/utils/impersonateStore.js +604 -0
  46. package/lib/module/impersonate/utils/index.js +4 -0
  47. package/lib/module/index.js +103 -0
  48. package/lib/module/preset.js +209 -0
  49. package/lib/typescript/impersonate/components/DataNukeSettings.d.ts +37 -0
  50. package/lib/typescript/impersonate/components/DataNukeSettings.d.ts.map +1 -0
  51. package/lib/typescript/impersonate/components/ImpersonateBanner.d.ts +40 -0
  52. package/lib/typescript/impersonate/components/ImpersonateBanner.d.ts.map +1 -0
  53. package/lib/typescript/impersonate/components/ImpersonateHistoryList.d.ts +24 -0
  54. package/lib/typescript/impersonate/components/ImpersonateHistoryList.d.ts.map +1 -0
  55. package/lib/typescript/impersonate/components/ImpersonateModal.d.ts +10 -0
  56. package/lib/typescript/impersonate/components/ImpersonateModal.d.ts.map +1 -0
  57. package/lib/typescript/impersonate/components/ImpersonateStatusBar.d.ts +15 -0
  58. package/lib/typescript/impersonate/components/ImpersonateStatusBar.d.ts.map +1 -0
  59. package/lib/typescript/impersonate/components/UserAvatar.d.ts +32 -0
  60. package/lib/typescript/impersonate/components/UserAvatar.d.ts.map +1 -0
  61. package/lib/typescript/impersonate/components/UserCard.d.ts +28 -0
  62. package/lib/typescript/impersonate/components/UserCard.d.ts.map +1 -0
  63. package/lib/typescript/impersonate/components/UserSearchView.d.ts +31 -0
  64. package/lib/typescript/impersonate/components/UserSearchView.d.ts.map +1 -0
  65. package/lib/typescript/impersonate/components/index.d.ts +16 -0
  66. package/lib/typescript/impersonate/components/index.d.ts.map +1 -0
  67. package/lib/typescript/impersonate/hooks/index.d.ts +11 -0
  68. package/lib/typescript/impersonate/hooks/index.d.ts.map +1 -0
  69. package/lib/typescript/impersonate/hooks/useAutoClearAsyncStorage.d.ts +48 -0
  70. package/lib/typescript/impersonate/hooks/useAutoClearAsyncStorage.d.ts.map +1 -0
  71. package/lib/typescript/impersonate/hooks/useAutoClearReactQuery.d.ts +48 -0
  72. package/lib/typescript/impersonate/hooks/useAutoClearReactQuery.d.ts.map +1 -0
  73. package/lib/typescript/impersonate/hooks/useAutoClearRedux.d.ts +78 -0
  74. package/lib/typescript/impersonate/hooks/useAutoClearRedux.d.ts.map +1 -0
  75. package/lib/typescript/impersonate/hooks/useImpersonate.d.ts +76 -0
  76. package/lib/typescript/impersonate/hooks/useImpersonate.d.ts.map +1 -0
  77. package/lib/typescript/impersonate/hooks/useImpersonateHistory.d.ts +43 -0
  78. package/lib/typescript/impersonate/hooks/useImpersonateHistory.d.ts.map +1 -0
  79. package/lib/typescript/impersonate/index.d.ts +5 -0
  80. package/lib/typescript/impersonate/index.d.ts.map +1 -0
  81. package/lib/typescript/impersonate/types/index.d.ts +2 -0
  82. package/lib/typescript/impersonate/types/index.d.ts.map +1 -0
  83. package/lib/typescript/impersonate/types/types.d.ts +177 -0
  84. package/lib/typescript/impersonate/types/types.d.ts.map +1 -0
  85. package/lib/typescript/impersonate/utils/impersonateListener.d.ts +115 -0
  86. package/lib/typescript/impersonate/utils/impersonateListener.d.ts.map +1 -0
  87. package/lib/typescript/impersonate/utils/impersonateStore.d.ts +151 -0
  88. package/lib/typescript/impersonate/utils/impersonateStore.d.ts.map +1 -0
  89. package/lib/typescript/impersonate/utils/index.d.ts +3 -0
  90. package/lib/typescript/impersonate/utils/index.d.ts.map +1 -0
  91. package/lib/typescript/index.d.ts +80 -0
  92. package/lib/typescript/index.d.ts.map +1 -0
  93. package/lib/typescript/preset.d.ts +71 -0
  94. package/lib/typescript/preset.d.ts.map +1 -0
  95. package/package.json +78 -0
@@ -0,0 +1,85 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ Object.defineProperty(exports, "AVATAR_COLORS", {
7
+ enumerable: true,
8
+ get: function () {
9
+ return _UserAvatar.AVATAR_COLORS;
10
+ }
11
+ });
12
+ Object.defineProperty(exports, "DataNukeSettingsComponent", {
13
+ enumerable: true,
14
+ get: function () {
15
+ return _DataNukeSettings.DataNukeSettings;
16
+ }
17
+ });
18
+ Object.defineProperty(exports, "ImpersonateBanner", {
19
+ enumerable: true,
20
+ get: function () {
21
+ return _ImpersonateBanner.ImpersonateBanner;
22
+ }
23
+ });
24
+ Object.defineProperty(exports, "ImpersonateBannerMinimal", {
25
+ enumerable: true,
26
+ get: function () {
27
+ return _ImpersonateBanner.ImpersonateBannerMinimal;
28
+ }
29
+ });
30
+ Object.defineProperty(exports, "ImpersonateHistoryList", {
31
+ enumerable: true,
32
+ get: function () {
33
+ return _ImpersonateHistoryList.ImpersonateHistoryList;
34
+ }
35
+ });
36
+ Object.defineProperty(exports, "ImpersonateModal", {
37
+ enumerable: true,
38
+ get: function () {
39
+ return _ImpersonateModal.ImpersonateModal;
40
+ }
41
+ });
42
+ Object.defineProperty(exports, "ImpersonateStatusBar", {
43
+ enumerable: true,
44
+ get: function () {
45
+ return _ImpersonateStatusBar.ImpersonateStatusBar;
46
+ }
47
+ });
48
+ Object.defineProperty(exports, "UserAvatar", {
49
+ enumerable: true,
50
+ get: function () {
51
+ return _UserAvatar.UserAvatar;
52
+ }
53
+ });
54
+ Object.defineProperty(exports, "UserCard", {
55
+ enumerable: true,
56
+ get: function () {
57
+ return _UserCard.UserCard;
58
+ }
59
+ });
60
+ Object.defineProperty(exports, "UserSearchView", {
61
+ enumerable: true,
62
+ get: function () {
63
+ return _UserSearchView.UserSearchView;
64
+ }
65
+ });
66
+ Object.defineProperty(exports, "getAvatarColor", {
67
+ enumerable: true,
68
+ get: function () {
69
+ return _UserAvatar.getAvatarColor;
70
+ }
71
+ });
72
+ Object.defineProperty(exports, "getInitials", {
73
+ enumerable: true,
74
+ get: function () {
75
+ return _UserAvatar.getInitials;
76
+ }
77
+ });
78
+ var _UserSearchView = require("./UserSearchView");
79
+ var _DataNukeSettings = require("./DataNukeSettings");
80
+ var _ImpersonateHistoryList = require("./ImpersonateHistoryList");
81
+ var _ImpersonateModal = require("./ImpersonateModal");
82
+ var _ImpersonateBanner = require("./ImpersonateBanner");
83
+ var _ImpersonateStatusBar = require("./ImpersonateStatusBar");
84
+ var _UserAvatar = require("./UserAvatar");
85
+ var _UserCard = require("./UserCard");
@@ -0,0 +1,64 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ Object.defineProperty(exports, "REDUX_RESET_ACTION_TYPE", {
7
+ enumerable: true,
8
+ get: function () {
9
+ return _useAutoClearRedux.REDUX_RESET_ACTION_TYPE;
10
+ }
11
+ });
12
+ Object.defineProperty(exports, "useAsyncStorageAvailability", {
13
+ enumerable: true,
14
+ get: function () {
15
+ return _useAutoClearAsyncStorage.useAsyncStorageAvailability;
16
+ }
17
+ });
18
+ Object.defineProperty(exports, "useAutoClearAsyncStorage", {
19
+ enumerable: true,
20
+ get: function () {
21
+ return _useAutoClearAsyncStorage.useAutoClearAsyncStorage;
22
+ }
23
+ });
24
+ Object.defineProperty(exports, "useAutoClearReactQuery", {
25
+ enumerable: true,
26
+ get: function () {
27
+ return _useAutoClearReactQuery.useAutoClearReactQuery;
28
+ }
29
+ });
30
+ Object.defineProperty(exports, "useAutoClearRedux", {
31
+ enumerable: true,
32
+ get: function () {
33
+ return _useAutoClearRedux.useAutoClearRedux;
34
+ }
35
+ });
36
+ Object.defineProperty(exports, "useImpersonate", {
37
+ enumerable: true,
38
+ get: function () {
39
+ return _useImpersonate.useImpersonate;
40
+ }
41
+ });
42
+ Object.defineProperty(exports, "useImpersonateHistory", {
43
+ enumerable: true,
44
+ get: function () {
45
+ return _useImpersonateHistory.useImpersonateHistory;
46
+ }
47
+ });
48
+ Object.defineProperty(exports, "useReactQueryAvailability", {
49
+ enumerable: true,
50
+ get: function () {
51
+ return _useAutoClearReactQuery.useReactQueryAvailability;
52
+ }
53
+ });
54
+ Object.defineProperty(exports, "useReduxAvailability", {
55
+ enumerable: true,
56
+ get: function () {
57
+ return _useAutoClearRedux.useReduxAvailability;
58
+ }
59
+ });
60
+ var _useImpersonate = require("./useImpersonate");
61
+ var _useImpersonateHistory = require("./useImpersonateHistory");
62
+ var _useAutoClearReactQuery = require("./useAutoClearReactQuery");
63
+ var _useAutoClearRedux = require("./useAutoClearRedux");
64
+ var _useAutoClearAsyncStorage = require("./useAutoClearAsyncStorage");
@@ -0,0 +1,144 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.useAsyncStorageAvailability = useAsyncStorageAvailability;
7
+ exports.useAutoClearAsyncStorage = useAutoClearAsyncStorage;
8
+ var _react = require("react");
9
+ /**
10
+ * useAutoClearAsyncStorage Hook
11
+ *
12
+ * Auto-detects AsyncStorage and provides a clear function.
13
+ * Follows the same pattern as useAutoClearReactQuery and useAutoClearRedux.
14
+ *
15
+ * This hook:
16
+ * 1. Dynamically requires @react-native-async-storage/async-storage
17
+ * 2. Returns a clearStorage function that removes all non-buoy keys
18
+ *
19
+ * IMPORTANT: This preserves all @buoy/* keys to avoid clearing our own state.
20
+ */
21
+
22
+ // ============================================
23
+ // Types
24
+ // ============================================
25
+
26
+ // Flag to prevent double-firing (synchronous check)
27
+ let isClearing = false;
28
+ // ============================================
29
+ // Safe Module Loading
30
+ // ============================================
31
+
32
+ /**
33
+ * Safely attempt to load @react-native-async-storage/async-storage
34
+ */
35
+ function getAsyncStorage() {
36
+ try {
37
+ // Dynamic require to handle cases where async-storage isn't installed
38
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
39
+ const AsyncStorage = require("@react-native-async-storage/async-storage").default;
40
+ return AsyncStorage;
41
+ } catch {
42
+ // @react-native-async-storage/async-storage not available
43
+ return null;
44
+ }
45
+ }
46
+
47
+ // ============================================
48
+ // Main Hook
49
+ // ============================================
50
+
51
+ /**
52
+ * Hook to auto-detect AsyncStorage and provide clearing functionality.
53
+ *
54
+ * This clears all keys EXCEPT those starting with @buoy/ to preserve
55
+ * our own persisted state (impersonation settings, history, etc.).
56
+ *
57
+ * @example
58
+ * ```tsx
59
+ * function MyComponent() {
60
+ * const { isAvailable, clearStorage } = useAutoClearAsyncStorage();
61
+ *
62
+ * if (isAvailable && clearStorage) {
63
+ * // Clear all app data except Buoy state
64
+ * await clearStorage();
65
+ * }
66
+ * }
67
+ * ```
68
+ */
69
+ function useAutoClearAsyncStorage() {
70
+ const [asyncStorage, setAsyncStorage] = (0, _react.useState)(null);
71
+ const [error, setError] = (0, _react.useState)(null);
72
+
73
+ // Check for AsyncStorage on mount
74
+ (0, _react.useEffect)(() => {
75
+ const storage = getAsyncStorage();
76
+ if (storage) {
77
+ setAsyncStorage(storage);
78
+ setError(null);
79
+ } else {
80
+ setError("@react-native-async-storage/async-storage is not installed");
81
+ }
82
+ }, []);
83
+
84
+ // Create the clearStorage function with guard to prevent double-firing
85
+ const clearStorage = (0, _react.useCallback)(async () => {
86
+ // Synchronous guard - set flag immediately before any async work
87
+ if (isClearing) {
88
+ return;
89
+ }
90
+ isClearing = true;
91
+ try {
92
+ if (asyncStorage) {
93
+ // Get all keys
94
+ const allKeys = await asyncStorage.getAllKeys();
95
+
96
+ // Filter out @buoy/* keys to preserve our own state
97
+ const keysToRemove = allKeys.filter(key => !key.startsWith("@buoy/") && !key.startsWith("@buoy-"));
98
+ if (keysToRemove.length > 0) {
99
+ await asyncStorage.multiRemove([...keysToRemove]);
100
+ }
101
+ }
102
+ } finally {
103
+ // Reset flag after a short delay to allow next legitimate call
104
+ setTimeout(() => {
105
+ isClearing = false;
106
+ }, 100);
107
+ }
108
+ }, [asyncStorage]);
109
+
110
+ // Memoize result
111
+ const result = (0, _react.useMemo)(() => {
112
+ if (!asyncStorage || error) {
113
+ return {
114
+ isAvailable: false,
115
+ error: error || "@react-native-async-storage/async-storage is not available",
116
+ clearStorage: null
117
+ };
118
+ }
119
+ return {
120
+ isAvailable: true,
121
+ error: null,
122
+ clearStorage
123
+ };
124
+ }, [asyncStorage, error, clearStorage]);
125
+ return result;
126
+ }
127
+
128
+ /**
129
+ * Lightweight check to see if AsyncStorage is available
130
+ * without creating the clear function
131
+ */
132
+ function useAsyncStorageAvailability() {
133
+ const storage = getAsyncStorage();
134
+ if (!storage) {
135
+ return {
136
+ isInstalled: false,
137
+ error: "@react-native-async-storage/async-storage is not installed"
138
+ };
139
+ }
140
+ return {
141
+ isInstalled: true,
142
+ error: null
143
+ };
144
+ }
@@ -0,0 +1,155 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.useAutoClearReactQuery = useAutoClearReactQuery;
7
+ exports.useReactQueryAvailability = useReactQueryAvailability;
8
+ var _react = require("react");
9
+ /**
10
+ * useAutoClearReactQuery Hook
11
+ *
12
+ * Auto-detects React Query and provides a clear function.
13
+ * Uses the same pattern as @buoy-gg/redux's useAutoInstrumentRedux.
14
+ *
15
+ * This hook:
16
+ * 1. Dynamically requires @tanstack/react-query
17
+ * 2. Uses useQueryClient() to get the client from context
18
+ * 3. Returns a clearCache function that clears queries + mutations
19
+ */
20
+
21
+ // ============================================
22
+ // Types
23
+ // ============================================
24
+
25
+ // Flag to prevent double-firing (synchronous check)
26
+ let isClearing = false;
27
+ // ============================================
28
+ // Safe Module Loading
29
+ // ============================================
30
+
31
+ /**
32
+ * Safely attempt to load @tanstack/react-query and get useQueryClient hook
33
+ */
34
+ function getReactQueryUseQueryClient() {
35
+ try {
36
+ // Dynamic require to handle cases where react-query isn't installed
37
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
38
+ const reactQuery = require("@tanstack/react-query");
39
+ return reactQuery.useQueryClient;
40
+ } catch {
41
+ // @tanstack/react-query not available
42
+ return null;
43
+ }
44
+ }
45
+
46
+ // ============================================
47
+ // Main Hook
48
+ // ============================================
49
+
50
+ /**
51
+ * Hook to auto-detect React Query and provide cache clearing functionality.
52
+ *
53
+ * This mirrors how the react-query package's QueryBrowserModal.tsx clears cache:
54
+ * `queryClient.getQueryCache().clear()`
55
+ *
56
+ * @example
57
+ * ```tsx
58
+ * function MyComponent() {
59
+ * const { isAvailable, clearCache } = useAutoClearReactQuery();
60
+ *
61
+ * if (isAvailable && clearCache) {
62
+ * // Can clear React Query cache
63
+ * clearCache();
64
+ * }
65
+ * }
66
+ * ```
67
+ */
68
+ function useAutoClearReactQuery() {
69
+ // Check if @tanstack/react-query is available
70
+ const useQueryClientHook = getReactQueryUseQueryClient();
71
+ const isReactQueryInstalled = useQueryClientHook !== null;
72
+
73
+ // Try to get the query client using react-query's useQueryClient
74
+ // This must be called unconditionally due to hooks rules
75
+ let queryClient = null;
76
+ let clientError = null;
77
+ if (useQueryClientHook) {
78
+ try {
79
+ // eslint-disable-next-line react-hooks/rules-of-hooks
80
+ queryClient = useQueryClientHook();
81
+ } catch (e) {
82
+ // Not inside a QueryClientProvider or other error
83
+ clientError = e instanceof Error ? e.message : "Failed to access QueryClient. Make sure your app is wrapped in a QueryClientProvider.";
84
+ }
85
+ } else {
86
+ clientError = "@tanstack/react-query is not installed";
87
+ }
88
+
89
+ // Create the clearCache function with guard to prevent double-firing
90
+ const clearCache = (0, _react.useCallback)(() => {
91
+ // Synchronous guard - set flag immediately before any async work
92
+ if (isClearing) {
93
+ return;
94
+ }
95
+ isClearing = true;
96
+ if (queryClient) {
97
+ // Clear both query and mutation caches
98
+ // This is the same approach used in @buoy-gg/react-query
99
+ queryClient.getQueryCache().clear();
100
+ queryClient.getMutationCache().clear();
101
+ }
102
+
103
+ // Reset flag after a short delay to allow next legitimate call
104
+ setTimeout(() => {
105
+ isClearing = false;
106
+ }, 100);
107
+ }, [queryClient]);
108
+
109
+ // Memoize result
110
+ const result = (0, _react.useMemo)(() => {
111
+ if (!isReactQueryInstalled || clientError || !queryClient) {
112
+ return {
113
+ isAvailable: false,
114
+ error: clientError,
115
+ clearCache: null
116
+ };
117
+ }
118
+ return {
119
+ isAvailable: true,
120
+ error: null,
121
+ clearCache
122
+ };
123
+ }, [isReactQueryInstalled, clientError, queryClient, clearCache]);
124
+ return result;
125
+ }
126
+
127
+ /**
128
+ * Lightweight hook to just check if React Query is available
129
+ * without getting the client
130
+ */
131
+ function useReactQueryAvailability() {
132
+ const useQueryClientHook = getReactQueryUseQueryClient();
133
+ if (!useQueryClientHook) {
134
+ return {
135
+ isInstalled: false,
136
+ isConnected: false,
137
+ error: "@tanstack/react-query is not installed"
138
+ };
139
+ }
140
+ try {
141
+ // eslint-disable-next-line react-hooks/rules-of-hooks
142
+ const client = useQueryClientHook();
143
+ return {
144
+ isInstalled: true,
145
+ isConnected: client !== null && client !== undefined,
146
+ error: null
147
+ };
148
+ } catch (e) {
149
+ return {
150
+ isInstalled: true,
151
+ isConnected: false,
152
+ error: e instanceof Error ? e.message : "Not inside a QueryClientProvider"
153
+ };
154
+ }
155
+ }
@@ -0,0 +1,188 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.REDUX_RESET_ACTION_TYPE = void 0;
7
+ exports.useAutoClearRedux = useAutoClearRedux;
8
+ exports.useReduxAvailability = useReduxAvailability;
9
+ var _react = require("react");
10
+ /**
11
+ * useAutoClearRedux Hook
12
+ *
13
+ * Auto-detects Redux store and provides a reset function.
14
+ * Uses the same pattern as @buoy-gg/redux's useAutoInstrumentRedux.
15
+ *
16
+ * This hook:
17
+ * 1. Dynamically requires react-redux
18
+ * 2. Uses useStore() to get the store from context
19
+ * 3. Returns a resetStore function that dispatches a reset action
20
+ *
21
+ * IMPORTANT: Unlike React Query which has a universal .clear() method,
22
+ * Redux reset requires the app's reducer to handle the reset action.
23
+ * The default action type is '@@RESET' but can be customized.
24
+ *
25
+ * Example reducer handling:
26
+ * ```typescript
27
+ * const rootReducer = (state, action) => {
28
+ * if (action.type === '@@RESET') {
29
+ * return undefined; // Returns to initial state
30
+ * }
31
+ * return appReducer(state, action);
32
+ * };
33
+ * ```
34
+ */
35
+
36
+ // ============================================
37
+ // Types
38
+ // ============================================
39
+
40
+ // Flag to prevent double-firing (synchronous check)
41
+ let isDispatching = false;
42
+
43
+ /** The default action type dispatched to reset Redux state */
44
+ const REDUX_RESET_ACTION_TYPE = exports.REDUX_RESET_ACTION_TYPE = "@@RESET";
45
+ // ============================================
46
+ // Safe Module Loading
47
+ // ============================================
48
+
49
+ /**
50
+ * Safely attempt to load react-redux and get useStore hook
51
+ */
52
+ function getReactReduxUseStore() {
53
+ try {
54
+ // Dynamic require to handle cases where react-redux isn't installed
55
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
56
+ const reactRedux = require("react-redux");
57
+ return reactRedux.useStore;
58
+ } catch {
59
+ // react-redux not available
60
+ return null;
61
+ }
62
+ }
63
+
64
+ // ============================================
65
+ // Main Hook
66
+ // ============================================
67
+
68
+ /**
69
+ * Hook to auto-detect Redux store and provide state reset functionality.
70
+ *
71
+ * This dispatches a reset action (default: '@@RESET') to the store.
72
+ * Your app's root reducer must handle this action to actually reset state.
73
+ *
74
+ * @example
75
+ * ```tsx
76
+ * // In your component:
77
+ * function MyComponent() {
78
+ * const { isAvailable, resetStore } = useAutoClearRedux();
79
+ *
80
+ * if (isAvailable && resetStore) {
81
+ * resetStore(); // Dispatches { type: '@@RESET' }
82
+ * }
83
+ * }
84
+ *
85
+ * // In your root reducer:
86
+ * const rootReducer = (state, action) => {
87
+ * if (action.type === '@@RESET') {
88
+ * // Return undefined to reset to initial state
89
+ * // Or return a specific "logged out" state
90
+ * return undefined;
91
+ * }
92
+ * return appReducer(state, action);
93
+ * };
94
+ * ```
95
+ */
96
+ function useAutoClearRedux(options = {}) {
97
+ const {
98
+ resetActionType = REDUX_RESET_ACTION_TYPE
99
+ } = options;
100
+
101
+ // Check if react-redux is available
102
+ const useStoreHook = getReactReduxUseStore();
103
+ const isReactReduxInstalled = useStoreHook !== null;
104
+
105
+ // Try to get the store using react-redux's useStore
106
+ // This must be called unconditionally due to hooks rules
107
+ let store = null;
108
+ let storeError = null;
109
+ if (useStoreHook) {
110
+ try {
111
+ // eslint-disable-next-line react-hooks/rules-of-hooks
112
+ store = useStoreHook();
113
+ } catch (e) {
114
+ // Not inside a Provider or other error
115
+ storeError = e instanceof Error ? e.message : "Failed to access Redux store. Make sure your app is wrapped in a Redux Provider.";
116
+ }
117
+ } else {
118
+ storeError = "react-redux is not installed";
119
+ }
120
+
121
+ // Create the resetStore function with guard to prevent double-firing
122
+ const resetStore = (0, _react.useCallback)(() => {
123
+ // Synchronous guard - set flag immediately before any async work
124
+ if (isDispatching) {
125
+ return;
126
+ }
127
+ isDispatching = true;
128
+ if (store) {
129
+ // Dispatch the reset action
130
+ // The app's root reducer must handle this to actually reset state
131
+ store.dispatch({
132
+ type: resetActionType
133
+ });
134
+ }
135
+
136
+ // Reset flag after a short delay to allow next legitimate call
137
+ setTimeout(() => {
138
+ isDispatching = false;
139
+ }, 100);
140
+ }, [store, resetActionType]);
141
+
142
+ // Memoize result
143
+ const result = (0, _react.useMemo)(() => {
144
+ if (!isReactReduxInstalled || storeError || !store) {
145
+ return {
146
+ isAvailable: false,
147
+ error: storeError,
148
+ resetStore: null
149
+ };
150
+ }
151
+ return {
152
+ isAvailable: true,
153
+ error: null,
154
+ resetStore
155
+ };
156
+ }, [isReactReduxInstalled, storeError, store, resetStore]);
157
+ return result;
158
+ }
159
+
160
+ /**
161
+ * Lightweight hook to just check if Redux is available
162
+ * without getting the store
163
+ */
164
+ function useReduxAvailability() {
165
+ const useStoreHook = getReactReduxUseStore();
166
+ if (!useStoreHook) {
167
+ return {
168
+ isInstalled: false,
169
+ isConnected: false,
170
+ error: "react-redux is not installed"
171
+ };
172
+ }
173
+ try {
174
+ // eslint-disable-next-line react-hooks/rules-of-hooks
175
+ const store = useStoreHook();
176
+ return {
177
+ isInstalled: true,
178
+ isConnected: store !== null && store !== undefined,
179
+ error: null
180
+ };
181
+ } catch (e) {
182
+ return {
183
+ isInstalled: true,
184
+ isConnected: false,
185
+ error: e instanceof Error ? e.message : "Not inside a Redux Provider"
186
+ };
187
+ }
188
+ }