@adventurelabs/scout-core 1.0.110 → 1.0.111

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.
@@ -1,7 +1,7 @@
1
1
  import { useEffect, useCallback, useRef, useMemo } from "react";
2
2
  import { useAppDispatch } from "../store/hooks";
3
3
  import { useStore } from "react-redux";
4
- import { EnumScoutStateStatus, setHerdModules, setStatus, setHerdModulesLoadingState, setHerdModulesLoadedInMs, setHerdModulesApiDuration, setUserApiDuration, setDataProcessingDuration, setUser, setDataSource, setDataSourceInfo, } from "../store/scout";
4
+ import { EnumScoutStateStatus, setHerdModules, setStatus, setHerdModulesLoadingState, setHerdModulesLoadedInMs, setHerdModulesApiDuration, setUserApiDuration, setDataProcessingDuration, setCacheLoadDuration, 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
7
  import { scoutCache } from "../helpers/cache";
@@ -91,37 +91,75 @@ export function useScoutRefresh(options = {}) {
91
91
  }
92
92
  return true;
93
93
  }, []);
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);
94
+ // Helper function to find differences between herd modules for debugging
95
+ const findHerdModulesDifferences = useCallback((newData, currentData) => {
96
+ if (!Array.isArray(newData) || !Array.isArray(currentData)) {
97
+ return `Array type mismatch: new=${Array.isArray(newData)}, current=${Array.isArray(currentData)}`;
98
+ }
99
+ if (newData.length !== currentData.length) {
100
+ return `Array length mismatch: new=${newData.length}, current=${currentData.length}`;
114
101
  }
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
102
+ const differences = [];
103
+ for (let i = 0; i < newData.length; i++) {
104
+ const newHerd = newData[i];
105
+ const currentHerd = currentData[i];
106
+ if (!newHerd || !currentHerd) {
107
+ differences.push(`Herd ${i}: null/undefined mismatch`);
108
+ continue;
109
+ }
110
+ // Check top-level fields
111
+ const fieldsToCheck = [
112
+ "timestamp_last_refreshed",
113
+ "total_events",
114
+ "total_events_with_filters",
115
+ "events_page_index",
116
+ ];
117
+ fieldsToCheck.forEach((field) => {
118
+ if (newHerd[field] !== currentHerd[field]) {
119
+ differences.push(`Herd ${i}.${field}: ${currentHerd[field]} → ${newHerd[field]}`);
120
+ }
121
+ });
122
+ // Check array lengths for nested data
123
+ const arrayFields = [
124
+ "devices",
125
+ "events",
126
+ "plans",
127
+ "zones",
128
+ "sessions",
129
+ "layers",
130
+ "providers",
131
+ ];
132
+ arrayFields.forEach((field) => {
133
+ const newArray = newHerd[field];
134
+ const currentArray = currentHerd[field];
135
+ if (Array.isArray(newArray) && Array.isArray(currentArray)) {
136
+ if (newArray.length !== currentArray.length) {
137
+ differences.push(`Herd ${i}.${field}[]: length ${currentArray.length} → ${newArray.length}`);
138
+ }
139
+ }
140
+ });
141
+ }
142
+ return differences.length > 0
143
+ ? differences.join(", ")
144
+ : "No significant differences found";
145
+ }, []);
146
+ // Helper function to conditionally dispatch only if data has changed
147
+ const conditionalDispatch = useCallback((newData, currentData, actionCreator, dataType, enableDebugging = false) => {
148
+ if (!deepEqual(newData, currentData)) {
149
+ console.log(`[useScoutRefresh] ${dataType} data changed, updating store`);
150
+ // Add debugging for herd modules to see what actually changed
151
+ if (enableDebugging && dataType.includes("Herd modules")) {
152
+ const differences = findHerdModulesDifferences(newData, currentData);
153
+ console.log(`[useScoutRefresh] ${dataType} differences: ${differences}`);
154
+ }
155
+ dispatch(actionCreator(newData));
118
156
  return true;
119
157
  }
120
158
  else {
121
- console.log(`[useScoutRefresh] ${dataType} business data unchanged, skipping store update`);
159
+ console.log(`[useScoutRefresh] ${dataType} data unchanged, skipping store update`);
122
160
  return false;
123
161
  }
124
- }, [dispatch, deepEqual, normalizeHerdModulesForComparison]);
162
+ }, [dispatch, deepEqual, findHerdModulesDifferences]);
125
163
  // Helper function to handle IndexedDB errors - memoized for stability
