@adventurelabs/scout-core 1.0.109 → 1.0.110
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 +64 -30
- package/package.json +1 -1
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import { useEffect, useCallback, useRef } from "react";
|
|
1
|
+
import { useEffect, useCallback, useRef, useMemo } from "react";
|
|
2
2
|
import { useAppDispatch } from "../store/hooks";
|
|
3
3
|
import { useStore } from "react-redux";
|
|
4
4
|
import { EnumScoutStateStatus, setHerdModules, setStatus, setHerdModulesLoadingState, setHerdModulesLoadedInMs, setHerdModulesApiDuration, setUserApiDuration, setDataProcessingDuration, setUser, setDataSource, setDataSourceInfo, } from "../store/scout";
|
|
5
5
|
import { EnumHerdModulesLoadingState } from "../types/herd_module";
|
|
6
6
|
import { server_load_herd_modules } from "../helpers/herds";
|
|
7
|
-
import { server_get_user } from "../helpers/users";
|
|
8
7
|
import { scoutCache } from "../helpers/cache";
|
|
9
8
|
import { EnumDataSource } from "../types/data_source";
|
|
9
|
+
import { createBrowserClient } from "@supabase/ssr";
|
|
10
10
|
/**
|
|
11
11
|
* Hook for refreshing scout data with detailed timing measurements and cache-first loading
|
|
12
12
|
*
|
|
@@ -36,6 +36,10 @@ export function useScoutRefresh(options = {}) {
|
|
|
36
36
|
const dispatch = useAppDispatch();
|
|
37
37
|
const store = useStore();
|
|
38
38
|
const refreshInProgressRef = useRef(false);
|
|
39
|
+
// Create Supabase client directly to avoid circular dependency
|
|
40
|
+
const supabase = useMemo(() => {
|
|
41
|
+
return createBrowserClient(process.env.NEXT_PUBLIC_SUPABASE_URL || "", process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY || "");
|
|
42
|
+
}, []);
|
|
39
43
|
// Refs to store timing measurements
|
|
40
44
|
const timingRefs = useRef({
|
|
41
45
|
startTime: 0,
|
|
@@ -87,18 +91,37 @@ export function useScoutRefresh(options = {}) {
|
|
|
87
91
|
}
|
|
88
92
|
return true;
|
|
89
93
|
}, []);
|
|
90
|
-
// Helper function to
|
|
91
|
-
const
|
|
92
|
-
if (!
|
|
93
|
-
|
|
94
|
-
|
|
94
|
+
// Helper function to normalize herd modules for comparison (excludes metadata)
|
|
95
|
+
const normalizeHerdModulesForComparison = useCallback((herdModules) => {
|
|
96
|
+
if (!Array.isArray(herdModules))
|
|
97
|
+
return herdModules;
|
|
98
|
+
return herdModules.map((hm) => {
|
|
99
|
+
if (!hm || typeof hm !== "object")
|
|
100
|
+
return hm;
|
|
101
|
+
// Create a copy without metadata fields that don't represent business data changes
|
|
102
|
+
const { timestamp_last_refreshed, ...businessData } = hm;
|
|
103
|
+
return businessData;
|
|
104
|
+
});
|
|
105
|
+
}, []);
|
|
106
|
+
// Helper function to conditionally dispatch only if business data has changed
|
|
107
|
+
const conditionalDispatch = useCallback((newData, currentData, actionCreator, dataType, useNormalizedComparison = false) => {
|
|
108
|
+
let dataToCompare = newData;
|
|
109
|
+
let currentToCompare = currentData;
|
|
110
|
+
// For herd modules, use normalized comparison that ignores metadata
|
|
111
|
+
if (useNormalizedComparison && dataType.includes("Herd modules")) {
|
|
112
|
+
dataToCompare = normalizeHerdModulesForComparison(newData);
|
|
113
|
+
currentToCompare = normalizeHerdModulesForComparison(currentData);
|
|
114
|
+
}
|
|
115
|
+
if (!deepEqual(dataToCompare, currentToCompare)) {
|
|
116
|
+
console.log(`[useScoutRefresh] ${dataType} business data changed, updating store`);
|
|
117
|
+
dispatch(actionCreator(newData)); // Always dispatch the full data including timestamps
|
|
95
118
|
return true;
|
|
96
119
|
}
|
|
97
120
|
else {
|
|
98
|
-
console.log(`[useScoutRefresh] ${dataType} data unchanged, skipping store update`);
|
|
121
|
+
console.log(`[useScoutRefresh] ${dataType} business data unchanged, skipping store update`);
|
|
99
122
|
return false;
|
|
100
123
|
}
|
|
101
|
-
}, [dispatch, deepEqual]);
|
|
124
|
+
}, [dispatch, deepEqual, normalizeHerdModulesForComparison]);
|
|
102
125
|
// Helper function to handle IndexedDB errors - memoized for stability
|
|
103
126
|
const handleIndexedDbError = useCallback(async (error, operation, retryFn) => {
|
|
104
127
|
if (error instanceof Error &&
|
|
@@ -151,23 +174,13 @@ export function useScoutRefresh(options = {}) {
|
|
|
151
174
|
cacheAge: cacheResult.age,
|
|
152
175
|
isStale: cacheResult.isStale,
|
|
153
176
|
}));
|
|
154
|
-
// Conditionally update the store with cached data if different
|
|
177
|
+
// Conditionally update the store with cached data if business data is different
|
|
155
178
|
// Get current state at execution time to avoid dependency issues
|
|
156
179
|
const currentHerdModules = store.getState().scout.herd_modules;
|
|
157
|
-
const herdModulesChanged = conditionalDispatch(cachedHerdModules, currentHerdModules, setHerdModules, "Herd modules (cache)");
|
|
180
|
+
const herdModulesChanged = conditionalDispatch(cachedHerdModules, currentHerdModules, setHerdModules, "Herd modules (cache)", true);
|
|
158
181
|
if (herdModulesChanged) {
|
|
159
182
|
dispatch(setHerdModulesLoadingState(EnumHerdModulesLoadingState.SUCCESSFULLY_LOADED));
|
|
160
183
|
}
|
|
161
|
-
// Always load user data from API
|
|
162
|
-
const userStartTime = Date.now();
|
|
163
|
-
const res_new_user = await server_get_user();
|
|
164
|
-
const userApiDuration = Date.now() - userStartTime;
|
|
165
|
-
timingRefs.current.userApiDuration = userApiDuration;
|
|
166
|
-
dispatch(setUserApiDuration(userApiDuration));
|
|
167
|
-
if (res_new_user && res_new_user.data) {
|
|
168
|
-
const currentUser = store.getState().scout.user;
|
|
169
|
-
conditionalDispatch(res_new_user.data, currentUser, setUser, "User (initial)");
|
|
170
|
-
}
|
|
171
184
|
// If cache is fresh, we still background fetch but don't wait
|
|
172
185
|
if (!cacheResult.isStale) {
|
|
173
186
|
console.log("[useScoutRefresh] Cache is fresh, background fetching fresh data...");
|
|
@@ -177,8 +190,22 @@ export function useScoutRefresh(options = {}) {
|
|
|
177
190
|
console.log("[useScoutRefresh] Starting background fetch...");
|
|
178
191
|
const backgroundStartTime = Date.now();
|
|
179
192
|
const [backgroundHerdModulesResult, backgroundUserResult] = await Promise.all([
|
|
180
|
-
|
|
181
|
-
|
|
193
|
+
(async () => {
|
|
194
|
+
const start = Date.now();
|
|
195
|
+
const result = await server_load_herd_modules();
|
|
196
|
+
const duration = Date.now() - start;
|
|
197
|
+
timingRefs.current.herdModulesDuration = duration;
|
|
198
|
+
dispatch(setHerdModulesApiDuration(duration));
|
|
199
|
+
return result;
|
|
200
|
+
})(),
|
|
201
|
+
(async () => {
|
|
202
|
+
const start = Date.now();
|
|
203
|
+
const { data } = await supabase.auth.getUser();
|
|
204
|
+
const duration = Date.now() - start;
|
|
205
|
+
timingRefs.current.userApiDuration = duration;
|
|
206
|
+
dispatch(setUserApiDuration(duration));
|
|
207
|
+
return { data: data.user, status: "success" };
|
|
208
|
+
})(),
|
|
182
209
|
]);
|
|
183
210
|
const backgroundDuration = Date.now() - backgroundStartTime;
|
|
184
211
|
console.log(`[useScoutRefresh] Background fetch completed in ${backgroundDuration}ms`);
|
|
@@ -200,11 +227,13 @@ export function useScoutRefresh(options = {}) {
|
|
|
200
227
|
}
|
|
201
228
|
});
|
|
202
229
|
}
|
|
203
|
-
// Conditionally update store with fresh background data
|
|
230
|
+
// Conditionally update store with fresh background data using normalized comparison
|
|
204
231
|
const currentHerdModules = store.getState().scout.herd_modules;
|
|
205
232
|
const currentUser = store.getState().scout.user;
|
|
206
|
-
conditionalDispatch(backgroundHerdModulesResult.data, currentHerdModules, setHerdModules, "Herd modules (background)");
|
|
207
|
-
|
|
233
|
+
conditionalDispatch(backgroundHerdModulesResult.data, currentHerdModules, setHerdModules, "Herd modules (background)", true);
|
|
234
|
+
if (backgroundUserResult && backgroundUserResult.data) {
|
|
235
|
+
conditionalDispatch(backgroundUserResult.data, currentUser, setUser, "User (background)");
|
|
236
|
+
}
|
|
208
237
|
// Update data source to DATABASE
|
|
209
238
|
dispatch(setDataSource(EnumDataSource.DATABASE));
|
|
210
239
|
dispatch(setDataSourceInfo({
|
|
@@ -254,10 +283,14 @@ export function useScoutRefresh(options = {}) {
|
|
|
254
283
|
(async () => {
|
|
255
284
|
const start = Date.now();
|
|
256
285
|
console.log(`[useScoutRefresh] Starting user request at ${new Date(start).toISOString()}`);
|
|
257
|
-
const
|
|
286
|
+
const { data } = await supabase.auth.getUser();
|
|
258
287
|
const duration = Date.now() - start;
|
|
259
288
|
console.log(`[useScoutRefresh] User request completed in ${duration}ms`);
|
|
260
|
-
return {
|
|
289
|
+
return {
|
|
290
|
+
result: { data: data.user, status: "success" },
|
|
291
|
+
duration,
|
|
292
|
+
start,
|
|
293
|
+
};
|
|
261
294
|
})(),
|
|
262
295
|
]);
|
|
263
296
|
const parallelDuration = Date.now() - parallelStartTime;
|
|
@@ -306,11 +339,11 @@ export function useScoutRefresh(options = {}) {
|
|
|
306
339
|
await scoutCache.setHerdModules(compatible_new_herd_modules, cacheTtlMs);
|
|
307
340
|
});
|
|
308
341
|
}
|
|
309
|
-
// Step 4: Conditionally update store with fresh data
|
|
342
|
+
// Step 4: Conditionally update store with fresh data using normalized comparison
|
|
310
343
|
const dataProcessingStartTime = Date.now();
|
|
311
344
|
const currentHerdModules = store.getState().scout.herd_modules;
|
|
312
345
|
const currentUser = store.getState().scout.user;
|
|
313
|
-
const herdModulesChanged = conditionalDispatch(compatible_new_herd_modules, currentHerdModules, setHerdModules, "Herd modules (fresh API)");
|
|
346
|
+
const herdModulesChanged = conditionalDispatch(compatible_new_herd_modules, currentHerdModules, setHerdModules, "Herd modules (fresh API)", true);
|
|
314
347
|
const userChanged = conditionalDispatch(res_new_user.data, currentUser, setUser, "User (fresh API)");
|
|
315
348
|
if (herdModulesChanged) {
|
|
316
349
|
dispatch(setHerdModulesLoadingState(EnumHerdModulesLoadingState.SUCCESSFULLY_LOADED));
|
|
@@ -359,6 +392,7 @@ export function useScoutRefresh(options = {}) {
|
|
|
359
392
|
}, [
|
|
360
393
|
dispatch,
|
|
361
394
|
store,
|
|
395
|
+
supabase,
|
|
362
396
|
onRefreshComplete,
|
|
363
397
|
cacheFirst,
|
|
364
398
|
cacheTtlMs,
|