@adventurelabs/scout-core 1.4.67 → 1.4.69

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.
Files changed (34) hide show
  1. package/dist/helpers/index.d.ts +3 -0
  2. package/dist/helpers/index.js +3 -0
  3. package/dist/helpers/lifecycle.d.ts +14 -0
  4. package/dist/helpers/lifecycle.js +74 -0
  5. package/dist/helpers/parts.d.ts +19 -13
  6. package/dist/helpers/parts.js +51 -47
  7. package/dist/helpers/pubsub_token.d.ts +5 -0
  8. package/dist/helpers/pubsub_token.js +14 -0
  9. package/dist/helpers/pubsub_token_server.d.ts +7 -0
  10. package/dist/helpers/pubsub_token_server.js +7 -0
  11. package/dist/index.d.ts +3 -0
  12. package/dist/index.js +3 -0
  13. package/dist/providers/ScoutRefreshProvider.d.ts +208 -15
  14. package/dist/types/db.d.ts +2 -0
  15. package/dist/types/pubsub_token.d.ts +7 -0
  16. package/dist/types/supabase.d.ts +217 -17
  17. package/dist/types/supabase.js +2 -2
  18. package/package.json +1 -1
  19. package/dist/helpers/components.d.ts +0 -14
  20. package/dist/helpers/components.js +0 -155
  21. package/dist/helpers/operator.d.ts +0 -5
  22. package/dist/helpers/operator.js +0 -64
  23. package/dist/hooks/useHerdData.d.ts +0 -167
  24. package/dist/hooks/useHerdData.js +0 -153
  25. package/dist/hooks/useScoutBrowserClient.d.ts +0 -11
  26. package/dist/hooks/useScoutBrowserClient.js +0 -17
  27. package/dist/hooks/useScoutDbListener.d.ts +0 -3
  28. package/dist/hooks/useScoutDbListener.js +0 -134
  29. package/dist/hooks/useScoutRealtimeConnectivity copy.d.ts +0 -3
  30. package/dist/hooks/useScoutRealtimeConnectivity copy.js +0 -159
  31. package/dist/hooks/useScoutRealtimeDevices copy.d.ts +0 -3
  32. package/dist/hooks/useScoutRealtimeDevices copy.js +0 -55
  33. package/dist/types/data.d.ts +0 -4
  34. /package/dist/types/{data.js → pubsub_token.js} +0 -0
