@adventurelabs/scout-core 1.0.59 → 1.0.60

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,2 +1,2 @@
1
- export * from "./useScoutDbListener";
2
- export * from "./useScoutRefresh";
1
+ export { useScoutDbListener } from "./useScoutDbListener";
2
+ export { useScoutRefresh, type UseScoutRefreshOptions, } from "./useScoutRefresh";
@@ -1,2 +1,2 @@
1
- export * from "./useScoutDbListener";
2
- export * from "./useScoutRefresh";
1
+ export { useScoutDbListener } from "./useScoutDbListener";
2
+ export { useScoutRefresh, } from "./useScoutRefresh";
@@ -2,6 +2,37 @@ export interface UseScoutRefreshOptions {
2
2
  autoRefresh?: boolean;
3
3
  onRefreshComplete?: () => void;
4
4
  }
5
+ /**
6
+ * Hook for refreshing scout data with detailed timing measurements
7
+ *
8
+ * @param options - Configuration options for the refresh behavior
9
+ * @param options.autoRefresh - Whether to automatically refresh on mount (default: true)
10
+ * @param options.onRefreshComplete - Callback function called when refresh completes
11
+ *
12
+ * @returns Object containing:
13
+ * - handleRefresh: Function to manually trigger a refresh
14
+ * - getTimingStats: Function to get detailed timing statistics for the last refresh
15
+ *
16
+ * @example
17
+ * ```tsx
18
+ * const { handleRefresh, getTimingStats } = useScoutRefresh();
19
+ *
20
+ * // Get timing stats after a refresh
21
+ * const stats = getTimingStats();
22
+ * console.log('Herd modules API took:', stats.herdModulesApi, 'ms');
23
+ * console.log('User API took:', stats.userApi, 'ms');
24
+ * console.log('Data processing took:', stats.dataProcessing, 'ms');
25
+ * console.log('LocalStorage operations took:', stats.localStorage, 'ms');
26
+ * console.log('Total duration:', stats.totalDuration, 'ms');
27
+ * ```
28
+ */
5
29
  export declare function useScoutRefresh(options?: UseScoutRefreshOptions): {
6
30
  handleRefresh: () => Promise<void>;
31
+ getTimingStats: () => {
32
+ totalDuration: number;
33
+ herdModulesApi: number;
34
+ userApi: number;
35
+ dataProcessing: number;
36
+ localStorage: number;
37
+ };
7
38
  };
@@ -1,13 +1,45 @@
1
1
  import { useEffect, useCallback, useRef } from "react";
2
2
  import { useAppDispatch } from "../store/hooks";
3
- import { EnumScoutStateStatus, setActiveHerdId, setHerdModules, setStatus, setHerdModulesLoadingState, setHerdModulesLoadedInMs, setUser, } from "../store/scout";
3
+ import { EnumScoutStateStatus, setActiveHerdId, setHerdModules, setStatus, setHerdModulesLoadingState, setHerdModulesLoadedInMs, setHerdModulesApiDuration, setUserApiDuration, setDataProcessingDuration, setLocalStorageDuration, setUser, } from "../store/scout";
4
4
  import { EnumHerdModulesLoadingState } from "../types/herd_module";
5
5
  import { server_load_herd_modules } from "../helpers/herds";
6
6
  import { server_get_user } from "../helpers/users";
