@adventurelabs/scout-core 1.5.0 → 1.5.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. package/dist/helpers/artifactMedia.d.ts +5 -0
  2. package/dist/helpers/artifactMedia.js +31 -0
  3. package/dist/helpers/artifacts.js +13 -19
  4. package/dist/helpers/documents.d.ts +1 -0
  5. package/dist/helpers/documents.js +11 -2
  6. package/dist/helpers/index.d.ts +1 -0
  7. package/dist/helpers/index.js +1 -0
  8. package/dist/helpers/operating_contexts.d.ts +43 -0
  9. package/dist/helpers/operating_contexts.js +222 -0
  10. package/dist/helpers/realtime_topic_access.d.ts +5 -0
  11. package/dist/helpers/realtime_topic_access.js +55 -0
  12. package/dist/hooks/index.d.ts +2 -1
  13. package/dist/hooks/index.js +2 -1
  14. package/dist/hooks/useAuthorizedRealtimeTopics.d.ts +1 -0
  15. package/dist/hooks/useAuthorizedRealtimeTopics.js +14 -0
  16. package/dist/hooks/useScoutRealtimeAnalysisJobs.d.ts +2 -1
  17. package/dist/hooks/useScoutRealtimeAnalysisJobs.js +3 -5
  18. package/dist/hooks/useScoutRealtimeAnalysisTasks.d.ts +2 -1
  19. package/dist/hooks/useScoutRealtimeAnalysisTasks.js +3 -5
  20. package/dist/hooks/useScoutRealtimeBroadcast.d.ts +9 -5
  21. package/dist/hooks/useScoutRealtimeBroadcast.js +118 -25
  22. package/dist/hooks/useScoutRealtimeConnectivity.d.ts +2 -1
  23. package/dist/hooks/useScoutRealtimeConnectivity.js +18 -76
  24. package/dist/hooks/useScoutRealtimeContacts.d.ts +2 -1
  25. package/dist/hooks/useScoutRealtimeContacts.js +3 -3
  26. package/dist/hooks/useScoutRealtimeDevices.d.ts +2 -1
  27. package/dist/hooks/useScoutRealtimeDevices.js +3 -64
  28. package/dist/hooks/useScoutRealtimeDocuments.d.ts +3 -3
  29. package/dist/hooks/useScoutRealtimeDocuments.js +7 -5
  30. package/dist/hooks/useScoutRealtimeEvents.d.ts +2 -1
  31. package/dist/hooks/useScoutRealtimeEvents.js +3 -69
  32. package/dist/hooks/useScoutRealtimeMaintenanceRequests.d.ts +2 -1
  33. package/dist/hooks/useScoutRealtimeMaintenanceRequests.js +3 -3
  34. package/dist/hooks/useScoutRealtimeOperatingContexts.d.ts +12 -0
  35. package/dist/hooks/useScoutRealtimeOperatingContexts.js +26 -0
  36. package/dist/hooks/useScoutRealtimeParts.d.ts +2 -1
  37. package/dist/hooks/useScoutRealtimeParts.js +3 -3
  38. package/dist/hooks/useScoutRealtimePins.d.ts +2 -1
  39. package/dist/hooks/useScoutRealtimePins.js +3 -69
  40. package/dist/hooks/useScoutRealtimePlans.d.ts +2 -1
  41. package/dist/hooks/useScoutRealtimePlans.js +3 -3
  42. package/dist/hooks/useScoutRealtimeSessionIncidents.d.ts +2 -1
  43. package/dist/hooks/useScoutRealtimeSessionIncidents.js +3 -3
  44. package/dist/hooks/useScoutRealtimeSessions.d.ts +2 -1
  45. package/dist/hooks/useScoutRealtimeSessions.js +3 -69
  46. package/dist/hooks/useScoutRealtimeTags.d.ts +2 -1
  47. package/dist/hooks/useScoutRealtimeTags.js +3 -69
  48. package/dist/hooks/useScoutRealtimeVersionsSoftware.d.ts +2 -1
  49. package/dist/hooks/useScoutRealtimeVersionsSoftware.js +3 -5
  50. package/dist/index.d.ts +2 -0
  51. package/dist/index.js +2 -0
  52. package/dist/providers/ScoutRefreshProvider.d.ts +1 -0
  53. package/dist/providers/ScoutRefreshProvider.js +3 -0
  54. package/dist/store/api.js +14 -34
  55. package/dist/types/db.d.ts +85 -0
  56. package/dist/types/realtime.d.ts +1 -0
  57. package/dist/types/supabase.d.ts +967 -100
  58. package/dist/types/supabase.js +26 -1
  59. package/package.json +1 -1
@@ -1,73 +1,7 @@
1
1
  "use client";
2
2
  import { useSelector } from "react-redux";
