@adventurelabs/scout-core 1.0.54 → 1.0.56

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,7 +1,3 @@
1
- import { IEvent } from "../types/db";
2
1
  import { IWebResponseCompatible } from "../types/requests";
3
2
  import { EnumSessionsVisibility } from "../types/events";
4
- export declare function server_get_events_by_herd(herd_id: number, sessions_visibility: EnumSessionsVisibility): Promise<IWebResponseCompatible<IEvent[]>>;
5
- export declare function server_get_more_events_by_herd(herd_id: number, offset: number, page_count: number | undefined, sessions_visibility: EnumSessionsVisibility): Promise<IWebResponseCompatible<IEvent[]>>;
6
3
  export declare function server_get_total_events_by_herd(herd_id: number, sessions_visibility: EnumSessionsVisibility): Promise<IWebResponseCompatible<number>>;
7
- export declare function server_create_event(newEvent: any): Promise<IWebResponseCompatible<boolean>>;
@@ -1,79 +1,16 @@
1
1
  "use server";
2
2
  import { newServerClient } from "../supabase/server";
3
3
  import { EnumWebResponse, IWebResponse, } from "../types/requests";
4
- import { addSignedUrlsToEvents } from "./storage";
5
4
  import { EnumSessionsVisibility } from "../types/events";
6
- export async function server_get_events_by_herd(herd_id, sessions_visibility) {
7
- const supabase = await newServerClient();
8
- // fetch events and include devices
9
- // sort by timestamp
10
- let query = supabase
11
- .from("events")
12
- .select(`
13
- *,
14
- devices: devices!inner(*)
15
- `)
16
- .eq("devices.herd_id", herd_id);
17
- // Apply session filter based on sessions_visibility
18
- if (sessions_visibility === EnumSessionsVisibility.Only) {
19
- query = query.not("session_id", "is", null);
20
- }
21
- else if (sessions_visibility === EnumSessionsVisibility.Exclude) {
22
- query = query.is("session_id", null);
23
- }
24
- const { data } = await query.order("timestamp_observation", { ascending: false });
25
- // Add signed URLs to events using the same client
26
- const eventsWithSignedUrls = data
27
- ? await addSignedUrlsToEvents(data, supabase)
28
- : [];
29
- // TODO: DETERMINE WHEN TO PASS ERROR
30
- let response = IWebResponse.success(eventsWithSignedUrls);
31
- return response.to_compatible();
32
- }
33
- export async function server_get_more_events_by_herd(herd_id, offset, page_count = 10, sessions_visibility) {
34
- const from = offset * page_count;
35
- const to = from + page_count - 1;
36
- const supabase = await newServerClient();
37
- // fetch events and include devices
38
- // sort by timestamp
39
- let query = supabase
40
- .from("events")
41
- .select(`
42
- *,
43
- devices: devices!inner(*)
44
- `)
45
- .eq("devices.herd_id", herd_id)
46
- .range(from, to);
47
- // Apply session filter based on sessions_visibility
48
- if (sessions_visibility === EnumSessionsVisibility.Only) {
49
- query = query.not("session_id", "is", null);
50
- }
51
- else if (sessions_visibility === EnumSessionsVisibility.Exclude) {
52
- query = query.is("session_id", null);
53
- }
54
- const { data } = await query.order("timestamp_observation", { ascending: false });
55
- // Add signed URLs to events using the same client
56
- const eventsWithSignedUrls = data
57
- ? await addSignedUrlsToEvents(data, supabase)
58
- : [];
59
- // TODO: DETERMINE WHEN TO PASS ERROR
60
- let response = IWebResponse.success(eventsWithSignedUrls);
61
- return response.to_compatible();
62
- }
63
5
  // function to get total number of events for a herd
