@adventurelabs/scout-core 1.4.96 → 1.5.1
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.
- package/dist/api_keys/actions.d.ts +1 -2
- package/dist/api_keys/actions.js +4 -83
- package/dist/api_keys/queries.d.ts +4 -0
- package/dist/api_keys/queries.js +52 -0
- package/dist/helpers/artifacts.d.ts +10 -15
- package/dist/helpers/artifacts.internal.d.ts +22 -0
- package/dist/helpers/artifacts.internal.js +151 -0
- package/dist/helpers/artifacts.js +48 -81
- package/dist/helpers/client_abilities_jwt_keys.d.ts +3 -4
- package/dist/helpers/client_abilities_jwt_keys.js +7 -7
- package/dist/helpers/client_abilities_jwt_keys_internal.d.ts +9 -0
- package/dist/helpers/client_abilities_jwt_keys_internal.js +20 -0
- package/dist/helpers/client_abilities_token_server.d.ts +1 -5
- package/dist/helpers/client_abilities_token_server.js +2 -2
- package/dist/helpers/connectivity.d.ts +2 -3
- package/dist/helpers/connectivity.internal.d.ts +10 -0
- package/dist/helpers/connectivity.internal.js +47 -0
- package/dist/helpers/connectivity.js +6 -7
- package/dist/helpers/devices.d.ts +1 -3
- package/dist/helpers/devices.js +3 -12
- package/dist/helpers/devices.queries.d.ts +5 -0
- package/dist/helpers/devices.queries.js +10 -0
- package/dist/helpers/documents.d.ts +1 -0
- package/dist/helpers/documents.js +11 -2
- package/dist/helpers/embeddings.d.ts +1 -3
- package/dist/helpers/embeddings.internal.d.ts +5 -0
- package/dist/helpers/embeddings.internal.js +14 -0
- package/dist/helpers/embeddings.js +2 -2
- package/dist/helpers/events.d.ts +4 -6
- package/dist/helpers/events.internal.d.ts +13 -0
- package/dist/helpers/events.internal.js +88 -0
- package/dist/helpers/events.js +16 -17
- package/dist/helpers/herd_allowed_domains.d.ts +1 -3
- package/dist/helpers/herd_allowed_domains.js +2 -2
- package/dist/helpers/herd_allowed_domains_internal.d.ts +5 -0
- package/dist/helpers/herd_allowed_domains_internal.js +12 -0
- package/dist/helpers/herd_modules.queries.d.ts +3 -0
- package/dist/helpers/herd_modules.queries.js +106 -0
- package/dist/helpers/herd_roles.d.ts +12 -14
- package/dist/helpers/herd_roles.js +26 -34
- package/dist/helpers/herd_roles_internal.d.ts +18 -0
- package/dist/helpers/herd_roles_internal.js +159 -0
- package/dist/helpers/herd_scoped.queries.d.ts +7 -0
- package/dist/helpers/herd_scoped.queries.js +45 -0
- package/dist/helpers/herds.d.ts +2 -4
- package/dist/helpers/herds.js +11 -142
- package/dist/helpers/herds.queries.d.ts +5 -0
- package/dist/helpers/herds.queries.js +12 -0
- package/dist/helpers/index.d.ts +1 -0
- package/dist/helpers/index.js +1 -0
- package/dist/helpers/invitations.d.ts +4 -6
- package/dist/helpers/invitations.js +8 -8
- package/dist/helpers/invitations_internal.d.ts +10 -0
- package/dist/helpers/invitations_internal.js +63 -0
- package/dist/helpers/layers.d.ts +1 -3
- package/dist/helpers/layers.js +3 -18
- package/dist/helpers/layers.queries.d.ts +5 -0
- package/dist/helpers/layers.queries.js +20 -0
- package/dist/helpers/operating_contexts.d.ts +43 -0
- package/dist/helpers/operating_contexts.js +222 -0
- package/dist/helpers/plans.d.ts +1 -3
- package/dist/helpers/plans.js +3 -18
- package/dist/helpers/plans.queries.d.ts +5 -0
- package/dist/helpers/plans.queries.js +20 -0
- package/dist/helpers/providers.d.ts +1 -3
- package/dist/helpers/providers.js +3 -18
- package/dist/helpers/providers.queries.d.ts +5 -0
- package/dist/helpers/providers.queries.js +20 -0
- package/dist/helpers/pubsub_token_server.d.ts +1 -5
- package/dist/helpers/pubsub_token_server.js +2 -2
- package/dist/helpers/realtime_topic_access.d.ts +5 -0
- package/dist/helpers/realtime_topic_access.js +55 -0
- package/dist/helpers/session_summaries.d.ts +3 -4
- package/dist/helpers/session_summaries.js +13 -43
- package/dist/helpers/session_summaries.queries.d.ts +14 -0
- package/dist/helpers/session_summaries.queries.js +19 -0
- package/dist/helpers/sessions.d.ts +7 -8
- package/dist/helpers/sessions.js +23 -58
- package/dist/helpers/sessions.queries.d.ts +4 -0
- package/dist/helpers/sessions.queries.js +22 -0
- package/dist/helpers/storage.d.ts +2 -4
- package/dist/helpers/storage.js +7 -54
- package/dist/helpers/storage_internal.d.ts +4 -0
- package/dist/helpers/storage_internal.js +29 -0
- package/dist/helpers/tags.js +5 -5
- package/dist/helpers/users.d.ts +7 -8
- package/dist/helpers/users.js +13 -41
- package/dist/helpers/users.queries.d.ts +5 -0
- package/dist/helpers/users.queries.js +30 -0
- package/dist/helpers/versions_software_internal.d.ts +6 -0
- package/dist/helpers/versions_software_internal.js +53 -0
- package/dist/helpers/versions_software_server.d.ts +2 -3
- package/dist/helpers/versions_software_server.js +20 -18
- package/dist/hooks/index.d.ts +2 -1
- package/dist/hooks/index.js +2 -1
- package/dist/hooks/useAuthorizedRealtimeTopics.d.ts +1 -0
- package/dist/hooks/useAuthorizedRealtimeTopics.js +14 -0
- package/dist/hooks/useScoutRealtimeAnalysisJobs.d.ts +2 -1
- package/dist/hooks/useScoutRealtimeAnalysisJobs.js +3 -5
- package/dist/hooks/useScoutRealtimeAnalysisTasks.d.ts +2 -1
- package/dist/hooks/useScoutRealtimeAnalysisTasks.js +3 -5
- package/dist/hooks/useScoutRealtimeBroadcast.d.ts +9 -5
- package/dist/hooks/useScoutRealtimeBroadcast.js +118 -25
- package/dist/hooks/useScoutRealtimeConnectivity.d.ts +2 -1
- package/dist/hooks/useScoutRealtimeConnectivity.js +18 -76
- package/dist/hooks/useScoutRealtimeContacts.d.ts +2 -1
- package/dist/hooks/useScoutRealtimeContacts.js +3 -3
- package/dist/hooks/useScoutRealtimeDevices.d.ts +2 -1
- package/dist/hooks/useScoutRealtimeDevices.js +3 -64
- package/dist/hooks/useScoutRealtimeDocuments.d.ts +3 -3
- package/dist/hooks/useScoutRealtimeDocuments.js +7 -5
- package/dist/hooks/useScoutRealtimeEvents.d.ts +2 -1
- package/dist/hooks/useScoutRealtimeEvents.js +3 -69
- package/dist/hooks/useScoutRealtimeMaintenanceRequests.d.ts +2 -1
- package/dist/hooks/useScoutRealtimeMaintenanceRequests.js +3 -3
- package/dist/hooks/useScoutRealtimeOperatingContexts.d.ts +12 -0
- package/dist/hooks/useScoutRealtimeOperatingContexts.js +26 -0
- package/dist/hooks/useScoutRealtimeParts.d.ts +2 -1
- package/dist/hooks/useScoutRealtimeParts.js +3 -3
- package/dist/hooks/useScoutRealtimePins.d.ts +2 -1
- package/dist/hooks/useScoutRealtimePins.js +3 -69
- package/dist/hooks/useScoutRealtimePlans.d.ts +2 -1
- package/dist/hooks/useScoutRealtimePlans.js +3 -3
- package/dist/hooks/useScoutRealtimeSessionIncidents.d.ts +2 -1
- package/dist/hooks/useScoutRealtimeSessionIncidents.js +3 -3
- package/dist/hooks/useScoutRealtimeSessions.d.ts +2 -1
- package/dist/hooks/useScoutRealtimeSessions.js +3 -69
- package/dist/hooks/useScoutRealtimeTags.d.ts +2 -1
- package/dist/hooks/useScoutRealtimeTags.js +3 -69
- package/dist/hooks/useScoutRealtimeVersionsSoftware.d.ts +2 -1
- package/dist/hooks/useScoutRealtimeVersionsSoftware.js +3 -5
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/providers/ScoutRefreshProvider.d.ts +1 -0
- package/dist/providers/ScoutRefreshProvider.js +3 -0
- package/dist/supabase/server.d.ts +4 -1
- package/dist/supabase/server.js +6 -5
- package/dist/types/db.d.ts +82 -0
- package/dist/types/realtime.d.ts +1 -0
- package/dist/types/supabase.d.ts +952 -100
- package/dist/types/supabase.js +26 -1
- package/package.json +1 -1
package/dist/hooks/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { useScoutRefresh, type UseScoutRefreshOptions, } from "./useScoutRefresh";
|
|
2
|
-
export { useScoutRealtimeBroadcast } from "./useScoutRealtimeBroadcast";
|
|
2
|
+
export { useScoutRealtimeBroadcast, type ScoutRealtimeBroadcastOptions, type ScoutRealtimeAuthErrorMode, } from "./useScoutRealtimeBroadcast";
|
|
3
3
|
export { useScoutRealtimeConnectivity } from "./useScoutRealtimeConnectivity";
|
|
4
4
|
export { useScoutRealtimeDevices } from "./useScoutRealtimeDevices";
|
|
5
5
|
export { useScoutRealtimeVersionsSoftware } from "./useScoutRealtimeVersionsSoftware";
|
|
@@ -15,5 +15,6 @@ export { useScoutRealtimeDocuments, type DocumentRealtimeChannel, } from "./useS
|
|
|
15
15
|
export { useScoutRealtimeMaintenanceRequests } from "./useScoutRealtimeMaintenanceRequests";
|
|
16
16
|
export { useScoutRealtimeContacts } from "./useScoutRealtimeContacts";
|
|
17
17
|
export { useScoutRealtimeSessionIncidents } from "./useScoutRealtimeSessionIncidents";
|
|
18
|
+
export { useScoutRealtimeOperatingContexts, type OperatingContextRealtimeData, type OperatingContextRealtimeRow, } from "./useScoutRealtimeOperatingContexts";
|
|
18
19
|
export { useInfiniteSessionsByHerd, useInfiniteSessionsByDevice, useInfiniteEventsByHerd, useInfiniteEventsByDevice, useInfiniteArtifactsByHerd, useInfiniteArtifactsByDevice, useInfiniteFeedByHerd, useInfiniteFeedByDevice, useInfiniteAnalysisJobs, useInfiniteAnalysisTasks, useIntersectionObserver, type UseInfiniteScrollOptions, type UseAnalysisJobsInfiniteOptions, type UseAnalysisTasksInfiniteOptions, } from "./useInfiniteQuery";
|
|
19
20
|
export { useLoadingPerformance, useSessionSummariesByHerd, useHasSessionSummaries, } from "../store/hooks";
|
package/dist/hooks/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { useScoutRefresh, } from "./useScoutRefresh";
|
|
2
|
-
export { useScoutRealtimeBroadcast } from "./useScoutRealtimeBroadcast";
|
|
2
|
+
export { useScoutRealtimeBroadcast, } from "./useScoutRealtimeBroadcast";
|
|
3
3
|
export { useScoutRealtimeConnectivity } from "./useScoutRealtimeConnectivity";
|
|
4
4
|
export { useScoutRealtimeDevices } from "./useScoutRealtimeDevices";
|
|
5
5
|
export { useScoutRealtimeVersionsSoftware } from "./useScoutRealtimeVersionsSoftware";
|
|
@@ -15,6 +15,7 @@ export { useScoutRealtimeDocuments, } from "./useScoutRealtimeDocuments";
|
|
|
15
15
|
export { useScoutRealtimeMaintenanceRequests } from "./useScoutRealtimeMaintenanceRequests";
|
|
16
16
|
export { useScoutRealtimeContacts } from "./useScoutRealtimeContacts";
|
|
17
17
|
export { useScoutRealtimeSessionIncidents } from "./useScoutRealtimeSessionIncidents";
|
|
18
|
+
export { useScoutRealtimeOperatingContexts, } from "./useScoutRealtimeOperatingContexts";
|
|
18
19
|
// RTK Query infinite scroll hooks
|
|
19
20
|
export { useInfiniteSessionsByHerd, useInfiniteSessionsByDevice, useInfiniteEventsByHerd, useInfiniteEventsByDevice, useInfiniteArtifactsByHerd, useInfiniteArtifactsByDevice, useInfiniteFeedByHerd, useInfiniteFeedByDevice, useInfiniteAnalysisJobs, useInfiniteAnalysisTasks, useIntersectionObserver, } from "./useInfiniteQuery";
|
|
20
21
|
// Session summaries and performance hooks
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function useAuthorizedRealtimeTopics(topics: string[]): string[];
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { useMemo } from "react";
|
|
3
|
+
import { filter_realtime_topics } from "../helpers/realtime_topic_access";
|
|
4
|
+
import { useOptionalClientAbilitiesMint } from "../providers/ScoutRefreshProvider";
|
|
5
|
+
export function useAuthorizedRealtimeTopics(topics) {
|
|
6
|
+
const abilities = useOptionalClientAbilitiesMint();
|
|
7
|
+
const topicsKey = topics.join("|");
|
|
8
|
+
return useMemo(() => {
|
|
9
|
+
const requested = topicsKey.split("|").filter(Boolean);
|
|
10
|
+
if (!abilities)
|
|
11
|
+
return requested;
|
|
12
|
+
return filter_realtime_topics(abilities.status, abilities.mint, requested);
|
|
13
|
+
}, [abilities, topicsKey]);
|
|
14
|
+
}
|
|
@@ -2,4 +2,5 @@ import { SupabaseClient } from "@supabase/supabase-js";
|
|
|
2
2
|
import { Database } from "../types/supabase";
|
|
3
3
|
import { IAnalysisJob } from "../types/db";
|
|
4
4
|
import { RealtimeData } from "../types/realtime";
|
|
5
|
-
|
|
5
|
+
import { ScoutRealtimeBroadcastOptions } from "./useScoutRealtimeBroadcast";
|
|
6
|
+
export declare function useScoutRealtimeAnalysisJobs(scoutSupabase: SupabaseClient<Database>, options?: ScoutRealtimeBroadcastOptions): [RealtimeData<IAnalysisJob> | null, () => void];
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { useScoutRealtimeBroadcast } from "./useScoutRealtimeBroadcast";
|
|
3
|
-
export function useScoutRealtimeAnalysisJobs(scoutSupabase) {
|
|
4
|
-
return useScoutRealtimeBroadcast(scoutSupabase, [
|
|
5
|
-
"analysis_jobs_changes",
|
|
6
|
-
]);
|
|
2
|
+
import { useScoutRealtimeBroadcast, } from "./useScoutRealtimeBroadcast";
|
|
3
|
+
export function useScoutRealtimeAnalysisJobs(scoutSupabase, options) {
|
|
4
|
+
return useScoutRealtimeBroadcast(scoutSupabase, ["analysis_jobs_changes"], options);
|
|
7
5
|
}
|
|
@@ -2,4 +2,5 @@ import { SupabaseClient } from "@supabase/supabase-js";
|
|
|
2
2
|
import { Database } from "../types/supabase";
|
|
3
3
|
import { IAnalysisTask } from "../types/db";
|
|
4
4
|
import { RealtimeData } from "../types/realtime";
|
|
5
|
-
|
|
5
|
+
import { ScoutRealtimeBroadcastOptions } from "./useScoutRealtimeBroadcast";
|
|
6
|
+
export declare function useScoutRealtimeAnalysisTasks(scoutSupabase: SupabaseClient<Database>, options?: ScoutRealtimeBroadcastOptions): [RealtimeData<IAnalysisTask> | null, () => void];
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { useScoutRealtimeBroadcast } from "./useScoutRealtimeBroadcast";
|
|
3
|
-
export function useScoutRealtimeAnalysisTasks(scoutSupabase) {
|
|
4
|
-
return useScoutRealtimeBroadcast(scoutSupabase, [
|
|
5
|
-
"analysis_tasks_changes",
|
|
6
|
-
]);
|
|
2
|
+
import { useScoutRealtimeBroadcast, } from "./useScoutRealtimeBroadcast";
|
|
3
|
+
export function useScoutRealtimeAnalysisTasks(scoutSupabase, options) {
|
|
4
|
+
return useScoutRealtimeBroadcast(scoutSupabase, ["analysis_tasks_changes"], options);
|
|
7
5
|
}
|
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
import { SupabaseClient } from "@supabase/supabase-js";
|
|
2
2
|
import { Database } from "../types/supabase";
|
|
3
3
|
import { RealtimeData } from "../types/realtime";
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
4
|
+
export type ScoutRealtimeAuthErrorMode = "stop" | "backoff";
|
|
5
|
+
export type ScoutRealtimeBroadcastOptions = {
|
|
6
|
+
/** `stop` prevents Phoenix rejoin loops on auth failure. */
|
|
7
|
+
authErrorRetry?: ScoutRealtimeAuthErrorMode;
|
|
8
|
+
backoffInitialMs?: number;
|
|
9
|
+
backoffMaxMs?: number;
|
|
10
|
+
backoffMaxAttempts?: number;
|
|
11
|
+
};
|
|
12
|
+
export declare function useScoutRealtimeBroadcast<T>(scoutSupabase: SupabaseClient<Database>, topics: string[], options?: ScoutRealtimeBroadcastOptions, rowFilter?: (row: T) => boolean): [RealtimeData<T> | null, () => void];
|
|
@@ -1,44 +1,137 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { useCallback, useEffect,
|
|
2
|
+
import { useCallback, useEffect, useState } from "react";
|
|
3
3
|
import { EnumRealtimeOperation } from "../types/realtime";
|
|
4
|
+
import { useAuthorizedRealtimeTopics } from "./useAuthorizedRealtimeTopics";
|
|
4
5
|
const OPERATIONS = {
|
|
5
6
|
INSERT: EnumRealtimeOperation.INSERT,
|
|
6
7
|
UPDATE: EnumRealtimeOperation.UPDATE,
|
|
7
8
|
DELETE: EnumRealtimeOperation.DELETE,
|
|
8
9
|
};
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
10
|
+
const DEFAULT_BACKOFF_INITIAL_MS = 1000;
|
|
11
|
+
const DEFAULT_BACKOFF_MAX_MS = 60000;
|
|
12
|
+
function isRealtimeAuthError(error) {
|
|
13
|
+
const message = error?.message ?? "";
|
|
14
|
+
return /unauthorized|permission/i.test(message);
|
|
15
|
+
}
|
|
16
|
+
function backoffDelayMs(attempt, initialMs, maxMs) {
|
|
17
|
+
return Math.min(maxMs, initialMs * 2 ** Math.max(0, attempt));
|
|
18
|
+
}
|
|
19
|
+
export function useScoutRealtimeBroadcast(scoutSupabase, topics, options = {}, rowFilter) {
|
|
20
|
+
const { authErrorRetry = "stop", backoffInitialMs = DEFAULT_BACKOFF_INITIAL_MS, backoffMaxMs = DEFAULT_BACKOFF_MAX_MS, backoffMaxAttempts = Number.POSITIVE_INFINITY, } = options;
|
|
14
21
|
const [latestUpdate, setLatestUpdate] = useState(null);
|
|
15
|
-
|
|
16
|
-
// their topics inline.
|
|
17
|
-
const topicsKey = topics.join("|");
|
|
18
|
-
const subscribedTopics = useMemo(() => topicsKey.split("|").filter(Boolean), [topicsKey]);
|
|
22
|
+
const subscribedTopics = useAuthorizedRealtimeTopics(topics);
|
|
19
23
|
const clearLatestUpdate = useCallback(() => setLatestUpdate(null), []);
|
|
20
24
|
useEffect(() => {
|
|
21
25
|
setLatestUpdate(null);
|
|
22
26
|
if (!scoutSupabase || subscribedTopics.length === 0)
|
|
23
27
|
return;
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
28
|
+
let cancelled = false;
|
|
29
|
+
const channels = new Map();
|
|
30
|
+
const authAttempts = new Map();
|
|
31
|
+
const blockedTopics = new Set();
|
|
32
|
+
const retryTimers = new Map();
|
|
33
|
+
const removeTopicChannel = (topic) => {
|
|
34
|
+
const channel = channels.get(topic);
|
|
35
|
+
if (!channel)
|
|
36
|
+
return;
|
|
37
|
+
channels.delete(topic);
|
|
38
|
+
void scoutSupabase.removeChannel(channel);
|
|
39
|
+
};
|
|
40
|
+
const scheduleRetry = (topic) => {
|
|
41
|
+
if (authErrorRetry !== "backoff" || cancelled)
|
|
42
|
+
return;
|
|
43
|
+
const attempt = authAttempts.get(topic) ?? 0;
|
|
44
|
+
if (attempt >= backoffMaxAttempts)
|
|
31
45
|
return;
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
46
|
+
authAttempts.set(topic, attempt + 1);
|
|
47
|
+
const existing = retryTimers.get(topic);
|
|
48
|
+
if (existing)
|
|
49
|
+
clearTimeout(existing);
|
|
50
|
+
retryTimers.set(topic, setTimeout(() => {
|
|
51
|
+
retryTimers.delete(topic);
|
|
52
|
+
void authenticateAndJoin([topic]);
|
|
53
|
+
}, backoffDelayMs(attempt, backoffInitialMs, backoffMaxMs)));
|
|
54
|
+
};
|
|
55
|
+
const joinTopic = (topic) => {
|
|
56
|
+
if (cancelled || channels.has(topic))
|
|
57
|
+
return;
|
|
58
|
+
const channel = scoutSupabase
|
|
59
|
+
.channel(topic, { config: { private: true } })
|
|
60
|
+
.on("broadcast", { event: "*" }, (message) => {
|
|
61
|
+
const change = message.payload;
|
|
62
|
+
const operation = OPERATIONS[change.operation];
|
|
63
|
+
const row = change.record ?? change.old_record;
|
|
64
|
+
if (operation === undefined || !row)
|
|
65
|
+
return;
|
|
66
|
+
if (rowFilter && !rowFilter(row))
|
|
67
|
+
return;
|
|
68
|
+
setLatestUpdate({ data: row, operation, table: change.table });
|
|
69
|
+
});
|
|
70
|
+
channels.set(topic, channel);
|
|
71
|
+
channel.subscribe((status, error) => {
|
|
72
|
+
if (status === "SUBSCRIBED") {
|
|
73
|
+
authAttempts.delete(topic);
|
|
74
|
+
blockedTopics.delete(topic);
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
if (status !== "CHANNEL_ERROR")
|
|
78
|
+
return;
|
|
79
|
+
console.warn(`[scout-core realtime] 🟡 ${topic} unavailable`, error?.message ?? "");
|
|
80
|
+
if (!isRealtimeAuthError(error) || cancelled)
|
|
81
|
+
return;
|
|
82
|
+
blockedTopics.add(topic);
|
|
83
|
+
removeTopicChannel(topic);
|
|
84
|
+
scheduleRetry(topic);
|
|
85
|
+
});
|
|
86
|
+
};
|
|
87
|
+
async function authenticateAndJoin(topicsToJoin) {
|
|
88
|
+
try {
|
|
89
|
+
await scoutSupabase.realtime.setAuth();
|
|
90
|
+
}
|
|
91
|
+
catch (error) {
|
|
92
|
+
console.warn("[scout-core realtime] failed to refresh auth", error);
|
|
93
|
+
}
|
|
94
|
+
if (!cancelled)
|
|
95
|
+
topicsToJoin.forEach(joinTopic);
|
|
96
|
+
}
|
|
97
|
+
const retryBlockedTopics = () => {
|
|
98
|
+
const topicsToRetry = Array.from(blockedTopics);
|
|
99
|
+
blockedTopics.forEach((topic) => {
|
|
100
|
+
const timer = retryTimers.get(topic);
|
|
101
|
+
if (timer)
|
|
102
|
+
clearTimeout(timer);
|
|
103
|
+
retryTimers.delete(topic);
|
|
104
|
+
authAttempts.delete(topic);
|
|
105
|
+
});
|
|
106
|
+
if (topicsToRetry.length > 0)
|
|
107
|
+
void authenticateAndJoin(topicsToRetry);
|
|
108
|
+
};
|
|
109
|
+
const { data: { subscription: authSubscription }, } = scoutSupabase.auth.onAuthStateChange((event) => {
|
|
110
|
+
if (event === "INITIAL_SESSION" ||
|
|
111
|
+
event === "SIGNED_IN" ||
|
|
112
|
+
event === "TOKEN_REFRESHED") {
|
|
113
|
+
retryBlockedTopics();
|
|
37
114
|
}
|
|
38
|
-
})
|
|
115
|
+
});
|
|
116
|
+
void authenticateAndJoin(subscribedTopics);
|
|
39
117
|
return () => {
|
|
40
|
-
|
|
118
|
+
cancelled = true;
|
|
119
|
+
authSubscription.unsubscribe();
|
|
120
|
+
retryTimers.forEach((timer) => clearTimeout(timer));
|
|
121
|
+
retryTimers.clear();
|
|
122
|
+
channels.forEach((channel) => {
|
|
123
|
+
void scoutSupabase.removeChannel(channel);
|
|
124
|
+
});
|
|
125
|
+
channels.clear();
|
|
41
126
|
};
|
|
42
|
-
}, [
|
|
127
|
+
}, [
|
|
128
|
+
scoutSupabase,
|
|
129
|
+
subscribedTopics,
|
|
130
|
+
authErrorRetry,
|
|
131
|
+
backoffInitialMs,
|
|
132
|
+
backoffMaxMs,
|
|
133
|
+
backoffMaxAttempts,
|
|
134
|
+
rowFilter,
|
|
135
|
+
]);
|
|
43
136
|
return [latestUpdate, clearLatestUpdate];
|
|
44
137
|
}
|
|
@@ -2,4 +2,5 @@ import { SupabaseClient } from "@supabase/supabase-js";
|
|
|
2
2
|
import { Database } from "../types/supabase";
|
|
3
3
|
import { IConnectivityWithCoordinates } from "../types/db";
|
|
4
4
|
import { RealtimeData } from "../types/realtime";
|
|
5
|
-
|
|
5
|
+
import { ScoutRealtimeBroadcastOptions } from "./useScoutRealtimeBroadcast";
|
|
6
|
+
export declare function useScoutRealtimeConnectivity(scoutSupabase: SupabaseClient<Database>, options?: ScoutRealtimeBroadcastOptions): [RealtimeData<IConnectivityWithCoordinates> | null, () => void];
|
|
@@ -1,84 +1,26 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { useSelector } from "react-redux";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
3
|
+
import { useMemo } from "react";
|
|
4
|
+
import { useScoutRealtimeBroadcast, } from "./useScoutRealtimeBroadcast";
|
|
5
|
+
const GPS_DEVICE_TYPES = [
|
|
6
|
+
"gps_tracker",
|
|
7
|
+
"gps_tracker_vehicle",
|
|
8
|
+
"gps_tracker_person",
|
|
9
|
+
];
|
|
10
|
+
function isGpsConnectivity(row) {
|
|
11
|
+
return Boolean(row.device_id && !row.session_id);
|
|
12
|
+
}
|
|
13
|
+
export function useScoutRealtimeConnectivity(scoutSupabase, options) {
|
|
8
14
|
const activeHerdId = useSelector((state) => state.scout.active_herd_id);
|
|
9
15
|
const herdModules = useSelector((state) => state.scout.herd_modules);
|
|
10
|
-
|
|
11
|
-
const gpsDeviceIds = useMemo(() => {
|
|
16
|
+
const hasGpsDevices = useMemo(() => {
|
|
12
17
|
if (!activeHerdId)
|
|
13
|
-
return
|
|
18
|
+
return false;
|
|
14
19
|
const activeHerdModule = herdModules.find((hm) => hm.herd.id?.toString() === activeHerdId);
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
const gpsDevices = activeHerdModule.devices.filter((device) => device.device_type &&
|
|
18
|
-
["gps_tracker", "gps_tracker_vehicle", "gps_tracker_person"].includes(device.device_type));
|
|
19
|
-
return gpsDevices
|
|
20
|
-
.map((d) => d.id)
|
|
21
|
-
.filter(Boolean)
|
|
22
|
-
.sort()
|
|
23
|
-
.join(",");
|
|
20
|
+
return activeHerdModule?.devices.some((device) => device.device_type &&
|
|
21
|
+
GPS_DEVICE_TYPES.includes(device.device_type)) ?? false;
|
|
24
22
|
}, [activeHerdId, herdModules]);
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
const connectivityData = data.record || data.old_record;
|
|
29
|
-
// Only process GPS tracker data (no session_id)
|
|
30
|
-
if (!connectivityData?.device_id || connectivityData.session_id) {
|
|
31
|
-
return;
|
|
32
|
-
}
|
|
33
|
-
let operation;
|
|
34
|
-
switch (data.operation) {
|
|
35
|
-
case "INSERT":
|
|
36
|
-
operation = EnumRealtimeOperation.INSERT;
|
|
37
|
-
break;
|
|
38
|
-
case "UPDATE":
|
|
39
|
-
operation = EnumRealtimeOperation.UPDATE;
|
|
40
|
-
break;
|
|
41
|
-
case "DELETE":
|
|
42
|
-
operation = EnumRealtimeOperation.DELETE;
|
|
43
|
-
break;
|
|
44
|
-
default:
|
|
45
|
-
return;
|
|
46
|
-
}
|
|
47
|
-
console.log(`[scout-core realtime] CONNECTIVITY ${data.operation} received for device ${connectivityData.device_id}:`, JSON.stringify(connectivityData));
|
|
48
|
-
const realtimeData = {
|
|
49
|
-
data: connectivityData,
|
|
50
|
-
operation,
|
|
51
|
-
};
|
|
52
|
-
setLatestConnectivityUpdate(realtimeData);
|
|
53
|
-
}, []);
|
|
54
|
-
// Clear latest update
|
|
55
|
-
const clearLatestUpdate = useCallback(() => {
|
|
56
|
-
setLatestConnectivityUpdate(null);
|
|
57
|
-
}, []);
|
|
58
|
-
useEffect(() => {
|
|
59
|
-
if (!scoutSupabase || gpsDeviceIds === "")
|
|
60
|
-
return;
|
|
61
|
-
// Clean up existing channels
|
|
62
|
-
channels.current.forEach((channel) => scoutSupabase.removeChannel(channel));
|
|
63
|
-
channels.current = [];
|
|
64
|
-
// Clear previous update when switching herds
|
|
65
|
-
clearLatestUpdate();
|
|
66
|
-
// Create connectivity channel
|
|
67
|
-
const channel = scoutSupabase
|
|
68
|
-
.channel(`${activeHerdId}-connectivity`, { config: { private: true } })
|
|
69
|
-
.on("broadcast", { event: "*" }, handleConnectivityBroadcast)
|
|
70
|
-
.subscribe();
|
|
71
|
-
channels.current.push(channel);
|
|
72
|
-
return () => {
|
|
73
|
-
channels.current.forEach((ch) => scoutSupabase.removeChannel(ch));
|
|
74
|
-
channels.current = [];
|
|
75
|
-
};
|
|
76
|
-
}, [
|
|
77
|
-
scoutSupabase,
|
|
78
|
-
gpsDeviceIds,
|
|
79
|
-
activeHerdId,
|
|
80
|
-
handleConnectivityBroadcast,
|
|
81
|
-
clearLatestUpdate,
|
|
82
|
-
]);
|
|
83
|
-
return [latestConnectivityUpdate, clearLatestUpdate];
|
|
23
|
+
return useScoutRealtimeBroadcast(scoutSupabase, activeHerdId && hasGpsDevices
|
|
24
|
+
? [`${activeHerdId}-connectivity`]
|
|
25
|
+
: [], options, isGpsConnectivity);
|
|
84
26
|
}
|
|
@@ -2,4 +2,5 @@ import { SupabaseClient } from "@supabase/supabase-js";
|
|
|
2
2
|
import { Database } from "../types/supabase";
|
|
3
3
|
import { IContact } from "../types/db";
|
|
4
4
|
import { RealtimeData } from "../types/realtime";
|
|
5
|
-
|
|
5
|
+
import { ScoutRealtimeBroadcastOptions } from "./useScoutRealtimeBroadcast";
|
|
6
|
+
export declare function useScoutRealtimeContacts(scoutSupabase: SupabaseClient<Database>, options?: ScoutRealtimeBroadcastOptions): [RealtimeData<IContact> | null, () => void];
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { useSelector } from "react-redux";
|
|
3
|
-
import { useScoutRealtimeBroadcast } from "./useScoutRealtimeBroadcast";
|
|
4
|
-
export function useScoutRealtimeContacts(scoutSupabase) {
|
|
3
|
+
import { useScoutRealtimeBroadcast, } from "./useScoutRealtimeBroadcast";
|
|
4
|
+
export function useScoutRealtimeContacts(scoutSupabase, options) {
|
|
5
5
|
const activeHerdId = useSelector((state) => state.scout.active_herd_id);
|
|
6
|
-
return useScoutRealtimeBroadcast(scoutSupabase, activeHerdId ? [`${activeHerdId}-contacts`] : []);
|
|
6
|
+
return useScoutRealtimeBroadcast(scoutSupabase, activeHerdId ? [`${activeHerdId}-contacts`] : [], options);
|
|
7
7
|
}
|
|
@@ -2,4 +2,5 @@ import { SupabaseClient } from "@supabase/supabase-js";
|
|
|
2
2
|
import { Database } from "../types/supabase";
|
|
3
3
|
import { IDevicePrettyLocation } from "../types/db";
|
|
4
4
|
import { RealtimeData } from "../types/realtime";
|
|
5
|
-
|
|
5
|
+
import { ScoutRealtimeBroadcastOptions } from "./useScoutRealtimeBroadcast";
|
|
6
|
+
export declare function useScoutRealtimeDevices(scoutSupabase: SupabaseClient<Database>, options?: ScoutRealtimeBroadcastOptions): [RealtimeData<IDevicePrettyLocation> | null, () => void];
|
|
@@ -1,68 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { useSelector } from "react-redux";
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
export function useScoutRealtimeDevices(scoutSupabase) {
|
|
6
|
-
const channels = useRef([]);
|
|
7
|
-
const [latestDeviceUpdate, setLatestDeviceUpdate] = useState(null);
|
|
3
|
+
import { useScoutRealtimeBroadcast, } from "./useScoutRealtimeBroadcast";
|
|
4
|
+
export function useScoutRealtimeDevices(scoutSupabase, options) {
|
|
8
5
|
const activeHerdId = useSelector((state) => state.scout.active_herd_id);
|
|
9
|
-
|
|
10
|
-
const { payload: data } = message;
|
|
11
|
-
if (data.table !== "devices" || data.schema !== "public") {
|
|
12
|
-
return;
|
|
13
|
-
}
|
|
14
|
-
const deviceData = data.operation === "DELETE"
|
|
15
|
-
? data.old_record
|
|
16
|
-
: data.record ?? data.old_record;
|
|
17
|
-
if (!deviceData)
|
|
18
|
-
return;
|
|
19
|
-
let operation;
|
|
20
|
-
switch (data.operation) {
|
|
21
|
-
case "INSERT":
|
|
22
|
-
operation = EnumRealtimeOperation.INSERT;
|
|
23
|
-
break;
|
|
24
|
-
case "UPDATE":
|
|
25
|
-
operation = EnumRealtimeOperation.UPDATE;
|
|
26
|
-
break;
|
|
27
|
-
case "DELETE":
|
|
28
|
-
operation = EnumRealtimeOperation.DELETE;
|
|
29
|
-
break;
|
|
30
|
-
default:
|
|
31
|
-
return;
|
|
32
|
-
}
|
|
33
|
-
const realtimeData = {
|
|
34
|
-
data: deviceData,
|
|
35
|
-
operation,
|
|
36
|
-
};
|
|
37
|
-
setLatestDeviceUpdate(realtimeData);
|
|
38
|
-
}, []);
|
|
39
|
-
const clearLatestUpdate = useCallback(() => {
|
|
40
|
-
setLatestDeviceUpdate(null);
|
|
41
|
-
}, []);
|
|
42
|
-
useEffect(() => {
|
|
43
|
-
if (!scoutSupabase)
|
|
44
|
-
return;
|
|
45
|
-
channels.current.forEach((channel) => scoutSupabase.removeChannel(channel));
|
|
46
|
-
channels.current = [];
|
|
47
|
-
clearLatestUpdate();
|
|
48
|
-
if (activeHerdId) {
|
|
49
|
-
const channel = scoutSupabase
|
|
50
|
-
.channel(`${activeHerdId}-devices`, { config: { private: true } })
|
|
51
|
-
.on("broadcast", { event: "*" }, handleDeviceBroadcast)
|
|
52
|
-
.subscribe((status) => {
|
|
53
|
-
if (status === "SUBSCRIBED") {
|
|
54
|
-
console.log(`[Devices] ✅ Connected to herd ${activeHerdId}`);
|
|
55
|
-
}
|
|
56
|
-
else if (status === "CHANNEL_ERROR") {
|
|
57
|
-
console.warn(`[Devices] 🟡 Failed to connect to herd ${activeHerdId}`);
|
|
58
|
-
}
|
|
59
|
-
});
|
|
60
|
-
channels.current.push(channel);
|
|
61
|
-
}
|
|
62
|
-
return () => {
|
|
63
|
-
channels.current.forEach((ch) => scoutSupabase.removeChannel(ch));
|
|
64
|
-
channels.current = [];
|
|
65
|
-
};
|
|
66
|
-
}, [scoutSupabase, activeHerdId, handleDeviceBroadcast, clearLatestUpdate]);
|
|
67
|
-
return [latestDeviceUpdate, clearLatestUpdate];
|
|
6
|
+
return useScoutRealtimeBroadcast(scoutSupabase, activeHerdId ? [`${activeHerdId}-devices`] : [], options);
|
|
68
7
|
}
|
|
@@ -2,6 +2,6 @@ import { SupabaseClient } from "@supabase/supabase-js";
|
|
|
2
2
|
import { Database } from "../types/supabase";
|
|
3
3
|
import { IDocument } from "../types/db";
|
|
4
4
|
import { RealtimeData } from "../types/realtime";
|
|
5
|
-
|
|
6
|
-
export type DocumentRealtimeChannel = "herd" | "device" | "user" | "own" | "product";
|
|
7
|
-
export declare function useScoutRealtimeDocuments(scoutSupabase: SupabaseClient<Database>, channels?: DocumentRealtimeChannel[]): [RealtimeData<IDocument> | null, () => void];
|
|
5
|
+
import { ScoutRealtimeBroadcastOptions } from "./useScoutRealtimeBroadcast";
|
|
6
|
+
export type DocumentRealtimeChannel = "herd" | "device" | "user" | "own" | "product" | "operating_context";
|
|
7
|
+
export declare function useScoutRealtimeDocuments(scoutSupabase: SupabaseClient<Database>, channels?: DocumentRealtimeChannel[], options?: ScoutRealtimeBroadcastOptions): [RealtimeData<IDocument> | null, () => void];
|
|
@@ -1,22 +1,24 @@
|
|
|
1
1
|
"use client";
|
|
2
|
+
import { useMemo } from "react";
|
|
2
3
|
import { useSelector } from "react-redux";
|
|
3
|
-
import { useScoutRealtimeBroadcast } from "./useScoutRealtimeBroadcast";
|
|
4
|
+
import { useScoutRealtimeBroadcast, } from "./useScoutRealtimeBroadcast";
|
|
4
5
|
const ALL_DOCUMENT_CHANNELS = [
|
|
5
6
|
"herd",
|
|
6
7
|
"device",
|
|
7
8
|
"user",
|
|
8
9
|
"own",
|
|
9
10
|
"product",
|
|
11
|
+
"operating_context",
|
|
10
12
|
];
|
|
11
|
-
export function useScoutRealtimeDocuments(scoutSupabase, channels = ALL_DOCUMENT_CHANNELS) {
|
|
13
|
+
export function useScoutRealtimeDocuments(scoutSupabase, channels = ALL_DOCUMENT_CHANNELS, options) {
|
|
12
14
|
const activeHerdId = useSelector((state) => state.scout.active_herd_id);
|
|
13
15
|
const userId = useSelector((state) => state.scout.user?.id ?? null);
|
|
14
|
-
const topics = channels.flatMap((channel) => {
|
|
16
|
+
const topics = useMemo(() => channels.flatMap((channel) => {
|
|
15
17
|
if (channel === "product")
|
|
16
18
|
return ["product_documents_changes"];
|
|
17
19
|
if (channel === "own")
|
|
18
20
|
return userId ? [`user_${userId}-documents`] : [];
|
|
19
21
|
return activeHerdId ? [`${activeHerdId}-${channel}_documents`] : [];
|
|
20
|
-
});
|
|
21
|
-
return useScoutRealtimeBroadcast(scoutSupabase, topics);
|
|
22
|
+
}), [channels, activeHerdId, userId]);
|
|
23
|
+
return useScoutRealtimeBroadcast(scoutSupabase, topics, options);
|
|
22
24
|
}
|
|
@@ -2,4 +2,5 @@ import { SupabaseClient } from "@supabase/supabase-js";
|
|
|
2
2
|
import { Database } from "../types/supabase";
|
|
3
3
|
import { IEventAndTagsPrettyLocation } from "../types/db";
|
|
4
4
|
import { RealtimeData } from "../types/realtime";
|
|
5
|
-
|
|
5
|
+
import { ScoutRealtimeBroadcastOptions } from "./useScoutRealtimeBroadcast";
|
|
6
|
+
export declare function useScoutRealtimeEvents(scoutSupabase: SupabaseClient<Database>, options?: ScoutRealtimeBroadcastOptions): [RealtimeData<IEventAndTagsPrettyLocation> | null, () => void];
|
|
@@ -1,73 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { useSelector } from "react-redux";
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
export function useScoutRealtimeEvents(scoutSupabase) {
|
|
6
|
-
const channels = useRef([]);
|
|
7
|
-
const [latestEventUpdate, setLatestEventUpdate] = useState(null);
|
|
3
|
+
import { useScoutRealtimeBroadcast, } from "./useScoutRealtimeBroadcast";
|
|
4
|
+
export function useScoutRealtimeEvents(scoutSupabase, options) {
|
|
8
5
|
const activeHerdId = useSelector((state) => state.scout.active_herd_id);
|
|
9
|
-
|
|
10
|
-
const handleEventBroadcast = useCallback((payload) => {
|
|
11
|
-
console.log("[Events] Broadcast received:", payload.payload.operation);
|
|
12
|
-
const data = payload.payload;
|
|
13
|
-
const eventData = data.record || data.old_record;
|
|
14
|
-
if (!eventData)
|
|
15
|
-
return;
|
|
16
|
-
let operation;
|
|
17
|
-
switch (data.operation) {
|
|
18
|
-
case "INSERT":
|
|
19
|
-
operation = EnumRealtimeOperation.INSERT;
|
|
20
|
-
console.log("[Events] New event received:", data.record);
|
|
21
|
-
break;
|
|
22
|
-
case "UPDATE":
|
|
23
|
-
operation = EnumRealtimeOperation.UPDATE;
|
|
24
|
-
console.log("[Events] Event updated:", data.record);
|
|
25
|
-
break;
|
|
26
|
-
case "DELETE":
|
|
27
|
-
operation = EnumRealtimeOperation.DELETE;
|
|
28
|
-
console.log("[Events] Event deleted:", data.old_record);
|
|
29
|
-
break;
|
|
30
|
-
default:
|
|
31
|
-
return;
|
|
32
|
-
}
|
|
33
|
-
const realtimeData = {
|
|
34
|
-
data: eventData,
|
|
35
|
-
operation,
|
|
36
|
-
};
|
|
37
|
-
console.log(`[scout-core realtime] EVENT ${data.operation} received:`, JSON.stringify(realtimeData));
|
|
38
|
-
setLatestEventUpdate(realtimeData);
|
|
39
|
-
}, []);
|
|
40
|
-
// Clear latest update
|
|
41
|
-
const clearLatestUpdate = useCallback(() => {
|
|
42
|
-
setLatestEventUpdate(null);
|
|
43
|
-
}, []);
|
|
44
|
-
const cleanupChannels = () => {
|
|
45
|
-
channels.current.forEach((channel) => scoutSupabase.removeChannel(channel));
|
|
46
|
-
channels.current = [];
|
|
47
|
-
};
|
|
48
|
-
const createEventsChannel = (herdId) => {
|
|
49
|
-
return scoutSupabase
|
|
50
|
-
.channel(`${herdId}-events`, { config: { private: true } })
|
|
51
|
-
.on("broadcast", { event: "*" }, handleEventBroadcast)
|
|
52
|
-
.subscribe((status) => {
|
|
53
|
-
if (status === "SUBSCRIBED") {
|
|
54
|
-
console.log(`[Events] ✅ Connected to herd ${herdId}`);
|
|
55
|
-
}
|
|
56
|
-
else if (status === "CHANNEL_ERROR") {
|
|
57
|
-
console.warn(`[Events] 🟡 Failed to connect to herd ${herdId}`);
|
|
58
|
-
}
|
|
59
|
-
});
|
|
60
|
-
};
|
|
61
|
-
useEffect(() => {
|
|
62
|
-
cleanupChannels();
|
|
63
|
-
// Clear previous update when switching herds
|
|
64
|
-
clearLatestUpdate();
|
|
65
|
-
// Create events channel for active herd
|
|
66
|
-
if (activeHerdId) {
|
|
67
|
-
const channel = createEventsChannel(activeHerdId);
|
|
68
|
-
channels.current.push(channel);
|
|
69
|
-
}
|
|
70
|
-
return cleanupChannels;
|
|
71
|
-
}, [activeHerdId, clearLatestUpdate]);
|
|
72
|
-
return [latestEventUpdate, clearLatestUpdate];
|
|
6
|
+
return useScoutRealtimeBroadcast(scoutSupabase, activeHerdId ? [`${activeHerdId}-events`] : [], options);
|
|
73
7
|
}
|
|
@@ -2,4 +2,5 @@ import { SupabaseClient } from "@supabase/supabase-js";
|
|
|
2
2
|
import { Database } from "../types/supabase";
|
|
3
3
|
import { IMaintenanceRequest } from "../types/db";
|
|
4
4
|
import { RealtimeData } from "../types/realtime";
|
|
5
|
-
|
|
5
|
+
import { ScoutRealtimeBroadcastOptions } from "./useScoutRealtimeBroadcast";
|
|
6
|
+
export declare function useScoutRealtimeMaintenanceRequests(scoutSupabase: SupabaseClient<Database>, options?: ScoutRealtimeBroadcastOptions): [RealtimeData<IMaintenanceRequest> | null, () => void];
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { useSelector } from "react-redux";
|
|
3
|
-
import { useScoutRealtimeBroadcast } from "./useScoutRealtimeBroadcast";
|
|
4
|
-
export function useScoutRealtimeMaintenanceRequests(scoutSupabase) {
|
|
3
|
+
import { useScoutRealtimeBroadcast, } from "./useScoutRealtimeBroadcast";
|
|
4
|
+
export function useScoutRealtimeMaintenanceRequests(scoutSupabase, options) {
|
|
5
5
|
const activeHerdId = useSelector((state) => state.scout.active_herd_id);
|
|
6
|
-
return useScoutRealtimeBroadcast(scoutSupabase, activeHerdId ? [`${activeHerdId}-maintenance_requests`] : []);
|
|
6
|
+
return useScoutRealtimeBroadcast(scoutSupabase, activeHerdId ? [`${activeHerdId}-maintenance_requests`] : [], options);
|
|
7
7
|
}
|