@adventurelabs/scout-core 1.4.95 → 1.4.96

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,4 +1,5 @@
1
1
  export { useScoutRefresh, type UseScoutRefreshOptions, } from "./useScoutRefresh";
2
+ export { useScoutRealtimeBroadcast } from "./useScoutRealtimeBroadcast";
2
3
  export { useScoutRealtimeConnectivity } from "./useScoutRealtimeConnectivity";
3
4
  export { useScoutRealtimeDevices } from "./useScoutRealtimeDevices";
4
5
  export { useScoutRealtimeVersionsSoftware } from "./useScoutRealtimeVersionsSoftware";
@@ -10,5 +11,9 @@ export { useScoutRealtimePins } from "./useScoutRealtimePins";
10
11
  export { useScoutRealtimeParts } from "./useScoutRealtimeParts";
11
12
  export { useScoutRealtimeAnalysisJobs } from "./useScoutRealtimeAnalysisJobs";
12
13
  export { useScoutRealtimeAnalysisTasks } from "./useScoutRealtimeAnalysisTasks";
14
+ export { useScoutRealtimeDocuments, type DocumentRealtimeChannel, } from "./useScoutRealtimeDocuments";
15
+ export { useScoutRealtimeMaintenanceRequests } from "./useScoutRealtimeMaintenanceRequests";
16
+ export { useScoutRealtimeContacts } from "./useScoutRealtimeContacts";
17
+ export { useScoutRealtimeSessionIncidents } from "./useScoutRealtimeSessionIncidents";
13
18
  export { useInfiniteSessionsByHerd, useInfiniteSessionsByDevice, useInfiniteEventsByHerd, useInfiniteEventsByDevice, useInfiniteArtifactsByHerd, useInfiniteArtifactsByDevice, useInfiniteFeedByHerd, useInfiniteFeedByDevice, useInfiniteAnalysisJobs, useInfiniteAnalysisTasks, useIntersectionObserver, type UseInfiniteScrollOptions, type UseAnalysisJobsInfiniteOptions, type UseAnalysisTasksInfiniteOptions, } from "./useInfiniteQuery";
14
19
  export { useLoadingPerformance, useSessionSummariesByHerd, useHasSessionSummaries, } from "../store/hooks";
@@ -1,4 +1,5 @@
1
1
  export { useScoutRefresh, } from "./useScoutRefresh";
2
+ export { useScoutRealtimeBroadcast } from "./useScoutRealtimeBroadcast";
2
3
  export { useScoutRealtimeConnectivity } from "./useScoutRealtimeConnectivity";
3
4
  export { useScoutRealtimeDevices } from "./useScoutRealtimeDevices";
4
5
  export { useScoutRealtimeVersionsSoftware } from "./useScoutRealtimeVersionsSoftware";
@@ -10,6 +11,10 @@ export { useScoutRealtimePins } from "./useScoutRealtimePins";
10
11
  export { useScoutRealtimeParts } from "./useScoutRealtimeParts";
11
12
  export { useScoutRealtimeAnalysisJobs } from "./useScoutRealtimeAnalysisJobs";
12
13
  export { useScoutRealtimeAnalysisTasks } from "./useScoutRealtimeAnalysisTasks";
14
+ export { useScoutRealtimeDocuments, } from "./useScoutRealtimeDocuments";
15
+ export { useScoutRealtimeMaintenanceRequests } from "./useScoutRealtimeMaintenanceRequests";
16
+ export { useScoutRealtimeContacts } from "./useScoutRealtimeContacts";
17
+ export { useScoutRealtimeSessionIncidents } from "./useScoutRealtimeSessionIncidents";
13
18
  // RTK Query infinite scroll hooks
14
19
  export { useInfiniteSessionsByHerd, useInfiniteSessionsByDevice, useInfiniteEventsByHerd, useInfiniteEventsByDevice, useInfiniteArtifactsByHerd, useInfiniteArtifactsByDevice, useInfiniteFeedByHerd, useInfiniteFeedByDevice, useInfiniteAnalysisJobs, useInfiniteAnalysisTasks, useIntersectionObserver, } from "./useInfiniteQuery";
15
20
  // Session summaries and performance hooks
@@ -1,61 +1,7 @@
1
1
  "use client";
