@adventurelabs/scout-core 1.4.18 → 1.4.19

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,6 +1,7 @@
1
1
  import { IArtifact, IArtifactWithMediaUrl, ArtifactInsert, ArtifactUpdate } from "../types/db";
2
2
  import { IWebResponseCompatible } from "../types/requests";
3
3
  import { SupabaseClient } from "@supabase/supabase-js";
4
+ export declare function server_get_artifact_by_id(id: number, client?: SupabaseClient): Promise<IWebResponseCompatible<IArtifactWithMediaUrl | null>>;
4
5
  export declare function server_get_artifacts_by_herd(herd_id: number, limit?: number, offset?: number, options?: {
5
6
  start_timestamp?: string;
6
7
  end_timestamp?: string;
@@ -1,7 +1,30 @@
1
1
  "use server";
2
2
  import { newServerClient } from "../supabase/server";
3
3
  import { IWebResponse } from "../types/requests";
4
- import { generateSignedUrlsBatch } from "./storage";
4
+ import { generateSignedUrlsBatch, generateSignedUrl } from "./storage";
5
+ export async function server_get_artifact_by_id(id, client) {
6
+ const supabase = client || (await newServerClient());
7
+ const { data, error } = await supabase
8
+ .from("artifacts")
9
+ .select("*")
10
+ .eq("id", id)
11
+ .single();
12
+ if (error) {
13
+ return IWebResponse.error(error.message).to_compatible();
14
+ }
15
+ if (!data) {
16
+ return IWebResponse.success(null).to_compatible();
17
+ }
18
+ const artifact = data;
19
+ let media_url = null;
20
+ if (artifact.file_path) {
21
+ media_url = await generateSignedUrl(artifact.file_path, undefined, client);
22
+ }
23
+ return IWebResponse.success({
24
+ ...artifact,
25
+ media_url,
26
+ }).to_compatible();
27
+ }
5
28
  export async function server_get_artifacts_by_herd(herd_id, limit = 50, offset = 0, options) {
6
29
  const supabase = options?.client || (await newServerClient());
7
30
  const { data, error } = await supabase.rpc("get_artifacts_for_herd", {
@@ -1,7 +1,8 @@
1
1
  import { IWebResponseCompatible } from "../types/requests";
2
2
  import { EnumSessionsVisibility } from "../types/events";
3
- import { IEvent, EventInsert, EventUpdate } from "../types/db";
3
+ import { IEvent, IEventWithMediaUrl, EventInsert, EventUpdate } from "../types/db";
4
4
  import { SupabaseClient } from "@supabase/supabase-js";
5
+ export declare function server_get_event_by_id(id: number, client?: SupabaseClient): Promise<IWebResponseCompatible<IEventWithMediaUrl | null>>;
5
6
  export declare function server_get_total_events_by_herd(herd_id: number, sessions_visibility: EnumSessionsVisibility): Promise<IWebResponseCompatible<number>>;
6
7
  export declare function server_insert_event(events: EventInsert | EventInsert[], client?: SupabaseClient): Promise<IWebResponseCompatible<IEvent[]>>;
7
8
  export declare function server_update_event(events: (EventUpdate & {
@@ -2,6 +2,30 @@
2
2
  import { newServerClient } from "../supabase/server";
3
3
  import { EnumWebResponse, IWebResponse, } from "../types/requests";
4
4
  import { EnumSessionsVisibility } from "../types/events";
5
+ import { generateSignedUrl } from "./storage";
6
+ export async function server_get_event_by_id(id, client) {
7
+ const supabase = client || (await newServerClient());
8
+ const { data, error } = await supabase
9
+ .from("events")
10
+ .select("*")
11
+ .eq("id", id)
12
+ .single();
13
+ if (error) {
14
+ return IWebResponse.error(error.message).to_compatible();
15
+ }
16
+ if (!data) {
17
+ return IWebResponse.success(null).to_compatible();
18
+ }
19
+ const event = data;
20
+ let media_url = null;
21
+ if (event.file_path) {
22
+ media_url = await generateSignedUrl(event.file_path, undefined, client);
23
+ }
24
+ return IWebResponse.success({
25
+ ...event,
26
+ media_url,
27
+ }).to_compatible();
28
+ }
5
29
  // function to get total number of events for a herd
6
30
  export async function server_get_total_events_by_herd(herd_id, sessions_visibility) {
7
31
  const supabase = await newServerClient();
@@ -419,6 +419,7 @@ export async function get_event_and_tags_by_event_id(event_id) {
419
419
  y: tag.y,
420
420
  class: tag.class,
421
421
  timestamp_observation: tag.timestamp_observation,
422
+ frame_index: tag.frame_index ?? null,
422
423
  origin_location: tag.origin_location ?? null,
423
424
  origin_pitch: tag.origin_pitch,
424
425
  origin_heading: tag.origin_heading,
@@ -1,5 +1,5 @@
1
1
  import { SupabaseClient } from "@supabase/supabase-js";
2
- import { IArtifactWithMediaUrl, ISessionWithCoordinates, IEventAndTagsPrettyLocation } from "../types/db";
2
+ import { IArtifactWithMediaUrl, ISessionWithCoordinates, IEventAndTagsPrettyLocation, IFeedItem } from "../types/db";
3
3
  interface UseInfiniteScrollOptions {
4
4
  limit?: number;
5
5
  enabled?: boolean;
@@ -20,5 +20,7 @@ export declare const useInfiniteEventsByHerd: (herdId: number, options: UseInfin
20
20
  export declare const useInfiniteEventsByDevice: (deviceId: number, options: UseInfiniteScrollOptions) => InfiniteScrollData<IEventAndTagsPrettyLocation>;
21
21
  export declare const useInfiniteArtifactsByHerd: (herdId: number, options: UseInfiniteScrollOptions) => InfiniteScrollData<IArtifactWithMediaUrl>;
22
22
  export declare const useInfiniteArtifactsByDevice: (deviceId: number, options: UseInfiniteScrollOptions) => InfiniteScrollData<IArtifactWithMediaUrl>;
23
+ export declare const useInfiniteFeedByHerd: (herdId: number, options: UseInfiniteScrollOptions) => InfiniteScrollData<IFeedItem>;
24
+ export declare const useInfiniteFeedByDevice: (deviceId: number, options: UseInfiniteScrollOptions) => InfiniteScrollData<IFeedItem>;
23
25
  export declare const useIntersectionObserver: (callback: () => void, options?: IntersectionObserverInit) => import("react").Dispatch<import("react").SetStateAction<Element | null>>;
24
26
  export {};
@@ -1,5 +1,5 @@
1
1
  import { useState, useCallback, useMemo, useEffect, useRef } from "react";
2
- import { useGetSessionsInfiniteByHerdQuery, useGetSessionsInfiniteByDeviceQuery, useGetEventsInfiniteByHerdQuery, useGetEventsInfiniteByDeviceQuery, useGetArtifactsInfiniteByHerdQuery, useGetArtifactsInfiniteByDeviceQuery, } from "../store/api";
2
+ import { useGetSessionsInfiniteByHerdQuery, useGetSessionsInfiniteByDeviceQuery, useGetEventsInfiniteByHerdQuery, useGetEventsInfiniteByDeviceQuery, useGetArtifactsInfiniteByHerdQuery, useGetArtifactsInfiniteByDeviceQuery, useGetFeedInfiniteByHerdQuery, useGetFeedInfiniteByDeviceQuery, } from "../store/api";
3
3
  // =====================================================
4
4
  // SESSIONS INFINITE SCROLL HOOKS
5
5
  // =====================================================
@@ -407,6 +407,127 @@ export const useInfiniteArtifactsByDevice = (deviceId, options) => {
407
407
  error: currentQuery.error,
408
408
  };
409
409
  };
410
+ const feedCursorEq = (a, b) => {
411
+ if (a === null && b === null)
412
+ return true;
413
+ if (!a || !b)
414
+ return false;
415
+ return a.timestamp === b.timestamp && a.id === b.id && a.feed_type === b.feed_type;
416
+ };
417
+ export const useInfiniteFeedByHerd = (herdId, options) => {
418
+ const [pages, setPages] = useState([]);
419
+ const [currentCursor, setCurrentCursor] = useState(null);
420
+ const prevHerdIdRef = useRef();
421
+ const currentQuery = useGetFeedInfiniteByHerdQuery({
422
+ herdId,
423
+ limit: options.limit || 20,
424
+ cursor: currentCursor,
425
+ supabase: options.supabase,
426
+ }, { skip: !options.enabled || !herdId });
427
+ useEffect(() => {
428
+ if (prevHerdIdRef.current !== undefined &&
429
+ prevHerdIdRef.current !== herdId &&
430
+ options.enabled &&
431
+ herdId) {
432
+ setPages([]);
433
+ setCurrentCursor(null);
434
+ }
435
+ prevHerdIdRef.current = herdId;
436
+ }, [herdId, options.enabled]);
437
+ useEffect(() => {
438
+ if (currentQuery.data && !currentQuery.isLoading) {
439
+ setPages((prev) => {
440
+ const existingPage = prev.find((p) => feedCursorEq(p.cursor, currentCursor));
441
+ if (!existingPage) {
442
+ return [
443
+ ...prev,
444
+ { cursor: currentCursor, data: currentQuery.data.items },
445
+ ];
446
+ }
447
+ return prev;
448
+ });
449
+ }
450
+ }, [currentQuery.data, currentQuery.isLoading, currentCursor]);
451
+ const loadMore = useCallback(() => {
452
+ if (currentQuery.data?.hasMore &&
453
+ currentQuery.data.nextCursor &&
454
+ !currentQuery.isLoading) {
455
+ setCurrentCursor(currentQuery.data.nextCursor);
456
+ }
457
+ }, [currentQuery.data, currentQuery.isLoading]);
458
+ const refetch = useCallback(() => {
459
+ setPages([]);
460
+ setCurrentCursor(null);
461
+ currentQuery.refetch();
462
+ }, [currentQuery]);
463
+ const allItems = useMemo(() => pages.flatMap((p) => p.data), [pages]);
464
+ return {
465
+ items: allItems,
466
+ isLoading: currentQuery.isLoading && pages.length === 0,
467
+ isLoadingMore: currentQuery.isLoading && pages.length > 0,
468
+ hasMore: currentQuery.data?.hasMore ?? false,
469
+ loadMore,
470
+ refetch,
471
+ error: currentQuery.error,
472
+ };
473
+ };
474
+ export const useInfiniteFeedByDevice = (deviceId, options) => {
475
+ const [pages, setPages] = useState([]);
476
+ const [currentCursor, setCurrentCursor] = useState(null);
477
+ const prevDeviceIdRef = useRef();
478
+ const currentQuery = useGetFeedInfiniteByDeviceQuery({
479
+ deviceId,
480
+ limit: options.limit || 20,
481
+ cursor: currentCursor,
482
+ supabase: options.supabase,
483
+ }, { skip: !options.enabled || !deviceId });
484
+ useEffect(() => {
485
+ if (prevDeviceIdRef.current !== undefined &&
486
+ prevDeviceIdRef.current !== deviceId &&
487
+ options.enabled &&
488
+ deviceId) {
489
+ setPages([]);
490
+ setCurrentCursor(null);
491
+ }
492
+ prevDeviceIdRef.current = deviceId;
493
+ }, [deviceId, options.enabled]);
494
+ useEffect(() => {
495
+ if (currentQuery.data && !currentQuery.isLoading) {
496
+ setPages((prev) => {
497
+ const existingPage = prev.find((p) => feedCursorEq(p.cursor, currentCursor));
498
+ if (!existingPage) {
499
+ return [
500
+ ...prev,
501
+ { cursor: currentCursor, data: currentQuery.data.items },
502
+ ];
503
+ }
504
+ return prev;
505
+ });
506
+ }
507
+ }, [currentQuery.data, currentQuery.isLoading, currentCursor]);
508
+ const loadMore = useCallback(() => {
509
+ if (currentQuery.data?.hasMore &&
510
+ currentQuery.data.nextCursor &&
511
+ !currentQuery.isLoading) {
512
+ setCurrentCursor(currentQuery.data.nextCursor);
513
+ }
514
+ }, [currentQuery.data, currentQuery.isLoading]);
515
+ const refetch = useCallback(() => {
516
+ setPages([]);
517
+ setCurrentCursor(null);
518
+ currentQuery.refetch();
519
+ }, [currentQuery]);
520
+ const allItems = useMemo(() => pages.flatMap((p) => p.data), [pages]);
521
+ return {
522
+ items: allItems,
523
+ isLoading: currentQuery.isLoading && pages.length === 0,
524
+ isLoadingMore: currentQuery.isLoading && pages.length > 0,
525
+ hasMore: currentQuery.data?.hasMore ?? false,
526
+ loadMore,
527
+ refetch,
528
+ error: currentQuery.error,
529
+ };
530
+ };
410
531
  // =====================================================
411
532
  // INTERSECTION OBSERVER HOOK FOR AUTO-LOADING
412
533
  // =====================================================
@@ -927,6 +927,7 @@ export declare function useSupabase(): SupabaseClient<Database, "public", "publi
927
927
  conf: number;
928
928
  detector: string;
929
929
  event_id: number | null;
930
+ frame_index: number | null;
930
931
  height: number;
931
932
  id: number;
932
933
  inserted_at: string;
@@ -953,6 +954,7 @@ export declare function useSupabase(): SupabaseClient<Database, "public", "publi
953
954
  conf: number;
954
955
  detector?: string;
955
956
  event_id?: number | null;
957
+ frame_index?: number | null;
956
958
  height?: number;
957
959
  id?: number;
958
960
  inserted_at?: string;
@@ -979,6 +981,7 @@ export declare function useSupabase(): SupabaseClient<Database, "public", "publi
979
981
  conf?: number;
980
982
  detector?: string;
981
983
  event_id?: number | null;
984
+ frame_index?: number | null;
982
985
  height?: number;
983
986
  id?: number;
984
987
  inserted_at?: string;
@@ -1694,6 +1697,38 @@ export declare function useSupabase(): SupabaseClient<Database, "public", "publi
1694
1697
  isSetofReturn: true;
1695
1698
  };
1696
1699
  };
1700
+ get_feed_infinite_by_device: {
1701
+ Args: {
1702
+ cursor_feed_type?: string;
1703
+ cursor_id?: number;
1704
+ cursor_timestamp?: string;
1705
+ device_id_caller: number;
1706
+ limit_caller?: number;
1707
+ };
1708
+ Returns: Database["public"]["CompositeTypes"]["feed_item"][];
1709
+ SetofOptions: {
1710
+ from: "*";
1711
+ to: "feed_item";
1712
+ isOneToOne: false;
1713
+ isSetofReturn: true;
1714
+ };
1715
+ };
1716
+ get_feed_infinite_by_herd: {
1717
+ Args: {
1718
+ cursor_feed_type?: string;
1719
+ cursor_id?: number;
1720
+ cursor_timestamp?: string;
1721
+ herd_id_caller: number;
1722
+ limit_caller?: number;
1723
+ };
1724
+ Returns: Database["public"]["CompositeTypes"]["feed_item"][];
1725
+ SetofOptions: {
1726
+ from: "*";
1727
+ to: "feed_item";
1728
+ isOneToOne: false;
1729
+ isSetofReturn: true;
1730
+ };
1731
+ };
1697
1732
  get_health_metrics_summary: {
1698
1733
  Args: {
1699
1734
  p_device_id: number;
@@ -2066,6 +2101,13 @@ export declare function useSupabase(): SupabaseClient<Database, "public", "publi
2066
2101
  is_public: boolean | null;
2067
2102
  tags: Database["public"]["Tables"]["tags"]["Row"][] | null;
2068
2103
  };
2104
+ feed_item: {
2105
+ feed_type: string | null;
2106
+ sort_ts: string | null;
2107
+ sort_id: number | null;
2108
+ event_data: Database["public"]["CompositeTypes"]["event_and_tags_pretty_location"] | null;
2109
+ artifact_data: Database["public"]["Tables"]["artifacts"]["Row"] | null;
2110
+ };
2069
2111
  herds_pretty_location: {
2070
2112
  id: number | null;
2071
2113
  inserted_at: string | null;
@@ -2125,6 +2167,7 @@ export declare function useSupabase(): SupabaseClient<Database, "public", "publi
2125
2167
  y: number | null;
2126
2168
  class: string | null;
2127
2169
  timestamp_observation: string | null;
2170
+ frame_index: number | null;
2128
2171
  origin_location: unknown;
2129
2172
  origin_pitch: number | null;
2130
2173
  origin_heading: number | null;
@@ -1,5 +1,5 @@
1
1
  import { SupabaseClient } from "@supabase/supabase-js";
2
- import { IArtifactWithMediaUrl, ISessionWithCoordinates, IEventAndTagsPrettyLocation } from "../types/db";
2
+ import { IArtifactWithMediaUrl, ISessionWithCoordinates, IEventAndTagsPrettyLocation, IFeedItem } from "../types/db";
3
3
  export interface InfiniteQueryArgs {
4
4
  herdId?: number;
5
5
  deviceId?: number;
@@ -33,6 +33,16 @@ export interface ArtifactsInfiniteResponse {
33
33
  } | null;
34
34
  hasMore: boolean;
35
35
  }
36
+ export interface FeedCursor {
37
+ timestamp: string;
38
+ id: number;
39
+ feed_type: string;
40
+ }
41
+ export interface FeedInfiniteResponse {
42
+ items: IFeedItem[];
43
+ nextCursor: FeedCursor | null;
44
+ hasMore: boolean;
45
+ }
36
46
  export declare const scoutApi: import("@reduxjs/toolkit/query").Api<import("@reduxjs/toolkit/query").BaseQueryFn<any, unknown, unknown, {}, {}>, {
37
47
  getSessionsInfiniteByHerd: import("@reduxjs/toolkit/query").QueryDefinition<InfiniteQueryArgs & {
38
48
  supabase: SupabaseClient;
@@ -52,6 +62,18 @@ export declare const scoutApi: import("@reduxjs/toolkit/query").Api<import("@red
52
62
  getArtifactsInfiniteByDevice: import("@reduxjs/toolkit/query").QueryDefinition<InfiniteQueryArgs & {
53
63
  supabase: SupabaseClient;
54
64
  }, import("@reduxjs/toolkit/query").BaseQueryFn<any, unknown, unknown, {}, {}>, "Session" | "Event" | "Artifact", ArtifactsInfiniteResponse, "scoutApi", unknown>;
65
+ getFeedInfiniteByHerd: import("@reduxjs/toolkit/query").QueryDefinition<{
66
+ herdId: number;
67
+ limit?: number;
68
+ cursor?: FeedCursor | null;
69
+ supabase: SupabaseClient;
70
+ }, import("@reduxjs/toolkit/query").BaseQueryFn<any, unknown, unknown, {}, {}>, "Session" | "Event" | "Artifact", FeedInfiniteResponse, "scoutApi", unknown>;
71
+ getFeedInfiniteByDevice: import("@reduxjs/toolkit/query").QueryDefinition<{
72
+ deviceId: number;
73
+ limit?: number;
74
+ cursor?: FeedCursor | null;
75
+ supabase: SupabaseClient;
76
+ }, import("@reduxjs/toolkit/query").BaseQueryFn<any, unknown, unknown, {}, {}>, "Session" | "Event" | "Artifact", FeedInfiniteResponse, "scoutApi", unknown>;
55
77
  }, "scoutApi", "Session" | "Event" | "Artifact", typeof import("@reduxjs/toolkit/query").coreModuleName | typeof import("@reduxjs/toolkit/query/react").reactHooksModuleName>;
56
78
  export declare const useGetSessionsInfiniteByHerdQuery: <R extends Record<string, any> = import("@reduxjs/toolkit/query").TSHelpersId<(Omit<{
57
79
  status: import("@reduxjs/toolkit/query").QueryStatus.uninitialized;
@@ -965,4 +987,368 @@ export declare const useGetSessionsInfiniteByHerdQuery: <R extends Record<string
965
987
  refetch: () => import("@reduxjs/toolkit/query").QueryActionCreatorResult<import("@reduxjs/toolkit/query").QueryDefinition<InfiniteQueryArgs & {
966
988
  supabase: SupabaseClient;
967
989
  }, import("@reduxjs/toolkit/query").BaseQueryFn<any, unknown, unknown, {}, {}>, "Session" | "Event" | "Artifact", ArtifactsInfiniteResponse, "scoutApi", unknown>>;
990
+ }, useGetFeedInfiniteByHerdQuery: <R extends Record<string, any> = import("@reduxjs/toolkit/query").TSHelpersId<(Omit<{
991
+ status: import("@reduxjs/toolkit/query").QueryStatus.uninitialized;
992
+ originalArgs?: undefined | undefined;
993
+ data?: undefined | undefined;
994
+ error?: undefined | undefined;
995
+ requestId?: undefined | undefined;
996
+ endpointName?: string | undefined;
997
+ startedTimeStamp?: undefined | undefined;
998
+ fulfilledTimeStamp?: undefined | undefined;
999
+ } & {
1000
+ currentData?: FeedInfiniteResponse | undefined;
1001
+ isUninitialized: false;
1002
+ isLoading: false;
1003
+ isFetching: false;
1004
+ isSuccess: false;
1005
+ isError: false;
1006
+ }, "isUninitialized"> & {
1007
+ isUninitialized: true;
1008
+ }) | import("@reduxjs/toolkit/query").TSHelpersOverride<import("@reduxjs/toolkit/query").QuerySubState<import("@reduxjs/toolkit/query").QueryDefinition<{
1009
+ herdId: number;
1010
+ limit?: number;
1011
+ cursor?: FeedCursor | null;
1012
+ supabase: SupabaseClient;
1013
+ }, import("@reduxjs/toolkit/query").BaseQueryFn<any, unknown, unknown, {}, {}>, "Session" | "Event" | "Artifact", FeedInfiniteResponse, "scoutApi", unknown>> & {
1014
+ currentData?: FeedInfiniteResponse | undefined;
1015
+ isUninitialized: false;
1016
+ isLoading: false;
1017
+ isFetching: false;
1018
+ isSuccess: false;
1019
+ isError: false;
1020
+ }, {
1021
+ isLoading: true;
1022
+ isFetching: boolean;
1023
+ data: undefined;
1024
+ } | ({
1025
+ isSuccess: true;
1026
+ isFetching: true;
1027
+ error: undefined;
1028
+ } & Required<Pick<import("@reduxjs/toolkit/query").QuerySubState<import("@reduxjs/toolkit/query").QueryDefinition<{
1029
+ herdId: number;
1030
+ limit?: number;
1031
+ cursor?: FeedCursor | null;
1032
+ supabase: SupabaseClient;
1033
+ }, import("@reduxjs/toolkit/query").BaseQueryFn<any, unknown, unknown, {}, {}>, "Session" | "Event" | "Artifact", FeedInfiniteResponse, "scoutApi", unknown>> & {
1034
+ currentData?: FeedInfiniteResponse | undefined;
1035
+ isUninitialized: false;
1036
+ isLoading: false;
1037
+ isFetching: false;
1038
+ isSuccess: false;
1039
+ isError: false;
1040
+ }, "data" | "fulfilledTimeStamp">>) | ({
1041
+ isSuccess: true;
1042
+ isFetching: false;
1043
+ error: undefined;
1044
+ } & Required<Pick<import("@reduxjs/toolkit/query").QuerySubState<import("@reduxjs/toolkit/query").QueryDefinition<{
1045
+ herdId: number;
1046
+ limit?: number;
1047
+ cursor?: FeedCursor | null;
1048
+ supabase: SupabaseClient;
1049
+ }, import("@reduxjs/toolkit/query").BaseQueryFn<any, unknown, unknown, {}, {}>, "Session" | "Event" | "Artifact", FeedInfiniteResponse, "scoutApi", unknown>> & {
1050
+ currentData?: FeedInfiniteResponse | undefined;
1051
+ isUninitialized: false;
1052
+ isLoading: false;
1053
+ isFetching: false;
1054
+ isSuccess: false;
1055
+ isError: false;
1056
+ }, "data" | "fulfilledTimeStamp" | "currentData">>) | ({
1057
+ isError: true;
1058
+ } & Required<Pick<import("@reduxjs/toolkit/query").QuerySubState<import("@reduxjs/toolkit/query").QueryDefinition<{
1059
+ herdId: number;
1060
+ limit?: number;
1061
+ cursor?: FeedCursor | null;
1062
+ supabase: SupabaseClient;
1063
+ }, import("@reduxjs/toolkit/query").BaseQueryFn<any, unknown, unknown, {}, {}>, "Session" | "Event" | "Artifact", FeedInfiniteResponse, "scoutApi", unknown>> & {
1064
+ currentData?: FeedInfiniteResponse | undefined;
1065
+ isUninitialized: false;
1066
+ isLoading: false;
1067
+ isFetching: false;
1068
+ isSuccess: false;
1069
+ isError: false;
1070
+ }, "error">>)>> & {
1071
+ status: import("@reduxjs/toolkit/query").QueryStatus;
1072
+ }>(arg: {
1073
+ herdId: number;
1074
+ limit?: number;
1075
+ cursor?: FeedCursor | null;
1076
+ supabase: SupabaseClient;
1077
+ } | typeof import("@reduxjs/toolkit/query").skipToken, options?: (import("@reduxjs/toolkit/query").SubscriptionOptions & {
1078
+ skip?: boolean;
1079
+ refetchOnMountOrArgChange?: boolean | number;
1080
+ } & {
1081
+ skip?: boolean;
1082
+ selectFromResult?: ((state: import("@reduxjs/toolkit/query").TSHelpersId<(Omit<{
1083
+ status: import("@reduxjs/toolkit/query").QueryStatus.uninitialized;
1084
+ originalArgs?: undefined | undefined;
1085
+ data?: undefined | undefined;
1086
+ error?: undefined | undefined;
1087
+ requestId?: undefined | undefined;
1088
+ endpointName?: string | undefined;
1089
+ startedTimeStamp?: undefined | undefined;
1090
+ fulfilledTimeStamp?: undefined | undefined;
1091
+ } & {
1092
+ currentData?: FeedInfiniteResponse | undefined;
1093
+ isUninitialized: false;
1094
+ isLoading: false;
1095
+ isFetching: false;
1096
+ isSuccess: false;
1097
+ isError: false;
1098
+ }, "isUninitialized"> & {
1099
+ isUninitialized: true;
1100
+ }) | import("@reduxjs/toolkit/query").TSHelpersOverride<import("@reduxjs/toolkit/query").QuerySubState<import("@reduxjs/toolkit/query").QueryDefinition<{
1101
+ herdId: number;
1102
+ limit?: number;
1103
+ cursor?: FeedCursor | null;
1104
+ supabase: SupabaseClient;
1105
+ }, import("@reduxjs/toolkit/query").BaseQueryFn<any, unknown, unknown, {}, {}>, "Session" | "Event" | "Artifact", FeedInfiniteResponse, "scoutApi", unknown>> & {
1106
+ currentData?: FeedInfiniteResponse | undefined;
1107
+ isUninitialized: false;
1108
+ isLoading: false;
1109
+ isFetching: false;
1110
+ isSuccess: false;
1111
+ isError: false;
1112
+ }, {
1113
+ isLoading: true;
1114
+ isFetching: boolean;
1115
+ data: undefined;
1116
+ } | ({
1117
+ isSuccess: true;
1118
+ isFetching: true;
1119
+ error: undefined;
1120
+ } & Required<Pick<import("@reduxjs/toolkit/query").QuerySubState<import("@reduxjs/toolkit/query").QueryDefinition<{
1121
+ herdId: number;
1122
+ limit?: number;
1123
+ cursor?: FeedCursor | null;
1124
+ supabase: SupabaseClient;
1125
+ }, import("@reduxjs/toolkit/query").BaseQueryFn<any, unknown, unknown, {}, {}>, "Session" | "Event" | "Artifact", FeedInfiniteResponse, "scoutApi", unknown>> & {
1126
+ currentData?: FeedInfiniteResponse | undefined;
1127
+ isUninitialized: false;
1128
+ isLoading: false;
1129
+ isFetching: false;
1130
+ isSuccess: false;
1131
+ isError: false;
1132
+ }, "data" | "fulfilledTimeStamp">>) | ({
1133
+ isSuccess: true;
1134
+ isFetching: false;
1135
+ error: undefined;
1136
+ } & Required<Pick<import("@reduxjs/toolkit/query").QuerySubState<import("@reduxjs/toolkit/query").QueryDefinition<{
1137
+ herdId: number;
1138
+ limit?: number;
1139
+ cursor?: FeedCursor | null;
1140
+ supabase: SupabaseClient;
1141
+ }, import("@reduxjs/toolkit/query").BaseQueryFn<any, unknown, unknown, {}, {}>, "Session" | "Event" | "Artifact", FeedInfiniteResponse, "scoutApi", unknown>> & {
1142
+ currentData?: FeedInfiniteResponse | undefined;
1143
+ isUninitialized: false;
1144
+ isLoading: false;
1145
+ isFetching: false;
1146
+ isSuccess: false;
1147
+ isError: false;
1148
+ }, "data" | "fulfilledTimeStamp" | "currentData">>) | ({
1149
+ isError: true;
1150
+ } & Required<Pick<import("@reduxjs/toolkit/query").QuerySubState<import("@reduxjs/toolkit/query").QueryDefinition<{
1151
+ herdId: number;
1152
+ limit?: number;
1153
+ cursor?: FeedCursor | null;
1154
+ supabase: SupabaseClient;
1155
+ }, import("@reduxjs/toolkit/query").BaseQueryFn<any, unknown, unknown, {}, {}>, "Session" | "Event" | "Artifact", FeedInfiniteResponse, "scoutApi", unknown>> & {
1156
+ currentData?: FeedInfiniteResponse | undefined;
1157
+ isUninitialized: false;
1158
+ isLoading: false;
1159
+ isFetching: false;
1160
+ isSuccess: false;
1161
+ isError: false;
1162
+ }, "error">>)>> & {
1163
+ status: import("@reduxjs/toolkit/query").QueryStatus;
1164
+ }) => R) | undefined;
1165
+ }) | undefined) => [R][R extends any ? 0 : never] & {
1166
+ refetch: () => import("@reduxjs/toolkit/query").QueryActionCreatorResult<import("@reduxjs/toolkit/query").QueryDefinition<{
1167
+ herdId: number;
1168
+ limit?: number;
1169
+ cursor?: FeedCursor | null;
1170
+ supabase: SupabaseClient;
1171
+ }, import("@reduxjs/toolkit/query").BaseQueryFn<any, unknown, unknown, {}, {}>, "Session" | "Event" | "Artifact", FeedInfiniteResponse, "scoutApi", unknown>>;
1172
+ }, useGetFeedInfiniteByDeviceQuery: <R extends Record<string, any> = import("@reduxjs/toolkit/query").TSHelpersId<(Omit<{
1173
+ status: import("@reduxjs/toolkit/query").QueryStatus.uninitialized;
1174
+ originalArgs?: undefined | undefined;
1175
+ data?: undefined | undefined;
1176
+ error?: undefined | undefined;
1177
+ requestId?: undefined | undefined;
1178
+ endpointName?: string | undefined;
1179
+ startedTimeStamp?: undefined | undefined;
1180
+ fulfilledTimeStamp?: undefined | undefined;
1181
+ } & {
1182
+ currentData?: FeedInfiniteResponse | undefined;
1183
+ isUninitialized: false;
1184
+ isLoading: false;
1185
+ isFetching: false;
1186
+ isSuccess: false;
1187
+ isError: false;
1188
+ }, "isUninitialized"> & {
1189
+ isUninitialized: true;
1190
+ }) | import("@reduxjs/toolkit/query").TSHelpersOverride<import("@reduxjs/toolkit/query").QuerySubState<import("@reduxjs/toolkit/query").QueryDefinition<{
1191
+ deviceId: number;
1192
+ limit?: number;
1193
+ cursor?: FeedCursor | null;
1194
+ supabase: SupabaseClient;
1195
+ }, import("@reduxjs/toolkit/query").BaseQueryFn<any, unknown, unknown, {}, {}>, "Session" | "Event" | "Artifact", FeedInfiniteResponse, "scoutApi", unknown>> & {
1196
+ currentData?: FeedInfiniteResponse | undefined;
1197
+ isUninitialized: false;
1198
+ isLoading: false;
1199
+ isFetching: false;
1200
+ isSuccess: false;
1201
+ isError: false;
1202
+ }, {
1203
+ isLoading: true;
1204
+ isFetching: boolean;
1205
+ data: undefined;
1206
+ } | ({
1207
+ isSuccess: true;
1208
+ isFetching: true;
1209
+ error: undefined;
1210
+ } & Required<Pick<import("@reduxjs/toolkit/query").QuerySubState<import("@reduxjs/toolkit/query").QueryDefinition<{
1211
+ deviceId: number;
1212
+ limit?: number;
1213
+ cursor?: FeedCursor | null;
1214
+ supabase: SupabaseClient;
1215
+ }, import("@reduxjs/toolkit/query").BaseQueryFn<any, unknown, unknown, {}, {}>, "Session" | "Event" | "Artifact", FeedInfiniteResponse, "scoutApi", unknown>> & {
1216
+ currentData?: FeedInfiniteResponse | undefined;
1217
+ isUninitialized: false;
1218
+ isLoading: false;
1219
+ isFetching: false;
1220
+ isSuccess: false;
1221
+ isError: false;
1222
+ }, "data" | "fulfilledTimeStamp">>) | ({
1223
+ isSuccess: true;
1224
+ isFetching: false;
1225
+ error: undefined;
1226
+ } & Required<Pick<import("@reduxjs/toolkit/query").QuerySubState<import("@reduxjs/toolkit/query").QueryDefinition<{
1227
+ deviceId: number;
1228
+ limit?: number;
1229
+ cursor?: FeedCursor | null;
1230
+ supabase: SupabaseClient;
1231
+ }, import("@reduxjs/toolkit/query").BaseQueryFn<any, unknown, unknown, {}, {}>, "Session" | "Event" | "Artifact", FeedInfiniteResponse, "scoutApi", unknown>> & {
1232
+ currentData?: FeedInfiniteResponse | undefined;
1233
+ isUninitialized: false;
1234
+ isLoading: false;
1235
+ isFetching: false;
1236
+ isSuccess: false;
1237
+ isError: false;
1238
+ }, "data" | "fulfilledTimeStamp" | "currentData">>) | ({
1239
+ isError: true;
1240
+ } & Required<Pick<import("@reduxjs/toolkit/query").QuerySubState<import("@reduxjs/toolkit/query").QueryDefinition<{
1241
+ deviceId: number;
1242
+ limit?: number;
1243
+ cursor?: FeedCursor | null;
1244
+ supabase: SupabaseClient;
1245
+ }, import("@reduxjs/toolkit/query").BaseQueryFn<any, unknown, unknown, {}, {}>, "Session" | "Event" | "Artifact", FeedInfiniteResponse, "scoutApi", unknown>> & {
1246
+ currentData?: FeedInfiniteResponse | undefined;
1247
+ isUninitialized: false;
1248
+ isLoading: false;
1249
+ isFetching: false;
1250
+ isSuccess: false;
1251
+ isError: false;
1252
+ }, "error">>)>> & {
1253
+ status: import("@reduxjs/toolkit/query").QueryStatus;
1254
+ }>(arg: {
1255
+ deviceId: number;
1256
+ limit?: number;
1257
+ cursor?: FeedCursor | null;
1258
+ supabase: SupabaseClient;
1259
+ } | typeof import("@reduxjs/toolkit/query").skipToken, options?: (import("@reduxjs/toolkit/query").SubscriptionOptions & {
1260
+ skip?: boolean;
1261
+ refetchOnMountOrArgChange?: boolean | number;
1262
+ } & {
1263
+ skip?: boolean;
1264
+ selectFromResult?: ((state: import("@reduxjs/toolkit/query").TSHelpersId<(Omit<{
1265
+ status: import("@reduxjs/toolkit/query").QueryStatus.uninitialized;
1266
+ originalArgs?: undefined | undefined;
1267
+ data?: undefined | undefined;
1268
+ error?: undefined | undefined;
1269
+ requestId?: undefined | undefined;
1270
+ endpointName?: string | undefined;
1271
+ startedTimeStamp?: undefined | undefined;
1272
+ fulfilledTimeStamp?: undefined | undefined;
1273
+ } & {
1274
+ currentData?: FeedInfiniteResponse | undefined;
1275
+ isUninitialized: false;
1276
+ isLoading: false;
1277
+ isFetching: false;
1278
+ isSuccess: false;
1279
+ isError: false;
1280
+ }, "isUninitialized"> & {
1281
+ isUninitialized: true;
1282
+ }) | import("@reduxjs/toolkit/query").TSHelpersOverride<import("@reduxjs/toolkit/query").QuerySubState<import("@reduxjs/toolkit/query").QueryDefinition<{
1283
+ deviceId: number;
1284
+ limit?: number;
1285
+ cursor?: FeedCursor | null;
1286
+ supabase: SupabaseClient;
1287
+ }, import("@reduxjs/toolkit/query").BaseQueryFn<any, unknown, unknown, {}, {}>, "Session" | "Event" | "Artifact", FeedInfiniteResponse, "scoutApi", unknown>> & {
1288
+ currentData?: FeedInfiniteResponse | undefined;
1289
+ isUninitialized: false;
1290
+ isLoading: false;
1291
+ isFetching: false;
1292
+ isSuccess: false;
1293
+ isError: false;
1294
+ }, {
1295
+ isLoading: true;
1296
+ isFetching: boolean;
1297
+ data: undefined;
1298
+ } | ({
1299
+ isSuccess: true;
1300
+ isFetching: true;
1301
+ error: undefined;
1302
+ } & Required<Pick<import("@reduxjs/toolkit/query").QuerySubState<import("@reduxjs/toolkit/query").QueryDefinition<{
1303
+ deviceId: number;
1304
+ limit?: number;
1305
+ cursor?: FeedCursor | null;
1306
+ supabase: SupabaseClient;
1307
+ }, import("@reduxjs/toolkit/query").BaseQueryFn<any, unknown, unknown, {}, {}>, "Session" | "Event" | "Artifact", FeedInfiniteResponse, "scoutApi", unknown>> & {
1308
+ currentData?: FeedInfiniteResponse | undefined;
1309
+ isUninitialized: false;
1310
+ isLoading: false;
1311
+ isFetching: false;
1312
+ isSuccess: false;
1313
+ isError: false;
1314
+ }, "data" | "fulfilledTimeStamp">>) | ({
1315
+ isSuccess: true;
1316
+ isFetching: false;
1317
+ error: undefined;
1318
+ } & Required<Pick<import("@reduxjs/toolkit/query").QuerySubState<import("@reduxjs/toolkit/query").QueryDefinition<{
1319
+ deviceId: number;
1320
+ limit?: number;
1321
+ cursor?: FeedCursor | null;
1322
+ supabase: SupabaseClient;
1323
+ }, import("@reduxjs/toolkit/query").BaseQueryFn<any, unknown, unknown, {}, {}>, "Session" | "Event" | "Artifact", FeedInfiniteResponse, "scoutApi", unknown>> & {
1324
+ currentData?: FeedInfiniteResponse | undefined;
1325
+ isUninitialized: false;
1326
+ isLoading: false;
1327
+ isFetching: false;
1328
+ isSuccess: false;
1329
+ isError: false;
1330
+ }, "data" | "fulfilledTimeStamp" | "currentData">>) | ({
1331
+ isError: true;
1332
+ } & Required<Pick<import("@reduxjs/toolkit/query").QuerySubState<import("@reduxjs/toolkit/query").QueryDefinition<{
1333
+ deviceId: number;
1334
+ limit?: number;
1335
+ cursor?: FeedCursor | null;
1336
+ supabase: SupabaseClient;
1337
+ }, import("@reduxjs/toolkit/query").BaseQueryFn<any, unknown, unknown, {}, {}>, "Session" | "Event" | "Artifact", FeedInfiniteResponse, "scoutApi", unknown>> & {
1338
+ currentData?: FeedInfiniteResponse | undefined;
1339
+ isUninitialized: false;
1340
+ isLoading: false;
1341
+ isFetching: false;
1342
+ isSuccess: false;
1343
+ isError: false;
1344
+ }, "error">>)>> & {
1345
+ status: import("@reduxjs/toolkit/query").QueryStatus;
1346
+ }) => R) | undefined;
1347
+ }) | undefined) => [R][R extends any ? 0 : never] & {
1348
+ refetch: () => import("@reduxjs/toolkit/query").QueryActionCreatorResult<import("@reduxjs/toolkit/query").QueryDefinition<{
1349
+ deviceId: number;
1350
+ limit?: number;
1351
+ cursor?: FeedCursor | null;
1352
+ supabase: SupabaseClient;
1353
+ }, import("@reduxjs/toolkit/query").BaseQueryFn<any, unknown, unknown, {}, {}>, "Session" | "Event" | "Artifact", FeedInfiniteResponse, "scoutApi", unknown>>;
968
1354
  };
package/dist/store/api.js CHANGED
@@ -430,7 +430,174 @@ export const scoutApi = createApi({
430
430
  ]
431
431
  : [{ type: "Artifact", id: "LIST" }],
432
432
  }),
433
+ // =====================================================
434
+ // FEED INFINITE QUERIES (merged events + artifacts)
435
+ // =====================================================
436
+ getFeedInfiniteByHerd: builder.query({
437
+ serializeQueryArgs,
438
+ async queryFn({ herdId, limit = 20, cursor, supabase }) {
439
+ try {
440
+ if (!herdId) {
441
+ return {
442
+ error: { status: "CUSTOM_ERROR", error: "Herd ID is required" },
443
+ };
444
+ }
445
+ const { data, error } = await supabase.rpc("get_feed_infinite_by_herd", {
446
+ herd_id_caller: herdId,
447
+ limit_caller: limit + 1,
448
+ cursor_timestamp: cursor?.timestamp ?? null,
449
+ cursor_id: cursor?.id ?? null,
450
+ cursor_feed_type: cursor?.feed_type ?? null,
451
+ });
452
+ if (error) {
453
+ return {
454
+ error: { status: "SUPABASE_ERROR", error: error.message },
455
+ };
456
+ }
457
+ const rows = data || [];
458
+ const hasMore = rows.length > limit;
459
+ const resultRows = hasMore ? rows.slice(0, limit) : rows;
460
+ const uniqueFilePaths = Array.from(new Set(resultRows.flatMap((row) => {
461
+ const paths = [];
462
+ if (row.event_data?.file_path)
463
+ paths.push(row.event_data.file_path);
464
+ if (row.artifact_data?.file_path)
465
+ paths.push(row.artifact_data.file_path);
466
+ return paths;
467
+ })));
468
+ let urlMap = new Map();
469
+ if (uniqueFilePaths.length > 0) {
470
+ try {
471
+ const urlResults = await generateSignedUrlsBatch(uniqueFilePaths);
472
+ urlResults.forEach((url, index) => {
473
+ if (url)
474
+ urlMap.set(uniqueFilePaths[index], url);
475
+ });
476
+ }
477
+ catch (urlError) {
478
+ console.warn("Failed to generate signed URLs for feed:", urlError);
479
+ }
480
+ }
481
+ const items = resultRows.map((row) => ({
482
+ ...row,
483
+ event_data: row.event_data
484
+ ? {
485
+ ...row.event_data,
486
+ media_url: row.event_data.file_path
487
+ ? urlMap.get(row.event_data.file_path) ?? null
488
+ : null,
489
+ }
490
+ : null,
491
+ artifact_data: row.artifact_data
492
+ ? {
493
+ ...row.artifact_data,
494
+ media_url: row.artifact_data.file_path
495
+ ? urlMap.get(row.artifact_data.file_path) ?? null
496
+ : null,
497
+ }
498
+ : null,
499
+ }));
500
+ const last = resultRows[resultRows.length - 1];
501
+ const nextCursor = hasMore && last
502
+ ? {
503
+ timestamp: last.sort_ts ?? "",
504
+ id: last.sort_id ?? 0,
505
+ feed_type: last.feed_type ?? "",
506
+ }
507
+ : null;
508
+ return {
509
+ data: { items, nextCursor, hasMore },
510
+ };
511
+ }
512
+ catch (err) {
513
+ return { error: { status: "FETCH_ERROR", error: String(err) } };
514
+ }
515
+ },
516
+ providesTags: () => [{ type: "Event", id: "LIST" }, { type: "Artifact", id: "LIST" }],
517
+ }),
518
+ getFeedInfiniteByDevice: builder.query({
519
+ serializeQueryArgs,
520
+ async queryFn({ deviceId, limit = 20, cursor, supabase }) {
521
+ try {
522
+ if (!deviceId) {
523
+ return {
524
+ error: { status: "CUSTOM_ERROR", error: "Device ID is required" },
525
+ };
526
+ }
527
+ const { data, error } = await supabase.rpc("get_feed_infinite_by_device", {
528
+ device_id_caller: deviceId,
529
+ limit_caller: limit + 1,
530
+ cursor_timestamp: cursor?.timestamp ?? null,
531
+ cursor_id: cursor?.id ?? null,
532
+ cursor_feed_type: cursor?.feed_type ?? null,
533
+ });
534
+ if (error) {
535
+ return {
536
+ error: { status: "SUPABASE_ERROR", error: error.message },
537
+ };
538
+ }
539
+ const rows = data || [];
540
+ const hasMore = rows.length > limit;
541
+ const resultRows = hasMore ? rows.slice(0, limit) : rows;
542
+ const uniqueFilePaths = Array.from(new Set(resultRows.flatMap((row) => {
543
+ const paths = [];
544
+ if (row.event_data?.file_path)
545
+ paths.push(row.event_data.file_path);
546
+ if (row.artifact_data?.file_path)
547
+ paths.push(row.artifact_data.file_path);
548
+ return paths;
549
+ })));
550
+ let urlMap = new Map();
551
+ if (uniqueFilePaths.length > 0) {
552
+ try {
553
+ const urlResults = await generateSignedUrlsBatch(uniqueFilePaths);
554
+ urlResults.forEach((url, index) => {
555
+ if (url)
556
+ urlMap.set(uniqueFilePaths[index], url);
557
+ });
558
+ }
559
+ catch (urlError) {
560
+ console.warn("Failed to generate signed URLs for feed:", urlError);
561
+ }
562
+ }
563
+ const items = resultRows.map((row) => ({
564
+ ...row,
565
+ event_data: row.event_data
566
+ ? {
567
+ ...row.event_data,
568
+ media_url: row.event_data.file_path
569
+ ? urlMap.get(row.event_data.file_path) ?? null
570
+ : null,
571
+ }
572
+ : null,
573
+ artifact_data: row.artifact_data
574
+ ? {
575
+ ...row.artifact_data,
576
+ media_url: row.artifact_data.file_path
577
+ ? urlMap.get(row.artifact_data.file_path) ?? null
578
+ : null,
579
+ }
580
+ : null,
581
+ }));
582
+ const last = resultRows[resultRows.length - 1];
583
+ const nextCursor = hasMore && last
584
+ ? {
585
+ timestamp: last.sort_ts ?? "",
586
+ id: last.sort_id ?? 0,
587
+ feed_type: last.feed_type ?? "",
588
+ }
589
+ : null;
590
+ return {
591
+ data: { items, nextCursor, hasMore },
592
+ };
593
+ }
594
+ catch (err) {
595
+ return { error: { status: "FETCH_ERROR", error: String(err) } };
596
+ }
597
+ },
598
+ providesTags: () => [{ type: "Event", id: "LIST" }, { type: "Artifact", id: "LIST" }],
599
+ }),
433
600
  }),
434
601
  });
435
602
  // Export hooks for usage in functional components
436
- export const { useGetSessionsInfiniteByHerdQuery, useGetSessionsInfiniteByDeviceQuery, useGetEventsInfiniteByHerdQuery, useGetEventsInfiniteByDeviceQuery, useGetArtifactsInfiniteByHerdQuery, useGetArtifactsInfiniteByDeviceQuery, } = scoutApi;
603
+ export const { useGetSessionsInfiniteByHerdQuery, useGetSessionsInfiniteByDeviceQuery, useGetEventsInfiniteByHerdQuery, useGetEventsInfiniteByDeviceQuery, useGetArtifactsInfiniteByHerdQuery, useGetArtifactsInfiniteByDeviceQuery, useGetFeedInfiniteByHerdQuery, useGetFeedInfiniteByDeviceQuery, } = scoutApi;
@@ -19,6 +19,18 @@ export declare const configureScoutStore: () => import("@reduxjs/toolkit").Enhan
19
19
  getArtifactsInfiniteByDevice: import("@reduxjs/toolkit/query").QueryDefinition<import("./api").InfiniteQueryArgs & {
20
20
  supabase: import("@supabase/supabase-js").SupabaseClient;
21
21
  }, import("@reduxjs/toolkit/query").BaseQueryFn<any, unknown, unknown, {}, {}>, "Session" | "Event" | "Artifact", import("./api").ArtifactsInfiniteResponse, "scoutApi", unknown>;
22
+ getFeedInfiniteByHerd: import("@reduxjs/toolkit/query").QueryDefinition<{
23
+ herdId: number;
24
+ limit?: number;
25
+ cursor?: import("./api").FeedCursor | null;
26
+ supabase: import("@supabase/supabase-js").SupabaseClient;
27
+ }, import("@reduxjs/toolkit/query").BaseQueryFn<any, unknown, unknown, {}, {}>, "Session" | "Event" | "Artifact", import("./api").FeedInfiniteResponse, "scoutApi", unknown>;
28
+ getFeedInfiniteByDevice: import("@reduxjs/toolkit/query").QueryDefinition<{
29
+ deviceId: number;
30
+ limit?: number;
31
+ cursor?: import("./api").FeedCursor | null;
32
+ supabase: import("@supabase/supabase-js").SupabaseClient;
33
+ }, import("@reduxjs/toolkit/query").BaseQueryFn<any, unknown, unknown, {}, {}>, "Session" | "Event" | "Artifact", import("./api").FeedInfiniteResponse, "scoutApi", unknown>;
22
34
  }, "Session" | "Event" | "Artifact", "scoutApi">;
23
35
  }, import("redux").UnknownAction, import("@reduxjs/toolkit").Tuple<[import("redux").StoreEnhancer<{
24
36
  dispatch: import("redux-thunk").ThunkDispatch<{
@@ -42,6 +54,18 @@ export declare const configureScoutStore: () => import("@reduxjs/toolkit").Enhan
42
54
  getArtifactsInfiniteByDevice: import("@reduxjs/toolkit/query").QueryDefinition<import("./api").InfiniteQueryArgs & {
43
55
  supabase: import("@supabase/supabase-js").SupabaseClient;
44
56
  }, import("@reduxjs/toolkit/query").BaseQueryFn<any, unknown, unknown, {}, {}>, "Session" | "Event" | "Artifact", import("./api").ArtifactsInfiniteResponse, "scoutApi", unknown>;
57
+ getFeedInfiniteByHerd: import("@reduxjs/toolkit/query").QueryDefinition<{
58
+ herdId: number;
59
+ limit?: number;
60
+ cursor?: import("./api").FeedCursor | null;
61
+ supabase: import("@supabase/supabase-js").SupabaseClient;
62
+ }, import("@reduxjs/toolkit/query").BaseQueryFn<any, unknown, unknown, {}, {}>, "Session" | "Event" | "Artifact", import("./api").FeedInfiniteResponse, "scoutApi", unknown>;
63
+ getFeedInfiniteByDevice: import("@reduxjs/toolkit/query").QueryDefinition<{
64
+ deviceId: number;
65
+ limit?: number;
66
+ cursor?: import("./api").FeedCursor | null;
67
+ supabase: import("@supabase/supabase-js").SupabaseClient;
68
+ }, import("@reduxjs/toolkit/query").BaseQueryFn<any, unknown, unknown, {}, {}>, "Session" | "Event" | "Artifact", import("./api").FeedInfiniteResponse, "scoutApi", unknown>;
45
69
  }, "Session" | "Event" | "Artifact", "scoutApi">;
46
70
  }, undefined, import("redux").UnknownAction>;
47
71
  }>, import("redux").StoreEnhancer]>>;
@@ -68,6 +92,18 @@ export declare const store: import("@reduxjs/toolkit").EnhancedStore<{
68
92
  getArtifactsInfiniteByDevice: import("@reduxjs/toolkit/query").QueryDefinition<import("./api").InfiniteQueryArgs & {
69
93
  supabase: import("@supabase/supabase-js").SupabaseClient;
70
94
  }, import("@reduxjs/toolkit/query").BaseQueryFn<any, unknown, unknown, {}, {}>, "Session" | "Event" | "Artifact", import("./api").ArtifactsInfiniteResponse, "scoutApi", unknown>;
95
+ getFeedInfiniteByHerd: import("@reduxjs/toolkit/query").QueryDefinition<{
96
+ herdId: number;
97
+ limit?: number;
98
+ cursor?: import("./api").FeedCursor | null;
99
+ supabase: import("@supabase/supabase-js").SupabaseClient;
100
+ }, import("@reduxjs/toolkit/query").BaseQueryFn<any, unknown, unknown, {}, {}>, "Session" | "Event" | "Artifact", import("./api").FeedInfiniteResponse, "scoutApi", unknown>;
101
+ getFeedInfiniteByDevice: import("@reduxjs/toolkit/query").QueryDefinition<{
102
+ deviceId: number;
103
+ limit?: number;
104
+ cursor?: import("./api").FeedCursor | null;
105
+ supabase: import("@supabase/supabase-js").SupabaseClient;
106
+ }, import("@reduxjs/toolkit/query").BaseQueryFn<any, unknown, unknown, {}, {}>, "Session" | "Event" | "Artifact", import("./api").FeedInfiniteResponse, "scoutApi", unknown>;
71
107
  }, "Session" | "Event" | "Artifact", "scoutApi">;
72
108
  }, import("redux").UnknownAction, import("@reduxjs/toolkit").Tuple<[import("redux").StoreEnhancer<{
73
109
  dispatch: import("redux-thunk").ThunkDispatch<{
@@ -91,6 +127,18 @@ export declare const store: import("@reduxjs/toolkit").EnhancedStore<{
91
127
  getArtifactsInfiniteByDevice: import("@reduxjs/toolkit/query").QueryDefinition<import("./api").InfiniteQueryArgs & {
92
128
  supabase: import("@supabase/supabase-js").SupabaseClient;
93
129
  }, import("@reduxjs/toolkit/query").BaseQueryFn<any, unknown, unknown, {}, {}>, "Session" | "Event" | "Artifact", import("./api").ArtifactsInfiniteResponse, "scoutApi", unknown>;
130
+ getFeedInfiniteByHerd: import("@reduxjs/toolkit/query").QueryDefinition<{
131
+ herdId: number;
132
+ limit?: number;
133
+ cursor?: import("./api").FeedCursor | null;
134
+ supabase: import("@supabase/supabase-js").SupabaseClient;
135
+ }, import("@reduxjs/toolkit/query").BaseQueryFn<any, unknown, unknown, {}, {}>, "Session" | "Event" | "Artifact", import("./api").FeedInfiniteResponse, "scoutApi", unknown>;
136
+ getFeedInfiniteByDevice: import("@reduxjs/toolkit/query").QueryDefinition<{
137
+ deviceId: number;
138
+ limit?: number;
139
+ cursor?: import("./api").FeedCursor | null;
140
+ supabase: import("@supabase/supabase-js").SupabaseClient;
141
+ }, import("@reduxjs/toolkit/query").BaseQueryFn<any, unknown, unknown, {}, {}>, "Session" | "Event" | "Artifact", import("./api").FeedInfiniteResponse, "scoutApi", unknown>;
94
142
  }, "Session" | "Event" | "Artifact", "scoutApi">;
95
143
  }, undefined, import("redux").UnknownAction>;
96
144
  }>, import("redux").StoreEnhancer]>>;
@@ -33,6 +33,9 @@ export type IHealthMetricSummaryRow = Database["public"]["Functions"]["get_healt
33
33
  export type IArtifactWithMediaUrl = IArtifact & {
34
34
  media_url?: string | null;
35
35
  };
36
+ export type IEventWithMediaUrl = IEvent & {
37
+ media_url?: string | null;
38
+ };
36
39
  export type IVersionsSoftwareWithBuildUrl = IVersionsSoftware & {
37
40
  build_artifact_url?: string | null;
38
41
  };
@@ -75,6 +78,16 @@ export type IDevicePrettyLocation = Database["public"]["CompositeTypes"]["device
75
78
  export type IEventAndTagsPrettyLocation = Database["public"]["CompositeTypes"]["event_and_tags_pretty_location"];
76
79
  export type IZonesAndActionsPrettyLocation = Database["public"]["CompositeTypes"]["zones_and_actions_pretty_location"];
77
80
  export type IHerdPrettyLocation = Database["public"]["CompositeTypes"]["herds_pretty_location"];
81
+ export type IFeedItemRow = Database["public"]["CompositeTypes"]["feed_item"];
82
+ export type IFeedItem = {
83
+ feed_type: string | null;
84
+ sort_ts: string | null;
85
+ sort_id: number | null;
86
+ event_data: (IEventAndTagsPrettyLocation & {
87
+ media_url?: string | null;
88
+ }) | null;
89
+ artifact_data: IArtifactWithMediaUrl | null;
90
+ };
78
91
  export type ISessionWithCoordinates = Database["public"]["CompositeTypes"]["session_with_coordinates"];
79
92
  export type IConnectivityWithCoordinates = Database["public"]["CompositeTypes"]["connectivity_with_coordinates"];
80
93
  export type IDeviceHeartbeatAnalysis = Database["public"]["CompositeTypes"]["device_heartbeat_analysis"];
@@ -974,6 +974,7 @@ export type Database = {
974
974
  conf: number;
975
975
  detector: string;
976
976
  event_id: number | null;
977
+ frame_index: number | null;
977
978
  height: number;
978
979
  id: number;
979
980
  inserted_at: string;
@@ -1000,6 +1001,7 @@ export type Database = {
1000
1001
  conf: number;
1001
1002
  detector?: string;
1002
1003
  event_id?: number | null;
1004
+ frame_index?: number | null;
1003
1005
  height?: number;
1004
1006
  id?: number;
1005
1007
  inserted_at?: string;
@@ -1026,6 +1028,7 @@ export type Database = {
1026
1028
  conf?: number;
1027
1029
  detector?: string;
1028
1030
  event_id?: number | null;
1031
+ frame_index?: number | null;
1029
1032
  height?: number;
1030
1033
  id?: number;
1031
1034
  inserted_at?: string;
@@ -1761,6 +1764,38 @@ export type Database = {
1761
1764
  isSetofReturn: true;
1762
1765
  };
1763
1766
  };
1767
+ get_feed_infinite_by_device: {
1768
+ Args: {
1769
+ cursor_feed_type?: string;
1770
+ cursor_id?: number;
1771
+ cursor_timestamp?: string;
1772
+ device_id_caller: number;
1773
+ limit_caller?: number;
1774
+ };
1775
+ Returns: Database["public"]["CompositeTypes"]["feed_item"][];
1776
+ SetofOptions: {
1777
+ from: "*";
1778
+ to: "feed_item";
1779
+ isOneToOne: false;
1780
+ isSetofReturn: true;
1781
+ };
1782
+ };
1783
+ get_feed_infinite_by_herd: {
1784
+ Args: {
1785
+ cursor_feed_type?: string;
1786
+ cursor_id?: number;
1787
+ cursor_timestamp?: string;
1788
+ herd_id_caller: number;
1789
+ limit_caller?: number;
1790
+ };
1791
+ Returns: Database["public"]["CompositeTypes"]["feed_item"][];
1792
+ SetofOptions: {
1793
+ from: "*";
1794
+ to: "feed_item";
1795
+ isOneToOne: false;
1796
+ isSetofReturn: true;
1797
+ };
1798
+ };
1764
1799
  get_health_metrics_summary: {
1765
1800
  Args: {
1766
1801
  p_device_id: number;
@@ -2133,6 +2168,13 @@ export type Database = {
2133
2168
  is_public: boolean | null;
2134
2169
  tags: Database["public"]["Tables"]["tags"]["Row"][] | null;
2135
2170
  };
2171
+ feed_item: {
2172
+ feed_type: string | null;
2173
+ sort_ts: string | null;
2174
+ sort_id: number | null;
2175
+ event_data: Database["public"]["CompositeTypes"]["event_and_tags_pretty_location"] | null;
2176
+ artifact_data: Database["public"]["Tables"]["artifacts"]["Row"] | null;
2177
+ };
2136
2178
  herds_pretty_location: {
2137
2179
  id: number | null;
2138
2180
  inserted_at: string | null;
@@ -2192,6 +2234,7 @@ export type Database = {
2192
2234
  y: number | null;
2193
2235
  class: string | null;
2194
2236
  timestamp_observation: string | null;
2237
+ frame_index: number | null;
2195
2238
  origin_location: unknown;
2196
2239
  origin_pitch: number | null;
2197
2240
  origin_heading: number | null;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adventurelabs/scout-core",
3
- "version": "1.4.18",
3
+ "version": "1.4.19",
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",