rhombus-node-mcp 0.1.22 → 0.1.23
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/README.md +8 -0
- package/dist/api/access-control-tool-api.js +256 -0
- package/dist/api/alarm-monitoring-tool-api.js +65 -0
- package/dist/api/camera-tool-api.js +35 -15
- package/dist/api/camera-uptime-tool-api.js +112 -0
- package/dist/api/clips-tool-api.js +110 -21
- package/dist/api/create-tool-api.js +143 -16
- package/dist/api/door-tool-api.js +66 -0
- package/dist/api/events-tool-api.js +151 -28
- package/dist/api/faces-tool-api.js +118 -90
- package/dist/api/get-entity-tool-api.js +2 -0
- package/dist/api/guest-management-tool-api.js +75 -0
- package/dist/api/location-tool-api.js +48 -1
- package/dist/api/lpr-tool-api.js +26 -0
- package/dist/api/policy-alerts-tool-api.js +54 -0
- package/dist/api/report-tool-api.js +345 -23
- package/dist/api/rules-tool-api.js +78 -0
- package/dist/api/search-tool-api.js +93 -0
- package/dist/api/time-tool-api.js +3 -1
- package/dist/api/update-tool-api.js +204 -0
- package/dist/api/user-access-trail-tool-api.js +45 -0
- package/dist/api/user-audit-tool-api.js +47 -0
- package/dist/api/user-tool-api.js +77 -0
- package/dist/createServer.js +3 -1
- package/dist/filtering-utils.js +298 -0
- package/dist/index.js +0 -9
- package/dist/logger.js +6 -5
- package/dist/network.js +18 -4
- package/dist/tools/access-control-tool.js +97 -0
- package/dist/tools/alarm-monitoring-tool.js +50 -0
- package/dist/tools/analytics-tool.js +383 -0
- package/dist/tools/camera-tool.js +27 -9
- package/dist/tools/camera-uptime-tool.js +50 -0
- package/dist/tools/clips-tool.js +46 -16
- package/dist/tools/door-tool.js +66 -0
- package/dist/tools/events-tool.js +103 -81
- package/dist/tools/faces-tool.js +175 -32
- package/dist/tools/get-entity-tool.js +6 -1
- package/dist/tools/guest-management-tool.js +50 -0
- package/dist/tools/location-tool.js +23 -4
- package/dist/tools/lpr-tool.js +26 -20
- package/dist/tools/policy-alerts-tool.js +34 -4
- package/dist/tools/report-tool.js +181 -45
- package/dist/tools/rules-tool.js +76 -0
- package/dist/tools/search-tool.js +69 -0
- package/dist/tools/update-tool.js +63 -2
- package/dist/tools/user-access-trail-tool.js +64 -0
- package/dist/tools/user-audit-tool.js +53 -0
- package/dist/tools/user-tool.js +55 -0
- package/dist/tools/video-walls-tool.js +41 -0
- package/dist/transports/streamable-http.js +25 -15
- package/dist/types/access-control-tool-types.js +120 -0
- package/dist/types/alarm-monitoring-tool-types.js +60 -0
- package/dist/types/analytics-tool-types.js +190 -0
- package/dist/types/camera-tool-types.js +3 -2
- package/dist/types/camera-uptime-tool-types.js +52 -0
- package/dist/types/clips-tool-types.js +60 -11
- package/dist/types/door-tool-types.js +64 -0
- package/dist/types/events-tools-types.js +71 -3
- package/dist/types/faces-tools-types.js +36 -0
- package/dist/types/guest-management-tool-types.js +57 -0
- package/dist/types/location-tool-types.js +10 -1
- package/dist/types/lpr-tool-types.js +14 -0
- package/dist/types/policy-alerts-tool-types.js +38 -3
- package/dist/types/report-tool-types.js +284 -42
- package/dist/types/rules-tool-types.js +58 -0
- package/dist/types/schema.js +3123 -1
- package/dist/types/search-tool-types.js +82 -0
- package/dist/types/update-tool-types.js +4 -1
- package/dist/types/user-access-trail-tool-types.js +54 -0
- package/dist/types/user-audit-tool-types.js +48 -0
- package/dist/types/user-tool-types.js +61 -0
- package/dist/types/video-walls-tool-types.js +59 -0
- package/dist/types/zod-schemas.js +3237 -986
- package/dist/types.js +0 -21
- package/dist/util.js +34 -57
- package/package.json +7 -5
- package/dist/disabled-tools/semantic-search-tool.js +0 -90
- package/dist/tools/create-tool.js +0 -30
- package/dist/types/create-tool-types.js +0 -8
- package/dist/types/schema-components.js +0 -7211
- package/dist/types/semantic-search-tool-types.js +0 -5
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { postApi } from "../network.js";
|
|
2
|
+
export async function getAllGuestsByOrg(requestModifiers, sessionId) {
|
|
3
|
+
const res = await postApi({
|
|
4
|
+
route: "/guestmanagement/getAllGuestsByOrg",
|
|
5
|
+
body: {},
|
|
6
|
+
modifiers: requestModifiers,
|
|
7
|
+
sessionId,
|
|
8
|
+
});
|
|
9
|
+
if (res.error) {
|
|
10
|
+
throw new Error(res.errorMsg ?? "Failed to get guests");
|
|
11
|
+
}
|
|
12
|
+
return (res.allGuests?.map(guest => ({
|
|
13
|
+
firstName: guest.firstName ?? undefined,
|
|
14
|
+
lastName: guest.lastName ?? undefined,
|
|
15
|
+
email: guest.email ?? undefined,
|
|
16
|
+
companyName: guest.companyName ?? undefined,
|
|
17
|
+
locationUuid: guest.locationUuid ?? undefined,
|
|
18
|
+
hostUserUuid: guest.hostUserUuid ?? undefined,
|
|
19
|
+
guestType: guest.guestType ?? undefined,
|
|
20
|
+
checkedInStatus: guest.checkedInEnum ?? undefined,
|
|
21
|
+
lastCheckedInMs: guest.lastCheckedInMs ?? undefined,
|
|
22
|
+
lastCheckedOutMs: guest.lastCheckedOutMs ?? undefined,
|
|
23
|
+
phoneNumber: guest.phoneNumber ?? undefined,
|
|
24
|
+
})) ?? []);
|
|
25
|
+
}
|
|
26
|
+
export async function getGuestActivityLogs(startTimeMs, endTimeMs, requestModifiers, sessionId) {
|
|
27
|
+
const body = {};
|
|
28
|
+
if (startTimeMs)
|
|
29
|
+
body.createdAfterMs = startTimeMs;
|
|
30
|
+
if (endTimeMs)
|
|
31
|
+
body.createdBeforeMs = endTimeMs;
|
|
32
|
+
const res = await postApi({
|
|
33
|
+
route: "/guestmanagement/getGuestActivityLogs",
|
|
34
|
+
body,
|
|
35
|
+
modifiers: requestModifiers,
|
|
36
|
+
sessionId,
|
|
37
|
+
});
|
|
38
|
+
if (res.error) {
|
|
39
|
+
throw new Error(res.errorMsg ?? "Failed to get guest activity logs");
|
|
40
|
+
}
|
|
41
|
+
return (res.guestActivities?.map(a => ({
|
|
42
|
+
activity: a.activity ?? undefined,
|
|
43
|
+
email: a.email ?? undefined,
|
|
44
|
+
guestType: a.guestType ?? undefined,
|
|
45
|
+
locationUuid: a.locationUuid ?? undefined,
|
|
46
|
+
hostUserUuid: a.hostUserUuid ?? undefined,
|
|
47
|
+
timestampMs: a.timestampMs ?? undefined,
|
|
48
|
+
})) ?? []);
|
|
49
|
+
}
|
|
50
|
+
export async function getActivitiesForLocation(locationUuid, startTimeMs, endTimeMs, requestModifiers, sessionId) {
|
|
51
|
+
const body = {
|
|
52
|
+
locationUuid,
|
|
53
|
+
};
|
|
54
|
+
if (startTimeMs)
|
|
55
|
+
body.createdAfterMs = startTimeMs;
|
|
56
|
+
if (endTimeMs)
|
|
57
|
+
body.createdBeforeMs = endTimeMs;
|
|
58
|
+
const res = await postApi({
|
|
59
|
+
route: "/guestmanagement/getActivitiesForLocation",
|
|
60
|
+
body,
|
|
61
|
+
modifiers: requestModifiers,
|
|
62
|
+
sessionId,
|
|
63
|
+
});
|
|
64
|
+
if (res.error) {
|
|
65
|
+
throw new Error(res.errorMsg ?? "Failed to get activities for location");
|
|
66
|
+
}
|
|
67
|
+
return (res.guestActivities?.map(a => ({
|
|
68
|
+
activity: a.activity ?? undefined,
|
|
69
|
+
email: a.email ?? undefined,
|
|
70
|
+
guestType: a.guestType ?? undefined,
|
|
71
|
+
locationUuid: a.locationUuid ?? undefined,
|
|
72
|
+
hostUserUuid: a.hostUserUuid ?? undefined,
|
|
73
|
+
timestampMs: a.timestampMs ?? undefined,
|
|
74
|
+
})) ?? []);
|
|
75
|
+
}
|
|
@@ -1,9 +1,56 @@
|
|
|
1
1
|
import { postApi } from "../network.js";
|
|
2
2
|
export async function getLocations(requestModifiers, sessionId) {
|
|
3
|
-
|
|
3
|
+
const res = await postApi({
|
|
4
4
|
route: "/location/getLocationsV2",
|
|
5
5
|
body: {},
|
|
6
6
|
modifiers: requestModifiers,
|
|
7
7
|
sessionId,
|
|
8
8
|
});
|
|
9
|
+
return {
|
|
10
|
+
locations: (res.locations || []).map((loc) => ({
|
|
11
|
+
uuid: loc.uuid ?? undefined,
|
|
12
|
+
name: loc.name ?? undefined,
|
|
13
|
+
})),
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
export async function createLocation(name, address, requestModifiers, sessionId) {
|
|
17
|
+
const res = await postApi({
|
|
18
|
+
route: "/location/createLocation",
|
|
19
|
+
body: { name, address: address || undefined },
|
|
20
|
+
modifiers: requestModifiers,
|
|
21
|
+
sessionId,
|
|
22
|
+
});
|
|
23
|
+
if (res.error)
|
|
24
|
+
throw new Error(JSON.stringify(res));
|
|
25
|
+
return { uuid: res.locationUuid ?? res.uuid ?? undefined, success: true };
|
|
26
|
+
}
|
|
27
|
+
export async function updateLocation(locationUuid, name, address, requestModifiers, sessionId) {
|
|
28
|
+
const body = { locationUuid };
|
|
29
|
+
if (name)
|
|
30
|
+
body.name = name;
|
|
31
|
+
if (address)
|
|
32
|
+
body.address = address;
|
|
33
|
+
const res = await postApi({
|
|
34
|
+
route: "/location/updateLocation",
|
|
35
|
+
body,
|
|
36
|
+
modifiers: requestModifiers,
|
|
37
|
+
sessionId,
|
|
38
|
+
});
|
|
39
|
+
if (res.error)
|
|
40
|
+
throw new Error(JSON.stringify(res));
|
|
41
|
+
return { success: true };
|
|
42
|
+
}
|
|
43
|
+
export async function getLocationLabels(requestModifiers, sessionId) {
|
|
44
|
+
const res = await postApi({
|
|
45
|
+
route: "/location/getLocationLabelsForOrg",
|
|
46
|
+
body: {},
|
|
47
|
+
modifiers: requestModifiers,
|
|
48
|
+
sessionId,
|
|
49
|
+
});
|
|
50
|
+
if (res.error)
|
|
51
|
+
throw new Error(JSON.stringify(res));
|
|
52
|
+
return (res.locationLabels || []).map((label) => ({
|
|
53
|
+
uuid: label.uuid ?? undefined,
|
|
54
|
+
name: label.name ?? undefined,
|
|
55
|
+
}));
|
|
9
56
|
}
|
package/dist/api/lpr-tool-api.js
CHANGED
|
@@ -66,3 +66,29 @@ export async function getVehicleLabels(requestModifiers, sessionId) {
|
|
|
66
66
|
}
|
|
67
67
|
return processedVehicleLabels;
|
|
68
68
|
}
|
|
69
|
+
export async function searchLicensePlates(query, timeZone, requestModifiers, sessionId) {
|
|
70
|
+
const res = await postApi({
|
|
71
|
+
route: "/search/searchLicensePlates",
|
|
72
|
+
body: { licensePlateQuery: query },
|
|
73
|
+
modifiers: requestModifiers,
|
|
74
|
+
sessionId,
|
|
75
|
+
});
|
|
76
|
+
if (res.error)
|
|
77
|
+
throw new Error(JSON.stringify(res));
|
|
78
|
+
return (res.licensePlateEvents || []).map((event) => ({
|
|
79
|
+
licensePlate: event.vehicleLicensePlate ?? undefined,
|
|
80
|
+
deviceUuid: event.deviceUuid ?? undefined,
|
|
81
|
+
timestampMs: event.eventTimestamp ?? undefined,
|
|
82
|
+
}));
|
|
83
|
+
}
|
|
84
|
+
export async function saveVehicle(name, licensePlate, description, requestModifiers, sessionId) {
|
|
85
|
+
const res = await postApi({
|
|
86
|
+
route: "/vehicle/saveVehicle",
|
|
87
|
+
body: { name, licensePlate, description: description || "" },
|
|
88
|
+
modifiers: requestModifiers,
|
|
89
|
+
sessionId,
|
|
90
|
+
});
|
|
91
|
+
if (res.error)
|
|
92
|
+
throw new Error(JSON.stringify(res));
|
|
93
|
+
return { success: true };
|
|
94
|
+
}
|
|
@@ -40,3 +40,57 @@ export async function getExpiringPolicyAlerts(args, requestModifiers, sessionId)
|
|
|
40
40
|
};
|
|
41
41
|
});
|
|
42
42
|
}
|
|
43
|
+
export async function getPolicyAlertDetails(alertUuid, requestModifiers, sessionId) {
|
|
44
|
+
const response = await postApi({
|
|
45
|
+
route: "/event/getPolicyAlertDetails",
|
|
46
|
+
body: { policyAlertUuid: alertUuid },
|
|
47
|
+
modifiers: requestModifiers,
|
|
48
|
+
sessionId,
|
|
49
|
+
});
|
|
50
|
+
return { policyAlerts: response.policyAlert ? [response.policyAlert] : [] };
|
|
51
|
+
}
|
|
52
|
+
export async function dismissPolicyAlert(alertUuid, requestModifiers, sessionId) {
|
|
53
|
+
const response = await postApi({
|
|
54
|
+
route: "/event/dismissPolicyAlertV2",
|
|
55
|
+
body: { policyAlertUuid: alertUuid },
|
|
56
|
+
modifiers: requestModifiers,
|
|
57
|
+
sessionId,
|
|
58
|
+
});
|
|
59
|
+
return { policyAlerts: [], dismissed: true };
|
|
60
|
+
}
|
|
61
|
+
export async function getUnhealthyDeviceAlerts(requestModifiers, sessionId) {
|
|
62
|
+
const response = await postApi({
|
|
63
|
+
route: "/event/getUnhealthyDeviceAlerts",
|
|
64
|
+
body: {},
|
|
65
|
+
modifiers: requestModifiers,
|
|
66
|
+
sessionId,
|
|
67
|
+
});
|
|
68
|
+
return { policyAlerts: response.unhealthyDeviceAlerts || [] };
|
|
69
|
+
}
|
|
70
|
+
export async function getPolicyAlertGroups(payload, requestModifiers, sessionId) {
|
|
71
|
+
const body = {};
|
|
72
|
+
if (payload.afterTimestampMs)
|
|
73
|
+
body.afterTimestampMs = payload.afterTimestampMs;
|
|
74
|
+
if (payload.beforeTimestampMs)
|
|
75
|
+
body.beforeTimestampMs = payload.beforeTimestampMs;
|
|
76
|
+
if (payload.deviceFilter)
|
|
77
|
+
body.deviceUuids = payload.deviceFilter;
|
|
78
|
+
if (payload.locationFilter)
|
|
79
|
+
body.locationUuids = payload.locationFilter;
|
|
80
|
+
if (payload.maxResults)
|
|
81
|
+
body.maxResults = payload.maxResults;
|
|
82
|
+
if (payload.lastTimestampMs != null)
|
|
83
|
+
body.lastTimestampMs = payload.lastTimestampMs;
|
|
84
|
+
if (payload.lastUuid)
|
|
85
|
+
body.lastUuid = payload.lastUuid;
|
|
86
|
+
const response = await postApi({
|
|
87
|
+
route: "/event/getPolicyAlertGroupsV2",
|
|
88
|
+
body,
|
|
89
|
+
modifiers: requestModifiers,
|
|
90
|
+
sessionId,
|
|
91
|
+
});
|
|
92
|
+
return {
|
|
93
|
+
...response,
|
|
94
|
+
policyAlerts: response.policyAlertGroups || [],
|
|
95
|
+
};
|
|
96
|
+
}
|
|
@@ -1,13 +1,12 @@
|
|
|
1
|
+
import { DateTime } from "luxon";
|
|
1
2
|
import { getLogger } from "../logger.js";
|
|
2
3
|
import { postApi } from "../network.js";
|
|
4
|
+
import { ReportTypeEnum } from "../types/schema.js";
|
|
3
5
|
import { formatTimestamp } from "../util.js";
|
|
4
|
-
import { GetCountReportV2WSRequestTypesEnum } from "../types/schema-components.js";
|
|
5
|
-
import { DateTime } from "luxon";
|
|
6
6
|
const REPORT_TYPES_THAT_RETURN_UTC = new Set([
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
GetCountReportV2WSRequestTypesEnum.DWELL,
|
|
7
|
+
ReportTypeEnum.BANDWIDTH,
|
|
8
|
+
ReportTypeEnum.LICENSEPLATES,
|
|
9
|
+
ReportTypeEnum.DWELL,
|
|
11
10
|
]);
|
|
12
11
|
const logger = getLogger();
|
|
13
12
|
function getUtcTime(datetime, reportType, timeZone) {
|
|
@@ -15,8 +14,8 @@ function getUtcTime(datetime, reportType, timeZone) {
|
|
|
15
14
|
return datetime;
|
|
16
15
|
}
|
|
17
16
|
else {
|
|
18
|
-
logger.
|
|
19
|
-
return DateTime.fromISO(datetime, { zone: timeZone }).toUTC().toISO();
|
|
17
|
+
logger.trace("timeZone", datetime);
|
|
18
|
+
return DateTime.fromISO(datetime, { zone: timeZone }).toUTC().toISO() ?? datetime;
|
|
20
19
|
}
|
|
21
20
|
}
|
|
22
21
|
export async function getOccupancyCountReport(deviceUuid, startTimeMs, endTimeMs, interval, requestModifiers, sessionId) {
|
|
@@ -59,7 +58,9 @@ export async function getSummaryCountReport(interval, scope, types, uuid, endTim
|
|
|
59
58
|
scope,
|
|
60
59
|
startTimeMs,
|
|
61
60
|
types,
|
|
62
|
-
|
|
61
|
+
// omit for org
|
|
62
|
+
...(uuid && scope !== "ORG" ? { uuid } : {}),
|
|
63
|
+
...(timeZone ? { timeZone } : {}),
|
|
63
64
|
};
|
|
64
65
|
const response = await postApi({
|
|
65
66
|
route: "/report/getCountReportV2",
|
|
@@ -68,8 +69,8 @@ export async function getSummaryCountReport(interval, scope, types, uuid, endTim
|
|
|
68
69
|
sessionId,
|
|
69
70
|
});
|
|
70
71
|
// Process response to convert date strings to UTC milliseconds timestamps
|
|
71
|
-
let newTimeSeriesDataPoints
|
|
72
|
-
if (response
|
|
72
|
+
let newTimeSeriesDataPoints;
|
|
73
|
+
if (response?.timeSeriesDataPoints && Array.isArray(response.timeSeriesDataPoints)) {
|
|
73
74
|
newTimeSeriesDataPoints = response.timeSeriesDataPoints.map((dataPoint) => {
|
|
74
75
|
const sanitizedDataPoint = {
|
|
75
76
|
eventCountMap: dataPoint.eventCountMap,
|
|
@@ -162,7 +163,7 @@ export async function getThresholdCrossingCountReport(deviceUuid, startTimeMs, e
|
|
|
162
163
|
}))
|
|
163
164
|
: undefined;
|
|
164
165
|
// Calculate metrics if we have crossing counts and the bucket size is appropriate
|
|
165
|
-
let metrics
|
|
166
|
+
let metrics;
|
|
166
167
|
if (crossingCounts && crossingCounts.length > 0) {
|
|
167
168
|
// Calculate total entries and exits
|
|
168
169
|
let totalEntries = 0;
|
|
@@ -244,17 +245,17 @@ export async function getThresholdCrossingCountReport(deviceUuid, startTimeMs, e
|
|
|
244
245
|
averageExitsPerHour: totalExits / hoursInPeriod,
|
|
245
246
|
mostEntriesInHour: {
|
|
246
247
|
count: maxEntries,
|
|
247
|
-
timestamp: maxEntriesTimestamp ? DateTime.fromMillis(maxEntriesTimestamp).toISO() : "",
|
|
248
|
+
timestamp: maxEntriesTimestamp ? DateTime.fromMillis(maxEntriesTimestamp).toISO() ?? "" : "",
|
|
248
249
|
hourLabel: formatHourLabel(maxEntriesTimestamp),
|
|
249
250
|
},
|
|
250
251
|
mostExitsInHour: {
|
|
251
252
|
count: maxExits,
|
|
252
|
-
timestamp: maxExitsTimestamp ? DateTime.fromMillis(maxExitsTimestamp).toISO() : "",
|
|
253
|
+
timestamp: maxExitsTimestamp ? DateTime.fromMillis(maxExitsTimestamp).toISO() ?? "" : "",
|
|
253
254
|
hourLabel: formatHourLabel(maxExitsTimestamp),
|
|
254
255
|
},
|
|
255
256
|
busiestHour: {
|
|
256
257
|
totalCount: maxTotal,
|
|
257
|
-
timestamp: maxTotalTimestamp ? DateTime.fromMillis(maxTotalTimestamp).toISO() : "",
|
|
258
|
+
timestamp: maxTotalTimestamp ? DateTime.fromMillis(maxTotalTimestamp).toISO() ?? "" : "",
|
|
258
259
|
hourLabel: formatHourLabel(maxTotalTimestamp),
|
|
259
260
|
entries: maxTotalEntries,
|
|
260
261
|
exits: maxTotalExits,
|
|
@@ -307,13 +308,10 @@ export async function getCustomLLMReport(promptUuid, promptType, startTimeMs, en
|
|
|
307
308
|
endTimeMs,
|
|
308
309
|
interval,
|
|
309
310
|
}));
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
startTimeMs,
|
|
313
|
-
endTimeMs,
|
|
314
|
-
interval,
|
|
315
|
-
};
|
|
316
|
-
// Determine the correct endpoint based on promptType
|
|
311
|
+
// PERCENT endpoint uses a different request schema that doesn't accept interval
|
|
312
|
+
const body = promptType === "PERCENT"
|
|
313
|
+
? { promptUuid, startTimeMs, endTimeMs }
|
|
314
|
+
: { promptUuid, startTimeMs, endTimeMs, interval };
|
|
317
315
|
let route;
|
|
318
316
|
switch (promptType) {
|
|
319
317
|
case "COUNT":
|
|
@@ -348,7 +346,7 @@ export async function getCustomLLMReport(promptUuid, promptType, startTimeMs, en
|
|
|
348
346
|
logger.info(`📊 ${promptType} response structure:`, JSON.stringify({ reportEntries: reportEntries.length }));
|
|
349
347
|
// Aggregate data from all devices
|
|
350
348
|
const aggregatedData = {};
|
|
351
|
-
reportEntries.forEach(([
|
|
349
|
+
reportEntries.forEach(([_, reportData]) => {
|
|
352
350
|
if (Array.isArray(reportData)) {
|
|
353
351
|
reportData.forEach((item) => {
|
|
354
352
|
const dateKey = item.localDate || new Date().toISOString();
|
|
@@ -424,3 +422,327 @@ export async function getCustomLLMReport(promptUuid, promptType, startTimeMs, en
|
|
|
424
422
|
}));
|
|
425
423
|
return result;
|
|
426
424
|
}
|
|
425
|
+
export async function getAuditFeed(startTimeMs, endTimeMs, requestModifiers, sessionId) {
|
|
426
|
+
const body = { startTimeMs, endTimeMs };
|
|
427
|
+
const response = await postApi({
|
|
428
|
+
route: "/report/getAuditFeed",
|
|
429
|
+
body,
|
|
430
|
+
modifiers: requestModifiers,
|
|
431
|
+
sessionId,
|
|
432
|
+
});
|
|
433
|
+
return {
|
|
434
|
+
error: response.error ?? undefined,
|
|
435
|
+
errorMsg: response.errorMsg ?? undefined,
|
|
436
|
+
auditEvents: (response.auditEvents || []).map((event) => ({
|
|
437
|
+
timestamp: event.timestamp != null ? String(event.timestamp) : undefined,
|
|
438
|
+
action: event.action ?? undefined,
|
|
439
|
+
displayText: event.displayText ?? undefined,
|
|
440
|
+
principalName: event.principalName ?? undefined,
|
|
441
|
+
principalUuid: event.principalUuid ?? undefined,
|
|
442
|
+
principalType: event.principalType ?? undefined,
|
|
443
|
+
targetName: event.targetName ?? undefined,
|
|
444
|
+
targetUuid: event.targetUuid ?? undefined,
|
|
445
|
+
})),
|
|
446
|
+
};
|
|
447
|
+
}
|
|
448
|
+
export async function getDiagnosticFeed(startTimeMs, endTimeMs, requestModifiers, sessionId) {
|
|
449
|
+
const body = { startTimeMs, endTimeMs };
|
|
450
|
+
const response = await postApi({
|
|
451
|
+
route: "/report/getDiagnosticFeed",
|
|
452
|
+
body,
|
|
453
|
+
modifiers: requestModifiers,
|
|
454
|
+
sessionId,
|
|
455
|
+
});
|
|
456
|
+
return {
|
|
457
|
+
error: response.error ?? undefined,
|
|
458
|
+
errorMsg: response.errorMsg ?? undefined,
|
|
459
|
+
diagnosticEvents: (response.diagnosticEvents || []).map((event) => ({
|
|
460
|
+
timestampMs: event.timestamp ?? undefined,
|
|
461
|
+
deviceUuid: event.deviceUuid ?? undefined,
|
|
462
|
+
eventType: event.activity ?? undefined,
|
|
463
|
+
description: event.description ?? undefined,
|
|
464
|
+
})),
|
|
465
|
+
};
|
|
466
|
+
}
|
|
467
|
+
export async function getThresholdCrossingEvents(deviceUuid, startTimeMs, endTimeMs, requestModifiers, sessionId) {
|
|
468
|
+
const body = { deviceUuid, startTimeMs, endTimeMs };
|
|
469
|
+
const response = await postApi({
|
|
470
|
+
route: "/report/getThresholdCrossingEvents",
|
|
471
|
+
body,
|
|
472
|
+
modifiers: requestModifiers,
|
|
473
|
+
sessionId,
|
|
474
|
+
});
|
|
475
|
+
return {
|
|
476
|
+
error: response.error ?? undefined,
|
|
477
|
+
errorMsg: response.errorMsg ?? undefined,
|
|
478
|
+
events: (response.thresholdEvents || response.events || []).map((event) => ({
|
|
479
|
+
timestampMs: event.timestampMs ?? undefined,
|
|
480
|
+
direction: event.direction ?? undefined,
|
|
481
|
+
objectType: event.objectType ?? undefined,
|
|
482
|
+
})),
|
|
483
|
+
};
|
|
484
|
+
}
|
|
485
|
+
export async function getCustomEventsReport(promptUuid, startTimeMs, endTimeMs, interval, requestModifiers, sessionId) {
|
|
486
|
+
const body = { promptUuid, startTimeMs, endTimeMs, interval };
|
|
487
|
+
const response = await postApi({
|
|
488
|
+
route: "/report/getCustomEventsReport",
|
|
489
|
+
body,
|
|
490
|
+
modifiers: requestModifiers,
|
|
491
|
+
sessionId,
|
|
492
|
+
});
|
|
493
|
+
return {
|
|
494
|
+
error: response.error ?? undefined,
|
|
495
|
+
errorMsg: response.errorMsg ?? undefined,
|
|
496
|
+
timeSeriesDataPoints: response.timeSeriesDataPoints?.map((dp) => ({
|
|
497
|
+
dateLocal: dp.dateLocal ?? undefined,
|
|
498
|
+
dateUtc: dp.dateUtc ?? undefined,
|
|
499
|
+
eventCountMap: dp.eventCountMap ?? undefined,
|
|
500
|
+
})),
|
|
501
|
+
};
|
|
502
|
+
}
|
|
503
|
+
export async function getPeopleCountEvents(deviceUuids, requestModifiers, sessionId) {
|
|
504
|
+
const body = { deviceUuids };
|
|
505
|
+
const response = await postApi({
|
|
506
|
+
route: "/report/getMostRecentPeopleCountEvents",
|
|
507
|
+
body,
|
|
508
|
+
modifiers: requestModifiers,
|
|
509
|
+
sessionId,
|
|
510
|
+
});
|
|
511
|
+
return {
|
|
512
|
+
error: response.error ?? undefined,
|
|
513
|
+
errorMsg: response.errorMsg ?? undefined,
|
|
514
|
+
events: (response.events || []).map((event) => ({
|
|
515
|
+
deviceUuid: event.deviceUuid ?? undefined,
|
|
516
|
+
timestampMs: event.timestampMs ?? undefined,
|
|
517
|
+
count: event.count ?? undefined,
|
|
518
|
+
})),
|
|
519
|
+
};
|
|
520
|
+
}
|
|
521
|
+
export async function getBatchThresholdCrossingCountReport(deviceUuids, startTimeMs, endTimeMs, bucketSize, crossingObject, dedupe, timeZone, requestModifiers, sessionId) {
|
|
522
|
+
const body = {
|
|
523
|
+
deviceUuids,
|
|
524
|
+
startTimeMs,
|
|
525
|
+
endTimeMs,
|
|
526
|
+
bucketSize,
|
|
527
|
+
crossingObject,
|
|
528
|
+
dedupe,
|
|
529
|
+
...(timeZone ? { timeZone } : {}),
|
|
530
|
+
};
|
|
531
|
+
const response = await postApi({
|
|
532
|
+
route: "/report/getBatchThresholdCrossingCountReport",
|
|
533
|
+
body,
|
|
534
|
+
modifiers: requestModifiers,
|
|
535
|
+
sessionId,
|
|
536
|
+
});
|
|
537
|
+
if (response.error) {
|
|
538
|
+
throw new Error(response.errorMsg ?? "Failed to get batch threshold crossing report");
|
|
539
|
+
}
|
|
540
|
+
const deviceCrossingCounts = response.deviceCrossingCounts ?? response.crossingCounts ?? {};
|
|
541
|
+
const result = {};
|
|
542
|
+
for (const [deviceUuid, counts] of Object.entries(deviceCrossingCounts)) {
|
|
543
|
+
result[deviceUuid] = (counts || []).map((c) => ({
|
|
544
|
+
timestampMs: c.timestampMs ?? undefined,
|
|
545
|
+
ingressCount: c.ingressCount ?? undefined,
|
|
546
|
+
egressCount: c.egressCount ?? undefined,
|
|
547
|
+
}));
|
|
548
|
+
}
|
|
549
|
+
return result;
|
|
550
|
+
}
|
|
551
|
+
export async function getThresholdCrossingCountReportForOrg(startTimeMs, endTimeMs, bucketSize, crossingObject, dedupe, timeZone, requestModifiers, sessionId) {
|
|
552
|
+
const body = {
|
|
553
|
+
startTimeMs,
|
|
554
|
+
endTimeMs,
|
|
555
|
+
bucketSize,
|
|
556
|
+
crossingObject,
|
|
557
|
+
dedupe,
|
|
558
|
+
...(timeZone ? { timeZone } : {}),
|
|
559
|
+
};
|
|
560
|
+
const response = await postApi({
|
|
561
|
+
route: "/report/getThresholdCrossingCountReportForOrg",
|
|
562
|
+
body,
|
|
563
|
+
modifiers: requestModifiers,
|
|
564
|
+
sessionId,
|
|
565
|
+
});
|
|
566
|
+
if (response.error) {
|
|
567
|
+
throw new Error(response.errorMsg ?? "Failed to get org threshold crossing report");
|
|
568
|
+
}
|
|
569
|
+
return (response.crossingCounts ?? []).map(c => ({
|
|
570
|
+
timestampMs: c.timestampMs ?? undefined,
|
|
571
|
+
ingressCount: c.ingressCount ?? undefined,
|
|
572
|
+
egressCount: c.egressCount ?? undefined,
|
|
573
|
+
}));
|
|
574
|
+
}
|
|
575
|
+
export async function getThresholdCrossingCounts(devices, startTimeMs, endTimeMs, crossingObject, dailyResetTimeMinute, requestModifiers, sessionId) {
|
|
576
|
+
const body = {
|
|
577
|
+
devices,
|
|
578
|
+
startTimeMs,
|
|
579
|
+
endTimeMs,
|
|
580
|
+
crossingObject,
|
|
581
|
+
};
|
|
582
|
+
if (dailyResetTimeMinute != null)
|
|
583
|
+
body.dailyResetTimeMinute = dailyResetTimeMinute;
|
|
584
|
+
const response = await postApi({
|
|
585
|
+
route: "/report/getThresholdCrossingCounts",
|
|
586
|
+
body,
|
|
587
|
+
modifiers: requestModifiers,
|
|
588
|
+
sessionId,
|
|
589
|
+
});
|
|
590
|
+
if (response.error) {
|
|
591
|
+
throw new Error(response.errorMsg ?? "Failed to get threshold crossing counts");
|
|
592
|
+
}
|
|
593
|
+
return (response.counts ?? []).map((c) => ({
|
|
594
|
+
count: c.count ?? undefined,
|
|
595
|
+
timestampMs: c.timestampMs ?? undefined,
|
|
596
|
+
}));
|
|
597
|
+
}
|
|
598
|
+
export async function getCountReportsForDevicesAtLocation(locationUuid, startTimeMs, endTimeMs, interval, type, requestModifiers, sessionId) {
|
|
599
|
+
const body = {
|
|
600
|
+
locationUuid,
|
|
601
|
+
startTimeMs,
|
|
602
|
+
endTimeMs,
|
|
603
|
+
interval,
|
|
604
|
+
type,
|
|
605
|
+
};
|
|
606
|
+
const response = await postApi({
|
|
607
|
+
route: "/report/getCountReportsForDevicesAtLocation",
|
|
608
|
+
body,
|
|
609
|
+
modifiers: requestModifiers,
|
|
610
|
+
sessionId,
|
|
611
|
+
});
|
|
612
|
+
if (response.error) {
|
|
613
|
+
throw new Error(response.errorMsg ?? "Failed to get count reports for devices at location");
|
|
614
|
+
}
|
|
615
|
+
const deviceDataMap = {};
|
|
616
|
+
const rawMap = response.timeSeriesDataPointsMap ?? {};
|
|
617
|
+
for (const [deviceUuid, dataPoints] of Object.entries(rawMap)) {
|
|
618
|
+
deviceDataMap[deviceUuid] = (dataPoints || []).map((dp) => ({
|
|
619
|
+
dateUtcString: dp.dateLocal ?? dp.dateUtc ?? undefined,
|
|
620
|
+
eventCountMap: dp.eventCountMap ?? undefined,
|
|
621
|
+
}));
|
|
622
|
+
}
|
|
623
|
+
return deviceDataMap;
|
|
624
|
+
}
|
|
625
|
+
export async function getRunningAverage(uuid, startTimeMs, endTimeMs, interval, scope, timeZone, requestModifiers, sessionId) {
|
|
626
|
+
const body = {
|
|
627
|
+
startTimeMs,
|
|
628
|
+
endTimeMs,
|
|
629
|
+
interval,
|
|
630
|
+
scope,
|
|
631
|
+
};
|
|
632
|
+
if (uuid)
|
|
633
|
+
body.uuid = uuid;
|
|
634
|
+
if (timeZone)
|
|
635
|
+
body.timeZone = timeZone;
|
|
636
|
+
const response = await postApi({
|
|
637
|
+
route: "/report/getRunningAverage",
|
|
638
|
+
body,
|
|
639
|
+
modifiers: requestModifiers,
|
|
640
|
+
sessionId,
|
|
641
|
+
});
|
|
642
|
+
if (response.error) {
|
|
643
|
+
throw new Error(response.errorMsg ?? "Failed to get running average");
|
|
644
|
+
}
|
|
645
|
+
return (response.statsDataPoints ?? []).map((dp) => ({
|
|
646
|
+
date: dp.date ?? undefined,
|
|
647
|
+
stats: dp.stats ?? undefined,
|
|
648
|
+
}));
|
|
649
|
+
}
|
|
650
|
+
export async function triggerScenePrompt(deviceFacetUuid, prompt, promptType, timestampMs, requestModifiers, sessionId) {
|
|
651
|
+
const body = {
|
|
652
|
+
deviceFacetUuid,
|
|
653
|
+
prompt,
|
|
654
|
+
promptType,
|
|
655
|
+
};
|
|
656
|
+
if (timestampMs != null)
|
|
657
|
+
body.timestampMs = timestampMs;
|
|
658
|
+
const response = await postApi({
|
|
659
|
+
route: "/scenequery/triggerPrompt",
|
|
660
|
+
body,
|
|
661
|
+
modifiers: requestModifiers,
|
|
662
|
+
sessionId,
|
|
663
|
+
});
|
|
664
|
+
if (response.error) {
|
|
665
|
+
throw new Error(response.errorMsg ?? "Failed to trigger scene prompt");
|
|
666
|
+
}
|
|
667
|
+
const event = response.event;
|
|
668
|
+
return {
|
|
669
|
+
value: event?.value ?? undefined,
|
|
670
|
+
prompt: event?.prompt ?? undefined,
|
|
671
|
+
timestampMs: event?.timestampMs ?? undefined,
|
|
672
|
+
checkCondition: event?.checkCondition ?? undefined,
|
|
673
|
+
image: event?.image ?? undefined,
|
|
674
|
+
};
|
|
675
|
+
}
|
|
676
|
+
export async function adHocScenePrompt(deviceFacetUuid, promptUuid, timestampMs, requestModifiers, sessionId) {
|
|
677
|
+
const body = {
|
|
678
|
+
deviceFacetUuid,
|
|
679
|
+
promptUuid,
|
|
680
|
+
};
|
|
681
|
+
if (timestampMs != null)
|
|
682
|
+
body.timestampMs = timestampMs;
|
|
683
|
+
const response = await postApi({
|
|
684
|
+
route: "/scenequery/adHocPrompt",
|
|
685
|
+
body,
|
|
686
|
+
modifiers: requestModifiers,
|
|
687
|
+
sessionId,
|
|
688
|
+
});
|
|
689
|
+
if (response.error) {
|
|
690
|
+
throw new Error(response.errorMsg ?? "Failed to execute ad-hoc scene prompt");
|
|
691
|
+
}
|
|
692
|
+
const event = response.event;
|
|
693
|
+
return {
|
|
694
|
+
value: event?.value ?? undefined,
|
|
695
|
+
prompt: event?.prompt ?? undefined,
|
|
696
|
+
timestampMs: event?.timestampMs ?? undefined,
|
|
697
|
+
checkCondition: event?.checkCondition ?? undefined,
|
|
698
|
+
image: event?.image ?? undefined,
|
|
699
|
+
};
|
|
700
|
+
}
|
|
701
|
+
const MAX_FACE_COUNT_PAGES = 5;
|
|
702
|
+
const FACE_COUNT_PAGE_SIZE = 200;
|
|
703
|
+
export async function getUniqueFaceCount(deviceUuid, startTimeMs, endTimeMs, requestModifiers, sessionId) {
|
|
704
|
+
const uniquePersonUuids = new Set();
|
|
705
|
+
let totalFaceEvents = 0;
|
|
706
|
+
let lastEvaluatedKey;
|
|
707
|
+
for (let page = 0; page < MAX_FACE_COUNT_PAGES; page++) {
|
|
708
|
+
const body = {
|
|
709
|
+
searchFilter: {
|
|
710
|
+
deviceUuids: [deviceUuid],
|
|
711
|
+
timestampFilter: {
|
|
712
|
+
rangeStart: new Date(startTimeMs).toISOString(),
|
|
713
|
+
rangeEnd: new Date(endTimeMs).toISOString(),
|
|
714
|
+
},
|
|
715
|
+
},
|
|
716
|
+
pageRequest: {
|
|
717
|
+
maxPageSize: FACE_COUNT_PAGE_SIZE,
|
|
718
|
+
...(lastEvaluatedKey ? { lastEvaluatedKey } : {}),
|
|
719
|
+
},
|
|
720
|
+
};
|
|
721
|
+
try {
|
|
722
|
+
const response = await postApi({
|
|
723
|
+
route: "/faceRecognition/faceEvent/findFaceEventsByOrg",
|
|
724
|
+
body,
|
|
725
|
+
modifiers: requestModifiers,
|
|
726
|
+
sessionId,
|
|
727
|
+
});
|
|
728
|
+
if (response.error || !response.faceEvents) {
|
|
729
|
+
break;
|
|
730
|
+
}
|
|
731
|
+
for (const event of response.faceEvents) {
|
|
732
|
+
totalFaceEvents++;
|
|
733
|
+
if (event.personUuid) {
|
|
734
|
+
uniquePersonUuids.add(event.personUuid);
|
|
735
|
+
}
|
|
736
|
+
}
|
|
737
|
+
if (response.faceEvents.length < FACE_COUNT_PAGE_SIZE || !response.lastEvaluatedKey) {
|
|
738
|
+
break;
|
|
739
|
+
}
|
|
740
|
+
lastEvaluatedKey = response.lastEvaluatedKey;
|
|
741
|
+
}
|
|
742
|
+
catch (err) {
|
|
743
|
+
logger.error("Error fetching face events for enrichment", err);
|
|
744
|
+
break;
|
|
745
|
+
}
|
|
746
|
+
}
|
|
747
|
+
return { uniqueFaceCount: uniquePersonUuids.size, totalFaceEvents };
|
|
748
|
+
}
|