2
- import { useEffect, useRef, useCallback, useState } from "react";
3
- import { EnumRealtimeOperation } from "../types/realtime";
2
+ import { useScoutRealtimeBroadcast } from "./useScoutRealtimeBroadcast";
4
3
  export function useScoutRealtimeAnalysisJobs(scoutSupabase) {
5
- const channels = useRef([]);
6
- const [latestJobUpdate, setLatestJobUpdate] = useState(null);
7
- const handleAnalysisJobBroadcast = useCallback((payload) => {
8
- const { payload: data } = payload;
9
- const jobData = data.record || data.old_record;
10
- if (!jobData) {
11
- return;
12
- }
13
- let operation;
14
- switch (data.operation) {
15
- case "INSERT":
16
- operation = EnumRealtimeOperation.INSERT;
17
- break;
18
- case "UPDATE":
19
- operation = EnumRealtimeOperation.UPDATE;
20
- break;
21
- case "DELETE":
22
- operation = EnumRealtimeOperation.DELETE;
23
- break;
24
- default:
25
- return;
26
- }
27
- console.log(`[scout-core realtime] ANALYSIS_JOB ${data.operation} received for job ${jobData.id}:`, JSON.stringify(jobData));
28
- const realtimeData = {
29
- data: jobData,
30
- operation,
31
- };
32
- setLatestJobUpdate(realtimeData);
33
- }, []);
34
- const clearLatestUpdate = useCallback(() => {
35
- setLatestJobUpdate(null);
36
- }, []);
37
- useEffect(() => {
38
- if (!scoutSupabase)
39
- return;
40
- channels.current.forEach((channel) => scoutSupabase.removeChannel(channel));
41
- channels.current = [];
42
- clearLatestUpdate();
43
- const channel = scoutSupabase
44
- .channel("analysis_jobs_changes", { config: { private: true } })
45
- .on("broadcast", { event: "*" }, handleAnalysisJobBroadcast)
46
- .subscribe((status) => {
47
- if (status === "SUBSCRIBED") {
48
- console.log("[ANALYSIS_JOBS] ✅ Connected to analysis jobs broadcasts");
49
- }
50
- else if (status === "CHANNEL_ERROR") {
51
- console.warn("[ANALYSIS_JOBS] 🟡 Failed to connect to analysis jobs broadcasts");
52
- }
53
- });
54
- channels.current.push(channel);
55
- return () => {
56
- channels.current.forEach((ch) => scoutSupabase.removeChannel(ch));
57
- channels.current = [];
58
- };
59
- }, [scoutSupabase, handleAnalysisJobBroadcast, clearLatestUpdate]);
60
- return [latestJobUpdate, clearLatestUpdate];
4
+ return useScoutRealtimeBroadcast(scoutSupabase, [
5
+ "analysis_jobs_changes",
6
+ ]);
61
7
  }
@@ -1,61 +1,7 @@
1
1
  "use client";
2
- import { useEffect, useRef, useCallback, useState } from "react";
3
- import { EnumRealtimeOperation } from "../types/realtime";
2
+ import { useScoutRealtimeBroadcast } from "./useScoutRealtimeBroadcast";
4
3
  export function useScoutRealtimeAnalysisTasks(scoutSupabase) {
5
- const channels = useRef([]);
6
- const [latestTaskUpdate, setLatestTaskUpdate] = useState(null);
7
- const handleAnalysisTaskBroadcast = useCallback((payload) => {
8
- const { payload: data } = payload;
9
- const taskData = data.record || data.old_record;
10
- if (!taskData) {
11
- return;
12
- }
13
- let operation;
14
- switch (data.operation) {
15
- case "INSERT":
16
- operation = EnumRealtimeOperation.INSERT;
17
- break;
18
- case "UPDATE":
19
- operation = EnumRealtimeOperation.UPDATE;
20
- break;
21
- case "DELETE":
22
- operation = EnumRealtimeOperation.DELETE;
23
- break;
24
- default:
25
- return;
26
- }
27
- console.log(`[scout-core realtime] ANALYSIS_TASK ${data.operation} received for task ${taskData.id} (job ${taskData.job_id}):`, JSON.stringify(taskData));
28
- const realtimeData = {
29
- data: taskData,
30
- operation,
31
- };
32
- setLatestTaskUpdate(realtimeData);
33
- }, []);
34
- const clearLatestUpdate = useCallback(() => {
35
- setLatestTaskUpdate(null);
36
- }, []);
37
- useEffect(() => {
38
- if (!scoutSupabase)
39
- return;
40
- channels.current.forEach((channel) => scoutSupabase.removeChannel(channel));
41
- channels.current = [];
42
- clearLatestUpdate();
43
- const channel = scoutSupabase
44
- .channel("analysis_tasks_changes", { config: { private: true } })
45
- .on("broadcast", { event: "*" }, handleAnalysisTaskBroadcast)
46
- .subscribe((status) => {
47
- if (status === "SUBSCRIBED") {
48
- console.log("[ANALYSIS_TASKS] ✅ Connected to analysis tasks broadcasts");
49
- }
50
- else if (status === "CHANNEL_ERROR") {
51
- console.warn("[ANALYSIS_TASKS] 🟡 Failed to connect to analysis tasks broadcasts");
52
- }
53
- });
54
- channels.current.push(channel);
55
- return () => {
56
- channels.current.forEach((ch) => scoutSupabase.removeChannel(ch));
57
- channels.current = [];
58
- };
59
- }, [scoutSupabase, handleAnalysisTaskBroadcast, clearLatestUpdate]);
60
- return [latestTaskUpdate, clearLatestUpdate];
4
+ return useScoutRealtimeBroadcast(scoutSupabase, [
5
+ "analysis_tasks_changes",
6
+ ]);
61
7
  }
