@adventurelabs/scout-core 1.4.73 → 1.4.75

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.
@@ -0,0 +1,10 @@
1
+ import { SupabaseClient } from "@supabase/supabase-js";
2
+ import { Database, Json } from "../types/supabase";
3
+ import { IWebResponseCompatible } from "../types/requests";
4
+ export type ClientAbilitiesPublicJwk = Record<string, Json | undefined> & {
5
+ kty: string;
6
+ kid?: string;
7
+ };
8
+ /** Register or rotate a verification key (service_role or platform superadmin). */
9
+ export declare function server_upsert_client_abilities_jwt_public_key(kid: string, public_jwk: ClientAbilitiesPublicJwk, supabaseClient?: SupabaseClient<Database>): Promise<IWebResponseCompatible<null>>;
10
+ export declare function server_revoke_client_abilities_jwt_public_key(kid: string, supabaseClient?: SupabaseClient<Database>): Promise<IWebResponseCompatible<null>>;
@@ -0,0 +1,25 @@
1
+ "use server";
2
+ import { IWebResponse } from "../types/requests";
3
+ import { newServerClient } from "../supabase/server";
4
+ /** Register or rotate a verification key (service_role or platform superadmin). */
5
+ export async function server_upsert_client_abilities_jwt_public_key(kid, public_jwk, supabaseClient) {
6
+ const supabase = supabaseClient ?? (await newServerClient());
7
+ const { error } = await supabase.rpc("upsert_client_abilities_jwt_public_key", {
8
+ p_kid: kid,
9
+ p_public_jwk: public_jwk,
10
+ });
11
+ if (error) {
12
+ return IWebResponse.error(error.message).to_compatible();
13
+ }
14
+ return IWebResponse.success(null).to_compatible();
15
+ }
16
+ export async function server_revoke_client_abilities_jwt_public_key(kid, supabaseClient) {
17
+ const supabase = supabaseClient ?? (await newServerClient());
18
+ const { error } = await supabase.rpc("revoke_client_abilities_jwt_public_key", {
19
+ p_kid: kid,
20
+ });
21
+ if (error) {
22
+ return IWebResponse.error(error.message).to_compatible();
23
+ }
24
+ return IWebResponse.success(null).to_compatible();
25
+ }
@@ -0,0 +1,8 @@
1
+ import { SupabaseClient } from "@supabase/supabase-js";
2
+ import { Database } from "../types/supabase";
3
+ import { IClientAbilitiesJwtPublicKeyEntry, IClientAbilitiesTokenMint } from "../types/client_abilities_token";
4
+ import { IWebResponseCompatible } from "../types/requests";
5
+ export declare function mint_client_abilities_token(client: SupabaseClient<Database>): Promise<IWebResponseCompatible<IClientAbilitiesTokenMint>>;
6
+ export declare function get_client_abilities_jwt_public_keys(client: SupabaseClient<Database>): Promise<IWebResponseCompatible<IClientAbilitiesJwtPublicKeyEntry[]>>;
7
+ /** Cryptographic check only; returns the same mint envelope from the edge. */
8
+ export declare function verify_client_abilities_token(mint: IClientAbilitiesTokenMint, publicKeys: IClientAbilitiesJwtPublicKeyEntry[]): Promise<IClientAbilitiesTokenMint>;
@@ -0,0 +1,54 @@
1
+ import * as jose from "jose";
2
+ import { CLIENT_ABILITIES_JWT_AUDIENCE, } from "../types/client_abilities_token";
3
+ import { IWebResponse } from "../types/requests";
4
+ export async function mint_client_abilities_token(client) {
5
+ const { data, error } = await client.functions.invoke("mint-client-abilities-token", { method: "POST" });
6
+ if (error) {
7
+ return IWebResponse.error(error.message).to_compatible();
8
+ }
9
+ const mint = data;
10
+ if (!mint?.token) {
11
+ return IWebResponse.error("mint-client-abilities-token returned no token").to_compatible();
12
+ }
13
+ return IWebResponse.success(mint).to_compatible();
14
+ }
15
+ export async function get_client_abilities_jwt_public_keys(client) {
16
+ const { data, error } = await client.rpc("get_client_abilities_jwt_public_keys");
17
+ if (error) {
18
+ return IWebResponse.error(error.message).to_compatible();
19
+ }
20
+ const entries = Array.isArray(data) ? data : [];
21
+ const keys = [];
22
+ for (const row of entries) {
23
+ if (row &&
24
+ typeof row === "object" &&
25
+ "kid" in row &&
26
+ "jwk" in row &&
27
+ typeof row.kid === "string" &&
28
+ row.jwk &&
29
+ typeof row.jwk === "object") {
30
+ keys.push({ kid: row.kid, jwk: row.jwk });
31
+ }
32
+ }
33
+ return IWebResponse.success(keys).to_compatible();
34
+ }
35
+ /** Cryptographic check only; returns the same mint envelope from the edge. */
36
+ export async function verify_client_abilities_token(mint, publicKeys) {
37
+ if (publicKeys.length === 0) {
38
+ throw new Error("no client abilities JWT public keys configured");
39
+ }
40
+ const kid = jose.decodeProtectedHeader(mint.token).kid;
41
+ if (!kid || typeof kid !== "string") {
42
+ throw new Error("client abilities JWT missing kid");
43
+ }
44
+ const entry = publicKeys.find((k) => k.kid === kid);
45
+ if (!entry) {
46
+ throw new Error(`unknown client abilities JWT kid: ${kid}`);
47
+ }
48
+ const verifyKey = await jose.importJWK(entry.jwk, "ES256");
49
+ await jose.jwtVerify(mint.token, verifyKey, {
50
+ algorithms: ["ES256"],
51
+ audience: CLIENT_ABILITIES_JWT_AUDIENCE,
52
+ });
53
+ return mint;
54
+ }
@@ -0,0 +1,7 @@
1
+ import { SupabaseClient } from "@supabase/supabase-js";
2
+ import { Database } from "../types/supabase";
3
+ import { IClientAbilitiesTokenMint } from "../types/client_abilities_token";
4
+ import { IWebResponseCompatible } from "../types/requests";
5
+ export declare function server_mint_client_abilities_token(options?: {
6
+ client?: SupabaseClient<Database>;
7
+ }): Promise<IWebResponseCompatible<IClientAbilitiesTokenMint>>;
@@ -0,0 +1,7 @@
1
+ "use server";
2
+ import { newServerClient } from "../supabase/server";
3
+ import { mint_client_abilities_token } from "./client_abilities_token";
4
+ export async function server_mint_client_abilities_token(options) {
5
+ const client = options?.client ?? (await newServerClient());
6
+ return mint_client_abilities_token(client);
7
+ }
@@ -0,0 +1,14 @@
1
+ import { SupabaseClient } from "@supabase/supabase-js";
2
+ import { Database } from "../types/supabase";
3
+ import { IAbility, IHerdRole, IHerdRoleAbilityRow, IHerdRoleWithAbilities } from "../types/db";
4
+ import { IWebResponseCompatible } from "../types/requests";
5
+ export declare function server_list_abilities(supabaseClient?: SupabaseClient<Database>): Promise<IWebResponseCompatible<IAbility[]>>;
6
+ export declare function server_get_herd_roles(herd_id: number, supabaseClient?: SupabaseClient<Database>): Promise<IWebResponseCompatible<IHerdRole[]>>;
7
+ export declare function server_get_herd_roles_with_abilities(herd_id: number, supabaseClient?: SupabaseClient<Database>): Promise<IWebResponseCompatible<IHerdRoleWithAbilities[]>>;
8
+ export declare function server_get_herd_role_by_system_name(herd_id: number, system_name: string, supabaseClient?: SupabaseClient<Database>): Promise<IWebResponseCompatible<IHerdRole | null>>;
9
+ export declare function server_create_herd_role(herd_id: number, system_name: string, name: string, supabaseClient?: SupabaseClient<Database>): Promise<IWebResponseCompatible<IHerdRole | null>>;
10
+ export declare function server_update_herd_role(herd_role_id: number, patch: {
11
+ name?: string;
12
+ }, supabaseClient?: SupabaseClient<Database>): Promise<IWebResponseCompatible<IHerdRole | null>>;
13
+ export declare function server_delete_herd_role(herd_role_id: number, supabaseClient?: SupabaseClient<Database>): Promise<IWebResponseCompatible<null>>;
14
+ export declare function server_set_herd_role_abilities(herd_role_id: number, ability_ids: number[], supabaseClient?: SupabaseClient<Database>): Promise<IWebResponseCompatible<IHerdRoleAbilityRow[]>>;
@@ -0,0 +1,134 @@
1
+ "use server";
2
+ import { IWebResponse } from "../types/requests";
3
+ import { newServerClient } from "../supabase/server";
4
+ export async function server_list_abilities(supabaseClient) {
5
+ const supabase = supabaseClient ?? (await newServerClient());
6
+ const { data, error } = await supabase
7
+ .from("abilities")
8
+ .select("*")
9
+ .order("key", { ascending: true });
10
+ if (error) {
11
+ return IWebResponse.error(error.message).to_compatible();
12
+ }
13
+ return IWebResponse.success(data ?? []).to_compatible();
14
+ }
15
+ export async function server_get_herd_roles(herd_id, supabaseClient) {
16
+ const supabase = supabaseClient ?? (await newServerClient());
17
+ const { data, error } = await supabase
18
+ .from("herd_roles")
19
+ .select("*")
20
+ .eq("herd_id", herd_id)
21
+ .order("system_name", { ascending: true });
22
+ if (error) {
23
+ return IWebResponse.error(error.message).to_compatible();
24
+ }
25
+ return IWebResponse.success(data ?? []).to_compatible();
26
+ }
27
+ export async function server_get_herd_roles_with_abilities(herd_id, supabaseClient) {
28
+ const supabase = supabaseClient ?? (await newServerClient());
29
+ const { data, error } = await supabase
30
+ .from("herd_roles")
31
+ .select(`
32
+ *,
33
+ herd_role_abilities (
34
+ id,
35
+ ability_id,
36
+ abilities (*)
37
+ )
38
+ `)
39
+ .eq("herd_id", herd_id)
40
+ .order("system_name", { ascending: true });
41
+ if (error) {
42
+ return IWebResponse.error(error.message).to_compatible();
43
+ }
44
+ const rows = (data ?? []).map((row) => {
45
+ const { herd_role_abilities: matrix, ...role } = row;
46
+ const links = matrix ?? [];
47
+ return {
48
+ ...role,
49
+ abilities: links
50
+ .map((m) => m.abilities)
51
+ .filter((a) => a != null),
52
+ ability_ids: links.map((m) => m.ability_id),
53
+ };
54
+ });
55
+ return IWebResponse.success(rows).to_compatible();
56
+ }
57
+ export async function server_get_herd_role_by_system_name(herd_id, system_name, supabaseClient) {
58
+ const supabase = supabaseClient ?? (await newServerClient());
59
+ const { data, error } = await supabase
60
+ .from("herd_roles")
61
+ .select("*")
62
+ .eq("herd_id", herd_id)
63
+ .eq("system_name", system_name)
64
+ .maybeSingle();
65
+ if (error) {
66
+ return IWebResponse.error(error.message).to_compatible();
67
+ }
68
+ return IWebResponse.success(data).to_compatible();
69
+ }
70
+ export async function server_create_herd_role(herd_id, system_name, name, supabaseClient) {
71
+ const supabase = supabaseClient ?? (await newServerClient());
72
+ const { data, error } = await supabase
73
+ .from("herd_roles")
74
+ .insert({
75
+ herd_id,
76
+ system_name,
77
+ name,
78
+ is_system: false,
79
+ })
80
+ .select("*")
81
+ .single();
82
+ if (error) {
83
+ return IWebResponse.error(error.message).to_compatible();
84
+ }
85
+ return IWebResponse.success(data).to_compatible();
86
+ }
87
+ export async function server_update_herd_role(herd_role_id, patch, supabaseClient) {
88
+ const supabase = supabaseClient ?? (await newServerClient());
89
+ const { data, error } = await supabase
90
+ .from("herd_roles")
91
+ .update(patch)
92
+ .eq("id", herd_role_id)
93
+ .select("*")
94
+ .single();
95
+ if (error) {
96
+ return IWebResponse.error(error.message).to_compatible();
97
+ }
98
+ return IWebResponse.success(data).to_compatible();
99
+ }
100
+ export async function server_delete_herd_role(herd_role_id, supabaseClient) {
101
+ const supabase = supabaseClient ?? (await newServerClient());
102
+ const { error } = await supabase
103
+ .from("herd_roles")
104
+ .delete()
105
+ .eq("id", herd_role_id);
106
+ if (error) {
107
+ return IWebResponse.error(error.message).to_compatible();
108
+ }
109
+ return IWebResponse.success(null).to_compatible();
110
+ }
111
+ export async function server_set_herd_role_abilities(herd_role_id, ability_ids, supabaseClient) {
112
+ const supabase = supabaseClient ?? (await newServerClient());
113
+ const { error: deleteError } = await supabase
114
+ .from("herd_role_abilities")
115
+ .delete()
116
+ .eq("herd_role_id", herd_role_id);
117
+ if (deleteError) {
118
+ return IWebResponse.error(deleteError.message).to_compatible();
119
+ }
120
+ if (ability_ids.length === 0) {
121
+ return IWebResponse.success([]).to_compatible();
122
+ }
123
+ const { data, error } = await supabase
124
+ .from("herd_role_abilities")
125
+ .insert(ability_ids.map((ability_id) => ({
126
+ herd_role_id,
127
+ ability_id,
128
+ })))
129
+ .select("*");
130
+ if (error) {
131
+ return IWebResponse.error(error.message).to_compatible();
132
+ }
133
+ return IWebResponse.success(data ?? []).to_compatible();
134
+ }
@@ -25,14 +25,7 @@ export async function get_herds_with_location(client) {
25
25
  data: null,
26
26
  };