64
6
  export async function server_get_total_events_by_herd(herd_id, sessions_visibility) {
65
7
  const supabase = await newServerClient();
66
- let query = supabase
67
- .from("events")
68
- .select("id", { count: "exact", head: true })
69
- .eq("devices.herd_id", herd_id);
70
- if (sessions_visibility === EnumSessionsVisibility.Only) {
71
- query = query.not("session_id", "is", null);
72
- }
73
- else if (sessions_visibility === EnumSessionsVisibility.Exclude) {
74
- query = query.is("session_id", null);
75
- }
76
- const { count, error } = await query;
8
+ // Convert sessions_visibility to exclude_session_events boolean
9
+ const exclude_session_events = sessions_visibility === EnumSessionsVisibility.Exclude;
10
+ const { data, error } = (await supabase.rpc("get_total_events_for_herd_with_session_filter", {
11
+ herd_id_caller: herd_id,
12
+ exclude_session_events: exclude_session_events,
13
+ }));
77
14
  if (error) {
78
15
  return {
79
16
  status: EnumWebResponse.ERROR,
@@ -82,21 +19,6 @@ export async function server_get_total_events_by_herd(herd_id, sessions_visibili
82
19
  };
83
20
  }
84
21
  else {
85
- return IWebResponse.success(count || 0).to_compatible();
86
- }
87
- }
88
- export async function server_create_event(newEvent) {
89
- const supabase = await newServerClient();
90
- // strip id field from herd object
91
- const { data, error } = await supabase.from("events").insert([newEvent]);
92
- if (error) {
93
- return {
94
- status: EnumWebResponse.ERROR,
95
- msg: error.message,
96
- data: null,
97
- };
98
- }
99
- else {
100
- return IWebResponse.success(true).to_compatible();
22
+ return IWebResponse.success(data || 0).to_compatible();
101
23
  }
102
24
  }
@@ -1,6 +1,5 @@
1
1
  import { IEventWithTags, ITag } from "../types/db";
2
2
  import { IWebResponseCompatible } from "../types/requests";
3
- export declare function test_event_loading(device_id: number): Promise<boolean>;
4
3
  export declare function server_create_tags(tags: ITag[]): Promise<IWebResponseCompatible<ITag[]>>;
5
4
  export declare function server_delete_tags_by_ids(tag_ids: number[]): Promise<IWebResponseCompatible<boolean>>;
6
5
  export declare function server_update_tags(tags: ITag[]): Promise<IWebResponseCompatible<ITag[]>>;
@@ -3,25 +3,6 @@
3
3
  import { newServerClient } from "../supabase/server";
4
4
  import { EnumWebResponse, IWebResponse, } from "../types/requests";
5
5
  import { addSignedUrlsToEvents, addSignedUrlToEvent } from "./storage";
6
- // Test function to verify individual event loading works
7
- export async function test_event_loading(device_id) {
8
- try {
9
- console.log(`[Event Test] Testing individual event loading for device ${device_id}`);
10
- const events_response = await server_get_events_and_tags_for_device(device_id, 1);
11
- if (events_response.status === EnumWebResponse.SUCCESS) {
12
- console.log(`[Event Test] Successfully loaded ${events_response.data?.length || 0} events for device ${device_id}`);
13
- return true;
14
- }
15
- else {
16
- console.error(`[Event Test] Failed to load events for device ${device_id}:`, events_response.msg);
17
- return false;
18
- }
19
- }
20
- catch (error) {
21
- console.error(`[Event Test] Failed to load events for device ${device_id}:`, error);
22
- return false;
23
- }
24
- }
25
6
  export async function server_create_tags(tags) {
26
7
  const supabase = await newServerClient();
27
8
  // remove id key from tags
@@ -94,29 +75,6 @@ export async function server_update_tags(tags) {
94
75
  }
95
76
  return IWebResponse.success(updatedTags).to_compatible();
96
77
  }
97
- // export async function server_get_events_with_tags_by_herd(
98
- // herd_id: number
99
- // ): Promise<IWebResponseCompatible<IEventWithTags[]>> {
100
- // const supabase = await newServerClient();
101
- // const { data, error } = await supabase
102
- // .from("events")
103
- // .select(
104
- // `
105
- // *,
106
- // tags: tags (*)
107
- // `
108
- // )
109
- // .eq("devices.herd_id", herd_id)
110
- // .order("timestamp_observation", { ascending: false });
111
- // if (error) {
112
- // return {
113
- // status: EnumWebResponse.ERROR,
114
- // msg: error.message,
115
- // data: [],
116
- // };
117
- // }
118
- // return IWebResponse.success(data).to_compatible();
119
- // }
120
78
  export async function server_get_more_events_with_tags_by_herd(herd_id, offset, page_count = 10) {
121
79
  const from = offset * page_count;
122
80
  const to = from + page_count - 1;
@@ -1,18 +1,3 @@
1
1
  import { SupabaseClient } from "@supabase/supabase-js";
2
2
  import { Database } from "../types/supabase";
3
- declare enum ConnectionState {
4
- DISCONNECTED = "disconnected",
5
- CONNECTING = "connecting",
6
- CONNECTED = "connected",
7
- ERROR = "error"
8
- }
9
- /**
10
- * Hook for listening to real-time database changes
11
- */
12
- export declare function useScoutDbListener(scoutSupabase: SupabaseClient<Database>): {
13
- connectionState: ConnectionState;
14
- lastError: string | null;
15
- isConnected: boolean;
16
- isConnecting: boolean;
17
- };
18
- export {};
3
+ export declare function useScoutDbListener(scoutSupabase: SupabaseClient<Database>): void;
@@ -1,170 +1,177 @@
1
1
  "use client";
2
2
  import { useAppDispatch } from "../store/hooks";
3
- import { useEffect, useRef, useState } from "react";
4
- import { addDevice, addPlan, addTag, deleteDevice, deletePlan, deleteTag, updateDevice, updatePlan, updateTag, } from "../store/scout";
5
- // Connection state enum
6
- var ConnectionState;
7
- (function (ConnectionState) {
8
- ConnectionState["DISCONNECTED"] = "disconnected";
9
- ConnectionState["CONNECTING"] = "connecting";
10
- ConnectionState["CONNECTED"] = "connected";
11
- ConnectionState["ERROR"] = "error";
12
- })(ConnectionState || (ConnectionState = {}));
13
- /**
14
- * Hook for listening to real-time database changes
15
- */
3
+ import { useEffect, useRef } from "react";
4
+ import { addDevice, addPlan, addTag, addSessionToStore, deleteDevice, deletePlan, deleteSessionFromStore, deleteTag, updateDevice, updatePlan, updateSessionInStore, updateTag, } from "../store/scout";
16
5
  export function useScoutDbListener(scoutSupabase) {
6
+ const supabase = useRef(null);
17
7
  const channels = useRef([]);
18
8
  const dispatch = useAppDispatch();
19
- const [connectionState, setConnectionState] = useState(ConnectionState.DISCONNECTED);
20
- const [lastError, setLastError] = useState(null);
9
+ const reconnectTimeoutRef = useRef(null);
10
+ const reconnectAttemptsRef = useRef(0);
11
+ const maxReconnectAttempts = 10;
12
+ const baseDelay = 1000; // 1 second
13
+ const maxDelay = 5000; // 5 seconds
14
+ function handleTagInserts(payload) {
15
+ console.log("[DB Listener] Tag INSERT received:", payload.new);
16
+ dispatch(addTag(payload.new));
17
+ }
18
+ function handleTagDeletes(payload) {
19
+ console.log("[DB Listener] Tag DELETE received:", payload.old);
20
+ if (!payload.old || !payload.old.id) {
21
+ console.error("[DB Listener] Tag DELETE - Invalid payload, missing tag data");
22
+ return;
23
+ }
24
+ dispatch(deleteTag(payload.old));
25
+ }
26
+ function handleTagUpdates(payload) {
27
+ console.log("[DB Listener] Tag UPDATE received:", payload.new);
28
+ dispatch(updateTag(payload.new));
29
+ }
30
+ function handleDeviceInserts(payload) {
31
+ console.log("[DB Listener] Device INSERT received:", payload.new);
32
+ dispatch(addDevice(payload.new));
33
+ }
34
+ function handleDeviceDeletes(payload) {
35
+ console.log("[DB Listener] Device DELETE received:", payload.old);
36
+ dispatch(deleteDevice(payload.old));
37
+ }
38
+ function handleDeviceUpdates(payload) {
39
+ console.log("[DB Listener] Device UPDATE received:", payload.new);
40
+ dispatch(updateDevice(payload.new));
41
+ }
42
+ function handlePlanInserts(payload) {
43
+ console.log("[DB Listener] Plan INSERT received:", payload.new);
44
+ dispatch(addPlan(payload.new));
45
+ }
46
+ function handlePlanDeletes(payload) {
47
+ console.log("[DB Listener] Plan DELETE received:", payload.old);
48
+ dispatch(deletePlan(payload.old));
49
+ }
50
+ function handlePlanUpdates(payload) {
51
+ console.log("[DB Listener] Plan UPDATE received:", payload.new);
52
+ dispatch(updatePlan(payload.new));
53
+ }
54
+ function handleSessionInserts(payload) {
55
+ console.log("[DB Listener] Session INSERT received:", payload.new);
56
+ dispatch(addSessionToStore(payload.new));
57
+ }
58
+ function handleSessionDeletes(payload) {
59
+ console.log("[DB Listener] Session DELETE received:", payload.old);
60
+ if (!payload.old || !payload.old.id) {
61
+ console.error("[DB Listener] Session DELETE - Invalid payload, missing session data");
62
+ return;
63
+ }
64
+ dispatch(deleteSessionFromStore(payload.old));
65
+ }
66
+ function handleSessionUpdates(payload) {
67
+ console.log("[DB Listener] Session UPDATE received:", payload.new);
68
+ dispatch(updateSessionInStore(payload.new));
69
+ }
70
+ function handleConnectivityInserts(payload) {
71
+ console.log("[DB Listener] Connectivity INSERT received:", payload.new);
72
+ }
73
+ function handleConnectivityDeletes(payload) {
74
+ console.log("[DB Listener] Connectivity DELETE received:", payload.old);
75
+ }
76
+ function handleConnectivityUpdates(payload) {
77
+ console.log("[DB Listener] Connectivity UPDATE received:", payload.new);
78
+ }
21
79
  // Clean up all channels
22
80
  const cleanupChannels = () => {
23
81
  channels.current.forEach((channel) => {
24
- if (channel && scoutSupabase) {
25
- try {
26
- scoutSupabase.removeChannel(channel);
27
- }
28
- catch (error) {
29
- console.warn("[DB Listener] Error removing channel:", error);
30
- }
82
+ if (channel) {
83
+ scoutSupabase.removeChannel(channel);
31
84
  }
32
85
  });
33
86
  channels.current = [];
34
87
  };
35
- // Create event handlers
36
- const handlers = {
37
- tags: {
38
- INSERT: (payload) => {
39
- if (payload.new)
40
- dispatch(addTag(payload.new));
41
- },
42
- UPDATE: (payload) => {
43
- if (payload.new)
44
- dispatch(updateTag(payload.new));
45
- },
46
- DELETE: (payload) => {
47
- if (payload.old)
48
- dispatch(deleteTag(payload.old));
49
- },
50
- },
51
- devices: {
52
- INSERT: (payload) => {
53
- if (payload.new)
54
- dispatch(addDevice(payload.new));
55
- },
56
- UPDATE: (payload) => {
57
- if (payload.new)
58
- dispatch(updateDevice(payload.new));
59
- },
60
- DELETE: (payload) => {
61
- if (payload.old)
62
- dispatch(deleteDevice(payload.old));
63
- },
64
- },
65
- plans: {
66
- INSERT: (payload) => {
67
- if (payload.new)
68
- dispatch(addPlan(payload.new));
69
- },
70
- UPDATE: (payload) => {
71
- if (payload.new)
72
- dispatch(updatePlan(payload.new));
73
- },
74
- DELETE: (payload) => {
75
- if (payload.old)
76
- dispatch(deletePlan(payload.old));
77
- },
78
- },
79
- sessions: {
80
- INSERT: (payload) => console.log("[DB Listener] Session INSERT:", payload),
81
- UPDATE: (payload) => console.log("[DB Listener] Session UPDATE:", payload),
82
- DELETE: (payload) => console.log("[DB Listener] Session DELETE:", payload),
83
- },
84
- connectivity: {
85
- INSERT: (payload) => console.log("[DB Listener] Connectivity INSERT:", payload),
86
- UPDATE: (payload) => console.log("[DB Listener] Connectivity UPDATE:", payload),
87
- DELETE: (payload) => console.log("[DB Listener] Connectivity DELETE:", payload),
88
- },
89
- };
90
- // Set up channels
91
- const setupChannels = async () => {
88
+ // Setup channel with event handlers
89
+ const setupChannel = () => {
92
90
  if (!scoutSupabase)
93
- return false;
94
- cleanupChannels();
95
- const tables = Object.keys(handlers);
96
- let successCount = 0;
97
- const totalChannels = tables.length;
98
- for (const tableName of tables) {
99
- try {
100
- const channelName = `scout_broadcast_${tableName}_${Date.now()}`;
101
- const channel = scoutSupabase.channel(channelName, {
102
- config: { private: false },
103
- });
104
- // Set up event handlers
105
- const tableHandler = handlers[tableName];
106
- Object.entries(tableHandler).forEach(([event, handler]) => {
107
- channel.on("broadcast", { event }, handler);
108
- });
109
- // Subscribe to the channel
110
- channel.subscribe((status) => {
111
- if (status === "SUBSCRIBED") {
112
- successCount++;
113
- if (successCount === totalChannels) {
114
- setConnectionState(ConnectionState.CONNECTED);
115
- setLastError(null);
116
- }
117
- }
118
- else if (status === "CHANNEL_ERROR" || status === "TIMED_OUT") {
119
- setLastError(`Channel subscription failed: ${status}`);
120
- }
121
- });
122
- channels.current.push(channel);
91
+ return null;
92
+ const mainChannel = scoutSupabase.channel("schema_db_changes");
93
+ // Subscribe to all events
94
+ mainChannel
95
+ .on("postgres_changes", { event: "INSERT", schema: "public", table: "plans" }, handlePlanInserts)
96
+ .on("postgres_changes", { event: "DELETE", schema: "public", table: "plans" }, handlePlanDeletes)
97
+ .on("postgres_changes", { event: "UPDATE", schema: "public", table: "plans" }, handlePlanUpdates)
98
+ .on("postgres_changes", { event: "INSERT", schema: "public", table: "devices" }, handleDeviceInserts)
99
+ .on("postgres_changes", { event: "DELETE", schema: "public", table: "devices" }, handleDeviceDeletes)
100
+ .on("postgres_changes", { event: "UPDATE", schema: "public", table: "devices" }, handleDeviceUpdates)
101
+ .on("postgres_changes", { event: "INSERT", schema: "public", table: "tags" }, handleTagInserts)
102
+ .on("postgres_changes", { event: "DELETE", schema: "public", table: "tags" }, handleTagDeletes)
103
+ .on("postgres_changes", { event: "UPDATE", schema: "public", table: "tags" }, handleTagUpdates)
104
+ .on("postgres_changes", { event: "INSERT", schema: "public", table: "connectivity" }, handleConnectivityInserts)
105
+ .on("postgres_changes", { event: "DELETE", schema: "public", table: "connectivity" }, handleConnectivityDeletes)
106
+ .on("postgres_changes", { event: "UPDATE", schema: "public", table: "connectivity" }, handleConnectivityUpdates)
107
+ .on("postgres_changes", { event: "INSERT", schema: "public", table: "sessions" }, handleSessionInserts)
108
+ .on("postgres_changes", { event: "DELETE", schema: "public", table: "sessions" }, handleSessionDeletes)
109
+ .on("postgres_changes", { event: "UPDATE", schema: "public", table: "sessions" }, handleSessionUpdates)
110
+ .subscribe((status) => {
111
+ console.log("[DB Listener] Subscription status:", status);
112
+ if (status === "SUBSCRIBED") {
113
+ console.log("[DB Listener] ✅ Successfully subscribed to real-time updates");
114
+ reconnectAttemptsRef.current = 0; // Reset reconnect attempts on successful connection
123
115
  }
124
- catch (error) {
125
- console.error(`[DB Listener] Failed to set up ${tableName} channel:`, error);
116
+ else if (status === "CHANNEL_ERROR") {
117
+ console.error("[DB Listener] Channel error occurred. Reconnecting...");
118
+ handleReconnect();
126
119
  }
127
- }
128
- return successCount > 0;
129
- };
130
- // Initialize connection
131
- const initializeConnection = async () => {
132
- if (!scoutSupabase)
133
- return;
134
- setConnectionState(ConnectionState.CONNECTING);
135
- try {
136
- // Test database connection
137
- const { error } = await scoutSupabase.from("tags").select("id").limit(1);
138
- if (error) {
139
- throw new Error("Database connection test failed");
120
+ else if (status === "TIMED_OUT") {
121
+ console.error("[DB Listener] Subscription timed out. Reconnecting...");
122
+ handleReconnect();
140
123
  }
141
- // Set up channels
142
- const success = await setupChannels();
143
- if (!success) {
144
- throw new Error("Channel setup failed");
124
+ else if (status === "CLOSED") {
125
+ console.log("[DB Listener] 🔒 Channel closed. Reconnecting...");
126
+ handleReconnect();
145
127
  }
128
+ });
129
+ return mainChannel;
130
+ };
131
+ // Handle reconnection with exponential backoff
132
+ const handleReconnect = () => {
133
+ if (reconnectAttemptsRef.current >= maxReconnectAttempts) {
134
+ console.error("[DB Listener] 🚫 Max reconnection attempts reached");
135
+ return;
146
136
  }
147
- catch (error) {
148
- setLastError(error instanceof Error ? error.message : "Unknown error");
149
- setConnectionState(ConnectionState.ERROR);
137
+ // Clear any existing timeout
138
+ if (reconnectTimeoutRef.current) {
139
+ clearTimeout(reconnectTimeoutRef.current);
150
140
  }
141
+ const delay = Math.min(baseDelay * (reconnectAttemptsRef.current + 1), maxDelay);
142
+ console.log(`[DB Listener] 🔄 Attempting reconnection in ${delay}ms (attempt ${reconnectAttemptsRef.current + 1}/${maxReconnectAttempts})`);
143
+ reconnectTimeoutRef.current = setTimeout(() => {
144
+ reconnectAttemptsRef.current++;
145
+ cleanupChannels();
146
+ const newChannel = setupChannel();
147
+ if (newChannel) {
148
+ channels.current.push(newChannel);
149
+ }
150
+ }, delay);
151
151
  };
152
- // Main effect
153
152
  useEffect(() => {
154
153
  if (!scoutSupabase) {
155
- setConnectionState(ConnectionState.ERROR);
156
- setLastError("No Supabase client available");
154
+ console.error("[DB Listener] No Supabase client available");
157
155
  return;
158
156
  }
159
- initializeConnection();
157
+ supabase.current = scoutSupabase;
158
+ // Initial channel setup
159
+ const mainChannel = setupChannel();
160
+ if (mainChannel) {
161
+ channels.current.push(mainChannel);
162
+ }
163
+ // Cleanup function
160
164
  return () => {
165
+ console.log("[DB Listener] 🧹 Cleaning up channels");
166
+ // Clear any pending reconnection attempts
167
+ if (reconnectTimeoutRef.current) {
168
+ clearTimeout(reconnectTimeoutRef.current);
169
+ reconnectTimeoutRef.current = null;
170
+ }
171
+ // Reset reconnect attempts
172
+ reconnectAttemptsRef.current = 0;
173
+ // Clean up channels
161
174
  cleanupChannels();
162
175
  };
163
- }, [scoutSupabase]);
164
- return {
165
- connectionState,
166
- lastError,
167
- isConnected: connectionState === ConnectionState.CONNECTED,
168
- isConnecting: connectionState === ConnectionState.CONNECTING,
169
- };
176
+ }, [scoutSupabase, dispatch]);
170
177
  }
@@ -716,6 +716,13 @@ export declare function useSupabase(): SupabaseClient<Database, "public", {
716
716
  };
717
717
  Returns: number;
718
718
  };
719
+ get_total_events_for_herd_with_session_filter: {
720
+ Args: {
721
+ herd_id_caller: number;
722
+ exclude_session_events: boolean;
723
+ };
724
+ Returns: number;
725
+ };
719
726
  get_zones_and_actions_for_herd: {
720
727
  Args: {
721
728
  herd_id_caller: number;
@@ -707,6 +707,13 @@ export declare function newServerClient(): Promise<import("@supabase/supabase-js
707
707
  };
708
708
  Returns: number;
709
709
  };
710
+ get_total_events_for_herd_with_session_filter: {
711
+ Args: {
712
+ herd_id_caller: number;
713
+ exclude_session_events: boolean;
714
+ };
715
+ Returns: number;
716
+ };
710
717
  get_zones_and_actions_for_herd: {
711
718
  Args: {
712
719
  herd_id_caller: number;
@@ -776,6 +776,13 @@ export type Database = {
776
776
  };
777
777
  Returns: number;
778
778
  };
779
+ get_total_events_for_herd_with_session_filter: {
780
+ Args: {
781
+ herd_id_caller: number;
782
+ exclude_session_events: boolean;
783
+ };
784
+ Returns: number;
785
+ };
779
786
  get_zones_and_actions_for_herd: {
780
787
  Args: {
781
788
  herd_id_caller: number;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adventurelabs/scout-core",
3
- "version": "1.0.54",
3
+ "version": "1.0.56",
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",