@adventurelabs/scout-core 1.0.83 → 1.0.84
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/helpers/cache.d.ts +0 -2
- package/dist/helpers/cache.js +3 -112
- package/dist/helpers/heartbeats.d.ts +9 -0
- package/dist/helpers/heartbeats.js +90 -0
- package/dist/helpers/index.d.ts +1 -0
- package/dist/helpers/index.js +1 -0
- package/dist/providers/ScoutRefreshProvider.d.ts +27 -0
- package/dist/types/db.d.ts +1 -1
- package/dist/types/herd_module.d.ts +2 -4
- package/dist/types/herd_module.js +6 -23
- package/dist/types/supabase.d.ts +29 -0
- package/package.json +1 -1
package/dist/helpers/cache.d.ts
CHANGED
|
@@ -47,8 +47,6 @@ export declare class ScoutCache {
|
|
|
47
47
|
reason: string;
|
|
48
48
|
}>;
|
|
49
49
|
preloadCache(loadFunction: () => Promise<IHerdModule[]>, ttlMs?: number): Promise<void>;
|
|
50
|
-
getProvidersForHerd(herdId: string): Promise<CacheResult<any[]>>;
|
|
51
|
-
setProvidersForHerd(herdId: string, providers: any[], ttlMs?: number): Promise<void>;
|
|
52
50
|
getDefaultTtl(): number;
|
|
53
51
|
}
|
|
54
52
|
export declare const scoutCache: ScoutCache;
|
package/dist/helpers/cache.js
CHANGED
|
@@ -2,7 +2,6 @@ const DB_NAME = "ScoutCache";
|
|
|
2
2
|
const DB_VERSION = 1;
|
|
3
3
|
const HERD_MODULES_STORE = "herd_modules";
|
|
4
4
|
const CACHE_METADATA_STORE = "cache_metadata";
|
|
5
|
-
const PROVIDERS_STORE = "providers";
|
|
6
5
|
// Default TTL: 24 hours (1 day)
|
|
7
6
|
const DEFAULT_TTL_MS = 24 * 60 * 60 * 1000;
|
|
8
7
|
export class ScoutCache {
|
|
@@ -47,15 +46,6 @@ export class ScoutCache {
|
|
|
47
46
|
keyPath: "key",
|
|
48
47
|
});
|
|
49
48
|
}
|
|
50
|
-
// Create providers store
|
|
51
|
-
if (!db.objectStoreNames.contains(PROVIDERS_STORE)) {
|
|
52
|
-
const providersStore = db.createObjectStore(PROVIDERS_STORE, {
|
|
53
|
-
keyPath: "herdId",
|
|
54
|
-
});
|
|
55
|
-
providersStore.createIndex("timestamp", "timestamp", {
|
|
56
|
-
unique: false,
|
|
57
|
-
});
|
|
58
|
-
}
|
|
59
49
|
console.log("[ScoutCache] Database schema upgraded");
|
|
60
50
|
};
|
|
61
51
|
});
|
|
@@ -65,16 +55,15 @@ export class ScoutCache {
|
|
|
65
55
|
await this.init();
|
|
66
56
|
if (!this.db)
|
|
67
57
|
throw new Error("Database not initialized");
|
|
68
|
-
const transaction = this.db.transaction([HERD_MODULES_STORE, CACHE_METADATA_STORE
|
|
58
|
+
const transaction = this.db.transaction([HERD_MODULES_STORE, CACHE_METADATA_STORE], "readwrite");
|
|
69
59
|
return new Promise((resolve, reject) => {
|
|
70
60
|
transaction.onerror = () => reject(transaction.error);
|
|
71
61
|
transaction.oncomplete = () => resolve();
|
|
72
62
|
const herdModulesStore = transaction.objectStore(HERD_MODULES_STORE);
|
|
73
63
|
const metadataStore = transaction.objectStore(CACHE_METADATA_STORE);
|
|
74
|
-
const providersStore = transaction.objectStore(PROVIDERS_STORE);
|
|
75
64
|
const timestamp = Date.now();
|
|
76
65
|
const version = "1.0.0";
|
|
77
|
-
// Store each herd module
|
|
66
|
+
// Store each herd module
|
|
78
67
|
herdModules.forEach((herdModule) => {
|
|
79
68
|
const cacheEntry = {
|
|
80
69
|
herdId: herdModule.herd.id.toString(),
|
|
@@ -82,15 +71,6 @@ export class ScoutCache {
|
|
|
82
71
|
timestamp,
|
|
83
72
|
};
|
|
84
73
|
herdModulesStore.put(cacheEntry);
|
|
85
|
-
// Store providers separately for easier querying
|
|
86
|
-
if (herdModule.providers && herdModule.providers.length > 0) {
|
|
87
|
-
const providersCacheEntry = {
|
|
88
|
-
herdId: herdModule.herd.id.toString(),
|
|
89
|
-
data: herdModule.providers,
|
|
90
|
-
timestamp,
|
|
91
|
-
};
|
|
92
|
-
providersStore.put(providersCacheEntry);
|
|
93
|
-
}
|
|
94
74
|
});
|
|
95
75
|
// Store cache metadata
|
|
96
76
|
const metadata = {
|
|
@@ -102,16 +82,6 @@ export class ScoutCache {
|
|
|
102
82
|
lastModified: timestamp,
|
|
103
83
|
};
|
|
104
84
|
metadataStore.put(metadata);
|
|
105
|
-
// Store providers metadata
|
|
106
|
-
const providersMetadata = {
|
|
107
|
-
key: "providers",
|
|
108
|
-
timestamp,
|
|
109
|
-
ttl: ttlMs,
|
|
110
|
-
version,
|
|
111
|
-
etag,
|
|
112
|
-
lastModified: timestamp,
|
|
113
|
-
};
|
|
114
|
-
metadataStore.put(providersMetadata);
|
|
115
85
|
});
|
|
116
86
|
}
|
|
117
87
|
async getHerdModules() {
|
|
@@ -164,17 +134,14 @@ export class ScoutCache {
|
|
|
164
134
|
await this.init();
|
|
165
135
|
if (!this.db)
|
|
166
136
|
throw new Error("Database not initialized");
|
|
167
|
-
const transaction = this.db.transaction([HERD_MODULES_STORE, CACHE_METADATA_STORE
|
|
137
|
+
const transaction = this.db.transaction([HERD_MODULES_STORE, CACHE_METADATA_STORE], "readwrite");
|
|
168
138
|
return new Promise((resolve, reject) => {
|
|
169
139
|
transaction.onerror = () => reject(transaction.error);
|
|
170
140
|
transaction.oncomplete = () => resolve();
|
|
171
141
|
const herdModulesStore = transaction.objectStore(HERD_MODULES_STORE);
|
|
172
142
|
const metadataStore = transaction.objectStore(CACHE_METADATA_STORE);
|
|
173
|
-
const providersStore = transaction.objectStore(PROVIDERS_STORE);
|
|
174
143
|
herdModulesStore.clear();
|
|
175
|
-
providersStore.clear();
|
|
176
144
|
metadataStore.delete("herd_modules");
|
|
177
|
-
metadataStore.delete("providers");
|
|
178
145
|
});
|
|
179
146
|
}
|
|
180
147
|
async invalidateHerdModules() {
|
|
@@ -187,7 +154,6 @@ export class ScoutCache {
|
|
|
187
154
|
transaction.oncomplete = () => resolve();
|
|
188
155
|
const metadataStore = transaction.objectStore(CACHE_METADATA_STORE);
|
|
189
156
|
metadataStore.delete("herd_modules");
|
|
190
|
-
metadataStore.delete("providers");
|
|
191
157
|
});
|
|
192
158
|
}
|
|
193
159
|
async getCacheStats() {
|
|
@@ -248,81 +214,6 @@ export class ScoutCache {
|
|
|
248
214
|
console.warn("[ScoutCache] Background preload failed:", error);
|
|
249
215
|
}
|
|
250
216
|
}
|
|
251
|
-
// Method to get providers for a specific herd from cache
|
|
252
|
-
async getProvidersForHerd(herdId) {
|
|
253
|
-
await this.init();
|
|
254
|
-
if (!this.db)
|
|
255
|
-
throw new Error("Database not initialized");
|
|
256
|
-
const transaction = this.db.transaction([PROVIDERS_STORE, CACHE_METADATA_STORE], "readonly");
|
|
257
|
-
return new Promise((resolve, reject) => {
|
|
258
|
-
transaction.onerror = () => reject(transaction.error);
|
|
259
|
-
const providersStore = transaction.objectStore(PROVIDERS_STORE);
|
|
260
|
-
const metadataStore = transaction.objectStore(CACHE_METADATA_STORE);
|
|
261
|
-
// Get metadata first
|
|
262
|
-
const metadataRequest = metadataStore.get("providers");
|
|
263
|
-
metadataRequest.onsuccess = () => {
|
|
264
|
-
const metadata = metadataRequest.result;
|
|
265
|
-
const now = Date.now();
|
|
266
|
-
if (!metadata) {
|
|
267
|
-
this.stats.misses++;
|
|
268
|
-
resolve({ data: null, isStale: true, age: 0, metadata: null });
|
|
269
|
-
return;
|
|
270
|
-
}
|
|
271
|
-
const age = now - metadata.timestamp;
|
|
272
|
-
const isStale = age > metadata.ttl;
|
|
273
|
-
// Get providers for specific herd
|
|
274
|
-
const getRequest = providersStore.get(herdId);
|
|
275
|
-
getRequest.onsuccess = () => {
|
|
276
|
-
const cacheEntry = getRequest.result;
|
|
277
|
-
const providers = cacheEntry?.data || [];
|
|
278
|
-
// Update stats
|
|
279
|
-
if (providers.length > 0) {
|
|
280
|
-
this.stats.hits++;
|
|
281
|
-
}
|
|
282
|
-
else {
|
|
283
|
-
this.stats.misses++;
|
|
284
|
-
}
|
|
285
|
-
resolve({
|
|
286
|
-
data: providers,
|
|
287
|
-
isStale,
|
|
288
|
-
age,
|
|
289
|
-
metadata,
|
|
290
|
-
});
|
|
291
|
-
};
|
|
292
|
-
};
|
|
293
|
-
});
|
|
294
|
-
}
|
|
295
|
-
// Method to set providers for a specific herd
|
|
296
|
-
async setProvidersForHerd(herdId, providers, ttlMs = DEFAULT_TTL_MS) {
|
|
297
|
-
await this.init();
|
|
298
|
-
if (!this.db)
|
|
299
|
-
throw new Error("Database not initialized");
|
|
300
|
-
const transaction = this.db.transaction([PROVIDERS_STORE, CACHE_METADATA_STORE], "readwrite");
|
|
301
|
-
return new Promise((resolve, reject) => {
|
|
302
|
-
transaction.onerror = () => reject(transaction.error);
|
|
303
|
-
transaction.oncomplete = () => resolve();
|
|
304
|
-
const providersStore = transaction.objectStore(PROVIDERS_STORE);
|
|
305
|
-
const metadataStore = transaction.objectStore(CACHE_METADATA_STORE);
|
|
306
|
-
const timestamp = Date.now();
|
|
307
|
-
const version = "1.0.0";
|
|
308
|
-
// Store providers
|
|
309
|
-
const providersCacheEntry = {
|
|
310
|
-
herdId,
|
|
311
|
-
data: providers,
|
|
312
|
-
timestamp,
|
|
313
|
-
};
|
|
314
|
-
providersStore.put(providersCacheEntry);
|
|
315
|
-
// Update providers metadata
|
|
316
|
-
const metadata = {
|
|
317
|
-
key: "providers",
|
|
318
|
-
timestamp,
|
|
319
|
-
ttl: ttlMs,
|
|
320
|
-
version,
|
|
321
|
-
lastModified: timestamp,
|
|
322
|
-
};
|
|
323
|
-
metadataStore.put(metadata);
|
|
324
|
-
});
|
|
325
|
-
}
|
|
326
217
|
// Get the default TTL value
|
|
327
218
|
getDefaultTtl() {
|
|
328
219
|
return DEFAULT_TTL_MS;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { IWebResponseCompatible } from "../types/requests";
|
|
2
|
+
import { IHeartbeat } from "../types/db";
|
|
3
|
+
export declare function server_get_last_heartbeat_by_device(device_id: number): Promise<IWebResponseCompatible<IHeartbeat | null>>;
|
|
4
|
+
export declare function server_get_heartbeats_by_device(device_id: number, limit?: number): Promise<IWebResponseCompatible<IHeartbeat[]>>;
|
|
5
|
+
export declare function server_check_device_online_status(device_id: number, offline_threshold_minutes?: number): Promise<IWebResponseCompatible<{
|
|
6
|
+
is_online: boolean;
|
|
7
|
+
last_heartbeat: IHeartbeat | null;
|
|
8
|
+
minutes_since_last_heartbeat: number | null;
|
|
9
|
+
}>>;
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
"use server";
|
|
2
|
+
import { newServerClient } from "../supabase/server";
|
|
3
|
+
import { EnumWebResponse, IWebResponse, } from "../types/requests";
|
|
4
|
+
// Function to get the last heartbeat for a device
|
|
5
|
+
export async function server_get_last_heartbeat_by_device(device_id) {
|
|
6
|
+
const supabase = await newServerClient();
|
|
7
|
+
const { data, error } = await supabase
|
|
8
|
+
.from("heartbeats")
|
|
9
|
+
.select("*")
|
|
10
|
+
.eq("device_id", device_id)
|
|
11
|
+
.order("timestamp", { ascending: false })
|
|
12
|
+
.limit(1)
|
|
13
|
+
.single();
|
|
14
|
+
if (error) {
|
|
15
|
+
// If no heartbeats found, return null data instead of error
|
|
16
|
+
if (error.code === "PGRST116") {
|
|
17
|
+
return {
|
|
18
|
+
status: EnumWebResponse.SUCCESS,
|
|
19
|
+
msg: null,
|
|
20
|
+
data: null,
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
return {
|
|
24
|
+
status: EnumWebResponse.ERROR,
|
|
25
|
+
msg: error.message,
|
|
26
|
+
data: null,
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
else {
|
|
30
|
+
return IWebResponse.success(data).to_compatible();
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
// Function to get all heartbeats for a device
|
|
34
|
+
export async function server_get_heartbeats_by_device(device_id, limit) {
|
|
35
|
+
const supabase = await newServerClient();
|
|
36
|
+
let query = supabase
|
|
37
|
+
.from("heartbeats")
|
|
38
|
+
.select("*")
|
|
39
|
+
.eq("device_id", device_id)
|
|
40
|
+
.order("timestamp", { ascending: false });
|
|
41
|
+
if (limit) {
|
|
42
|
+
query = query.limit(limit);
|
|
43
|
+
}
|
|
44
|
+
const { data, error } = await query;
|
|
45
|
+
if (error) {
|
|
46
|
+
return {
|
|
47
|
+
status: EnumWebResponse.ERROR,
|
|
48
|
+
msg: error.message,
|
|
49
|
+
data: [],
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
else {
|
|
53
|
+
return IWebResponse.success(data || []).to_compatible();
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
// Function to check if a device is online based on heartbeat recency
|
|
57
|
+
export async function server_check_device_online_status(device_id, offline_threshold_minutes = 5) {
|
|
58
|
+
const supabase = await newServerClient();
|
|
59
|
+
const { data, error } = await supabase
|
|
60
|
+
.from("heartbeats")
|
|
61
|
+
.select("*")
|
|
62
|
+
.eq("device_id", device_id)
|
|
63
|
+
.order("timestamp", { ascending: false })
|
|
64
|
+
.limit(1)
|
|
65
|
+
.single();
|
|
66
|
+
if (error) {
|
|
67
|
+
// If no heartbeats found
|
|
68
|
+
if (error.code === "PGRST116") {
|
|
69
|
+
return IWebResponse.success({
|
|
70
|
+
is_online: false,
|
|
71
|
+
last_heartbeat: null,
|
|
72
|
+
minutes_since_last_heartbeat: null,
|
|
73
|
+
}).to_compatible();
|
|
74
|
+
}
|
|
75
|
+
return {
|
|
76
|
+
status: EnumWebResponse.ERROR,
|
|
77
|
+
msg: error.message,
|
|
78
|
+
data: null,
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
const now = new Date();
|
|
82
|
+
const heartbeatTime = new Date(data.timestamp);
|
|
83
|
+
const minutesSinceLastHeartbeat = Math.floor((now.getTime() - heartbeatTime.getTime()) / (1000 * 60));
|
|
84
|
+
const isOnline = minutesSinceLastHeartbeat <= offline_threshold_minutes;
|
|
85
|
+
return IWebResponse.success({
|
|
86
|
+
is_online: isOnline,
|
|
87
|
+
last_heartbeat: data,
|
|
88
|
+
minutes_since_last_heartbeat: minutesSinceLastHeartbeat,
|
|
89
|
+
}).to_compatible();
|
|
90
|
+
}
|
package/dist/helpers/index.d.ts
CHANGED
package/dist/helpers/index.js
CHANGED
|
@@ -289,6 +289,33 @@ export declare function useSupabase(): SupabaseClient<Database, "public", "publi
|
|
|
289
289
|
referencedColumns: ["id"];
|
|
290
290
|
}];
|
|
291
291
|
};
|
|
292
|
+
heartbeats: {
|
|
293
|
+
Row: {
|
|
294
|
+
created_at: string;
|
|
295
|
+
device_id: number;
|
|
296
|
+
id: number;
|
|
297
|
+
timestamp: string;
|
|
298
|
+
};
|
|
299
|
+
Insert: {
|
|
300
|
+
created_at?: string;
|
|
301
|
+
device_id: number;
|
|
302
|
+
id?: number;
|
|
303
|
+
timestamp: string;
|
|
304
|
+
};
|
|
305
|
+
Update: {
|
|
306
|
+
created_at?: string;
|
|
307
|
+
device_id?: number;
|
|
308
|
+
id?: number;
|
|
309
|
+
timestamp?: string;
|
|
310
|
+
};
|
|
311
|
+
Relationships: [{
|
|
312
|
+
foreignKeyName: "heartbeats_device_id_fkey";
|
|
313
|
+
columns: ["device_id"];
|
|
314
|
+
isOneToOne: false;
|
|
315
|
+
referencedRelation: "devices";
|
|
316
|
+
referencedColumns: ["id"];
|
|
317
|
+
}];
|
|
318
|
+
};
|
|
292
319
|
herds: {
|
|
293
320
|
Row: {
|
|
294
321
|
created_by: string;
|
package/dist/types/db.d.ts
CHANGED
|
@@ -21,7 +21,7 @@ export type IUserRolePerHerd = Database["public"]["Tables"]["users_roles_per_her
|
|
|
21
21
|
export type IHerd = Database["public"]["Tables"]["herds"]["Row"];
|
|
22
22
|
export type ISession = Database["public"]["Tables"]["sessions"]["Row"];
|
|
23
23
|
export type IConnectivity = Database["public"]["Tables"]["connectivity"]["Row"];
|
|
24
|
-
export type
|
|
24
|
+
export type IHeartbeat = Database["public"]["Tables"]["heartbeats"]["Row"];
|
|
25
25
|
export type IEventWithTags = Database["public"]["CompositeTypes"]["event_with_tags"] & {
|
|
26
26
|
earthranger_url: string | null;
|
|
27
27
|
file_path: string | null;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { SupabaseClient } from "@supabase/supabase-js";
|
|
2
|
-
import { IDevice, IEventWithTags, IHerd, IPlan, ILayer,
|
|
2
|
+
import { IDevice, IEventWithTags, IHerd, IPlan, ILayer, IUserAndRole, IZoneWithActions, ISessionWithCoordinates } from "../types/db";
|
|
3
3
|
import { EnumWebResponse } from "./requests";
|
|
4
4
|
export declare enum EnumHerdModulesLoadingState {
|
|
5
5
|
NOT_LOADING = "NOT_LOADING",
|
|
@@ -21,8 +21,7 @@ export declare class HerdModule {
|
|
|
21
21
|
labels: string[];
|
|
22
22
|
plans: IPlan[];
|
|
23
23
|
layers: ILayer[];
|
|
24
|
-
|
|
25
|
-
constructor(herd: IHerd, devices: IDevice[], events: IEventWithTags[], timestamp_last_refreshed: number, user_roles?: IUserAndRole[] | null, events_page_index?: number, total_events?: number, total_events_with_filters?: number, labels?: string[], plans?: IPlan[], zones?: IZoneWithActions[], sessions?: ISessionWithCoordinates[], layers?: ILayer[], providers?: IProvider[]);
|
|
24
|
+
constructor(herd: IHerd, devices: IDevice[], events: IEventWithTags[], timestamp_last_refreshed: number, user_roles?: IUserAndRole[] | null, events_page_index?: number, total_events?: number, total_events_with_filters?: number, labels?: string[], plans?: IPlan[], zones?: IZoneWithActions[], sessions?: ISessionWithCoordinates[], layers?: ILayer[]);
|
|
26
25
|
to_serializable(): IHerdModule;
|
|
27
26
|
static from_herd(herd: IHerd, client: SupabaseClient): Promise<HerdModule>;
|
|
28
27
|
}
|
|
@@ -40,7 +39,6 @@ export interface IHerdModule {
|
|
|
40
39
|
zones: IZoneWithActions[];
|
|
41
40
|
sessions: ISessionWithCoordinates[];
|
|
42
41
|
layers: ILayer[];
|
|
43
|
-
providers: IProvider[];
|
|
44
42
|
}
|
|
45
43
|
export interface IHerdModulesResponse {
|
|
46
44
|
data: IHerdModule[];
|
|
@@ -4,7 +4,6 @@ import { server_get_total_events_by_herd } from "../helpers/events";
|
|
|
4
4
|
import { EnumSessionsVisibility } from "./events";
|
|
5
5
|
import { server_get_plans_by_herd } from "../helpers/plans";
|
|
6
6
|
import { server_get_layers_by_herd } from "../helpers/layers";
|
|
7
|
-
import { server_get_providers_by_herd } from "../helpers/providers";
|
|
8
7
|
import { server_get_events_and_tags_for_devices_batch } from "../helpers/tags";
|
|
9
8
|
import { server_get_users_with_herd_access } from "../helpers/users";
|
|
10
9
|
import { EnumWebResponse } from "./requests";
|
|
@@ -19,7 +18,7 @@ export var EnumHerdModulesLoadingState;
|
|
|
19
18
|
EnumHerdModulesLoadingState["UNSUCCESSFULLY_LOADED"] = "UNSUCCESSFULLY_LOADED";
|
|
20
19
|
})(EnumHerdModulesLoadingState || (EnumHerdModulesLoadingState = {}));
|
|
21
20
|
export class HerdModule {
|
|
22
|
-
constructor(herd, devices, events, timestamp_last_refreshed, user_roles = null, events_page_index = 0, total_events = 0, total_events_with_filters = 0, labels = [], plans = [], zones = [], sessions = [], layers = []
|
|
21
|
+
constructor(herd, devices, events, timestamp_last_refreshed, user_roles = null, events_page_index = 0, total_events = 0, total_events_with_filters = 0, labels = [], plans = [], zones = [], sessions = [], layers = []) {
|
|
23
22
|
this.user_roles = null;
|
|
24
23
|
this.events_page_index = 0;
|
|
25
24
|
this.total_events = 0;
|
|
@@ -27,7 +26,6 @@ export class HerdModule {
|
|
|
27
26
|
this.labels = [];
|
|
28
27
|
this.plans = [];
|
|
29
28
|
this.layers = [];
|
|
30
|
-
this.providers = [];
|
|
31
29
|
this.herd = herd;
|
|
32
30
|
this.devices = devices;
|
|
33
31
|
this.events = events;
|
|
@@ -41,7 +39,6 @@ export class HerdModule {
|
|
|
41
39
|
this.zones = zones;
|
|
42
40
|
this.sessions = sessions;
|
|
43
41
|
this.layers = layers;
|
|
44
|
-
this.providers = providers;
|
|
45
42
|
}
|
|
46
43
|
to_serializable() {
|
|
47
44
|
return {
|
|
@@ -58,7 +55,6 @@ export class HerdModule {
|
|
|
58
55
|
zones: this.zones,
|
|
59
56
|
sessions: this.sessions,
|
|
60
57
|
layers: this.layers,
|
|
61
|
-
providers: this.providers,
|
|
62
58
|
};
|
|
63
59
|
}
|
|
64
60
|
static async from_herd(herd, client) {
|
|
@@ -99,7 +95,7 @@ export class HerdModule {
|
|
|
99
95
|
}
|
|
100
96
|
}
|
|
101
97
|
// Run all remaining requests in parallel with individual error handling
|
|
102
|
-
const [res_zones, res_user_roles, total_event_count, res_plans, res_sessions, res_layers,
|
|
98
|
+
const [res_zones, res_user_roles, total_event_count, res_plans, res_sessions, res_layers,] = await Promise.allSettled([
|
|
103
99
|
server_get_more_zones_and_actions_for_herd(herd.id, 0, 10).catch((error) => {
|
|
104
100
|
console.warn(`[HerdModule] Failed to get zones and actions:`, error);
|
|
105
101
|
return { status: EnumWebResponse.ERROR, data: null };
|
|
@@ -118,20 +114,12 @@ export class HerdModule {
|
|
|
118
114
|
}),
|
|
119
115
|
server_get_sessions_by_herd_id(herd.id).catch((error) => {
|
|
120
116
|
console.warn(`[HerdModule] Failed to get sessions:`, error);
|
|
121
|
-
return {
|
|
122
|
-
status: EnumWebResponse.ERROR,
|
|
123
|
-
data: [],
|
|
124
|
-
msg: error.message,
|
|
125
|
-
};
|
|
117
|
+
return { status: EnumWebResponse.ERROR, data: [], msg: error.message };
|
|
126
118
|
}),
|
|
127
119
|
server_get_layers_by_herd(herd.id).catch((error) => {
|
|
128
120
|
console.warn(`[HerdModule] Failed to get layers:`, error);
|
|
129
121
|
return { status: EnumWebResponse.ERROR, data: null };
|
|
130
122
|
}),
|
|
131
|
-
server_get_providers_by_herd(herd.id).catch((error) => {
|
|
132
|
-
console.warn(`[HerdModule] Failed to get providers:`, error);
|
|
133
|
-
return { status: EnumWebResponse.ERROR, data: null };
|
|
134
|
-
}),
|
|
135
123
|
]);
|
|
136
124
|
// Assign recent events to devices from batch results
|
|
137
125
|
for (let i = 0; i < new_devices.length; i++) {
|
|
@@ -160,28 +148,23 @@ export class HerdModule {
|
|
|
160
148
|
const plans = res_plans.status === "fulfilled" && res_plans.value?.data
|
|
161
149
|
? res_plans.value.data
|
|
162
150
|
: [];
|
|
163
|
-
const sessions = res_sessions.status === "fulfilled" && res_sessions.value?.data
|
|
164
|
-
? res_sessions.value.data
|
|
165
|
-
: [];
|
|
151
|
+
const sessions = res_sessions.status === "fulfilled" && res_sessions.value?.data ? res_sessions.value.data : [];
|
|
166
152
|
const layers = res_layers.status === "fulfilled" && res_layers.value?.data
|
|
167
153
|
? res_layers.value.data
|
|
168
154
|
: [];
|
|
169
|
-
const providers = res_providers.status === "fulfilled" && res_providers.value?.data
|
|
170
|
-
? res_providers.value.data
|
|
171
|
-
: [];
|
|
172
155
|
// TODO: store in DB and retrieve on load?
|
|
173
156
|
const newLabels = LABELS;
|
|
174
157
|
const endTime = Date.now();
|
|
175
158
|
const loadTime = endTime - startTime;
|
|
176
159
|
console.log(`[HerdModule] Loaded herd ${herd.slug} in ${loadTime}ms (${new_devices.length} devices)`);
|
|
177
|
-
return new HerdModule(herd, new_devices, [], Date.now(), user_roles, 0, total_events, total_events, newLabels, plans, zones, sessions, layers
|
|
160
|
+
return new HerdModule(herd, new_devices, [], Date.now(), user_roles, 0, total_events, total_events, newLabels, plans, zones, sessions, layers);
|
|
178
161
|
}
|
|
179
162
|
catch (error) {
|
|
180
163
|
const endTime = Date.now();
|
|
181
164
|
const loadTime = endTime - startTime;
|
|
182
165
|
console.error(`[HerdModule] Critical error in HerdModule.from_herd (${loadTime}ms):`, error);
|
|
183
166
|
// Return a minimal but valid HerdModule instance to prevent complete failure
|
|
184
|
-
return new HerdModule(herd, [], [], Date.now(), null, 0, 0, 0, [], [], [], [], []
|
|
167
|
+
return new HerdModule(herd, [], [], Date.now(), null, 0, 0, 0, [], [], [], [], []);
|
|
185
168
|
}
|
|
186
169
|
}
|
|
187
170
|
}
|
package/dist/types/supabase.d.ts
CHANGED
|
@@ -302,6 +302,35 @@ export type Database = {
|
|
|
302
302
|
}
|
|
303
303
|
];
|
|
304
304
|
};
|
|
305
|
+
heartbeats: {
|
|
306
|
+
Row: {
|
|
307
|
+
created_at: string;
|
|
308
|
+
device_id: number;
|
|
309
|
+
id: number;
|
|
310
|
+
timestamp: string;
|
|
311
|
+
};
|
|
312
|
+
Insert: {
|
|
313
|
+
created_at?: string;
|
|
314
|
+
device_id: number;
|
|
315
|
+
id?: number;
|
|
316
|
+
timestamp: string;
|
|
317
|
+
};
|
|
318
|
+
Update: {
|
|
319
|
+
created_at?: string;
|
|
320
|
+
device_id?: number;
|
|
321
|
+
id?: number;
|
|
322
|
+
timestamp?: string;
|
|
323
|
+
};
|
|
324
|
+
Relationships: [
|
|
325
|
+
{
|
|
326
|
+
foreignKeyName: "heartbeats_device_id_fkey";
|
|
327
|
+
columns: ["device_id"];
|
|
328
|
+
isOneToOne: false;
|
|
329
|
+
referencedRelation: "devices";
|
|
330
|
+
referencedColumns: ["id"];
|
|
331
|
+
}
|
|
332
|
+
];
|
|
333
|
+
};
|
|
305
334
|
herds: {
|
|
306
335
|
Row: {
|
|
307
336
|
created_by: string;
|