@adventurelabs/scout-core 1.0.112 → 1.0.114

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.
@@ -101,47 +101,48 @@ export function useScoutRefresh(options = {}) {
101
101
  return aId - bId;
102
102
  });
103
103
  }, []);
104
- // Helper function to find differences between herd modules for debugging
105
- const findHerdModulesDifferences = useCallback((newData, currentData) => {
104
+ // Helper function to normalize herd modules for comparison (excludes timestamp metadata)
105
+ const normalizeHerdModulesForComparison = useCallback((herdModules) => {
106
+ if (!Array.isArray(herdModules))
107
+ return herdModules;
108
+ return herdModules.map((hm) => {
109
+ if (!hm || typeof hm !== "object")
110
+ return hm;
111
+ // Create a copy without timestamp metadata that doesn't represent business data changes
112
+ const { timestamp_last_refreshed, ...businessData } = hm;
113
+ return businessData;
114
+ });
115
+ }, []);
116
+ // Helper function to find what specifically changed for debugging
117
+ const findBusinessDataChanges = useCallback((newData, currentData) => {
106
118
  if (!Array.isArray(newData) || !Array.isArray(currentData)) {
107
119
  return `Array type mismatch: new=${Array.isArray(newData)}, current=${Array.isArray(currentData)}`;
108
120
  }
109
121
  if (newData.length !== currentData.length) {
110
- return `Array length mismatch: new=${newData.length}, current=${currentData.length}`;
122
+ return `Array length: ${currentData.length} → ${newData.length}`;
111
123
  }
112
- // Sort both arrays by herd ID for consistent comparison
113
- const sortedNew = sortHerdModulesById(newData);
114
- const sortedCurrent = sortHerdModulesById(currentData);
115
- const differences = [];
124
+ // Sort and normalize both for consistent comparison
125
+ const sortedNew = normalizeHerdModulesForComparison(sortHerdModulesById(newData));
126
+ const sortedCurrent = normalizeHerdModulesForComparison(sortHerdModulesById(currentData));
127
+ const changes = [];
116
128
  for (let i = 0; i < sortedNew.length; i++) {
117
129
  const newHerd = sortedNew[i];
118
130
  const currentHerd = sortedCurrent[i];
119
- if (!newHerd || !currentHerd) {
120
- differences.push(`Herd ${i}: null/undefined mismatch`);
131
+ if (!newHerd || !currentHerd)
121
132
  continue;
122
- }
123
- // Get herd identifiers for better debugging
124
- const newHerdId = newHerd.herd?.id || "unknown";
125
- const currentHerdId = currentHerd.herd?.id || "unknown";
126
- const newHerdName = newHerd.herd?.name || "unknown";
127
- const currentHerdName = currentHerd.herd?.name || "unknown";
128
- // Check if herd IDs match (data shuffling detection)
129
- if (newHerdId !== currentHerdId) {
130
- differences.push(`Herd ${i}: ID mismatch - expected ${currentHerdId}(${currentHerdName}) got ${newHerdId}(${newHerdName})`);
131
- }
132
- // Check top-level fields
133
- const fieldsToCheck = [
134
- "timestamp_last_refreshed",
133
+ const herdName = newHerd.herd?.name || newHerd.name || `herd-${newHerd.herd?.id || i}`;
134
+ // Check key business fields
135
+ const businessFields = [
135
136
  "total_events",
136
137
  "total_events_with_filters",
137
138
  "events_page_index",
138
139
  ];
139
- fieldsToCheck.forEach((field) => {
140
+ businessFields.forEach((field) => {
140
141
  if (newHerd[field] !== currentHerd[field]) {
141
- differences.push(`Herd ${i}(${newHerdName}).${field}: ${currentHerd[field]} → ${newHerd[field]}`);
142
+ changes.push(`${herdName}.${field}: ${currentHerd[field]} → ${newHerd[field]}`);
142
143
  }
143
144
  });
144
- // Check array lengths for nested data
145
+ // Check array lengths
145
146
  const arrayFields = [
146
147
  "devices",
147
148
  "events",
@@ -156,39 +157,51 @@ export function useScoutRefresh(options = {}) {
156
157
  const currentArray = currentHerd[field];
157
158
  if (Array.isArray(newArray) && Array.isArray(currentArray)) {
158
159
  if (newArray.length !== currentArray.length) {
159
- differences.push(`Herd ${i}(${newHerdName}).${field}[]: length ${currentArray.length} → ${newArray.length}`);
160
+ changes.push(`${herdName}.${field}[]: ${currentArray.length} → ${newArray.length}`);
160
161
  }
161
162
  }
162
163
  });
163
164
  }
164
- return differences.length > 0
165
- ? differences.join(", ")
166
- : "No significant differences found";
167
- }, []);
168
- // Helper function to conditionally dispatch only if data has changed
169
- const conditionalDispatch = useCallback((newData, currentData, actionCreator, dataType, enableDebugging = false) => {
165
+ return changes.length > 0
166
+ ? changes.join(", ")
167
+ : "No specific changes identified";
168
+ }, [normalizeHerdModulesForComparison, sortHerdModulesById]);
169
+ // Helper function to conditionally dispatch only if business data has changed
170
+ const conditionalDispatch = useCallback((newData, currentData, actionCreator, dataType, skipTimestampOnlyUpdates = false) => {
170
171
  // For herd modules, sort both datasets by ID before comparison
171
172
  let dataToCompare = newData;
172
173
  let currentToCompare = currentData;
173
174
  if (dataType.includes("Herd modules")) {
174
175
  dataToCompare = sortHerdModulesById(newData);
175
176
  currentToCompare = sortHerdModulesById(currentData);
177
+ // If we want to skip timestamp-only updates, normalize the data for comparison
178
+ if (skipTimestampOnlyUpdates) {
179
+ dataToCompare = normalizeHerdModulesForComparison(dataToCompare);
180
+ currentToCompare =
181
+ normalizeHerdModulesForComparison(currentToCompare);
182
+ }
176
183
  }
177
184
  if (!deepEqual(dataToCompare, currentToCompare)) {
178
- console.log(`[useScoutRefresh] ${dataType} data changed, updating store`);
179
- // Add debugging for herd modules to see what actually changed
180
- if (enableDebugging && dataType.includes("Herd modules")) {
181
- const differences = findHerdModulesDifferences(newData, currentData);
182
- console.log(`[useScoutRefresh] ${dataType} differences: ${differences}`);
185
+ console.log(`[useScoutRefresh] ${dataType} business data changed, updating store`);
186
+ // Add debugging for unexpected business changes
187
+ if (skipTimestampOnlyUpdates && dataType.includes("Herd modules")) {
188
+ const changes = findBusinessDataChanges(newData, currentData);
189
+ console.log(`[useScoutRefresh] ${dataType} changes: ${changes}`);
183
190
  }
184
191
  dispatch(actionCreator(newData)); // Always dispatch original unsorted data
185
192
  return true;
186
193
  }
187
194
  else {
188
- console.log(`[useScoutRefresh] ${dataType} data unchanged, skipping store update`);
195
+ console.log(`[useScoutRefresh] ${dataType} business data unchanged, skipping store update`);
189
196
  return false;
190
197
  }
191
- }, [dispatch, deepEqual, findHerdModulesDifferences, sortHerdModulesById]);
198
+ }, [
199
+ dispatch,
200
+ deepEqual,
201
+ sortHerdModulesById,
202
+ normalizeHerdModulesForComparison,
203
+ findBusinessDataChanges,
204
+ ]);
192
205
  // Helper function to handle IndexedDB errors - memoized for stability
193
206
  const handleIndexedDbError = useCallback(async (error, operation, retryFn) => {
194
207
  if (error instanceof Error &&
@@ -295,7 +308,7 @@ export function useScoutRefresh(options = {}) {
295
308
  }
296
309
  });
297
310
  }
298
- // Conditionally update store with fresh background data using normalized comparison
311
+ // Conditionally update store with fresh background data, skip timestamp-only changes
299
312
  const currentHerdModules = store.getState().scout.herd_modules;
300
313
  const currentUser = store.getState().scout.user;
301
314
  conditionalDispatch(backgroundHerdModulesResult.data, currentHerdModules, setHerdModules, "Herd modules (background)", true);
@@ -407,7 +420,7 @@ export function useScoutRefresh(options = {}) {
407
420
  await scoutCache.setHerdModules(compatible_new_herd_modules, cacheTtlMs);
408
421
  });
409
422
  }
410
- // Step 4: Conditionally update store with fresh data using normalized comparison
423
+ // Step 4: Conditionally update store with fresh data, skip timestamp-only changes
411
424
  const dataProcessingStartTime = Date.now();
412
425
  const currentHerdModules = store.getState().scout.herd_modules;
413
426
  const currentUser = store.getState().scout.user;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adventurelabs/scout-core",
3
- "version": "1.0.112",
3
+ "version": "1.0.114",
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",