@adventurelabs/scout-core 1.0.99 → 1.0.101

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.
@@ -10,7 +10,9 @@ export function convertDateToTimeString(date) {
10
10
  return `${date.toLocaleTimeString()}, ${date.toLocaleDateString()} UTC`;
11
11
  }
12
12
  // Format a Date object as a PostgreSQL-compatible timestamp string
13
- // Returns format: "YYYY-MM-DDTHH:MM:SS.SSSZ" (ISO 8601 with timezone)
13
+ // Returns ISO 8601 format: "YYYY-MM-DDTHH:MM:SS.SSSZ"
14
+ // PostgreSQL automatically converts this to its internal format: "YYYY-MM-DD HH:MM:SS.SSSSSS+00"
15
+ // This ensures compatibility with both PostgreSQL storage and RPC function expectations
14
16
  export function formatTimestampForDatabase(date) {
15
17
  return date.toISOString();
16
18
  }
@@ -5,7 +5,7 @@ import { useEffect, useRef, useCallback, useMemo } from "react";
5
5
  import { setActiveHerdGpsTrackersConnectivity } from "../store/scout";
6
6
  import { server_get_connectivity_by_device_id } from "../helpers/connectivity";
7
7
  import { EnumWebResponse } from "../types/requests";
8
- import { getDaysAgoTimestamp } from "../helpers/time";
8
+ import { getHoursAgoTimestamp } from "../helpers/time";
9
9
  export function useScoutRealtimeConnectivity(scoutSupabase) {
10
10
  const channels = useRef([]);
11
11
  const dispatch = useAppDispatch();
@@ -39,65 +39,69 @@ export function useScoutRealtimeConnectivity(scoutSupabase) {
39
39
  const updatedConnectivity = { ...connectivity };
40
40
  switch (data.operation) {
41
41
  case "INSERT":
42
+ console.log(`[CONNECTIVITY] INSERT for ${deviceId}, ${JSON.stringify(connectivityData)}`);
42
43
  if (!updatedConnectivity[deviceId]) {
43
44
  updatedConnectivity[deviceId] = {
44
45
  most_recent: connectivityData,
45
- history: [connectivityData],
46
+ history: [],
46
47
  };
47
48
  }
48
49
  else {
49
- // Create a copy of the existing historical data
50
50
  const newHistory = [
51
+ updatedConnectivity[deviceId].most_recent,
51
52
  ...updatedConnectivity[deviceId].history,
52
- connectivityData,
53
- ];
54
- // Keep only recent 100 entries
55
- const sortedHistory = newHistory
56
- .sort((a, b) => new Date(b.timestamp_start || 0).getTime() -
57
- new Date(a.timestamp_start || 0).getTime())
58
- .slice(0, 100);
53
+ ].slice(0, 99);
59
54
  updatedConnectivity[deviceId] = {
60
- most_recent: sortedHistory[0],
61
- history: sortedHistory,
55
+ most_recent: connectivityData,
56
+ history: newHistory,
62
57
  };
63
58
  }
64
59
  break;
65
60
  case "UPDATE":
66
61
  if (updatedConnectivity[deviceId]) {
67
- // Create a copy of the history array before modifying
68
- const newHistory = [...updatedConnectivity[deviceId].history];
69
- const index = newHistory.findIndex((c) => c.id === connectivityData.id);
70
- if (index >= 0) {
71
- newHistory[index] = connectivityData;
72
- // Update most_recent if this was the most recent item
73
- const sortedHistory = newHistory.sort((a, b) => new Date(b.timestamp_start || 0).getTime() -
74
- new Date(a.timestamp_start || 0).getTime());
62
+ if (updatedConnectivity[deviceId].most_recent.id ===
63
+ connectivityData.id) {
75
64
  updatedConnectivity[deviceId] = {
76
- most_recent: sortedHistory[0],
77
- history: sortedHistory,
65
+ ...updatedConnectivity[deviceId],
66
+ most_recent: connectivityData,
78
67
  };
79
68
  }
69
+ else {
70
+ const historyIndex = updatedConnectivity[deviceId].history.findIndex((c) => c.id === connectivityData.id);
71
+ if (historyIndex >= 0) {
72
+ const newHistory = [...updatedConnectivity[deviceId].history];
73
+ newHistory[historyIndex] = connectivityData;
74
+ updatedConnectivity[deviceId] = {
75
+ ...updatedConnectivity[deviceId],
76
+ history: newHistory,
77
+ };
78
+ }
79
+ }
80
80
  }
81
81
  break;
82
82
  case "DELETE":
83
83
  if (updatedConnectivity[deviceId]) {
84
- // Filter creates a new array, so this is safe
85
- const newHistory = updatedConnectivity[deviceId].history.filter((c) => c.id !== connectivityData.id);
86
- if (newHistory.length === 0) {
87
- delete updatedConnectivity[deviceId];
84
+ if (updatedConnectivity[deviceId].most_recent.id ===
85
+ connectivityData.id) {
86
+ if (updatedConnectivity[deviceId].history.length === 0) {
87
+ delete updatedConnectivity[deviceId];
88
+ }
89
+ else {
90
+ updatedConnectivity[deviceId] = {
91
+ most_recent: updatedConnectivity[deviceId].history[0],
92
+ history: updatedConnectivity[deviceId].history.slice(1),
93
+ };
94
+ }
88
95
  }
89
96
  else {
90
- const sortedHistory = newHistory.sort((a, b) => new Date(b.timestamp_start || 0).getTime() -
91
- new Date(a.timestamp_start || 0).getTime());
92
97
  updatedConnectivity[deviceId] = {
93
- most_recent: sortedHistory[0],
94
- history: sortedHistory,
98
+ ...updatedConnectivity[deviceId],
99
+ history: updatedConnectivity[deviceId].history.filter((c) => c.id !== connectivityData.id),
95
100
  };
96
101
  }
97
102
  }
98
103
  break;
99
104
  }
100
- console.log("[Connectivity] updating tracker connectivity in response to broadcast");
101
105
  dispatch(setActiveHerdGpsTrackersConnectivity(updatedConnectivity));
102
106
  }, [connectivity, dispatch]);
103
107
  // Fetch initial connectivity data
@@ -108,8 +112,7 @@ export function useScoutRealtimeConnectivity(scoutSupabase) {
108
112
  if (deviceIds.length === 0) {
109
113
  return;
110
114
  }
111
- console.log(`[Connectivity] Loading data for ${deviceIds.length} GPS trackers`);
112
- const timestampFilter = getDaysAgoTimestamp(1);
115
+ const timestampFilter = getHoursAgoTimestamp(1);
113
116
  const connectivityData = {};
114
117
  await Promise.all(deviceIds.map(async (deviceId) => {
115
118
  try {
@@ -123,25 +126,20 @@ export function useScoutRealtimeConnectivity(scoutSupabase) {
123
126
  .slice(0, 100);
124
127
  connectivityData[deviceId] = {
125
128
  most_recent: sortedData[0],
126
- history: sortedData,
129
+ history: sortedData.slice(1), // Exclude the most recent item
127
130
  };
128
131
  }
129
132
  }
130
- else {
131
- console.warn(`[Connectivity] API error for device ${deviceId}:`, response.msg || "Unknown error");
132
- }
133
133
  }
134
134
  catch (error) {
135
- console.warn(`[Connectivity] Failed to fetch data for device ${deviceId}:`, error);
135
+ // Silent error handling
136
136
  }
137
137
  }));
138
138
  dispatch(setActiveHerdGpsTrackersConnectivity(connectivityData));
139
- console.log(`[Connectivity] Loaded data for ${Object.keys(connectivityData).length} devices`);
140
139
  }, [gpsDeviceIds, dispatch]);
