@adventurelabs/scout-core 1.4.64 → 1.4.66

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,14 @@
1
+ import { Database } from "../types/supabase";
2
+ import { CertificateInsert, CertificateUpdate, ICertificate } from "../types/db";
3
+ import { IWebResponseCompatible } from "../types/requests";
4
+ import { SupabaseClient } from "@supabase/supabase-js";
5
+ export declare function get_certificates_by_device(client: SupabaseClient<Database>, device_id: number): Promise<IWebResponseCompatible<ICertificate[]>>;
6
+ export declare function get_certificate_by_device(client: SupabaseClient<Database>, certificate_id: number, device_id: number): Promise<IWebResponseCompatible<ICertificate | null>>;
7
+ export declare function create_certificate_by_device(client: SupabaseClient<Database>, device_id: number, row: CertificateInsert): Promise<IWebResponseCompatible<ICertificate | null>>;
8
+ export declare function update_certificate_by_device(client: SupabaseClient<Database>, certificate_id: number, device_id: number, patch: CertificateUpdate): Promise<IWebResponseCompatible<ICertificate | null>>;
9
+ export declare function delete_certificate_by_device(client: SupabaseClient<Database>, certificate_id: number, device_id: number): Promise<IWebResponseCompatible<ICertificate | null>>;
10
+ export declare function get_certificates_by_part(client: SupabaseClient<Database>, part_id: number): Promise<IWebResponseCompatible<ICertificate[]>>;
11
+ export declare function get_certificate_by_part(client: SupabaseClient<Database>, certificate_id: number, part_id: number): Promise<IWebResponseCompatible<ICertificate | null>>;
12
+ export declare function create_certificate_by_part(client: SupabaseClient<Database>, part_id: number, row: CertificateInsert): Promise<IWebResponseCompatible<ICertificate | null>>;
13
+ export declare function update_certificate_by_part(client: SupabaseClient<Database>, certificate_id: number, part_id: number, patch: CertificateUpdate): Promise<IWebResponseCompatible<ICertificate | null>>;
14
+ export declare function delete_certificate_by_part(client: SupabaseClient<Database>, certificate_id: number, part_id: number): Promise<IWebResponseCompatible<ICertificate | null>>;
@@ -0,0 +1,233 @@
1
+ import { EnumWebResponse, IWebResponse, } from "../types/requests";
2
+ const SELECT_CERT_FOR_DEVICE = `
3
+ id,
4
+ created_at,
5
+ expiration,
6
+ issuer,
7
+ part_id,
8
+ tracking_number,
9
+ type,
10
+ updated_at,
11
+ parts!inner ( device_id )
12
+ `;
13
+ function to_certificate(row) {
14
+ const { parts: _p, ...cert } = row;
15
+ return cert;
16
+ }
17
+ function assertCertificateInsertBase(row) {
18
+ if (!row.issuer?.trim()) {
19
+ return IWebResponse.error("issuer is required")
20
+ .to_compatible();
21
+ }
22
+ if (!row.type?.trim()) {
23
+ return IWebResponse.error("type is required")
24
+ .to_compatible();
25
+ }
26
+ return null;
27
+ }
28
+ // --- by device (join `parts` so scope is the device the part belongs to) ---
29
+ export async function get_certificates_by_device(client, device_id) {
30
+ const { data, error } = await client
31
+ .from("certificates")
32
+ .select(SELECT_CERT_FOR_DEVICE)
33
+ .eq("parts.device_id", device_id)
34
+ .order("created_at", { ascending: false });
35
+ if (error) {
36
+ return IWebResponse.error(error.message).to_compatible();
37
+ }
38
+ const rows = (data ?? []);
39
+ return IWebResponse.success(rows.map(to_certificate)).to_compatible();
40
+ }
41
+ export async function get_certificate_by_device(client, certificate_id, device_id) {
42
+ const { data, error } = await client
43
+ .from("certificates")
44
+ .select(SELECT_CERT_FOR_DEVICE)
45
+ .eq("id", certificate_id)
46
+ .eq("parts.device_id", device_id)
47
+ .single();
48
+ if (error) {
49
+ return IWebResponse.error(error.message).to_compatible();
50
+ }
51
+ if (!data) {
52
+ return IWebResponse.error("Certificate not found")
53
+ .to_compatible();
54
+ }
55
+ return IWebResponse.success(to_certificate(data)).to_compatible();
56
+ }
57
+ export async function create_certificate_by_device(client, device_id, row) {
58
+ if (row.part_id == null) {
59
+ return IWebResponse.error("part_id is required")
60
+ .to_compatible();
61
+ }
62
+ const baseErr = assertCertificateInsertBase(row);
63
+ if (baseErr) {
64
+ return baseErr;
65
+ }
66
+ const { data: part, error: partError } = await client
67
+ .from("parts")
68
+ .select("id")
69
+ .eq("id", row.part_id)
70
+ .eq("device_id", device_id)
71
+ .maybeSingle();
72
+ if (partError) {
73
+ return IWebResponse.error(partError.message)
74
+ .to_compatible();
75
+ }
76
+ if (!part) {
77
+ return IWebResponse.error("part not found for this device").to_compatible();
78
+ }
79
+ const { data, error } = await client
80
+ .from("certificates")
81
+ .insert([row])
82
+ .select("*")
83
+ .single();
84
+ if (error) {
85
+ return IWebResponse.error(error.message).to_compatible();
86
+ }
87
+ if (!data) {
88
+ return IWebResponse.error("Failed to create certificate").to_compatible();
89
+ }
90
+ return IWebResponse.success(data).to_compatible();
91
+ }
92
+ export async function update_certificate_by_device(client, certificate_id, device_id, patch) {
93
+ // Herd RLS is broader than device: must verify this cert is on the device.
94
+ const check = await get_certificate_by_device(client, certificate_id, device_id);
95
+ if (check.status !== EnumWebResponse.SUCCESS || check.data == null) {
96
+ return IWebResponse.error(check.msg ?? "Certificate not found").to_compatible();
97
+ }
98
+ const partId = check.data.part_id;
99
+ if (partId == null) {
100
+ return IWebResponse.error("Certificate not found")
101
+ .to_compatible();
102
+ }
103
+ const { id: _id, part_id: _pid, created_at: _ca, ...updateData } = patch;
104
+ if (Object.keys(updateData).length === 0) {
105
+ return IWebResponse.error("No valid fields to update").to_compatible();
106
+ }
107
+ const { data, error } = await client
108
+ .from("certificates")
109
+ .update(updateData)
110
+ .eq("id", certificate_id)
111
+ .eq("part_id", partId)
112
+ .select("*")
113
+ .single();
114
+ if (error) {
115
+ return IWebResponse.error(error.message).to_compatible();
116
+ }
117
+ if (!data) {
118
+ return IWebResponse.error("Certificate not found")
119
+ .to_compatible();
120
+ }
121
+ return IWebResponse.success(data).to_compatible();
122
+ }
123
+ export async function delete_certificate_by_device(client, certificate_id, device_id) {
124
+ const check = await get_certificate_by_device(client, certificate_id, device_id);
125
+ if (check.status !== EnumWebResponse.SUCCESS || check.data == null) {
126
+ return IWebResponse.error(check.msg ?? "Certificate not found").to_compatible();
127
+ }
128
+ const partId = check.data.part_id;
129
+ if (partId == null) {
130
+ return IWebResponse.error("Certificate not found")
131
+ .to_compatible();
132
+ }
133
+ const { data, error } = await client
134
+ .from("certificates")
135
+ .delete()
136
+ .eq("id", certificate_id)
137
+ .eq("part_id", partId)
138
+ .select("*")
139
+ .single();
140
+ if (error) {
141
+ return IWebResponse.error(error.message).to_compatible();
142
+ }
143
+ if (!data) {
144
+ return IWebResponse.error("Certificate not found")
145
+ .to_compatible();
146
+ }
147
+ return IWebResponse.success(data).to_compatible();
148
+ }
149
+ // --- by part (direct `part_id` on `certificates`) ---
150
+ export async function get_certificates_by_part(client, part_id) {
151
+ const { data, error } = await client
152
+ .from("certificates")
153
+ .select("*")
154
+ .eq("part_id", part_id)
155
+ .order("created_at", { ascending: false });
156
+ if (error) {
157
+ return IWebResponse.error(error.message).to_compatible();
158
+ }
159
+ return IWebResponse.success(data ?? []).to_compatible();
160
+ }
161
+ export async function get_certificate_by_part(client, certificate_id, part_id) {
162
+ const { data, error } = await client
163
+ .from("certificates")
164
+ .select("*")
165
+ .eq("id", certificate_id)
166
+ .eq("part_id", part_id)
167
+ .single();
168
+ if (error) {
169
+ return IWebResponse.error(error.message).to_compatible();
170
+ }
171
+ if (!data) {
172
+ return IWebResponse.error("Certificate not found")
173
+ .to_compatible();
174
+ }
175
+ return IWebResponse.success(data).to_compatible();
176
+ }
177
+ export async function create_certificate_by_part(client, part_id, row) {
178
+ const baseErr = assertCertificateInsertBase(row);
179
+ if (baseErr) {
180
+ return baseErr;
181
+ }
182
+ const insert = { ...row, part_id };
183
+ const { data, error } = await client
184
+ .from("certificates")
185
+ .insert([insert])
186
+ .select("*")
187
+ .single();
188
+ if (error) {
189
+ return IWebResponse.error(error.message).to_compatible();
190
+ }
191
+ if (!data) {
192
+ return IWebResponse.error("Failed to create certificate").to_compatible();
193
+ }
194
+ return IWebResponse.success(data).to_compatible();
195
+ }
196
+ export async function update_certificate_by_part(client, certificate_id, part_id, patch) {
197
+ const { id: _id, part_id: _pid, created_at: _ca, ...updateData } = patch;
198
+ if (Object.keys(updateData).length === 0) {
199
+ return IWebResponse.error("No valid fields to update").to_compatible();
200
+ }
201
+ const { data, error } = await client
202
+ .from("certificates")
203
+ .update(updateData)
204
+ .eq("id", certificate_id)
205
+ .eq("part_id", part_id)
206
+ .select("*")
207
+ .single();
208
+ if (error) {
209
+ return IWebResponse.error(error.message).to_compatible();
210
+ }
211
+ if (!data) {
212
+ return IWebResponse.error("Certificate not found")
213
+ .to_compatible();
214
+ }
215
+ return IWebResponse.success(data).to_compatible();
216
+ }
217
+ export async function delete_certificate_by_part(client, certificate_id, part_id) {
218
+ const { data, error } = await client
219
+ .from("certificates")
220
+ .delete()
221
+ .eq("id", certificate_id)
222
+ .eq("part_id", part_id)
223
+ .select("*")
224
+ .single();
225
+ if (error) {
226
+ return IWebResponse.error(error.message).to_compatible();
227
+ }
228
+ if (!data) {
229
+ return IWebResponse.error("Certificate not found")
230
+ .to_compatible();
231
+ }
232
+ return IWebResponse.success(data).to_compatible();
233
+ }
@@ -0,0 +1,9 @@
1
+ import { Database } from "../types/supabase";
2
+ import { CredentialInsert, CredentialUpdate, ICredential } from "../types/db";
3
+ import { IWebResponseCompatible } from "../types/requests";
4
+ import { SupabaseClient } from "@supabase/supabase-js";
5
+ export declare function get_credentials_by_user_id(client: SupabaseClient<Database>, user_id: string): Promise<IWebResponseCompatible<ICredential[]>>;
6
+ export declare function get_credential_by_id(client: SupabaseClient<Database>, credential_id: number, user_id: string): Promise<IWebResponseCompatible<ICredential | null>>;
7
+ export declare function create_credential(client: SupabaseClient<Database>, row: CredentialInsert): Promise<IWebResponseCompatible<ICredential | null>>;
8
+ export declare function update_credential(client: SupabaseClient<Database>, credential_id: number, user_id: string, patch: CredentialUpdate): Promise<IWebResponseCompatible<ICredential | null>>;
9
+ export declare function delete_credential(client: SupabaseClient<Database>, credential_id: number, user_id: string): Promise<IWebResponseCompatible<ICredential | null>>;
@@ -0,0 +1,92 @@
1
+ import { IWebResponse } from "../types/requests";
2
+ export async function get_credentials_by_user_id(client, user_id) {
3
+ const { data, error } = await client
4
+ .from("credentials")
5
+ .select("*")
6
+ .eq("user_id", user_id)
7
+ .order("created_at", { ascending: false });
8
+ if (error) {
9
+ return IWebResponse.error(error.message).to_compatible();
10
+ }
11
+ return IWebResponse.success(data ?? []).to_compatible();
12
+ }
13
+ export async function get_credential_by_id(client, credential_id, user_id) {
14
+ const { data, error } = await client
15
+ .from("credentials")
16
+ .select("*")
17
+ .eq("id", credential_id)
18
+ .eq("user_id", user_id)
19
+ .single();
20
+ if (error) {
21
+ return IWebResponse.error(error.message).to_compatible();
22
+ }
23
+ if (!data) {
24
+ return IWebResponse.error("Credential not found")
25
+ .to_compatible();
26
+ }
27
+ return IWebResponse.success(data).to_compatible();
28
+ }
29
+ export async function create_credential(client, row) {
30
+ if (!row.user_id) {
31
+ return IWebResponse.error("user_id is required")
32
+ .to_compatible();
33
+ }
34
+ if (!row.issuer?.trim()) {
35
+ return IWebResponse.error("issuer is required")
36
+ .to_compatible();
37
+ }
38
+ if (!row.type?.trim()) {
39
+ return IWebResponse.error("type is required")
40
+ .to_compatible();
41
+ }
42
+ const { data, error } = await client
43
+ .from("credentials")
44
+ .insert([row])
45
+ .select("*")
46
+ .single();
47
+ if (error) {
48
+ return IWebResponse.error(error.message).to_compatible();
49
+ }
50
+ if (!data) {
51
+ return IWebResponse.error("Failed to create credential").to_compatible();
52
+ }
53
+ return IWebResponse.success(data).to_compatible();
54
+ }
55
+ export async function update_credential(client, credential_id, user_id, patch) {
56
+ const { id: _id, user_id: _uid, created_at: _ca, ...updateData } = patch;
57
+ if (Object.keys(updateData).length === 0) {
58
+ return IWebResponse.error("No valid fields to update").to_compatible();
59
+ }
60
+ const { data, error } = await client
61
+ .from("credentials")
62
+ .update(updateData)
63
+ .eq("id", credential_id)
64
+ .eq("user_id", user_id)
65
+ .select("*")
66
+ .single();
67
+ if (error) {
68
+ return IWebResponse.error(error.message).to_compatible();
69
+ }
70
+ if (!data) {
71
+ return IWebResponse.error("Credential not found")
72
+ .to_compatible();
73
+ }
74
+ return IWebResponse.success(data).to_compatible();
75
+ }
76
+ export async function delete_credential(client, credential_id, user_id) {
77
+ const { data, error } = await client
78
+ .from("credentials")
79
+ .delete()
80
+ .eq("id", credential_id)
81
+ .eq("user_id", user_id)
82
+ .select("*")
83
+ .single();
84
+ if (error) {
85
+ return IWebResponse.error(error.message).to_compatible();
86
+ }
87
+ if (!data) {
88
+ return IWebResponse.error("Credential not found")
89
+ .to_compatible();
90
+ }
91
+ return IWebResponse.success(data).to_compatible();
92
+ }
@@ -2,6 +2,8 @@ export * from "./analysis_usage";
2
2
  export * from "./auth";