27
27
  }
28
- if (!data) {
29
- return {
30
- status: EnumWebResponse.ERROR,
31
- msg: "No herds found",
32
- data: null,
33
- };
34
- }
35
- return IWebResponse.success(data).to_compatible();
28
+ return IWebResponse.success(data ?? []).to_compatible();
36
29
  }
37
30
  export async function get_herd_by_slug(slug) {
38
31
  const supabase = await newServerClient();
@@ -83,11 +76,10 @@ export async function server_load_herd_modules() {
83
76
  const client_supabase = await newServerClient();
84
77
  const herdsResult = await get_herds_with_location(client_supabase);
85
78
  if (herdsResult.status !== EnumWebResponse.SUCCESS ||
86
- !herdsResult.data ||
87
- herdsResult.data.length === 0) {
79
+ !herdsResult.data) {
88
80
  return {
89
81
  status: EnumWebResponse.ERROR,
90
- msg: herdsResult.msg ?? "No herds found",
82
+ msg: herdsResult.msg ?? "Failed to load herds",
91
83
  data: null,
92
84
  time_finished: Date.now(),
93
85
  time_sent: Date.now(),
@@ -95,20 +87,29 @@ export async function server_load_herd_modules() {
95
87
  };
96
88
  }
97
89
  const herds = herdsResult.data.filter((h) => h.id != null);
98
- let new_herd_modules = [];
99
- const herdModulePromises = herds.map((herd) => HerdModule.from_herd(herd, client_supabase));
100
- new_herd_modules = await Promise.all(herdModulePromises);
101
- const serialized_herd_modules = new_herd_modules.map((herd_module) => herd_module.to_serializable());
102
90
  const endTime = Date.now();
103
91
  const totalLoadTime = endTime - startTime;
92
+ if (herds.length === 0) {
93
+ console.log(`[server_load_herd_modules] No accessible herds (${totalLoadTime}ms)`);
94
+ return {
95
+ status: EnumWebResponse.SUCCESS,
96
+ msg: "No herds accessible",
97
+ data: [],
98
+ time_finished: endTime,
99
+ time_sent: endTime,
100
+ server_processing_time_ms: totalLoadTime,
101
+ };
102
+ }
103
+ const herdModulePromises = herds.map((herd) => HerdModule.from_herd(herd, client_supabase));
104
+ const new_herd_modules = await Promise.all(herdModulePromises);
105
+ const serialized_herd_modules = new_herd_modules.map((herd_module) => herd_module.to_serializable());
104
106
  console.log(`[server_load_herd_modules] Loaded ${herds.length} herds in ${totalLoadTime}ms (parallel processing)`);
105
- const timeSent = Date.now();
106
107
  return {
107
108
  status: EnumWebResponse.SUCCESS,
108
109
  msg: "Herd modules loaded successfully",
109
110
  data: serialized_herd_modules,
110
111
  time_finished: endTime,
111
- time_sent: timeSent,
112
+ time_sent: endTime,
112
113
  server_processing_time_ms: totalLoadTime,
113
114
  };
114
115
  }
@@ -33,4 +33,8 @@ export * from "./artifacts";
33
33
  export * from "./pins";
34
34
  export * from "./pubsub_token";
35
35
  export * from "./pubsub_token_server";
36
+ export * from "./client_abilities_token";
37
+ export * from "./client_abilities_token_server";
38
+ export * from "./client_abilities_jwt_keys";
39
+ export * from "./herd_roles";
36
40
  export * from "./storagePath";
@@ -33,4 +33,8 @@ export * from "./artifacts";
33
33
  export * from "./pins";
34
34
  export * from "./pubsub_token";
35
35
  export * from "./pubsub_token_server";
36
+ export * from "./client_abilities_token";
37
+ export * from "./client_abilities_token_server";
38
+ export * from "./client_abilities_jwt_keys";
39
+ export * from "./herd_roles";
36
40
  export * from "./storagePath";
@@ -1,8 +1,8 @@
1
1
  import { Database } from "../types/supabase";
2
- import { IHerdInvitation, IHerdInvitationWithHerdSlug, Role } from "../types/db";
2
+ import { IHerdInvitation, IHerdInvitationWithHerdSlug } from "../types/db";
3
3
  import { IWebResponseCompatible } from "../types/requests";
4
4
  import { SupabaseClient } from "@supabase/supabase-js";
5
- export declare function server_create_herd_invitation(herd_id: number, email: string, role: Role, expires_at?: string | null): Promise<IWebResponseCompatible<IHerdInvitation | null>>;
5
+ export declare function server_create_herd_invitation(herd_id: number, email: string, herd_role_id: number, expires_at?: string | null): Promise<IWebResponseCompatible<IHerdInvitation | null>>;
6
6
  export declare function accept_herd_invitations_for_current_user(invitation_ids: number[], supabaseClient?: SupabaseClient<Database>): Promise<IWebResponseCompatible<IHerdInvitation[]>>;
7
7
  export declare function server_get_herd_invitations_for_current_user(): Promise<IWebResponseCompatible<IHerdInvitationWithHerdSlug[]>>;
8
8
  export declare function server_get_herd_invitations_by_herd(herd_id: number, supabaseClient?: SupabaseClient<Database>): Promise<IWebResponseCompatible<IHerdInvitation[]>>;
@@ -1,12 +1,12 @@
1
1
  "use server";
2
2
  import { newServerClient } from "../supabase/server";
3
3
  import { IWebResponse } from "../types/requests";
4
- export async function server_create_herd_invitation(herd_id, email, role, expires_at) {
4
+ export async function server_create_herd_invitation(herd_id, email, herd_role_id, expires_at) {
5
5
  const supabase = await newServerClient();
6
6
  const { data, error } = await supabase.rpc("create_herd_invitation", {
7
7
  p_herd_id: herd_id,
8
8
  p_email: email,
9
- p_role: role,
9
+ p_herd_role_id: herd_role_id,
10
10
  p_expires_at: expires_at ?? undefined,
11
11
  });
12
12
  if (error) {
@@ -1,4 +1,5 @@
1
- import { Role } from "../types/db";
2
- export declare function formatRoleCasing(role: Role): string;
1
+ import { IHerdRole } from "../types/db";
2
+ /** Display label for a herd role (prefers `name`, falls back to `system_name`). */
3
+ export declare function formatRoleCasing(role: Pick<IHerdRole, "name" | "system_name"> | string): string;
3
4
  export declare function formatUsernameInitials(username: string): string;
4
5
  export declare function roundToXDecimals(num: number, decimals: number): number;
@@ -1,5 +1,10 @@
1
+ /** Display label for a herd role (prefers `name`, falls back to `system_name`). */
1
2
  export function formatRoleCasing(role) {
2
- return role.charAt(0).toUpperCase() + role.slice(1);
3
+ const label = typeof role === "string" ? role : role.name || role.system_name;
4
+ if (!label) {
5
+ return "";
6
+ }
7
+ return label.charAt(0).toUpperCase() + label.slice(1);
3
8
  }
4
9
  export function formatUsernameInitials(username) {
5
10
  if (!username) {
@@ -1,11 +1,12 @@
1
- import { IUser, IUserAndRole, IUserProfileRow, IUserRolePerHerd, Role } from "../types/db";
1
+ import { IUser, IUserAndRole, IUserProfileRow, IUserRolePerHerd } from "../types/db";
2
2
  import { IWebResponseCompatible } from "../types/requests";
3
3
  import { SupabaseClient } from "@supabase/supabase-js";
4
4
  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_upsert_user_with_role(herd_id: number, username: string, role: Role): Promise<IWebResponseCompatible<IUserAndRole | null>>;
8
+ export declare function server_upsert_user_herd_role(herd_id: number, username: string, herd_role_id: number): Promise<IWebResponseCompatible<IUserAndRole | null>>;
9
9
  export type UserProfileUpdate = Database["public"]["Tables"]["users"]["Update"];
10
10
  export declare function update_user_profile(client: SupabaseClient<Database>, user_id: string, patch: UserProfileUpdate): Promise<IWebResponseCompatible<IUserProfileRow | null>>;
11
11
  export declare function leave_herd_for_current_user(herd_id: number, supabaseClient?: SupabaseClient<Database>): Promise<IWebResponseCompatible<IUserRolePerHerd | null>>;
12
+ export declare function remove_user_from_herd_for_admin(herd_id: number, user_id: string, supabaseClient?: SupabaseClient<Database>): Promise<IWebResponseCompatible<IUserRolePerHerd | null>>;
@@ -30,7 +30,8 @@ export async function server_get_users_with_herd_access(herd_id, supabaseClient)
30
30
  const { data, error } = await supabase
31
31
  .from("users_roles_per_herd")
32
32
  .select(`
33
- role,
33
+ herd_role_id,
34
+ herd_roles (*),
34
35
  users!users_roles_per_herd_user_id_fkey (*)
35
36
  `)
36
37
  .eq("herd_id", herd_id);
@@ -41,17 +42,15 @@ export async function server_get_users_with_herd_access(herd_id, supabaseClient)
41
42
  data: null,
42
43
  };
43
44
  }
44
- else {
45
- const transformedData = data.map((item) => ({
46
- user: item.users,
47
- role: item.role,
48
- }));
49
- return IWebResponse.success(transformedData).to_compatible();
50
- }
45
+ const transformedData = (data ?? []).map((item) => ({
46
+ user: item.users,
47
+ herd_role_id: item.herd_role_id,
48
+ herd_role: item.herd_roles,
49
+ }));
50
+ return IWebResponse.success(transformedData).to_compatible();
51
51
  }
52
- export async function server_upsert_user_with_role(herd_id, username, role) {
52
+ export async function server_upsert_user_herd_role(herd_id, username, herd_role_id) {
53
53
  const supabase = await newServerClient();
54
- // first try to get user by username
55
54
  const { data: user, error: user_error } = await supabase
56
55
  .from("users")
57
56
  .select("*")
@@ -63,16 +62,28 @@ export async function server_upsert_user_with_role(herd_id, username, role) {
63
62
  if (!user) {
64
63
  return IWebResponse.error("User not found").to_compatible();
65
64
  }
66
- const newRoleForDb = {
65
+ const { data: herdRole, error: role_error } = await supabase
66
+ .from("herd_roles")
67
+ .select("*")
68
+ .eq("id", herd_role_id)
69
+ .eq("herd_id", herd_id)
70
+ .single();
71
+ if (role_error || !herdRole) {
72
+ return IWebResponse.error("Invalid herd role for this herd").to_compatible();
73
+ }
74
+ const { error } = await supabase.from("users_roles_per_herd").upsert({
67
75
  user_id: user.id,
68
- herd_id: herd_id,
69
- role: role,
70
- };
71
- const { error } = await supabase.from("users_roles_per_herd").upsert(newRoleForDb);
76
+ herd_id,
77
+ herd_role_id,
78
+ });
72
79
  if (error) {
73
80
  return IWebResponse.error("Unable to update or add user with provided username. Ensure you have sufficient permissions.").to_compatible();
74
81
  }
75
- return IWebResponse.success({ user, role }).to_compatible();
82
+ return IWebResponse.success({
83
+ user,
84
+ herd_role_id,
85
+ herd_role: herdRole,
86
+ }).to_compatible();
76
87
  }
77
88
  export async function update_user_profile(client, user_id, patch) {
78
89
  const { data, error } = await client
@@ -99,3 +110,14 @@ export async function leave_herd_for_current_user(herd_id, supabaseClient) {
99
110
  }
100
111
  return IWebResponse.success(data).to_compatible();
101
112
  }
113
+ export async function remove_user_from_herd_for_admin(herd_id, user_id, supabaseClient) {
114
+ const supabase = supabaseClient ?? (await newServerClient());
115
+ const { data, error } = await supabase.rpc("remove_user_from_herd_for_admin", {
116
+ p_herd_id: herd_id,
117
+ p_user_id: user_id,
118
+ });
119
+ if (error) {
120
+ return IWebResponse.error(error.message).to_compatible();
121
+ }
122
+ return IWebResponse.success(data).to_compatible();
123
+ }
@@ -6,6 +6,7 @@ import { EnumHerdModulesLoadingState } from "../types/herd_module";
6
6
  import { server_load_herd_modules } from "../helpers/herds";
7
7
  import { scoutCache } from "../helpers/cache";
8
8
  import { EnumDataSource } from "../types/data_source";
9
+ import { EnumWebResponse } from "../types/requests";
9
10
  import { createBrowserClient } from "@supabase/ssr";
10
11
  /**
11
12
  * Hook for refreshing scout data with detailed timing measurements and cache-first loading
@@ -185,7 +186,8 @@ export function useScoutRefresh(options = {}) {
185
186
  }
186
187
  const backgroundUserResult = await userPromise;
187
188
  // Validate background responses
188
- if (backgroundHerdModulesResult.data &&
189
+ if (backgroundHerdModulesResult.status ===
190
+ EnumWebResponse.SUCCESS &&
189
191
  Array.isArray(backgroundHerdModulesResult.data) &&
190
192
  backgroundUserResult) {
191
193
  // Update cache with fresh data
@@ -295,9 +297,9 @@ export function useScoutRefresh(options = {}) {
295
297
  // Dispatch timing actions
296
298
  dispatch(setHerdModulesApiServerProcessingDuration(herdModulesServerDuration));
297
299
  dispatch(setHerdModulesApiTotalRequestDuration(herdModulesTotalDuration));
298
- // Validate API responses
300
+ // Validate API responses
299
301
  const validationStartTime = Date.now();
300
- if (!herdModulesResponse.data ||
302
+ if (herdModulesResponse.status !== EnumWebResponse.SUCCESS ||
301
303
  !Array.isArray(herdModulesResponse.data)) {
302
304
  throw new Error("Invalid herd modules response");
303
305
  }
package/dist/index.d.ts CHANGED
@@ -11,6 +11,7 @@ export * from "./types/bounding_boxes";
11
11
  export * from "./types/events";
12
12
  export * from "./types/connectivity";
13
13
  export * from "./types/pubsub_token";
14
+ export * from "./types/client_abilities_token";
14
15
  export * from "./helpers/analysis_usage";
15
16
  export * from "./helpers/artifacts";
16
17
  export * from "./helpers/auth";
@@ -48,6 +49,10 @@ export * from "./helpers/heartbeats";
48
49
  export * from "./helpers/providers";
49
50
  export * from "./helpers/pubsub_token";
50
51
  export * from "./helpers/pubsub_token_server";
52
+ export * from "./helpers/client_abilities_token";
53
+ export * from "./helpers/client_abilities_token_server";
54
+ export * from "./helpers/client_abilities_jwt_keys";
55
+ export * from "./helpers/herd_roles";
51
56
  export * from "./helpers/observations";
52
57
  export * from "./helpers/operators";
53
58
  export * from "./helpers/versions_software";
@@ -76,5 +81,5 @@ export * from "./supabase/middleware";
76
81
  export * from "./supabase/server";
77
82
  export * from "./api_keys/actions";
78
83
  export type { HerdModule, IHerdModule } from "./types/herd_module";
79
- export type { IDevice, IEvent, IUser, IHerd, IHerdPrettyLocation, IEventWithTags, IZoneWithActions, ICredential, CredentialInsert, CredentialUpdate, ICertificate, CertificateInsert, CertificateUpdate, IUserAndRole, IUserProfileRow, IHerdInvitation, IHerdInvitationWithHerdSlug, IHerdAllowedDomain, IUserRolePerHerd, HerdInvitationStatus, IApiKeyScout, ILayer, IHeartbeat, IProvider, IConnectivity, ISession, ISessionWithCoordinates, IConnectivityWithCoordinates, IObservation, ObservationInsert, ObservationUpdate, IAnalysisJob, IAnalysisTask, AnalysisWorkStatus, } from "./types/db";
84
+ export type { IDevice, IEvent, IUser, IHerd, IHerdPrettyLocation, IEventWithTags, IZoneWithActions, ICredential, CredentialInsert, CredentialUpdate, ICertificate, CertificateInsert, CertificateUpdate, IUserAndRole, IUserProfileRow, IHerdInvitation, IHerdInvitationWithHerdSlug, IHerdAllowedDomain, IUserRolePerHerd, IAbility, IHerdRole, IHerdRoleWithAbilities, HerdRoleSystemName, HerdInvitationStatus, IApiKeyScout, ILayer, IHeartbeat, IProvider, IConnectivity, ISession, ISessionWithCoordinates, IConnectivityWithCoordinates, IObservation, ObservationInsert, ObservationUpdate, IAnalysisJob, IAnalysisTask, AnalysisWorkStatus, } from "./types/db";
80
85
  export { EnumSessionsVisibility } from "./types/events";
package/dist/index.js CHANGED
@@ -13,6 +13,7 @@ export * from "./types/bounding_boxes";
13
13
  export * from "./types/events";
14
14
  export * from "./types/connectivity";
15
15
  export * from "./types/pubsub_token";
16
+ export * from "./types/client_abilities_token";
16
17
  // Helpers
17
18
  export * from "./helpers/analysis_usage";
18
19
  export * from "./helpers/artifacts";
@@ -51,6 +52,10 @@ export * from "./helpers/heartbeats";
51
52
  export * from "./helpers/providers";
52
53
  export * from "./helpers/pubsub_token";
53
54
  export * from "./helpers/pubsub_token_server";
55
+ export * from "./helpers/client_abilities_token";
56
+ export * from "./helpers/client_abilities_token_server";
57
+ export * from "./helpers/client_abilities_jwt_keys";
58
+ export * from "./helpers/herd_roles";
54
59
  export * from "./helpers/observations";
55
60
  export * from "./helpers/operators";
56
61
  export * from "./helpers/versions_software";