@adventurelabs/scout-core 1.0.79 → 1.0.82

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,8 +1,9 @@
1
- import { IDevice } from "../types/db";
1
+ import { Database } from "@/types";
2
+ import { DeviceInsert, IDevice } from "../types/db";
2
3
  import { IWebResponseCompatible } from "../types/requests";
3
4
  import { SupabaseClient } from "@supabase/supabase-js";
4
- export declare function get_devices_by_herd(herd_id: number, client: SupabaseClient): Promise<IWebResponseCompatible<IDevice[]>>;
5
- export declare function get_device_by_id(device_id: number, client?: SupabaseClient): Promise<IWebResponseCompatible<IDevice | null>>;
5
+ export declare function get_devices_by_herd(herd_id: number, client: SupabaseClient<Database>): Promise<IWebResponseCompatible<IDevice[]>>;
6
+ export declare function get_device_by_id(device_id: number, client?: SupabaseClient<Database>): Promise<IWebResponseCompatible<IDevice | null>>;
6
7
  export declare function serverUpdateDevice(updatedDevice: IDevice): Promise<IWebResponseCompatible<IDevice | null>>;
7
- export declare function serverCreateDevice(newDevice: any): Promise<IWebResponseCompatible<IDevice | null>>;
8
+ export declare function serverCreateDevice(newDevice: DeviceInsert): Promise<IWebResponseCompatible<IDevice | null>>;
8
9
  export declare function serverDeleteDeviceById(device_id: number): Promise<IWebResponseCompatible<IDevice | null>>;
