@adventurelabs/scout-core 1.4.83 → 1.4.85
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/api_keys/actions.d.ts +2 -1
- package/dist/api_keys/actions.js +2 -2
- package/dist/helpers/herd_credentials.d.ts +9 -0
- package/dist/helpers/herd_credentials.js +85 -0
- package/dist/helpers/herds.js +93 -14
- package/dist/helpers/index.d.ts +2 -1
- package/dist/helpers/index.js +2 -1
- package/dist/helpers/layers.d.ts +3 -0
- package/dist/helpers/layers.js +20 -0
- package/dist/helpers/parts.d.ts +7 -0
- package/dist/helpers/parts.js +32 -0
- package/dist/helpers/plans.d.ts +3 -0
- package/dist/helpers/plans.js +20 -0
- package/dist/helpers/providers.d.ts +3 -0
- package/dist/helpers/providers.js +20 -0
- package/dist/helpers/user_credentials.d.ts +9 -0
- package/dist/helpers/user_credentials.js +85 -0
- package/dist/helpers/users.d.ts +1 -0
- package/dist/helpers/users.js +30 -0
- package/dist/helpers/zones.d.ts +2 -1
- package/dist/helpers/zones.js +2 -2
- package/dist/hooks/useDeviceDisplayName.d.ts +8 -0
- package/dist/hooks/useDeviceDisplayName.js +49 -0
- package/dist/hooks/useScoutRefresh.js +24 -8
- package/dist/index.d.ts +4 -3
- package/dist/index.js +2 -1
- package/dist/store/scout.d.ts +1 -0
- package/dist/store/scout.js +18 -2
- package/dist/types/db.d.ts +9 -3
- package/dist/types/herd_module.d.ts +2 -17
- package/dist/types/herd_module.js +0 -166
- package/dist/types/supabase.d.ts +152 -82
- package/package.json +1 -1
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { IApiKeyScout } from "../types/db";
|
|
2
|
+
import { SupabaseClient } from "@supabase/supabase-js";
|
|
2
3
|
export declare function test_api_key_loading(device_id: number): Promise<boolean>;
|
|
3
4
|
export declare function server_list_api_keys(device_id: number): Promise<IApiKeyScout[]>;
|
|
4
|
-
export declare function server_list_api_keys_batch(device_ids: number[]): Promise<{
|
|
5
|
+
export declare function server_list_api_keys_batch(device_ids: number[], client?: SupabaseClient): Promise<{
|
|
5
6
|
[device_id: number]: IApiKeyScout[];
|
|
6
7
|
}>;
|
package/dist/api_keys/actions.js
CHANGED
|
@@ -31,8 +31,8 @@ export async function server_list_api_keys(device_id) {
|
|
|
31
31
|
}
|
|
32
32
|
return data_to_return;
|
|
33
33
|
}
|
|
34
|
-
export async function server_list_api_keys_batch(device_ids) {
|
|
35
|
-
const supabase = await newServerClient();
|
|
34
|
+
export async function server_list_api_keys_batch(device_ids, client) {
|
|
35
|
+
const supabase = client || (await newServerClient());
|
|
36
36
|
// Check if the batch function exists by trying a simple call
|
|
37
37
|
try {
|
|
38
38
|
const { data, error } = await supabase.rpc("load_api_keys_batch", {
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { Database } from "../types/supabase";
|
|
2
|
+
import { CredentialQueryArgs, IHerdCredential, HerdCredentialInsert, HerdCredentialUpdate } from "../types/db";
|
|
3
|
+
import { IWebResponseCompatible } from "../types/requests";
|
|
4
|
+
import { SupabaseClient } from "@supabase/supabase-js";
|
|
5
|
+
export declare function get_herd_credentials_by_herd_id(client: SupabaseClient<Database>, herd_id: number, args?: CredentialQueryArgs): Promise<IWebResponseCompatible<IHerdCredential[]>>;
|
|
6
|
+
export declare function get_herd_credential_by_id(client: SupabaseClient<Database>, credential_id: number): Promise<IWebResponseCompatible<IHerdCredential | null>>;
|
|
7
|
+
export declare function create_herd_credential(client: SupabaseClient<Database>, row: HerdCredentialInsert): Promise<IWebResponseCompatible<IHerdCredential | null>>;
|
|
8
|
+
export declare function update_herd_credential(client: SupabaseClient<Database>, credential_id: number, patch: HerdCredentialUpdate): Promise<IWebResponseCompatible<IHerdCredential | null>>;
|
|
9
|
+
export declare function delete_herd_credential(client: SupabaseClient<Database>, credential_id: number): Promise<IWebResponseCompatible<IHerdCredential | null>>;
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { IWebResponse } from "../types/requests";
|
|
2
|
+
export async function get_herd_credentials_by_herd_id(client, herd_id, args) {
|
|
3
|
+
let query = client
|
|
4
|
+
.from("herd_credentials")
|
|
5
|
+
.select("*")
|
|
6
|
+
.eq("herd_id", herd_id);
|
|
7
|
+
if (args?.type)
|
|
8
|
+
query = query.eq("type", args.type);
|
|
9
|
+
const { data, error } = await query.order("created_at", { ascending: false });
|
|
10
|
+
if (error) {
|
|
11
|
+
return IWebResponse.error(error.message).to_compatible();
|
|
12
|
+
}
|
|
13
|
+
return IWebResponse.success(data ?? []).to_compatible();
|
|
14
|
+
}
|
|
15
|
+
export async function get_herd_credential_by_id(client, credential_id) {
|
|
16
|
+
const { data, error } = await client
|
|
17
|
+
.from("herd_credentials")
|
|
18
|
+
.select("*")
|
|
19
|
+
.eq("id", credential_id)
|
|
20
|
+
.single();
|
|
21
|
+
if (error) {
|
|
22
|
+
return IWebResponse.error(error.message).to_compatible();
|
|
23
|
+
}
|
|
24
|
+
if (!data) {
|
|
25
|
+
return IWebResponse.error("Herd credential not found").to_compatible();
|
|
26
|
+
}
|
|
27
|
+
return IWebResponse.success(data).to_compatible();
|
|
28
|
+
}
|
|
29
|
+
export async function create_herd_credential(client, row) {
|
|
30
|
+
if (!row.herd_id) {
|
|
31
|
+
return IWebResponse.error("herd_id is required").to_compatible();
|
|
32
|
+
}
|
|
33
|
+
if (!row.issuer?.trim()) {
|
|
34
|
+
return IWebResponse.error("issuer is required").to_compatible();
|
|
35
|
+
}
|
|
36
|
+
if (!row.type?.trim()) {
|
|
37
|
+
return IWebResponse.error("type is required").to_compatible();
|
|
38
|
+
}
|
|
39
|
+
const { data, error } = await client
|
|
40
|
+
.from("herd_credentials")
|
|
41
|
+
.insert([row])
|
|
42
|
+
.select("*")
|
|
43
|
+
.single();
|
|
44
|
+
if (error) {
|
|
45
|
+
return IWebResponse.error(error.message).to_compatible();
|
|
46
|
+
}
|
|
47
|
+
if (!data) {
|
|
48
|
+
return IWebResponse.error("Failed to create herd credential").to_compatible();
|
|
49
|
+
}
|
|
50
|
+
return IWebResponse.success(data).to_compatible();
|
|
51
|
+
}
|
|
52
|
+
export async function update_herd_credential(client, credential_id, patch) {
|
|
53
|
+
const { id: _id, herd_id: _hid, created_at: _ca, ...updateData } = patch;
|
|
54
|
+
if (Object.keys(updateData).length === 0) {
|
|
55
|
+
return IWebResponse.error("No valid fields to update").to_compatible();
|
|
56
|
+
}
|
|
57
|
+
const { data, error } = await client
|
|
58
|
+
.from("herd_credentials")
|
|
59
|
+
.update(updateData)
|
|
60
|
+
.eq("id", credential_id)
|
|
61
|
+
.select("*")
|
|
62
|
+
.single();
|
|
63
|
+
if (error) {
|
|
64
|
+
return IWebResponse.error(error.message).to_compatible();
|
|
65
|
+
}
|
|
66
|
+
if (!data) {
|
|
67
|
+
return IWebResponse.error("Herd credential not found").to_compatible();
|
|
68
|
+
}
|
|
69
|
+
return IWebResponse.success(data).to_compatible();
|
|
70
|
+
}
|
|
71
|
+
export async function delete_herd_credential(client, credential_id) {
|
|
72
|
+
const { data, error } = await client
|
|
73
|
+
.from("herd_credentials")
|
|
74
|
+
.delete()
|
|
75
|
+
.eq("id", credential_id)
|
|
76
|
+
.select("*")
|
|
77
|
+
.single();
|
|
78
|
+
if (error) {
|
|
79
|
+
return IWebResponse.error(error.message).to_compatible();
|
|
80
|
+
}
|
|
81
|
+
if (!data) {
|
|
82
|
+
return IWebResponse.error("Herd credential not found").to_compatible();
|
|
83
|
+
}
|
|
84
|
+
return IWebResponse.success(data).to_compatible();
|
|
85
|
+
}
|
package/dist/helpers/herds.js
CHANGED
|
@@ -1,7 +1,18 @@
|
|
|
1
1
|
"use server";
|
|
2
|
+
import { createHash } from "crypto";
|
|
2
3
|
import { newServerClient } from "../supabase/server";
|
|
3
4
|
import { EnumWebResponse, IWebResponse, } from "../types/requests";
|
|
4
|
-
import {
|
|
5
|
+
import { LABELS } from "../constants/annotator";
|
|
6
|
+
import { get_devices_by_herd } from "./devices";
|
|
7
|
+
import { server_get_plans_by_herd_ids } from "./plans";
|
|
8
|
+
import { server_get_layers_by_herd_ids } from "./layers";
|
|
9
|
+
import { server_get_providers_by_herd_ids } from "./providers";
|
|
10
|
+
import { server_get_users_with_herd_access_batch } from "./users";
|
|
11
|
+
import { get_parts_by_herd_ids } from "./parts";
|
|
12
|
+
import { server_get_more_zones_and_actions_for_herd } from "./zones";
|
|
13
|
+
import { server_list_api_keys_batch } from "../api_keys/actions";
|
|
14
|
+
import { server_get_session_summaries_by_herd } from "./session_summaries";
|
|
15
|
+
import { server_get_session_usage_over_time_by_herd } from "./sessions";
|
|
5
16
|
export async function get_herds(client) {
|
|
6
17
|
const { data: herds } = await client.from("herds").select();
|
|
7
18
|
if (!herds) {
|
|
@@ -45,7 +56,7 @@ export async function get_herd_by_slug(slug) {
|
|
|
45
56
|
}
|
|
46
57
|
export async function deleteHerd(herd_id) {
|
|
47
58
|
const supabase = await newServerClient();
|
|
48
|
-
const { error } = await supabase.from("herds").delete().match({ id:
|
|
59
|
+
const { error } = await supabase.from("herds").delete().match({ id: herd_id });
|
|
49
60
|
if (error) {
|
|
50
61
|
return {
|
|
51
62
|
status: EnumWebResponse.ERROR,
|
|
@@ -71,12 +82,17 @@ export async function createHerd(newHerd) {
|
|
|
71
82
|
return IWebResponse.success(true).to_compatible();
|
|
72
83
|
}
|
|
73
84
|
}
|
|
85
|
+
// Stable hash of modules (queries return rows in a deterministic DB order), minus
|
|
86
|
+
// the per-fetch timestamp, so the client can skip no-op updates without a deep walk.
|
|
87
|
+
function hashHerdModules(modules) {
|
|
88
|
+
const stable = modules.map(({ timestamp_last_refreshed: _ts, ...rest }) => rest);
|
|
89
|
+
return createHash("sha1").update(JSON.stringify(stable)).digest("hex");
|
|
90
|
+
}
|
|
74
91
|
export async function server_load_herd_modules() {
|
|
75
92
|
const startTime = Date.now();
|
|
76
|
-
const
|
|
77
|
-
const herdsResult = await get_herds_with_location(
|
|
78
|
-
if (herdsResult.status !== EnumWebResponse.SUCCESS ||
|
|
79
|
-
!herdsResult.data) {
|
|
93
|
+
const client = await newServerClient();
|
|
94
|
+
const herdsResult = await get_herds_with_location(client);
|
|
95
|
+
if (herdsResult.status !== EnumWebResponse.SUCCESS || !herdsResult.data) {
|
|
80
96
|
return {
|
|
81
97
|
status: EnumWebResponse.ERROR,
|
|
82
98
|
msg: herdsResult.msg ?? "Failed to load herds",
|
|
@@ -84,26 +100,88 @@ export async function server_load_herd_modules() {
|
|
|
84
100
|
time_finished: Date.now(),
|
|
85
101
|
time_sent: Date.now(),
|
|
86
102
|
server_processing_time_ms: Date.now() - startTime,
|
|
103
|
+
content_hash: "",
|
|
87
104
|
};
|
|
88
105
|
}
|
|
89
106
|
const herds = herdsResult.data.filter((h) => h.id != null);
|
|
90
|
-
const endTime = Date.now();
|
|
91
|
-
const totalLoadTime = endTime - startTime;
|
|
92
107
|
if (herds.length === 0) {
|
|
93
|
-
|
|
108
|
+
const endTime = Date.now();
|
|
109
|
+
console.log(`[server_load_herd_modules] No accessible herds (${endTime - startTime}ms)`);
|
|
94
110
|
return {
|
|
95
111
|
status: EnumWebResponse.SUCCESS,
|
|
96
112
|
msg: "No herds accessible",
|
|
97
113
|
data: [],
|
|
98
114
|
time_finished: endTime,
|
|
99
115
|
time_sent: endTime,
|
|
100
|
-
server_processing_time_ms:
|
|
116
|
+
server_processing_time_ms: endTime - startTime,
|
|
117
|
+
content_hash: hashHerdModules([]),
|
|
101
118
|
};
|
|
102
119
|
}
|
|
103
|
-
const
|
|
104
|
-
|
|
105
|
-
const
|
|
106
|
-
|
|
120
|
+
const herdIds = herds.map((h) => h.id);
|
|
121
|
+
// Run a per-herd RPC across all herds in parallel, tolerating individual failures.
|
|
122
|
+
const perHerd = (fn) => Promise.all(herds.map((h) => fn(h.id).catch(() => ({
|
|
123
|
+
status: EnumWebResponse.ERROR,
|
|
124
|
+
msg: "",
|
|
125
|
+
data: null,
|
|
126
|
+
}))));
|
|
127
|
+
const grouped = (p) => p.then((r) => r.data ?? {}).catch(() => ({}));
|
|
128
|
+
const [plansByHerd, layersByHerd, providersByHerd, usersByHerd, partsByDevice, devicesResults, zonesResults, summariesResults, usageResults,] = await Promise.all([
|
|
129
|
+
grouped(server_get_plans_by_herd_ids(herdIds, client)),
|
|
130
|
+
grouped(server_get_layers_by_herd_ids(herdIds, client)),
|
|
131
|
+
grouped(server_get_providers_by_herd_ids(herdIds, client)),
|
|
132
|
+
server_get_users_with_herd_access_batch(herdIds, client)
|
|
133
|
+
.then((r) => (r.status === EnumWebResponse.SUCCESS ? r.data : null))
|
|
134
|
+
.catch(() => null),
|
|
135
|
+
grouped(get_parts_by_herd_ids(client, herdIds)),
|
|
136
|
+
perHerd((id) => get_devices_by_herd(id, client)),
|
|
137
|
+
perHerd((id) => server_get_more_zones_and_actions_for_herd(id, 0, 10, client)),
|
|
138
|
+
perHerd((id) => server_get_session_summaries_by_herd(id, client)),
|
|
139
|
+
perHerd((id) => server_get_session_usage_over_time_by_herd(id, client)),
|
|
140
|
+
]);
|
|
141
|
+
const devicesByHerdIndex = devicesResults.map((res) => res.status === EnumWebResponse.SUCCESS && res.data ? res.data : []);
|
|
142
|
+
const allDevices = devicesByHerdIndex.flat();
|
|
143
|
+
const allDeviceIds = allDevices.map((device) => device.id ?? 0);
|
|
144
|
+
let apiKeysByDevice = {};
|
|
145
|
+
if (allDeviceIds.length > 0) {
|
|
146
|
+
try {
|
|
147
|
+
apiKeysByDevice = await server_list_api_keys_batch(allDeviceIds, client);
|
|
148
|
+
}
|
|
149
|
+
catch (error) {
|
|
150
|
+
console.error(`[server_load_herd_modules] Failed to load API keys:`, error);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
for (const device of allDevices) {
|
|
154
|
+
const deviceId = device.id ?? 0;
|
|
155
|
+
device.api_keys_scout = apiKeysByDevice[deviceId] || [];
|
|
156
|
+
device.parts = partsByDevice[deviceId] || [];
|
|
157
|
+
}
|
|
158
|
+
const serialized_herd_modules = herds.map((herd, index) => {
|
|
159
|
+
const zonesRes = zonesResults[index];
|
|
160
|
+
const summariesRes = summariesResults[index];
|
|
161
|
+
const usageRes = usageResults[index];
|
|
162
|
+
return {
|
|
163
|
+
herd,
|
|
164
|
+
devices: devicesByHerdIndex[index],
|
|
165
|
+
timestamp_last_refreshed: Date.now(),
|
|
166
|
+
user_roles: usersByHerd ? usersByHerd[herd.id] ?? [] : null,
|
|
167
|
+
labels: LABELS,
|
|
168
|
+
plans: plansByHerd[herd.id] ?? [],
|
|
169
|
+
zones: zonesRes.status === EnumWebResponse.SUCCESS && zonesRes.data
|
|
170
|
+
? zonesRes.data
|
|
171
|
+
: [],
|
|
172
|
+
layers: layersByHerd[herd.id] ?? [],
|
|
173
|
+
providers: providersByHerd[herd.id] ?? [],
|
|
174
|
+
session_summaries: summariesRes.status === EnumWebResponse.SUCCESS && summariesRes.data
|
|
175
|
+
? summariesRes.data
|
|
176
|
+
: null,
|
|
177
|
+
session_usage: usageRes.status === EnumWebResponse.SUCCESS && usageRes.data
|
|
178
|
+
? usageRes.data
|
|
179
|
+
: null,
|
|
180
|
+
};
|
|
181
|
+
});
|
|
182
|
+
const endTime = Date.now();
|
|
183
|
+
const totalLoadTime = endTime - startTime;
|
|
184
|
+
console.log(`[server_load_herd_modules] Loaded ${herds.length} herds in ${totalLoadTime}ms (batched queries)`);
|
|
107
185
|
return {
|
|
108
186
|
status: EnumWebResponse.SUCCESS,
|
|
109
187
|
msg: "Herd modules loaded successfully",
|
|
@@ -111,5 +189,6 @@ export async function server_load_herd_modules() {
|
|
|
111
189
|
time_finished: endTime,
|
|
112
190
|
time_sent: endTime,
|
|
113
191
|
server_processing_time_ms: totalLoadTime,
|
|
192
|
+
content_hash: hashHerdModules(serialized_herd_modules),
|
|
114
193
|
};
|
|
115
194
|
}
|
package/dist/helpers/index.d.ts
CHANGED
|
@@ -3,7 +3,8 @@ export * from "./auth";
|
|
|
3
3
|
export * from "./bounding_boxes";
|
|
4
4
|
export * from "./chat";
|
|
5
5
|
export * from "./certificates";
|
|
6
|
-
export * from "./
|
|
6
|
+
export * from "./user_credentials";
|
|
7
|
+
export * from "./herd_credentials";
|
|
7
8
|
export * from "./db";
|
|
8
9
|
export * from "./devices";
|
|
9
10
|
export * from "./email";
|
package/dist/helpers/index.js
CHANGED
|
@@ -3,7 +3,8 @@ export * from "./auth";
|
|
|
3
3
|
export * from "./bounding_boxes";
|
|
4
4
|
export * from "./chat";
|
|
5
5
|
export * from "./certificates";
|
|
6
|
-
export * from "./
|
|
6
|
+
export * from "./user_credentials";
|
|
7
|
+
export * from "./herd_credentials";
|
|
7
8
|
export * from "./db";
|
|
8
9
|
export * from "./devices";
|
|
9
10
|
export * from "./email";
|
package/dist/helpers/layers.d.ts
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import { Database } from "../types/supabase";
|
|
1
2
|
import { ILayer } from "../types/db";
|
|
2
3
|
import { IWebResponseCompatible } from "../types/requests";
|
|
4
|
+
import { SupabaseClient } from "@supabase/supabase-js";
|
|
3
5
|
export declare function server_get_layers_by_herd(herd_id: number): Promise<IWebResponseCompatible<ILayer[]>>;
|
|
6
|
+
export declare function server_get_layers_by_herd_ids(herd_ids: number[], client: SupabaseClient<Database>): Promise<IWebResponseCompatible<Record<number, ILayer[]>>>;
|
package/dist/helpers/layers.js
CHANGED
|
@@ -19,3 +19,23 @@ export async function server_get_layers_by_herd(herd_id) {
|
|
|
19
19
|
return IWebResponse.success(data).to_compatible();
|
|
20
20
|
}
|
|
21
21
|
}
|
|
22
|
+
// Fetches layers for many herds in one query, grouped by herd_id.
|
|
23
|
+
export async function server_get_layers_by_herd_ids(herd_ids, client) {
|
|
24
|
+
var _a;
|
|
25
|
+
if (herd_ids.length === 0) {
|
|
26
|
+
return IWebResponse.success({}).to_compatible();
|
|
27
|
+
}
|
|
28
|
+
const { data, error } = await client
|
|
29
|
+
.from("layers")
|
|
30
|
+
.select("*")
|
|
31
|
+
.in("herd_id", herd_ids)
|
|
32
|
+
.order("id", { ascending: true });
|
|
33
|
+
if (error) {
|
|
34
|
+
return { status: EnumWebResponse.ERROR, msg: error.message, data: null };
|
|
35
|
+
}
|
|
36
|
+
const grouped = {};
|
|
37
|
+
for (const row of data ?? []) {
|
|
38
|
+
(grouped[_a = row.herd_id] ?? (grouped[_a] = [])).push(row);
|
|
39
|
+
}
|
|
40
|
+
return IWebResponse.success(grouped).to_compatible();
|
|
41
|
+
}
|
package/dist/helpers/parts.d.ts
CHANGED
|
@@ -75,6 +75,13 @@ export declare function get_parts_by_certificate_id(client: SupabaseClient<Datab
|
|
|
75
75
|
* @param herd_id - ID of the herd to get parts for
|
|
76
76
|
*/
|
|
77
77
|
export declare function get_parts_by_herd_id(client: SupabaseClient<Database>, herd_id: number): Promise<IWebResponseCompatible<IPart[]>>;
|
|
78
|
+
/**
|
|
79
|
+
* Retrieves active parts for all devices across many herds in one query,
|
|
80
|
+
* grouped by device_id.
|
|
81
|
+
* @param client - Supabase client instance
|
|
82
|
+
* @param herd_ids - IDs of the herds to get parts for
|
|
83
|
+
*/
|
|
84
|
+
export declare function get_parts_by_herd_ids(client: SupabaseClient<Database>, herd_ids: number[]): Promise<IWebResponseCompatible<Record<number, IPart[]>>>;
|
|
78
85
|
/**
|
|
79
86
|
* Restores a deleted part to active lifecycle
|
|
80
87
|
* @param client - Supabase client instance
|
package/dist/helpers/parts.js
CHANGED
|
@@ -238,6 +238,38 @@ export async function get_parts_by_herd_id(client, herd_id) {
|
|
|
238
238
|
}
|
|
239
239
|
return IWebResponse.success(data).to_compatible();
|
|
240
240
|
}
|
|
241
|
+
/**
|
|
242
|
+
* Retrieves active parts for all devices across many herds in one query,
|
|
243
|
+
* grouped by device_id.
|
|
244
|
+
* @param client - Supabase client instance
|
|
245
|
+
* @param herd_ids - IDs of the herds to get parts for
|
|
246
|
+
*/
|
|
247
|
+
export async function get_parts_by_herd_ids(client, herd_ids) {
|
|
248
|
+
var _a;
|
|
249
|
+
if (herd_ids.length === 0) {
|
|
250
|
+
return IWebResponse.success({}).to_compatible();
|
|
251
|
+
}
|
|
252
|
+
const { data, error } = await client
|
|
253
|
+
.from("parts")
|
|
254
|
+
.select(`
|
|
255
|
+
*,
|
|
256
|
+
devices!parts_device_id_fkey(herd_id)
|
|
257
|
+
`)
|
|
258
|
+
.in("devices.herd_id", herd_ids)
|
|
259
|
+
.eq("lifecycle", "active")
|
|
260
|
+
.order("created_at", { ascending: false })
|
|
261
|
+
.order("id", { ascending: true });
|
|
262
|
+
if (error) {
|
|
263
|
+
return IWebResponse.error(error.message).to_compatible();
|
|
264
|
+
}
|
|
265
|
+
const grouped = {};
|
|
266
|
+
for (const row of data ?? []) {
|
|
267
|
+
if (row.device_id == null)
|
|
268
|
+
continue;
|
|
269
|
+
(grouped[_a = row.device_id] ?? (grouped[_a] = [])).push(row);
|
|
270
|
+
}
|
|
271
|
+
return IWebResponse.success(grouped).to_compatible();
|
|
272
|
+
}
|
|
241
273
|
/**
|
|
242
274
|
* Restores a deleted part to active lifecycle
|
|
243
275
|
* @param client - Supabase client instance
|
package/dist/helpers/plans.d.ts
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
|
+
import { Database } from "../types/supabase";
|
|
1
2
|
import { IPlan } from "../types/db";
|
|
2
3
|
import { IWebResponseCompatible } from "../types/requests";
|
|
4
|
+
import { SupabaseClient } from "@supabase/supabase-js";
|
|
3
5
|
export declare function server_get_plans_by_herd(herd_id: number): Promise<IWebResponseCompatible<IPlan[]>>;
|
|
6
|
+
export declare function server_get_plans_by_herd_ids(herd_ids: number[], client: SupabaseClient<Database>): Promise<IWebResponseCompatible<Record<number, IPlan[]>>>;
|
|
4
7
|
export declare function server_create_plans(plans: IPlan[]): Promise<IWebResponseCompatible<IPlan[]>>;
|
|
5
8
|
export declare function server_delete_plans_by_ids(plan_ids: number[]): Promise<IWebResponseCompatible<boolean>>;
|
package/dist/helpers/plans.js
CHANGED
|
@@ -19,6 +19,26 @@ export async function server_get_plans_by_herd(herd_id) {
|
|
|
19
19
|
return IWebResponse.success(data).to_compatible();
|
|
20
20
|
}
|
|
21
21
|
}
|
|
22
|
+
// Fetches plans for many herds in one query, grouped by herd_id.
|
|
23
|
+
export async function server_get_plans_by_herd_ids(herd_ids, client) {
|
|
24
|
+
var _a;
|
|
25
|
+
if (herd_ids.length === 0) {
|
|
26
|
+
return IWebResponse.success({}).to_compatible();
|
|
27
|
+
}
|
|
28
|
+
const { data, error } = await client
|
|
29
|
+
.from("plans")
|
|
30
|
+
.select("*")
|
|
31
|
+
.in("herd_id", herd_ids)
|
|
32
|
+
.order("id", { ascending: true });
|
|
33
|
+
if (error) {
|
|
34
|
+
return { status: EnumWebResponse.ERROR, msg: error.message, data: null };
|
|
35
|
+
}
|
|
36
|
+
const grouped = {};
|
|
37
|
+
for (const row of data ?? []) {
|
|
38
|
+
(grouped[_a = row.herd_id] ?? (grouped[_a] = [])).push(row);
|
|
39
|
+
}
|
|
40
|
+
return IWebResponse.success(grouped).to_compatible();
|
|
41
|
+
}
|
|
22
42
|
// function that uploads plan to our db
|
|
23
43
|
export async function server_create_plans(plans) {
|
|
24
44
|
// loop through plans and format
|
|
@@ -1,6 +1,9 @@
|
|
|
1
|
+
import { Database } from "../types/supabase";
|
|
1
2
|
import { IProvider } from "../types/db";
|
|
2
3
|
import { IWebResponseCompatible } from "../types/requests";
|
|
4
|
+
import { SupabaseClient } from "@supabase/supabase-js";
|
|
3
5
|
export declare function server_get_providers_by_herd(herd_id: number): Promise<IWebResponseCompatible<IProvider[]>>;
|
|
6
|
+
export declare function server_get_providers_by_herd_ids(herd_ids: number[], client: SupabaseClient<Database>): Promise<IWebResponseCompatible<Record<number, IProvider[]>>>;
|
|
4
7
|
export declare function server_create_provider(provider: Omit<IProvider, "id" | "created_at">): Promise<IWebResponseCompatible<IProvider>>;
|
|
5
8
|
export declare function server_update_provider(provider_id: number, updates: Partial<Omit<IProvider, "id" | "created_at">>): Promise<IWebResponseCompatible<IProvider>>;
|
|
6
9
|
export declare function server_delete_providers_by_ids(provider_ids: number[]): Promise<IWebResponseCompatible<boolean>>;
|
|
@@ -19,6 +19,26 @@ export async function server_get_providers_by_herd(herd_id) {
|
|
|
19
19
|
return IWebResponse.success(data).to_compatible();
|
|
20
20
|
}
|
|
21
21
|
}
|
|
22
|
+
// Fetches providers for many herds in one query, grouped by herd_id.
|
|
23
|
+
export async function server_get_providers_by_herd_ids(herd_ids, client) {
|
|
24
|
+
var _a;
|
|
25
|
+
if (herd_ids.length === 0) {
|
|
26
|
+
return IWebResponse.success({}).to_compatible();
|
|
27
|
+
}
|
|
28
|
+
const { data, error } = await client
|
|
29
|
+
.from("providers")
|
|
30
|
+
.select("*")
|
|
31
|
+
.in("herd_id", herd_ids)
|
|
32
|
+
.order("id", { ascending: true });
|
|
33
|
+
if (error) {
|
|
34
|
+
return { status: EnumWebResponse.ERROR, msg: error.message, data: null };
|
|
35
|
+
}
|
|
36
|
+
const grouped = {};
|
|
37
|
+
for (const row of data ?? []) {
|
|
38
|
+
(grouped[_a = row.herd_id] ?? (grouped[_a] = [])).push(row);
|
|
39
|
+
}
|
|
40
|
+
return IWebResponse.success(grouped).to_compatible();
|
|
41
|
+
}
|
|
22
42
|
// function that creates a new provider in our db
|
|
23
43
|
export async function server_create_provider(provider) {
|
|
24
44
|
const supabase = await newServerClient();
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { Database } from "../types/supabase";
|
|
2
|
+
import { CredentialQueryArgs, IUserCredential, UserCredentialInsert, UserCredentialUpdate } from "../types/db";
|
|
3
|
+
import { IWebResponseCompatible } from "../types/requests";
|
|
4
|
+
import { SupabaseClient } from "@supabase/supabase-js";
|
|
5
|
+
export declare function get_user_credentials_by_user_id(client: SupabaseClient<Database>, user_id: string, args?: CredentialQueryArgs): Promise<IWebResponseCompatible<IUserCredential[]>>;
|
|
6
|
+
export declare function get_user_credential_by_id(client: SupabaseClient<Database>, credential_id: number): Promise<IWebResponseCompatible<IUserCredential | null>>;
|
|
7
|
+
export declare function create_user_credential(client: SupabaseClient<Database>, row: UserCredentialInsert): Promise<IWebResponseCompatible<IUserCredential | null>>;
|
|
8
|
+
export declare function update_user_credential(client: SupabaseClient<Database>, credential_id: number, patch: UserCredentialUpdate): Promise<IWebResponseCompatible<IUserCredential | null>>;
|
|
9
|
+
export declare function delete_user_credential(client: SupabaseClient<Database>, credential_id: number): Promise<IWebResponseCompatible<IUserCredential | null>>;
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { IWebResponse } from "../types/requests";
|
|
2
|
+
export async function get_user_credentials_by_user_id(client, user_id, args) {
|
|
3
|
+
let query = client
|
|
4
|
+
.from("user_credentials")
|
|
5
|
+
.select("*")
|
|
6
|
+
.eq("user_id", user_id);
|
|
7
|
+
if (args?.type)
|
|
8
|
+
query = query.eq("type", args.type);
|
|
9
|
+
const { data, error } = await query.order("created_at", { ascending: false });
|
|
10
|
+
if (error) {
|
|
11
|
+
return IWebResponse.error(error.message).to_compatible();
|
|
12
|
+
}
|
|
13
|
+
return IWebResponse.success(data ?? []).to_compatible();
|
|
14
|
+
}
|
|
15
|
+
export async function get_user_credential_by_id(client, credential_id) {
|
|
16
|
+
const { data, error } = await client
|
|
17
|
+
.from("user_credentials")
|
|
18
|
+
.select("*")
|
|
19
|
+
.eq("id", credential_id)
|
|
20
|
+
.single();
|
|
21
|
+
if (error) {
|
|
22
|
+
return IWebResponse.error(error.message).to_compatible();
|
|
23
|
+
}
|
|
24
|
+
if (!data) {
|
|
25
|
+
return IWebResponse.error("User credential not found").to_compatible();
|
|
26
|
+
}
|
|
27
|
+
return IWebResponse.success(data).to_compatible();
|
|
28
|
+
}
|
|
29
|
+
export async function create_user_credential(client, row) {
|
|
30
|
+
if (!row.user_id) {
|
|
31
|
+
return IWebResponse.error("user_id is required").to_compatible();
|
|
32
|
+
}
|
|
33
|
+
if (!row.issuer?.trim()) {
|
|
34
|
+
return IWebResponse.error("issuer is required").to_compatible();
|
|
35
|
+
}
|
|
36
|
+
if (!row.type?.trim()) {
|
|
37
|
+
return IWebResponse.error("type is required").to_compatible();
|
|
38
|
+
}
|
|
39
|
+
const { data, error } = await client
|
|
40
|
+
.from("user_credentials")
|
|
41
|
+
.insert([row])
|
|
42
|
+
.select("*")
|
|
43
|
+
.single();
|
|
44
|
+
if (error) {
|
|
45
|
+
return IWebResponse.error(error.message).to_compatible();
|
|
46
|
+
}
|
|
47
|
+
if (!data) {
|
|
48
|
+
return IWebResponse.error("Failed to create user credential").to_compatible();
|
|
49
|
+
}
|
|
50
|
+
return IWebResponse.success(data).to_compatible();
|
|
51
|
+
}
|
|
52
|
+
export async function update_user_credential(client, credential_id, patch) {
|
|
53
|
+
const { id: _id, user_id: _uid, created_at: _ca, ...updateData } = patch;
|
|
54
|
+
if (Object.keys(updateData).length === 0) {
|
|
55
|
+
return IWebResponse.error("No valid fields to update").to_compatible();
|
|
56
|
+
}
|
|
57
|
+
const { data, error } = await client
|
|
58
|
+
.from("user_credentials")
|
|
59
|
+
.update(updateData)
|
|
60
|
+
.eq("id", credential_id)
|
|
61
|
+
.select("*")
|
|
62
|
+
.single();
|
|
63
|
+
if (error) {
|
|
64
|
+
return IWebResponse.error(error.message).to_compatible();
|
|
65
|
+
}
|
|
66
|
+
if (!data) {
|
|
67
|
+
return IWebResponse.error("User credential not found").to_compatible();
|
|
68
|
+
}
|
|
69
|
+
return IWebResponse.success(data).to_compatible();
|
|
70
|
+
}
|
|
71
|
+
export async function delete_user_credential(client, credential_id) {
|
|
72
|
+
const { data, error } = await client
|
|
73
|
+
.from("user_credentials")
|
|
74
|
+
.delete()
|
|
75
|
+
.eq("id", credential_id)
|
|
76
|
+
.select("*")
|
|
77
|
+
.single();
|
|
78
|
+
if (error) {
|
|
79
|
+
return IWebResponse.error(error.message).to_compatible();
|
|
80
|
+
}
|
|
81
|
+
if (!data) {
|
|
82
|
+
return IWebResponse.error("User credential not found").to_compatible();
|
|
83
|
+
}
|
|
84
|
+
return IWebResponse.success(data).to_compatible();
|
|
85
|
+
}
|
package/dist/helpers/users.d.ts
CHANGED
|
@@ -5,6 +5,7 @@ import { Database } from "../types/supabase";
|
|
|
5
5
|
export declare function server_get_user_roles(herd_id: number): Promise<IWebResponseCompatible<IUserRolePerHerd[]>>;
|
|
6
6
|
export declare function server_get_user(): Promise<IWebResponseCompatible<IUser | null>>;
|
|
7
7
|
export declare function server_get_users_with_herd_access(herd_id: number, supabaseClient?: SupabaseClient): Promise<IWebResponseCompatible<IUserAndRole[]>>;
|
|
8
|
+
export declare function server_get_users_with_herd_access_batch(herd_ids: number[], client: SupabaseClient): Promise<IWebResponseCompatible<Record<number, IUserAndRole[]>>>;
|
|
8
9
|
export declare function server_upsert_user_herd_role(herd_id: number, username: string, herd_role_id: number): Promise<IWebResponseCompatible<IUserAndRole | null>>;
|
|
9
10
|
export type UserProfileUpdate = Database["public"]["Tables"]["users"]["Update"];
|
|
10
11
|
export declare function update_user_profile(client: SupabaseClient<Database>, user_id: string, patch: UserProfileUpdate): Promise<IWebResponseCompatible<IUserProfileRow | null>>;
|
package/dist/helpers/users.js
CHANGED
|
@@ -49,6 +49,36 @@ export async function server_get_users_with_herd_access(herd_id, supabaseClient)
|
|
|
49
49
|
}));
|
|
50
50
|
return IWebResponse.success(transformedData).to_compatible();
|
|
51
51
|
}
|
|
52
|
+
// Fetches users-with-role for many herds in one query, grouped by herd_id.
|
|
53
|
+
export async function server_get_users_with_herd_access_batch(herd_ids, client) {
|
|
54
|
+
var _a;
|
|
55
|
+
if (herd_ids.length === 0) {
|
|
56
|
+
return IWebResponse.success({}).to_compatible();
|
|
57
|
+
}
|
|
58
|
+
const { data, error } = await client
|
|
59
|
+
.from("users_roles_per_herd")
|
|
60
|
+
.select(`
|
|
61
|
+
herd_id,
|
|
62
|
+
herd_role_id,
|
|
63
|
+
herd_roles (*),
|
|
64
|
+
users!users_roles_per_herd_user_id_fkey (*)
|
|
65
|
+
`)
|
|
66
|
+
.in("herd_id", herd_ids)
|
|
67
|
+
.order("herd_id", { ascending: true })
|
|
68
|
+
.order("user_id", { ascending: true });
|
|
69
|
+
if (error) {
|
|
70
|
+
return { status: EnumWebResponse.ERROR, msg: error.message, data: null };
|
|
71
|
+
}
|
|
72
|
+
const grouped = {};
|
|
73
|
+
for (const item of (data ?? [])) {
|
|
74
|
+
(grouped[_a = item.herd_id] ?? (grouped[_a] = [])).push({
|
|
75
|
+
user: item.users,
|
|
76
|
+
herd_role_id: item.herd_role_id,
|
|
77
|
+
herd_role: item.herd_roles,
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
return IWebResponse.success(grouped).to_compatible();
|
|
81
|
+
}
|
|
52
82
|
export async function server_upsert_user_herd_role(herd_id, username, herd_role_id) {
|
|
53
83
|
const supabase = await newServerClient();
|
|
54
84
|
const { data: user, error: user_error } = await supabase
|
package/dist/helpers/zones.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { IZoneWithActions } from "../types/db";
|
|
2
2
|
import { IWebResponseCompatible } from "../types/requests";
|
|
3
|
+
import { SupabaseClient } from "@supabase/supabase-js";
|
|
3
4
|
/**
|
|
4
5
|
* Get more zones and actions for a herd
|
|
5
6
|
* @param herd_id - The ID of the herd to get zones and actions for
|
|
@@ -8,7 +9,7 @@ import { IWebResponseCompatible } from "../types/requests";
|
|
|
8
9
|
* @returns A list of zones and actions
|
|
9
10
|
* @throws An error if the zones or actions are not fetched
|
|
10
11
|
*/
|
|
11
|
-
export declare function server_get_more_zones_and_actions_for_herd(herd_id: number, offset: number, page_count?: number): Promise<IWebResponseCompatible<IZoneWithActions[]>>;
|
|
12
|
+
export declare function server_get_more_zones_and_actions_for_herd(herd_id: number, offset: number, page_count?: number, client?: SupabaseClient): Promise<IWebResponseCompatible<IZoneWithActions[]>>;
|
|
12
13
|
/**
|
|
13
14
|
* Create zones and actions for a herd
|
|
14
15
|
* @param zones - The zones to create
|
package/dist/helpers/zones.js
CHANGED
|
@@ -8,10 +8,10 @@ import { EnumWebResponse, IWebResponse, } from "../types/requests";
|
|
|
8
8
|
* @returns A list of zones and actions
|
|
9
9
|
* @throws An error if the zones or actions are not fetched
|
|
10
10
|
*/
|
|
11
|
-
export async function server_get_more_zones_and_actions_for_herd(herd_id, offset, page_count = 10) {
|
|
11
|
+
export async function server_get_more_zones_and_actions_for_herd(herd_id, offset, page_count = 10, client) {
|
|
12
12
|
const from = offset * page_count;
|
|
13
13
|
const to = from + page_count - 1;
|
|
14
|
-
const supabase = await newServerClient();
|
|
14
|
+
const supabase = client || (await newServerClient());
|
|
15
15
|
// make rpc call to get_events_with_tags_for_herd(herd_id, offset, limit)
|
|
16
16
|
const { data, error } = await supabase.rpc("get_zones_and_actions_for_herd", {
|
|
17
17
|
herd_id_caller: herd_id,
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { SupabaseClient } from "@supabase/supabase-js";
|
|
2
|
+
import type { IDevice } from "../types/db";
|
|
3
|
+
import type { IHerdModule } from "../types/herd_module";
|
|
4
|
+
export declare function primeDeviceDisplayNameCache(devices: Iterable<IDevice>): void;
|
|
5
|
+
export declare function useDeviceDisplayName(deviceId: number | null | undefined, options?: {
|
|
6
|
+
herdModules?: IHerdModule[];
|
|
7
|
+
supabase?: SupabaseClient;
|
|
8
|
+
}): string | null;
|