@@ -1,134 +0,0 @@
1
- "use client";
2
- import { useAppDispatch } from "../store/hooks";
3
- import { useEffect, useRef } from "react";
4
- import { addDevice, addPlan, addTag, addSessionToStore, deleteDevice, deletePlan, deleteSessionFromStore, deleteTag, updateDevice, updatePlan, updateSessionInStore, updateTag, } from "../store/scout";
5
- export function useScoutDbListener(scoutSupabase) {
6
- const supabase = useRef(null);
7
- const channels = useRef([]);
8
- const dispatch = useAppDispatch();
9
- function handleTagInserts(payload) {
10
- console.log("[DB Listener] Tag INSERT received:", payload.new);
11
- dispatch(addTag(payload.new));
12
- }
13
- function handleTagDeletes(payload) {
14
- console.log("[DB Listener] Tag DELETE received:", payload.old);
15
- if (!payload.old || !payload.old.id) {
16
- console.error("[DB Listener] Tag DELETE - Invalid payload, missing tag data");
17
- return;
18
- }
19
- dispatch(deleteTag(payload.old));
20
- }
21
- function handleTagUpdates(payload) {
22
- console.log("[DB Listener] Tag UPDATE received:", payload.new);
23
- dispatch(updateTag(payload.new));
24
- }
25
- function handleDeviceInserts(payload) {
26
- console.log("[DB Listener] Device INSERT received:", payload.new);
27
- dispatch(addDevice(payload.new));
28
- }
29
- function handleDeviceDeletes(payload) {
30
- console.log("[DB Listener] Device DELETE received:", payload.old);
31
- dispatch(deleteDevice(payload.old));
32
- }
33
- function handleDeviceUpdates(payload) {
34
- console.log("[DB Listener] Device UPDATE received:", payload.new);
35
- dispatch(updateDevice(payload.new));
36
- }
37
- function handlePlanInserts(payload) {
38
- console.log("[DB Listener] Plan INSERT received:", payload.new);
39
- dispatch(addPlan(payload.new));
40
- }
41
- function handlePlanDeletes(payload) {
42
- console.log("[DB Listener] Plan DELETE received:", payload.old);
43
- dispatch(deletePlan(payload.old));
44
- }
45
- function handlePlanUpdates(payload) {
46
- console.log("[DB Listener] Plan UPDATE received:", payload.new);
47
- dispatch(updatePlan(payload.new));
48
- }
49
- function handleSessionInserts(payload) {
50
- console.log("[DB Listener] Session INSERT received:", payload.new);
51
- dispatch(addSessionToStore(payload.new));
52
- }
53
- function handleSessionDeletes(payload) {
54
- console.log("[DB Listener] Session DELETE received:", payload.old);
55
- if (!payload.old || !payload.old.id) {
56
- console.error("[DB Listener] Session DELETE - Invalid payload, missing session data");
57
- return;
58
- }
59
- dispatch(deleteSessionFromStore(payload.old));
60
- }
61
- function handleSessionUpdates(payload) {
62
- console.log("[DB Listener] Session UPDATE received:", payload.new);
63
- dispatch(updateSessionInStore(payload.new));
64
- }
65
- function handleConnectivityInserts(payload) {
66
- console.log("[DB Listener] Connectivity INSERT received:", payload.new);
67
- }
68
- function handleConnectivityDeletes(payload) {
69
- console.log("[DB Listener] Connectivity DELETE received:", payload.old);
70
- }
71
- function handleConnectivityUpdates(payload) {
72
- console.log("[DB Listener] Connectivity UPDATE received:", payload.new);
73
- }
74
- // Clean up all channels
75
- const cleanupChannels = () => {
76
- channels.current.forEach((channel) => {
77
- if (channel) {
78
- scoutSupabase.removeChannel(channel);
79
- }
80
- });
81
- channels.current = [];
82
- };
83
- // Setup channel with event handlers
84
- const setupChannel = () => {
85
- if (!scoutSupabase)
86
- return null;
87
- const channelId = `scout_realtime_${Date.now()}_${Math.random()
88
- .toString(36)
89
- .substr(2, 9)}`;
90
- const mainChannel = scoutSupabase.channel(channelId);
91
- console.log(`[DB Listener] Creating channel: ${channelId}`);
92
- // Subscribe to all events
93
- mainChannel
94
- .on("postgres_changes", { event: "INSERT", schema: "public", table: "plans" }, handlePlanInserts)
95
- .on("postgres_changes", { event: "DELETE", schema: "public", table: "plans" }, handlePlanDeletes)
96
- .on("postgres_changes", { event: "UPDATE", schema: "public", table: "plans" }, handlePlanUpdates)
97
- .on("postgres_changes", { event: "INSERT", schema: "public", table: "devices" }, handleDeviceInserts)
98
- .on("postgres_changes", { event: "DELETE", schema: "public", table: "devices" }, handleDeviceDeletes)
99
- .on("postgres_changes", { event: "UPDATE", schema: "public", table: "devices" }, handleDeviceUpdates)
100
- .on("postgres_changes", { event: "INSERT", schema: "public", table: "tags" }, handleTagInserts)
101
- .on("postgres_changes", { event: "DELETE", schema: "public", table: "tags" }, handleTagDeletes)
102
- .on("postgres_changes", { event: "UPDATE", schema: "public", table: "tags" }, handleTagUpdates)
103
- .on("postgres_changes", { event: "INSERT", schema: "public", table: "connectivity" }, handleConnectivityInserts)
104
- .on("postgres_changes", { event: "DELETE", schema: "public", table: "connectivity" }, handleConnectivityDeletes)
105
- .on("postgres_changes", { event: "UPDATE", schema: "public", table: "connectivity" }, handleConnectivityUpdates)
106
- .on("postgres_changes", { event: "INSERT", schema: "public", table: "sessions" }, handleSessionInserts)
107
- .on("postgres_changes", { event: "DELETE", schema: "public", table: "sessions" }, handleSessionDeletes)
108
- .on("postgres_changes", { event: "UPDATE", schema: "public", table: "sessions" }, handleSessionUpdates)
109
- .subscribe((status) => {
110
- console.log("[DB Listener] Subscription status:", status);
111
- if (status === "SUBSCRIBED") {
112
- console.log("[DB Listener] ✅ Successfully subscribed to real-time updates");
113
- }
114
- });
115
- return mainChannel;
116
- };
117
- useEffect(() => {
118
- if (!scoutSupabase) {
119
- console.error("[DB Listener] No Supabase client available");
120
- return;
121
- }
122
- supabase.current = scoutSupabase;
123
- // Initial channel setup
124
- const mainChannel = setupChannel();
125
- if (mainChannel) {
126
- channels.current.push(mainChannel);
127
- }
128
- // Cleanup function
129
- return () => {
130
- console.log("[DB Listener] 🧹 Cleaning up channels");
131
- cleanupChannels();
132
- };
133
- }, [scoutSupabase, dispatch]);
134
- }
@@ -1,3 +0,0 @@
1
- import { SupabaseClient } from "@supabase/supabase-js";
2
- import { Database } from "../types/supabase";
3
- export declare function useScoutRealtimeConnectivity(scoutSupabase: SupabaseClient<Database>): void;
@@ -1,159 +0,0 @@
1
- "use client";
2
- import { useAppDispatch } from "../store/hooks";
3
- import { useSelector } from "react-redux";
4
- import { useEffect, useRef, useCallback, useMemo } from "react";
5
- import { setActiveHerdGpsTrackersConnectivity } from "../store/scout";
6
- import { server_get_connectivity_by_device_id } from "../helpers/connectivity";
7
- import { EnumWebResponse } from "../types/requests";
8
- import { getHoursAgoTimestamp } from "../helpers/time";
9
- export function useScoutRealtimeConnectivity(scoutSupabase) {
10
- const channels = useRef([]);
11
- const dispatch = useAppDispatch();
12
- const activeHerdId = useSelector((state) => state.scout.active_herd_id);
13
- const connectivity = useSelector((state) => state.scout.active_herd_gps_trackers_connectivity);
14
- const herdModules = useSelector((state) => state.scout.herd_modules);
15
- // Create stable reference for GPS device IDs to prevent unnecessary refetching
16
- const gpsDeviceIds = useMemo(() => {
17
- if (!activeHerdId)
18
- return "";
19
- const activeHerdModule = herdModules.find((hm) => hm.herd.id.toString() === activeHerdId);
20
- if (!activeHerdModule)
21
- return "";
22
- const gpsDevices = activeHerdModule.devices.filter((device) => device.device_type &&
23
- ["gps_tracker", "gps_tracker_vehicle", "gps_tracker_person"].includes(device.device_type));
24
- return gpsDevices
25
- .map((d) => d.id)
26
- .filter(Boolean)
27
- .sort()
28
- .join(",");
29
- }, [activeHerdId, herdModules]);
30
- // Handle connectivity broadcasts
31
- const handleConnectivityBroadcast = useCallback((payload) => {
32
- const { event, payload: data } = payload;
33
- const connectivityData = data.record || data.old_record;
34
- // Only process GPS tracker data (no session_id)
35
- if (!connectivityData?.device_id || connectivityData.session_id) {
36
- return;
37
- }
38
- const deviceId = connectivityData.device_id;
39
- const updatedConnectivity = { ...connectivity };
40
- switch (data.operation) {
41
- case "INSERT":
42
- console.log(`[CONNECTIVITY] INSERT for ${deviceId}, ${JSON.stringify(connectivityData)}`);
43
- if (!updatedConnectivity[deviceId]) {
44
- updatedConnectivity[deviceId] = {
45
- most_recent: connectivityData,
46
- history: [],
47
- };
48
- }
49
- else {
50
- const newHistory = [
51
- updatedConnectivity[deviceId].most_recent,
52
- ...updatedConnectivity[deviceId].history,
53
- ].slice(0, 99);
54
- updatedConnectivity[deviceId] = {
55
- most_recent: connectivityData,
56
- history: newHistory,
57
- };
58
- }
59
- break;
60
- case "UPDATE":
61
- if (updatedConnectivity[deviceId]) {
62
- if (updatedConnectivity[deviceId].most_recent.id ===
63
- connectivityData.id) {
64
- updatedConnectivity[deviceId] = {
65
- ...updatedConnectivity[deviceId],
66
- most_recent: connectivityData,
67
- };
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
- }
81
- break;
82
- case "DELETE":
83
- if (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
- }
95
- }
96
- else {
97
- updatedConnectivity[deviceId] = {
98
- ...updatedConnectivity[deviceId],
99
- history: updatedConnectivity[deviceId].history.filter((c) => c.id !== connectivityData.id),
100
- };
101
- }
102
- }
103
- break;
104
- }
105
- dispatch(setActiveHerdGpsTrackersConnectivity(updatedConnectivity));
106
- }, [connectivity, dispatch]);
107
- // Fetch initial connectivity data
108
- const fetchInitialData = useCallback(async () => {
109
- if (!gpsDeviceIds)
110
- return;
111
- const deviceIds = gpsDeviceIds.split(",").filter(Boolean).map(Number);
112
- if (deviceIds.length === 0) {
113
- return;
114
- }
115
- const timestampFilter = getHoursAgoTimestamp(1);
116
- const connectivityData = {};
117
- await Promise.all(deviceIds.map(async (deviceId) => {
118
- try {
119
- const response = await server_get_connectivity_by_device_id(deviceId, timestampFilter);
120
- if (response.status === EnumWebResponse.SUCCESS && response.data) {
121
- const trackerData = response.data.filter((conn) => !conn.session_id);
122
- if (trackerData.length > 0) {
123
- const sortedData = trackerData
124
- .sort((a, b) => new Date(b.timestamp_start || 0).getTime() -
125
- new Date(a.timestamp_start || 0).getTime())
126
- .slice(0, 100);
127
- connectivityData[deviceId] = {
128
- most_recent: sortedData[0],
129
- history: sortedData.slice(1), // Exclude the most recent item
130
- };
131
- }
132
- }
133
- }
134
- catch (error) {
135
- // Silent error handling
136
- }
137
- }));
138
- dispatch(setActiveHerdGpsTrackersConnectivity(connectivityData));
139
- }, [gpsDeviceIds, dispatch]);
140
- useEffect(() => {
141
- if (!scoutSupabase || gpsDeviceIds === "")
142
- return;
143
- // Clean up existing channels
144
- channels.current.forEach((channel) => scoutSupabase.removeChannel(channel));
145
- channels.current = [];
146
- // Create connectivity channel
147
- const channel = scoutSupabase
148
- .channel(`${activeHerdId}-connectivity`, { config: { private: true } })
149
- .on("broadcast", { event: "*" }, handleConnectivityBroadcast)
150
- .subscribe();
151
- channels.current.push(channel);
152
- // Fetch initial data
153
- fetchInitialData();
154
- return () => {
155
- channels.current.forEach((ch) => scoutSupabase.removeChannel(ch));
156
- channels.current = [];
157
- };
158
- }, [scoutSupabase, gpsDeviceIds, activeHerdId, handleConnectivityBroadcast]);
159
- }
@@ -1,3 +0,0 @@
1
- import { SupabaseClient } from "@supabase/supabase-js";
2
- import { Database } from "../types/supabase";
3
- export declare function useScoutRealtimeDevices(scoutSupabase: SupabaseClient<Database>): void;
@@ -1,55 +0,0 @@
1
- "use client";
2
- import { useAppDispatch } from "../store/hooks";
3
- import { useSelector } from "react-redux";
4
- import { useEffect, useRef, useCallback } from "react";
5
- import { addDevice, deleteDevice, updateDevice } from "../store/scout";
6
- export function useScoutRealtimeDevices(scoutSupabase) {
7
- const channels = useRef([]);
8
- const dispatch = useAppDispatch();
9
- const activeHerdId = useSelector((state) => state.scout.active_herd_id);
10
- // Device broadcast handler
11
- const handleDeviceBroadcast = useCallback((payload) => {
12
- console.log("[Devices] Broadcast received:", payload.payload.operation);
13
- const data = payload.payload;
14
- switch (data.operation) {
15
- case "INSERT":
16
- if (data.record)
17
- dispatch(addDevice(data.record));
18
- break;
19
- case "UPDATE":
20
- if (data.record)
21
- dispatch(updateDevice(data.record));
22
- break;
23
- case "DELETE":
24
- if (data.old_record)
25
- dispatch(deleteDevice(data.old_record));
26
- break;
27
- }
28
- }, [dispatch]);
29
- const cleanupChannels = () => {
30
- channels.current.forEach((channel) => scoutSupabase.removeChannel(channel));
31
- channels.current = [];
32
- };
33
- const createDevicesChannel = (herdId) => {
34
- return scoutSupabase
35
- .channel(`${herdId}-devices`, { config: { private: true } })
36
- .on("broadcast", { event: "*" }, handleDeviceBroadcast)
37
- .subscribe((status) => {
38
- if (status === "SUBSCRIBED") {
39
- console.log(`[Devices] ✅ Connected to herd ${herdId}`);
40
- }
41
- else if (status === "CHANNEL_ERROR") {
42
- console.warn(`[Devices] 🟡 Failed to connect to herd ${herdId}`);
43
- }
44
- });
45
- };
46
- useEffect(() => {
47
- cleanupChannels();
48
- // Create devices channel for active herd
49
- if (activeHerdId) {
50
- const channel = createDevicesChannel(activeHerdId);
51
- channels.current.push(channel);
52
- }
53
- return cleanupChannels;
54
- }, [activeHerdId]);
55
- }
@@ -1,4 +0,0 @@
1
- export type HistoricalData<T> = {
2
- most_recent: T;
3
- history: T[];
4
- };
File without changes