@camstack/addon-provider-gree 0.2.98 → 0.2.100
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
|
@@ -2,7 +2,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
|
2
2
|
let dgram = require("dgram");
|
|
3
3
|
let crypto$1 = require("crypto");
|
|
4
4
|
let events = require("events");
|
|
5
|
-
//#region ../types/dist/event-category-
|
|
5
|
+
//#region ../types/dist/event-category-ZyX6jcse.mjs
|
|
6
6
|
var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
7
7
|
EventCategory["SystemBoot"] = "system.boot";
|
|
8
8
|
EventCategory["SystemAddonsReady"] = "system.addons-ready";
|
|
@@ -563,7 +563,7 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
|
563
563
|
* a package zone — a newly-appeared stationary object of a package class
|
|
564
564
|
* that cleared the class / zone / dwell / size gates. Payload:
|
|
565
565
|
* `PipelineAnalyticsPackageDeliveredPayload` carrying `{ deviceId,
|
|
566
|
-
* entryId, className, zoneIds,
|
|
566
|
+
* entryId, className, zoneIds, keyFrameMediaId?, bbox, timestamp }`.
|
|
567
567
|
* Telemetry (D8): the durable record is the `package-events` store row;
|
|
568
568
|
* this bus topic drives notifier rules + live UI. See
|
|
569
569
|
* docs/superpowers/specs/2026-07-17-package-zones-design.md §5.1.
|
|
@@ -5349,7 +5349,7 @@ var ZodIssueCode = {
|
|
|
5349
5349
|
var ZodFirstPartyTypeKind;
|
|
5350
5350
|
ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
|
|
5351
5351
|
//#endregion
|
|
5352
|
-
//#region ../types/dist/sleep-
|
|
5352
|
+
//#region ../types/dist/sleep-DBKu2-U5.mjs
|
|
5353
5353
|
/**
|
|
5354
5354
|
* The audio chunk plane's byte format, and the ONE expansion from a coded
|
|
5355
5355
|
* window to float samples (D455).
|
|
@@ -7316,13 +7316,30 @@ new Set([
|
|
|
7316
7316
|
"scene",
|
|
7317
7317
|
"motion",
|
|
7318
7318
|
"object",
|
|
7319
|
-
"audio"
|
|
7319
|
+
"audio",
|
|
7320
|
+
"mosaic"
|
|
7320
7321
|
]);
|
|
7321
|
-
|
|
7322
|
+
/**
|
|
7323
|
+
* The owner types that are event tables, in the order the event-media resolver
|
|
7324
|
+
* should consider them. Exported so a consumer asking "is this key an event?"
|
|
7325
|
+
* does not re-spell the list and drift from it.
|
|
7326
|
+
*/
|
|
7327
|
+
var EVENT_OWNER_TYPES = [
|
|
7322
7328
|
"motion",
|
|
7323
7329
|
"object",
|
|
7324
7330
|
"audio"
|
|
7325
|
-
]
|
|
7331
|
+
];
|
|
7332
|
+
/**
|
|
7333
|
+
* The same list as a Zod enum, for the cap inputs that must NAME the table
|
|
7334
|
+
* (D482: `getEventMedia` / `listEventMedia` take an owner, and an owner is
|
|
7335
|
+
* `(table, id)`).
|
|
7336
|
+
*
|
|
7337
|
+
* Built FROM {@link EVENT_OWNER_TYPES} rather than re-spelled: a fourth event
|
|
7338
|
+
* table would otherwise be accepted by the codec and refused at the door, with
|
|
7339
|
+
* nothing failing until a caller asked.
|
|
7340
|
+
*/
|
|
7341
|
+
var EventOwnerTypeSchema = _enum(EVENT_OWNER_TYPES);
|
|
7342
|
+
new Set(EVENT_OWNER_TYPES);
|
|
7326
7343
|
var EncodeProfileSchema = object({
|
|
7327
7344
|
video: object({
|
|
7328
7345
|
codec: _enum([
|
|
@@ -7361,7 +7378,23 @@ var EncodeProfileSchema = object({
|
|
|
7361
7378
|
"zerolatency",
|
|
7362
7379
|
"film",
|
|
7363
7380
|
"animation"
|
|
7364
|
-
]).optional()
|
|
7381
|
+
]).optional(),
|
|
7382
|
+
/**
|
|
7383
|
+
* ONE slice per access unit.
|
|
7384
|
+
*
|
|
7385
|
+
* `-tune zerolatency` turns on x264's sliced threads, and a frame then leaves
|
|
7386
|
+
* the encoder as five NAL slices that share one RTP timestamp and carry one
|
|
7387
|
+
* marker bit. A libwebrtc depacketiser sees five frame-starts and one
|
|
7388
|
+
* frame-end per frame: the first pictures render and the video then freezes
|
|
7389
|
+
* for good while the audio, on its own plane, plays on. Measured on this hub
|
|
7390
|
+
* 2026-09-13 against the Echo, and reduced to one slice by this flag alone.
|
|
7391
|
+
*
|
|
7392
|
+
* A NAMED field and not a raw flag, because {@link EgressEncodeSchema} omits
|
|
7393
|
+
* `outputArgs` on purpose: an opaque array is part of the sharing key, so two
|
|
7394
|
+
* consumers meaning the same thing spelled differently would stop sharing one
|
|
7395
|
+
* child. Absent means "whatever the encoder does" — today's behaviour.
|
|
7396
|
+
*/
|
|
7397
|
+
singleSlicePerFrame: boolean().optional()
|
|
7365
7398
|
}),
|
|
7366
7399
|
audio: union([literal("passthrough"), object({
|
|
7367
7400
|
codec: _enum([
|
|
@@ -7411,7 +7444,7 @@ var BASE_LIVE_EGRESS_PROFILE = {
|
|
|
7411
7444
|
audio: "passthrough"
|
|
7412
7445
|
};
|
|
7413
7446
|
({ ...BASE_LIVE_EGRESS_PROFILE }), { ...BASE_LIVE_EGRESS_PROFILE.video };
|
|
7414
|
-
({ ...BASE_LIVE_EGRESS_PROFILE });
|
|
7447
|
+
({ ...BASE_LIVE_EGRESS_PROFILE }), { ...BASE_LIVE_EGRESS_PROFILE.video };
|
|
7415
7448
|
/**
|
|
7416
7449
|
* Deep wiring healthcheck — snapshot of active reachability probes across
|
|
7417
7450
|
* every declared capability + widget of every installed plugin, on every
|
|
@@ -12521,6 +12554,16 @@ method(object({
|
|
|
12521
12554
|
filter: QueryFilterSchema.optional(),
|
|
12522
12555
|
columns: array(string()).readonly().optional()
|
|
12523
12556
|
}), array(SettingsRecordSchema).readonly()), method(object({
|
|
12557
|
+
namespace: string().optional(),
|
|
12558
|
+
collection: string(),
|
|
12559
|
+
/** Declared columns identifying the slot; must be covered by a UNIQUE
|
|
12560
|
+
* index on the collection. Never empty. */
|
|
12561
|
+
conflict: array(string()).readonly(),
|
|
12562
|
+
record: BulkRecordSchema
|
|
12563
|
+
}), object({
|
|
12564
|
+
/** The id the row HAS: assigned by SQLite on an insert, or the existing
|
|
12565
|
+
* row's own id on an update. */
|
|
12566
|
+
id: union([string(), number()]) }), { kind: "mutation" }), method(object({
|
|
12524
12567
|
namespace: string().optional(),
|
|
12525
12568
|
collection: string(),
|
|
12526
12569
|
record: object({
|
|
@@ -12655,6 +12698,14 @@ method(_void(), EngineInfoSchema, { auth: "admin" }), method(object({
|
|
|
12655
12698
|
id: union([string(), number()]) }), {
|
|
12656
12699
|
kind: "mutation",
|
|
12657
12700
|
auth: "admin"
|
|
12701
|
+
}), method(object({
|
|
12702
|
+
namespace: string().optional(),
|
|
12703
|
+
collection: string(),
|
|
12704
|
+
conflict: array(string()).readonly(),
|
|
12705
|
+
record: BulkRecordSchema
|
|
12706
|
+
}), object({ id: union([string(), number()]) }), {
|
|
12707
|
+
kind: "mutation",
|
|
12708
|
+
auth: "admin"
|
|
12658
12709
|
}), method(object({
|
|
12659
12710
|
namespace: string().optional(),
|
|
12660
12711
|
collection: string(),
|
|
@@ -19137,8 +19188,8 @@ var TrackPositionSchema = object({
|
|
|
19137
19188
|
var TrackSnapshotSchema = object({
|
|
19138
19189
|
timestamp: number(),
|
|
19139
19190
|
position: TrackPositionSchema,
|
|
19140
|
-
/**
|
|
19141
|
-
|
|
19191
|
+
/** The snapshot's media row id (D482); resolve via `listTrackMedia({ trackId })`. */
|
|
19192
|
+
mediaId: number().int()
|
|
19142
19193
|
});
|
|
19143
19194
|
/**
|
|
19144
19195
|
* Normalized 0..1 trajectory envelope (min/max over every position bbox,
|
|
@@ -19742,14 +19793,14 @@ var ObjectEventSchema = object({
|
|
|
19742
19793
|
* pixel-space `bbox` onto a displayed image. Omitted in slim projection. */
|
|
19743
19794
|
frameWidth: number().optional(),
|
|
19744
19795
|
frameHeight: number().optional(),
|
|
19745
|
-
/**
|
|
19746
|
-
|
|
19747
|
-
/** Design B:
|
|
19796
|
+
/** Media row id of the crop attached to this event (if any) — D482. */
|
|
19797
|
+
mediaId: number().int().optional(),
|
|
19798
|
+
/** Design B: media row id of the track's native-resolution key frame (the
|
|
19748
19799
|
* best-detection full frame). Resolve via the event-media data-plane
|
|
19749
|
-
* (`/addon/<addonId>/event-media/<
|
|
19800
|
+
* (`/addon/<addonId>/event-media/m/<keyFrameMediaId>`) for a detail view that
|
|
19750
19801
|
* draws `bbox` over the native frame. Absent on legacy rows / non-decoded
|
|
19751
|
-
* sources — consumers fall back to `
|
|
19752
|
-
|
|
19802
|
+
* sources — consumers fall back to `mediaId` (the tight crop). */
|
|
19803
|
+
keyFrameMediaId: number().int().optional(),
|
|
19753
19804
|
/** Populated by B5 (recording playback URL for this event). */
|
|
19754
19805
|
mediaUrl: string().optional(),
|
|
19755
19806
|
/** The parent track's key-event importance [0,1], propagated to every object
|
|
@@ -19799,7 +19850,7 @@ var MediaFileKindEnum = _enum([
|
|
|
19799
19850
|
* hub-main's heap on the way past — for an `<img>` that would have cached it.
|
|
19800
19851
|
*
|
|
19801
19852
|
* `url` points at the `event-media` data plane
|
|
19802
|
-
* (`/addon/<addonId>/event-media/<
|
|
19853
|
+
* (`/addon/<addonId>/event-media/m/<mediaId>` — D482), which serves the same blob
|
|
19803
19854
|
* with an ETag and `Cache-Control: immutable`, honours conditional GETs, can
|
|
19804
19855
|
* render a `?variant=thumb`, and streams. The hub gate in front of it requires
|
|
19805
19856
|
* a bearer or the session cookie (`access: 'authenticated'`), so the bytes are
|
|
@@ -19807,10 +19858,13 @@ var MediaFileKindEnum = _enum([
|
|
|
19807
19858
|
* `data-plane-access.ts` for the rule and the one gap it does not close
|
|
19808
19859
|
* (per-device scoping).
|
|
19809
19860
|
*
|
|
19810
|
-
* The URL is built from the row's
|
|
19811
|
-
*
|
|
19861
|
+
* The URL is built from the row's own id, which since D482 says nothing about
|
|
19862
|
+
* the row's owner or kind — and that is the point. The published `kind` is not
|
|
19863
|
+
* the stored one (a track's face/plate crop is stored as `crop` under
|
|
19812
19864
|
* `('face'|'plate', '<prefix>-<trackId>')` and published as
|
|
19813
|
-
* `faceCrop`/`plateCrop
|
|
19865
|
+
* `faceCrop`/`plateCrop`), and under the old composite key the URL had to be
|
|
19866
|
+
* taken from `row.key` verbatim or it 404'd exactly those two rows. An id
|
|
19867
|
+
* cannot be mis-reconstructed, because there is nothing in it to reconstruct.
|
|
19814
19868
|
*
|
|
19815
19869
|
* ## `base64` is TRANSITIONAL and is going away
|
|
19816
19870
|
*
|
|
@@ -19823,7 +19877,19 @@ var MediaFileKindEnum = _enum([
|
|
|
19823
19877
|
* `analytics-query-facade.ts`; nothing else reads it.
|
|
19824
19878
|
*/
|
|
19825
19879
|
var MediaFileSchema = object({
|
|
19826
|
-
|
|
19880
|
+
/**
|
|
19881
|
+
* The media row's OWN id — the rowid SQLite assigned it (D482).
|
|
19882
|
+
*
|
|
19883
|
+
* It used to be the row's composite key, `<ownerType>:<ownerId>:<fileKind>
|
|
19884
|
+
* [:<timestampMs>]`, which embedded a FOREIGN id. D474 made event ids
|
|
19885
|
+
* per-table rowid aliases, so `object:101314` and `motion:101314` are two
|
|
19886
|
+
* different rows that spell the same number, and a track whose
|
|
19887
|
+
* `bestEventId` was an object event was served a motion event's snapshot —
|
|
19888
|
+
* a night-time thumbnail on an afternoon track, with no error anywhere. A
|
|
19889
|
+
* surrogate id cannot name the wrong row's owner, because it names no owner
|
|
19890
|
+
* at all.
|
|
19891
|
+
*/
|
|
19892
|
+
mediaId: number().int(),
|
|
19827
19893
|
kind: MediaFileKindEnum,
|
|
19828
19894
|
sizeBytes: number(),
|
|
19829
19895
|
timestamp: number()
|
|
@@ -19931,7 +19997,7 @@ var RetrainTrackSchema = object({
|
|
|
19931
19997
|
});
|
|
19932
19998
|
/** A frame the picker may offer — an index row, no blob was read to produce it. */
|
|
19933
19999
|
var RetrainFrameCandidateSchema = object({
|
|
19934
|
-
|
|
20000
|
+
mediaId: number().int(),
|
|
19935
20001
|
kind: MediaFileKindEnum,
|
|
19936
20002
|
timestamp: number(),
|
|
19937
20003
|
sizeBytes: number().int(),
|
|
@@ -19945,7 +20011,7 @@ var RetrainFrameSchema = object({
|
|
|
19945
20011
|
deviceId: number(),
|
|
19946
20012
|
trackId: string(),
|
|
19947
20013
|
/** Provenance only. It may already point at nothing — that is expected. */
|
|
19948
|
-
|
|
20014
|
+
sourceMediaId: number().int(),
|
|
19949
20015
|
sourceKind: MediaFileKindEnum,
|
|
19950
20016
|
sizeBytes: number().int(),
|
|
19951
20017
|
width: number().int(),
|
|
@@ -19961,7 +20027,7 @@ var RetrainCopyRefusalSchema = _enum([
|
|
|
19961
20027
|
var RetrainFrameSelectionSchema = object({
|
|
19962
20028
|
copied: array(RetrainFrameSchema).readonly(),
|
|
19963
20029
|
refused: array(object({
|
|
19964
|
-
|
|
20030
|
+
sourceMediaId: number().int(),
|
|
19965
20031
|
reason: RetrainCopyRefusalSchema
|
|
19966
20032
|
})).readonly()
|
|
19967
20033
|
});
|
|
@@ -19969,7 +20035,7 @@ var RetrainFrameListSchema = object({
|
|
|
19969
20035
|
candidates: array(RetrainFrameCandidateSchema).readonly(),
|
|
19970
20036
|
copies: array(RetrainFrameSchema).readonly(),
|
|
19971
20037
|
/** What the page pre-selects — the native key frame when one survives. */
|
|
19972
|
-
|
|
20038
|
+
autoPickMediaId: number().int().optional()
|
|
19973
20039
|
});
|
|
19974
20040
|
/** What the operator asked the assist to look for. */
|
|
19975
20041
|
var RetrainAssistSubjectSchema = discriminatedUnion("kind", [object({
|
|
@@ -20064,9 +20130,11 @@ var RecentTracksQueryInput = object({
|
|
|
20064
20130
|
});
|
|
20065
20131
|
/**
|
|
20066
20132
|
* A Summary (D359): the per-camera session envelope that references tracks.
|
|
20067
|
-
* `
|
|
20068
|
-
* served by the event-media plane
|
|
20069
|
-
* member visible has been materialised
|
|
20133
|
+
* `groupShotMediaId` is the media ROW id of its group shot (`ownerKind:
|
|
20134
|
+
* 'summary'`, served by the event-media plane at `/m/<id>`), null until the
|
|
20135
|
+
* first frame with a member visible has been materialised (D482 — it was the
|
|
20136
|
+
* row's composite key, which embedded the owner and could name another table's
|
|
20137
|
+
* row once event ids became per-table rowids).
|
|
20070
20138
|
*/
|
|
20071
20139
|
var SummarySchema = object({
|
|
20072
20140
|
id: string(),
|
|
@@ -20075,19 +20143,115 @@ var SummarySchema = object({
|
|
|
20075
20143
|
lastActiveAt: number(),
|
|
20076
20144
|
sealedAt: number().nullable(),
|
|
20077
20145
|
memberCount: number().int().nonnegative(),
|
|
20078
|
-
|
|
20146
|
+
groupShotMediaId: number().int().nullable()
|
|
20079
20147
|
});
|
|
20080
20148
|
var SummariesQueryInput = object({
|
|
20081
20149
|
deviceIds: array(number()).min(1),
|
|
20082
20150
|
since: number().optional(),
|
|
20083
20151
|
until: number().optional(),
|
|
20084
|
-
limit: number().int().min(1).max(200).default(50)
|
|
20152
|
+
limit: number().int().min(1).max(200).default(50),
|
|
20153
|
+
/** The same member-wise filter {@link listRecentSummaries} takes — one
|
|
20154
|
+
* meaning of "dog" on every summary surface. */
|
|
20155
|
+
classes: array(string().min(1).max(60)).max(40).optional()
|
|
20085
20156
|
});
|
|
20086
|
-
var SummariesPageSchema = object({ summaries: array(SummarySchema).readonly() });
|
|
20087
20157
|
var SummaryDetailSchema = object({
|
|
20088
20158
|
summary: SummarySchema,
|
|
20089
|
-
/**
|
|
20090
|
-
|
|
20159
|
+
/** Members in absorption order, oldest join first. */
|
|
20160
|
+
members: array(object({
|
|
20161
|
+
trackId: string(),
|
|
20162
|
+
/**
|
|
20163
|
+
* The track's class at the time it JOINED, or `null` when it was unresolved
|
|
20164
|
+
* and the track no longer exists to fill it.
|
|
20165
|
+
*
|
|
20166
|
+
* The join, not the latest opinion: class voting can re-decide a track's
|
|
20167
|
+
* class afterwards, and a group's composition is the history of who came
|
|
20168
|
+
* together. A consumer counts these to badge a thumbnail — "two people and a
|
|
20169
|
+
* dog" — rather than being handed a second, denormalised tally that would
|
|
20170
|
+
* drift from the members it claims to describe.
|
|
20171
|
+
*/
|
|
20172
|
+
className: string().nullable(),
|
|
20173
|
+
/** `primary` is the one member that carries the group's identity. */
|
|
20174
|
+
role: _enum([
|
|
20175
|
+
"primary",
|
|
20176
|
+
"sibling",
|
|
20177
|
+
"child"
|
|
20178
|
+
]).nullable(),
|
|
20179
|
+
joinedAt: number(),
|
|
20180
|
+
/** Tier 1 — the sub-class (`dog`, `van`), resolved from the member's track
|
|
20181
|
+
* at read time. Absent when nothing resolved, never an empty string. */
|
|
20182
|
+
label: string().optional(),
|
|
20183
|
+
/** Tier 2 — the instance: a person's name, a plate. Absent when the pipeline
|
|
20184
|
+
* recognised nobody, and absent for a member whose track has been pruned —
|
|
20185
|
+
* a thumbnail that names the wrong person is worse than one naming nobody. */
|
|
20186
|
+
subLabel: string().optional()
|
|
20187
|
+
})).readonly()
|
|
20188
|
+
});
|
|
20189
|
+
/**
|
|
20190
|
+
* What a LIST of groups carries: the envelope plus what it is MADE OF.
|
|
20191
|
+
*
|
|
20192
|
+
* Coarse on purpose — the operator's rule is "only the rough data on the list,
|
|
20193
|
+
* we extend when we notice we need more". Enough to draw the card ("two people
|
|
20194
|
+
* and a dog") and no more. The MEMBERS, their names and the per-member links
|
|
20195
|
+
* are on {@link getSummary}: shipping every member of every group so a client
|
|
20196
|
+
* can count them turns a page of two hundred groups into a thousand records to
|
|
20197
|
+
* draw two hundred badges.
|
|
20198
|
+
*/
|
|
20199
|
+
var SummaryListItemSchema = object({
|
|
20200
|
+
summary: SummarySchema,
|
|
20201
|
+
/** Class counts, most numerous first; `className: null` is a member whose
|
|
20202
|
+
* class never resolved, counted so the counts add up to `memberCount`. */
|
|
20203
|
+
classes: array(object({
|
|
20204
|
+
className: string().nullable(),
|
|
20205
|
+
count: number().int().positive()
|
|
20206
|
+
})).readonly()
|
|
20207
|
+
});
|
|
20208
|
+
var SummariesPageSchema = object({ summaries: array(SummaryListItemSchema).readonly() });
|
|
20209
|
+
/**
|
|
20210
|
+
* The paged feed, deliberately the SAME shape as {@link RecentTracksQueryInput}.
|
|
20211
|
+
*
|
|
20212
|
+
* The reel on the cameras page and the Events gallery both ride a cursor, so a
|
|
20213
|
+
* summaries feed that could only answer "the last N for these cameras"
|
|
20214
|
+
* (`listSummaries`) would make groups available in the timeline and nowhere
|
|
20215
|
+
* else. Two feeds with different ordering contracts would be two ideas of what
|
|
20216
|
+
* "newest" means, on one screen.
|
|
20217
|
+
*/
|
|
20218
|
+
var RecentSummariesQueryInput = object({
|
|
20219
|
+
/** Devices to merge. An empty array yields an empty page. */
|
|
20220
|
+
deviceIds: array(number()),
|
|
20221
|
+
/** Window lower bound on `lastActiveAt` (inclusive). */
|
|
20222
|
+
since: number().optional(),
|
|
20223
|
+
/** Window upper bound on `lastActiveAt` (inclusive). */
|
|
20224
|
+
until: number().optional(),
|
|
20225
|
+
limit: number().int().min(1).max(500).default(100),
|
|
20226
|
+
/** Opaque continuation cursor from a previous page's `nextCursor`. */
|
|
20227
|
+
cursor: string().optional(),
|
|
20228
|
+
/**
|
|
20229
|
+
* Restrict to these classes — THE SAME FIELD `listRecentTracks` takes, and
|
|
20230
|
+
* deliberately the same name: the events filter tree emits one list of ticked
|
|
20231
|
+
* taxonomy nodes, and a summaries feed that called it something else would
|
|
20232
|
+
* make the operator's one filter component produce two shapes.
|
|
20233
|
+
*
|
|
20234
|
+
* A question about the MEMBERS: a group matches when ANY of them does. "Show
|
|
20235
|
+
* me the arrivals with a dog" has to return the group of four people who had
|
|
20236
|
+
* one with them; a filter on the group's own fields could only ever answer
|
|
20237
|
+
* about its primary.
|
|
20238
|
+
*
|
|
20239
|
+
* Matched against all THREE tiers of a member — the class (`animal`), the
|
|
20240
|
+
* sub-class (`dog`) and the instance (a name, a plate) — because which tier a
|
|
20241
|
+
* ticked node lives on is the taxonomy's business, not the caller's. `dog` is
|
|
20242
|
+
* an event kind in the tree and a tier-1 label on an `animal` track; a filter
|
|
20243
|
+
* that read only the class would answer "animal" and never "dog".
|
|
20244
|
+
*
|
|
20245
|
+
* ABSENT or EMPTY means no filter — absent is not a selection of none.
|
|
20246
|
+
*/
|
|
20247
|
+
classes: array(string().min(1).max(60)).max(40).optional()
|
|
20248
|
+
});
|
|
20249
|
+
var RecentSummariesPageSchema = object({
|
|
20250
|
+
/** Ordered by (`lastActiveAt` DESC, id DESC). Same light item as
|
|
20251
|
+
* {@link listSummaries} — one list shape, so a card renders the same
|
|
20252
|
+
* whichever feed drew it. */
|
|
20253
|
+
summaries: array(SummaryListItemSchema).readonly(),
|
|
20254
|
+
nextCursor: string().nullable()
|
|
20091
20255
|
});
|
|
20092
20256
|
var RecentTracksPageSchema = object({
|
|
20093
20257
|
/** Merged page, ordered by (`lastSeen` DESC, `trackId` DESC). */
|
|
@@ -20501,7 +20665,7 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
|
|
|
20501
20665
|
classes: array(string()).optional(),
|
|
20502
20666
|
/** See {@link ExcludeSourcesDoc}. */
|
|
20503
20667
|
excludeSources: array(TrackSourceSchema).optional()
|
|
20504
|
-
}), array(TrackSchema).readonly()), method(RecentTracksQueryInput, RecentTracksPageSchema), method(SummariesQueryInput, SummariesPageSchema), method(object({ id: string() }), SummaryDetailSchema.nullable()), method(object({ deviceId: number() }), _void(), {
|
|
20668
|
+
}), array(TrackSchema).readonly()), method(RecentTracksQueryInput, RecentTracksPageSchema), method(SummariesQueryInput, SummariesPageSchema), method(RecentSummariesQueryInput, RecentSummariesPageSchema), method(object({ id: string() }), SummaryDetailSchema.nullable()), method(object({ deviceId: number() }), _void(), {
|
|
20505
20669
|
kind: "mutation",
|
|
20506
20670
|
auth: "admin"
|
|
20507
20671
|
}), method(DeviceEventQueryInput, array(MotionEventSchema).readonly()), method(ObjectEventQueryInput, array(ObjectEventSchema).readonly()), method(DeviceEventQueryInput, array(AudioEventSchema).readonly()), method(object({ deviceId: number() }), array(EventKindDescriptorSchema).readonly()), method(object({ deviceIds: array(number()).min(1).max(200) }), array(EventKindsForDeviceSchema).readonly()), method(object({
|
|
@@ -20629,7 +20793,7 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
|
|
|
20629
20793
|
}), method(object({
|
|
20630
20794
|
deviceId: number(),
|
|
20631
20795
|
trackId: string(),
|
|
20632
|
-
|
|
20796
|
+
mediaIds: array(number().int()).min(1)
|
|
20633
20797
|
}), RetrainFrameSelectionSchema, {
|
|
20634
20798
|
kind: "mutation",
|
|
20635
20799
|
auth: "admin"
|
|
@@ -20697,7 +20861,10 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
|
|
|
20697
20861
|
kind: "query",
|
|
20698
20862
|
auth: "admin"
|
|
20699
20863
|
}), method(object({
|
|
20700
|
-
|
|
20864
|
+
/** Which of the three event tables owns the row. */
|
|
20865
|
+
ownerType: EventOwnerTypeSchema,
|
|
20866
|
+
/** The event's rowid in that table (D474: an event id is a number). */
|
|
20867
|
+
eventId: number().int(),
|
|
20701
20868
|
kind: MediaFileKindEnum.optional(),
|
|
20702
20869
|
deviceId: number()
|
|
20703
20870
|
}), array(MediaFileSchema).readonly()), method(object({
|
|
@@ -20708,7 +20875,8 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
|
|
|
20708
20875
|
trackId: string(),
|
|
20709
20876
|
deviceId: number()
|
|
20710
20877
|
}), array(MediaFileInfoSchema).readonly()), method(object({
|
|
20711
|
-
|
|
20878
|
+
ownerType: EventOwnerTypeSchema,
|
|
20879
|
+
eventId: number().int(),
|
|
20712
20880
|
deviceId: number()
|
|
20713
20881
|
}), array(MediaFileInfoSchema).readonly()), method(SearchObjectEventsInput, array(ScoredObjectEventSchema).readonly()), method(object({}), WipeObjectEmbeddingsResultSchema, {
|
|
20714
20882
|
kind: "mutation",
|
|
@@ -25901,8 +26069,8 @@ var IdentitySchema = object({
|
|
|
25901
26069
|
id: string(),
|
|
25902
26070
|
name: string(),
|
|
25903
26071
|
sampleCount: number().int().nonnegative(),
|
|
25904
|
-
|
|
25905
|
-
/** Inline base64 of the cover sample's crop, resolved from `
|
|
26072
|
+
coverMediaId: number().int().optional(),
|
|
26073
|
+
/** Inline base64 of the cover sample's crop, resolved from `coverMediaId`.
|
|
25906
26074
|
* Lets the UI render the person's face avatar instead of a placeholder icon. */
|
|
25907
26075
|
coverBase64: string().optional()
|
|
25908
26076
|
});
|
|
@@ -25928,8 +26096,8 @@ var IdentitySampleAuditRowSchema = object({
|
|
|
25928
26096
|
enrolledAt: number().int(),
|
|
25929
26097
|
deviceId: number().int().optional(),
|
|
25930
26098
|
source: _enum(["detected", "photo"]),
|
|
25931
|
-
/** The enrolled crop's media
|
|
25932
|
-
|
|
26099
|
+
/** The enrolled crop's media row id, so the panel can show the evidence. */
|
|
26100
|
+
mediaId: number().int().optional(),
|
|
25933
26101
|
/**
|
|
25934
26102
|
* False = the sample is stamped with a DIFFERENT face model, and a cosine
|
|
25935
26103
|
* across feature spaces is a well-formed float with no meaning. Every number
|
|
@@ -25998,15 +26166,15 @@ var FaceInfoSchema = object({
|
|
|
25998
26166
|
*/
|
|
25999
26167
|
cropUrl: string().optional(),
|
|
26000
26168
|
/** Design B: the face bbox (pixel space) on the key frame — lets a detail
|
|
26001
|
-
* view draw the box over the native `
|
|
26169
|
+
* view draw the box over the native `keyFrameMediaId` frame. Absent on
|
|
26002
26170
|
* legacy rows written before design B. */
|
|
26003
26171
|
faceBbox: BoundingBoxSchema.optional(),
|
|
26004
26172
|
/** Design B: MediaStore key of the track's native-resolution key frame.
|
|
26005
26173
|
* Fetch the native JPEG via the event-media data-plane
|
|
26006
|
-
* (`/addon/<addonId>/event-media/<
|
|
26174
|
+
* (`/addon/<addonId>/event-media/m/<keyFrameMediaId>`). Absent when the
|
|
26007
26175
|
* track produced no key frame (e.g. native/onboard source) — the UI falls
|
|
26008
26176
|
* back to the inline `base64` face crop. */
|
|
26009
|
-
|
|
26177
|
+
keyFrameMediaId: number().int().optional(),
|
|
26010
26178
|
/** Winning identity-match cosine (0..1) for this face's track, when an
|
|
26011
26179
|
* identity was auto-confirmed. Lets the UI surface WHY a face was assigned
|
|
26012
26180
|
* (confidence badge / low-confidence audit). Absent on legacy rows and on
|
|
@@ -26075,11 +26243,14 @@ var FaceClusterSchema = object({
|
|
|
26075
26243
|
* `data:image/jpeg;base64,…` from a row whose `key` sat right beside it, in a
|
|
26076
26244
|
* dialog already rendering its key FRAME from the `event-media` plane.
|
|
26077
26245
|
*
|
|
26078
|
-
* `url` is `/addon/<addonId>/event-media/<
|
|
26079
|
-
* media
|
|
26246
|
+
* `url` is `/addon/<addonId>/event-media/m/<mediaId>` (D482). The plane
|
|
26247
|
+
* resolves a media row by its own id, so this needed no new plane and no new
|
|
26248
|
+
* access decision.
|
|
26080
26249
|
*/
|
|
26081
26250
|
var MediaFileLiteSchema$1 = object({
|
|
26082
|
-
|
|
26251
|
+
/** The media row's own id — the same address `MediaFileRef.mediaId` carries
|
|
26252
|
+
* (D482). It was the row's composite key, which embedded the owner. */
|
|
26253
|
+
mediaId: number().int(),
|
|
26083
26254
|
kind: string(),
|
|
26084
26255
|
url: string(),
|
|
26085
26256
|
sizeBytes: number(),
|
|
@@ -26096,7 +26267,7 @@ method(object({
|
|
|
26096
26267
|
* covers inline, ~10 KB of base64 per row, on a query this UI mounts
|
|
26097
26268
|
* four times and the viewer holds at `staleTime: 30_000`.
|
|
26098
26269
|
*
|
|
26099
|
-
* Nothing loses its avatar: `
|
|
26270
|
+
* Nothing loses its avatar: `coverMediaId` is already on every row and
|
|
26100
26271
|
* the `event-media` plane serves that key `immutable` with an ETag.
|
|
26101
26272
|
*
|
|
26102
26273
|
* **This is an INPUT field, so it does not reach the addon until the
|
|
@@ -29459,8 +29630,8 @@ var VehicleSchema = object({
|
|
|
29459
29630
|
id: string(),
|
|
29460
29631
|
name: string(),
|
|
29461
29632
|
sampleCount: number().int().nonnegative(),
|
|
29462
|
-
|
|
29463
|
-
/** Inline base64 of the cover sample's plate crop, resolved from `
|
|
29633
|
+
coverMediaId: number().int().optional(),
|
|
29634
|
+
/** Inline base64 of the cover sample's plate crop, resolved from `coverMediaId`. */
|
|
29464
29635
|
coverBase64: string().optional()
|
|
29465
29636
|
});
|
|
29466
29637
|
var VehicleSampleInfoSchema = object({
|
|
@@ -29493,7 +29664,7 @@ var PlateInfoSchema = object({
|
|
|
29493
29664
|
/** keyFrame parity: the plate bbox (pixel space) on the native key frame. */
|
|
29494
29665
|
plateBbox: BoundingBoxSchema.optional(),
|
|
29495
29666
|
/** keyFrame parity: MediaStore key of the track's native-resolution key frame. */
|
|
29496
|
-
|
|
29667
|
+
keyFrameMediaId: number().int().optional(),
|
|
29497
29668
|
base64: string().optional(),
|
|
29498
29669
|
/**
|
|
29499
29670
|
* Same crop as a data-plane URL, always present when the plate has a stored
|
|
@@ -29514,11 +29685,14 @@ var PlateInfoSchema = object({
|
|
|
29514
29685
|
* `data:image/jpeg;base64,…` from a row whose `key` sat right beside it, in a
|
|
29515
29686
|
* dialog already rendering its key FRAME from the `event-media` plane.
|
|
29516
29687
|
*
|
|
29517
|
-
* `url` is `/addon/<addonId>/event-media/<
|
|
29518
|
-
* media
|
|
29688
|
+
* `url` is `/addon/<addonId>/event-media/m/<mediaId>` (D482). The plane
|
|
29689
|
+
* resolves a media row by its own id, so this needed no new plane and no new
|
|
29690
|
+
* access decision.
|
|
29519
29691
|
*/
|
|
29520
29692
|
var MediaFileLiteSchema = object({
|
|
29521
|
-
|
|
29693
|
+
/** The media row's own id — the same address `MediaFileRef.mediaId` carries
|
|
29694
|
+
* (D482). It was the row's composite key, which embedded the owner. */
|
|
29695
|
+
mediaId: number().int(),
|
|
29522
29696
|
kind: string(),
|
|
29523
29697
|
url: string(),
|
|
29524
29698
|
sizeBytes: number(),
|
|
@@ -29577,7 +29751,7 @@ method(object({
|
|
|
29577
29751
|
}), method(object({
|
|
29578
29752
|
/** Inline {@link VehicleSchema.coverBase64} on every row. Default
|
|
29579
29753
|
* `false` — the vehicle twin of `faceGallery.listIdentities`'s
|
|
29580
|
-
* option; `
|
|
29754
|
+
* option; `coverMediaId` + the `event-media` plane carry the picture.
|
|
29581
29755
|
* INPUT field: stripped by the hub router until the train ships, which
|
|
29582
29756
|
* resolves to `false` and is exactly the intended default. */
|
|
29583
29757
|
includeCrops: boolean().optional() }).optional(), array(VehicleSchema).readonly()), method(object({ name: string().min(1) }), VehicleSchema, {
|
|
@@ -31146,7 +31320,14 @@ var SceneReferenceSchema = object({
|
|
|
31146
31320
|
modelId: string(),
|
|
31147
31321
|
condition: SceneConditionSchema,
|
|
31148
31322
|
capturedAt: number(),
|
|
31149
|
-
|
|
31323
|
+
/**
|
|
31324
|
+
* The reference thumbnail's media ROW id (D482).
|
|
31325
|
+
*
|
|
31326
|
+
* The name already said `mediaId` while the value was the row's composite
|
|
31327
|
+
* key — a leftover that read as done and was not. It is the row's own id
|
|
31328
|
+
* now, addressed at `/addon/<addonId>/event-media/m/<id>`.
|
|
31329
|
+
*/
|
|
31330
|
+
thumbnailMediaId: number().int().optional(),
|
|
31150
31331
|
/** Whole-frame (downscaled) embedding captured alongside the ROI crop. The
|
|
31151
31332
|
* anti-view-shift anchor: a bumped camera, a PTZ preset or a re-aim makes the
|
|
31152
31333
|
* normalized rect frame a different piece of world, and the scene would
|
|
@@ -32237,7 +32418,29 @@ var LoggingSettingsPatchSchema = object({
|
|
|
32237
32418
|
* disarmed the channels it did not mention would make the Levels page and
|
|
32238
32419
|
* the Diagnostics page fight over the same value.
|
|
32239
32420
|
*/
|
|
32240
|
-
channels: array(LogChannelWindowPatchSchema).readonly().optional()
|
|
32421
|
+
channels: array(LogChannelWindowPatchSchema).readonly().optional(),
|
|
32422
|
+
/**
|
|
32423
|
+
* How many days the analytics OPS LOG is kept — the audit trail of what
|
|
32424
|
+
* retention actually deleted.
|
|
32425
|
+
*
|
|
32426
|
+
* It lives HERE, on the logging document, and not on the analytics addon's
|
|
32427
|
+
* settings form, on the operator's instruction: every other log-ish window in
|
|
32428
|
+
* this system is configured through this one document, and a retention audit
|
|
32429
|
+
* configured somewhere else is a second place to look when the question is
|
|
32430
|
+
* "what happened to my data".
|
|
32431
|
+
*
|
|
32432
|
+
* That placement has a cost worth stating: this document ships in the
|
|
32433
|
+
* framework closure, so this knob needs a published `@camstack/server` while
|
|
32434
|
+
* the four windows beside it (D485) reach a node on `camstack deploy`.
|
|
32435
|
+
*
|
|
32436
|
+
* `retention-model.ts` argued this one must NOT follow a device window,
|
|
32437
|
+
* because the audit trail is the history of the SWEEP and not of the camera.
|
|
32438
|
+
* That argument stands and is untouched — what changes is that 30 days stops
|
|
32439
|
+
* being a constant nobody can reach. `0` keeps it forever. The floor is 1 day
|
|
32440
|
+
* rather than 0-as-delete: an audit log truncated to nothing is precisely the
|
|
32441
|
+
* state in which the next 9.5 GiB leak cannot be explained.
|
|
32442
|
+
*/
|
|
32443
|
+
opsLogRetentionDays: number().int().min(0).max(3650).optional()
|
|
32241
32444
|
});
|
|
32242
32445
|
/**
|
|
32243
32446
|
* Which LAYER of the hierarchy is addressed. Absent = the cluster layer.
|
|
@@ -32310,6 +32513,14 @@ var LoggingSettingsStateSchema = object({
|
|
|
32310
32513
|
channels: array(LogChannelDescriptorSchema).readonly(),
|
|
32311
32514
|
/** The channels ARMED right now, each with its deadline. */
|
|
32312
32515
|
activeChannels: array(LogChannelWindowStateSchema).readonly(),
|
|
32516
|
+
/**
|
|
32517
|
+
* The ops-log window in days, as it is in force. `0` = kept forever.
|
|
32518
|
+
*
|
|
32519
|
+
* Reported rather than left to the caller's memory of what it wrote: this is
|
|
32520
|
+
* the value the analytics sweep will actually use, and an operator asking how
|
|
32521
|
+
* long their audit trail lives should not have to infer it from a default.
|
|
32522
|
+
*/
|
|
32523
|
+
opsLogRetentionDays: number().int().min(0),
|
|
32313
32524
|
persisted: boolean()
|
|
32314
32525
|
});
|
|
32315
32526
|
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(), {
|
|
@@ -33130,7 +33341,7 @@ var StationaryObjectSchema = object({
|
|
|
33130
33341
|
/** Enrichment label carried from the source track (identity / plate). */
|
|
33131
33342
|
label: string().optional(),
|
|
33132
33343
|
/** Native-resolution key-frame media key for the parked object's best image. */
|
|
33133
|
-
|
|
33344
|
+
keyFrameMediaId: number().int().optional()
|
|
33134
33345
|
});
|
|
33135
33346
|
var CameraOccupancySnapshotSchema = object({
|
|
33136
33347
|
/** Frame timestamp of the inference result that produced this snapshot. */
|
|
@@ -35868,6 +36079,12 @@ Object.freeze({
|
|
|
35868
36079
|
addonId: null,
|
|
35869
36080
|
access: "create"
|
|
35870
36081
|
},
|
|
36082
|
+
"dataStoreProvider.upsert": {
|
|
36083
|
+
capName: "data-store-provider",
|
|
36084
|
+
capScope: "system",
|
|
36085
|
+
addonId: null,
|
|
36086
|
+
access: "create"
|
|
36087
|
+
},
|
|
35871
36088
|
"dayNight.getOptions": {
|
|
35872
36089
|
capName: "day-night",
|
|
35873
36090
|
capScope: "device",
|
|
@@ -38304,6 +38521,12 @@ Object.freeze({
|
|
|
38304
38521
|
addonId: null,
|
|
38305
38522
|
access: "view"
|
|
38306
38523
|
},
|
|
38524
|
+
"pipelineAnalytics.listRecentSummaries": {
|
|
38525
|
+
capName: "pipeline-analytics",
|
|
38526
|
+
capScope: "device",
|
|
38527
|
+
addonId: null,
|
|
38528
|
+
access: "view"
|
|
38529
|
+
},
|
|
38307
38530
|
"pipelineAnalytics.listRecentTracks": {
|
|
38308
38531
|
capName: "pipeline-analytics",
|
|
38309
38532
|
capScope: "device",
|
|
@@ -39732,6 +39955,12 @@ Object.freeze({
|
|
|
39732
39955
|
addonId: null,
|
|
39733
39956
|
access: "create"
|
|
39734
39957
|
},
|
|
39958
|
+
"settingsStore.upsert": {
|
|
39959
|
+
capName: "settings-store",
|
|
39960
|
+
capScope: "system",
|
|
39961
|
+
addonId: null,
|
|
39962
|
+
access: "create"
|
|
39963
|
+
},
|
|
39735
39964
|
"smtpProvider.getStatus": {
|
|
39736
39965
|
capName: "smtp-provider",
|
|
39737
39966
|
capScope: "system",
|
|
@@ -42125,6 +42354,11 @@ Object.freeze({
|
|
|
42125
42354
|
form: "single",
|
|
42126
42355
|
optional: true
|
|
42127
42356
|
}],
|
|
42357
|
+
"pipelineAnalytics.listRecentSummaries": [{
|
|
42358
|
+
name: "deviceIds",
|
|
42359
|
+
form: "array",
|
|
42360
|
+
optional: false
|
|
42361
|
+
}],
|
|
42128
42362
|
"pipelineAnalytics.listRecentTracks": [{
|
|
42129
42363
|
name: "deviceIds",
|
|
42130
42364
|
form: "array",
|
package/dist/addon.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createSocket } from "dgram";
|
|
2
2
|
import { createCipheriv, createDecipheriv } from "crypto";
|
|
3
3
|
import { EventEmitter } from "events";
|
|
4
|
-
//#region ../types/dist/event-category-
|
|
4
|
+
//#region ../types/dist/event-category-ZyX6jcse.mjs
|
|
5
5
|
var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
6
6
|
EventCategory["SystemBoot"] = "system.boot";
|
|
7
7
|
EventCategory["SystemAddonsReady"] = "system.addons-ready";
|
|
@@ -562,7 +562,7 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
|
562
562
|
* a package zone — a newly-appeared stationary object of a package class
|
|
563
563
|
* that cleared the class / zone / dwell / size gates. Payload:
|
|
564
564
|
* `PipelineAnalyticsPackageDeliveredPayload` carrying `{ deviceId,
|
|
565
|
-
* entryId, className, zoneIds,
|
|
565
|
+
* entryId, className, zoneIds, keyFrameMediaId?, bbox, timestamp }`.
|
|
566
566
|
* Telemetry (D8): the durable record is the `package-events` store row;
|
|
567
567
|
* this bus topic drives notifier rules + live UI. See
|
|
568
568
|
* docs/superpowers/specs/2026-07-17-package-zones-design.md §5.1.
|
|
@@ -5348,7 +5348,7 @@ var ZodIssueCode = {
|
|
|
5348
5348
|
var ZodFirstPartyTypeKind;
|
|
5349
5349
|
ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
|
|
5350
5350
|
//#endregion
|
|
5351
|
-
//#region ../types/dist/sleep-
|
|
5351
|
+
//#region ../types/dist/sleep-DBKu2-U5.mjs
|
|
5352
5352
|
/**
|
|
5353
5353
|
* The audio chunk plane's byte format, and the ONE expansion from a coded
|
|
5354
5354
|
* window to float samples (D455).
|
|
@@ -7315,13 +7315,30 @@ new Set([
|
|
|
7315
7315
|
"scene",
|
|
7316
7316
|
"motion",
|
|
7317
7317
|
"object",
|
|
7318
|
-
"audio"
|
|
7318
|
+
"audio",
|
|
7319
|
+
"mosaic"
|
|
7319
7320
|
]);
|
|
7320
|
-
|
|
7321
|
+
/**
|
|
7322
|
+
* The owner types that are event tables, in the order the event-media resolver
|
|
7323
|
+
* should consider them. Exported so a consumer asking "is this key an event?"
|
|
7324
|
+
* does not re-spell the list and drift from it.
|
|
7325
|
+
*/
|
|
7326
|
+
var EVENT_OWNER_TYPES = [
|
|
7321
7327
|
"motion",
|
|
7322
7328
|
"object",
|
|
7323
7329
|
"audio"
|
|
7324
|
-
]
|
|
7330
|
+
];
|
|
7331
|
+
/**
|
|
7332
|
+
* The same list as a Zod enum, for the cap inputs that must NAME the table
|
|
7333
|
+
* (D482: `getEventMedia` / `listEventMedia` take an owner, and an owner is
|
|
7334
|
+
* `(table, id)`).
|
|
7335
|
+
*
|
|
7336
|
+
* Built FROM {@link EVENT_OWNER_TYPES} rather than re-spelled: a fourth event
|
|
7337
|
+
* table would otherwise be accepted by the codec and refused at the door, with
|
|
7338
|
+
* nothing failing until a caller asked.
|
|
7339
|
+
*/
|
|
7340
|
+
var EventOwnerTypeSchema = _enum(EVENT_OWNER_TYPES);
|
|
7341
|
+
new Set(EVENT_OWNER_TYPES);
|
|
7325
7342
|
var EncodeProfileSchema = object({
|
|
7326
7343
|
video: object({
|
|
7327
7344
|
codec: _enum([
|
|
@@ -7360,7 +7377,23 @@ var EncodeProfileSchema = object({
|
|
|
7360
7377
|
"zerolatency",
|
|
7361
7378
|
"film",
|
|
7362
7379
|
"animation"
|
|
7363
|
-
]).optional()
|
|
7380
|
+
]).optional(),
|
|
7381
|
+
/**
|
|
7382
|
+
* ONE slice per access unit.
|
|
7383
|
+
*
|
|
7384
|
+
* `-tune zerolatency` turns on x264's sliced threads, and a frame then leaves
|
|
7385
|
+
* the encoder as five NAL slices that share one RTP timestamp and carry one
|
|
7386
|
+
* marker bit. A libwebrtc depacketiser sees five frame-starts and one
|
|
7387
|
+
* frame-end per frame: the first pictures render and the video then freezes
|
|
7388
|
+
* for good while the audio, on its own plane, plays on. Measured on this hub
|
|
7389
|
+
* 2026-09-13 against the Echo, and reduced to one slice by this flag alone.
|
|
7390
|
+
*
|
|
7391
|
+
* A NAMED field and not a raw flag, because {@link EgressEncodeSchema} omits
|
|
7392
|
+
* `outputArgs` on purpose: an opaque array is part of the sharing key, so two
|
|
7393
|
+
* consumers meaning the same thing spelled differently would stop sharing one
|
|
7394
|
+
* child. Absent means "whatever the encoder does" — today's behaviour.
|
|
7395
|
+
*/
|
|
7396
|
+
singleSlicePerFrame: boolean().optional()
|
|
7364
7397
|
}),
|
|
7365
7398
|
audio: union([literal("passthrough"), object({
|
|
7366
7399
|
codec: _enum([
|
|
@@ -7410,7 +7443,7 @@ var BASE_LIVE_EGRESS_PROFILE = {
|
|
|
7410
7443
|
audio: "passthrough"
|
|
7411
7444
|
};
|
|
7412
7445
|
({ ...BASE_LIVE_EGRESS_PROFILE }), { ...BASE_LIVE_EGRESS_PROFILE.video };
|
|
7413
|
-
({ ...BASE_LIVE_EGRESS_PROFILE });
|
|
7446
|
+
({ ...BASE_LIVE_EGRESS_PROFILE }), { ...BASE_LIVE_EGRESS_PROFILE.video };
|
|
7414
7447
|
/**
|
|
7415
7448
|
* Deep wiring healthcheck — snapshot of active reachability probes across
|
|
7416
7449
|
* every declared capability + widget of every installed plugin, on every
|
|
@@ -12520,6 +12553,16 @@ method(object({
|
|
|
12520
12553
|
filter: QueryFilterSchema.optional(),
|
|
12521
12554
|
columns: array(string()).readonly().optional()
|
|
12522
12555
|
}), array(SettingsRecordSchema).readonly()), method(object({
|
|
12556
|
+
namespace: string().optional(),
|
|
12557
|
+
collection: string(),
|
|
12558
|
+
/** Declared columns identifying the slot; must be covered by a UNIQUE
|
|
12559
|
+
* index on the collection. Never empty. */
|
|
12560
|
+
conflict: array(string()).readonly(),
|
|
12561
|
+
record: BulkRecordSchema
|
|
12562
|
+
}), object({
|
|
12563
|
+
/** The id the row HAS: assigned by SQLite on an insert, or the existing
|
|
12564
|
+
* row's own id on an update. */
|
|
12565
|
+
id: union([string(), number()]) }), { kind: "mutation" }), method(object({
|
|
12523
12566
|
namespace: string().optional(),
|
|
12524
12567
|
collection: string(),
|
|
12525
12568
|
record: object({
|
|
@@ -12654,6 +12697,14 @@ method(_void(), EngineInfoSchema, { auth: "admin" }), method(object({
|
|
|
12654
12697
|
id: union([string(), number()]) }), {
|
|
12655
12698
|
kind: "mutation",
|
|
12656
12699
|
auth: "admin"
|
|
12700
|
+
}), method(object({
|
|
12701
|
+
namespace: string().optional(),
|
|
12702
|
+
collection: string(),
|
|
12703
|
+
conflict: array(string()).readonly(),
|
|
12704
|
+
record: BulkRecordSchema
|
|
12705
|
+
}), object({ id: union([string(), number()]) }), {
|
|
12706
|
+
kind: "mutation",
|
|
12707
|
+
auth: "admin"
|
|
12657
12708
|
}), method(object({
|
|
12658
12709
|
namespace: string().optional(),
|
|
12659
12710
|
collection: string(),
|
|
@@ -19136,8 +19187,8 @@ var TrackPositionSchema = object({
|
|
|
19136
19187
|
var TrackSnapshotSchema = object({
|
|
19137
19188
|
timestamp: number(),
|
|
19138
19189
|
position: TrackPositionSchema,
|
|
19139
|
-
/**
|
|
19140
|
-
|
|
19190
|
+
/** The snapshot's media row id (D482); resolve via `listTrackMedia({ trackId })`. */
|
|
19191
|
+
mediaId: number().int()
|
|
19141
19192
|
});
|
|
19142
19193
|
/**
|
|
19143
19194
|
* Normalized 0..1 trajectory envelope (min/max over every position bbox,
|
|
@@ -19741,14 +19792,14 @@ var ObjectEventSchema = object({
|
|
|
19741
19792
|
* pixel-space `bbox` onto a displayed image. Omitted in slim projection. */
|
|
19742
19793
|
frameWidth: number().optional(),
|
|
19743
19794
|
frameHeight: number().optional(),
|
|
19744
|
-
/**
|
|
19745
|
-
|
|
19746
|
-
/** Design B:
|
|
19795
|
+
/** Media row id of the crop attached to this event (if any) — D482. */
|
|
19796
|
+
mediaId: number().int().optional(),
|
|
19797
|
+
/** Design B: media row id of the track's native-resolution key frame (the
|
|
19747
19798
|
* best-detection full frame). Resolve via the event-media data-plane
|
|
19748
|
-
* (`/addon/<addonId>/event-media/<
|
|
19799
|
+
* (`/addon/<addonId>/event-media/m/<keyFrameMediaId>`) for a detail view that
|
|
19749
19800
|
* draws `bbox` over the native frame. Absent on legacy rows / non-decoded
|
|
19750
|
-
* sources — consumers fall back to `
|
|
19751
|
-
|
|
19801
|
+
* sources — consumers fall back to `mediaId` (the tight crop). */
|
|
19802
|
+
keyFrameMediaId: number().int().optional(),
|
|
19752
19803
|
/** Populated by B5 (recording playback URL for this event). */
|
|
19753
19804
|
mediaUrl: string().optional(),
|
|
19754
19805
|
/** The parent track's key-event importance [0,1], propagated to every object
|
|
@@ -19798,7 +19849,7 @@ var MediaFileKindEnum = _enum([
|
|
|
19798
19849
|
* hub-main's heap on the way past — for an `<img>` that would have cached it.
|
|
19799
19850
|
*
|
|
19800
19851
|
* `url` points at the `event-media` data plane
|
|
19801
|
-
* (`/addon/<addonId>/event-media/<
|
|
19852
|
+
* (`/addon/<addonId>/event-media/m/<mediaId>` — D482), which serves the same blob
|
|
19802
19853
|
* with an ETag and `Cache-Control: immutable`, honours conditional GETs, can
|
|
19803
19854
|
* render a `?variant=thumb`, and streams. The hub gate in front of it requires
|
|
19804
19855
|
* a bearer or the session cookie (`access: 'authenticated'`), so the bytes are
|
|
@@ -19806,10 +19857,13 @@ var MediaFileKindEnum = _enum([
|
|
|
19806
19857
|
* `data-plane-access.ts` for the rule and the one gap it does not close
|
|
19807
19858
|
* (per-device scoping).
|
|
19808
19859
|
*
|
|
19809
|
-
* The URL is built from the row's
|
|
19810
|
-
*
|
|
19860
|
+
* The URL is built from the row's own id, which since D482 says nothing about
|
|
19861
|
+
* the row's owner or kind — and that is the point. The published `kind` is not
|
|
19862
|
+
* the stored one (a track's face/plate crop is stored as `crop` under
|
|
19811
19863
|
* `('face'|'plate', '<prefix>-<trackId>')` and published as
|
|
19812
|
-
* `faceCrop`/`plateCrop
|
|
19864
|
+
* `faceCrop`/`plateCrop`), and under the old composite key the URL had to be
|
|
19865
|
+
* taken from `row.key` verbatim or it 404'd exactly those two rows. An id
|
|
19866
|
+
* cannot be mis-reconstructed, because there is nothing in it to reconstruct.
|
|
19813
19867
|
*
|
|
19814
19868
|
* ## `base64` is TRANSITIONAL and is going away
|
|
19815
19869
|
*
|
|
@@ -19822,7 +19876,19 @@ var MediaFileKindEnum = _enum([
|
|
|
19822
19876
|
* `analytics-query-facade.ts`; nothing else reads it.
|
|
19823
19877
|
*/
|
|
19824
19878
|
var MediaFileSchema = object({
|
|
19825
|
-
|
|
19879
|
+
/**
|
|
19880
|
+
* The media row's OWN id — the rowid SQLite assigned it (D482).
|
|
19881
|
+
*
|
|
19882
|
+
* It used to be the row's composite key, `<ownerType>:<ownerId>:<fileKind>
|
|
19883
|
+
* [:<timestampMs>]`, which embedded a FOREIGN id. D474 made event ids
|
|
19884
|
+
* per-table rowid aliases, so `object:101314` and `motion:101314` are two
|
|
19885
|
+
* different rows that spell the same number, and a track whose
|
|
19886
|
+
* `bestEventId` was an object event was served a motion event's snapshot —
|
|
19887
|
+
* a night-time thumbnail on an afternoon track, with no error anywhere. A
|
|
19888
|
+
* surrogate id cannot name the wrong row's owner, because it names no owner
|
|
19889
|
+
* at all.
|
|
19890
|
+
*/
|
|
19891
|
+
mediaId: number().int(),
|
|
19826
19892
|
kind: MediaFileKindEnum,
|
|
19827
19893
|
sizeBytes: number(),
|
|
19828
19894
|
timestamp: number()
|
|
@@ -19930,7 +19996,7 @@ var RetrainTrackSchema = object({
|
|
|
19930
19996
|
});
|
|
19931
19997
|
/** A frame the picker may offer — an index row, no blob was read to produce it. */
|
|
19932
19998
|
var RetrainFrameCandidateSchema = object({
|
|
19933
|
-
|
|
19999
|
+
mediaId: number().int(),
|
|
19934
20000
|
kind: MediaFileKindEnum,
|
|
19935
20001
|
timestamp: number(),
|
|
19936
20002
|
sizeBytes: number().int(),
|
|
@@ -19944,7 +20010,7 @@ var RetrainFrameSchema = object({
|
|
|
19944
20010
|
deviceId: number(),
|
|
19945
20011
|
trackId: string(),
|
|
19946
20012
|
/** Provenance only. It may already point at nothing — that is expected. */
|
|
19947
|
-
|
|
20013
|
+
sourceMediaId: number().int(),
|
|
19948
20014
|
sourceKind: MediaFileKindEnum,
|
|
19949
20015
|
sizeBytes: number().int(),
|
|
19950
20016
|
width: number().int(),
|
|
@@ -19960,7 +20026,7 @@ var RetrainCopyRefusalSchema = _enum([
|
|
|
19960
20026
|
var RetrainFrameSelectionSchema = object({
|
|
19961
20027
|
copied: array(RetrainFrameSchema).readonly(),
|
|
19962
20028
|
refused: array(object({
|
|
19963
|
-
|
|
20029
|
+
sourceMediaId: number().int(),
|
|
19964
20030
|
reason: RetrainCopyRefusalSchema
|
|
19965
20031
|
})).readonly()
|
|
19966
20032
|
});
|
|
@@ -19968,7 +20034,7 @@ var RetrainFrameListSchema = object({
|
|
|
19968
20034
|
candidates: array(RetrainFrameCandidateSchema).readonly(),
|
|
19969
20035
|
copies: array(RetrainFrameSchema).readonly(),
|
|
19970
20036
|
/** What the page pre-selects — the native key frame when one survives. */
|
|
19971
|
-
|
|
20037
|
+
autoPickMediaId: number().int().optional()
|
|
19972
20038
|
});
|
|
19973
20039
|
/** What the operator asked the assist to look for. */
|
|
19974
20040
|
var RetrainAssistSubjectSchema = discriminatedUnion("kind", [object({
|
|
@@ -20063,9 +20129,11 @@ var RecentTracksQueryInput = object({
|
|
|
20063
20129
|
});
|
|
20064
20130
|
/**
|
|
20065
20131
|
* A Summary (D359): the per-camera session envelope that references tracks.
|
|
20066
|
-
* `
|
|
20067
|
-
* served by the event-media plane
|
|
20068
|
-
* member visible has been materialised
|
|
20132
|
+
* `groupShotMediaId` is the media ROW id of its group shot (`ownerKind:
|
|
20133
|
+
* 'summary'`, served by the event-media plane at `/m/<id>`), null until the
|
|
20134
|
+
* first frame with a member visible has been materialised (D482 — it was the
|
|
20135
|
+
* row's composite key, which embedded the owner and could name another table's
|
|
20136
|
+
* row once event ids became per-table rowids).
|
|
20069
20137
|
*/
|
|
20070
20138
|
var SummarySchema = object({
|
|
20071
20139
|
id: string(),
|
|
@@ -20074,19 +20142,115 @@ var SummarySchema = object({
|
|
|
20074
20142
|
lastActiveAt: number(),
|
|
20075
20143
|
sealedAt: number().nullable(),
|
|
20076
20144
|
memberCount: number().int().nonnegative(),
|
|
20077
|
-
|
|
20145
|
+
groupShotMediaId: number().int().nullable()
|
|
20078
20146
|
});
|
|
20079
20147
|
var SummariesQueryInput = object({
|
|
20080
20148
|
deviceIds: array(number()).min(1),
|
|
20081
20149
|
since: number().optional(),
|
|
20082
20150
|
until: number().optional(),
|
|
20083
|
-
limit: number().int().min(1).max(200).default(50)
|
|
20151
|
+
limit: number().int().min(1).max(200).default(50),
|
|
20152
|
+
/** The same member-wise filter {@link listRecentSummaries} takes — one
|
|
20153
|
+
* meaning of "dog" on every summary surface. */
|
|
20154
|
+
classes: array(string().min(1).max(60)).max(40).optional()
|
|
20084
20155
|
});
|
|
20085
|
-
var SummariesPageSchema = object({ summaries: array(SummarySchema).readonly() });
|
|
20086
20156
|
var SummaryDetailSchema = object({
|
|
20087
20157
|
summary: SummarySchema,
|
|
20088
|
-
/**
|
|
20089
|
-
|
|
20158
|
+
/** Members in absorption order, oldest join first. */
|
|
20159
|
+
members: array(object({
|
|
20160
|
+
trackId: string(),
|
|
20161
|
+
/**
|
|
20162
|
+
* The track's class at the time it JOINED, or `null` when it was unresolved
|
|
20163
|
+
* and the track no longer exists to fill it.
|
|
20164
|
+
*
|
|
20165
|
+
* The join, not the latest opinion: class voting can re-decide a track's
|
|
20166
|
+
* class afterwards, and a group's composition is the history of who came
|
|
20167
|
+
* together. A consumer counts these to badge a thumbnail — "two people and a
|
|
20168
|
+
* dog" — rather than being handed a second, denormalised tally that would
|
|
20169
|
+
* drift from the members it claims to describe.
|
|
20170
|
+
*/
|
|
20171
|
+
className: string().nullable(),
|
|
20172
|
+
/** `primary` is the one member that carries the group's identity. */
|
|
20173
|
+
role: _enum([
|
|
20174
|
+
"primary",
|
|
20175
|
+
"sibling",
|
|
20176
|
+
"child"
|
|
20177
|
+
]).nullable(),
|
|
20178
|
+
joinedAt: number(),
|
|
20179
|
+
/** Tier 1 — the sub-class (`dog`, `van`), resolved from the member's track
|
|
20180
|
+
* at read time. Absent when nothing resolved, never an empty string. */
|
|
20181
|
+
label: string().optional(),
|
|
20182
|
+
/** Tier 2 — the instance: a person's name, a plate. Absent when the pipeline
|
|
20183
|
+
* recognised nobody, and absent for a member whose track has been pruned —
|
|
20184
|
+
* a thumbnail that names the wrong person is worse than one naming nobody. */
|
|
20185
|
+
subLabel: string().optional()
|
|
20186
|
+
})).readonly()
|
|
20187
|
+
});
|
|
20188
|
+
/**
|
|
20189
|
+
* What a LIST of groups carries: the envelope plus what it is MADE OF.
|
|
20190
|
+
*
|
|
20191
|
+
* Coarse on purpose — the operator's rule is "only the rough data on the list,
|
|
20192
|
+
* we extend when we notice we need more". Enough to draw the card ("two people
|
|
20193
|
+
* and a dog") and no more. The MEMBERS, their names and the per-member links
|
|
20194
|
+
* are on {@link getSummary}: shipping every member of every group so a client
|
|
20195
|
+
* can count them turns a page of two hundred groups into a thousand records to
|
|
20196
|
+
* draw two hundred badges.
|
|
20197
|
+
*/
|
|
20198
|
+
var SummaryListItemSchema = object({
|
|
20199
|
+
summary: SummarySchema,
|
|
20200
|
+
/** Class counts, most numerous first; `className: null` is a member whose
|
|
20201
|
+
* class never resolved, counted so the counts add up to `memberCount`. */
|
|
20202
|
+
classes: array(object({
|
|
20203
|
+
className: string().nullable(),
|
|
20204
|
+
count: number().int().positive()
|
|
20205
|
+
})).readonly()
|
|
20206
|
+
});
|
|
20207
|
+
var SummariesPageSchema = object({ summaries: array(SummaryListItemSchema).readonly() });
|
|
20208
|
+
/**
|
|
20209
|
+
* The paged feed, deliberately the SAME shape as {@link RecentTracksQueryInput}.
|
|
20210
|
+
*
|
|
20211
|
+
* The reel on the cameras page and the Events gallery both ride a cursor, so a
|
|
20212
|
+
* summaries feed that could only answer "the last N for these cameras"
|
|
20213
|
+
* (`listSummaries`) would make groups available in the timeline and nowhere
|
|
20214
|
+
* else. Two feeds with different ordering contracts would be two ideas of what
|
|
20215
|
+
* "newest" means, on one screen.
|
|
20216
|
+
*/
|
|
20217
|
+
var RecentSummariesQueryInput = object({
|
|
20218
|
+
/** Devices to merge. An empty array yields an empty page. */
|
|
20219
|
+
deviceIds: array(number()),
|
|
20220
|
+
/** Window lower bound on `lastActiveAt` (inclusive). */
|
|
20221
|
+
since: number().optional(),
|
|
20222
|
+
/** Window upper bound on `lastActiveAt` (inclusive). */
|
|
20223
|
+
until: number().optional(),
|
|
20224
|
+
limit: number().int().min(1).max(500).default(100),
|
|
20225
|
+
/** Opaque continuation cursor from a previous page's `nextCursor`. */
|
|
20226
|
+
cursor: string().optional(),
|
|
20227
|
+
/**
|
|
20228
|
+
* Restrict to these classes — THE SAME FIELD `listRecentTracks` takes, and
|
|
20229
|
+
* deliberately the same name: the events filter tree emits one list of ticked
|
|
20230
|
+
* taxonomy nodes, and a summaries feed that called it something else would
|
|
20231
|
+
* make the operator's one filter component produce two shapes.
|
|
20232
|
+
*
|
|
20233
|
+
* A question about the MEMBERS: a group matches when ANY of them does. "Show
|
|
20234
|
+
* me the arrivals with a dog" has to return the group of four people who had
|
|
20235
|
+
* one with them; a filter on the group's own fields could only ever answer
|
|
20236
|
+
* about its primary.
|
|
20237
|
+
*
|
|
20238
|
+
* Matched against all THREE tiers of a member — the class (`animal`), the
|
|
20239
|
+
* sub-class (`dog`) and the instance (a name, a plate) — because which tier a
|
|
20240
|
+
* ticked node lives on is the taxonomy's business, not the caller's. `dog` is
|
|
20241
|
+
* an event kind in the tree and a tier-1 label on an `animal` track; a filter
|
|
20242
|
+
* that read only the class would answer "animal" and never "dog".
|
|
20243
|
+
*
|
|
20244
|
+
* ABSENT or EMPTY means no filter — absent is not a selection of none.
|
|
20245
|
+
*/
|
|
20246
|
+
classes: array(string().min(1).max(60)).max(40).optional()
|
|
20247
|
+
});
|
|
20248
|
+
var RecentSummariesPageSchema = object({
|
|
20249
|
+
/** Ordered by (`lastActiveAt` DESC, id DESC). Same light item as
|
|
20250
|
+
* {@link listSummaries} — one list shape, so a card renders the same
|
|
20251
|
+
* whichever feed drew it. */
|
|
20252
|
+
summaries: array(SummaryListItemSchema).readonly(),
|
|
20253
|
+
nextCursor: string().nullable()
|
|
20090
20254
|
});
|
|
20091
20255
|
var RecentTracksPageSchema = object({
|
|
20092
20256
|
/** Merged page, ordered by (`lastSeen` DESC, `trackId` DESC). */
|
|
@@ -20500,7 +20664,7 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
|
|
|
20500
20664
|
classes: array(string()).optional(),
|
|
20501
20665
|
/** See {@link ExcludeSourcesDoc}. */
|
|
20502
20666
|
excludeSources: array(TrackSourceSchema).optional()
|
|
20503
|
-
}), array(TrackSchema).readonly()), method(RecentTracksQueryInput, RecentTracksPageSchema), method(SummariesQueryInput, SummariesPageSchema), method(object({ id: string() }), SummaryDetailSchema.nullable()), method(object({ deviceId: number() }), _void(), {
|
|
20667
|
+
}), array(TrackSchema).readonly()), method(RecentTracksQueryInput, RecentTracksPageSchema), method(SummariesQueryInput, SummariesPageSchema), method(RecentSummariesQueryInput, RecentSummariesPageSchema), method(object({ id: string() }), SummaryDetailSchema.nullable()), method(object({ deviceId: number() }), _void(), {
|
|
20504
20668
|
kind: "mutation",
|
|
20505
20669
|
auth: "admin"
|
|
20506
20670
|
}), method(DeviceEventQueryInput, array(MotionEventSchema).readonly()), method(ObjectEventQueryInput, array(ObjectEventSchema).readonly()), method(DeviceEventQueryInput, array(AudioEventSchema).readonly()), method(object({ deviceId: number() }), array(EventKindDescriptorSchema).readonly()), method(object({ deviceIds: array(number()).min(1).max(200) }), array(EventKindsForDeviceSchema).readonly()), method(object({
|
|
@@ -20628,7 +20792,7 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
|
|
|
20628
20792
|
}), method(object({
|
|
20629
20793
|
deviceId: number(),
|
|
20630
20794
|
trackId: string(),
|
|
20631
|
-
|
|
20795
|
+
mediaIds: array(number().int()).min(1)
|
|
20632
20796
|
}), RetrainFrameSelectionSchema, {
|
|
20633
20797
|
kind: "mutation",
|
|
20634
20798
|
auth: "admin"
|
|
@@ -20696,7 +20860,10 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
|
|
|
20696
20860
|
kind: "query",
|
|
20697
20861
|
auth: "admin"
|
|
20698
20862
|
}), method(object({
|
|
20699
|
-
|
|
20863
|
+
/** Which of the three event tables owns the row. */
|
|
20864
|
+
ownerType: EventOwnerTypeSchema,
|
|
20865
|
+
/** The event's rowid in that table (D474: an event id is a number). */
|
|
20866
|
+
eventId: number().int(),
|
|
20700
20867
|
kind: MediaFileKindEnum.optional(),
|
|
20701
20868
|
deviceId: number()
|
|
20702
20869
|
}), array(MediaFileSchema).readonly()), method(object({
|
|
@@ -20707,7 +20874,8 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
|
|
|
20707
20874
|
trackId: string(),
|
|
20708
20875
|
deviceId: number()
|
|
20709
20876
|
}), array(MediaFileInfoSchema).readonly()), method(object({
|
|
20710
|
-
|
|
20877
|
+
ownerType: EventOwnerTypeSchema,
|
|
20878
|
+
eventId: number().int(),
|
|
20711
20879
|
deviceId: number()
|
|
20712
20880
|
}), array(MediaFileInfoSchema).readonly()), method(SearchObjectEventsInput, array(ScoredObjectEventSchema).readonly()), method(object({}), WipeObjectEmbeddingsResultSchema, {
|
|
20713
20881
|
kind: "mutation",
|
|
@@ -25900,8 +26068,8 @@ var IdentitySchema = object({
|
|
|
25900
26068
|
id: string(),
|
|
25901
26069
|
name: string(),
|
|
25902
26070
|
sampleCount: number().int().nonnegative(),
|
|
25903
|
-
|
|
25904
|
-
/** Inline base64 of the cover sample's crop, resolved from `
|
|
26071
|
+
coverMediaId: number().int().optional(),
|
|
26072
|
+
/** Inline base64 of the cover sample's crop, resolved from `coverMediaId`.
|
|
25905
26073
|
* Lets the UI render the person's face avatar instead of a placeholder icon. */
|
|
25906
26074
|
coverBase64: string().optional()
|
|
25907
26075
|
});
|
|
@@ -25927,8 +26095,8 @@ var IdentitySampleAuditRowSchema = object({
|
|
|
25927
26095
|
enrolledAt: number().int(),
|
|
25928
26096
|
deviceId: number().int().optional(),
|
|
25929
26097
|
source: _enum(["detected", "photo"]),
|
|
25930
|
-
/** The enrolled crop's media
|
|
25931
|
-
|
|
26098
|
+
/** The enrolled crop's media row id, so the panel can show the evidence. */
|
|
26099
|
+
mediaId: number().int().optional(),
|
|
25932
26100
|
/**
|
|
25933
26101
|
* False = the sample is stamped with a DIFFERENT face model, and a cosine
|
|
25934
26102
|
* across feature spaces is a well-formed float with no meaning. Every number
|
|
@@ -25997,15 +26165,15 @@ var FaceInfoSchema = object({
|
|
|
25997
26165
|
*/
|
|
25998
26166
|
cropUrl: string().optional(),
|
|
25999
26167
|
/** Design B: the face bbox (pixel space) on the key frame — lets a detail
|
|
26000
|
-
* view draw the box over the native `
|
|
26168
|
+
* view draw the box over the native `keyFrameMediaId` frame. Absent on
|
|
26001
26169
|
* legacy rows written before design B. */
|
|
26002
26170
|
faceBbox: BoundingBoxSchema.optional(),
|
|
26003
26171
|
/** Design B: MediaStore key of the track's native-resolution key frame.
|
|
26004
26172
|
* Fetch the native JPEG via the event-media data-plane
|
|
26005
|
-
* (`/addon/<addonId>/event-media/<
|
|
26173
|
+
* (`/addon/<addonId>/event-media/m/<keyFrameMediaId>`). Absent when the
|
|
26006
26174
|
* track produced no key frame (e.g. native/onboard source) — the UI falls
|
|
26007
26175
|
* back to the inline `base64` face crop. */
|
|
26008
|
-
|
|
26176
|
+
keyFrameMediaId: number().int().optional(),
|
|
26009
26177
|
/** Winning identity-match cosine (0..1) for this face's track, when an
|
|
26010
26178
|
* identity was auto-confirmed. Lets the UI surface WHY a face was assigned
|
|
26011
26179
|
* (confidence badge / low-confidence audit). Absent on legacy rows and on
|
|
@@ -26074,11 +26242,14 @@ var FaceClusterSchema = object({
|
|
|
26074
26242
|
* `data:image/jpeg;base64,…` from a row whose `key` sat right beside it, in a
|
|
26075
26243
|
* dialog already rendering its key FRAME from the `event-media` plane.
|
|
26076
26244
|
*
|
|
26077
|
-
* `url` is `/addon/<addonId>/event-media/<
|
|
26078
|
-
* media
|
|
26245
|
+
* `url` is `/addon/<addonId>/event-media/m/<mediaId>` (D482). The plane
|
|
26246
|
+
* resolves a media row by its own id, so this needed no new plane and no new
|
|
26247
|
+
* access decision.
|
|
26079
26248
|
*/
|
|
26080
26249
|
var MediaFileLiteSchema$1 = object({
|
|
26081
|
-
|
|
26250
|
+
/** The media row's own id — the same address `MediaFileRef.mediaId` carries
|
|
26251
|
+
* (D482). It was the row's composite key, which embedded the owner. */
|
|
26252
|
+
mediaId: number().int(),
|
|
26082
26253
|
kind: string(),
|
|
26083
26254
|
url: string(),
|
|
26084
26255
|
sizeBytes: number(),
|
|
@@ -26095,7 +26266,7 @@ method(object({
|
|
|
26095
26266
|
* covers inline, ~10 KB of base64 per row, on a query this UI mounts
|
|
26096
26267
|
* four times and the viewer holds at `staleTime: 30_000`.
|
|
26097
26268
|
*
|
|
26098
|
-
* Nothing loses its avatar: `
|
|
26269
|
+
* Nothing loses its avatar: `coverMediaId` is already on every row and
|
|
26099
26270
|
* the `event-media` plane serves that key `immutable` with an ETag.
|
|
26100
26271
|
*
|
|
26101
26272
|
* **This is an INPUT field, so it does not reach the addon until the
|
|
@@ -29458,8 +29629,8 @@ var VehicleSchema = object({
|
|
|
29458
29629
|
id: string(),
|
|
29459
29630
|
name: string(),
|
|
29460
29631
|
sampleCount: number().int().nonnegative(),
|
|
29461
|
-
|
|
29462
|
-
/** Inline base64 of the cover sample's plate crop, resolved from `
|
|
29632
|
+
coverMediaId: number().int().optional(),
|
|
29633
|
+
/** Inline base64 of the cover sample's plate crop, resolved from `coverMediaId`. */
|
|
29463
29634
|
coverBase64: string().optional()
|
|
29464
29635
|
});
|
|
29465
29636
|
var VehicleSampleInfoSchema = object({
|
|
@@ -29492,7 +29663,7 @@ var PlateInfoSchema = object({
|
|
|
29492
29663
|
/** keyFrame parity: the plate bbox (pixel space) on the native key frame. */
|
|
29493
29664
|
plateBbox: BoundingBoxSchema.optional(),
|
|
29494
29665
|
/** keyFrame parity: MediaStore key of the track's native-resolution key frame. */
|
|
29495
|
-
|
|
29666
|
+
keyFrameMediaId: number().int().optional(),
|
|
29496
29667
|
base64: string().optional(),
|
|
29497
29668
|
/**
|
|
29498
29669
|
* Same crop as a data-plane URL, always present when the plate has a stored
|
|
@@ -29513,11 +29684,14 @@ var PlateInfoSchema = object({
|
|
|
29513
29684
|
* `data:image/jpeg;base64,…` from a row whose `key` sat right beside it, in a
|
|
29514
29685
|
* dialog already rendering its key FRAME from the `event-media` plane.
|
|
29515
29686
|
*
|
|
29516
|
-
* `url` is `/addon/<addonId>/event-media/<
|
|
29517
|
-
* media
|
|
29687
|
+
* `url` is `/addon/<addonId>/event-media/m/<mediaId>` (D482). The plane
|
|
29688
|
+
* resolves a media row by its own id, so this needed no new plane and no new
|
|
29689
|
+
* access decision.
|
|
29518
29690
|
*/
|
|
29519
29691
|
var MediaFileLiteSchema = object({
|
|
29520
|
-
|
|
29692
|
+
/** The media row's own id — the same address `MediaFileRef.mediaId` carries
|
|
29693
|
+
* (D482). It was the row's composite key, which embedded the owner. */
|
|
29694
|
+
mediaId: number().int(),
|
|
29521
29695
|
kind: string(),
|
|
29522
29696
|
url: string(),
|
|
29523
29697
|
sizeBytes: number(),
|
|
@@ -29576,7 +29750,7 @@ method(object({
|
|
|
29576
29750
|
}), method(object({
|
|
29577
29751
|
/** Inline {@link VehicleSchema.coverBase64} on every row. Default
|
|
29578
29752
|
* `false` — the vehicle twin of `faceGallery.listIdentities`'s
|
|
29579
|
-
* option; `
|
|
29753
|
+
* option; `coverMediaId` + the `event-media` plane carry the picture.
|
|
29580
29754
|
* INPUT field: stripped by the hub router until the train ships, which
|
|
29581
29755
|
* resolves to `false` and is exactly the intended default. */
|
|
29582
29756
|
includeCrops: boolean().optional() }).optional(), array(VehicleSchema).readonly()), method(object({ name: string().min(1) }), VehicleSchema, {
|
|
@@ -31145,7 +31319,14 @@ var SceneReferenceSchema = object({
|
|
|
31145
31319
|
modelId: string(),
|
|
31146
31320
|
condition: SceneConditionSchema,
|
|
31147
31321
|
capturedAt: number(),
|
|
31148
|
-
|
|
31322
|
+
/**
|
|
31323
|
+
* The reference thumbnail's media ROW id (D482).
|
|
31324
|
+
*
|
|
31325
|
+
* The name already said `mediaId` while the value was the row's composite
|
|
31326
|
+
* key — a leftover that read as done and was not. It is the row's own id
|
|
31327
|
+
* now, addressed at `/addon/<addonId>/event-media/m/<id>`.
|
|
31328
|
+
*/
|
|
31329
|
+
thumbnailMediaId: number().int().optional(),
|
|
31149
31330
|
/** Whole-frame (downscaled) embedding captured alongside the ROI crop. The
|
|
31150
31331
|
* anti-view-shift anchor: a bumped camera, a PTZ preset or a re-aim makes the
|
|
31151
31332
|
* normalized rect frame a different piece of world, and the scene would
|
|
@@ -32236,7 +32417,29 @@ var LoggingSettingsPatchSchema = object({
|
|
|
32236
32417
|
* disarmed the channels it did not mention would make the Levels page and
|
|
32237
32418
|
* the Diagnostics page fight over the same value.
|
|
32238
32419
|
*/
|
|
32239
|
-
channels: array(LogChannelWindowPatchSchema).readonly().optional()
|
|
32420
|
+
channels: array(LogChannelWindowPatchSchema).readonly().optional(),
|
|
32421
|
+
/**
|
|
32422
|
+
* How many days the analytics OPS LOG is kept — the audit trail of what
|
|
32423
|
+
* retention actually deleted.
|
|
32424
|
+
*
|
|
32425
|
+
* It lives HERE, on the logging document, and not on the analytics addon's
|
|
32426
|
+
* settings form, on the operator's instruction: every other log-ish window in
|
|
32427
|
+
* this system is configured through this one document, and a retention audit
|
|
32428
|
+
* configured somewhere else is a second place to look when the question is
|
|
32429
|
+
* "what happened to my data".
|
|
32430
|
+
*
|
|
32431
|
+
* That placement has a cost worth stating: this document ships in the
|
|
32432
|
+
* framework closure, so this knob needs a published `@camstack/server` while
|
|
32433
|
+
* the four windows beside it (D485) reach a node on `camstack deploy`.
|
|
32434
|
+
*
|
|
32435
|
+
* `retention-model.ts` argued this one must NOT follow a device window,
|
|
32436
|
+
* because the audit trail is the history of the SWEEP and not of the camera.
|
|
32437
|
+
* That argument stands and is untouched — what changes is that 30 days stops
|
|
32438
|
+
* being a constant nobody can reach. `0` keeps it forever. The floor is 1 day
|
|
32439
|
+
* rather than 0-as-delete: an audit log truncated to nothing is precisely the
|
|
32440
|
+
* state in which the next 9.5 GiB leak cannot be explained.
|
|
32441
|
+
*/
|
|
32442
|
+
opsLogRetentionDays: number().int().min(0).max(3650).optional()
|
|
32240
32443
|
});
|
|
32241
32444
|
/**
|
|
32242
32445
|
* Which LAYER of the hierarchy is addressed. Absent = the cluster layer.
|
|
@@ -32309,6 +32512,14 @@ var LoggingSettingsStateSchema = object({
|
|
|
32309
32512
|
channels: array(LogChannelDescriptorSchema).readonly(),
|
|
32310
32513
|
/** The channels ARMED right now, each with its deadline. */
|
|
32311
32514
|
activeChannels: array(LogChannelWindowStateSchema).readonly(),
|
|
32515
|
+
/**
|
|
32516
|
+
* The ops-log window in days, as it is in force. `0` = kept forever.
|
|
32517
|
+
*
|
|
32518
|
+
* Reported rather than left to the caller's memory of what it wrote: this is
|
|
32519
|
+
* the value the analytics sweep will actually use, and an operator asking how
|
|
32520
|
+
* long their audit trail lives should not have to infer it from a default.
|
|
32521
|
+
*/
|
|
32522
|
+
opsLogRetentionDays: number().int().min(0),
|
|
32312
32523
|
persisted: boolean()
|
|
32313
32524
|
});
|
|
32314
32525
|
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(), {
|
|
@@ -33129,7 +33340,7 @@ var StationaryObjectSchema = object({
|
|
|
33129
33340
|
/** Enrichment label carried from the source track (identity / plate). */
|
|
33130
33341
|
label: string().optional(),
|
|
33131
33342
|
/** Native-resolution key-frame media key for the parked object's best image. */
|
|
33132
|
-
|
|
33343
|
+
keyFrameMediaId: number().int().optional()
|
|
33133
33344
|
});
|
|
33134
33345
|
var CameraOccupancySnapshotSchema = object({
|
|
33135
33346
|
/** Frame timestamp of the inference result that produced this snapshot. */
|
|
@@ -35867,6 +36078,12 @@ Object.freeze({
|
|
|
35867
36078
|
addonId: null,
|
|
35868
36079
|
access: "create"
|
|
35869
36080
|
},
|
|
36081
|
+
"dataStoreProvider.upsert": {
|
|
36082
|
+
capName: "data-store-provider",
|
|
36083
|
+
capScope: "system",
|
|
36084
|
+
addonId: null,
|
|
36085
|
+
access: "create"
|
|
36086
|
+
},
|
|
35870
36087
|
"dayNight.getOptions": {
|
|
35871
36088
|
capName: "day-night",
|
|
35872
36089
|
capScope: "device",
|
|
@@ -38303,6 +38520,12 @@ Object.freeze({
|
|
|
38303
38520
|
addonId: null,
|
|
38304
38521
|
access: "view"
|
|
38305
38522
|
},
|
|
38523
|
+
"pipelineAnalytics.listRecentSummaries": {
|
|
38524
|
+
capName: "pipeline-analytics",
|
|
38525
|
+
capScope: "device",
|
|
38526
|
+
addonId: null,
|
|
38527
|
+
access: "view"
|
|
38528
|
+
},
|
|
38306
38529
|
"pipelineAnalytics.listRecentTracks": {
|
|
38307
38530
|
capName: "pipeline-analytics",
|
|
38308
38531
|
capScope: "device",
|
|
@@ -39731,6 +39954,12 @@ Object.freeze({
|
|
|
39731
39954
|
addonId: null,
|
|
39732
39955
|
access: "create"
|
|
39733
39956
|
},
|
|
39957
|
+
"settingsStore.upsert": {
|
|
39958
|
+
capName: "settings-store",
|
|
39959
|
+
capScope: "system",
|
|
39960
|
+
addonId: null,
|
|
39961
|
+
access: "create"
|
|
39962
|
+
},
|
|
39734
39963
|
"smtpProvider.getStatus": {
|
|
39735
39964
|
capName: "smtp-provider",
|
|
39736
39965
|
capScope: "system",
|
|
@@ -42124,6 +42353,11 @@ Object.freeze({
|
|
|
42124
42353
|
form: "single",
|
|
42125
42354
|
optional: true
|
|
42126
42355
|
}],
|
|
42356
|
+
"pipelineAnalytics.listRecentSummaries": [{
|
|
42357
|
+
name: "deviceIds",
|
|
42358
|
+
form: "array",
|
|
42359
|
+
optional: false
|
|
42360
|
+
}],
|
|
42127
42361
|
"pipelineAnalytics.listRecentTracks": [{
|
|
42128
42362
|
name: "deviceIds",
|
|
42129
42363
|
form: "array",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@camstack/addon-provider-gree",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.100",
|
|
4
4
|
"description": "Gree air-conditioner device-provider addon for CamStack — wraps the @apocaliss92/nodegree local-UDP client (LAN discovery + AES control), exposing climate-control and fan-control",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"camstack",
|