@@ -0,0 +1,8 @@
1
+ import { SupabaseClient } from "@supabase/supabase-js";
2
+ import { Database } from "../types/supabase";
3
+ import { RealtimeData } from "../types/realtime";
4
+ /**
5
+ * Subscribes to private realtime topics and reports the most recent row change across them.
6
+ * Changing the topic set resubscribes and clears the pending change.
7
+ */
8
+ export declare function useScoutRealtimeBroadcast<T>(scoutSupabase: SupabaseClient<Database>, topics: string[]): [RealtimeData<T> | null, () => void];
@@ -0,0 +1,44 @@
1
+ "use client";
2
+ import { useCallback, useEffect, useMemo, useState } from "react";
3
+ import { EnumRealtimeOperation } from "../types/realtime";
4
+ const OPERATIONS = {
5
+ INSERT: EnumRealtimeOperation.INSERT,
6
+ UPDATE: EnumRealtimeOperation.UPDATE,
7
+ DELETE: EnumRealtimeOperation.DELETE,
8
+ };
9
+ /**
10
+ * Subscribes to private realtime topics and reports the most recent row change across them.
11
+ * Changing the topic set resubscribes and clears the pending change.
12
+ */
13
+ export function useScoutRealtimeBroadcast(scoutSupabase, topics) {
14
+ const [latestUpdate, setLatestUpdate] = useState(null);
15
+ // Key the subscription on the topic set rather than the array identity, so callers can build
16
+ // their topics inline.
17
+ const topicsKey = topics.join("|");
18
+ const subscribedTopics = useMemo(() => topicsKey.split("|").filter(Boolean), [topicsKey]);
19
+ const clearLatestUpdate = useCallback(() => setLatestUpdate(null), []);
20
+ useEffect(() => {
21
+ setLatestUpdate(null);
22
+ if (!scoutSupabase || subscribedTopics.length === 0)
23
+ return;
24
+ const channels = subscribedTopics.map((topic) => scoutSupabase
25
+ .channel(topic, { config: { private: true } })
26
+ .on("broadcast", { event: "*" }, (message) => {
27
+ const change = message.payload;
28
+ const operation = OPERATIONS[change.operation];
29
+ const row = change.record ?? change.old_record;
30
+ if (operation === undefined || !row)
31
+ return;
32
+ setLatestUpdate({ data: row, operation });
33
+ })
34
+ .subscribe((status) => {
35
+ if (status === "CHANNEL_ERROR") {
36
+ console.warn(`[scout-core realtime] 🟡 ${topic} unavailable`);
37
+ }
38
+ }));
39
+ return () => {
40
+ channels.forEach((channel) => scoutSupabase.removeChannel(channel));
41
+ };
42
+ }, [scoutSupabase, subscribedTopics]);
43
+ return [latestUpdate, clearLatestUpdate];
44
+ }
@@ -0,0 +1,5 @@
1
+ import { SupabaseClient } from "@supabase/supabase-js";
2
+ import { Database } from "../types/supabase";
3
+ import { IContact } from "../types/db";
4
+ import { RealtimeData } from "../types/realtime";
5
+ export declare function useScoutRealtimeContacts(scoutSupabase: SupabaseClient<Database>): [RealtimeData<IContact> | null, () => void];
@@ -0,0 +1,7 @@
1
+ "use client";
2
+ import { useSelector } from "react-redux";
3
+ import { useScoutRealtimeBroadcast } from "./useScoutRealtimeBroadcast";
4
+ export function useScoutRealtimeContacts(scoutSupabase) {
5
+ const activeHerdId = useSelector((state) => state.scout.active_herd_id);
6
+ return useScoutRealtimeBroadcast(scoutSupabase, activeHerdId ? [`${activeHerdId}-contacts`] : []);
7
+ }
@@ -0,0 +1,7 @@
1
+ import { SupabaseClient } from "@supabase/supabase-js";
2
+ import { Database } from "../types/supabase";
3
+ import { IDocument } from "../types/db";
4
+ import { RealtimeData } from "../types/realtime";
5
+ /** One channel per document owner class, each gated on that class's read ability. */
6
+ export type DocumentRealtimeChannel = "herd" | "device" | "user" | "own" | "product";
7
+ export declare function useScoutRealtimeDocuments(scoutSupabase: SupabaseClient<Database>, channels?: DocumentRealtimeChannel[]): [RealtimeData<IDocument> | null, () => void];
@@ -0,0 +1,22 @@
1
+ "use client";
2
+ import { useSelector } from "react-redux";
3
+ import { useScoutRealtimeBroadcast } from "./useScoutRealtimeBroadcast";
4
+ const ALL_DOCUMENT_CHANNELS = [
5
+ "herd",
6
+ "device",
7
+ "user",
8
+ "own",
9
+ "product",
10
+ ];
11
+ export function useScoutRealtimeDocuments(scoutSupabase, channels = ALL_DOCUMENT_CHANNELS) {
12
+ const activeHerdId = useSelector((state) => state.scout.active_herd_id);
13
+ const userId = useSelector((state) => state.scout.user?.id ?? null);
14
+ const topics = channels.flatMap((channel) => {
15
+ if (channel === "product")
16
+ return ["product_documents_changes"];
17
+ if (channel === "own")
18
+ return userId ? [`user_${userId}-documents`] : [];
19
+ return activeHerdId ? [`${activeHerdId}-${channel}_documents`] : [];
20
+ });
21
+ return useScoutRealtimeBroadcast(scoutSupabase, topics);
22
+ }
@@ -0,0 +1,5 @@
1
+ import { SupabaseClient } from "@supabase/supabase-js";
2
+ import { Database } from "../types/supabase";
3
+ import { IMaintenanceRequest } from "../types/db";
4
+ import { RealtimeData } from "../types/realtime";
5
+ export declare function useScoutRealtimeMaintenanceRequests(scoutSupabase: SupabaseClient<Database>): [RealtimeData<IMaintenanceRequest> | null, () => void];
@@ -0,0 +1,7 @@
1
+ "use client";
2
+ import { useSelector } from "react-redux";
3
+ import { useScoutRealtimeBroadcast } from "./useScoutRealtimeBroadcast";
4
+ export function useScoutRealtimeMaintenanceRequests(scoutSupabase) {
5
+ const activeHerdId = useSelector((state) => state.scout.active_herd_id);
6
+ return useScoutRealtimeBroadcast(scoutSupabase, activeHerdId ? [`${activeHerdId}-maintenance_requests`] : []);
7
+ }
@@ -1,73 +1,7 @@
1
1
  "use client";