3
- import { useEffect, useRef, useCallback, useState } from "react";
4
- import { EnumRealtimeOperation } from "../types/realtime";
5
- export function useScoutRealtimePins(scoutSupabase) {
6
- const channels = useRef([]);
7
- const [latestPinUpdate, setLatestPinUpdate] = useState(null);
3
+ import { useScoutRealtimeBroadcast, } from "./useScoutRealtimeBroadcast";
4
+ export function useScoutRealtimePins(scoutSupabase, options) {
8
5
  const activeHerdId = useSelector((state) => state.scout.active_herd_id);
9
- // Pin broadcast handler - just pass data, don't mutate state
10
- const handlePinBroadcast = useCallback((payload) => {
11
- console.log("[Pins] Broadcast received:", payload.payload.operation);
12
- const data = payload.payload;
13
- const pinData = data.record || data.old_record;
14
- if (!pinData)
15
- return;
16
- let operation;
17
- switch (data.operation) {
18
- case "INSERT":
19
- operation = EnumRealtimeOperation.INSERT;
20
- console.log("[Pins] New pin received:", data.record);
21
- break;
22
- case "UPDATE":
23
- operation = EnumRealtimeOperation.UPDATE;
24
- console.log("[Pins] Pin updated:", data.record);
25
- break;
26
- case "DELETE":
27
- operation = EnumRealtimeOperation.DELETE;
28
- console.log("[Pins] Pin deleted:", data.old_record);
29
- break;
30
- default:
31
- return;
32
- }
33
- const realtimeData = {
34
- data: pinData,
35
- operation,
36
- };
37
- console.log(`[scout-core realtime] PIN ${data.operation} received for pin "${pinData.name}" (${pinData.id}):`, JSON.stringify(realtimeData));
38
- setLatestPinUpdate(realtimeData);
39
- }, []);
40
- // Clear latest update
41
- const clearLatestUpdate = useCallback(() => {
42
- setLatestPinUpdate(null);
43
- }, []);
44
- const cleanupChannels = () => {
45
- channels.current.forEach((channel) => scoutSupabase.removeChannel(channel));
46
- channels.current = [];
47
- };
48
- const createPinsChannel = (herdId) => {
49
- return scoutSupabase
50
- .channel(`${herdId}-pins`, { config: { private: true } })
51
- .on("broadcast", { event: "*" }, handlePinBroadcast)
52
- .subscribe((status) => {
53
- if (status === "SUBSCRIBED") {
54
- console.log(`[Pins] ✅ Connected to herd ${herdId} pins broadcasts`);
55
- }
56
- else if (status === "CHANNEL_ERROR") {
57
- console.warn(`[Pins] 🟡 Failed to connect to herd ${herdId} pins broadcasts`);
58
- }
59
- });
60
- };
61
- useEffect(() => {
62
- cleanupChannels();
63
- // Clear previous update when switching herds
64
- clearLatestUpdate();
65
- // Create pins channel for active herd
66
- if (activeHerdId) {
67
- const channel = createPinsChannel(activeHerdId);
68
- channels.current.push(channel);
69
- }
70
- return cleanupChannels;
71
- }, [activeHerdId, clearLatestUpdate]);
72
- return [latestPinUpdate, clearLatestUpdate];
6
+ return useScoutRealtimeBroadcast(scoutSupabase, activeHerdId ? [`${activeHerdId}-pins`] : [], options);
73
7
  }
@@ -2,4 +2,5 @@ import { SupabaseClient } from "@supabase/supabase-js";
2
2
  import { Database } from "../types/supabase";
3
3
  import { IPlan } from "../types/db";
4
4
  import { RealtimeData } from "../types/realtime";
5
- export declare function useScoutRealtimePlans(scoutSupabase: SupabaseClient<Database>): [RealtimeData<IPlan> | null, () => void];
5
+ import { ScoutRealtimeBroadcastOptions } from "./useScoutRealtimeBroadcast";
6
+ export declare function useScoutRealtimePlans(scoutSupabase: SupabaseClient<Database>, options?: ScoutRealtimeBroadcastOptions): [RealtimeData<IPlan> | 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 useScoutRealtimePlans(scoutSupabase) {
3
+ import { useScoutRealtimeBroadcast, } from "./useScoutRealtimeBroadcast";
4
+ export function useScoutRealtimePlans(scoutSupabase, options) {
5
5
  const activeHerdId = useSelector((state) => state.scout.active_herd_id);
6
- return useScoutRealtimeBroadcast(scoutSupabase, activeHerdId ? [`${activeHerdId}-plans`] : []);
6
+ return useScoutRealtimeBroadcast(scoutSupabase, activeHerdId ? [`${activeHerdId}-plans`] : [], options);
7
7
  }
@@ -2,4 +2,5 @@ import { SupabaseClient } from "@supabase/supabase-js";
2
2
  import { Database } from "../types/supabase";
3
3
  import { ISessionIncident } from "../types/db";
4
4
  import { RealtimeData } from "../types/realtime";
5
- export declare function useScoutRealtimeSessionIncidents(scoutSupabase: SupabaseClient<Database>): [RealtimeData<ISessionIncident> | null, () => void];
5
+ import { ScoutRealtimeBroadcastOptions } from "./useScoutRealtimeBroadcast";
6
+ export declare function useScoutRealtimeSessionIncidents(scoutSupabase: SupabaseClient<Database>, options?: ScoutRealtimeBroadcastOptions): [RealtimeData<ISessionIncident> | 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 useScoutRealtimeSessionIncidents(scoutSupabase) {
3
+ import { useScoutRealtimeBroadcast, } from "./useScoutRealtimeBroadcast";
4
+ export function useScoutRealtimeSessionIncidents(scoutSupabase, options) {
5
5
  const activeHerdId = useSelector((state) => state.scout.active_herd_id);
6
- return useScoutRealtimeBroadcast(scoutSupabase, activeHerdId ? [`${activeHerdId}-session_incidents`] : []);
6
+ return useScoutRealtimeBroadcast(scoutSupabase, activeHerdId ? [`${activeHerdId}-session_incidents`] : [], options);
7
7
  }
@@ -2,4 +2,5 @@ import { SupabaseClient } from "@supabase/supabase-js";
2
2
  import { Database } from "../types/supabase";
3
3
  import { ISessionWithCoordinates } from "../types/db";
4
4
  import { RealtimeData } from "../types/realtime";
5
- export declare function useScoutRealtimeSessions(scoutSupabase: SupabaseClient<Database>): [RealtimeData<ISessionWithCoordinates> | null, () => void];
5
+ import { ScoutRealtimeBroadcastOptions } from "./useScoutRealtimeBroadcast";
6
+ export declare function useScoutRealtimeSessions(scoutSupabase: SupabaseClient<Database>, options?: ScoutRealtimeBroadcastOptions): [RealtimeData<ISessionWithCoordinates> | null, () => void];
@@ -1,73 +1,7 @@
1
1
  "use client";
2
2
  import { useSelector } from "react-redux";
3
- import { useEffect, useRef, useCallback, useState } from "react";
4
- import { EnumRealtimeOperation } from "../types/realtime";
5
- export function useScoutRealtimeSessions(scoutSupabase) {
6
- const channels = useRef([]);
7
- const [latestSessionUpdate, setLatestSessionUpdate] = useState(null);
3
+ import { useScoutRealtimeBroadcast, } from "./useScoutRealtimeBroadcast";
4
+ export function useScoutRealtimeSessions(scoutSupabase, options) {
8
5
  const activeHerdId = useSelector((state) => state.scout.active_herd_id);
9
- // Session broadcast handler - just pass data, don't mutate state
10
- const handleSessionBroadcast = useCallback((payload) => {
11
- console.log("[Sessions] Broadcast received:", payload.payload.operation);
12
- const data = payload.payload;
13
- const sessionData = data.record || data.old_record;
14
- if (!sessionData)
15
- return;
16
- let operation;
17
- switch (data.operation) {
18
- case "INSERT":
19
- operation = EnumRealtimeOperation.INSERT;
20
- console.log("[Sessions] New session received:", data.record);
21
- break;
22
- case "UPDATE":
23
- operation = EnumRealtimeOperation.UPDATE;
24
- console.log("[Sessions] Session updated:", data.record);
25
- break;
26
- case "DELETE":
27
- operation = EnumRealtimeOperation.DELETE;
28
- console.log("[Sessions] Session deleted:", data.old_record);
29
- break;
30
- default:
31
- return;
32
- }
33
- const realtimeData = {
34
- data: sessionData,
35
- operation,
36
- };
37
- console.log(`[scout-core realtime] SESSION ${data.operation} received:`, JSON.stringify(realtimeData));
38
- setLatestSessionUpdate(realtimeData);
39
- }, []);
40
- // Clear latest update
41
- const clearLatestUpdate = useCallback(() => {
42
- setLatestSessionUpdate(null);
43
- }, []);
44
- const cleanupChannels = () => {
45
- channels.current.forEach((channel) => scoutSupabase.removeChannel(channel));
46
- channels.current = [];
47
- };
48
- const createSessionsChannel = (herdId) => {
49
- return scoutSupabase
50
- .channel(`${herdId}-sessions`, { config: { private: true } })
51
- .on("broadcast", { event: "*" }, handleSessionBroadcast)
52
- .subscribe((status) => {
53
- if (status === "SUBSCRIBED") {
54
- console.log(`[Sessions] ✅ Connected to herd ${herdId}`);
55
- }
56
- else if (status === "CHANNEL_ERROR") {
57
- console.warn(`[Sessions] 🟡 Failed to connect to herd ${herdId}`);
58
- }
59
- });
60
- };
61
- useEffect(() => {
62
- cleanupChannels();
63
- // Clear previous update when switching herds
64
- clearLatestUpdate();
65
- // Create sessions channel for active herd
66
- if (activeHerdId) {
67
- const channel = createSessionsChannel(activeHerdId);
68
- channels.current.push(channel);
69
- }
70
- return cleanupChannels;
71
- }, [activeHerdId, clearLatestUpdate]);
72
- return [latestSessionUpdate, clearLatestUpdate];
6
+ return useScoutRealtimeBroadcast(scoutSupabase, activeHerdId ? [`${activeHerdId}-sessions`] : [], options);
73
7
  }
@@ -2,4 +2,5 @@ import { SupabaseClient } from "@supabase/supabase-js";
2
2
  import { Database } from "../types/supabase";
3
3
  import { ITagPrettyLocation } from "../types/db";
4
4
  import { RealtimeData } from "../types/realtime";
5
- export declare function useScoutRealtimeTags(scoutSupabase: SupabaseClient<Database>): [RealtimeData<ITagPrettyLocation> | null, () => void];
5
+ import { ScoutRealtimeBroadcastOptions } from "./useScoutRealtimeBroadcast";
6
+ export declare function useScoutRealtimeTags(scoutSupabase: SupabaseClient<Database>, options?: ScoutRealtimeBroadcastOptions): [RealtimeData<ITagPrettyLocation> | null, () => void];
@@ -1,73 +1,7 @@
1
1
  "use client";
2
2
  import { useSelector } from "react-redux";
3
- import { useEffect, useRef, useCallback, useState } from "react";
4
- import { EnumRealtimeOperation } from "../types/realtime";
5
- export function useScoutRealtimeTags(scoutSupabase) {
6
- const channels = useRef([]);
7
- const [latestTagUpdate, setLatestTagUpdate] = useState(null);
3
+ import { useScoutRealtimeBroadcast, } from "./useScoutRealtimeBroadcast";
4
+ export function useScoutRealtimeTags(scoutSupabase, options) {
8
5
  const activeHerdId = useSelector((state) => state.scout.active_herd_id);
9
- // Tag broadcast handler - just pass data, don't mutate state
10
- const handleTagBroadcast = useCallback((payload) => {
11
- console.log("[Tags] Broadcast received:", payload.payload.operation);
12
- const data = payload.payload;
13
- const tagData = data.record || data.old_record;
14
- if (!tagData)
15
- return;
16
- let operation;
17
- switch (data.operation) {
18
- case "INSERT":
19
- operation = EnumRealtimeOperation.INSERT;
20
- console.log("[Tags] New tag received:", data.record);
21
- break;
22
- case "UPDATE":
23
- operation = EnumRealtimeOperation.UPDATE;
24
- console.log("[Tags] Tag updated:", data.record);
25
- break;
26
- case "DELETE":
27
- operation = EnumRealtimeOperation.DELETE;
28
- console.log("[Tags] Tag deleted:", data.old_record);
29
- break;
30
- default:
31
- return;
32
- }
33
- const realtimeData = {
34
- data: tagData,
35
- operation,
36
- };
37
- console.log(`[scout-core realtime] TAG ${data.operation} received:`, JSON.stringify(realtimeData));
38
- setLatestTagUpdate(realtimeData);
39
- }, []);
40
- // Clear latest update
41
- const clearLatestUpdate = useCallback(() => {
42
- setLatestTagUpdate(null);
43
- }, []);
44
- const cleanupChannels = () => {
45
- channels.current.forEach((channel) => scoutSupabase.removeChannel(channel));
46
- channels.current = [];
47
- };
48
- const createTagsChannel = (herdId) => {
49
- return scoutSupabase
50
- .channel(`${herdId}-tags`, { config: { private: true } })
51
- .on("broadcast", { event: "*" }, handleTagBroadcast)
52
- .subscribe((status) => {
53
- if (status === "SUBSCRIBED") {
54
- console.log(`[Tags] ✅ Connected to herd ${herdId}`);
55
- }
56
- else if (status === "CHANNEL_ERROR") {
57
- console.warn(`[Tags] 🟡 Failed to connect to herd ${herdId}`);
58
- }
59
- });
60
- };
61
- useEffect(() => {
62
- cleanupChannels();
63
- // Clear previous update when switching herds
64
- clearLatestUpdate();
65
- // Create tags channel for active herd
66
- if (activeHerdId) {
67
- const channel = createTagsChannel(activeHerdId);
68
- channels.current.push(channel);
69
- }
70
- return cleanupChannels;
71
- }, [activeHerdId, clearLatestUpdate]);
72
- return [latestTagUpdate, clearLatestUpdate];
6
+ return useScoutRealtimeBroadcast(scoutSupabase, activeHerdId ? [`${activeHerdId}-tags`] : [], options);
73
7
  }
@@ -2,4 +2,5 @@ import { SupabaseClient } from "@supabase/supabase-js";
2
2
  import { Database } from "../types/supabase";
3
3
  import { IVersionsSoftware } from "../types/db";
4
4
  import { RealtimeData } from "../types/realtime";
5
- export declare function useScoutRealtimeVersionsSoftware(scoutSupabase: SupabaseClient<Database>): [RealtimeData<IVersionsSoftware> | null, () => void];
5
+ import { ScoutRealtimeBroadcastOptions } from "./useScoutRealtimeBroadcast";
6
+ export declare function useScoutRealtimeVersionsSoftware(scoutSupabase: SupabaseClient<Database>, options?: ScoutRealtimeBroadcastOptions): [RealtimeData<IVersionsSoftware> | null, () => void];
@@ -1,7 +1,5 @@
1
1
  "use client";
2
- import { useScoutRealtimeBroadcast } from "./useScoutRealtimeBroadcast";
3
- export function useScoutRealtimeVersionsSoftware(scoutSupabase) {
4
- return useScoutRealtimeBroadcast(scoutSupabase, [
5
- "versions_software_changes",
6
- ]);
2
+ import { useScoutRealtimeBroadcast, } from "./useScoutRealtimeBroadcast";
3
+ export function useScoutRealtimeVersionsSoftware(scoutSupabase, options) {
4
+ return useScoutRealtimeBroadcast(scoutSupabase, ["versions_software_changes"], options);
7
5
  }
package/dist/index.d.ts CHANGED
@@ -72,6 +72,7 @@ export * from "./helpers/documents";
72
72
  export * from "./helpers/maintenance_requests";
73
73
  export * from "./helpers/session_incidents";
74
74
  export * from "./helpers/contacts";
75
+ export * from "./helpers/operating_contexts";
75
76
  export * from "./helpers/lifecycle";
76
77
  export * from "./helpers/storagePath";
77
78
  export * from "./hooks/useScoutRealtimeBroadcast";
@@ -90,6 +91,7 @@ export * from "./hooks/useScoutRealtimeDocuments";
90
91
  export * from "./hooks/useScoutRealtimeMaintenanceRequests";
91
92
  export * from "./hooks/useScoutRealtimeContacts";
92
93
  export * from "./hooks/useScoutRealtimeSessionIncidents";
94
+ export * from "./hooks/useScoutRealtimeOperatingContexts";
93
95
  export * from "./hooks/useScoutRefresh";
94
96
  export * from "./hooks/useInfiniteQuery";
95
97
  export * from "./providers";
package/dist/index.js CHANGED
@@ -75,6 +75,7 @@ export * from "./helpers/documents";
75
75
  export * from "./helpers/maintenance_requests";
76
76
  export * from "./helpers/session_incidents";
77
77
  export * from "./helpers/contacts";
78
+ export * from "./helpers/operating_contexts";
78
79
  export * from "./helpers/lifecycle";
79
80
  export * from "./helpers/storagePath";
80
81
  // Hooks
@@ -94,6 +95,7 @@ export * from "./hooks/useScoutRealtimeDocuments";
94
95
  export * from "./hooks/useScoutRealtimeMaintenanceRequests";
95
96
  export * from "./hooks/useScoutRealtimeContacts";
96
97
  export * from "./hooks/useScoutRealtimeSessionIncidents";
98
+ export * from "./hooks/useScoutRealtimeOperatingContexts";
97
99
  export * from "./hooks/useScoutRefresh";
98
100
  export * from "./hooks/useInfiniteQuery";
99
101
  // Providers
@@ -27,6 +27,7 @@ export interface PubsubTokenMintState {
27
27
  }
28
28
  export declare function useSupabase(): SupabaseClient<Database>;
29
29
  export declare function useClientAbilitiesMint(): ClientAbilitiesMintState;
30
+ export declare function useOptionalClientAbilitiesMint(): ClientAbilitiesMintState | null;
30
31
  export declare function usePubsubTokenMint(): PubsubTokenMintState;
31
32
  export interface ScoutRefreshProviderProps extends UseScoutRefreshOptions {
32
33
  children: ReactNode;
@@ -32,6 +32,9 @@ export function useSupabase() {
32
32
  export function useClientAbilitiesMint() {
33
33
  return useScoutRefreshContext().abilities;
34
34
  }
35
+ export function useOptionalClientAbilitiesMint() {
36
+ return useContext(ScoutRefreshContext)?.abilities ?? null;
37
+ }
35
38
  export function usePubsubTokenMint() {
36
39
  return useScoutRefreshContext().pubsub;
37
40
  }
package/dist/store/api.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import { createApi, fakeBaseQuery } from "@reduxjs/toolkit/query/react";
2
2
  import { generateSignedUrlsBatch, } from "../helpers/storage";
3
+ import { collectArtifactStoragePaths, withArtifactMediaUrls, } from "../helpers/artifactMedia";
3
4
  import { isNonEmptyStorageFilePath } from "../helpers/storagePath";
4
5
  async function signedUrlMapForFeedRows(rows) {
5
6
  const seen = new Set();
@@ -10,10 +11,13 @@ async function signedUrlMapForFeedRows(rows) {
10
11
  seen.add(ep);
11
12
  paths.push(ep);
12
13
  }
13
- const ap = row.artifact_data?.file_path;
14
- if (isNonEmptyStorageFilePath(ap) && !seen.has(ap)) {
15
- seen.add(ap);
16
- paths.push(ap);
14
+ if (row.artifact_data) {
15
+ for (const path of collectArtifactStoragePaths([row.artifact_data])) {
16
+ if (!seen.has(path)) {
17
+ seen.add(path);
18
+ paths.push(path);
19
+ }
20
+ }
17
21
  }
18
22
  }
19
23
  const map = new Map();
@@ -345,9 +349,7 @@ export const scoutApi = createApi({
345
349
  ? artifacts.slice(0, limit)
346
350
  : artifacts;
347
351
  // Generate signed URLs for artifacts
348
- const uniqueFilePaths = Array.from(new Set(resultArtifacts
349
- .map((artifact) => artifact.file_path)
350
- .filter(isNonEmptyStorageFilePath)));
352
+ const uniqueFilePaths = collectArtifactStoragePaths(resultArtifacts);
351
353
  let urlMap = new Map();
352
354
  if (uniqueFilePaths.length > 0) {
353
355
  try {
@@ -362,12 +364,7 @@ export const scoutApi = createApi({
362
364
  console.warn("Failed to generate signed URLs for artifacts:", urlError);
363
365
  }
364
366
  }
365
- const artifactsWithUrls = resultArtifacts.map((artifact) => ({
366
- ...artifact,
367
- media_url: isNonEmptyStorageFilePath(artifact.file_path)
368
- ? urlMap.get(artifact.file_path) ?? null
369
- : null,
370
- }));
367
+ const artifactsWithUrls = resultArtifacts.map((artifact) => withArtifactMediaUrls(artifact, urlMap));
371
368
  const nextCursor = hasMore && resultArtifacts.length > 0
372
369
  ? {
373
370
  timestamp: resultArtifacts[resultArtifacts.length - 1].created_at,
@@ -424,9 +421,7 @@ export const scoutApi = createApi({
424
421
  ? artifacts.slice(0, limit)
425
422
  : artifacts;
426
423
  // Generate signed URLs for artifacts
427
- const uniqueFilePaths = Array.from(new Set(resultArtifacts
428
- .map((artifact) => artifact.file_path)
429
- .filter(isNonEmptyStorageFilePath)));
424
+ const uniqueFilePaths = collectArtifactStoragePaths(resultArtifacts);
430
425
  let urlMap = new Map();
431
426
  if (uniqueFilePaths.length > 0) {
432
427
  try {
@@ -441,12 +436,7 @@ export const scoutApi = createApi({
441
436
  console.warn("Failed to generate signed URLs for artifacts:", urlError);
442
437
  }
443
438
  }
444
- const artifactsWithUrls = resultArtifacts.map((artifact) => ({
445
- ...artifact,
446
- media_url: isNonEmptyStorageFilePath(artifact.file_path)
447
- ? urlMap.get(artifact.file_path) ?? null
448
- : null,
449
- }));
439
+ const artifactsWithUrls = resultArtifacts.map((artifact) => withArtifactMediaUrls(artifact, urlMap));
450
440
  const nextCursor = hasMore && resultArtifacts.length > 0
451
441
  ? {
452
442
  timestamp: resultArtifacts[resultArtifacts.length - 1].created_at,
@@ -523,12 +513,7 @@ export const scoutApi = createApi({
523
513
  }
524
514
  : null,
525
515
  artifact_data: row.artifact_data
526
- ? {
527
- ...row.artifact_data,
528
- media_url: isNonEmptyStorageFilePath(row.artifact_data.file_path)
529
- ? urlMap.get(row.artifact_data.file_path) ?? null
530
- : null,
531
- }
516
+ ? withArtifactMediaUrls(row.artifact_data, urlMap)
532
517
  : null,
533
518
  }));
534
519
  const last = resultRows[resultRows.length - 1];
@@ -598,12 +583,7 @@ export const scoutApi = createApi({
598
583
  }
599
584
  : null,
600
585
  artifact_data: row.artifact_data
601
- ? {
602
- ...row.artifact_data,
603
- media_url: isNonEmptyStorageFilePath(row.artifact_data.file_path)
604
- ? urlMap.get(row.artifact_data.file_path) ?? null
605
- : null,
606
- }
586
+ ? withArtifactMediaUrls(row.artifact_data, urlMap)
607
587
  : null,
608
588
  }));
609
589
  const last = resultRows[resultRows.length - 1];
@@ -6,6 +6,7 @@ export type MediaType = Database["public"]["Enums"]["media_type"];
6
6
  export type TagObservationType = Database["public"]["Enums"]["tag_observation_type"];
7
7
  export type AnalysisWorkStatus = Database["public"]["Enums"]["analysis_work_status"];
8
8
  export type EntityLifecycle = Database["public"]["Enums"]["entity_lifecycle"];
9
+ export type DocumentEntity = Database["public"]["Enums"]["document_entity"];
9
10
  /** Supabase Auth user (`auth.getUser()`); not `public.users`. */
10
11
  export type IUser = User;
11
12
  /** Full `public.users` profile row (generated from DB). */
@@ -71,6 +72,66 @@ export type IMaintenanceRequest = Database["public"]["Tables"]["maintenance_requ
71
72
  export type ISessionIncident = Database["public"]["Tables"]["session_incidents"]["Row"];
72
73
  export type SessionIncidentType = Database["public"]["Enums"]["session_incident_type"];
73
74
  export type IContact = Database["public"]["Tables"]["contacts"]["Row"];
75
+ export type IDocumentCondition = Database["public"]["Tables"]["document_conditions"]["Row"];
76
+ export type IOperatingContextType = Database["public"]["Tables"]["operating_context_types"]["Row"];
77
+ export type IOperatingContextRole = Database["public"]["Tables"]["operating_context_roles"]["Row"];
78
+ export type IOperatingContextEquipmentCategory = Database["public"]["Tables"]["operating_context_equipment_categories"]["Row"];
79
+ export type IOperatingContextEquipmentItem = Database["public"]["Tables"]["operating_context_equipment_items"]["Row"];
80
+ export type IOperatingContext = Database["public"]["Tables"]["operating_contexts"]["Row"];
81
+ export type IOperatingContextPayload = Database["public"]["Tables"]["operating_context_payloads"]["Row"];
82
+ export type IOperatingContextRoleAssignment = Database["public"]["Tables"]["operating_context_role_assignments"]["Row"];
83
+ export type IOperatingContextEquipmentRequirement = Database["public"]["Tables"]["operating_context_equipment_requirements"]["Row"];
84
+ export type IOperatingContextRegion = Database["public"]["Tables"]["operating_context_regions"]["Row"];
85
+ export type IOperatingContextRisk = Database["public"]["Tables"]["operating_context_risks"]["Row"];
86
+ export type IOperatingContextWeatherSnapshot = Database["public"]["Tables"]["operating_context_weather_snapshots"]["Row"];
87
+ export type OperatingContextPayloadType = Database["public"]["Enums"]["operating_context_payload_type"];
88
+ export type OperatingContextRiskProbability = Database["public"]["Enums"]["operating_context_risk_probability"];
89
+ export type OperatingContextRiskSeverity = Database["public"]["Enums"]["operating_context_risk_severity"];
90
+ export interface OperatingContextListOptions {
91
+ include_inactive?: boolean;
92
+ limit?: number;
93
+ after_id?: number;
94
+ }
95
+ export interface GeographyPoint {
96
+ type: "Point";
97
+ coordinates: [number, number];
98
+ }
99
+ export interface GeographyPolygon {
100
+ type: "Polygon";
101
+ coordinates: number[][][];
102
+ }
103
+ export interface LifecyclePatch {
104
+ lifecycle?: EntityLifecycle;
105
+ lifecycle_reason?: string | null;
106
+ }
107
+ export type DocumentConditionCreateInput = Pick<DocumentConditionInsert, "localization_id" | "condition_text" | "requirement_text">;
108
+ export type DocumentConditionUpdateInput = Partial<DocumentConditionCreateInput> & LifecyclePatch;
109
+ export type OperatingContextTypeCreateInput = Pick<OperatingContextTypeInsert, "localization_id" | "name">;
110
+ export type OperatingContextTypeUpdateInput = Partial<OperatingContextTypeCreateInput> & LifecyclePatch;
111
+ export type OperatingContextRoleCreateInput = Pick<OperatingContextRoleInsert, "localization_id" | "name">;
112
+ export type OperatingContextRoleUpdateInput = Partial<OperatingContextRoleCreateInput> & LifecyclePatch;
113
+ export type OperatingContextEquipmentCategoryCreateInput = Pick<OperatingContextEquipmentCategoryInsert, "localization_id" | "name">;
114
+ export type OperatingContextEquipmentCategoryUpdateInput = Partial<OperatingContextEquipmentCategoryCreateInput> & LifecyclePatch;
115
+ export type OperatingContextEquipmentItemCreateInput = Pick<OperatingContextEquipmentItemInsert, "equipment_category_id" | "name">;
116
+ export type OperatingContextEquipmentItemUpdateInput = Partial<OperatingContextEquipmentItemCreateInput> & LifecyclePatch;
117
+ export type OperatingContextCreateInput = Pick<OperatingContextInsert, "herd_id" | "operating_context_type_id" | "name" | "description" | "valid_from" | "valid_to" | "distance_max_from_home" | "altitude_agl_max" | "involves_third_party_land">;
118
+ export type OperatingContextUpdateInput = Partial<Omit<OperatingContextCreateInput, "herd_id">> & LifecyclePatch;
119
+ export type OperatingContextPayloadCreateInput = Pick<OperatingContextPayloadInsert, "operating_context_id" | "payload_type" | "weight_kg" | "description">;
120
+ export type OperatingContextPayloadUpdateInput = Partial<Omit<OperatingContextPayloadCreateInput, "operating_context_id">> & LifecyclePatch;
121
+ export type OperatingContextRoleAssignmentCreateInput = Pick<OperatingContextRoleAssignmentInsert, "operating_context_id" | "membership_id" | "role_id" | "herd_id">;
122
+ export type OperatingContextRoleAssignmentUpdateInput = Partial<Pick<OperatingContextRoleAssignmentCreateInput, "membership_id" | "role_id">> & LifecyclePatch;
123
+ export type OperatingContextEquipmentRequirementCreateInput = Pick<OperatingContextEquipmentRequirementInsert, "operating_context_id" | "equipment_item_id">;
124
+ export type OperatingContextEquipmentRequirementUpdateInput = Partial<Pick<OperatingContextEquipmentRequirementCreateInput, "equipment_item_id">> & LifecyclePatch;
125
+ export interface OperatingContextRegionCreateInput {
126
+ operating_context_id: number;
127
+ is_exclusion: boolean;
128
+ region: GeographyPolygon | string;
129
+ name?: string | null;
130
+ weather_origin?: GeographyPoint | string | null;
131
+ }
132
+ export type OperatingContextRegionUpdateInput = Partial<Omit<OperatingContextRegionCreateInput, "operating_context_id">> & LifecyclePatch;
133
+ export type OperatingContextRiskCreateInput = Pick<OperatingContextRiskInsert, "operating_context_id" | "severity_before" | "probability_before" | "hazard" | "mitigation" | "severity_after" | "probability_after">;
134
+ export type OperatingContextRiskUpdateInput = Partial<Omit<OperatingContextRiskCreateInput, "operating_context_id">> & LifecyclePatch;
74
135
  /** A part with its resolved product (parts.product_number -> product_numbers -> products). */
75
136
  export type IPartWithProduct = IPart & {
76
137
  product?: IProduct | null;
@@ -88,6 +149,8 @@ export type IAnalysisJob = Database["public"]["Tables"]["analysis_jobs"]["Row"];
88
149
  export type IAnalysisTask = Database["public"]["Tables"]["analysis_tasks"]["Row"];
89
150
  export type IArtifactWithMediaUrl = IArtifact & {
90
151
  media_url?: string | null;
152
+ thumbnail_url?: string | null;
153
+ proxy_url?: string | null;
91
154
  };
92
155
  export type IEventWithMediaUrl = IEvent & {
93
156
  media_url?: string | null;
@@ -146,6 +209,28 @@ export type SessionIncidentInsert = Database["public"]["Tables"]["session_incide
146
209
  export type SessionIncidentUpdate = Database["public"]["Tables"]["session_incidents"]["Update"];
147
210
  export type ContactInsert = Database["public"]["Tables"]["contacts"]["Insert"];
148
211
  export type ContactUpdate = Database["public"]["Tables"]["contacts"]["Update"];
212
+ export type DocumentConditionInsert = Database["public"]["Tables"]["document_conditions"]["Insert"];
213
+ export type DocumentConditionUpdate = Database["public"]["Tables"]["document_conditions"]["Update"];
214
+ export type OperatingContextTypeInsert = Database["public"]["Tables"]["operating_context_types"]["Insert"];
215
+ export type OperatingContextTypeUpdate = Database["public"]["Tables"]["operating_context_types"]["Update"];
216
+ export type OperatingContextRoleInsert = Database["public"]["Tables"]["operating_context_roles"]["Insert"];
217
+ export type OperatingContextRoleUpdate = Database["public"]["Tables"]["operating_context_roles"]["Update"];
218
+ export type OperatingContextEquipmentCategoryInsert = Database["public"]["Tables"]["operating_context_equipment_categories"]["Insert"];
219
+ export type OperatingContextEquipmentCategoryUpdate = Database["public"]["Tables"]["operating_context_equipment_categories"]["Update"];
220
+ export type OperatingContextEquipmentItemInsert = Database["public"]["Tables"]["operating_context_equipment_items"]["Insert"];
221
+ export type OperatingContextEquipmentItemUpdate = Database["public"]["Tables"]["operating_context_equipment_items"]["Update"];
222
+ export type OperatingContextInsert = Database["public"]["Tables"]["operating_contexts"]["Insert"];
223
+ export type OperatingContextUpdate = Database["public"]["Tables"]["operating_contexts"]["Update"];
224
+ export type OperatingContextPayloadInsert = Database["public"]["Tables"]["operating_context_payloads"]["Insert"];
225
+ export type OperatingContextPayloadUpdate = Database["public"]["Tables"]["operating_context_payloads"]["Update"];
226
+ export type OperatingContextRoleAssignmentInsert = Database["public"]["Tables"]["operating_context_role_assignments"]["Insert"];
227
+ export type OperatingContextRoleAssignmentUpdate = Database["public"]["Tables"]["operating_context_role_assignments"]["Update"];
228
+ export type OperatingContextEquipmentRequirementInsert = Database["public"]["Tables"]["operating_context_equipment_requirements"]["Insert"];
229
+ export type OperatingContextEquipmentRequirementUpdate = Database["public"]["Tables"]["operating_context_equipment_requirements"]["Update"];
230
+ export type OperatingContextRegionInsert = Database["public"]["Tables"]["operating_context_regions"]["Insert"];
231
+ export type OperatingContextRegionUpdate = Database["public"]["Tables"]["operating_context_regions"]["Update"];
232
+ export type OperatingContextRiskInsert = Database["public"]["Tables"]["operating_context_risks"]["Insert"];
233
+ export type OperatingContextRiskUpdate = Database["public"]["Tables"]["operating_context_risks"]["Update"];
149
234
  export interface CredentialQueryArgs {
150
235
  type?: string;
151
236
  }
@@ -6,4 +6,5 @@ export declare enum EnumRealtimeOperation {
6
6
  export type RealtimeData<T> = {
7
7
  data: T;
8
8
  operation: EnumRealtimeOperation;
9
+ table: string;
9
10
  };