@adventurelabs/scout-core 1.0.46 → 1.0.47

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.
@@ -1,4 +1,5 @@
1
1
  import { IApiKeyScout } from "../types/db";
2
+ export declare function test_api_key_loading(device_id: string): Promise<boolean>;
2
3
  export declare function server_list_api_keys(device_id: string): Promise<IApiKeyScout[]>;
3
4
  export declare function server_list_api_keys_batch(device_ids: string[]): Promise<{
4
5
  [device_id: number]: IApiKeyScout[];
@@ -1,5 +1,18 @@
1
1
  "use server";
2
2
  import { newServerClient } from "../supabase/server";
3
+ // Test function to verify individual API key loading works
4
+ export async function test_api_key_loading(device_id) {
5
+ try {
6
+ console.log(`[API Key Test] Testing individual API key loading for device ${device_id}`);
7
+ const api_keys = await server_list_api_keys(device_id);
8
+ console.log(`[API Key Test] Successfully loaded ${api_keys.length} API keys for device ${device_id}`);
9
+ return true;
10
+ }
11
+ catch (error) {
12
+ console.error(`[API Key Test] Failed to load API keys for device ${device_id}:`, error);
13
+ return false;
14
+ }
15
+ }
3
16
  export async function server_list_api_keys(device_id) {
4
17
  const supabase = await newServerClient();
5
18
  const { data, error } = await supabase.rpc("load_api_keys", {
@@ -19,24 +32,38 @@ export async function server_list_api_keys(device_id) {
19
32
  }
20
33
  export async function server_list_api_keys_batch(device_ids) {
21
34
  const startTime = Date.now();
22
- console.log(`[API Keys Batch] Starting batch load for ${device_ids.length} devices at ${new Date().toISOString()}`);
23
- console.log(`[API Keys Batch] Debug: device_ids array:`, device_ids);
24
- console.log(`[API Keys Batch] Debug: device_ids types:`, device_ids.map((id) => ({ id, type: typeof id })));
35
+ // CRITICAL: Check for UUIDs being passed instead of device IDs
36
+ const invalidIds = device_ids.filter((id) => !/^\d+$/.test(id));
37
+ if (invalidIds.length > 0) {
38
+ console.error(`[CRITICAL] UUIDs detected instead of device IDs:`, invalidIds);
39
+ console.error(`[CRITICAL] Valid device IDs should be:`, device_ids.filter((id) => /^\d+$/.test(id)));
40
+ return {};
41
+ }
25
42
  const supabase = await newServerClient();
26
- console.log(`[API Keys Batch] Making RPC call to load_api_keys_batch...`);
27
43
  const { data, error } = await supabase.rpc("load_api_keys_batch", {
28
44
  device_ids: device_ids,
29
45
  });
30
- const duration = Date.now() - startTime;
31
46
  if (error) {
32
- console.error(`[API Keys Batch] ERROR after ${duration}ms:`, error.message);
33
- return {};
47
+ console.error(`[API Keys Batch] Database error:`, error.message);
48
+ console.log(`[API Keys Batch] Falling back to individual calls...`);
49
+ // Fallback to individual API key loading
50
+ const result = {};
51
+ const promises = device_ids.map(async (device_id) => {
52
+ try {
53
+ const api_keys = await server_list_api_keys(device_id);
54
+ result[parseInt(device_id)] = api_keys;
55
+ }
56
+ catch (err) {
57
+ console.warn(`[API Keys Batch] Failed for device ${device_id}:`, err);
58
+ result[parseInt(device_id)] = [];
59
+ }
60
+ });
61
+ await Promise.all(promises);
62
+ return result;
34
63
  }
35
64
  if (!data) {
36
- console.log(`[API Keys Batch] No data returned after ${duration}ms`);
37
65
  return {};
38
66
  }
39
- console.log(`[API Keys Batch] RPC completed in ${duration}ms, received ${data.length} API key records`);
40
67
  const result = {};
41
68
  // Group API keys by device_id
42
69
  data.forEach((item) => {
@@ -49,7 +76,5 @@ export async function server_list_api_keys_batch(device_ids) {
49
76
  key: item.api_key_key,
50
77
  });
51
78
  });
52
- const totalDuration = Date.now() - startTime;
53
- console.log(`[API Keys Batch] COMPLETED in ${totalDuration}ms - returning API keys for ${Object.keys(result).length} devices`);
54
79
  return result;
55
80
  }
@@ -1,5 +1,6 @@
1
1
  import { IEventWithTags, ITag } from "../types/db";
2
2
  import { IWebResponseCompatible } from "../types/requests";
3
+ export declare function test_event_loading(device_id: number): Promise<boolean>;
3
4
  export declare function server_create_tags(tags: ITag[]): Promise<IWebResponseCompatible<ITag[]>>;
4
5
  export declare function server_delete_tags_by_ids(tag_ids: number[]): Promise<IWebResponseCompatible<boolean>>;
5
6
  export declare function server_update_tags(tags: ITag[]): Promise<IWebResponseCompatible<ITag[]>>;
@@ -3,6 +3,25 @@
3
3
  import { newServerClient } from "../supabase/server";
4
4
  import { EnumWebResponse, IWebResponse, } from "../types/requests";
5
5
  import { addSignedUrlsToEvents, addSignedUrlToEvent } from "./storage";
6
+ // Test function to verify individual event loading works
7
+ export async function test_event_loading(device_id) {
8
+ try {
9
+ console.log(`[Event Test] Testing individual event loading for device ${device_id}`);
10
+ const events_response = await server_get_events_and_tags_for_device(device_id, 1);
11
+ if (events_response.status === EnumWebResponse.SUCCESS) {
12
+ console.log(`[Event Test] Successfully loaded ${events_response.data?.length || 0} events for device ${device_id}`);
13
+ return true;
14
+ }
15
+ else {
16
+ console.error(`[Event Test] Failed to load events for device ${device_id}:`, events_response.msg);
17
+ return false;
18
+ }
19
+ }
20
+ catch (error) {
21
+ console.error(`[Event Test] Failed to load events for device ${device_id}:`, error);
22
+ return false;
23
+ }
24
+ }
6
25
  export async function server_create_tags(tags) {
7
26
  const supabase = await newServerClient();
8
27
  // remove id key from tags
@@ -148,30 +167,47 @@ export async function server_get_events_and_tags_for_device(device_id, limit = 3
148
167
  }
149
168
  export async function server_get_events_and_tags_for_devices_batch(device_ids, limit = 1) {
150
169
  const startTime = Date.now();
151
- console.log(`[Events Batch] Starting batch load for ${device_ids.length} devices (limit: ${limit}) at ${new Date().toISOString()}`);
152
- console.log(`[Events Batch] Debug: device_ids array:`, device_ids);
153
- console.log(`[Events Batch] Debug: device_ids types:`, device_ids.map((id) => ({ id, type: typeof id })));
170
+ // CRITICAL: Check for UUIDs being passed instead of device IDs
171
+ const invalidIds = device_ids.filter((id) => !/^\d+$/.test(id));
172
+ if (invalidIds.length > 0) {
173
+ console.error(`[CRITICAL] UUIDs detected instead of device IDs:`, invalidIds);
174
+ console.error(`[CRITICAL] Valid device IDs should be:`, device_ids.filter((id) => /^\d+$/.test(id)));
175
+ return IWebResponse.success({}).to_compatible();
176
+ }
154
177
  const supabase = await newServerClient();
155
- console.log(`[Events Batch] Making RPC call to get_events_and_tags_for_devices_batch...`);
156
178
  // Use single RPC call for all devices
157
179
  const { data, error } = await supabase.rpc("get_events_and_tags_for_devices_batch", {
158
180
  device_ids: device_ids,
159
181
  limit_per_device: limit,
160
182
  });
161
- const duration = Date.now() - startTime;
162
183
  if (error) {
163
- console.error(`[Events Batch] ERROR after ${duration}ms:`, error.message);
164
- return {
165
- status: EnumWebResponse.ERROR,
166
- msg: error.message,
167
- data: {},
168
- };
184
+ console.error(`[Events Batch] Database error:`, error.message);
185
+ console.log(`[Events Batch] Falling back to individual calls...`);
186
+ // Fallback to individual event loading
187
+ const result = {};
188
+ const promises = device_ids.map(async (device_id) => {
189
+ try {
190
+ const device_id_num = parseInt(device_id);
191
+ const events_response = await server_get_events_and_tags_for_device(device_id_num, limit);
192
+ if (events_response.status === EnumWebResponse.SUCCESS &&
193
+ events_response.data) {
194
+ result[device_id_num] = events_response.data;
195
+ }
196
+ else {
197
+ result[device_id_num] = [];
198
+ }
199
+ }
200
+ catch (err) {
201
+ console.warn(`[Events Batch] Failed for device ${device_id}:`, err);
202
+ result[parseInt(device_id)] = [];
203
+ }
204
+ });
205
+ await Promise.all(promises);
206
+ return IWebResponse.success(result).to_compatible();
169
207
  }
170
208
  if (!data) {
171
- console.log(`[Events Batch] No data returned after ${duration}ms`);
172
209
  return IWebResponse.success({}).to_compatible();
173
210
  }
174
- console.log(`[Events Batch] RPC completed in ${duration}ms, received ${data.length} event records`);
175
211
  // Group events by device_id
176
212
  const eventsByDevice = {};
177
213
  data.forEach((row) => {
@@ -179,7 +215,7 @@ export async function server_get_events_and_tags_for_devices_batch(device_ids, l
179
215
  if (!eventsByDevice[device_id]) {
180
216
  eventsByDevice[device_id] = [];
181
217
  }
182
- // Create event object from the new structure
218
+ // Create event object from the database function structure
183
219
  const event = {
184
220
  id: row.event_id,
185
221
  inserted_at: row.inserted_at,
@@ -206,8 +242,6 @@ export async function server_get_events_and_tags_for_devices_batch(device_ids, l
206
242
  const eventsWithSignedUrls = await addSignedUrlsToEvents(events, supabase);
207
243
  result[parseInt(device_id)] = eventsWithSignedUrls;
208
244
  }
209
- const totalDuration = Date.now() - startTime;
210
- console.log(`[Events Batch] COMPLETED in ${totalDuration}ms - returning events for ${Object.keys(result).length} devices`);
211
245
  return IWebResponse.success(result).to_compatible();
212
246
  }
213
247
  export async function get_event_and_tags_by_event_id(event_id) {
@@ -52,7 +52,7 @@ export class HerdModule {
52
52
  let response_new_devices = await get_devices_by_herd(herd.id, client);
53
53
  if (response_new_devices.status == EnumWebResponse.ERROR ||
54
54
  !response_new_devices.data) {
55
- console.warn("No devices found for herd");
55
+ console.warn(`[HerdModule] No devices found for herd ${herd.id}`);
56
56
  return new HerdModule(herd, [], [], Date.now());
57
57
  }
58
58
  const new_devices = response_new_devices.data;
@@ -61,60 +61,58 @@ export class HerdModule {
61
61
  if (new_devices.length > 0) {
62
62
  const batchStartTime = Date.now();
63
63
  try {
64
- console.log(`[HerdModule] Debug: new_devices array:`, new_devices.map((d) => ({
65
- id: d.id,
66
- type: typeof d.id,
67
- created_by: d.created_by,
68
- name: d.name,
69
- })));
70
64
  const device_ids = new_devices.map((device) => (device.id ?? 0).toString());
71
- console.log(`[HerdModule] Starting parallel batch load for ${device_ids.length} devices at ${new Date().toISOString()}:`, device_ids);
65
+ // CRITICAL: Check for UUIDs being passed instead of device IDs
66
+ const invalidDeviceIds = device_ids.filter((id) => !/^\d+$/.test(id));
67
+ if (invalidDeviceIds.length > 0) {
68
+ console.error(`[CRITICAL] UUIDs detected in HerdModule:`, invalidDeviceIds);
69
+ console.error(`[CRITICAL] Device objects:`, new_devices.map((d) => ({ id: d.id, created_by: d.created_by })));
70
+ // Filter out invalid IDs
71
+ const validDeviceIds = device_ids.filter((id) => /^\d+$/.test(id));
72
+ device_ids.length = 0;
73
+ device_ids.push(...validDeviceIds);
74
+ }
72
75
  // Load API keys and events in parallel
73
- console.log(`[HerdModule] Initiating Promise.all for API keys and events...`);
74
76
  const [api_keys_batch, events_response] = await Promise.all([
75
77
  server_list_api_keys_batch(device_ids),
76
78
  server_get_events_and_tags_for_devices_batch(device_ids, 1),
77
79
  ]);
78
- const batchDuration = Date.now() - batchStartTime;
79
- console.log(`[HerdModule] Parallel batch load completed in ${batchDuration}ms`);
80
80
  // Assign API keys to devices
81
81
  for (let i = 0; i < new_devices.length; i++) {
82
82
  const device_id = new_devices[i].id ?? 0;
83
83
  new_devices[i].api_keys_scout = api_keys_batch[device_id] || [];
84
84
  }
85
- console.log(`[HerdModule] API keys loaded for ${Object.keys(api_keys_batch).length} devices`);
86
85
  // Process events response
87
86
  if (events_response.status === EnumWebResponse.SUCCESS &&
88
87
  events_response.data) {
89
88
  recent_events_batch = events_response.data;
90
- console.log(`[HerdModule] Events loaded for ${Object.keys(recent_events_batch).length} devices`);
91
89
  }
92
90
  }
93
91
  catch (error) {
94
- console.error(`[HerdModule] CRITICAL ERROR in batch load after ${Date.now() - batchStartTime}ms:`, error);
92
+ console.error(`[HerdModule] Batch load error:`, error);
95
93
  // Continue without API keys and events
96
94
  }
97
95
  }
98
96
  // Run all remaining requests in parallel with individual error handling
99
97
  const [res_zones, res_user_roles, total_event_count, res_plans, res_sessions,] = await Promise.allSettled([
100
98
  server_get_more_zones_and_actions_for_herd(herd.id, 0, 10).catch((error) => {
101
- console.warn("Failed to get zones and actions:", error);
99
+ console.warn(`[HerdModule] Failed to get zones and actions:`, error);
102
100
  return { status: EnumWebResponse.ERROR, data: null };
103
101
  }),
104
102
  server_get_users_with_herd_access(herd.id).catch((error) => {
105
- console.warn("Failed to get user roles:", error);
103
+ console.warn(`[HerdModule] Failed to get user roles:`, error);
106
104
  return { status: EnumWebResponse.ERROR, data: null };
107
105
  }),
108
106
  server_get_total_events_by_herd(herd.id, EnumSessionsVisibility.Exclude).catch((error) => {
109
- console.warn("Failed to get total events count:", error);
107
+ console.warn(`[HerdModule] Failed to get total events count:`, error);
110
108
  return { status: EnumWebResponse.ERROR, data: null };
111
109
  }),
112
110
  server_get_plans_by_herd(herd.id).catch((error) => {
113
- console.warn("Failed to get plans:", error);
111
+ console.warn(`[HerdModule] Failed to get plans:`, error);
114
112
  return { status: EnumWebResponse.ERROR, data: null };
115
113
  }),
116
114
  getSessionsByHerdId(client, herd.id).catch((error) => {
117
- console.warn("Failed to get sessions:", error);
115
+ console.warn(`[HerdModule] Failed to get sessions:`, error);
118
116
  return [];
119
117
  }),
120
118
  ]);
@@ -151,7 +149,7 @@ export class HerdModule {
151
149
  return new HerdModule(herd, new_devices, [], Date.now(), user_roles, 0, total_events, total_events, newLabels, plans, zones, sessions);
152
150
  }
153
151
  catch (error) {
154
- console.error("Critical error in HerdModule.from_herd:", error);
152
+ console.error(`[HerdModule] Critical error in HerdModule.from_herd:`, error);
155
153
  // Return a minimal but valid HerdModule instance to prevent complete failure
156
154
  return new HerdModule(herd, [], [], Date.now());
157
155
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adventurelabs/scout-core",
3
- "version": "1.0.46",
3
+ "version": "1.0.47",
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",