2
2
  import { useSelector } from "react-redux";
3
- import { useEffect, useRef, useCallback, useState } from "react";
4
- import { EnumRealtimeOperation } from "../types/realtime";
3
+ import { useScoutRealtimeBroadcast } from "./useScoutRealtimeBroadcast";
5
4
  export function useScoutRealtimeParts(scoutSupabase) {
6
- const channels = useRef([]);
7
- const [latestPartUpdate, setLatestPartUpdate] = useState(null);
8
5
  const activeHerdId = useSelector((state) => state.scout.active_herd_id);
9
- // Part broadcast handler - just pass data, don't mutate state
10
- const handlePartBroadcast = useCallback((payload) => {
11
- console.log("[Parts] Broadcast received:", payload.payload.operation);
12
- const data = payload.payload;
13
- const partData = data.record || data.old_record;
14
- if (!partData)
15
- return;
16
- let operation;
17
- switch (data.operation) {
18
- case "INSERT":
19
- operation = EnumRealtimeOperation.INSERT;
20
- console.log("[Parts] New part received:", data.record);
21
- break;
22
- case "UPDATE":
23
- operation = EnumRealtimeOperation.UPDATE;
24
- console.log("[Parts] Part updated:", data.record);
25
- break;
26
- case "DELETE":
27
- operation = EnumRealtimeOperation.DELETE;
28
- console.log("[Parts] Part deleted:", data.old_record);
29
- break;
30
- default:
31
- return;
32
- }
33
- const realtimeData = {
34
- data: partData,
35
- operation,
36
- };
37
- console.log(`[scout-core realtime] PART ${data.operation} received:`, JSON.stringify(realtimeData));
38
- setLatestPartUpdate(realtimeData);
39
- }, []);
40
- // Clear latest update
41
- const clearLatestUpdate = useCallback(() => {
42
- setLatestPartUpdate(null);
43
- }, []);
44
- const cleanupChannels = () => {
45
- channels.current.forEach((channel) => scoutSupabase.removeChannel(channel));
46
- channels.current = [];
47
- };
48
- const createPartsChannel = (herdId) => {
49
- return scoutSupabase
50
- .channel(`${herdId}-parts`, { config: { private: true } })
51
- .on("broadcast", { event: "*" }, handlePartBroadcast)
52
- .subscribe((status) => {
53
- if (status === "SUBSCRIBED") {
54
- console.log(`[Parts] ✅ Connected to herd ${herdId}`);
55
- }
56
- else if (status === "CHANNEL_ERROR") {
57
- console.warn(`[Parts] 🟡 Failed to connect to herd ${herdId}`);
58
- }
59
- });
60
- };
61
- useEffect(() => {
62
- cleanupChannels();
63
- // Clear previous update when switching herds
64
- clearLatestUpdate();
65
- // Create parts channel for active herd
66
- if (activeHerdId) {
67
- const channel = createPartsChannel(activeHerdId);
68
- channels.current.push(channel);
69
- }
70
- return cleanupChannels;
71
- }, [activeHerdId, clearLatestUpdate]);
72
- return [latestPartUpdate, clearLatestUpdate];
6
+ return useScoutRealtimeBroadcast(scoutSupabase, activeHerdId ? [`${activeHerdId}-parts`] : []);
73
7
  }
