@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.
- package/LICENSE +58 -0
- package/lib/commonjs/impersonate/components/DataNukeSettings.js +715 -0
- package/lib/commonjs/impersonate/components/ImpersonateBanner.js +217 -0
- package/lib/commonjs/impersonate/components/ImpersonateHistoryList.js +173 -0
- package/lib/commonjs/impersonate/components/ImpersonateModal.js +304 -0
- package/lib/commonjs/impersonate/components/ImpersonateStatusBar.js +130 -0
- package/lib/commonjs/impersonate/components/UserAvatar.js +146 -0
- package/lib/commonjs/impersonate/components/UserCard.js +200 -0
- package/lib/commonjs/impersonate/components/UserSearchView.js +227 -0
- package/lib/commonjs/impersonate/components/index.js +85 -0
- package/lib/commonjs/impersonate/hooks/index.js +64 -0
- package/lib/commonjs/impersonate/hooks/useAutoClearAsyncStorage.js +144 -0
- package/lib/commonjs/impersonate/hooks/useAutoClearReactQuery.js +155 -0
- package/lib/commonjs/impersonate/hooks/useAutoClearRedux.js +188 -0
- package/lib/commonjs/impersonate/hooks/useImpersonate.js +215 -0
- package/lib/commonjs/impersonate/hooks/useImpersonateHistory.js +56 -0
- package/lib/commonjs/impersonate/index.js +49 -0
- package/lib/commonjs/impersonate/types/index.js +16 -0
- package/lib/commonjs/impersonate/types/types.js +1 -0
- package/lib/commonjs/impersonate/utils/impersonateListener.js +280 -0
- package/lib/commonjs/impersonate/utils/impersonateStore.js +607 -0
- package/lib/commonjs/impersonate/utils/index.js +49 -0
- package/lib/commonjs/index.js +118 -0
- package/lib/commonjs/package.json +1 -0
- package/lib/commonjs/preset.js +214 -0
- package/lib/module/impersonate/components/DataNukeSettings.js +710 -0
- package/lib/module/impersonate/components/ImpersonateBanner.js +211 -0
- package/lib/module/impersonate/components/ImpersonateHistoryList.js +168 -0
- package/lib/module/impersonate/components/ImpersonateModal.js +300 -0
- package/lib/module/impersonate/components/ImpersonateStatusBar.js +125 -0
- package/lib/module/impersonate/components/UserAvatar.js +140 -0
- package/lib/module/impersonate/components/UserCard.js +195 -0
- package/lib/module/impersonate/components/UserSearchView.js +222 -0
- package/lib/module/impersonate/components/index.js +11 -0
- package/lib/module/impersonate/hooks/index.js +7 -0
- package/lib/module/impersonate/hooks/useAutoClearAsyncStorage.js +140 -0
- package/lib/module/impersonate/hooks/useAutoClearReactQuery.js +151 -0
- package/lib/module/impersonate/hooks/useAutoClearRedux.js +183 -0
- package/lib/module/impersonate/hooks/useImpersonate.js +212 -0
- package/lib/module/impersonate/hooks/useImpersonateHistory.js +52 -0
- package/lib/module/impersonate/index.js +13 -0
- package/lib/module/impersonate/types/index.js +3 -0
- package/lib/module/impersonate/types/types.js +1 -0
- package/lib/module/impersonate/utils/impersonateListener.js +271 -0
- package/lib/module/impersonate/utils/impersonateStore.js +604 -0
- package/lib/module/impersonate/utils/index.js +4 -0
- package/lib/module/index.js +103 -0
- package/lib/module/preset.js +209 -0
- package/lib/typescript/impersonate/components/DataNukeSettings.d.ts +37 -0
- package/lib/typescript/impersonate/components/DataNukeSettings.d.ts.map +1 -0
- package/lib/typescript/impersonate/components/ImpersonateBanner.d.ts +40 -0
- package/lib/typescript/impersonate/components/ImpersonateBanner.d.ts.map +1 -0
- package/lib/typescript/impersonate/components/ImpersonateHistoryList.d.ts +24 -0
- package/lib/typescript/impersonate/components/ImpersonateHistoryList.d.ts.map +1 -0
- package/lib/typescript/impersonate/components/ImpersonateModal.d.ts +10 -0
- package/lib/typescript/impersonate/components/ImpersonateModal.d.ts.map +1 -0
- package/lib/typescript/impersonate/components/ImpersonateStatusBar.d.ts +15 -0
- package/lib/typescript/impersonate/components/ImpersonateStatusBar.d.ts.map +1 -0
- package/lib/typescript/impersonate/components/UserAvatar.d.ts +32 -0
- package/lib/typescript/impersonate/components/UserAvatar.d.ts.map +1 -0
- package/lib/typescript/impersonate/components/UserCard.d.ts +28 -0
- package/lib/typescript/impersonate/components/UserCard.d.ts.map +1 -0
- package/lib/typescript/impersonate/components/UserSearchView.d.ts +31 -0
- package/lib/typescript/impersonate/components/UserSearchView.d.ts.map +1 -0
- package/lib/typescript/impersonate/components/index.d.ts +16 -0
- package/lib/typescript/impersonate/components/index.d.ts.map +1 -0
- package/lib/typescript/impersonate/hooks/index.d.ts +11 -0
- package/lib/typescript/impersonate/hooks/index.d.ts.map +1 -0
- package/lib/typescript/impersonate/hooks/useAutoClearAsyncStorage.d.ts +48 -0
- package/lib/typescript/impersonate/hooks/useAutoClearAsyncStorage.d.ts.map +1 -0
- package/lib/typescript/impersonate/hooks/useAutoClearReactQuery.d.ts +48 -0
- package/lib/typescript/impersonate/hooks/useAutoClearReactQuery.d.ts.map +1 -0
- package/lib/typescript/impersonate/hooks/useAutoClearRedux.d.ts +78 -0
- package/lib/typescript/impersonate/hooks/useAutoClearRedux.d.ts.map +1 -0
- package/lib/typescript/impersonate/hooks/useImpersonate.d.ts +76 -0
- package/lib/typescript/impersonate/hooks/useImpersonate.d.ts.map +1 -0
- package/lib/typescript/impersonate/hooks/useImpersonateHistory.d.ts +43 -0
- package/lib/typescript/impersonate/hooks/useImpersonateHistory.d.ts.map +1 -0
- package/lib/typescript/impersonate/index.d.ts +5 -0
- package/lib/typescript/impersonate/index.d.ts.map +1 -0
- package/lib/typescript/impersonate/types/index.d.ts +2 -0
- package/lib/typescript/impersonate/types/index.d.ts.map +1 -0
- package/lib/typescript/impersonate/types/types.d.ts +177 -0
- package/lib/typescript/impersonate/types/types.d.ts.map +1 -0
- package/lib/typescript/impersonate/utils/impersonateListener.d.ts +115 -0
- package/lib/typescript/impersonate/utils/impersonateListener.d.ts.map +1 -0
- package/lib/typescript/impersonate/utils/impersonateStore.d.ts +151 -0
- package/lib/typescript/impersonate/utils/impersonateStore.d.ts.map +1 -0
- package/lib/typescript/impersonate/utils/index.d.ts +3 -0
- package/lib/typescript/impersonate/utils/index.d.ts.map +1 -0
- package/lib/typescript/index.d.ts +80 -0
- package/lib/typescript/index.d.ts.map +1 -0
- package/lib/typescript/preset.d.ts +71 -0
- package/lib/typescript/preset.d.ts.map +1 -0
- 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
|
+
}
|