@camstack/addon-ai 0.4.104 → 0.4.106
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 +292 -58
- package/dist/addon.mjs +292 -58
- package/package.json +1 -1
package/dist/addon.js
CHANGED
|
@@ -12,7 +12,7 @@ let _camstack_system_addon_utils = require("@camstack/system/addon-utils");
|
|
|
12
12
|
let node_fs_promises = require("node:fs/promises");
|
|
13
13
|
node_fs_promises = require_chunk.__toESM(node_fs_promises);
|
|
14
14
|
let node_child_process = require("node:child_process");
|
|
15
|
-
//#region ../types/dist/event-category-
|
|
15
|
+
//#region ../types/dist/event-category-ZyX6jcse.mjs
|
|
16
16
|
var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
17
17
|
EventCategory["SystemBoot"] = "system.boot";
|
|
18
18
|
EventCategory["SystemAddonsReady"] = "system.addons-ready";
|
|
@@ -573,7 +573,7 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
|
573
573
|
* a package zone — a newly-appeared stationary object of a package class
|
|
574
574
|
* that cleared the class / zone / dwell / size gates. Payload:
|
|
575
575
|
* `PipelineAnalyticsPackageDeliveredPayload` carrying `{ deviceId,
|
|
576
|
-
* entryId, className, zoneIds,
|
|
576
|
+
* entryId, className, zoneIds, keyFrameMediaId?, bbox, timestamp }`.
|
|
577
577
|
* Telemetry (D8): the durable record is the `package-events` store row;
|
|
578
578
|
* this bus topic drives notifier rules + live UI. See
|
|
579
579
|
* docs/superpowers/specs/2026-07-17-package-zones-design.md §5.1.
|
|
@@ -5506,7 +5506,7 @@ function number(params) {
|
|
|
5506
5506
|
return /* @__PURE__ */ _coercedNumber(ZodNumber, params);
|
|
5507
5507
|
}
|
|
5508
5508
|
//#endregion
|
|
5509
|
-
//#region ../types/dist/sleep-
|
|
5509
|
+
//#region ../types/dist/sleep-DBKu2-U5.mjs
|
|
5510
5510
|
/**
|
|
5511
5511
|
* The audio chunk plane's byte format, and the ONE expansion from a coded
|
|
5512
5512
|
* window to float samples (D455).
|
|
@@ -7516,13 +7516,30 @@ new Set([
|
|
|
7516
7516
|
"scene",
|
|
7517
7517
|
"motion",
|
|
7518
7518
|
"object",
|
|
7519
|
-
"audio"
|
|
7519
|
+
"audio",
|
|
7520
|
+
"mosaic"
|
|
7520
7521
|
]);
|
|
7521
|
-
|
|
7522
|
+
/**
|
|
7523
|
+
* The owner types that are event tables, in the order the event-media resolver
|
|
7524
|
+
* should consider them. Exported so a consumer asking "is this key an event?"
|
|
7525
|
+
* does not re-spell the list and drift from it.
|
|
7526
|
+
*/
|
|
7527
|
+
var EVENT_OWNER_TYPES = [
|
|
7522
7528
|
"motion",
|
|
7523
7529
|
"object",
|
|
7524
7530
|
"audio"
|
|
7525
|
-
]
|
|
7531
|
+
];
|
|
7532
|
+
/**
|
|
7533
|
+
* The same list as a Zod enum, for the cap inputs that must NAME the table
|
|
7534
|
+
* (D482: `getEventMedia` / `listEventMedia` take an owner, and an owner is
|
|
7535
|
+
* `(table, id)`).
|
|
7536
|
+
*
|
|
7537
|
+
* Built FROM {@link EVENT_OWNER_TYPES} rather than re-spelled: a fourth event
|
|
7538
|
+
* table would otherwise be accepted by the codec and refused at the door, with
|
|
7539
|
+
* nothing failing until a caller asked.
|
|
7540
|
+
*/
|
|
7541
|
+
var EventOwnerTypeSchema = _enum(EVENT_OWNER_TYPES);
|
|
7542
|
+
new Set(EVENT_OWNER_TYPES);
|
|
7526
7543
|
var EncodeProfileSchema = object({
|
|
7527
7544
|
video: object({
|
|
7528
7545
|
codec: _enum([
|
|
@@ -7561,7 +7578,23 @@ var EncodeProfileSchema = object({
|
|
|
7561
7578
|
"zerolatency",
|
|
7562
7579
|
"film",
|
|
7563
7580
|
"animation"
|
|
7564
|
-
]).optional()
|
|
7581
|
+
]).optional(),
|
|
7582
|
+
/**
|
|
7583
|
+
* ONE slice per access unit.
|
|
7584
|
+
*
|
|
7585
|
+
* `-tune zerolatency` turns on x264's sliced threads, and a frame then leaves
|
|
7586
|
+
* the encoder as five NAL slices that share one RTP timestamp and carry one
|
|
7587
|
+
* marker bit. A libwebrtc depacketiser sees five frame-starts and one
|
|
7588
|
+
* frame-end per frame: the first pictures render and the video then freezes
|
|
7589
|
+
* for good while the audio, on its own plane, plays on. Measured on this hub
|
|
7590
|
+
* 2026-09-13 against the Echo, and reduced to one slice by this flag alone.
|
|
7591
|
+
*
|
|
7592
|
+
* A NAMED field and not a raw flag, because {@link EgressEncodeSchema} omits
|
|
7593
|
+
* `outputArgs` on purpose: an opaque array is part of the sharing key, so two
|
|
7594
|
+
* consumers meaning the same thing spelled differently would stop sharing one
|
|
7595
|
+
* child. Absent means "whatever the encoder does" — today's behaviour.
|
|
7596
|
+
*/
|
|
7597
|
+
singleSlicePerFrame: boolean().optional()
|
|
7565
7598
|
}),
|
|
7566
7599
|
audio: union([literal("passthrough"), object({
|
|
7567
7600
|
codec: _enum([
|
|
@@ -7611,7 +7644,7 @@ var BASE_LIVE_EGRESS_PROFILE = {
|
|
|
7611
7644
|
audio: "passthrough"
|
|
7612
7645
|
};
|
|
7613
7646
|
({ ...BASE_LIVE_EGRESS_PROFILE }), { ...BASE_LIVE_EGRESS_PROFILE.video };
|
|
7614
|
-
({ ...BASE_LIVE_EGRESS_PROFILE });
|
|
7647
|
+
({ ...BASE_LIVE_EGRESS_PROFILE }), { ...BASE_LIVE_EGRESS_PROFILE.video };
|
|
7615
7648
|
/**
|
|
7616
7649
|
* Deep wiring healthcheck — snapshot of active reachability probes across
|
|
7617
7650
|
* every declared capability + widget of every installed plugin, on every
|
|
@@ -12619,6 +12652,16 @@ method(object({
|
|
|
12619
12652
|
filter: QueryFilterSchema.optional(),
|
|
12620
12653
|
columns: array(string()).readonly().optional()
|
|
12621
12654
|
}), array(SettingsRecordSchema).readonly()), method(object({
|
|
12655
|
+
namespace: string().optional(),
|
|
12656
|
+
collection: string(),
|
|
12657
|
+
/** Declared columns identifying the slot; must be covered by a UNIQUE
|
|
12658
|
+
* index on the collection. Never empty. */
|
|
12659
|
+
conflict: array(string()).readonly(),
|
|
12660
|
+
record: BulkRecordSchema
|
|
12661
|
+
}), object({
|
|
12662
|
+
/** The id the row HAS: assigned by SQLite on an insert, or the existing
|
|
12663
|
+
* row's own id on an update. */
|
|
12664
|
+
id: union([string(), number$1()]) }), { kind: "mutation" }), method(object({
|
|
12622
12665
|
namespace: string().optional(),
|
|
12623
12666
|
collection: string(),
|
|
12624
12667
|
record: object({
|
|
@@ -12753,6 +12796,14 @@ method(_void(), EngineInfoSchema, { auth: "admin" }), method(object({
|
|
|
12753
12796
|
id: union([string(), number$1()]) }), {
|
|
12754
12797
|
kind: "mutation",
|
|
12755
12798
|
auth: "admin"
|
|
12799
|
+
}), method(object({
|
|
12800
|
+
namespace: string().optional(),
|
|
12801
|
+
collection: string(),
|
|
12802
|
+
conflict: array(string()).readonly(),
|
|
12803
|
+
record: BulkRecordSchema
|
|
12804
|
+
}), object({ id: union([string(), number$1()]) }), {
|
|
12805
|
+
kind: "mutation",
|
|
12806
|
+
auth: "admin"
|
|
12756
12807
|
}), method(object({
|
|
12757
12808
|
namespace: string().optional(),
|
|
12758
12809
|
collection: string(),
|
|
@@ -19063,8 +19114,8 @@ var TrackPositionSchema = object({
|
|
|
19063
19114
|
var TrackSnapshotSchema = object({
|
|
19064
19115
|
timestamp: number$1(),
|
|
19065
19116
|
position: TrackPositionSchema,
|
|
19066
|
-
/**
|
|
19067
|
-
|
|
19117
|
+
/** The snapshot's media row id (D482); resolve via `listTrackMedia({ trackId })`. */
|
|
19118
|
+
mediaId: number$1().int()
|
|
19068
19119
|
});
|
|
19069
19120
|
/**
|
|
19070
19121
|
* Normalized 0..1 trajectory envelope (min/max over every position bbox,
|
|
@@ -19668,14 +19719,14 @@ var ObjectEventSchema = object({
|
|
|
19668
19719
|
* pixel-space `bbox` onto a displayed image. Omitted in slim projection. */
|
|
19669
19720
|
frameWidth: number$1().optional(),
|
|
19670
19721
|
frameHeight: number$1().optional(),
|
|
19671
|
-
/**
|
|
19672
|
-
|
|
19673
|
-
/** Design B:
|
|
19722
|
+
/** Media row id of the crop attached to this event (if any) — D482. */
|
|
19723
|
+
mediaId: number$1().int().optional(),
|
|
19724
|
+
/** Design B: media row id of the track's native-resolution key frame (the
|
|
19674
19725
|
* best-detection full frame). Resolve via the event-media data-plane
|
|
19675
|
-
* (`/addon/<addonId>/event-media/<
|
|
19726
|
+
* (`/addon/<addonId>/event-media/m/<keyFrameMediaId>`) for a detail view that
|
|
19676
19727
|
* draws `bbox` over the native frame. Absent on legacy rows / non-decoded
|
|
19677
|
-
* sources — consumers fall back to `
|
|
19678
|
-
|
|
19728
|
+
* sources — consumers fall back to `mediaId` (the tight crop). */
|
|
19729
|
+
keyFrameMediaId: number$1().int().optional(),
|
|
19679
19730
|
/** Populated by B5 (recording playback URL for this event). */
|
|
19680
19731
|
mediaUrl: string().optional(),
|
|
19681
19732
|
/** The parent track's key-event importance [0,1], propagated to every object
|
|
@@ -19725,7 +19776,7 @@ var MediaFileKindEnum = _enum([
|
|
|
19725
19776
|
* hub-main's heap on the way past — for an `<img>` that would have cached it.
|
|
19726
19777
|
*
|
|
19727
19778
|
* `url` points at the `event-media` data plane
|
|
19728
|
-
* (`/addon/<addonId>/event-media/<
|
|
19779
|
+
* (`/addon/<addonId>/event-media/m/<mediaId>` — D482), which serves the same blob
|
|
19729
19780
|
* with an ETag and `Cache-Control: immutable`, honours conditional GETs, can
|
|
19730
19781
|
* render a `?variant=thumb`, and streams. The hub gate in front of it requires
|
|
19731
19782
|
* a bearer or the session cookie (`access: 'authenticated'`), so the bytes are
|
|
@@ -19733,10 +19784,13 @@ var MediaFileKindEnum = _enum([
|
|
|
19733
19784
|
* `data-plane-access.ts` for the rule and the one gap it does not close
|
|
19734
19785
|
* (per-device scoping).
|
|
19735
19786
|
*
|
|
19736
|
-
* The URL is built from the row's
|
|
19737
|
-
*
|
|
19787
|
+
* The URL is built from the row's own id, which since D482 says nothing about
|
|
19788
|
+
* the row's owner or kind — and that is the point. The published `kind` is not
|
|
19789
|
+
* the stored one (a track's face/plate crop is stored as `crop` under
|
|
19738
19790
|
* `('face'|'plate', '<prefix>-<trackId>')` and published as
|
|
19739
|
-
* `faceCrop`/`plateCrop
|
|
19791
|
+
* `faceCrop`/`plateCrop`), and under the old composite key the URL had to be
|
|
19792
|
+
* taken from `row.key` verbatim or it 404'd exactly those two rows. An id
|
|
19793
|
+
* cannot be mis-reconstructed, because there is nothing in it to reconstruct.
|
|
19740
19794
|
*
|
|
19741
19795
|
* ## `base64` is TRANSITIONAL and is going away
|
|
19742
19796
|
*
|
|
@@ -19749,7 +19803,19 @@ var MediaFileKindEnum = _enum([
|
|
|
19749
19803
|
* `analytics-query-facade.ts`; nothing else reads it.
|
|
19750
19804
|
*/
|
|
19751
19805
|
var MediaFileSchema = object({
|
|
19752
|
-
|
|
19806
|
+
/**
|
|
19807
|
+
* The media row's OWN id — the rowid SQLite assigned it (D482).
|
|
19808
|
+
*
|
|
19809
|
+
* It used to be the row's composite key, `<ownerType>:<ownerId>:<fileKind>
|
|
19810
|
+
* [:<timestampMs>]`, which embedded a FOREIGN id. D474 made event ids
|
|
19811
|
+
* per-table rowid aliases, so `object:101314` and `motion:101314` are two
|
|
19812
|
+
* different rows that spell the same number, and a track whose
|
|
19813
|
+
* `bestEventId` was an object event was served a motion event's snapshot —
|
|
19814
|
+
* a night-time thumbnail on an afternoon track, with no error anywhere. A
|
|
19815
|
+
* surrogate id cannot name the wrong row's owner, because it names no owner
|
|
19816
|
+
* at all.
|
|
19817
|
+
*/
|
|
19818
|
+
mediaId: number$1().int(),
|
|
19753
19819
|
kind: MediaFileKindEnum,
|
|
19754
19820
|
sizeBytes: number$1(),
|
|
19755
19821
|
timestamp: number$1()
|
|
@@ -19857,7 +19923,7 @@ var RetrainTrackSchema = object({
|
|
|
19857
19923
|
});
|
|
19858
19924
|
/** A frame the picker may offer — an index row, no blob was read to produce it. */
|
|
19859
19925
|
var RetrainFrameCandidateSchema = object({
|
|
19860
|
-
|
|
19926
|
+
mediaId: number$1().int(),
|
|
19861
19927
|
kind: MediaFileKindEnum,
|
|
19862
19928
|
timestamp: number$1(),
|
|
19863
19929
|
sizeBytes: number$1().int(),
|
|
@@ -19871,7 +19937,7 @@ var RetrainFrameSchema = object({
|
|
|
19871
19937
|
deviceId: number$1(),
|
|
19872
19938
|
trackId: string(),
|
|
19873
19939
|
/** Provenance only. It may already point at nothing — that is expected. */
|
|
19874
|
-
|
|
19940
|
+
sourceMediaId: number$1().int(),
|
|
19875
19941
|
sourceKind: MediaFileKindEnum,
|
|
19876
19942
|
sizeBytes: number$1().int(),
|
|
19877
19943
|
width: number$1().int(),
|
|
@@ -19887,7 +19953,7 @@ var RetrainCopyRefusalSchema = _enum([
|
|
|
19887
19953
|
var RetrainFrameSelectionSchema = object({
|
|
19888
19954
|
copied: array(RetrainFrameSchema).readonly(),
|
|
19889
19955
|
refused: array(object({
|
|
19890
|
-
|
|
19956
|
+
sourceMediaId: number$1().int(),
|
|
19891
19957
|
reason: RetrainCopyRefusalSchema
|
|
19892
19958
|
})).readonly()
|
|
19893
19959
|
});
|
|
@@ -19895,7 +19961,7 @@ var RetrainFrameListSchema = object({
|
|
|
19895
19961
|
candidates: array(RetrainFrameCandidateSchema).readonly(),
|
|
19896
19962
|
copies: array(RetrainFrameSchema).readonly(),
|
|
19897
19963
|
/** What the page pre-selects — the native key frame when one survives. */
|
|
19898
|
-
|
|
19964
|
+
autoPickMediaId: number$1().int().optional()
|
|
19899
19965
|
});
|
|
19900
19966
|
/** What the operator asked the assist to look for. */
|
|
19901
19967
|
var RetrainAssistSubjectSchema = discriminatedUnion("kind", [object({
|
|
@@ -19990,9 +20056,11 @@ var RecentTracksQueryInput = object({
|
|
|
19990
20056
|
});
|
|
19991
20057
|
/**
|
|
19992
20058
|
* A Summary (D359): the per-camera session envelope that references tracks.
|
|
19993
|
-
* `
|
|
19994
|
-
* served by the event-media plane
|
|
19995
|
-
* member visible has been materialised
|
|
20059
|
+
* `groupShotMediaId` is the media ROW id of its group shot (`ownerKind:
|
|
20060
|
+
* 'summary'`, served by the event-media plane at `/m/<id>`), null until the
|
|
20061
|
+
* first frame with a member visible has been materialised (D482 — it was the
|
|
20062
|
+
* row's composite key, which embedded the owner and could name another table's
|
|
20063
|
+
* row once event ids became per-table rowids).
|
|
19996
20064
|
*/
|
|
19997
20065
|
var SummarySchema = object({
|
|
19998
20066
|
id: string(),
|
|
@@ -20001,19 +20069,115 @@ var SummarySchema = object({
|
|
|
20001
20069
|
lastActiveAt: number$1(),
|
|
20002
20070
|
sealedAt: number$1().nullable(),
|
|
20003
20071
|
memberCount: number$1().int().nonnegative(),
|
|
20004
|
-
|
|
20072
|
+
groupShotMediaId: number$1().int().nullable()
|
|
20005
20073
|
});
|
|
20006
20074
|
var SummariesQueryInput = object({
|
|
20007
20075
|
deviceIds: array(number$1()).min(1),
|
|
20008
20076
|
since: number$1().optional(),
|
|
20009
20077
|
until: number$1().optional(),
|
|
20010
|
-
limit: number$1().int().min(1).max(200).default(50)
|
|
20078
|
+
limit: number$1().int().min(1).max(200).default(50),
|
|
20079
|
+
/** The same member-wise filter {@link listRecentSummaries} takes — one
|
|
20080
|
+
* meaning of "dog" on every summary surface. */
|
|
20081
|
+
classes: array(string().min(1).max(60)).max(40).optional()
|
|
20011
20082
|
});
|
|
20012
|
-
var SummariesPageSchema = object({ summaries: array(SummarySchema).readonly() });
|
|
20013
20083
|
var SummaryDetailSchema = object({
|
|
20014
20084
|
summary: SummarySchema,
|
|
20015
|
-
/**
|
|
20016
|
-
|
|
20085
|
+
/** Members in absorption order, oldest join first. */
|
|
20086
|
+
members: array(object({
|
|
20087
|
+
trackId: string(),
|
|
20088
|
+
/**
|
|
20089
|
+
* The track's class at the time it JOINED, or `null` when it was unresolved
|
|
20090
|
+
* and the track no longer exists to fill it.
|
|
20091
|
+
*
|
|
20092
|
+
* The join, not the latest opinion: class voting can re-decide a track's
|
|
20093
|
+
* class afterwards, and a group's composition is the history of who came
|
|
20094
|
+
* together. A consumer counts these to badge a thumbnail — "two people and a
|
|
20095
|
+
* dog" — rather than being handed a second, denormalised tally that would
|
|
20096
|
+
* drift from the members it claims to describe.
|
|
20097
|
+
*/
|
|
20098
|
+
className: string().nullable(),
|
|
20099
|
+
/** `primary` is the one member that carries the group's identity. */
|
|
20100
|
+
role: _enum([
|
|
20101
|
+
"primary",
|
|
20102
|
+
"sibling",
|
|
20103
|
+
"child"
|
|
20104
|
+
]).nullable(),
|
|
20105
|
+
joinedAt: number$1(),
|
|
20106
|
+
/** Tier 1 — the sub-class (`dog`, `van`), resolved from the member's track
|
|
20107
|
+
* at read time. Absent when nothing resolved, never an empty string. */
|
|
20108
|
+
label: string().optional(),
|
|
20109
|
+
/** Tier 2 — the instance: a person's name, a plate. Absent when the pipeline
|
|
20110
|
+
* recognised nobody, and absent for a member whose track has been pruned —
|
|
20111
|
+
* a thumbnail that names the wrong person is worse than one naming nobody. */
|
|
20112
|
+
subLabel: string().optional()
|
|
20113
|
+
})).readonly()
|
|
20114
|
+
});
|
|
20115
|
+
/**
|
|
20116
|
+
* What a LIST of groups carries: the envelope plus what it is MADE OF.
|
|
20117
|
+
*
|
|
20118
|
+
* Coarse on purpose — the operator's rule is "only the rough data on the list,
|
|
20119
|
+
* we extend when we notice we need more". Enough to draw the card ("two people
|
|
20120
|
+
* and a dog") and no more. The MEMBERS, their names and the per-member links
|
|
20121
|
+
* are on {@link getSummary}: shipping every member of every group so a client
|
|
20122
|
+
* can count them turns a page of two hundred groups into a thousand records to
|
|
20123
|
+
* draw two hundred badges.
|
|
20124
|
+
*/
|
|
20125
|
+
var SummaryListItemSchema = object({
|
|
20126
|
+
summary: SummarySchema,
|
|
20127
|
+
/** Class counts, most numerous first; `className: null` is a member whose
|
|
20128
|
+
* class never resolved, counted so the counts add up to `memberCount`. */
|
|
20129
|
+
classes: array(object({
|
|
20130
|
+
className: string().nullable(),
|
|
20131
|
+
count: number$1().int().positive()
|
|
20132
|
+
})).readonly()
|
|
20133
|
+
});
|
|
20134
|
+
var SummariesPageSchema = object({ summaries: array(SummaryListItemSchema).readonly() });
|
|
20135
|
+
/**
|
|
20136
|
+
* The paged feed, deliberately the SAME shape as {@link RecentTracksQueryInput}.
|
|
20137
|
+
*
|
|
20138
|
+
* The reel on the cameras page and the Events gallery both ride a cursor, so a
|
|
20139
|
+
* summaries feed that could only answer "the last N for these cameras"
|
|
20140
|
+
* (`listSummaries`) would make groups available in the timeline and nowhere
|
|
20141
|
+
* else. Two feeds with different ordering contracts would be two ideas of what
|
|
20142
|
+
* "newest" means, on one screen.
|
|
20143
|
+
*/
|
|
20144
|
+
var RecentSummariesQueryInput = object({
|
|
20145
|
+
/** Devices to merge. An empty array yields an empty page. */
|
|
20146
|
+
deviceIds: array(number$1()),
|
|
20147
|
+
/** Window lower bound on `lastActiveAt` (inclusive). */
|
|
20148
|
+
since: number$1().optional(),
|
|
20149
|
+
/** Window upper bound on `lastActiveAt` (inclusive). */
|
|
20150
|
+
until: number$1().optional(),
|
|
20151
|
+
limit: number$1().int().min(1).max(500).default(100),
|
|
20152
|
+
/** Opaque continuation cursor from a previous page's `nextCursor`. */
|
|
20153
|
+
cursor: string().optional(),
|
|
20154
|
+
/**
|
|
20155
|
+
* Restrict to these classes — THE SAME FIELD `listRecentTracks` takes, and
|
|
20156
|
+
* deliberately the same name: the events filter tree emits one list of ticked
|
|
20157
|
+
* taxonomy nodes, and a summaries feed that called it something else would
|
|
20158
|
+
* make the operator's one filter component produce two shapes.
|
|
20159
|
+
*
|
|
20160
|
+
* A question about the MEMBERS: a group matches when ANY of them does. "Show
|
|
20161
|
+
* me the arrivals with a dog" has to return the group of four people who had
|
|
20162
|
+
* one with them; a filter on the group's own fields could only ever answer
|
|
20163
|
+
* about its primary.
|
|
20164
|
+
*
|
|
20165
|
+
* Matched against all THREE tiers of a member — the class (`animal`), the
|
|
20166
|
+
* sub-class (`dog`) and the instance (a name, a plate) — because which tier a
|
|
20167
|
+
* ticked node lives on is the taxonomy's business, not the caller's. `dog` is
|
|
20168
|
+
* an event kind in the tree and a tier-1 label on an `animal` track; a filter
|
|
20169
|
+
* that read only the class would answer "animal" and never "dog".
|
|
20170
|
+
*
|
|
20171
|
+
* ABSENT or EMPTY means no filter — absent is not a selection of none.
|
|
20172
|
+
*/
|
|
20173
|
+
classes: array(string().min(1).max(60)).max(40).optional()
|
|
20174
|
+
});
|
|
20175
|
+
var RecentSummariesPageSchema = object({
|
|
20176
|
+
/** Ordered by (`lastActiveAt` DESC, id DESC). Same light item as
|
|
20177
|
+
* {@link listSummaries} — one list shape, so a card renders the same
|
|
20178
|
+
* whichever feed drew it. */
|
|
20179
|
+
summaries: array(SummaryListItemSchema).readonly(),
|
|
20180
|
+
nextCursor: string().nullable()
|
|
20017
20181
|
});
|
|
20018
20182
|
var RecentTracksPageSchema = object({
|
|
20019
20183
|
/** Merged page, ordered by (`lastSeen` DESC, `trackId` DESC). */
|
|
@@ -20427,7 +20591,7 @@ DeviceType.Camera, method(object({ deviceId: number$1() }), array(TrackSchema).r
|
|
|
20427
20591
|
classes: array(string()).optional(),
|
|
20428
20592
|
/** See {@link ExcludeSourcesDoc}. */
|
|
20429
20593
|
excludeSources: array(TrackSourceSchema).optional()
|
|
20430
|
-
}), array(TrackSchema).readonly()), method(RecentTracksQueryInput, RecentTracksPageSchema), method(SummariesQueryInput, SummariesPageSchema), method(object({ id: string() }), SummaryDetailSchema.nullable()), method(object({ deviceId: number$1() }), _void(), {
|
|
20594
|
+
}), array(TrackSchema).readonly()), method(RecentTracksQueryInput, RecentTracksPageSchema), method(SummariesQueryInput, SummariesPageSchema), method(RecentSummariesQueryInput, RecentSummariesPageSchema), method(object({ id: string() }), SummaryDetailSchema.nullable()), method(object({ deviceId: number$1() }), _void(), {
|
|
20431
20595
|
kind: "mutation",
|
|
20432
20596
|
auth: "admin"
|
|
20433
20597
|
}), method(DeviceEventQueryInput, array(MotionEventSchema).readonly()), method(ObjectEventQueryInput, array(ObjectEventSchema).readonly()), method(DeviceEventQueryInput, array(AudioEventSchema).readonly()), method(object({ deviceId: number$1() }), array(EventKindDescriptorSchema).readonly()), method(object({ deviceIds: array(number$1()).min(1).max(200) }), array(EventKindsForDeviceSchema).readonly()), method(object({
|
|
@@ -20555,7 +20719,7 @@ DeviceType.Camera, method(object({ deviceId: number$1() }), array(TrackSchema).r
|
|
|
20555
20719
|
}), method(object({
|
|
20556
20720
|
deviceId: number$1(),
|
|
20557
20721
|
trackId: string(),
|
|
20558
|
-
|
|
20722
|
+
mediaIds: array(number$1().int()).min(1)
|
|
20559
20723
|
}), RetrainFrameSelectionSchema, {
|
|
20560
20724
|
kind: "mutation",
|
|
20561
20725
|
auth: "admin"
|
|
@@ -20623,7 +20787,10 @@ DeviceType.Camera, method(object({ deviceId: number$1() }), array(TrackSchema).r
|
|
|
20623
20787
|
kind: "query",
|
|
20624
20788
|
auth: "admin"
|
|
20625
20789
|
}), method(object({
|
|
20626
|
-
|
|
20790
|
+
/** Which of the three event tables owns the row. */
|
|
20791
|
+
ownerType: EventOwnerTypeSchema,
|
|
20792
|
+
/** The event's rowid in that table (D474: an event id is a number). */
|
|
20793
|
+
eventId: number$1().int(),
|
|
20627
20794
|
kind: MediaFileKindEnum.optional(),
|
|
20628
20795
|
deviceId: number$1()
|
|
20629
20796
|
}), array(MediaFileSchema).readonly()), method(object({
|
|
@@ -20634,7 +20801,8 @@ DeviceType.Camera, method(object({ deviceId: number$1() }), array(TrackSchema).r
|
|
|
20634
20801
|
trackId: string(),
|
|
20635
20802
|
deviceId: number$1()
|
|
20636
20803
|
}), array(MediaFileInfoSchema).readonly()), method(object({
|
|
20637
|
-
|
|
20804
|
+
ownerType: EventOwnerTypeSchema,
|
|
20805
|
+
eventId: number$1().int(),
|
|
20638
20806
|
deviceId: number$1()
|
|
20639
20807
|
}), array(MediaFileInfoSchema).readonly()), method(SearchObjectEventsInput, array(ScoredObjectEventSchema).readonly()), method(object({}), WipeObjectEmbeddingsResultSchema, {
|
|
20640
20808
|
kind: "mutation",
|
|
@@ -25097,8 +25265,8 @@ var IdentitySchema = object({
|
|
|
25097
25265
|
id: string(),
|
|
25098
25266
|
name: string(),
|
|
25099
25267
|
sampleCount: number$1().int().nonnegative(),
|
|
25100
|
-
|
|
25101
|
-
/** Inline base64 of the cover sample's crop, resolved from `
|
|
25268
|
+
coverMediaId: number$1().int().optional(),
|
|
25269
|
+
/** Inline base64 of the cover sample's crop, resolved from `coverMediaId`.
|
|
25102
25270
|
* Lets the UI render the person's face avatar instead of a placeholder icon. */
|
|
25103
25271
|
coverBase64: string().optional()
|
|
25104
25272
|
});
|
|
@@ -25124,8 +25292,8 @@ var IdentitySampleAuditRowSchema = object({
|
|
|
25124
25292
|
enrolledAt: number$1().int(),
|
|
25125
25293
|
deviceId: number$1().int().optional(),
|
|
25126
25294
|
source: _enum(["detected", "photo"]),
|
|
25127
|
-
/** The enrolled crop's media
|
|
25128
|
-
|
|
25295
|
+
/** The enrolled crop's media row id, so the panel can show the evidence. */
|
|
25296
|
+
mediaId: number$1().int().optional(),
|
|
25129
25297
|
/**
|
|
25130
25298
|
* False = the sample is stamped with a DIFFERENT face model, and a cosine
|
|
25131
25299
|
* across feature spaces is a well-formed float with no meaning. Every number
|
|
@@ -25194,15 +25362,15 @@ var FaceInfoSchema = object({
|
|
|
25194
25362
|
*/
|
|
25195
25363
|
cropUrl: string().optional(),
|
|
25196
25364
|
/** Design B: the face bbox (pixel space) on the key frame — lets a detail
|
|
25197
|
-
* view draw the box over the native `
|
|
25365
|
+
* view draw the box over the native `keyFrameMediaId` frame. Absent on
|
|
25198
25366
|
* legacy rows written before design B. */
|
|
25199
25367
|
faceBbox: BoundingBoxSchema.optional(),
|
|
25200
25368
|
/** Design B: MediaStore key of the track's native-resolution key frame.
|
|
25201
25369
|
* Fetch the native JPEG via the event-media data-plane
|
|
25202
|
-
* (`/addon/<addonId>/event-media/<
|
|
25370
|
+
* (`/addon/<addonId>/event-media/m/<keyFrameMediaId>`). Absent when the
|
|
25203
25371
|
* track produced no key frame (e.g. native/onboard source) — the UI falls
|
|
25204
25372
|
* back to the inline `base64` face crop. */
|
|
25205
|
-
|
|
25373
|
+
keyFrameMediaId: number$1().int().optional(),
|
|
25206
25374
|
/** Winning identity-match cosine (0..1) for this face's track, when an
|
|
25207
25375
|
* identity was auto-confirmed. Lets the UI surface WHY a face was assigned
|
|
25208
25376
|
* (confidence badge / low-confidence audit). Absent on legacy rows and on
|
|
@@ -25271,11 +25439,14 @@ var FaceClusterSchema = object({
|
|
|
25271
25439
|
* `data:image/jpeg;base64,…` from a row whose `key` sat right beside it, in a
|
|
25272
25440
|
* dialog already rendering its key FRAME from the `event-media` plane.
|
|
25273
25441
|
*
|
|
25274
|
-
* `url` is `/addon/<addonId>/event-media/<
|
|
25275
|
-
* media
|
|
25442
|
+
* `url` is `/addon/<addonId>/event-media/m/<mediaId>` (D482). The plane
|
|
25443
|
+
* resolves a media row by its own id, so this needed no new plane and no new
|
|
25444
|
+
* access decision.
|
|
25276
25445
|
*/
|
|
25277
25446
|
var MediaFileLiteSchema$1 = object({
|
|
25278
|
-
|
|
25447
|
+
/** The media row's own id — the same address `MediaFileRef.mediaId` carries
|
|
25448
|
+
* (D482). It was the row's composite key, which embedded the owner. */
|
|
25449
|
+
mediaId: number$1().int(),
|
|
25279
25450
|
kind: string(),
|
|
25280
25451
|
url: string(),
|
|
25281
25452
|
sizeBytes: number$1(),
|
|
@@ -25292,7 +25463,7 @@ method(object({
|
|
|
25292
25463
|
* covers inline, ~10 KB of base64 per row, on a query this UI mounts
|
|
25293
25464
|
* four times and the viewer holds at `staleTime: 30_000`.
|
|
25294
25465
|
*
|
|
25295
|
-
* Nothing loses its avatar: `
|
|
25466
|
+
* Nothing loses its avatar: `coverMediaId` is already on every row and
|
|
25296
25467
|
* the `event-media` plane serves that key `immutable` with an ETag.
|
|
25297
25468
|
*
|
|
25298
25469
|
* **This is an INPUT field, so it does not reach the addon until the
|
|
@@ -27760,8 +27931,8 @@ var VehicleSchema = object({
|
|
|
27760
27931
|
id: string(),
|
|
27761
27932
|
name: string(),
|
|
27762
27933
|
sampleCount: number$1().int().nonnegative(),
|
|
27763
|
-
|
|
27764
|
-
/** Inline base64 of the cover sample's plate crop, resolved from `
|
|
27934
|
+
coverMediaId: number$1().int().optional(),
|
|
27935
|
+
/** Inline base64 of the cover sample's plate crop, resolved from `coverMediaId`. */
|
|
27765
27936
|
coverBase64: string().optional()
|
|
27766
27937
|
});
|
|
27767
27938
|
var VehicleSampleInfoSchema = object({
|
|
@@ -27794,7 +27965,7 @@ var PlateInfoSchema = object({
|
|
|
27794
27965
|
/** keyFrame parity: the plate bbox (pixel space) on the native key frame. */
|
|
27795
27966
|
plateBbox: BoundingBoxSchema.optional(),
|
|
27796
27967
|
/** keyFrame parity: MediaStore key of the track's native-resolution key frame. */
|
|
27797
|
-
|
|
27968
|
+
keyFrameMediaId: number$1().int().optional(),
|
|
27798
27969
|
base64: string().optional(),
|
|
27799
27970
|
/**
|
|
27800
27971
|
* Same crop as a data-plane URL, always present when the plate has a stored
|
|
@@ -27815,11 +27986,14 @@ var PlateInfoSchema = object({
|
|
|
27815
27986
|
* `data:image/jpeg;base64,…` from a row whose `key` sat right beside it, in a
|
|
27816
27987
|
* dialog already rendering its key FRAME from the `event-media` plane.
|
|
27817
27988
|
*
|
|
27818
|
-
* `url` is `/addon/<addonId>/event-media/<
|
|
27819
|
-
* media
|
|
27989
|
+
* `url` is `/addon/<addonId>/event-media/m/<mediaId>` (D482). The plane
|
|
27990
|
+
* resolves a media row by its own id, so this needed no new plane and no new
|
|
27991
|
+
* access decision.
|
|
27820
27992
|
*/
|
|
27821
27993
|
var MediaFileLiteSchema = object({
|
|
27822
|
-
|
|
27994
|
+
/** The media row's own id — the same address `MediaFileRef.mediaId` carries
|
|
27995
|
+
* (D482). It was the row's composite key, which embedded the owner. */
|
|
27996
|
+
mediaId: number$1().int(),
|
|
27823
27997
|
kind: string(),
|
|
27824
27998
|
url: string(),
|
|
27825
27999
|
sizeBytes: number$1(),
|
|
@@ -27878,7 +28052,7 @@ method(object({
|
|
|
27878
28052
|
}), method(object({
|
|
27879
28053
|
/** Inline {@link VehicleSchema.coverBase64} on every row. Default
|
|
27880
28054
|
* `false` — the vehicle twin of `faceGallery.listIdentities`'s
|
|
27881
|
-
* option; `
|
|
28055
|
+
* option; `coverMediaId` + the `event-media` plane carry the picture.
|
|
27882
28056
|
* INPUT field: stripped by the hub router until the train ships, which
|
|
27883
28057
|
* resolves to `false` and is exactly the intended default. */
|
|
27884
28058
|
includeCrops: boolean().optional() }).optional(), array(VehicleSchema).readonly()), method(object({ name: string().min(1) }), VehicleSchema, {
|
|
@@ -29202,7 +29376,14 @@ var SceneReferenceSchema = object({
|
|
|
29202
29376
|
modelId: string(),
|
|
29203
29377
|
condition: SceneConditionSchema,
|
|
29204
29378
|
capturedAt: number$1(),
|
|
29205
|
-
|
|
29379
|
+
/**
|
|
29380
|
+
* The reference thumbnail's media ROW id (D482).
|
|
29381
|
+
*
|
|
29382
|
+
* The name already said `mediaId` while the value was the row's composite
|
|
29383
|
+
* key — a leftover that read as done and was not. It is the row's own id
|
|
29384
|
+
* now, addressed at `/addon/<addonId>/event-media/m/<id>`.
|
|
29385
|
+
*/
|
|
29386
|
+
thumbnailMediaId: number$1().int().optional(),
|
|
29206
29387
|
/** Whole-frame (downscaled) embedding captured alongside the ROI crop. The
|
|
29207
29388
|
* anti-view-shift anchor: a bumped camera, a PTZ preset or a re-aim makes the
|
|
29208
29389
|
* normalized rect frame a different piece of world, and the scene would
|
|
@@ -30016,7 +30197,29 @@ var LoggingSettingsPatchSchema = object({
|
|
|
30016
30197
|
* disarmed the channels it did not mention would make the Levels page and
|
|
30017
30198
|
* the Diagnostics page fight over the same value.
|
|
30018
30199
|
*/
|
|
30019
|
-
channels: array(LogChannelWindowPatchSchema).readonly().optional()
|
|
30200
|
+
channels: array(LogChannelWindowPatchSchema).readonly().optional(),
|
|
30201
|
+
/**
|
|
30202
|
+
* How many days the analytics OPS LOG is kept — the audit trail of what
|
|
30203
|
+
* retention actually deleted.
|
|
30204
|
+
*
|
|
30205
|
+
* It lives HERE, on the logging document, and not on the analytics addon's
|
|
30206
|
+
* settings form, on the operator's instruction: every other log-ish window in
|
|
30207
|
+
* this system is configured through this one document, and a retention audit
|
|
30208
|
+
* configured somewhere else is a second place to look when the question is
|
|
30209
|
+
* "what happened to my data".
|
|
30210
|
+
*
|
|
30211
|
+
* That placement has a cost worth stating: this document ships in the
|
|
30212
|
+
* framework closure, so this knob needs a published `@camstack/server` while
|
|
30213
|
+
* the four windows beside it (D485) reach a node on `camstack deploy`.
|
|
30214
|
+
*
|
|
30215
|
+
* `retention-model.ts` argued this one must NOT follow a device window,
|
|
30216
|
+
* because the audit trail is the history of the SWEEP and not of the camera.
|
|
30217
|
+
* That argument stands and is untouched — what changes is that 30 days stops
|
|
30218
|
+
* being a constant nobody can reach. `0` keeps it forever. The floor is 1 day
|
|
30219
|
+
* rather than 0-as-delete: an audit log truncated to nothing is precisely the
|
|
30220
|
+
* state in which the next 9.5 GiB leak cannot be explained.
|
|
30221
|
+
*/
|
|
30222
|
+
opsLogRetentionDays: number$1().int().min(0).max(3650).optional()
|
|
30020
30223
|
});
|
|
30021
30224
|
/**
|
|
30022
30225
|
* Which LAYER of the hierarchy is addressed. Absent = the cluster layer.
|
|
@@ -30089,6 +30292,14 @@ var LoggingSettingsStateSchema = object({
|
|
|
30089
30292
|
channels: array(LogChannelDescriptorSchema).readonly(),
|
|
30090
30293
|
/** The channels ARMED right now, each with its deadline. */
|
|
30091
30294
|
activeChannels: array(LogChannelWindowStateSchema).readonly(),
|
|
30295
|
+
/**
|
|
30296
|
+
* The ops-log window in days, as it is in force. `0` = kept forever.
|
|
30297
|
+
*
|
|
30298
|
+
* Reported rather than left to the caller's memory of what it wrote: this is
|
|
30299
|
+
* the value the analytics sweep will actually use, and an operator asking how
|
|
30300
|
+
* long their audit trail lives should not have to infer it from a default.
|
|
30301
|
+
*/
|
|
30302
|
+
opsLogRetentionDays: number$1().int().min(0),
|
|
30092
30303
|
persisted: boolean()
|
|
30093
30304
|
});
|
|
30094
30305
|
method(_void(), FeatureManifestSchema), method(_void(), HealthStatusSchema), method(_void(), FeatureManifestSchema), method(_void(), array(NetworkAddressSchema).readonly()), method(_void(), unknown().nullable(), { auth: "admin" }), method(record(string(), unknown()), _null(), {
|
|
@@ -30650,7 +30861,7 @@ var StationaryObjectSchema = object({
|
|
|
30650
30861
|
/** Enrichment label carried from the source track (identity / plate). */
|
|
30651
30862
|
label: string().optional(),
|
|
30652
30863
|
/** Native-resolution key-frame media key for the parked object's best image. */
|
|
30653
|
-
|
|
30864
|
+
keyFrameMediaId: number$1().int().optional()
|
|
30654
30865
|
});
|
|
30655
30866
|
var CameraOccupancySnapshotSchema = object({
|
|
30656
30867
|
/** Frame timestamp of the inference result that produced this snapshot. */
|
|
@@ -31806,6 +32017,12 @@ Object.freeze({
|
|
|
31806
32017
|
addonId: null,
|
|
31807
32018
|
access: "create"
|
|
31808
32019
|
},
|
|
32020
|
+
"dataStoreProvider.upsert": {
|
|
32021
|
+
capName: "data-store-provider",
|
|
32022
|
+
capScope: "system",
|
|
32023
|
+
addonId: null,
|
|
32024
|
+
access: "create"
|
|
32025
|
+
},
|
|
31809
32026
|
"dayNight.getOptions": {
|
|
31810
32027
|
capName: "day-night",
|
|
31811
32028
|
capScope: "device",
|
|
@@ -34242,6 +34459,12 @@ Object.freeze({
|
|
|
34242
34459
|
addonId: null,
|
|
34243
34460
|
access: "view"
|
|
34244
34461
|
},
|
|
34462
|
+
"pipelineAnalytics.listRecentSummaries": {
|
|
34463
|
+
capName: "pipeline-analytics",
|
|
34464
|
+
capScope: "device",
|
|
34465
|
+
addonId: null,
|
|
34466
|
+
access: "view"
|
|
34467
|
+
},
|
|
34245
34468
|
"pipelineAnalytics.listRecentTracks": {
|
|
34246
34469
|
capName: "pipeline-analytics",
|
|
34247
34470
|
capScope: "device",
|
|
@@ -35670,6 +35893,12 @@ Object.freeze({
|
|
|
35670
35893
|
addonId: null,
|
|
35671
35894
|
access: "create"
|
|
35672
35895
|
},
|
|
35896
|
+
"settingsStore.upsert": {
|
|
35897
|
+
capName: "settings-store",
|
|
35898
|
+
capScope: "system",
|
|
35899
|
+
addonId: null,
|
|
35900
|
+
access: "create"
|
|
35901
|
+
},
|
|
35673
35902
|
"smtpProvider.getStatus": {
|
|
35674
35903
|
capName: "smtp-provider",
|
|
35675
35904
|
capScope: "system",
|
|
@@ -38063,6 +38292,11 @@ Object.freeze({
|
|
|
38063
38292
|
form: "single",
|
|
38064
38293
|
optional: true
|
|
38065
38294
|
}],
|
|
38295
|
+
"pipelineAnalytics.listRecentSummaries": [{
|
|
38296
|
+
name: "deviceIds",
|
|
38297
|
+
form: "array",
|
|
38298
|
+
optional: false
|
|
38299
|
+
}],
|
|
38066
38300
|
"pipelineAnalytics.listRecentTracks": [{
|
|
38067
38301
|
name: "deviceIds",
|
|
38068
38302
|
form: "array",
|
package/dist/addon.mjs
CHANGED
|
@@ -39,7 +39,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
39
39
|
}) : target, mod));
|
|
40
40
|
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
41
41
|
//#endregion
|
|
42
|
-
//#region ../types/dist/event-category-
|
|
42
|
+
//#region ../types/dist/event-category-ZyX6jcse.mjs
|
|
43
43
|
var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
44
44
|
EventCategory["SystemBoot"] = "system.boot";
|
|
45
45
|
EventCategory["SystemAddonsReady"] = "system.addons-ready";
|
|
@@ -600,7 +600,7 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
|
600
600
|
* a package zone — a newly-appeared stationary object of a package class
|
|
601
601
|
* that cleared the class / zone / dwell / size gates. Payload:
|
|
602
602
|
* `PipelineAnalyticsPackageDeliveredPayload` carrying `{ deviceId,
|
|
603
|
-
* entryId, className, zoneIds,
|
|
603
|
+
* entryId, className, zoneIds, keyFrameMediaId?, bbox, timestamp }`.
|
|
604
604
|
* Telemetry (D8): the durable record is the `package-events` store row;
|
|
605
605
|
* this bus topic drives notifier rules + live UI. See
|
|
606
606
|
* docs/superpowers/specs/2026-07-17-package-zones-design.md §5.1.
|
|
@@ -5533,7 +5533,7 @@ function number(params) {
|
|
|
5533
5533
|
return /* @__PURE__ */ _coercedNumber(ZodNumber, params);
|
|
5534
5534
|
}
|
|
5535
5535
|
//#endregion
|
|
5536
|
-
//#region ../types/dist/sleep-
|
|
5536
|
+
//#region ../types/dist/sleep-DBKu2-U5.mjs
|
|
5537
5537
|
/**
|
|
5538
5538
|
* The audio chunk plane's byte format, and the ONE expansion from a coded
|
|
5539
5539
|
* window to float samples (D455).
|
|
@@ -7543,13 +7543,30 @@ new Set([
|
|
|
7543
7543
|
"scene",
|
|
7544
7544
|
"motion",
|
|
7545
7545
|
"object",
|
|
7546
|
-
"audio"
|
|
7546
|
+
"audio",
|
|
7547
|
+
"mosaic"
|
|
7547
7548
|
]);
|
|
7548
|
-
|
|
7549
|
+
/**
|
|
7550
|
+
* The owner types that are event tables, in the order the event-media resolver
|
|
7551
|
+
* should consider them. Exported so a consumer asking "is this key an event?"
|
|
7552
|
+
* does not re-spell the list and drift from it.
|
|
7553
|
+
*/
|
|
7554
|
+
var EVENT_OWNER_TYPES = [
|
|
7549
7555
|
"motion",
|
|
7550
7556
|
"object",
|
|
7551
7557
|
"audio"
|
|
7552
|
-
]
|
|
7558
|
+
];
|
|
7559
|
+
/**
|
|
7560
|
+
* The same list as a Zod enum, for the cap inputs that must NAME the table
|
|
7561
|
+
* (D482: `getEventMedia` / `listEventMedia` take an owner, and an owner is
|
|
7562
|
+
* `(table, id)`).
|
|
7563
|
+
*
|
|
7564
|
+
* Built FROM {@link EVENT_OWNER_TYPES} rather than re-spelled: a fourth event
|
|
7565
|
+
* table would otherwise be accepted by the codec and refused at the door, with
|
|
7566
|
+
* nothing failing until a caller asked.
|
|
7567
|
+
*/
|
|
7568
|
+
var EventOwnerTypeSchema = _enum(EVENT_OWNER_TYPES);
|
|
7569
|
+
new Set(EVENT_OWNER_TYPES);
|
|
7553
7570
|
var EncodeProfileSchema = object({
|
|
7554
7571
|
video: object({
|
|
7555
7572
|
codec: _enum([
|
|
@@ -7588,7 +7605,23 @@ var EncodeProfileSchema = object({
|
|
|
7588
7605
|
"zerolatency",
|
|
7589
7606
|
"film",
|
|
7590
7607
|
"animation"
|
|
7591
|
-
]).optional()
|
|
7608
|
+
]).optional(),
|
|
7609
|
+
/**
|
|
7610
|
+
* ONE slice per access unit.
|
|
7611
|
+
*
|
|
7612
|
+
* `-tune zerolatency` turns on x264's sliced threads, and a frame then leaves
|
|
7613
|
+
* the encoder as five NAL slices that share one RTP timestamp and carry one
|
|
7614
|
+
* marker bit. A libwebrtc depacketiser sees five frame-starts and one
|
|
7615
|
+
* frame-end per frame: the first pictures render and the video then freezes
|
|
7616
|
+
* for good while the audio, on its own plane, plays on. Measured on this hub
|
|
7617
|
+
* 2026-09-13 against the Echo, and reduced to one slice by this flag alone.
|
|
7618
|
+
*
|
|
7619
|
+
* A NAMED field and not a raw flag, because {@link EgressEncodeSchema} omits
|
|
7620
|
+
* `outputArgs` on purpose: an opaque array is part of the sharing key, so two
|
|
7621
|
+
* consumers meaning the same thing spelled differently would stop sharing one
|
|
7622
|
+
* child. Absent means "whatever the encoder does" — today's behaviour.
|
|
7623
|
+
*/
|
|
7624
|
+
singleSlicePerFrame: boolean().optional()
|
|
7592
7625
|
}),
|
|
7593
7626
|
audio: union([literal("passthrough"), object({
|
|
7594
7627
|
codec: _enum([
|
|
@@ -7638,7 +7671,7 @@ var BASE_LIVE_EGRESS_PROFILE = {
|
|
|
7638
7671
|
audio: "passthrough"
|
|
7639
7672
|
};
|
|
7640
7673
|
({ ...BASE_LIVE_EGRESS_PROFILE }), { ...BASE_LIVE_EGRESS_PROFILE.video };
|
|
7641
|
-
({ ...BASE_LIVE_EGRESS_PROFILE });
|
|
7674
|
+
({ ...BASE_LIVE_EGRESS_PROFILE }), { ...BASE_LIVE_EGRESS_PROFILE.video };
|
|
7642
7675
|
/**
|
|
7643
7676
|
* Deep wiring healthcheck — snapshot of active reachability probes across
|
|
7644
7677
|
* every declared capability + widget of every installed plugin, on every
|
|
@@ -12646,6 +12679,16 @@ method(object({
|
|
|
12646
12679
|
filter: QueryFilterSchema.optional(),
|
|
12647
12680
|
columns: array(string()).readonly().optional()
|
|
12648
12681
|
}), array(SettingsRecordSchema).readonly()), method(object({
|
|
12682
|
+
namespace: string().optional(),
|
|
12683
|
+
collection: string(),
|
|
12684
|
+
/** Declared columns identifying the slot; must be covered by a UNIQUE
|
|
12685
|
+
* index on the collection. Never empty. */
|
|
12686
|
+
conflict: array(string()).readonly(),
|
|
12687
|
+
record: BulkRecordSchema
|
|
12688
|
+
}), object({
|
|
12689
|
+
/** The id the row HAS: assigned by SQLite on an insert, or the existing
|
|
12690
|
+
* row's own id on an update. */
|
|
12691
|
+
id: union([string(), number$1()]) }), { kind: "mutation" }), method(object({
|
|
12649
12692
|
namespace: string().optional(),
|
|
12650
12693
|
collection: string(),
|
|
12651
12694
|
record: object({
|
|
@@ -12780,6 +12823,14 @@ method(_void(), EngineInfoSchema, { auth: "admin" }), method(object({
|
|
|
12780
12823
|
id: union([string(), number$1()]) }), {
|
|
12781
12824
|
kind: "mutation",
|
|
12782
12825
|
auth: "admin"
|
|
12826
|
+
}), method(object({
|
|
12827
|
+
namespace: string().optional(),
|
|
12828
|
+
collection: string(),
|
|
12829
|
+
conflict: array(string()).readonly(),
|
|
12830
|
+
record: BulkRecordSchema
|
|
12831
|
+
}), object({ id: union([string(), number$1()]) }), {
|
|
12832
|
+
kind: "mutation",
|
|
12833
|
+
auth: "admin"
|
|
12783
12834
|
}), method(object({
|
|
12784
12835
|
namespace: string().optional(),
|
|
12785
12836
|
collection: string(),
|
|
@@ -19090,8 +19141,8 @@ var TrackPositionSchema = object({
|
|
|
19090
19141
|
var TrackSnapshotSchema = object({
|
|
19091
19142
|
timestamp: number$1(),
|
|
19092
19143
|
position: TrackPositionSchema,
|
|
19093
|
-
/**
|
|
19094
|
-
|
|
19144
|
+
/** The snapshot's media row id (D482); resolve via `listTrackMedia({ trackId })`. */
|
|
19145
|
+
mediaId: number$1().int()
|
|
19095
19146
|
});
|
|
19096
19147
|
/**
|
|
19097
19148
|
* Normalized 0..1 trajectory envelope (min/max over every position bbox,
|
|
@@ -19695,14 +19746,14 @@ var ObjectEventSchema = object({
|
|
|
19695
19746
|
* pixel-space `bbox` onto a displayed image. Omitted in slim projection. */
|
|
19696
19747
|
frameWidth: number$1().optional(),
|
|
19697
19748
|
frameHeight: number$1().optional(),
|
|
19698
|
-
/**
|
|
19699
|
-
|
|
19700
|
-
/** Design B:
|
|
19749
|
+
/** Media row id of the crop attached to this event (if any) — D482. */
|
|
19750
|
+
mediaId: number$1().int().optional(),
|
|
19751
|
+
/** Design B: media row id of the track's native-resolution key frame (the
|
|
19701
19752
|
* best-detection full frame). Resolve via the event-media data-plane
|
|
19702
|
-
* (`/addon/<addonId>/event-media/<
|
|
19753
|
+
* (`/addon/<addonId>/event-media/m/<keyFrameMediaId>`) for a detail view that
|
|
19703
19754
|
* draws `bbox` over the native frame. Absent on legacy rows / non-decoded
|
|
19704
|
-
* sources — consumers fall back to `
|
|
19705
|
-
|
|
19755
|
+
* sources — consumers fall back to `mediaId` (the tight crop). */
|
|
19756
|
+
keyFrameMediaId: number$1().int().optional(),
|
|
19706
19757
|
/** Populated by B5 (recording playback URL for this event). */
|
|
19707
19758
|
mediaUrl: string().optional(),
|
|
19708
19759
|
/** The parent track's key-event importance [0,1], propagated to every object
|
|
@@ -19752,7 +19803,7 @@ var MediaFileKindEnum = _enum([
|
|
|
19752
19803
|
* hub-main's heap on the way past — for an `<img>` that would have cached it.
|
|
19753
19804
|
*
|
|
19754
19805
|
* `url` points at the `event-media` data plane
|
|
19755
|
-
* (`/addon/<addonId>/event-media/<
|
|
19806
|
+
* (`/addon/<addonId>/event-media/m/<mediaId>` — D482), which serves the same blob
|
|
19756
19807
|
* with an ETag and `Cache-Control: immutable`, honours conditional GETs, can
|
|
19757
19808
|
* render a `?variant=thumb`, and streams. The hub gate in front of it requires
|
|
19758
19809
|
* a bearer or the session cookie (`access: 'authenticated'`), so the bytes are
|
|
@@ -19760,10 +19811,13 @@ var MediaFileKindEnum = _enum([
|
|
|
19760
19811
|
* `data-plane-access.ts` for the rule and the one gap it does not close
|
|
19761
19812
|
* (per-device scoping).
|
|
19762
19813
|
*
|
|
19763
|
-
* The URL is built from the row's
|
|
19764
|
-
*
|
|
19814
|
+
* The URL is built from the row's own id, which since D482 says nothing about
|
|
19815
|
+
* the row's owner or kind — and that is the point. The published `kind` is not
|
|
19816
|
+
* the stored one (a track's face/plate crop is stored as `crop` under
|
|
19765
19817
|
* `('face'|'plate', '<prefix>-<trackId>')` and published as
|
|
19766
|
-
* `faceCrop`/`plateCrop
|
|
19818
|
+
* `faceCrop`/`plateCrop`), and under the old composite key the URL had to be
|
|
19819
|
+
* taken from `row.key` verbatim or it 404'd exactly those two rows. An id
|
|
19820
|
+
* cannot be mis-reconstructed, because there is nothing in it to reconstruct.
|
|
19767
19821
|
*
|
|
19768
19822
|
* ## `base64` is TRANSITIONAL and is going away
|
|
19769
19823
|
*
|
|
@@ -19776,7 +19830,19 @@ var MediaFileKindEnum = _enum([
|
|
|
19776
19830
|
* `analytics-query-facade.ts`; nothing else reads it.
|
|
19777
19831
|
*/
|
|
19778
19832
|
var MediaFileSchema = object({
|
|
19779
|
-
|
|
19833
|
+
/**
|
|
19834
|
+
* The media row's OWN id — the rowid SQLite assigned it (D482).
|
|
19835
|
+
*
|
|
19836
|
+
* It used to be the row's composite key, `<ownerType>:<ownerId>:<fileKind>
|
|
19837
|
+
* [:<timestampMs>]`, which embedded a FOREIGN id. D474 made event ids
|
|
19838
|
+
* per-table rowid aliases, so `object:101314` and `motion:101314` are two
|
|
19839
|
+
* different rows that spell the same number, and a track whose
|
|
19840
|
+
* `bestEventId` was an object event was served a motion event's snapshot —
|
|
19841
|
+
* a night-time thumbnail on an afternoon track, with no error anywhere. A
|
|
19842
|
+
* surrogate id cannot name the wrong row's owner, because it names no owner
|
|
19843
|
+
* at all.
|
|
19844
|
+
*/
|
|
19845
|
+
mediaId: number$1().int(),
|
|
19780
19846
|
kind: MediaFileKindEnum,
|
|
19781
19847
|
sizeBytes: number$1(),
|
|
19782
19848
|
timestamp: number$1()
|
|
@@ -19884,7 +19950,7 @@ var RetrainTrackSchema = object({
|
|
|
19884
19950
|
});
|
|
19885
19951
|
/** A frame the picker may offer — an index row, no blob was read to produce it. */
|
|
19886
19952
|
var RetrainFrameCandidateSchema = object({
|
|
19887
|
-
|
|
19953
|
+
mediaId: number$1().int(),
|
|
19888
19954
|
kind: MediaFileKindEnum,
|
|
19889
19955
|
timestamp: number$1(),
|
|
19890
19956
|
sizeBytes: number$1().int(),
|
|
@@ -19898,7 +19964,7 @@ var RetrainFrameSchema = object({
|
|
|
19898
19964
|
deviceId: number$1(),
|
|
19899
19965
|
trackId: string(),
|
|
19900
19966
|
/** Provenance only. It may already point at nothing — that is expected. */
|
|
19901
|
-
|
|
19967
|
+
sourceMediaId: number$1().int(),
|
|
19902
19968
|
sourceKind: MediaFileKindEnum,
|
|
19903
19969
|
sizeBytes: number$1().int(),
|
|
19904
19970
|
width: number$1().int(),
|
|
@@ -19914,7 +19980,7 @@ var RetrainCopyRefusalSchema = _enum([
|
|
|
19914
19980
|
var RetrainFrameSelectionSchema = object({
|
|
19915
19981
|
copied: array(RetrainFrameSchema).readonly(),
|
|
19916
19982
|
refused: array(object({
|
|
19917
|
-
|
|
19983
|
+
sourceMediaId: number$1().int(),
|
|
19918
19984
|
reason: RetrainCopyRefusalSchema
|
|
19919
19985
|
})).readonly()
|
|
19920
19986
|
});
|
|
@@ -19922,7 +19988,7 @@ var RetrainFrameListSchema = object({
|
|
|
19922
19988
|
candidates: array(RetrainFrameCandidateSchema).readonly(),
|
|
19923
19989
|
copies: array(RetrainFrameSchema).readonly(),
|
|
19924
19990
|
/** What the page pre-selects — the native key frame when one survives. */
|
|
19925
|
-
|
|
19991
|
+
autoPickMediaId: number$1().int().optional()
|
|
19926
19992
|
});
|
|
19927
19993
|
/** What the operator asked the assist to look for. */
|
|
19928
19994
|
var RetrainAssistSubjectSchema = discriminatedUnion("kind", [object({
|
|
@@ -20017,9 +20083,11 @@ var RecentTracksQueryInput = object({
|
|
|
20017
20083
|
});
|
|
20018
20084
|
/**
|
|
20019
20085
|
* A Summary (D359): the per-camera session envelope that references tracks.
|
|
20020
|
-
* `
|
|
20021
|
-
* served by the event-media plane
|
|
20022
|
-
* member visible has been materialised
|
|
20086
|
+
* `groupShotMediaId` is the media ROW id of its group shot (`ownerKind:
|
|
20087
|
+
* 'summary'`, served by the event-media plane at `/m/<id>`), null until the
|
|
20088
|
+
* first frame with a member visible has been materialised (D482 — it was the
|
|
20089
|
+
* row's composite key, which embedded the owner and could name another table's
|
|
20090
|
+
* row once event ids became per-table rowids).
|
|
20023
20091
|
*/
|
|
20024
20092
|
var SummarySchema = object({
|
|
20025
20093
|
id: string(),
|
|
@@ -20028,19 +20096,115 @@ var SummarySchema = object({
|
|
|
20028
20096
|
lastActiveAt: number$1(),
|
|
20029
20097
|
sealedAt: number$1().nullable(),
|
|
20030
20098
|
memberCount: number$1().int().nonnegative(),
|
|
20031
|
-
|
|
20099
|
+
groupShotMediaId: number$1().int().nullable()
|
|
20032
20100
|
});
|
|
20033
20101
|
var SummariesQueryInput = object({
|
|
20034
20102
|
deviceIds: array(number$1()).min(1),
|
|
20035
20103
|
since: number$1().optional(),
|
|
20036
20104
|
until: number$1().optional(),
|
|
20037
|
-
limit: number$1().int().min(1).max(200).default(50)
|
|
20105
|
+
limit: number$1().int().min(1).max(200).default(50),
|
|
20106
|
+
/** The same member-wise filter {@link listRecentSummaries} takes — one
|
|
20107
|
+
* meaning of "dog" on every summary surface. */
|
|
20108
|
+
classes: array(string().min(1).max(60)).max(40).optional()
|
|
20038
20109
|
});
|
|
20039
|
-
var SummariesPageSchema = object({ summaries: array(SummarySchema).readonly() });
|
|
20040
20110
|
var SummaryDetailSchema = object({
|
|
20041
20111
|
summary: SummarySchema,
|
|
20042
|
-
/**
|
|
20043
|
-
|
|
20112
|
+
/** Members in absorption order, oldest join first. */
|
|
20113
|
+
members: array(object({
|
|
20114
|
+
trackId: string(),
|
|
20115
|
+
/**
|
|
20116
|
+
* The track's class at the time it JOINED, or `null` when it was unresolved
|
|
20117
|
+
* and the track no longer exists to fill it.
|
|
20118
|
+
*
|
|
20119
|
+
* The join, not the latest opinion: class voting can re-decide a track's
|
|
20120
|
+
* class afterwards, and a group's composition is the history of who came
|
|
20121
|
+
* together. A consumer counts these to badge a thumbnail — "two people and a
|
|
20122
|
+
* dog" — rather than being handed a second, denormalised tally that would
|
|
20123
|
+
* drift from the members it claims to describe.
|
|
20124
|
+
*/
|
|
20125
|
+
className: string().nullable(),
|
|
20126
|
+
/** `primary` is the one member that carries the group's identity. */
|
|
20127
|
+
role: _enum([
|
|
20128
|
+
"primary",
|
|
20129
|
+
"sibling",
|
|
20130
|
+
"child"
|
|
20131
|
+
]).nullable(),
|
|
20132
|
+
joinedAt: number$1(),
|
|
20133
|
+
/** Tier 1 — the sub-class (`dog`, `van`), resolved from the member's track
|
|
20134
|
+
* at read time. Absent when nothing resolved, never an empty string. */
|
|
20135
|
+
label: string().optional(),
|
|
20136
|
+
/** Tier 2 — the instance: a person's name, a plate. Absent when the pipeline
|
|
20137
|
+
* recognised nobody, and absent for a member whose track has been pruned —
|
|
20138
|
+
* a thumbnail that names the wrong person is worse than one naming nobody. */
|
|
20139
|
+
subLabel: string().optional()
|
|
20140
|
+
})).readonly()
|
|
20141
|
+
});
|
|
20142
|
+
/**
|
|
20143
|
+
* What a LIST of groups carries: the envelope plus what it is MADE OF.
|
|
20144
|
+
*
|
|
20145
|
+
* Coarse on purpose — the operator's rule is "only the rough data on the list,
|
|
20146
|
+
* we extend when we notice we need more". Enough to draw the card ("two people
|
|
20147
|
+
* and a dog") and no more. The MEMBERS, their names and the per-member links
|
|
20148
|
+
* are on {@link getSummary}: shipping every member of every group so a client
|
|
20149
|
+
* can count them turns a page of two hundred groups into a thousand records to
|
|
20150
|
+
* draw two hundred badges.
|
|
20151
|
+
*/
|
|
20152
|
+
var SummaryListItemSchema = object({
|
|
20153
|
+
summary: SummarySchema,
|
|
20154
|
+
/** Class counts, most numerous first; `className: null` is a member whose
|
|
20155
|
+
* class never resolved, counted so the counts add up to `memberCount`. */
|
|
20156
|
+
classes: array(object({
|
|
20157
|
+
className: string().nullable(),
|
|
20158
|
+
count: number$1().int().positive()
|
|
20159
|
+
})).readonly()
|
|
20160
|
+
});
|
|
20161
|
+
var SummariesPageSchema = object({ summaries: array(SummaryListItemSchema).readonly() });
|
|
20162
|
+
/**
|
|
20163
|
+
* The paged feed, deliberately the SAME shape as {@link RecentTracksQueryInput}.
|
|
20164
|
+
*
|
|
20165
|
+
* The reel on the cameras page and the Events gallery both ride a cursor, so a
|
|
20166
|
+
* summaries feed that could only answer "the last N for these cameras"
|
|
20167
|
+
* (`listSummaries`) would make groups available in the timeline and nowhere
|
|
20168
|
+
* else. Two feeds with different ordering contracts would be two ideas of what
|
|
20169
|
+
* "newest" means, on one screen.
|
|
20170
|
+
*/
|
|
20171
|
+
var RecentSummariesQueryInput = object({
|
|
20172
|
+
/** Devices to merge. An empty array yields an empty page. */
|
|
20173
|
+
deviceIds: array(number$1()),
|
|
20174
|
+
/** Window lower bound on `lastActiveAt` (inclusive). */
|
|
20175
|
+
since: number$1().optional(),
|
|
20176
|
+
/** Window upper bound on `lastActiveAt` (inclusive). */
|
|
20177
|
+
until: number$1().optional(),
|
|
20178
|
+
limit: number$1().int().min(1).max(500).default(100),
|
|
20179
|
+
/** Opaque continuation cursor from a previous page's `nextCursor`. */
|
|
20180
|
+
cursor: string().optional(),
|
|
20181
|
+
/**
|
|
20182
|
+
* Restrict to these classes — THE SAME FIELD `listRecentTracks` takes, and
|
|
20183
|
+
* deliberately the same name: the events filter tree emits one list of ticked
|
|
20184
|
+
* taxonomy nodes, and a summaries feed that called it something else would
|
|
20185
|
+
* make the operator's one filter component produce two shapes.
|
|
20186
|
+
*
|
|
20187
|
+
* A question about the MEMBERS: a group matches when ANY of them does. "Show
|
|
20188
|
+
* me the arrivals with a dog" has to return the group of four people who had
|
|
20189
|
+
* one with them; a filter on the group's own fields could only ever answer
|
|
20190
|
+
* about its primary.
|
|
20191
|
+
*
|
|
20192
|
+
* Matched against all THREE tiers of a member — the class (`animal`), the
|
|
20193
|
+
* sub-class (`dog`) and the instance (a name, a plate) — because which tier a
|
|
20194
|
+
* ticked node lives on is the taxonomy's business, not the caller's. `dog` is
|
|
20195
|
+
* an event kind in the tree and a tier-1 label on an `animal` track; a filter
|
|
20196
|
+
* that read only the class would answer "animal" and never "dog".
|
|
20197
|
+
*
|
|
20198
|
+
* ABSENT or EMPTY means no filter — absent is not a selection of none.
|
|
20199
|
+
*/
|
|
20200
|
+
classes: array(string().min(1).max(60)).max(40).optional()
|
|
20201
|
+
});
|
|
20202
|
+
var RecentSummariesPageSchema = object({
|
|
20203
|
+
/** Ordered by (`lastActiveAt` DESC, id DESC). Same light item as
|
|
20204
|
+
* {@link listSummaries} — one list shape, so a card renders the same
|
|
20205
|
+
* whichever feed drew it. */
|
|
20206
|
+
summaries: array(SummaryListItemSchema).readonly(),
|
|
20207
|
+
nextCursor: string().nullable()
|
|
20044
20208
|
});
|
|
20045
20209
|
var RecentTracksPageSchema = object({
|
|
20046
20210
|
/** Merged page, ordered by (`lastSeen` DESC, `trackId` DESC). */
|
|
@@ -20454,7 +20618,7 @@ DeviceType.Camera, method(object({ deviceId: number$1() }), array(TrackSchema).r
|
|
|
20454
20618
|
classes: array(string()).optional(),
|
|
20455
20619
|
/** See {@link ExcludeSourcesDoc}. */
|
|
20456
20620
|
excludeSources: array(TrackSourceSchema).optional()
|
|
20457
|
-
}), array(TrackSchema).readonly()), method(RecentTracksQueryInput, RecentTracksPageSchema), method(SummariesQueryInput, SummariesPageSchema), method(object({ id: string() }), SummaryDetailSchema.nullable()), method(object({ deviceId: number$1() }), _void(), {
|
|
20621
|
+
}), array(TrackSchema).readonly()), method(RecentTracksQueryInput, RecentTracksPageSchema), method(SummariesQueryInput, SummariesPageSchema), method(RecentSummariesQueryInput, RecentSummariesPageSchema), method(object({ id: string() }), SummaryDetailSchema.nullable()), method(object({ deviceId: number$1() }), _void(), {
|
|
20458
20622
|
kind: "mutation",
|
|
20459
20623
|
auth: "admin"
|
|
20460
20624
|
}), method(DeviceEventQueryInput, array(MotionEventSchema).readonly()), method(ObjectEventQueryInput, array(ObjectEventSchema).readonly()), method(DeviceEventQueryInput, array(AudioEventSchema).readonly()), method(object({ deviceId: number$1() }), array(EventKindDescriptorSchema).readonly()), method(object({ deviceIds: array(number$1()).min(1).max(200) }), array(EventKindsForDeviceSchema).readonly()), method(object({
|
|
@@ -20582,7 +20746,7 @@ DeviceType.Camera, method(object({ deviceId: number$1() }), array(TrackSchema).r
|
|
|
20582
20746
|
}), method(object({
|
|
20583
20747
|
deviceId: number$1(),
|
|
20584
20748
|
trackId: string(),
|
|
20585
|
-
|
|
20749
|
+
mediaIds: array(number$1().int()).min(1)
|
|
20586
20750
|
}), RetrainFrameSelectionSchema, {
|
|
20587
20751
|
kind: "mutation",
|
|
20588
20752
|
auth: "admin"
|
|
@@ -20650,7 +20814,10 @@ DeviceType.Camera, method(object({ deviceId: number$1() }), array(TrackSchema).r
|
|
|
20650
20814
|
kind: "query",
|
|
20651
20815
|
auth: "admin"
|
|
20652
20816
|
}), method(object({
|
|
20653
|
-
|
|
20817
|
+
/** Which of the three event tables owns the row. */
|
|
20818
|
+
ownerType: EventOwnerTypeSchema,
|
|
20819
|
+
/** The event's rowid in that table (D474: an event id is a number). */
|
|
20820
|
+
eventId: number$1().int(),
|
|
20654
20821
|
kind: MediaFileKindEnum.optional(),
|
|
20655
20822
|
deviceId: number$1()
|
|
20656
20823
|
}), array(MediaFileSchema).readonly()), method(object({
|
|
@@ -20661,7 +20828,8 @@ DeviceType.Camera, method(object({ deviceId: number$1() }), array(TrackSchema).r
|
|
|
20661
20828
|
trackId: string(),
|
|
20662
20829
|
deviceId: number$1()
|
|
20663
20830
|
}), array(MediaFileInfoSchema).readonly()), method(object({
|
|
20664
|
-
|
|
20831
|
+
ownerType: EventOwnerTypeSchema,
|
|
20832
|
+
eventId: number$1().int(),
|
|
20665
20833
|
deviceId: number$1()
|
|
20666
20834
|
}), array(MediaFileInfoSchema).readonly()), method(SearchObjectEventsInput, array(ScoredObjectEventSchema).readonly()), method(object({}), WipeObjectEmbeddingsResultSchema, {
|
|
20667
20835
|
kind: "mutation",
|
|
@@ -25124,8 +25292,8 @@ var IdentitySchema = object({
|
|
|
25124
25292
|
id: string(),
|
|
25125
25293
|
name: string(),
|
|
25126
25294
|
sampleCount: number$1().int().nonnegative(),
|
|
25127
|
-
|
|
25128
|
-
/** Inline base64 of the cover sample's crop, resolved from `
|
|
25295
|
+
coverMediaId: number$1().int().optional(),
|
|
25296
|
+
/** Inline base64 of the cover sample's crop, resolved from `coverMediaId`.
|
|
25129
25297
|
* Lets the UI render the person's face avatar instead of a placeholder icon. */
|
|
25130
25298
|
coverBase64: string().optional()
|
|
25131
25299
|
});
|
|
@@ -25151,8 +25319,8 @@ var IdentitySampleAuditRowSchema = object({
|
|
|
25151
25319
|
enrolledAt: number$1().int(),
|
|
25152
25320
|
deviceId: number$1().int().optional(),
|
|
25153
25321
|
source: _enum(["detected", "photo"]),
|
|
25154
|
-
/** The enrolled crop's media
|
|
25155
|
-
|
|
25322
|
+
/** The enrolled crop's media row id, so the panel can show the evidence. */
|
|
25323
|
+
mediaId: number$1().int().optional(),
|
|
25156
25324
|
/**
|
|
25157
25325
|
* False = the sample is stamped with a DIFFERENT face model, and a cosine
|
|
25158
25326
|
* across feature spaces is a well-formed float with no meaning. Every number
|
|
@@ -25221,15 +25389,15 @@ var FaceInfoSchema = object({
|
|
|
25221
25389
|
*/
|
|
25222
25390
|
cropUrl: string().optional(),
|
|
25223
25391
|
/** Design B: the face bbox (pixel space) on the key frame — lets a detail
|
|
25224
|
-
* view draw the box over the native `
|
|
25392
|
+
* view draw the box over the native `keyFrameMediaId` frame. Absent on
|
|
25225
25393
|
* legacy rows written before design B. */
|
|
25226
25394
|
faceBbox: BoundingBoxSchema.optional(),
|
|
25227
25395
|
/** Design B: MediaStore key of the track's native-resolution key frame.
|
|
25228
25396
|
* Fetch the native JPEG via the event-media data-plane
|
|
25229
|
-
* (`/addon/<addonId>/event-media/<
|
|
25397
|
+
* (`/addon/<addonId>/event-media/m/<keyFrameMediaId>`). Absent when the
|
|
25230
25398
|
* track produced no key frame (e.g. native/onboard source) — the UI falls
|
|
25231
25399
|
* back to the inline `base64` face crop. */
|
|
25232
|
-
|
|
25400
|
+
keyFrameMediaId: number$1().int().optional(),
|
|
25233
25401
|
/** Winning identity-match cosine (0..1) for this face's track, when an
|
|
25234
25402
|
* identity was auto-confirmed. Lets the UI surface WHY a face was assigned
|
|
25235
25403
|
* (confidence badge / low-confidence audit). Absent on legacy rows and on
|
|
@@ -25298,11 +25466,14 @@ var FaceClusterSchema = object({
|
|
|
25298
25466
|
* `data:image/jpeg;base64,…` from a row whose `key` sat right beside it, in a
|
|
25299
25467
|
* dialog already rendering its key FRAME from the `event-media` plane.
|
|
25300
25468
|
*
|
|
25301
|
-
* `url` is `/addon/<addonId>/event-media/<
|
|
25302
|
-
* media
|
|
25469
|
+
* `url` is `/addon/<addonId>/event-media/m/<mediaId>` (D482). The plane
|
|
25470
|
+
* resolves a media row by its own id, so this needed no new plane and no new
|
|
25471
|
+
* access decision.
|
|
25303
25472
|
*/
|
|
25304
25473
|
var MediaFileLiteSchema$1 = object({
|
|
25305
|
-
|
|
25474
|
+
/** The media row's own id — the same address `MediaFileRef.mediaId` carries
|
|
25475
|
+
* (D482). It was the row's composite key, which embedded the owner. */
|
|
25476
|
+
mediaId: number$1().int(),
|
|
25306
25477
|
kind: string(),
|
|
25307
25478
|
url: string(),
|
|
25308
25479
|
sizeBytes: number$1(),
|
|
@@ -25319,7 +25490,7 @@ method(object({
|
|
|
25319
25490
|
* covers inline, ~10 KB of base64 per row, on a query this UI mounts
|
|
25320
25491
|
* four times and the viewer holds at `staleTime: 30_000`.
|
|
25321
25492
|
*
|
|
25322
|
-
* Nothing loses its avatar: `
|
|
25493
|
+
* Nothing loses its avatar: `coverMediaId` is already on every row and
|
|
25323
25494
|
* the `event-media` plane serves that key `immutable` with an ETag.
|
|
25324
25495
|
*
|
|
25325
25496
|
* **This is an INPUT field, so it does not reach the addon until the
|
|
@@ -27787,8 +27958,8 @@ var VehicleSchema = object({
|
|
|
27787
27958
|
id: string(),
|
|
27788
27959
|
name: string(),
|
|
27789
27960
|
sampleCount: number$1().int().nonnegative(),
|
|
27790
|
-
|
|
27791
|
-
/** Inline base64 of the cover sample's plate crop, resolved from `
|
|
27961
|
+
coverMediaId: number$1().int().optional(),
|
|
27962
|
+
/** Inline base64 of the cover sample's plate crop, resolved from `coverMediaId`. */
|
|
27792
27963
|
coverBase64: string().optional()
|
|
27793
27964
|
});
|
|
27794
27965
|
var VehicleSampleInfoSchema = object({
|
|
@@ -27821,7 +27992,7 @@ var PlateInfoSchema = object({
|
|
|
27821
27992
|
/** keyFrame parity: the plate bbox (pixel space) on the native key frame. */
|
|
27822
27993
|
plateBbox: BoundingBoxSchema.optional(),
|
|
27823
27994
|
/** keyFrame parity: MediaStore key of the track's native-resolution key frame. */
|
|
27824
|
-
|
|
27995
|
+
keyFrameMediaId: number$1().int().optional(),
|
|
27825
27996
|
base64: string().optional(),
|
|
27826
27997
|
/**
|
|
27827
27998
|
* Same crop as a data-plane URL, always present when the plate has a stored
|
|
@@ -27842,11 +28013,14 @@ var PlateInfoSchema = object({
|
|
|
27842
28013
|
* `data:image/jpeg;base64,…` from a row whose `key` sat right beside it, in a
|
|
27843
28014
|
* dialog already rendering its key FRAME from the `event-media` plane.
|
|
27844
28015
|
*
|
|
27845
|
-
* `url` is `/addon/<addonId>/event-media/<
|
|
27846
|
-
* media
|
|
28016
|
+
* `url` is `/addon/<addonId>/event-media/m/<mediaId>` (D482). The plane
|
|
28017
|
+
* resolves a media row by its own id, so this needed no new plane and no new
|
|
28018
|
+
* access decision.
|
|
27847
28019
|
*/
|
|
27848
28020
|
var MediaFileLiteSchema = object({
|
|
27849
|
-
|
|
28021
|
+
/** The media row's own id — the same address `MediaFileRef.mediaId` carries
|
|
28022
|
+
* (D482). It was the row's composite key, which embedded the owner. */
|
|
28023
|
+
mediaId: number$1().int(),
|
|
27850
28024
|
kind: string(),
|
|
27851
28025
|
url: string(),
|
|
27852
28026
|
sizeBytes: number$1(),
|
|
@@ -27905,7 +28079,7 @@ method(object({
|
|
|
27905
28079
|
}), method(object({
|
|
27906
28080
|
/** Inline {@link VehicleSchema.coverBase64} on every row. Default
|
|
27907
28081
|
* `false` — the vehicle twin of `faceGallery.listIdentities`'s
|
|
27908
|
-
* option; `
|
|
28082
|
+
* option; `coverMediaId` + the `event-media` plane carry the picture.
|
|
27909
28083
|
* INPUT field: stripped by the hub router until the train ships, which
|
|
27910
28084
|
* resolves to `false` and is exactly the intended default. */
|
|
27911
28085
|
includeCrops: boolean().optional() }).optional(), array(VehicleSchema).readonly()), method(object({ name: string().min(1) }), VehicleSchema, {
|
|
@@ -29229,7 +29403,14 @@ var SceneReferenceSchema = object({
|
|
|
29229
29403
|
modelId: string(),
|
|
29230
29404
|
condition: SceneConditionSchema,
|
|
29231
29405
|
capturedAt: number$1(),
|
|
29232
|
-
|
|
29406
|
+
/**
|
|
29407
|
+
* The reference thumbnail's media ROW id (D482).
|
|
29408
|
+
*
|
|
29409
|
+
* The name already said `mediaId` while the value was the row's composite
|
|
29410
|
+
* key — a leftover that read as done and was not. It is the row's own id
|
|
29411
|
+
* now, addressed at `/addon/<addonId>/event-media/m/<id>`.
|
|
29412
|
+
*/
|
|
29413
|
+
thumbnailMediaId: number$1().int().optional(),
|
|
29233
29414
|
/** Whole-frame (downscaled) embedding captured alongside the ROI crop. The
|
|
29234
29415
|
* anti-view-shift anchor: a bumped camera, a PTZ preset or a re-aim makes the
|
|
29235
29416
|
* normalized rect frame a different piece of world, and the scene would
|
|
@@ -30043,7 +30224,29 @@ var LoggingSettingsPatchSchema = object({
|
|
|
30043
30224
|
* disarmed the channels it did not mention would make the Levels page and
|
|
30044
30225
|
* the Diagnostics page fight over the same value.
|
|
30045
30226
|
*/
|
|
30046
|
-
channels: array(LogChannelWindowPatchSchema).readonly().optional()
|
|
30227
|
+
channels: array(LogChannelWindowPatchSchema).readonly().optional(),
|
|
30228
|
+
/**
|
|
30229
|
+
* How many days the analytics OPS LOG is kept — the audit trail of what
|
|
30230
|
+
* retention actually deleted.
|
|
30231
|
+
*
|
|
30232
|
+
* It lives HERE, on the logging document, and not on the analytics addon's
|
|
30233
|
+
* settings form, on the operator's instruction: every other log-ish window in
|
|
30234
|
+
* this system is configured through this one document, and a retention audit
|
|
30235
|
+
* configured somewhere else is a second place to look when the question is
|
|
30236
|
+
* "what happened to my data".
|
|
30237
|
+
*
|
|
30238
|
+
* That placement has a cost worth stating: this document ships in the
|
|
30239
|
+
* framework closure, so this knob needs a published `@camstack/server` while
|
|
30240
|
+
* the four windows beside it (D485) reach a node on `camstack deploy`.
|
|
30241
|
+
*
|
|
30242
|
+
* `retention-model.ts` argued this one must NOT follow a device window,
|
|
30243
|
+
* because the audit trail is the history of the SWEEP and not of the camera.
|
|
30244
|
+
* That argument stands and is untouched — what changes is that 30 days stops
|
|
30245
|
+
* being a constant nobody can reach. `0` keeps it forever. The floor is 1 day
|
|
30246
|
+
* rather than 0-as-delete: an audit log truncated to nothing is precisely the
|
|
30247
|
+
* state in which the next 9.5 GiB leak cannot be explained.
|
|
30248
|
+
*/
|
|
30249
|
+
opsLogRetentionDays: number$1().int().min(0).max(3650).optional()
|
|
30047
30250
|
});
|
|
30048
30251
|
/**
|
|
30049
30252
|
* Which LAYER of the hierarchy is addressed. Absent = the cluster layer.
|
|
@@ -30116,6 +30319,14 @@ var LoggingSettingsStateSchema = object({
|
|
|
30116
30319
|
channels: array(LogChannelDescriptorSchema).readonly(),
|
|
30117
30320
|
/** The channels ARMED right now, each with its deadline. */
|
|
30118
30321
|
activeChannels: array(LogChannelWindowStateSchema).readonly(),
|
|
30322
|
+
/**
|
|
30323
|
+
* The ops-log window in days, as it is in force. `0` = kept forever.
|
|
30324
|
+
*
|
|
30325
|
+
* Reported rather than left to the caller's memory of what it wrote: this is
|
|
30326
|
+
* the value the analytics sweep will actually use, and an operator asking how
|
|
30327
|
+
* long their audit trail lives should not have to infer it from a default.
|
|
30328
|
+
*/
|
|
30329
|
+
opsLogRetentionDays: number$1().int().min(0),
|
|
30119
30330
|
persisted: boolean()
|
|
30120
30331
|
});
|
|
30121
30332
|
method(_void(), FeatureManifestSchema), method(_void(), HealthStatusSchema), method(_void(), FeatureManifestSchema), method(_void(), array(NetworkAddressSchema).readonly()), method(_void(), unknown().nullable(), { auth: "admin" }), method(record(string(), unknown()), _null(), {
|
|
@@ -30677,7 +30888,7 @@ var StationaryObjectSchema = object({
|
|
|
30677
30888
|
/** Enrichment label carried from the source track (identity / plate). */
|
|
30678
30889
|
label: string().optional(),
|
|
30679
30890
|
/** Native-resolution key-frame media key for the parked object's best image. */
|
|
30680
|
-
|
|
30891
|
+
keyFrameMediaId: number$1().int().optional()
|
|
30681
30892
|
});
|
|
30682
30893
|
var CameraOccupancySnapshotSchema = object({
|
|
30683
30894
|
/** Frame timestamp of the inference result that produced this snapshot. */
|
|
@@ -31833,6 +32044,12 @@ Object.freeze({
|
|
|
31833
32044
|
addonId: null,
|
|
31834
32045
|
access: "create"
|
|
31835
32046
|
},
|
|
32047
|
+
"dataStoreProvider.upsert": {
|
|
32048
|
+
capName: "data-store-provider",
|
|
32049
|
+
capScope: "system",
|
|
32050
|
+
addonId: null,
|
|
32051
|
+
access: "create"
|
|
32052
|
+
},
|
|
31836
32053
|
"dayNight.getOptions": {
|
|
31837
32054
|
capName: "day-night",
|
|
31838
32055
|
capScope: "device",
|
|
@@ -34269,6 +34486,12 @@ Object.freeze({
|
|
|
34269
34486
|
addonId: null,
|
|
34270
34487
|
access: "view"
|
|
34271
34488
|
},
|
|
34489
|
+
"pipelineAnalytics.listRecentSummaries": {
|
|
34490
|
+
capName: "pipeline-analytics",
|
|
34491
|
+
capScope: "device",
|
|
34492
|
+
addonId: null,
|
|
34493
|
+
access: "view"
|
|
34494
|
+
},
|
|
34272
34495
|
"pipelineAnalytics.listRecentTracks": {
|
|
34273
34496
|
capName: "pipeline-analytics",
|
|
34274
34497
|
capScope: "device",
|
|
@@ -35697,6 +35920,12 @@ Object.freeze({
|
|
|
35697
35920
|
addonId: null,
|
|
35698
35921
|
access: "create"
|
|
35699
35922
|
},
|
|
35923
|
+
"settingsStore.upsert": {
|
|
35924
|
+
capName: "settings-store",
|
|
35925
|
+
capScope: "system",
|
|
35926
|
+
addonId: null,
|
|
35927
|
+
access: "create"
|
|
35928
|
+
},
|
|
35700
35929
|
"smtpProvider.getStatus": {
|
|
35701
35930
|
capName: "smtp-provider",
|
|
35702
35931
|
capScope: "system",
|
|
@@ -38090,6 +38319,11 @@ Object.freeze({
|
|
|
38090
38319
|
form: "single",
|
|
38091
38320
|
optional: true
|
|
38092
38321
|
}],
|
|
38322
|
+
"pipelineAnalytics.listRecentSummaries": [{
|
|
38323
|
+
name: "deviceIds",
|
|
38324
|
+
form: "array",
|
|
38325
|
+
optional: false
|
|
38326
|
+
}],
|
|
38093
38327
|
"pipelineAnalytics.listRecentTracks": [{
|
|
38094
38328
|
name: "deviceIds",
|
|
38095
38329
|
form: "array",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@camstack/addon-ai",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.106",
|
|
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",
|