@@ -1,66 +1,7 @@
1
1
  "use client";
2
2
  import { useSelector } from "react-redux";
3
- import { useEffect, useRef, useCallback, useState } from "react";
4
- import { EnumRealtimeOperation } from "../types/realtime";
3
+ import { useScoutRealtimeBroadcast } from "./useScoutRealtimeBroadcast";
5
4
  export function useScoutRealtimePlans(scoutSupabase) {
6
- const channels = useRef([]);
7
- const [latestPlanUpdate, setLatestPlanUpdate] = useState(null);
8
5
  const activeHerdId = useSelector((state) => state.scout.active_herd_id);
9
- const handlePlanBroadcast = useCallback((message) => {
10
- const { payload: data } = message;
11
- if (data.table !== "plans" || data.schema !== "public") {
12
- return;
13
- }
14
- const planData = data.record ?? data.old_record;
15
- if (!planData)
16
- return;
17
- let operation;
18
- switch (data.operation) {
19
- case "INSERT":
20
- operation = EnumRealtimeOperation.INSERT;
21
- break;
22
- case "UPDATE":
23
- operation = EnumRealtimeOperation.UPDATE;
24
- break;
25
- case "DELETE":
26
- operation = EnumRealtimeOperation.DELETE;
27
- break;
28
- default:
29
- return;
30
- }
31
- const realtimeData = {
32
- data: planData,
33
- operation,
34
- };
35
- setLatestPlanUpdate(realtimeData);
36
- }, []);
37
- const clearLatestUpdate = useCallback(() => {
38
- setLatestPlanUpdate(null);
39
- }, []);
40
- useEffect(() => {
41
- if (!scoutSupabase)
42
- return;
43
- channels.current.forEach((channel) => scoutSupabase.removeChannel(channel));
44
- channels.current = [];
45
- clearLatestUpdate();
46
- if (activeHerdId) {
47
- const channel = scoutSupabase
48
- .channel(`${activeHerdId}-plans`, { config: { private: true } })
49
- .on("broadcast", { event: "*" }, handlePlanBroadcast)
50
- .subscribe((status) => {
51
- if (status === "SUBSCRIBED") {
52
- console.log(`[Plans] ✅ Connected to herd ${activeHerdId}`);
53
- }
54
- else if (status === "CHANNEL_ERROR") {
55
- console.warn(`[Plans] 🟡 Failed to connect to herd ${activeHerdId}`);
56
- }
57
- });
58
- channels.current.push(channel);
59
- }
60
- return () => {
61
- channels.current.forEach((ch) => scoutSupabase.removeChannel(ch));
62
- channels.current = [];
63
- };
64
- }, [scoutSupabase, activeHerdId, handlePlanBroadcast, clearLatestUpdate]);
65
- return [latestPlanUpdate, clearLatestUpdate];
6
+ return useScoutRealtimeBroadcast(scoutSupabase, activeHerdId ? [`${activeHerdId}-plans`] : []);
66
7
  }
