@adventurelabs/scout-core 1.4.37 → 1.4.38

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.
@@ -9,7 +9,7 @@ export declare function server_update_connectivity(connectivity: (ConnectivityUp
9
9
  }) | (ConnectivityUpdate & {
10
10
  id: number;
11
11
  })[], client?: SupabaseClient): Promise<IWebResponseCompatible<IConnectivity[]>>;
12
- /** Connectivity records for a herd within a time range (devices in herd). */
12
+ /** Connectivity records for a herd within a time range */
13
13
  export declare function server_get_connectivity_for_herd_time_range(herdId: number, startTimestamp: string, endTimestamp: string, maxCount?: number): Promise<IWebResponseCompatible<IConnectivityWithCoordinates[]>>;
14
14
  /** Connectivity records for an artifact (uses session when set, else device + time window). */
15
15
  export declare function server_get_connectivity_for_artifact(artifactId: number, maxElements?: number): Promise<IWebResponseCompatible<IConnectivityWithCoordinates[]>>;
@@ -96,7 +96,7 @@ export async function server_update_connectivity(connectivity, client) {
96
96
  }
97
97
  return IWebResponse.success(updatedConnectivity).to_compatible();
98
98
  }
99
- /** Connectivity records for a herd within a time range (devices in herd). */
99
+ /** Connectivity records for a herd within a time range */
100
100
  export async function server_get_connectivity_for_herd_time_range(herdId, startTimestamp, endTimestamp, maxCount = 1000) {
101
101
  const supabase = await newServerClient();
102
102
  const { data, error } = await supabase.rpc("get_connectivity_for_herd_time_range", {
@@ -82,6 +82,7 @@ export function useScoutRefresh(options = {}) {
82
82
  refreshInProgressRef.current = true;
83
83
  const startTime = Date.now();
84
84
  timingRefs.current.startTime = startTime;
85
+ const isOffline = typeof navigator === "undefined" || !navigator.onLine;
85
86
  try {
86
87
  dispatch(setStatus(EnumScoutStateStatus.LOADING));
87
88
  dispatch(setHerdModulesLoadingState(EnumHerdModulesLoadingState.LOADING));
@@ -110,77 +111,79 @@ export function useScoutRefresh(options = {}) {
110
111
  console.log(`[useScoutRefresh] Updating store with cached herd modules`);
111
112
  dispatch(setHerdModules(cachedHerdModules));
112
113
  dispatch(setHerdModulesLoadingState(EnumHerdModulesLoadingState.SUCCESSFULLY_LOADED));
113
- // If cache is fresh, we still background fetch but don't wait
114
+ // If cache is fresh, we still background fetch but don't wait (only when online)
114
115
  if (!cacheResult.isStale) {
115
- // Background fetch fresh data without blocking
116
- (async () => {
117
- try {
118
- const backgroundStartTime = Date.now();
119
- const [backgroundHerdModulesResult, backgroundUserResult] = await Promise.all([
120
- (async () => {
121
- const start = Date.now();
122
- const result = await server_load_herd_modules();
123
- const totalDuration = Date.now() - start;
124
- const serverDuration = result.server_processing_time_ms || totalDuration;
125
- const clientOverhead = totalDuration - serverDuration;
126
- console.log(`[useScoutRefresh] Background API timing breakdown:`);
127
- console.log(` - Server processing: ${serverDuration}ms`);
128
- console.log(` - Client overhead: ${clientOverhead}ms`);
129
- console.log(` - Total request: ${totalDuration}ms`);
130
- timingRefs.current.herdModulesDuration = serverDuration;
131
- dispatch(setHerdModulesApiServerProcessingDuration(serverDuration));
132
- dispatch(setHerdModulesApiTotalRequestDuration(totalDuration));
133
- return result;
134
- })(),
135
- (async () => {
136
- const start = Date.now();
137
- const { data } = await supabase.auth.getUser();
138
- const duration = Date.now() - start;
139
- timingRefs.current.userApiDuration = duration;
140
- dispatch(setUserApiDuration(duration));
141
- return { data: data.user, status: "success" };
142
- })(),
143
- ]);
144
- const backgroundDuration = Date.now() - backgroundStartTime;
145
- // Validate background responses
146
- if (backgroundHerdModulesResult.data &&
147
- Array.isArray(backgroundHerdModulesResult.data) &&
148
- backgroundUserResult &&
149
- backgroundUserResult.data) {
150
- // Update cache with fresh data
151
- try {
152
- await scoutCache.setHerdModules(backgroundHerdModulesResult.data, cacheTtlMs);
116
+ if (!isOffline) {
117
+ // Background fetch fresh data without blocking
118
+ (async () => {
119
+ try {
120
+ const backgroundStartTime = Date.now();
121
+ const [backgroundHerdModulesResult, backgroundUserResult] = await Promise.all([
122
+ (async () => {
123
+ const start = Date.now();
124
+ const result = await server_load_herd_modules();
125
+ const totalDuration = Date.now() - start;
126
+ const serverDuration = result.server_processing_time_ms || totalDuration;
127
+ const clientOverhead = totalDuration - serverDuration;
128
+ console.log(`[useScoutRefresh] Background API timing breakdown:`);
129
+ console.log(` - Server processing: ${serverDuration}ms`);
130
+ console.log(` - Client overhead: ${clientOverhead}ms`);
131
+ console.log(` - Total request: ${totalDuration}ms`);
132
+ timingRefs.current.herdModulesDuration = serverDuration;
133
+ dispatch(setHerdModulesApiServerProcessingDuration(serverDuration));
134
+ dispatch(setHerdModulesApiTotalRequestDuration(totalDuration));
135
+ return result;
136
+ })(),
137
+ (async () => {
138
+ const start = Date.now();
139
+ const { data } = await supabase.auth.getUser();
140
+ const duration = Date.now() - start;
141
+ timingRefs.current.userApiDuration = duration;
142
+ dispatch(setUserApiDuration(duration));
143
+ return { data: data.user, status: "success" };
144
+ })(),
145
+ ]);
146
+ const backgroundDuration = Date.now() - backgroundStartTime;
147
+ // Validate background responses
148
+ if (backgroundHerdModulesResult.data &&
149
+ Array.isArray(backgroundHerdModulesResult.data) &&
150
+ backgroundUserResult &&
151
+ backgroundUserResult.data) {
152
+ // Update cache with fresh data
153
+ try {
154
+ await scoutCache.setHerdModules(backgroundHerdModulesResult.data, cacheTtlMs);
155
+ }
156
+ catch (cacheError) {
157
+ console.warn("[useScoutRefresh] Background cache save failed:", cacheError);
158
+ await handleIndexedDbError(cacheError, "background cache save", async () => {
159
+ if (backgroundHerdModulesResult.data) {
160
+ await scoutCache.setHerdModules(backgroundHerdModulesResult.data, cacheTtlMs);
161
+ }
162
+ });
163
+ }
164
+ // Update store with fresh data from background request
165
+ console.log(`[useScoutRefresh] Updating store with background herd modules`);
166
+ dispatch(setHerdModules(backgroundHerdModulesResult.data));
167
+ if (backgroundUserResult && backgroundUserResult.data) {
168
+ console.log(`[useScoutRefresh] Updating store with background user data`);
169
+ dispatch(setUser(backgroundUserResult.data));
170
+ }
171
+ // Update data source to DATABASE
172
+ dispatch(setDataSource(EnumDataSource.DATABASE));
173
+ dispatch(setDataSourceInfo({
174
+ source: EnumDataSource.DATABASE,
175
+ timestamp: Date.now(),
176
+ }));
153
177
  }
154
- catch (cacheError) {
155
- console.warn("[useScoutRefresh] Background cache save failed:", cacheError);
156
- await handleIndexedDbError(cacheError, "background cache save", async () => {
157
- if (backgroundHerdModulesResult.data) {
158
- await scoutCache.setHerdModules(backgroundHerdModulesResult.data, cacheTtlMs);
159
- }
160
- });
178
+ else {
179
+ console.warn("[useScoutRefresh] Background fetch returned invalid data");
161
180
  }
162
- // Update store with fresh data from background request
163
- console.log(`[useScoutRefresh] Updating store with background herd modules`);
164
- dispatch(setHerdModules(backgroundHerdModulesResult.data));
165
- if (backgroundUserResult && backgroundUserResult.data) {
166
- console.log(`[useScoutRefresh] Updating store with background user data`);
167
- dispatch(setUser(backgroundUserResult.data));
168
- }
169
- // Update data source to DATABASE
170
- dispatch(setDataSource(EnumDataSource.DATABASE));
171
- dispatch(setDataSourceInfo({
172
- source: EnumDataSource.DATABASE,
173
- timestamp: Date.now(),
174
- }));
175
181
  }
176
- else {
177
- console.warn("[useScoutRefresh] Background fetch returned invalid data");
182
+ catch (backgroundError) {
183
+ console.warn("[useScoutRefresh] Background fetch failed:", backgroundError);
178
184
  }
179
- }
180
- catch (backgroundError) {
181
- console.warn("[useScoutRefresh] Background fetch failed:", backgroundError);
182
- }
183
- })();
185
+ })();
186
+ }
184
187
  const totalDuration = Date.now() - startTime;
185
188
  dispatch(setHerdModulesLoadedInMs(totalDuration));
186
189
  dispatch(setStatus(EnumScoutStateStatus.DONE_LOADING));
@@ -197,6 +200,32 @@ export function useScoutRefresh(options = {}) {
197
200
  // Continue with API call
198
201
  }
199
202
  }
203
+ // When offline, skip network/auth; use cache if available
204
+ if (isOffline) {
205
+ if (cachedHerdModules && cachedHerdModules.length > 0) {
206
+ dispatch(setDataSource(EnumDataSource.CACHE));
207
+ dispatch(setDataSourceInfo({
208
+ source: EnumDataSource.CACHE,
209
+ timestamp: Date.now(),
210
+ }));
211
+ dispatch(setHerdModules(cachedHerdModules));
212
+ dispatch(setHerdModulesLoadingState(EnumHerdModulesLoadingState.SUCCESSFULLY_LOADED));
213
+ }
214
+ else {
215
+ dispatch(setHerdModulesLoadingState(EnumHerdModulesLoadingState.UNSUCCESSFULLY_LOADED));
216
+ dispatch(setDataSource(EnumDataSource.UNKNOWN));
217
+ dispatch(setDataSourceInfo({
218
+ source: EnumDataSource.UNKNOWN,
219
+ timestamp: Date.now(),
220
+ }));
221
+ }
222
+ dispatch(setHerdModulesLoadedInMs(Date.now() - startTime));
223
+ dispatch(setStatus(EnumScoutStateStatus.DONE_LOADING));
224
+ onRefreshComplete?.();
225
+ refreshInProgressRef.current = false;
226
+ lastQueryAtRef.current = Date.now();
227
+ return;
228
+ }
200
229
  // Step 2: Load fresh data from API
201
230
  const parallelStartTime = Date.now();
202
231
  const [herdModulesResult, userResult] = await Promise.all([
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adventurelabs/scout-core",
3
- "version": "1.4.37",
3
+ "version": "1.4.38",
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",