3
3
  export * from "./bounding_boxes";
4
4
  export * from "./chat";
5
+ export * from "./certificates";
6
+ export * from "./credentials";
5
7
  export * from "./db";
6
8
  export * from "./devices";
7
9
  export * from "./email";
@@ -2,6 +2,8 @@ export * from "./analysis_usage";
2
2
  export * from "./auth";
3
3
  export * from "./bounding_boxes";
4
4
  export * from "./chat";
5
+ export * from "./certificates";
6
+ export * from "./credentials";
5
7
  export * from "./db";
6
8
  export * from "./devices";
7
9
  export * from "./email";
@@ -34,7 +34,10 @@ export async function server_get_users_with_herd_access(herd_id, supabaseClient)
34
34
  users (
35
35
  id,
36
36
  username,
37
- earthranger_id
37
+ earthranger_id,
38
+ first,
39
+ last,
40
+ title
38
41
  )
39
42
  `)
40
43
  .eq("herd_id", herd_id);
package/dist/index.d.ts CHANGED
@@ -15,7 +15,9 @@ export * from "./helpers/artifacts";
15
15
  export * from "./helpers/auth";
16
16
  export * from "./helpers/bounding_boxes";
17
17
  export * from "./helpers/chat";
18
+ export * from "./helpers/certificates";
18
19
  export * from "./helpers/connectivity";
20
+ export * from "./helpers/credentials";
19
21
  export * from "./helpers/db";
20
22
  export * from "./helpers/devices";
21
23
  export * from "./helpers/email";
@@ -68,5 +70,5 @@ export * from "./supabase/middleware";
68
70
  export * from "./supabase/server";
69
71
  export * from "./api_keys/actions";
70
72
  export type { HerdModule, IHerdModule } from "./types/herd_module";
71
- export type { IDevice, IEvent, IUser, IHerd, IHerdPrettyLocation, IEventWithTags, IZoneWithActions, IUserAndRole, IApiKeyScout, ILayer, IHeartbeat, IProvider, IConnectivity, ISession, ISessionWithCoordinates, IConnectivityWithCoordinates, IObservation, ObservationInsert, ObservationUpdate, IAnalysisJob, IAnalysisTask, AnalysisWorkStatus, } from "./types/db";
73
+ export type { IDevice, IEvent, IUser, IHerd, IHerdPrettyLocation, IEventWithTags, IZoneWithActions, ICredential, CredentialInsert, CredentialUpdate, ICertificate, CertificateInsert, CertificateUpdate, IUserAndRole, IApiKeyScout, ILayer, IHeartbeat, IProvider, IConnectivity, ISession, ISessionWithCoordinates, IConnectivityWithCoordinates, IObservation, ObservationInsert, ObservationUpdate, IAnalysisJob, IAnalysisTask, AnalysisWorkStatus, } from "./types/db";
72
74
  export { EnumSessionsVisibility } from "./types/events";
package/dist/index.js CHANGED
@@ -18,7 +18,9 @@ export * from "./helpers/artifacts";
18
18
  export * from "./helpers/auth";
19
19
  export * from "./helpers/bounding_boxes";
20
20
  export * from "./helpers/chat";
21
+ export * from "./helpers/certificates";
21
22
  export * from "./helpers/connectivity";
23
+ export * from "./helpers/credentials";
22
24
  export * from "./helpers/db";
23
25
  export * from "./helpers/devices";
24
26
  export * from "./helpers/email";
@@ -1367,17 +1367,26 @@ export declare function useSupabase(): SupabaseClient<Database, "public", "publi
1367
1367
  users: {
1368
1368
  Row: {
1369
1369
  earthranger_id: string | null;
1370
+ first: string | null;
1370
1371
  id: string;
1372
+ last: string | null;
1373
+ title: string | null;
1371
1374
  username: string | null;
1372
1375
  };
1373
1376
  Insert: {
1374
1377
  earthranger_id?: string | null;
1378
+ first?: string | null;
1375
1379
  id: string;
1380
+ last?: string | null;
1381
+ title?: string | null;
1376
1382
  username?: string | null;
1377
1383
  };
1378
1384
  Update: {
1379
1385
  earthranger_id?: string | null;
1386
+ first?: string | null;
1380
1387
  id?: string;
1388
+ last?: string | null;
1389
+ title?: string | null;
1381
1390
  username?: string | null;
1382
1391
  };
1383
1392
  Relationships: [];
@@ -30,6 +30,8 @@ export type IOperator = Database["public"]["Tables"]["operators"]["Row"];
30
30
  export type IObservation = Database["public"]["Tables"]["observations"]["Row"];
31
31
  export type IProvider = Database["public"]["Tables"]["providers"]["Row"];
32
32
  export type IPart = Database["public"]["Tables"]["parts"]["Row"];
33
+ export type ICredential = Database["public"]["Tables"]["credentials"]["Row"];
34
+ export type ICertificate = Database["public"]["Tables"]["certificates"]["Row"];
33
35
  export type IVersionsSoftware = Database["public"]["Tables"]["versions_software"]["Row"];
34
36
  export type IArtifact = Database["public"]["Tables"]["artifacts"]["Row"];
35
37
  export type IHealthMetric = Database["public"]["Tables"]["health_metrics"]["Row"];
@@ -69,6 +71,10 @@ export interface ISessionSummary {
69
71
  }
70
72
  export type ISessionUsageOverTime = Database["public"]["Functions"]["get_session_usage_over_time"]["Returns"];
71
73
  export type PartInsert = Database["public"]["Tables"]["parts"]["Insert"];
74
+ export type CredentialInsert = Database["public"]["Tables"]["credentials"]["Insert"];
75
+ export type CredentialUpdate = Database["public"]["Tables"]["credentials"]["Update"];
76
+ export type CertificateInsert = Database["public"]["Tables"]["certificates"]["Insert"];
77
+ export type CertificateUpdate = Database["public"]["Tables"]["certificates"]["Update"];
72
78
  export type VersionsSoftwareInsert = Database["public"]["Tables"]["versions_software"]["Insert"];
73
79
  export type ArtifactInsert = Database["public"]["Tables"]["artifacts"]["Insert"];
74
80
  export type ArtifactUpdate = Database["public"]["Tables"]["artifacts"]["Update"];
@@ -125,7 +131,7 @@ export interface IEventWithSession extends IEvent {
125
131
  session: ISession | null;
126
132
  }
127
133
  export type IUserAndRole = {
128
- user: Pick<Database["public"]["Tables"]["users"]["Row"], "id" | "username" | "earthranger_id"> | null;
134
+ user: Pick<Database["public"]["Tables"]["users"]["Row"], "id" | "username" | "earthranger_id" | "first" | "last" | "title"> | null;
129
135
  role: Role;
130
136
  };
131
137
  export interface IApiKeyScout {
@@ -1437,17 +1437,26 @@ export type Database = {
1437
1437
  users: {
1438
1438
  Row: {
1439
1439
  earthranger_id: string | null;
1440
+ first: string | null;
1440
1441
  id: string;
1442
+ last: string | null;
1443
+ title: string | null;
1441
1444
  username: string | null;
1442
1445
  };
1443
1446
  Insert: {
1444
1447
  earthranger_id?: string | null;
1448
+ first?: string | null;
1445
1449
  id: string;
1450
+ last?: string | null;
1451
+ title?: string | null;
1446
1452
  username?: string | null;
1447
1453
  };
1448
1454
  Update: {
1449
1455
  earthranger_id?: string | null;
1456
+ first?: string | null;
1450
1457
  id?: string;
1458
+ last?: string | null;
1459
+ title?: string | null;
1451
1460
  username?: string | null;
1452
1461
  };
1453
1462
  Relationships: [];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adventurelabs/scout-core",
3
- "version": "1.4.64",
3
+ "version": "1.4.66",
4
4
  "description": "Core utilities and helpers for Adventure Labs Scout applications",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",