@@ -0,0 +1,5 @@
1
+ import { SupabaseClient } from "@supabase/supabase-js";
2
+ import { Database } from "../types/supabase";
3
+ import { ISessionIncident } from "../types/db";
4
+ import { RealtimeData } from "../types/realtime";
5
+ export declare function useScoutRealtimeSessionIncidents(scoutSupabase: SupabaseClient<Database>): [RealtimeData<ISessionIncident> | null, () => void];
@@ -0,0 +1,7 @@
1
+ "use client";
2
+ import { useSelector } from "react-redux";
3
+ import { useScoutRealtimeBroadcast } from "./useScoutRealtimeBroadcast";
4
+ export function useScoutRealtimeSessionIncidents(scoutSupabase) {
5
+ const activeHerdId = useSelector((state) => state.scout.active_herd_id);
6
+ return useScoutRealtimeBroadcast(scoutSupabase, activeHerdId ? [`${activeHerdId}-session_incidents`] : []);
7
+ }
@@ -1,66 +1,7 @@
1
1
  "use client";
2
- import { useEffect, useRef, useCallback, useState } from "react";
3
- import { EnumRealtimeOperation } from "../types/realtime";
2
+ import { useScoutRealtimeBroadcast } from "./useScoutRealtimeBroadcast";
4
3
  export function useScoutRealtimeVersionsSoftware(scoutSupabase) {
5
- const channels = useRef([]);
6
- const [latestVersionUpdate, setLatestVersionUpdate] = useState(null);
7
- // Handle versions software broadcasts
8
- const handleVersionsSoftwareBroadcast = useCallback((payload) => {
9
- const { event, payload: data } = payload;
10
- const versionData = data.record || data.old_record;
11
- if (!versionData) {
12
- return;
13
- }
14
- let operation;
15
- switch (data.operation) {
16
- case "INSERT":
17
- operation = EnumRealtimeOperation.INSERT;
18
- break;
19
- case "UPDATE":
20
- operation = EnumRealtimeOperation.UPDATE;
21
- break;
22
- case "DELETE":
23
- operation = EnumRealtimeOperation.DELETE;
24
- break;
25
- default:
26
- return;
27
- }
28
- console.log(`[scout-core realtime] VERSIONS_SOFTWARE ${data.operation} received for version ${versionData.system}@${versionData.version}:`, JSON.stringify(versionData));
29
- const realtimeData = {
30
- data: versionData,
31
- operation,
32
- };
33
- setLatestVersionUpdate(realtimeData);
34
- }, []);
35
- // Clear latest update
36
- const clearLatestUpdate = useCallback(() => {
37
- setLatestVersionUpdate(null);
38
- }, []);
39
- useEffect(() => {
40
- if (!scoutSupabase)
41
- return;
42
- // Clean up existing channels
43
- channels.current.forEach((channel) => scoutSupabase.removeChannel(channel));
44
- channels.current = [];
45
- // Clear previous update when setting up
46
- clearLatestUpdate();
47
- // Create versions_software channel
48
- const channel = scoutSupabase
49
- .channel("versions_software_changes", { config: { private: true } })
50
- .on("broadcast", { event: "*" }, handleVersionsSoftwareBroadcast)
51
- .subscribe((status) => {
52
- if (status === "SUBSCRIBED") {
53
- console.log("[VERSIONS_SOFTWARE] ✅ Connected to software versions broadcasts");
54
- }
55
- else if (status === "CHANNEL_ERROR") {
56
- console.warn("[VERSIONS_SOFTWARE] 🟡 Failed to connect to software versions broadcasts");
57
- }
58
- });
59
- channels.current.push(channel);
60
- return () => {
61
- channels.current.forEach((ch) => scoutSupabase.removeChannel(ch));
62
- channels.current = [];
63
- };
64
- }, [scoutSupabase, handleVersionsSoftwareBroadcast, clearLatestUpdate]);
65
- return [latestVersionUpdate, clearLatestUpdate];
4
+ return useScoutRealtimeBroadcast(scoutSupabase, [
5
+ "versions_software_changes",
6
+ ]);
66
7
  }