@@ -60,6 +60,9 @@ export async function serverCreateDevice(newDevice) {
60
60
  const supabase = await newServerClient();
61
61
  const user = await supabase.auth.getUser();
62
62
  const userId = user?.data?.user?.id;
63
+ if (!userId) {
64
+ return IWebResponse.error("User not found").to_compatible();
65
+ }
63
66
  newDevice.created_by = userId;
64
67
  // strip id field from herd object
65
68
  const { data, error } = await supabase
@@ -152,7 +152,8 @@ export async function server_upsert_sessions(sessionsData) {
152
152
  if (updates.length > 0) {
153
153
  for (const sessionData of updates) {
154
154
  const updateResult = await server_upsert_session(sessionData);
155
- if (updateResult.status === EnumWebResponse.SUCCESS && updateResult.data) {
155
+ if (updateResult.status === EnumWebResponse.SUCCESS &&
156
+ updateResult.data) {
156
157
  results.push(updateResult.data);
157
158
  }
158
159
  else {
@@ -233,7 +234,8 @@ export async function server_upsert_connectivity_batch(connectivityDataArray) {
233
234
  if (updates.length > 0) {
234
235
  for (const connectivityData of updates) {
235
236
  const updateResult = await server_upsert_connectivity(connectivityData);
236
- if (updateResult.status === EnumWebResponse.SUCCESS && updateResult.data) {
237
+ if (updateResult.status === EnumWebResponse.SUCCESS &&
238
+ updateResult.data) {
237
239
  results.push(updateResult.data);
238
240
  }
239
241
  else {
@@ -266,8 +268,10 @@ export async function server_get_session_with_connectivity_and_events(sessionId,
266
268
  if (herdId) {
267
269
  // Use provided herd ID directly
268
270
  const sessionsResult = await server_get_sessions_by_herd_id(herdId);
269
- if (sessionsResult.status === EnumWebResponse.SUCCESS && sessionsResult.data) {
270
- sessionWithCoords = sessionsResult.data.find((s) => s.id === sessionId) || null;
271
+ if (sessionsResult.status === EnumWebResponse.SUCCESS &&
272
+ sessionsResult.data) {
273
+ sessionWithCoords =
274
+ sessionsResult.data.find((s) => s.id === sessionId) || null;
271
275
  }
272
276
  }
273
277
  else {
@@ -308,16 +312,22 @@ export async function server_get_session_with_connectivity_and_events(sessionId,
308
312
  };
309
313
  }
310
314
  const sessionsResult = await server_get_sessions_by_herd_id(device.herd_id);
311
- if (sessionsResult.status === EnumWebResponse.SUCCESS && sessionsResult.data) {
312
- sessionWithCoords = sessionsResult.data.find((s) => s.id === sessionId) || null;
315
+ if (sessionsResult.status === EnumWebResponse.SUCCESS &&
316
+ sessionsResult.data) {
317
+ sessionWithCoords =
318
+ sessionsResult.data.find((s) => s.id === sessionId) || null;
313
319
  }
314
320
  }
315
321
  const [connectivityResult, eventsResult] = await Promise.all([
316
322
  server_get_connectivity_by_session_id(sessionId),
317
323
  server_get_events_by_session_id(sessionId),
318
324
  ]);
319
- const connectivity = connectivityResult.status === EnumWebResponse.SUCCESS ? connectivityResult.data || [] : [];
320
- const events = eventsResult.status === EnumWebResponse.SUCCESS ? eventsResult.data || [] : [];
325
+ const connectivity = connectivityResult.status === EnumWebResponse.SUCCESS
326
+ ? connectivityResult.data || []
327
+ : [];
328
+ const events = eventsResult.status === EnumWebResponse.SUCCESS
329
+ ? eventsResult.data || []
330
+ : [];
321
331
  return IWebResponse.success({
322
332
  session: sessionWithCoords,
323
333
  connectivity,
@@ -333,8 +343,10 @@ export async function server_get_session_with_connectivity_and_events_with_tags(
333
343
  // Use provided herd ID directly
334
344
  actualHerdId = herdId;
335
345
  const sessionsResult = await server_get_sessions_by_herd_id(herdId);
336
- if (sessionsResult.status === EnumWebResponse.SUCCESS && sessionsResult.data) {
337
- sessionWithCoords = sessionsResult.data.find((s) => s.id === sessionId) || null;
346
+ if (sessionsResult.status === EnumWebResponse.SUCCESS &&
347
+ sessionsResult.data) {
348
+ sessionWithCoords =
349
+ sessionsResult.data.find((s) => s.id === sessionId) || null;
338
350
  }
339
351
  }
340
352
  else {
@@ -378,8 +390,10 @@ export async function server_get_session_with_connectivity_and_events_with_tags(
378
390
  }
379
391
  actualHerdId = device.herd_id;
380
392
  const sessionsResult = await server_get_sessions_by_herd_id(device.herd_id);
381
- if (sessionsResult.status === EnumWebResponse.SUCCESS && sessionsResult.data) {
382
- sessionWithCoords = sessionsResult.data.find((s) => s.id === sessionId) || null;
393
+ if (sessionsResult.status === EnumWebResponse.SUCCESS &&
394
+ sessionsResult.data) {
395
+ sessionWithCoords =
396
+ sessionsResult.data.find((s) => s.id === sessionId) || null;
383
397
  }
384
398
  }
385
399
  const [connectivityResult, eventsWithTagsResult, totalEventsResult] = await Promise.all([
@@ -387,9 +401,15 @@ export async function server_get_session_with_connectivity_and_events_with_tags(
387
401
  server_get_events_and_tags_by_session_id(sessionId, limit, offset),
388
402
  server_get_total_events_for_session(sessionId),
389
403
  ]);
390
- const connectivity = connectivityResult.status === EnumWebResponse.SUCCESS ? connectivityResult.data || [] : [];
391
- const eventsWithTags = eventsWithTagsResult.status === EnumWebResponse.SUCCESS ? eventsWithTagsResult.data || [] : [];
392
- const totalEvents = totalEventsResult.status === EnumWebResponse.SUCCESS ? totalEventsResult.data || 0 : 0;
404
+ const connectivity = connectivityResult.status === EnumWebResponse.SUCCESS
405
+ ? connectivityResult.data || []
406
+ : [];
407
+ const eventsWithTags = eventsWithTagsResult.status === EnumWebResponse.SUCCESS
408
+ ? eventsWithTagsResult.data || []
409
+ : [];
410
+ const totalEvents = totalEventsResult.status === EnumWebResponse.SUCCESS
411
+ ? totalEventsResult.data || 0
412
+ : 0;
393
413
  return IWebResponse.success({
394
414
  session: sessionWithCoords,
395
415
  connectivity,
@@ -77,7 +77,7 @@ export function useScoutRefresh(options = {}) {
77
77
  if (cacheResult.data && cacheResult.data.length > 0) {
78
78
  cachedHerdModules = cacheResult.data;
79
79
  console.log(`[useScoutRefresh] Loaded ${cachedHerdModules.length} herd modules from cache in ${cacheLoadDuration}ms (age: ${Math.round(cacheResult.age / 1000)}s, stale: ${cacheResult.isStale})`);
80
- // Set data source to CACHE
80
+ // Set data source to CACHE initially
81
81
  dispatch(setDataSource(EnumDataSource.CACHE));
82
82
  dispatch(setDataSourceInfo({
83
83
  source: EnumDataSource.CACHE,
@@ -88,22 +88,65 @@ export function useScoutRefresh(options = {}) {
88
88
  // Immediately update the store with cached data
89
89
  dispatch(setHerdModules(cachedHerdModules));
90
90
  dispatch(setHerdModulesLoadingState(EnumHerdModulesLoadingState.SUCCESSFULLY_LOADED));
91
- // If cache is fresh, we can return early
91
+ // Always load user data from API
92
+ const userStartTime = Date.now();
93
+ const res_new_user = await server_get_user();
94
+ const userApiDuration = Date.now() - userStartTime;
95
+ timingRefs.current.userApiDuration = userApiDuration;
96
+ dispatch(setUserApiDuration(userApiDuration));
97
+ if (res_new_user && res_new_user.data) {
98
+ dispatch(setUser(res_new_user.data));
99
+ }
100
+ // If cache is fresh, we still background fetch but don't wait
92
101
  if (!cacheResult.isStale) {
93
- console.log("[useScoutRefresh] Cache is fresh, skipping API call");
94
- // Still need to load user data
95
- const userStartTime = Date.now();
96
- const res_new_user = await server_get_user();
97
- const userApiDuration = Date.now() - userStartTime;
98
- timingRefs.current.userApiDuration = userApiDuration;
99
- dispatch(setUserApiDuration(userApiDuration));
100
- if (res_new_user && res_new_user.data) {
101
- dispatch(setUser(res_new_user.data));
102
- }
102
+ console.log("[useScoutRefresh] Cache is fresh, background fetching fresh data...");
103
+ // Background fetch fresh data without blocking
104
+ (async () => {
105
+ try {
106
+ console.log("[useScoutRefresh] Starting background fetch...");
107
+ const backgroundStartTime = Date.now();
108
+ const [backgroundHerdModulesResult, backgroundUserResult] = await Promise.all([
109
+ server_load_herd_modules(),
110
+ server_get_user()
111
+ ]);
112
+ const backgroundDuration = Date.now() - backgroundStartTime;
113
+ console.log(`[useScoutRefresh] Background fetch completed in ${backgroundDuration}ms`);
114
+ // Validate background responses
115
+ if (backgroundHerdModulesResult.data &&
116
+ Array.isArray(backgroundHerdModulesResult.data) &&
117
+ backgroundUserResult &&
118
+ backgroundUserResult.data) {
119
+ // Update cache with fresh data
120
+ try {
121
+ await scoutCache.setHerdModules(backgroundHerdModulesResult.data, cacheTtlMs);
122
+ console.log(`[useScoutRefresh] Background cache updated with TTL: ${Math.round(cacheTtlMs / 1000)}s`);
123
+ }
124
+ catch (cacheError) {
125
+ console.warn("[useScoutRefresh] Background cache save failed:", cacheError);
126
+ }
127
+ // Update store with fresh data
128
+ dispatch(setHerdModules(backgroundHerdModulesResult.data));
129
+ dispatch(setUser(backgroundUserResult.data));
130
+ // Update data source to DATABASE
131
+ dispatch(setDataSource(EnumDataSource.DATABASE));
132
+ dispatch(setDataSourceInfo({
133
+ source: EnumDataSource.DATABASE,
134
+ timestamp: Date.now(),
135
+ }));
136
+ console.log("[useScoutRefresh] Background fetch completed and store updated");
137
+ }
138
+ else {
139
+ console.warn("[useScoutRefresh] Background fetch returned invalid data");
140
+ }
141
+ }
142
+ catch (backgroundError) {
143
+ console.warn("[useScoutRefresh] Background fetch failed:", backgroundError);
144
+ }
145
+ })();
103
146
  const totalDuration = Date.now() - startTime;
104
147
  dispatch(setHerdModulesLoadedInMs(totalDuration));
105
148
  dispatch(setStatus(EnumScoutStateStatus.DONE_LOADING));
106
- console.log(`[useScoutRefresh] Cache-first refresh completed in ${totalDuration}ms`);
149
+ console.log(`[useScoutRefresh] Cache-first refresh completed in ${totalDuration}ms (background fetch in progress)`);
107
150
  onRefreshComplete?.();
108
151
  return;
109
152
  }
@@ -8,7 +8,7 @@ interface ConnectionStatus {
8
8
  retryCount: number;
9
9
  reconnect: () => void;
10
10
  }
11
- export declare function useSupabase(): SupabaseClient<Database, "public", {
11
+ export declare function useSupabase(): SupabaseClient<Database, "public", "public", {
12
12
  Tables: {
13
13
  actions: {
14
14
  Row: {
@@ -408,9 +408,9 @@ export declare function useSupabase(): SupabaseClient<Database, "public", {
408
408
  earthranger_url: string | null;
409
409
  id: number;
410
410
  inserted_at: string;
411
- locations: unknown;
411
+ locations: unknown | null;
412
412
  software_version: string;
413
- timestamp_end: string;
413
+ timestamp_end: string | null;
414
414
  timestamp_start: string;
415
415
  velocity_average: number;
416
416
  velocity_max: number;
@@ -426,9 +426,9 @@ export declare function useSupabase(): SupabaseClient<Database, "public", {
426
426
  earthranger_url?: string | null;
427
427
  id?: number;
428
428
  inserted_at?: string;
429
- locations: unknown;
429
+ locations?: unknown | null;
430
430
  software_version: string;
431
- timestamp_end: string;
431
+ timestamp_end?: string | null;
432
432
  timestamp_start: string;
433
433
  velocity_average: number;
434
434
  velocity_max: number;
@@ -444,9 +444,9 @@ export declare function useSupabase(): SupabaseClient<Database, "public", {
444
444
  earthranger_url?: string | null;
445
445
  id?: number;
446
446
  inserted_at?: string;
447
- locations?: unknown;
447
+ locations?: unknown | null;
448
448
  software_version?: string;
449
- timestamp_end?: string;
449
+ timestamp_end?: string | null;
450
450
  timestamp_start?: string;
451
451
  velocity_average?: number;
452
452
  velocity_max?: number;
@@ -829,7 +829,7 @@ export declare function useSupabase(): SupabaseClient<Database, "public", {
829
829
  device_type: "trail_camera" | "drone_fixed_wing" | "drone_quad" | "gps_tracker" | "sentry_tower" | "smart_buoy" | "radio_mesh_base_station" | "radio_mesh_repeater" | "unknown";
830
830
  media_type: "image" | "video" | "audio" | "text";
831
831
  plan_type: "mission" | "fence" | "rally" | "markov";
832
- role: "admin" | "viewer" | "editor";
832
+ role: "admin" | "viewer" | "editor" | "operator";
833
833
  tag_observation_type: "manual" | "auto";
834
834
  user_status: "ONLINE" | "OFFLINE";
835
835
  };
@@ -970,6 +970,8 @@ export declare function useSupabase(): SupabaseClient<Database, "public", {
970
970
  actions: Database["public"]["Tables"]["actions"]["Row"][] | null;
971
971
  };
972
972
  };
973
+ }, {
974
+ PostgrestVersion: "13.0.5";
973
975
  }>;
974
976
  export declare function useConnectionStatus(): ConnectionStatus;
975
977
  export interface ScoutRefreshProviderProps {
@@ -1,4 +1,4 @@
1
- export declare const useAppDispatch: <AppDispatch extends import("redux").Dispatch<import("redux").AnyAction> = import("redux").Dispatch<import("redux").AnyAction>>() => AppDispatch;
1
+ export declare const useAppDispatch: import("react-redux").UseDispatch<import("redux").Dispatch<import("redux").UnknownAction>>;
2
2
  export declare const useHerdModulesLoadingState: () => any;
3
3
  export declare const useIsHerdModulesLoading: () => boolean;
4
4
  export declare const useIsHerdModulesLoaded: () => boolean;