7
+ /**
8
+ * Hook for refreshing scout data with detailed timing measurements
9
+ *
10
+ * @param options - Configuration options for the refresh behavior
11
+ * @param options.autoRefresh - Whether to automatically refresh on mount (default: true)
12
+ * @param options.onRefreshComplete - Callback function called when refresh completes
13
+ *
14
+ * @returns Object containing:
15
+ * - handleRefresh: Function to manually trigger a refresh
16
+ * - getTimingStats: Function to get detailed timing statistics for the last refresh
17
+ *
18
+ * @example
19
+ * ```tsx
20
+ * const { handleRefresh, getTimingStats } = useScoutRefresh();
21
+ *
22
+ * // Get timing stats after a refresh
23
+ * const stats = getTimingStats();
24
+ * console.log('Herd modules API took:', stats.herdModulesApi, 'ms');
25
+ * console.log('User API took:', stats.userApi, 'ms');
26
+ * console.log('Data processing took:', stats.dataProcessing, 'ms');
27
+ * console.log('LocalStorage operations took:', stats.localStorage, 'ms');
28
+ * console.log('Total duration:', stats.totalDuration, 'ms');
29
+ * ```
30
+ */
7
31
  export function useScoutRefresh(options = {}) {
8
32
  const { autoRefresh = true, onRefreshComplete } = options;
9
33
  const dispatch = useAppDispatch();
10
34
  const refreshInProgressRef = useRef(false);
35
+ // Refs to store timing measurements
36
+ const timingRefs = useRef({
37
+ startTime: 0,
38
+ herdModulesDuration: 0,
39
+ userApiDuration: 0,
40
+ dataProcessingDuration: 0,
41
+ localStorageDuration: 0,
42
+ });
11
43
  const handleRefresh = useCallback(async () => {
12
44
  // Prevent concurrent refresh calls
13
45
  if (refreshInProgressRef.current) {
@@ -16,11 +48,22 @@ export function useScoutRefresh(options = {}) {
16
48
  }
17
49
  refreshInProgressRef.current = true;
18
50
  const startTime = Date.now();
51
+ timingRefs.current.startTime = startTime;
19
52
  try {
20
53
  dispatch(setStatus(EnumScoutStateStatus.LOADING));
21
54
  dispatch(setHerdModulesLoadingState(EnumHerdModulesLoadingState.LOADING));
55
+ // Measure herd modules API call duration
56
+ const herdModulesStartTime = Date.now();
22
57
  const compatible_new_herd_modules = await server_load_herd_modules();
58
+ const herdModulesDuration = Date.now() - herdModulesStartTime;
59
+ timingRefs.current.herdModulesDuration = herdModulesDuration;
60
+ dispatch(setHerdModulesApiDuration(herdModulesDuration));
61
+ // Measure user API call duration
62
+ const userApiStartTime = Date.now();
23
63
  const res_new_user = await server_get_user();
64
+ const userApiDuration = Date.now() - userApiStartTime;
65
+ timingRefs.current.userApiDuration = userApiDuration;
66
+ dispatch(setUserApiDuration(userApiDuration));
24
67
  // Validate API responses
25
68
  if (!compatible_new_herd_modules ||
26
69
  !Array.isArray(compatible_new_herd_modules)) {
@@ -29,11 +72,16 @@ export function useScoutRefresh(options = {}) {
29
72
  if (!res_new_user || !res_new_user.data) {
30
73
  throw new Error("Invalid user response");
31
74
  }
32
- const loadingDuration = Date.now() - startTime;
75
+ // Measure data processing duration
76
+ const dataProcessingStartTime = Date.now();
33
77
  dispatch(setHerdModules(compatible_new_herd_modules));
34
78
  dispatch(setUser(res_new_user.data));
35
79
  dispatch(setHerdModulesLoadingState(EnumHerdModulesLoadingState.SUCCESSFULLY_LOADED));
36
- dispatch(setHerdModulesLoadedInMs(loadingDuration));
80
+ const dataProcessingDuration = Date.now() - dataProcessingStartTime;
81
+ timingRefs.current.dataProcessingDuration = dataProcessingDuration;
82
+ dispatch(setDataProcessingDuration(dataProcessingDuration));
83
+ // Measure localStorage operations duration
84
+ const localStorageStartTime = Date.now();
37
85
  // Safely handle localStorage operations
38
86
  try {
39
87
  // Check local storage for a last selected herd
@@ -59,7 +107,19 @@ export function useScoutRefresh(options = {}) {
59
107
  dispatch(setActiveHerdId(compatible_new_herd_modules[0].herd.id.toString()));
60
108
  }
61
109
  }
110
+ const localStorageDuration = Date.now() - localStorageStartTime;
111
+ timingRefs.current.localStorageDuration = localStorageDuration;
112
+ dispatch(setLocalStorageDuration(localStorageDuration));
113
+ const loadingDuration = Date.now() - startTime;
114
+ dispatch(setHerdModulesLoadedInMs(loadingDuration));
62
115
  dispatch(setStatus(EnumScoutStateStatus.DONE_LOADING));
116
+ // Log timing statistics
117
+ console.log("[useScoutRefresh] Refresh completed successfully. Timing breakdown:");
118
+ console.log(` - Herd modules API: ${herdModulesDuration}ms`);
119
+ console.log(` - User API: ${userApiDuration}ms`);
120
+ console.log(` - Data processing: ${dataProcessingDuration}ms`);
121
+ console.log(` - LocalStorage operations: ${localStorageDuration}ms`);
122
+ console.log(` - Total duration: ${loadingDuration}ms`);
63
123
  onRefreshComplete?.();
64
124
  }
65
125
  catch (error) {
@@ -69,6 +129,13 @@ export function useScoutRefresh(options = {}) {
69
129
  dispatch(setHerdModulesLoadingState(EnumHerdModulesLoadingState.UNSUCCESSFULLY_LOADED));
70
130
  dispatch(setHerdModulesLoadedInMs(loadingDuration));
71
131
  dispatch(setStatus(EnumScoutStateStatus.DONE_LOADING));
132
+ // Log timing statistics even on error
133
+ console.log("[useScoutRefresh] Refresh failed. Partial timing breakdown:");
134
+ console.log(` - Herd modules API: ${timingRefs.current.herdModulesDuration}ms`);
135
+ console.log(` - User API: ${timingRefs.current.userApiDuration}ms`);
136
+ console.log(` - Data processing: ${timingRefs.current.dataProcessingDuration}ms`);
137
+ console.log(` - LocalStorage operations: ${timingRefs.current.localStorageDuration}ms`);
138
+ console.log(` - Total duration: ${loadingDuration}ms`);
72
139
  }
73
140
  finally {
74
141
  refreshInProgressRef.current = false;
@@ -79,7 +146,20 @@ export function useScoutRefresh(options = {}) {
79
146
  handleRefresh();
80
147
  }
81
148
  }, [autoRefresh, handleRefresh]);
149
+ // Utility function to get timing statistics
150
+ const getTimingStats = useCallback(() => {
151
+ const now = Date.now();
152
+ const startTime = timingRefs.current.startTime;
153
+ return {
154
+ totalDuration: startTime > 0 ? now - startTime : 0,
155
+ herdModulesApi: timingRefs.current.herdModulesDuration,
156
+ userApi: timingRefs.current.userApiDuration,
157
+ dataProcessing: timingRefs.current.dataProcessingDuration,
158
+ localStorage: timingRefs.current.localStorageDuration,
159
+ };
160
+ }, []);
82
161
  return {
83
162
  handleRefresh,
163
+ getTimingStats,
84
164
  };
85
165
  }
@@ -9,6 +9,10 @@ export interface ScoutState {
9
9
  status: EnumScoutStateStatus;
10
10
  herd_modules_loading_state: EnumHerdModulesLoadingState;
11
11
  herd_modules_loaded_in_ms: number | null;
12
+ herd_modules_api_duration_ms: number | null;
13
+ user_api_duration_ms: number | null;
14
+ data_processing_duration_ms: number | null;
15
+ localStorage_duration_ms: number | null;
12
16
  active_herd_id: string | null;
13
17
  active_device_id: string | null;
14
18
  lastRefreshed: number;
@@ -31,6 +35,22 @@ export declare const scoutSlice: import("@reduxjs/toolkit").Slice<ScoutState, {
31
35
  payload: any;
32
36
  type: string;
33
37
  }) => void;
38
+ setHerdModulesApiDuration: (state: import("immer").WritableDraft<ScoutState>, action: {
39
+ payload: any;
40
+ type: string;
41
+ }) => void;
42
+ setUserApiDuration: (state: import("immer").WritableDraft<ScoutState>, action: {
43
+ payload: any;
44
+ type: string;
45
+ }) => void;
46
+ setDataProcessingDuration: (state: import("immer").WritableDraft<ScoutState>, action: {
47
+ payload: any;
48
+ type: string;
49
+ }) => void;
50
+ setLocalStorageDuration: (state: import("immer").WritableDraft<ScoutState>, action: {
51
+ payload: any;
52
+ type: string;
53
+ }) => void;
34
54
  setActiveHerdId: (state: import("immer").WritableDraft<ScoutState>, action: {
35
55
  payload: any;
36
56
  type: string;
@@ -120,6 +140,6 @@ export declare const scoutSlice: import("@reduxjs/toolkit").Slice<ScoutState, {
120
140
  type: string;
121
141
  }) => void;
122
142
  }, "scout", "scout", import("@reduxjs/toolkit").SliceSelectors<ScoutState>>;
123
- 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">, setActiveHerdId: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/setActiveHerdId">, setActiveDeviceId: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/setActiveDeviceId">, 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">;
143
+ 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">, setLocalStorageDuration: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/setLocalStorageDuration">, setActiveHerdId: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/setActiveHerdId">, setActiveDeviceId: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/setActiveDeviceId">, 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">;
124
144
  declare const _default: import("redux").Reducer<ScoutState>;
125
145
  export default _default;
@@ -10,6 +10,11 @@ const initialState = {
10
10
  status: EnumScoutStateStatus.LOADING,
11
11
  herd_modules_loading_state: EnumHerdModulesLoadingState.NOT_LOADING,
12
12
  herd_modules_loaded_in_ms: null,
13
+ // Initialize timing variables
14
+ herd_modules_api_duration_ms: null,
15
+ user_api_duration_ms: null,
16
+ data_processing_duration_ms: null,
17
+ localStorage_duration_ms: null,
13
18
  lastRefreshed: 0,
14
19
  active_herd_id: null,
15
20
  active_device_id: null,
@@ -32,6 +37,18 @@ export const scoutSlice = createSlice({
32
37
  setHerdModulesLoadedInMs: (state, action) => {
33
38
  state.herd_modules_loaded_in_ms = action.payload;
34
39
  },
40
+ setHerdModulesApiDuration: (state, action) => {
41
+ state.herd_modules_api_duration_ms = action.payload;
42
+ },
43
+ setUserApiDuration: (state, action) => {
44
+ state.user_api_duration_ms = action.payload;
45
+ },
46
+ setDataProcessingDuration: (state, action) => {
47
+ state.data_processing_duration_ms = action.payload;
48
+ },
49
+ setLocalStorageDuration: (state, action) => {
50
+ state.localStorage_duration_ms = action.payload;
51
+ },
35
52
  setActiveHerdId: (state, action) => {
36
53
  state.active_herd_id = action.payload;
37
54
  },
@@ -237,5 +254,5 @@ export const scoutSlice = createSlice({
237
254
  },
238
255
  });
239
256
  // Action creators are generated for each case reducer function
240
- export const { setHerdModules, setStatus, setHerdModulesLoadingState, setHerdModulesLoadedInMs, setActiveHerdId, setActiveDeviceId, appendEventsToHerdModule, replaceEventsForHerdModule, updateEventValuesForHerdModule, updatePageIndexForHerdModule, appendPlansToHerdModule, setUser, addTag, deleteTag, updateTag, addNewDeviceToHerdModule, updateDeviceForHerdModule, addDevice, deleteDevice, updateDevice, addPlan, deletePlan, updatePlan, addSessionToStore, deleteSessionFromStore, updateSessionInStore, } = scoutSlice.actions;
257
+ export const { setHerdModules, setStatus, setHerdModulesLoadingState, setHerdModulesLoadedInMs, setHerdModulesApiDuration, setUserApiDuration, setDataProcessingDuration, setLocalStorageDuration, setActiveHerdId, setActiveDeviceId, appendEventsToHerdModule, replaceEventsForHerdModule, updateEventValuesForHerdModule, updatePageIndexForHerdModule, appendPlansToHerdModule, setUser, addTag, deleteTag, updateTag, addNewDeviceToHerdModule, updateDeviceForHerdModule, addDevice, deleteDevice, updateDevice, addPlan, deletePlan, updatePlan, addSessionToStore, deleteSessionFromStore, updateSessionInStore, } = scoutSlice.actions;
241
258
  export default scoutSlice.reducer;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adventurelabs/scout-core",
3
- "version": "1.0.59",
3
+ "version": "1.0.60",
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",