package/dist/index.d.ts CHANGED
@@ -10,6 +10,7 @@ export * from "./types/supabase";
10
10
  export * from "./types/bounding_boxes";
11
11
  export * from "./types/events";
12
12
  export * from "./types/connectivity";
13
+ export * from "./types/realtime";
13
14
  export * from "./types/pubsub_token";
14
15
  export * from "./types/client_abilities_token";
15
16
  export * from "./types/jwt_mint";
@@ -73,6 +74,7 @@ export * from "./helpers/session_incidents";
73
74
  export * from "./helpers/contacts";
74
75
  export * from "./helpers/lifecycle";
75
76
  export * from "./helpers/storagePath";
77
+ export * from "./hooks/useScoutRealtimeBroadcast";
76
78
  export * from "./hooks/useScoutRealtimeConnectivity";
77
79
  export * from "./hooks/useScoutRealtimeDevices";
78
80
  export * from "./hooks/useScoutRealtimeVersionsSoftware";
@@ -84,6 +86,10 @@ export * from "./hooks/useScoutRealtimePlans";
84
86
  export * from "./hooks/useScoutRealtimePins";
85
87
  export * from "./hooks/useScoutRealtimeAnalysisJobs";
86
88
  export * from "./hooks/useScoutRealtimeAnalysisTasks";
89
+ export * from "./hooks/useScoutRealtimeDocuments";
90
+ export * from "./hooks/useScoutRealtimeMaintenanceRequests";
91
+ export * from "./hooks/useScoutRealtimeContacts";
92
+ export * from "./hooks/useScoutRealtimeSessionIncidents";
87
93
  export * from "./hooks/useScoutRefresh";
88
94
  export * from "./hooks/useInfiniteQuery";
89
95
  export * from "./providers";
package/dist/index.js CHANGED
@@ -12,6 +12,7 @@ export * from "./types/supabase";
12
12
  export * from "./types/bounding_boxes";
13
13
  export * from "./types/events";
14
14
  export * from "./types/connectivity";
15
+ export * from "./types/realtime";
15
16
  export * from "./types/pubsub_token";
16
17
  export * from "./types/client_abilities_token";
17
18
  export * from "./types/jwt_mint";
@@ -77,6 +78,7 @@ export * from "./helpers/contacts";
77
78
  export * from "./helpers/lifecycle";
78
79
  export * from "./helpers/storagePath";
79
80
  // Hooks
81
+ export * from "./hooks/useScoutRealtimeBroadcast";
80
82
  export * from "./hooks/useScoutRealtimeConnectivity";
81
83
  export * from "./hooks/useScoutRealtimeDevices";
82
84
  export * from "./hooks/useScoutRealtimeVersionsSoftware";
@@ -88,6 +90,10 @@ export * from "./hooks/useScoutRealtimePlans";
88
90
  export * from "./hooks/useScoutRealtimePins";
89
91
  export * from "./hooks/useScoutRealtimeAnalysisJobs";
90
92
  export * from "./hooks/useScoutRealtimeAnalysisTasks";
93
+ export * from "./hooks/useScoutRealtimeDocuments";
94
+ export * from "./hooks/useScoutRealtimeMaintenanceRequests";
95
+ export * from "./hooks/useScoutRealtimeContacts";
96
+ export * from "./hooks/useScoutRealtimeSessionIncidents";
91
97
  export * from "./hooks/useScoutRefresh";
92
98
  export * from "./hooks/useInfiniteQuery";
93
99
  // Providers
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adventurelabs/scout-core",
3
- "version": "1.4.95",
3
+ "version": "1.4.96",
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",