@adventurelabs/scout-core 1.0.108 → 1.0.109
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/dist/hooks/useScoutRefresh.js +29 -12
- package/dist/store/hooks.d.ts +0 -2
- package/dist/store/hooks.js +0 -8
- package/package.json +1 -1
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { useEffect, useCallback, useRef } from "react";
|
|
2
|
-
import { useAppDispatch
|
|
2
|
+
import { useAppDispatch } from "../store/hooks";
|
|
3
|
+
import { useStore } from "react-redux";
|
|
3
4
|
import { EnumScoutStateStatus, setHerdModules, setStatus, setHerdModulesLoadingState, setHerdModulesLoadedInMs, setHerdModulesApiDuration, setUserApiDuration, setDataProcessingDuration, setUser, setDataSource, setDataSourceInfo, } from "../store/scout";
|
|
4
5
|
import { EnumHerdModulesLoadingState } from "../types/herd_module";
|
|
5
6
|
import { server_load_herd_modules } from "../helpers/herds";
|
|
@@ -33,8 +34,7 @@ export function useScoutRefresh(options = {}) {
|
|
|
33
34
|
const { autoRefresh = true, onRefreshComplete, cacheFirst = true, cacheTtlMs = 24 * 60 * 60 * 1000, // 24 hours default (1 day)
|
|
34
35
|
} = options;
|
|
35
36
|
const dispatch = useAppDispatch();
|
|
36
|
-
const
|
|
37
|
-
const currentUser = useUser();
|
|
37
|
+
const store = useStore();
|
|
38
38
|
const refreshInProgressRef = useRef(false);
|
|
39
39
|
// Refs to store timing measurements
|
|
40
40
|
const timingRefs = useRef({
|
|
@@ -46,7 +46,7 @@ export function useScoutRefresh(options = {}) {
|
|
|
46
46
|
cacheSaveDuration: 0,
|
|
47
47
|
});
|
|
48
48
|
// Helper function for deep comparison of objects
|
|
49
|
-
const deepEqual = useCallback((obj1, obj2) => {
|
|
49
|
+
const deepEqual = useCallback((obj1, obj2, visited = new WeakMap()) => {
|
|
50
50
|
if (obj1 === obj2)
|
|
51
51
|
return true;
|
|
52
52
|
if (obj1 == null || obj2 == null)
|
|
@@ -55,13 +55,22 @@ export function useScoutRefresh(options = {}) {
|
|
|
55
55
|
return false;
|
|
56
56
|
if (typeof obj1 !== "object")
|
|
57
57
|
return obj1 === obj2;
|
|
58
|
+
// Handle circular references
|
|
59
|
+
if (visited.has(obj1)) {
|
|
60
|
+
return visited.get(obj1) === obj2;
|
|
61
|
+
}
|
|
62
|
+
visited.set(obj1, obj2);
|
|
63
|
+
// Handle Date objects
|
|
64
|
+
if (obj1 instanceof Date && obj2 instanceof Date) {
|
|
65
|
+
return obj1.getTime() === obj2.getTime();
|
|
66
|
+
}
|
|
58
67
|
if (Array.isArray(obj1) !== Array.isArray(obj2))
|
|
59
68
|
return false;
|
|
60
69
|
if (Array.isArray(obj1)) {
|
|
61
70
|
if (obj1.length !== obj2.length)
|
|
62
71
|
return false;
|
|
63
72
|
for (let i = 0; i < obj1.length; i++) {
|
|
64
|
-
if (!deepEqual(obj1[i], obj2[i]))
|
|
73
|
+
if (!deepEqual(obj1[i], obj2[i], visited))
|
|
65
74
|
return false;
|
|
66
75
|
}
|
|
67
76
|
return true;
|
|
@@ -73,7 +82,7 @@ export function useScoutRefresh(options = {}) {
|
|
|
73
82
|
for (const key of keys1) {
|
|
74
83
|
if (!keys2.includes(key))
|
|
75
84
|
return false;
|
|
76
|
-
if (!deepEqual(obj1[key], obj2[key]))
|
|
85
|
+
if (!deepEqual(obj1[key], obj2[key], visited))
|
|
77
86
|
return false;
|
|
78
87
|
}
|
|
79
88
|
return true;
|
|
@@ -90,8 +99,8 @@ export function useScoutRefresh(options = {}) {
|
|
|
90
99
|
return false;
|
|
91
100
|
}
|
|
92
101
|
}, [dispatch, deepEqual]);
|
|
93
|
-
// Helper function to handle IndexedDB errors
|
|
94
|
-
const handleIndexedDbError = async (error, operation, retryFn) => {
|
|
102
|
+
// Helper function to handle IndexedDB errors - memoized for stability
|
|
103
|
+
const handleIndexedDbError = useCallback(async (error, operation, retryFn) => {
|
|
95
104
|
if (error instanceof Error &&
|
|
96
105
|
(error.message.includes("object store") ||
|
|
97
106
|
error.message.includes("NotFoundError"))) {
|
|
@@ -108,7 +117,7 @@ export function useScoutRefresh(options = {}) {
|
|
|
108
117
|
console.error(`[useScoutRefresh] Database reset and retry failed:`, resetError);
|
|
109
118
|
}
|
|
110
119
|
}
|
|
111
|
-
};
|
|
120
|
+
}, []);
|
|
112
121
|
const handleRefresh = useCallback(async () => {
|
|
113
122
|
// Prevent concurrent refresh calls
|
|
114
123
|
if (refreshInProgressRef.current) {
|
|
@@ -143,6 +152,8 @@ export function useScoutRefresh(options = {}) {
|
|
|
143
152
|
isStale: cacheResult.isStale,
|
|
144
153
|
}));
|
|
145
154
|
// Conditionally update the store with cached data if different
|
|
155
|
+
// Get current state at execution time to avoid dependency issues
|
|
156
|
+
const currentHerdModules = store.getState().scout.herd_modules;
|
|
146
157
|
const herdModulesChanged = conditionalDispatch(cachedHerdModules, currentHerdModules, setHerdModules, "Herd modules (cache)");
|
|
147
158
|
if (herdModulesChanged) {
|
|
148
159
|
dispatch(setHerdModulesLoadingState(EnumHerdModulesLoadingState.SUCCESSFULLY_LOADED));
|
|
@@ -154,6 +165,7 @@ export function useScoutRefresh(options = {}) {
|
|
|
154
165
|
timingRefs.current.userApiDuration = userApiDuration;
|
|
155
166
|
dispatch(setUserApiDuration(userApiDuration));
|
|
156
167
|
if (res_new_user && res_new_user.data) {
|
|
168
|
+
const currentUser = store.getState().scout.user;
|
|
157
169
|
conditionalDispatch(res_new_user.data, currentUser, setUser, "User (initial)");
|
|
158
170
|
}
|
|
159
171
|
// If cache is fresh, we still background fetch but don't wait
|
|
@@ -189,6 +201,8 @@ export function useScoutRefresh(options = {}) {
|
|
|
189
201
|
});
|
|
190
202
|
}
|
|
191
203
|
// Conditionally update store with fresh background data
|
|
204
|
+
const currentHerdModules = store.getState().scout.herd_modules;
|
|
205
|
+
const currentUser = store.getState().scout.user;
|
|
192
206
|
conditionalDispatch(backgroundHerdModulesResult.data, currentHerdModules, setHerdModules, "Herd modules (background)");
|
|
193
207
|
conditionalDispatch(backgroundUserResult.data, currentUser, setUser, "User (background)");
|
|
194
208
|
// Update data source to DATABASE
|
|
@@ -294,6 +308,8 @@ export function useScoutRefresh(options = {}) {
|
|
|
294
308
|
}
|
|
295
309
|
// Step 4: Conditionally update store with fresh data if different
|
|
296
310
|
const dataProcessingStartTime = Date.now();
|
|
311
|
+
const currentHerdModules = store.getState().scout.herd_modules;
|
|
312
|
+
const currentUser = store.getState().scout.user;
|
|
297
313
|
const herdModulesChanged = conditionalDispatch(compatible_new_herd_modules, currentHerdModules, setHerdModules, "Herd modules (fresh API)");
|
|
298
314
|
const userChanged = conditionalDispatch(res_new_user.data, currentUser, setUser, "User (fresh API)");
|
|
299
315
|
if (herdModulesChanged) {
|
|
@@ -334,19 +350,20 @@ export function useScoutRefresh(options = {}) {
|
|
|
334
350
|
console.log(` - Total duration: ${loadingDuration}ms`);
|
|
335
351
|
console.log(` - Herd modules: ${timingRefs.current.herdModulesDuration}ms`);
|
|
336
352
|
console.log(` - User API: ${timingRefs.current.userApiDuration}ms`);
|
|
353
|
+
// Call completion callback even on error for consistency
|
|
354
|
+
onRefreshComplete?.();
|
|
337
355
|
}
|
|
338
356
|
finally {
|
|
339
357
|
refreshInProgressRef.current = false;
|
|
340
358
|
}
|
|
341
359
|
}, [
|
|
342
360
|
dispatch,
|
|
361
|
+
store,
|
|
343
362
|
onRefreshComplete,
|
|
344
363
|
cacheFirst,
|
|
345
364
|
cacheTtlMs,
|
|
346
|
-
handleIndexedDbError,
|
|
347
|
-
currentHerdModules,
|
|
348
|
-
currentUser,
|
|
349
365
|
conditionalDispatch,
|
|
366
|
+
handleIndexedDbError,
|
|
350
367
|
]);
|
|
351
368
|
useEffect(() => {
|
|
352
369
|
if (autoRefresh) {
|
package/dist/store/hooks.d.ts
CHANGED
|
@@ -1,6 +1,4 @@
|
|
|
1
1
|
export declare const useAppDispatch: import("react-redux").UseDispatch<import("redux").Dispatch<import("redux").UnknownAction>>;
|
|
2
|
-
export declare const useHerdModules: () => import("../types/herd_module").IHerdModule[];
|
|
3
|
-
export declare const useUser: () => import("@supabase/auth-js").User | null;
|
|
4
2
|
export declare const useHerdModulesLoadingState: () => any;
|
|
5
3
|
export declare const useIsHerdModulesLoading: () => boolean;
|
|
6
4
|
export declare const useIsHerdModulesLoaded: () => boolean;
|
package/dist/store/hooks.js
CHANGED
|
@@ -2,14 +2,6 @@ import { useDispatch, useSelector } from "react-redux";
|
|
|
2
2
|
import { EnumHerdModulesLoadingState } from "../types/herd_module";
|
|
3
3
|
// Simple wrapper for useDispatch to maintain compatibility
|
|
4
4
|
export const useAppDispatch = useDispatch;
|
|
5
|
-
// Selector hook for current herd modules
|
|
6
|
-
export const useHerdModules = () => {
|
|
7
|
-
return useSelector((state) => state.scout.herd_modules);
|
|
8
|
-
};
|
|
9
|
-
// Selector hook for current user
|
|
10
|
-
export const useUser = () => {
|
|
11
|
-
return useSelector((state) => state.scout.user);
|
|
12
|
-
};
|
|
13
5
|
// Selector hook for herd modules loading state
|
|
14
6
|
export const useHerdModulesLoadingState = () => {
|
|
15
7
|
return useSelector((state) => state.scout.herd_modules_loading_state);
|