@camstack/addon-ai 0.1.3 → 0.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/addon.js +177 -13
- package/dist/addon.mjs +177 -13
- package/package.json +1 -1
package/dist/addon.js
CHANGED
|
@@ -43,7 +43,7 @@ let node_fs_promises = require("node:fs/promises");
|
|
|
43
43
|
node_fs_promises = __toESM(node_fs_promises);
|
|
44
44
|
let node_child_process = require("node:child_process");
|
|
45
45
|
let node_net = require("node:net");
|
|
46
|
-
//#region ../types/dist/event-category-
|
|
46
|
+
//#region ../types/dist/event-category-H4AVePnn.mjs
|
|
47
47
|
var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
48
48
|
EventCategory["SystemBoot"] = "system.boot";
|
|
49
49
|
EventCategory["SystemAddonsReady"] = "system.addons-ready";
|
|
@@ -193,6 +193,9 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
|
193
193
|
EventCategory["RecordingSegmentWritten"] = "recording.segment.written";
|
|
194
194
|
EventCategory["RecordingPolicyFallback"] = "recording.policy.fallback";
|
|
195
195
|
EventCategory["RecordingRetentionCompleted"] = "recording.retention.completed";
|
|
196
|
+
/** Runner-sampled scrub thumbnail (~1/5 s/camera). Telemetry (D8): a lost
|
|
197
|
+
* thumb is a scrub gap the recorder's keyframe backfill covers. */
|
|
198
|
+
EventCategory["RecordingThumbSampled"] = "recording.thumb-sampled";
|
|
196
199
|
EventCategory["DetectionEvent"] = "detection.event";
|
|
197
200
|
EventCategory["SessionTrackNew"] = "session.track.new";
|
|
198
201
|
EventCategory["SessionTrackExpired"] = "session.track.expired";
|
|
@@ -9887,7 +9890,7 @@ object({
|
|
|
9887
9890
|
deviceId: number(),
|
|
9888
9891
|
timestamp: number()
|
|
9889
9892
|
});
|
|
9890
|
-
DeviceType.Button;
|
|
9893
|
+
DeviceType.Button, DeviceType.Camera;
|
|
9891
9894
|
/**
|
|
9892
9895
|
* Enum-state sensor — a string value picked from a finite option set.
|
|
9893
9896
|
* Drives HA `sensor` entries with `state_class: enum` (HVAC action
|
|
@@ -14257,6 +14260,14 @@ var ConfigEntrySchema = object({
|
|
|
14257
14260
|
value: unknown(),
|
|
14258
14261
|
description: string().optional()
|
|
14259
14262
|
});
|
|
14263
|
+
var DeviceLinkModeSchema = _enum(["auto", "manual"]);
|
|
14264
|
+
/** One resolved linked device — the compact projection consumers need. */
|
|
14265
|
+
var LinkedDeviceSchema = object({
|
|
14266
|
+
deviceId: number(),
|
|
14267
|
+
name: string(),
|
|
14268
|
+
location: string().nullable(),
|
|
14269
|
+
features: array(string())
|
|
14270
|
+
});
|
|
14260
14271
|
var SavedDeviceRowSchema = object({
|
|
14261
14272
|
/** Numeric id reserved at allocateDeviceId time. */
|
|
14262
14273
|
id: number(),
|
|
@@ -14478,7 +14489,10 @@ method(object({
|
|
|
14478
14489
|
}), _void(), {
|
|
14479
14490
|
kind: "mutation",
|
|
14480
14491
|
auth: "admin"
|
|
14481
|
-
}), method(object({ addonId: string() }), array(SavedDeviceRowSchema)), method(object({ addonId: string().optional() }), array(DeviceInfoSchema)), method(object({ deviceId: number() }), DeviceInfoSchema.nullable()), method(object({ parentDeviceId: number() }), array(DeviceInfoSchema)), method(object({ deviceId: number() }),
|
|
14492
|
+
}), method(object({ addonId: string() }), array(SavedDeviceRowSchema)), method(object({ addonId: string().optional() }), array(DeviceInfoSchema)), method(object({ deviceId: number() }), DeviceInfoSchema.nullable()), method(object({ parentDeviceId: number() }), array(DeviceInfoSchema)), method(object({ deviceId: number() }), object({
|
|
14493
|
+
mode: DeviceLinkModeSchema,
|
|
14494
|
+
devices: array(LinkedDeviceSchema)
|
|
14495
|
+
})), method(object({ deviceId: number() }), array(StreamSourceEntrySchema$1)), method(object({ deviceId: number() }), array(ConfigEntrySchema)), method(object({ deviceId: number() }), ConfigUISchemaOutput), method(object({
|
|
14482
14496
|
deviceId: number(),
|
|
14483
14497
|
values: record(string(), unknown())
|
|
14484
14498
|
}), object({ success: literal(true) }), {
|
|
@@ -15792,6 +15806,61 @@ var EventKindSchema = _enum([
|
|
|
15792
15806
|
"object",
|
|
15793
15807
|
"audio"
|
|
15794
15808
|
]);
|
|
15809
|
+
/**
|
|
15810
|
+
* Spatial filter for `listTracks` — the rect + polygon variants of the shared
|
|
15811
|
+
* MaskShape vocabulary (see `mask-shape.ts`). Coordinates are NORMALIZED 0..1
|
|
15812
|
+
* of the camera frame (top-left origin), matching the drawing-plane editor.
|
|
15813
|
+
*/
|
|
15814
|
+
var TrackZoneFilterSchema = discriminatedUnion("kind", [MaskRectShapeSchema, MaskPolygonShapeSchema]);
|
|
15815
|
+
/** Closed icon vocabulary so clients render a known glyph per kind. */
|
|
15816
|
+
var EventKindIconSchema = _enum([
|
|
15817
|
+
"motion",
|
|
15818
|
+
"audio",
|
|
15819
|
+
"person",
|
|
15820
|
+
"vehicle",
|
|
15821
|
+
"animal",
|
|
15822
|
+
"door",
|
|
15823
|
+
"pir",
|
|
15824
|
+
"smoke",
|
|
15825
|
+
"water",
|
|
15826
|
+
"button",
|
|
15827
|
+
"generic"
|
|
15828
|
+
]);
|
|
15829
|
+
var EventKindCategorySchema = _enum([
|
|
15830
|
+
"motion",
|
|
15831
|
+
"audio",
|
|
15832
|
+
"detection",
|
|
15833
|
+
"sensor",
|
|
15834
|
+
"custom"
|
|
15835
|
+
]);
|
|
15836
|
+
var EventKindDescriptorSchema = object({
|
|
15837
|
+
/** Stable kind id (e.g. 'motion', 'person', 'contact'). */
|
|
15838
|
+
kind: string(),
|
|
15839
|
+
label: string(),
|
|
15840
|
+
/** Hex color for timeline/legend rendering. */
|
|
15841
|
+
color: string(),
|
|
15842
|
+
icon: EventKindIconSchema,
|
|
15843
|
+
category: EventKindCategorySchema,
|
|
15844
|
+
/** Which cap + device contributes this kind. For built-ins the camera
|
|
15845
|
+
* itself; for sensor kinds the LINKED source device. */
|
|
15846
|
+
source: object({
|
|
15847
|
+
capName: string(),
|
|
15848
|
+
deviceId: number()
|
|
15849
|
+
})
|
|
15850
|
+
});
|
|
15851
|
+
var SensorEventSchema = object({
|
|
15852
|
+
id: string(),
|
|
15853
|
+
/** The CAMERA the event is attributed to (a sensor linked to N cameras
|
|
15854
|
+
* yields N rows, one per camera). */
|
|
15855
|
+
deviceId: number(),
|
|
15856
|
+
/** The linked sensor device whose state changed. */
|
|
15857
|
+
sourceDeviceId: number(),
|
|
15858
|
+
/** Event kind id — matches an `EventKindDescriptor.kind`. */
|
|
15859
|
+
kind: string(),
|
|
15860
|
+
/** Snapshot of the sensor cap's runtime-state slice at the change. */
|
|
15861
|
+
value: record(string(), unknown()).nullable(),
|
|
15862
|
+
timestamp: number()
|
|
15863
|
+
});
|
|
15795
15864
|
var TrackPositionSchema = object({
|
|
15796
15865
|
x: number(),
|
|
15797
15866
|
y: number(),
|
|
@@ -15805,6 +15874,30 @@ var TrackSnapshotSchema = object({
|
|
|
15805
15874
|
mediaKey: string()
|
|
15806
15875
|
});
|
|
15807
15876
|
/**
|
|
15877
|
+
* Normalized 0..1 trajectory envelope (min/max over every position bbox,
|
|
15878
|
+
* divided by the track's detection-frame dims), computed at persist time.
|
|
15879
|
+
* Absent when the frame dims were unknown when the track was persisted
|
|
15880
|
+
* (legacy rows / dims-less sources) and on active (in-RAM) tracks.
|
|
15881
|
+
*/
|
|
15882
|
+
var TrackEnvelopeSchema = object({
|
|
15883
|
+
minX: number(),
|
|
15884
|
+
minY: number(),
|
|
15885
|
+
maxX: number(),
|
|
15886
|
+
maxY: number()
|
|
15887
|
+
});
|
|
15888
|
+
/**
|
|
15889
|
+
* Row projection for track list queries. `full` (default) returns the
|
|
15890
|
+
* complete Track including the frame-rate `positions[]` history and the
|
|
15891
|
+
* `snapshots[]` references — megabytes across a page of tracks. `slim`
|
|
15892
|
+
* keeps every scalar the list surfaces actually render (ids, class(es),
|
|
15893
|
+
* label / audioLabels / importance enrichment, firstSeen/lastSeen, state,
|
|
15894
|
+
* zonesVisited, bestEventId, envelope) and returns `positions` /
|
|
15895
|
+
* `snapshots` as EMPTY arrays — detail views re-fetch the full row via
|
|
15896
|
+
* `getTrack`. Mirrors the event-store `projection` convention
|
|
15897
|
+
* (`getObjectEvents` et al.).
|
|
15898
|
+
*/
|
|
15899
|
+
var TrackProjectionSchema = _enum(["full", "slim"]);
|
|
15900
|
+
/**
|
|
15808
15901
|
* One audio-classification label heard on the track's camera while the
|
|
15809
15902
|
* track was alive, aggregated per label. An "episode" is one persisted
|
|
15810
15903
|
* audio event (the confident-classification path: score ≥ the device's
|
|
@@ -15855,7 +15948,11 @@ var TrackSchema = object({
|
|
|
15855
15948
|
/** Audio-classification labels heard on the camera during the track's
|
|
15856
15949
|
* life (score ≥ device `classificationMinScore`), aggregated per label.
|
|
15857
15950
|
* Absent on legacy rows / tracks with no confident audio. */
|
|
15858
|
-
audioLabels: array(TrackAudioLabelSchema).readonly().optional()
|
|
15951
|
+
audioLabels: array(TrackAudioLabelSchema).readonly().optional(),
|
|
15952
|
+
/** Normalized 0..1 trajectory envelope (see {@link TrackEnvelopeSchema}).
|
|
15953
|
+
* Populated from the persisted envelope columns on historical reads;
|
|
15954
|
+
* absent on legacy rows, dims-less tracks and active (in-RAM) tracks. */
|
|
15955
|
+
envelope: TrackEnvelopeSchema.optional()
|
|
15859
15956
|
});
|
|
15860
15957
|
var BaseEventFields = {
|
|
15861
15958
|
id: string(),
|
|
@@ -15965,11 +16062,13 @@ var MediaFileSchema = object({
|
|
|
15965
16062
|
sizeBytes: number(),
|
|
15966
16063
|
timestamp: number()
|
|
15967
16064
|
});
|
|
16065
|
+
var DEFAULT_EVENT_QUERY_LIMIT = 1e3;
|
|
16066
|
+
var MAX_EVENT_QUERY_LIMIT = 5e3;
|
|
15968
16067
|
var DeviceEventQueryInput = object({
|
|
15969
16068
|
deviceId: number(),
|
|
15970
16069
|
since: number().optional(),
|
|
15971
16070
|
until: number().optional(),
|
|
15972
|
-
limit: number().int().min(1).max(
|
|
16071
|
+
limit: number().int().min(1).max(MAX_EVENT_QUERY_LIMIT).default(DEFAULT_EVENT_QUERY_LIMIT),
|
|
15973
16072
|
/** `slim` drops heavy JSON fields (regions/bbox/zones) and carries an
|
|
15974
16073
|
* optional `mediaUrl` (populated by B5). `full` (default) keeps today's
|
|
15975
16074
|
* exact behaviour. Callers may omit this field — the store defaults to
|
|
@@ -15977,6 +16076,27 @@ var DeviceEventQueryInput = object({
|
|
|
15977
16076
|
projection: _enum(["full", "slim"]).optional()
|
|
15978
16077
|
});
|
|
15979
16078
|
var ObjectEventQueryInput = DeviceEventQueryInput.extend({ classFilter: string().optional() });
|
|
16079
|
+
var RecentTracksQueryInput = object({
|
|
16080
|
+
/** Devices to merge. An empty array yields `{ tracks: [], nextCursor: null }`. */
|
|
16081
|
+
deviceIds: array(number()),
|
|
16082
|
+
/** Window lower bound on `lastSeen` (inclusive). */
|
|
16083
|
+
since: number().optional(),
|
|
16084
|
+
/** Window upper bound on `lastSeen` (inclusive). */
|
|
16085
|
+
until: number().optional(),
|
|
16086
|
+
/** Page size. Default 200, max 1000. */
|
|
16087
|
+
limit: number().int().min(1).max(1e3).default(200),
|
|
16088
|
+
/** Opaque continuation cursor from a previous page's `nextCursor`.
|
|
16089
|
+
* Encodes the (lastSeen, trackId) sort position — treat as opaque. */
|
|
16090
|
+
cursor: string().optional(),
|
|
16091
|
+
/** See {@link TrackProjectionSchema}. Default `full`. */
|
|
16092
|
+
projection: TrackProjectionSchema.optional()
|
|
16093
|
+
});
|
|
16094
|
+
var RecentTracksPageSchema = object({
|
|
16095
|
+
/** Merged page, ordered by (`lastSeen` DESC, `trackId` DESC). */
|
|
16096
|
+
tracks: array(TrackSchema).readonly(),
|
|
16097
|
+
/** Cursor for the next page, or null when this page is the last. */
|
|
16098
|
+
nextCursor: string().nullable()
|
|
16099
|
+
});
|
|
15980
16100
|
var KeyEventQueryInput = object({
|
|
15981
16101
|
deviceId: number(),
|
|
15982
16102
|
/** Window lower bound (track firstSeen ≥ since). */
|
|
@@ -16059,11 +16179,25 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
|
|
|
16059
16179
|
deviceId: number(),
|
|
16060
16180
|
since: number().optional(),
|
|
16061
16181
|
until: number().optional(),
|
|
16062
|
-
limit: number().optional()
|
|
16063
|
-
|
|
16064
|
-
|
|
16065
|
-
|
|
16066
|
-
|
|
16182
|
+
limit: number().optional(),
|
|
16183
|
+
/** Spatial filter — only tracks whose trajectory intersects the zone
|
|
16184
|
+
* (normalized 0..1 rect or polygon). SQL-prefiltered on the persisted
|
|
16185
|
+
* envelope columns, then precisely tested per position. Tracks with
|
|
16186
|
+
* an unknown envelope (no frame dims at persist time) always match. */
|
|
16187
|
+
zone: TrackZoneFilterSchema.optional(),
|
|
16188
|
+
/** See {@link TrackProjectionSchema}. Default `full` (backward
|
|
16189
|
+
* compatible — omitting the field keeps today's exact behaviour). */
|
|
16190
|
+
projection: TrackProjectionSchema.optional()
|
|
16191
|
+
}), array(TrackSchema).readonly()), method(RecentTracksQueryInput, RecentTracksPageSchema), method(object({ deviceId: number() }), _void(), {
|
|
16192
|
+
kind: "mutation",
|
|
16193
|
+
auth: "admin"
|
|
16194
|
+
}), method(DeviceEventQueryInput, array(MotionEventSchema).readonly()), method(ObjectEventQueryInput, array(ObjectEventSchema).readonly()), method(DeviceEventQueryInput, array(AudioEventSchema).readonly()), method(object({ deviceId: number() }), array(EventKindDescriptorSchema).readonly()), method(object({
|
|
16195
|
+
deviceId: number(),
|
|
16196
|
+
since: number().optional(),
|
|
16197
|
+
until: number().optional(),
|
|
16198
|
+
kinds: array(string()).optional(),
|
|
16199
|
+
limit: number().int().min(1).max(MAX_EVENT_QUERY_LIMIT).default(DEFAULT_EVENT_QUERY_LIMIT)
|
|
16200
|
+
}), array(SensorEventSchema).readonly()), method(KeyEventQueryInput, array(KeyEventSchema).readonly()), method(object({
|
|
16067
16201
|
deviceId: number(),
|
|
16068
16202
|
since: number(),
|
|
16069
16203
|
until: number(),
|
|
@@ -19264,7 +19398,12 @@ var RecordingStorageUsageSchema = object({
|
|
|
19264
19398
|
/**
|
|
19265
19399
|
* Result of locating footage at a wall-clock instant for one device/profile.
|
|
19266
19400
|
* `segment` carries the covering segment's window; `gap` reports the forward
|
|
19267
|
-
* nearest covered edge (`null` past the end of footage / when none exists)
|
|
19401
|
+
* nearest covered edge (`null` past the end of footage / when none exists)
|
|
19402
|
+
* and the backward covered edge `prevEndMs` (exclusive end of the nearest
|
|
19403
|
+
* footage behind the epoch; `null` when none — optional so older providers
|
|
19404
|
+
* that omit it stay valid). `prevEndMs` lets a backward frame-step hop the
|
|
19405
|
+
* small inter-segment cracks (durMs under-covers the span to the next
|
|
19406
|
+
* startMs by ~11-17 ms) instead of no-opping at a segment head.
|
|
19268
19407
|
*/
|
|
19269
19408
|
var LocateSegmentResultSchema = discriminatedUnion("kind", [object({
|
|
19270
19409
|
kind: literal("segment"),
|
|
@@ -19273,7 +19412,8 @@ var LocateSegmentResultSchema = discriminatedUnion("kind", [object({
|
|
|
19273
19412
|
bytes: number()
|
|
19274
19413
|
}), object({
|
|
19275
19414
|
kind: literal("gap"),
|
|
19276
|
-
nearestEdgeMs: number().nullable()
|
|
19415
|
+
nearestEdgeMs: number().nullable(),
|
|
19416
|
+
prevEndMs: number().nullable().optional()
|
|
19277
19417
|
})]);
|
|
19278
19418
|
/** Raw bytes of one finalized footage segment (read off disk on the recording node). */
|
|
19279
19419
|
var ReadSegmentBytesResultSchema = object({ data: _instanceof(Uint8Array) });
|
|
@@ -20842,6 +20982,12 @@ Object.freeze({
|
|
|
20842
20982
|
addonId: null,
|
|
20843
20983
|
access: "view"
|
|
20844
20984
|
},
|
|
20985
|
+
"deviceManager.getLinkedDevices": {
|
|
20986
|
+
capName: "device-manager",
|
|
20987
|
+
capScope: "system",
|
|
20988
|
+
addonId: null,
|
|
20989
|
+
access: "view"
|
|
20990
|
+
},
|
|
20845
20991
|
"deviceManager.getRoleDisplayDefaults": {
|
|
20846
20992
|
capName: "device-manager",
|
|
20847
20993
|
capScope: "system",
|
|
@@ -22396,6 +22542,12 @@ Object.freeze({
|
|
|
22396
22542
|
addonId: null,
|
|
22397
22543
|
access: "view"
|
|
22398
22544
|
},
|
|
22545
|
+
"pipelineAnalytics.getSensorEvents": {
|
|
22546
|
+
capName: "pipeline-analytics",
|
|
22547
|
+
capScope: "device",
|
|
22548
|
+
addonId: null,
|
|
22549
|
+
access: "view"
|
|
22550
|
+
},
|
|
22399
22551
|
"pipelineAnalytics.getTrack": {
|
|
22400
22552
|
capName: "pipeline-analytics",
|
|
22401
22553
|
capScope: "device",
|
|
@@ -22408,6 +22560,18 @@ Object.freeze({
|
|
|
22408
22560
|
addonId: null,
|
|
22409
22561
|
access: "view"
|
|
22410
22562
|
},
|
|
22563
|
+
"pipelineAnalytics.listEventKinds": {
|
|
22564
|
+
capName: "pipeline-analytics",
|
|
22565
|
+
capScope: "device",
|
|
22566
|
+
addonId: null,
|
|
22567
|
+
access: "view"
|
|
22568
|
+
},
|
|
22569
|
+
"pipelineAnalytics.listRecentTracks": {
|
|
22570
|
+
capName: "pipeline-analytics",
|
|
22571
|
+
capScope: "device",
|
|
22572
|
+
addonId: null,
|
|
22573
|
+
access: "view"
|
|
22574
|
+
},
|
|
22411
22575
|
"pipelineAnalytics.listTracks": {
|
|
22412
22576
|
capName: "pipeline-analytics",
|
|
22413
22577
|
capScope: "device",
|
|
@@ -25608,7 +25772,7 @@ function entryForRef(ref) {
|
|
|
25608
25772
|
};
|
|
25609
25773
|
}
|
|
25610
25774
|
//#endregion
|
|
25611
|
-
//#region ../system/dist/model-download-service-
|
|
25775
|
+
//#region ../system/dist/model-download-service-Cp9f4dk6.mjs
|
|
25612
25776
|
function isNonEmptyFile(filePath) {
|
|
25613
25777
|
return node_fs.existsSync(filePath) && node_fs.statSync(filePath).size > 0;
|
|
25614
25778
|
}
|
package/dist/addon.mjs
CHANGED
|
@@ -5,7 +5,7 @@ import { createReadStream } from "node:fs";
|
|
|
5
5
|
import * as fsp from "node:fs/promises";
|
|
6
6
|
import { spawn } from "node:child_process";
|
|
7
7
|
import { createServer } from "node:net";
|
|
8
|
-
//#region ../types/dist/event-category-
|
|
8
|
+
//#region ../types/dist/event-category-H4AVePnn.mjs
|
|
9
9
|
var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
10
10
|
EventCategory["SystemBoot"] = "system.boot";
|
|
11
11
|
EventCategory["SystemAddonsReady"] = "system.addons-ready";
|
|
@@ -155,6 +155,9 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
|
155
155
|
EventCategory["RecordingSegmentWritten"] = "recording.segment.written";
|
|
156
156
|
EventCategory["RecordingPolicyFallback"] = "recording.policy.fallback";
|
|
157
157
|
EventCategory["RecordingRetentionCompleted"] = "recording.retention.completed";
|
|
158
|
+
/** Runner-sampled scrub thumbnail (~1/5 s/camera). Telemetry (D8): a lost
|
|
159
|
+
* thumb is a scrub gap the recorder's keyframe backfill covers. */
|
|
160
|
+
EventCategory["RecordingThumbSampled"] = "recording.thumb-sampled";
|
|
158
161
|
EventCategory["DetectionEvent"] = "detection.event";
|
|
159
162
|
EventCategory["SessionTrackNew"] = "session.track.new";
|
|
160
163
|
EventCategory["SessionTrackExpired"] = "session.track.expired";
|
|
@@ -9849,7 +9852,7 @@ object({
|
|
|
9849
9852
|
deviceId: number(),
|
|
9850
9853
|
timestamp: number()
|
|
9851
9854
|
});
|
|
9852
|
-
DeviceType.Button;
|
|
9855
|
+
DeviceType.Button, DeviceType.Camera;
|
|
9853
9856
|
/**
|
|
9854
9857
|
* Enum-state sensor — a string value picked from a finite option set.
|
|
9855
9858
|
* Drives HA `sensor` entries with `state_class: enum` (HVAC action
|
|
@@ -14219,6 +14222,14 @@ var ConfigEntrySchema = object({
|
|
|
14219
14222
|
value: unknown(),
|
|
14220
14223
|
description: string().optional()
|
|
14221
14224
|
});
|
|
14225
|
+
var DeviceLinkModeSchema = _enum(["auto", "manual"]);
|
|
14226
|
+
/** One resolved linked device — the compact projection consumers need. */
|
|
14227
|
+
var LinkedDeviceSchema = object({
|
|
14228
|
+
deviceId: number(),
|
|
14229
|
+
name: string(),
|
|
14230
|
+
location: string().nullable(),
|
|
14231
|
+
features: array(string())
|
|
14232
|
+
});
|
|
14222
14233
|
var SavedDeviceRowSchema = object({
|
|
14223
14234
|
/** Numeric id reserved at allocateDeviceId time. */
|
|
14224
14235
|
id: number(),
|
|
@@ -14440,7 +14451,10 @@ method(object({
|
|
|
14440
14451
|
}), _void(), {
|
|
14441
14452
|
kind: "mutation",
|
|
14442
14453
|
auth: "admin"
|
|
14443
|
-
}), method(object({ addonId: string() }), array(SavedDeviceRowSchema)), method(object({ addonId: string().optional() }), array(DeviceInfoSchema)), method(object({ deviceId: number() }), DeviceInfoSchema.nullable()), method(object({ parentDeviceId: number() }), array(DeviceInfoSchema)), method(object({ deviceId: number() }),
|
|
14454
|
+
}), method(object({ addonId: string() }), array(SavedDeviceRowSchema)), method(object({ addonId: string().optional() }), array(DeviceInfoSchema)), method(object({ deviceId: number() }), DeviceInfoSchema.nullable()), method(object({ parentDeviceId: number() }), array(DeviceInfoSchema)), method(object({ deviceId: number() }), object({
|
|
14455
|
+
mode: DeviceLinkModeSchema,
|
|
14456
|
+
devices: array(LinkedDeviceSchema)
|
|
14457
|
+
})), method(object({ deviceId: number() }), array(StreamSourceEntrySchema$1)), method(object({ deviceId: number() }), array(ConfigEntrySchema)), method(object({ deviceId: number() }), ConfigUISchemaOutput), method(object({
|
|
14444
14458
|
deviceId: number(),
|
|
14445
14459
|
values: record(string(), unknown())
|
|
14446
14460
|
}), object({ success: literal(true) }), {
|
|
@@ -15754,6 +15768,61 @@ var EventKindSchema = _enum([
|
|
|
15754
15768
|
"object",
|
|
15755
15769
|
"audio"
|
|
15756
15770
|
]);
|
|
15771
|
+
/**
|
|
15772
|
+
* Spatial filter for `listTracks` — the rect + polygon variants of the shared
|
|
15773
|
+
* MaskShape vocabulary (see `mask-shape.ts`). Coordinates are NORMALIZED 0..1
|
|
15774
|
+
* of the camera frame (top-left origin), matching the drawing-plane editor.
|
|
15775
|
+
*/
|
|
15776
|
+
var TrackZoneFilterSchema = discriminatedUnion("kind", [MaskRectShapeSchema, MaskPolygonShapeSchema]);
|
|
15777
|
+
/** Closed icon vocabulary so clients render a known glyph per kind. */
|
|
15778
|
+
var EventKindIconSchema = _enum([
|
|
15779
|
+
"motion",
|
|
15780
|
+
"audio",
|
|
15781
|
+
"person",
|
|
15782
|
+
"vehicle",
|
|
15783
|
+
"animal",
|
|
15784
|
+
"door",
|
|
15785
|
+
"pir",
|
|
15786
|
+
"smoke",
|
|
15787
|
+
"water",
|
|
15788
|
+
"button",
|
|
15789
|
+
"generic"
|
|
15790
|
+
]);
|
|
15791
|
+
var EventKindCategorySchema = _enum([
|
|
15792
|
+
"motion",
|
|
15793
|
+
"audio",
|
|
15794
|
+
"detection",
|
|
15795
|
+
"sensor",
|
|
15796
|
+
"custom"
|
|
15797
|
+
]);
|
|
15798
|
+
var EventKindDescriptorSchema = object({
|
|
15799
|
+
/** Stable kind id (e.g. 'motion', 'person', 'contact'). */
|
|
15800
|
+
kind: string(),
|
|
15801
|
+
label: string(),
|
|
15802
|
+
/** Hex color for timeline/legend rendering. */
|
|
15803
|
+
color: string(),
|
|
15804
|
+
icon: EventKindIconSchema,
|
|
15805
|
+
category: EventKindCategorySchema,
|
|
15806
|
+
/** Which cap + device contributes this kind. For built-ins the camera
|
|
15807
|
+
* itself; for sensor kinds the LINKED source device. */
|
|
15808
|
+
source: object({
|
|
15809
|
+
capName: string(),
|
|
15810
|
+
deviceId: number()
|
|
15811
|
+
})
|
|
15812
|
+
});
|
|
15813
|
+
var SensorEventSchema = object({
|
|
15814
|
+
id: string(),
|
|
15815
|
+
/** The CAMERA the event is attributed to (a sensor linked to N cameras
|
|
15816
|
+
* yields N rows, one per camera). */
|
|
15817
|
+
deviceId: number(),
|
|
15818
|
+
/** The linked sensor device whose state changed. */
|
|
15819
|
+
sourceDeviceId: number(),
|
|
15820
|
+
/** Event kind id — matches an `EventKindDescriptor.kind`. */
|
|
15821
|
+
kind: string(),
|
|
15822
|
+
/** Snapshot of the sensor cap's runtime-state slice at the change. */
|
|
15823
|
+
value: record(string(), unknown()).nullable(),
|
|
15824
|
+
timestamp: number()
|
|
15825
|
+
});
|
|
15757
15826
|
var TrackPositionSchema = object({
|
|
15758
15827
|
x: number(),
|
|
15759
15828
|
y: number(),
|
|
@@ -15767,6 +15836,30 @@ var TrackSnapshotSchema = object({
|
|
|
15767
15836
|
mediaKey: string()
|
|
15768
15837
|
});
|
|
15769
15838
|
/**
|
|
15839
|
+
* Normalized 0..1 trajectory envelope (min/max over every position bbox,
|
|
15840
|
+
* divided by the track's detection-frame dims), computed at persist time.
|
|
15841
|
+
* Absent when the frame dims were unknown when the track was persisted
|
|
15842
|
+
* (legacy rows / dims-less sources) and on active (in-RAM) tracks.
|
|
15843
|
+
*/
|
|
15844
|
+
var TrackEnvelopeSchema = object({
|
|
15845
|
+
minX: number(),
|
|
15846
|
+
minY: number(),
|
|
15847
|
+
maxX: number(),
|
|
15848
|
+
maxY: number()
|
|
15849
|
+
});
|
|
15850
|
+
/**
|
|
15851
|
+
* Row projection for track list queries. `full` (default) returns the
|
|
15852
|
+
* complete Track including the frame-rate `positions[]` history and the
|
|
15853
|
+
* `snapshots[]` references — megabytes across a page of tracks. `slim`
|
|
15854
|
+
* keeps every scalar the list surfaces actually render (ids, class(es),
|
|
15855
|
+
* label / audioLabels / importance enrichment, firstSeen/lastSeen, state,
|
|
15856
|
+
* zonesVisited, bestEventId, envelope) and returns `positions` /
|
|
15857
|
+
* `snapshots` as EMPTY arrays — detail views re-fetch the full row via
|
|
15858
|
+
* `getTrack`. Mirrors the event-store `projection` convention
|
|
15859
|
+
* (`getObjectEvents` et al.).
|
|
15860
|
+
*/
|
|
15861
|
+
var TrackProjectionSchema = _enum(["full", "slim"]);
|
|
15862
|
+
/**
|
|
15770
15863
|
* One audio-classification label heard on the track's camera while the
|
|
15771
15864
|
* track was alive, aggregated per label. An "episode" is one persisted
|
|
15772
15865
|
* audio event (the confident-classification path: score ≥ the device's
|
|
@@ -15817,7 +15910,11 @@ var TrackSchema = object({
|
|
|
15817
15910
|
/** Audio-classification labels heard on the camera during the track's
|
|
15818
15911
|
* life (score ≥ device `classificationMinScore`), aggregated per label.
|
|
15819
15912
|
* Absent on legacy rows / tracks with no confident audio. */
|
|
15820
|
-
audioLabels: array(TrackAudioLabelSchema).readonly().optional()
|
|
15913
|
+
audioLabels: array(TrackAudioLabelSchema).readonly().optional(),
|
|
15914
|
+
/** Normalized 0..1 trajectory envelope (see {@link TrackEnvelopeSchema}).
|
|
15915
|
+
* Populated from the persisted envelope columns on historical reads;
|
|
15916
|
+
* absent on legacy rows, dims-less tracks and active (in-RAM) tracks. */
|
|
15917
|
+
envelope: TrackEnvelopeSchema.optional()
|
|
15821
15918
|
});
|
|
15822
15919
|
var BaseEventFields = {
|
|
15823
15920
|
id: string(),
|
|
@@ -15927,11 +16024,13 @@ var MediaFileSchema = object({
|
|
|
15927
16024
|
sizeBytes: number(),
|
|
15928
16025
|
timestamp: number()
|
|
15929
16026
|
});
|
|
16027
|
+
var DEFAULT_EVENT_QUERY_LIMIT = 1e3;
|
|
16028
|
+
var MAX_EVENT_QUERY_LIMIT = 5e3;
|
|
15930
16029
|
var DeviceEventQueryInput = object({
|
|
15931
16030
|
deviceId: number(),
|
|
15932
16031
|
since: number().optional(),
|
|
15933
16032
|
until: number().optional(),
|
|
15934
|
-
limit: number().int().min(1).max(
|
|
16033
|
+
limit: number().int().min(1).max(MAX_EVENT_QUERY_LIMIT).default(DEFAULT_EVENT_QUERY_LIMIT),
|
|
15935
16034
|
/** `slim` drops heavy JSON fields (regions/bbox/zones) and carries an
|
|
15936
16035
|
* optional `mediaUrl` (populated by B5). `full` (default) keeps today's
|
|
15937
16036
|
* exact behaviour. Callers may omit this field — the store defaults to
|
|
@@ -15939,6 +16038,27 @@ var DeviceEventQueryInput = object({
|
|
|
15939
16038
|
projection: _enum(["full", "slim"]).optional()
|
|
15940
16039
|
});
|
|
15941
16040
|
var ObjectEventQueryInput = DeviceEventQueryInput.extend({ classFilter: string().optional() });
|
|
16041
|
+
var RecentTracksQueryInput = object({
|
|
16042
|
+
/** Devices to merge. An empty array yields `{ tracks: [], nextCursor: null }`. */
|
|
16043
|
+
deviceIds: array(number()),
|
|
16044
|
+
/** Window lower bound on `lastSeen` (inclusive). */
|
|
16045
|
+
since: number().optional(),
|
|
16046
|
+
/** Window upper bound on `lastSeen` (inclusive). */
|
|
16047
|
+
until: number().optional(),
|
|
16048
|
+
/** Page size. Default 200, max 1000. */
|
|
16049
|
+
limit: number().int().min(1).max(1e3).default(200),
|
|
16050
|
+
/** Opaque continuation cursor from a previous page's `nextCursor`.
|
|
16051
|
+
* Encodes the (lastSeen, trackId) sort position — treat as opaque. */
|
|
16052
|
+
cursor: string().optional(),
|
|
16053
|
+
/** See {@link TrackProjectionSchema}. Default `full`. */
|
|
16054
|
+
projection: TrackProjectionSchema.optional()
|
|
16055
|
+
});
|
|
16056
|
+
var RecentTracksPageSchema = object({
|
|
16057
|
+
/** Merged page, ordered by (`lastSeen` DESC, `trackId` DESC). */
|
|
16058
|
+
tracks: array(TrackSchema).readonly(),
|
|
16059
|
+
/** Cursor for the next page, or null when this page is the last. */
|
|
16060
|
+
nextCursor: string().nullable()
|
|
16061
|
+
});
|
|
15942
16062
|
var KeyEventQueryInput = object({
|
|
15943
16063
|
deviceId: number(),
|
|
15944
16064
|
/** Window lower bound (track firstSeen ≥ since). */
|
|
@@ -16021,11 +16141,25 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
|
|
|
16021
16141
|
deviceId: number(),
|
|
16022
16142
|
since: number().optional(),
|
|
16023
16143
|
until: number().optional(),
|
|
16024
|
-
limit: number().optional()
|
|
16025
|
-
|
|
16026
|
-
|
|
16027
|
-
|
|
16028
|
-
|
|
16144
|
+
limit: number().optional(),
|
|
16145
|
+
/** Spatial filter — only tracks whose trajectory intersects the zone
|
|
16146
|
+
* (normalized 0..1 rect or polygon). SQL-prefiltered on the persisted
|
|
16147
|
+
* envelope columns, then precisely tested per position. Tracks with
|
|
16148
|
+
* an unknown envelope (no frame dims at persist time) always match. */
|
|
16149
|
+
zone: TrackZoneFilterSchema.optional(),
|
|
16150
|
+
/** See {@link TrackProjectionSchema}. Default `full` (backward
|
|
16151
|
+
* compatible — omitting the field keeps today's exact behaviour). */
|
|
16152
|
+
projection: TrackProjectionSchema.optional()
|
|
16153
|
+
}), array(TrackSchema).readonly()), method(RecentTracksQueryInput, RecentTracksPageSchema), method(object({ deviceId: number() }), _void(), {
|
|
16154
|
+
kind: "mutation",
|
|
16155
|
+
auth: "admin"
|
|
16156
|
+
}), method(DeviceEventQueryInput, array(MotionEventSchema).readonly()), method(ObjectEventQueryInput, array(ObjectEventSchema).readonly()), method(DeviceEventQueryInput, array(AudioEventSchema).readonly()), method(object({ deviceId: number() }), array(EventKindDescriptorSchema).readonly()), method(object({
|
|
16157
|
+
deviceId: number(),
|
|
16158
|
+
since: number().optional(),
|
|
16159
|
+
until: number().optional(),
|
|
16160
|
+
kinds: array(string()).optional(),
|
|
16161
|
+
limit: number().int().min(1).max(MAX_EVENT_QUERY_LIMIT).default(DEFAULT_EVENT_QUERY_LIMIT)
|
|
16162
|
+
}), array(SensorEventSchema).readonly()), method(KeyEventQueryInput, array(KeyEventSchema).readonly()), method(object({
|
|
16029
16163
|
deviceId: number(),
|
|
16030
16164
|
since: number(),
|
|
16031
16165
|
until: number(),
|
|
@@ -19226,7 +19360,12 @@ var RecordingStorageUsageSchema = object({
|
|
|
19226
19360
|
/**
|
|
19227
19361
|
* Result of locating footage at a wall-clock instant for one device/profile.
|
|
19228
19362
|
* `segment` carries the covering segment's window; `gap` reports the forward
|
|
19229
|
-
* nearest covered edge (`null` past the end of footage / when none exists)
|
|
19363
|
+
* nearest covered edge (`null` past the end of footage / when none exists)
|
|
19364
|
+
* and the backward covered edge `prevEndMs` (exclusive end of the nearest
|
|
19365
|
+
* footage behind the epoch; `null` when none — optional so older providers
|
|
19366
|
+
* that omit it stay valid). `prevEndMs` lets a backward frame-step hop the
|
|
19367
|
+
* small inter-segment cracks (durMs under-covers the span to the next
|
|
19368
|
+
* startMs by ~11-17 ms) instead of no-opping at a segment head.
|
|
19230
19369
|
*/
|
|
19231
19370
|
var LocateSegmentResultSchema = discriminatedUnion("kind", [object({
|
|
19232
19371
|
kind: literal("segment"),
|
|
@@ -19235,7 +19374,8 @@ var LocateSegmentResultSchema = discriminatedUnion("kind", [object({
|
|
|
19235
19374
|
bytes: number()
|
|
19236
19375
|
}), object({
|
|
19237
19376
|
kind: literal("gap"),
|
|
19238
|
-
nearestEdgeMs: number().nullable()
|
|
19377
|
+
nearestEdgeMs: number().nullable(),
|
|
19378
|
+
prevEndMs: number().nullable().optional()
|
|
19239
19379
|
})]);
|
|
19240
19380
|
/** Raw bytes of one finalized footage segment (read off disk on the recording node). */
|
|
19241
19381
|
var ReadSegmentBytesResultSchema = object({ data: _instanceof(Uint8Array) });
|
|
@@ -20804,6 +20944,12 @@ Object.freeze({
|
|
|
20804
20944
|
addonId: null,
|
|
20805
20945
|
access: "view"
|
|
20806
20946
|
},
|
|
20947
|
+
"deviceManager.getLinkedDevices": {
|
|
20948
|
+
capName: "device-manager",
|
|
20949
|
+
capScope: "system",
|
|
20950
|
+
addonId: null,
|
|
20951
|
+
access: "view"
|
|
20952
|
+
},
|
|
20807
20953
|
"deviceManager.getRoleDisplayDefaults": {
|
|
20808
20954
|
capName: "device-manager",
|
|
20809
20955
|
capScope: "system",
|
|
@@ -22358,6 +22504,12 @@ Object.freeze({
|
|
|
22358
22504
|
addonId: null,
|
|
22359
22505
|
access: "view"
|
|
22360
22506
|
},
|
|
22507
|
+
"pipelineAnalytics.getSensorEvents": {
|
|
22508
|
+
capName: "pipeline-analytics",
|
|
22509
|
+
capScope: "device",
|
|
22510
|
+
addonId: null,
|
|
22511
|
+
access: "view"
|
|
22512
|
+
},
|
|
22361
22513
|
"pipelineAnalytics.getTrack": {
|
|
22362
22514
|
capName: "pipeline-analytics",
|
|
22363
22515
|
capScope: "device",
|
|
@@ -22370,6 +22522,18 @@ Object.freeze({
|
|
|
22370
22522
|
addonId: null,
|
|
22371
22523
|
access: "view"
|
|
22372
22524
|
},
|
|
22525
|
+
"pipelineAnalytics.listEventKinds": {
|
|
22526
|
+
capName: "pipeline-analytics",
|
|
22527
|
+
capScope: "device",
|
|
22528
|
+
addonId: null,
|
|
22529
|
+
access: "view"
|
|
22530
|
+
},
|
|
22531
|
+
"pipelineAnalytics.listRecentTracks": {
|
|
22532
|
+
capName: "pipeline-analytics",
|
|
22533
|
+
capScope: "device",
|
|
22534
|
+
addonId: null,
|
|
22535
|
+
access: "view"
|
|
22536
|
+
},
|
|
22373
22537
|
"pipelineAnalytics.listTracks": {
|
|
22374
22538
|
capName: "pipeline-analytics",
|
|
22375
22539
|
capScope: "device",
|
|
@@ -25570,7 +25734,7 @@ function entryForRef(ref) {
|
|
|
25570
25734
|
};
|
|
25571
25735
|
}
|
|
25572
25736
|
//#endregion
|
|
25573
|
-
//#region ../system/dist/model-download-service-
|
|
25737
|
+
//#region ../system/dist/model-download-service-Cp9f4dk6.mjs
|
|
25574
25738
|
function isNonEmptyFile(filePath) {
|
|
25575
25739
|
return fs.existsSync(filePath) && fs.statSync(filePath).size > 0;
|
|
25576
25740
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@camstack/addon-ai",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.4",
|
|
4
4
|
"description": "AI addon for CamStack — the `llm` collection provider (cloud, LAN, and camstack-managed local llama.cpp profiles) plus the per-node `llm-runtime` managed executor.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"camstack",
|