126
164
  const handleIndexedDbError = useCallback(async (error, operation, retryFn) => {
127
165
  if (error instanceof Error &&
@@ -163,6 +201,7 @@ export function useScoutRefresh(options = {}) {
163
201
  const cacheResult = await scoutCache.getHerdModules();
164
202
  cacheLoadDuration = Date.now() - cacheStartTime;
165
203
  timingRefs.current.cacheLoadDuration = cacheLoadDuration;
204
+ dispatch(setCacheLoadDuration(cacheLoadDuration));
166
205
  if (cacheResult.data && cacheResult.data.length > 0) {
167
206
  cachedHerdModules = cacheResult.data;
168
207
  console.log(`[useScoutRefresh] Loaded ${cachedHerdModules.length} herd modules from cache in ${cacheLoadDuration}ms (age: ${Math.round(cacheResult.age / 1000)}s, stale: ${cacheResult.isStale})`);
@@ -14,6 +14,7 @@ export interface ScoutState {
14
14
  herd_modules_api_duration_ms: number | null;
15
15
  user_api_duration_ms: number | null;
16
16
  data_processing_duration_ms: number | null;
17
+ cache_load_duration_ms: number | null;
17
18
  active_herd_id: string | null;
18
19
  active_device_id: string | null;
19
20
  lastRefreshed: number;
@@ -54,6 +55,10 @@ export declare const scoutSlice: import("@reduxjs/toolkit").Slice<ScoutState, {
54
55
  payload: any;
55
56
  type: string;
56
57
  }) => void;
58
+ setCacheLoadDuration: (state: import("immer").WritableDraft<ScoutState>, action: {
59
+ payload: any;
60
+ type: string;
61
+ }) => void;
57
62
  setActiveHerdId: (state: import("immer").WritableDraft<ScoutState>, action: {
58
63
  payload: any;
59
64
  type: string;
@@ -155,6 +160,6 @@ export declare const scoutSlice: import("@reduxjs/toolkit").Slice<ScoutState, {
155
160
  type: string;
156
161
  }) => void;
157
162
  }, "scout", "scout", import("@reduxjs/toolkit").SliceSelectors<ScoutState>>;
158
- export declare const setHerdModules: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/setHerdModules">, setStatus: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/setStatus">, setHerdModulesLoadingState: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/setHerdModulesLoadingState">, setHerdModulesLoadedInMs: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/setHerdModulesLoadedInMs">, setHerdModulesApiDuration: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/setHerdModulesApiDuration">, setUserApiDuration: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/setUserApiDuration">, setDataProcessingDuration: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/setDataProcessingDuration">, setActiveHerdId: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/setActiveHerdId">, setActiveDeviceId: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/setActiveDeviceId">, setDataSource: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/setDataSource">, setDataSourceInfo: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/setDataSourceInfo">, appendEventsToHerdModule: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/appendEventsToHerdModule">, replaceEventsForHerdModule: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/replaceEventsForHerdModule">, updateEventValuesForHerdModule: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/updateEventValuesForHerdModule">, updatePageIndexForHerdModule: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/updatePageIndexForHerdModule">, appendPlansToHerdModule: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/appendPlansToHerdModule">, setUser: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/setUser">, addTag: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/addTag">, deleteTag: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/deleteTag">, updateTag: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/updateTag">, addNewDeviceToHerdModule: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/addNewDeviceToHerdModule">, updateDeviceForHerdModule: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/updateDeviceForHerdModule">, addDevice: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/addDevice">, deleteDevice: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/deleteDevice">, updateDevice: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/updateDevice">, addPlan: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/addPlan">, deletePlan: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/deletePlan">, updatePlan: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/updatePlan">, addSessionToStore: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/addSessionToStore">, deleteSessionFromStore: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/deleteSessionFromStore">, updateSessionInStore: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/updateSessionInStore">, setActiveHerdGpsTrackersConnectivity: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/setActiveHerdGpsTrackersConnectivity">;
163
+ export declare const setHerdModules: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/setHerdModules">, setStatus: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/setStatus">, setHerdModulesLoadingState: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/setHerdModulesLoadingState">, setHerdModulesLoadedInMs: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/setHerdModulesLoadedInMs">, setHerdModulesApiDuration: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/setHerdModulesApiDuration">, setUserApiDuration: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/setUserApiDuration">, setDataProcessingDuration: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/setDataProcessingDuration">, setCacheLoadDuration: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/setCacheLoadDuration">, setActiveHerdId: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/setActiveHerdId">, setActiveDeviceId: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/setActiveDeviceId">, setDataSource: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/setDataSource">, setDataSourceInfo: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/setDataSourceInfo">, appendEventsToHerdModule: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/appendEventsToHerdModule">, replaceEventsForHerdModule: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/replaceEventsForHerdModule">, updateEventValuesForHerdModule: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/updateEventValuesForHerdModule">, updatePageIndexForHerdModule: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/updatePageIndexForHerdModule">, appendPlansToHerdModule: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/appendPlansToHerdModule">, setUser: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/setUser">, addTag: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/addTag">, deleteTag: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/deleteTag">, updateTag: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/updateTag">, addNewDeviceToHerdModule: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/addNewDeviceToHerdModule">, updateDeviceForHerdModule: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/updateDeviceForHerdModule">, addDevice: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/addDevice">, deleteDevice: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/deleteDevice">, updateDevice: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/updateDevice">, addPlan: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/addPlan">, deletePlan: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/deletePlan">, updatePlan: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/updatePlan">, addSessionToStore: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/addSessionToStore">, deleteSessionFromStore: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/deleteSessionFromStore">, updateSessionInStore: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/updateSessionInStore">, setActiveHerdGpsTrackersConnectivity: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/setActiveHerdGpsTrackersConnectivity">;
159
164
  declare const _default: import("redux").Reducer<ScoutState>;
160
165
  export default _default;
@@ -15,6 +15,7 @@ const initialState = {
15
15
  herd_modules_api_duration_ms: null,
16
16
  user_api_duration_ms: null,
17
17
  data_processing_duration_ms: null,
18
+ cache_load_duration_ms: null,
18
19
  lastRefreshed: 0,
19
20
  active_herd_id: null,
20
21
  active_device_id: null,
@@ -50,6 +51,9 @@ export const scoutSlice = createSlice({
50
51
  setDataProcessingDuration: (state, action) => {
51
52
  state.data_processing_duration_ms = action.payload;
52
53
  },
54
+ setCacheLoadDuration: (state, action) => {
55
+ state.cache_load_duration_ms = action.payload;
56
+ },
53
57
  setActiveHerdId: (state, action) => {
54
58
  state.active_herd_id = action.payload;
55
59
  state.active_herd_gps_trackers_connectivity = {};
@@ -265,5 +269,5 @@ export const scoutSlice = createSlice({
265
269
  },
266
270
  });
267
271
  // Action creators are generated for each case reducer function
268
- export const { setHerdModules, setStatus, setHerdModulesLoadingState, setHerdModulesLoadedInMs, setHerdModulesApiDuration, setUserApiDuration, setDataProcessingDuration, setActiveHerdId, setActiveDeviceId, setDataSource, setDataSourceInfo, appendEventsToHerdModule, replaceEventsForHerdModule, updateEventValuesForHerdModule, updatePageIndexForHerdModule, appendPlansToHerdModule, setUser, addTag, deleteTag, updateTag, addNewDeviceToHerdModule, updateDeviceForHerdModule, addDevice, deleteDevice, updateDevice, addPlan, deletePlan, updatePlan, addSessionToStore, deleteSessionFromStore, updateSessionInStore, setActiveHerdGpsTrackersConnectivity, } = scoutSlice.actions;
272
+ export const { setHerdModules, setStatus, setHerdModulesLoadingState, setHerdModulesLoadedInMs, setHerdModulesApiDuration, setUserApiDuration, setDataProcessingDuration, setCacheLoadDuration, setActiveHerdId, setActiveDeviceId, setDataSource, setDataSourceInfo, appendEventsToHerdModule, replaceEventsForHerdModule, updateEventValuesForHerdModule, updatePageIndexForHerdModule, appendPlansToHerdModule, setUser, addTag, deleteTag, updateTag, addNewDeviceToHerdModule, updateDeviceForHerdModule, addDevice, deleteDevice, updateDevice, addPlan, deletePlan, updatePlan, addSessionToStore, deleteSessionFromStore, updateSessionInStore, setActiveHerdGpsTrackersConnectivity, } = scoutSlice.actions;
269
273
  export default scoutSlice.reducer;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adventurelabs/scout-core",
3
- "version": "1.0.110",
3
+ "version": "1.0.111",
4
4
  "description": "Core utilities and helpers for Adventure Labs Scout applications",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",