141
140
  useEffect(() => {
142
141
  if (!scoutSupabase || gpsDeviceIds === "")
143
142
  return;
144
- console.log(`[Connectivity Hook] Loading data for ${gpsDeviceIds}`);
145
143
  // Clean up existing channels
146
144
  channels.current.forEach((channel) => scoutSupabase.removeChannel(channel));
147
145
  channels.current = [];
@@ -149,14 +147,7 @@ export function useScoutRealtimeConnectivity(scoutSupabase) {
149
147
  const channel = scoutSupabase
150
148
  .channel(`${activeHerdId}-connectivity`, { config: { private: true } })
151
149
  .on("broadcast", { event: "*" }, handleConnectivityBroadcast)
152
- .subscribe((status) => {
153
- if (status === "SUBSCRIBED") {
154
- console.log(`[Connectivity] ✅ Connected to herd ${activeHerdId}`);
155
- }
156
- else if (status === "CHANNEL_ERROR") {
157
- console.warn(`[Connectivity] 🟡 Failed to connect to herd ${activeHerdId}`);
158
- }
159
- });
150
+ .subscribe();
160
151
  channels.current.push(channel);
161
152
  // Fetch initial data
162
153
  fetchInitialData();
@@ -164,11 +155,5 @@ export function useScoutRealtimeConnectivity(scoutSupabase) {
164
155
  channels.current.forEach((ch) => scoutSupabase.removeChannel(ch));
165
156
  channels.current = [];
166
157
  };
167
- }, [
168
- scoutSupabase,
169
- gpsDeviceIds,
170
- activeHerdId,
171
- handleConnectivityBroadcast,
172
- fetchInitialData,
173
- ]);
158
+ }, [scoutSupabase, gpsDeviceIds, activeHerdId, handleConnectivityBroadcast]);
174
159
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adventurelabs/scout-core",
3
- "version": "1.0.99",
3
+ "version": "1.0.101",
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",