@camstack/addon-provider-reolink 1.2.122 → 1.2.124
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
|
@@ -25,7 +25,7 @@ let fs_promises = require("fs/promises");
|
|
|
25
25
|
fs_promises = require_chunk.__toESM(fs_promises, 1);
|
|
26
26
|
let node_os = require("node:os");
|
|
27
27
|
node_os = require_chunk.__toESM(node_os);
|
|
28
|
-
//#region ../types/dist/event-category-
|
|
28
|
+
//#region ../types/dist/event-category-ZyX6jcse.mjs
|
|
29
29
|
var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
30
30
|
EventCategory["SystemBoot"] = "system.boot";
|
|
31
31
|
EventCategory["SystemAddonsReady"] = "system.addons-ready";
|
|
@@ -586,7 +586,7 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
|
586
586
|
* a package zone — a newly-appeared stationary object of a package class
|
|
587
587
|
* that cleared the class / zone / dwell / size gates. Payload:
|
|
588
588
|
* `PipelineAnalyticsPackageDeliveredPayload` carrying `{ deviceId,
|
|
589
|
-
* entryId, className, zoneIds,
|
|
589
|
+
* entryId, className, zoneIds, keyFrameMediaId?, bbox, timestamp }`.
|
|
590
590
|
* Telemetry (D8): the durable record is the `package-events` store row;
|
|
591
591
|
* this bus topic drives notifier rules + live UI. See
|
|
592
592
|
* docs/superpowers/specs/2026-07-17-package-zones-design.md §5.1.
|
|
@@ -5372,7 +5372,7 @@ var ZodIssueCode = {
|
|
|
5372
5372
|
var ZodFirstPartyTypeKind;
|
|
5373
5373
|
ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
|
|
5374
5374
|
//#endregion
|
|
5375
|
-
//#region ../types/dist/sleep-
|
|
5375
|
+
//#region ../types/dist/sleep-DBKu2-U5.mjs
|
|
5376
5376
|
/**
|
|
5377
5377
|
* The audio chunk plane's byte format, and the ONE expansion from a coded
|
|
5378
5378
|
* window to float samples (D455).
|
|
@@ -7351,13 +7351,30 @@ new Set([
|
|
|
7351
7351
|
"scene",
|
|
7352
7352
|
"motion",
|
|
7353
7353
|
"object",
|
|
7354
|
-
"audio"
|
|
7354
|
+
"audio",
|
|
7355
|
+
"mosaic"
|
|
7355
7356
|
]);
|
|
7356
|
-
|
|
7357
|
+
/**
|
|
7358
|
+
* The owner types that are event tables, in the order the event-media resolver
|
|
7359
|
+
* should consider them. Exported so a consumer asking "is this key an event?"
|
|
7360
|
+
* does not re-spell the list and drift from it.
|
|
7361
|
+
*/
|
|
7362
|
+
var EVENT_OWNER_TYPES = [
|
|
7357
7363
|
"motion",
|
|
7358
7364
|
"object",
|
|
7359
7365
|
"audio"
|
|
7360
|
-
]
|
|
7366
|
+
];
|
|
7367
|
+
/**
|
|
7368
|
+
* The same list as a Zod enum, for the cap inputs that must NAME the table
|
|
7369
|
+
* (D482: `getEventMedia` / `listEventMedia` take an owner, and an owner is
|
|
7370
|
+
* `(table, id)`).
|
|
7371
|
+
*
|
|
7372
|
+
* Built FROM {@link EVENT_OWNER_TYPES} rather than re-spelled: a fourth event
|
|
7373
|
+
* table would otherwise be accepted by the codec and refused at the door, with
|
|
7374
|
+
* nothing failing until a caller asked.
|
|
7375
|
+
*/
|
|
7376
|
+
var EventOwnerTypeSchema = _enum(EVENT_OWNER_TYPES);
|
|
7377
|
+
new Set(EVENT_OWNER_TYPES);
|
|
7361
7378
|
var EncodeProfileSchema = object({
|
|
7362
7379
|
video: object({
|
|
7363
7380
|
codec: _enum([
|
|
@@ -7396,7 +7413,23 @@ var EncodeProfileSchema = object({
|
|
|
7396
7413
|
"zerolatency",
|
|
7397
7414
|
"film",
|
|
7398
7415
|
"animation"
|
|
7399
|
-
]).optional()
|
|
7416
|
+
]).optional(),
|
|
7417
|
+
/**
|
|
7418
|
+
* ONE slice per access unit.
|
|
7419
|
+
*
|
|
7420
|
+
* `-tune zerolatency` turns on x264's sliced threads, and a frame then leaves
|
|
7421
|
+
* the encoder as five NAL slices that share one RTP timestamp and carry one
|
|
7422
|
+
* marker bit. A libwebrtc depacketiser sees five frame-starts and one
|
|
7423
|
+
* frame-end per frame: the first pictures render and the video then freezes
|
|
7424
|
+
* for good while the audio, on its own plane, plays on. Measured on this hub
|
|
7425
|
+
* 2026-09-13 against the Echo, and reduced to one slice by this flag alone.
|
|
7426
|
+
*
|
|
7427
|
+
* A NAMED field and not a raw flag, because {@link EgressEncodeSchema} omits
|
|
7428
|
+
* `outputArgs` on purpose: an opaque array is part of the sharing key, so two
|
|
7429
|
+
* consumers meaning the same thing spelled differently would stop sharing one
|
|
7430
|
+
* child. Absent means "whatever the encoder does" — today's behaviour.
|
|
7431
|
+
*/
|
|
7432
|
+
singleSlicePerFrame: boolean().optional()
|
|
7400
7433
|
}),
|
|
7401
7434
|
audio: union([literal("passthrough"), object({
|
|
7402
7435
|
codec: _enum([
|
|
@@ -7446,7 +7479,7 @@ var BASE_LIVE_EGRESS_PROFILE = {
|
|
|
7446
7479
|
audio: "passthrough"
|
|
7447
7480
|
};
|
|
7448
7481
|
({ ...BASE_LIVE_EGRESS_PROFILE }), { ...BASE_LIVE_EGRESS_PROFILE.video };
|
|
7449
|
-
({ ...BASE_LIVE_EGRESS_PROFILE });
|
|
7482
|
+
({ ...BASE_LIVE_EGRESS_PROFILE }), { ...BASE_LIVE_EGRESS_PROFILE.video };
|
|
7450
7483
|
/**
|
|
7451
7484
|
* Deep wiring healthcheck — snapshot of active reachability probes across
|
|
7452
7485
|
* every declared capability + widget of every installed plugin, on every
|
|
@@ -13122,6 +13155,16 @@ method(object({
|
|
|
13122
13155
|
filter: QueryFilterSchema.optional(),
|
|
13123
13156
|
columns: array(string()).readonly().optional()
|
|
13124
13157
|
}), array(SettingsRecordSchema).readonly()), method(object({
|
|
13158
|
+
namespace: string().optional(),
|
|
13159
|
+
collection: string(),
|
|
13160
|
+
/** Declared columns identifying the slot; must be covered by a UNIQUE
|
|
13161
|
+
* index on the collection. Never empty. */
|
|
13162
|
+
conflict: array(string()).readonly(),
|
|
13163
|
+
record: BulkRecordSchema
|
|
13164
|
+
}), object({
|
|
13165
|
+
/** The id the row HAS: assigned by SQLite on an insert, or the existing
|
|
13166
|
+
* row's own id on an update. */
|
|
13167
|
+
id: union([string(), number()]) }), { kind: "mutation" }), method(object({
|
|
13125
13168
|
namespace: string().optional(),
|
|
13126
13169
|
collection: string(),
|
|
13127
13170
|
record: object({
|
|
@@ -13256,6 +13299,14 @@ method(_void(), EngineInfoSchema, { auth: "admin" }), method(object({
|
|
|
13256
13299
|
id: union([string(), number()]) }), {
|
|
13257
13300
|
kind: "mutation",
|
|
13258
13301
|
auth: "admin"
|
|
13302
|
+
}), method(object({
|
|
13303
|
+
namespace: string().optional(),
|
|
13304
|
+
collection: string(),
|
|
13305
|
+
conflict: array(string()).readonly(),
|
|
13306
|
+
record: BulkRecordSchema
|
|
13307
|
+
}), object({ id: union([string(), number()]) }), {
|
|
13308
|
+
kind: "mutation",
|
|
13309
|
+
auth: "admin"
|
|
13259
13310
|
}), method(object({
|
|
13260
13311
|
namespace: string().optional(),
|
|
13261
13312
|
collection: string(),
|
|
@@ -19778,8 +19829,8 @@ var TrackPositionSchema = object({
|
|
|
19778
19829
|
var TrackSnapshotSchema = object({
|
|
19779
19830
|
timestamp: number(),
|
|
19780
19831
|
position: TrackPositionSchema,
|
|
19781
|
-
/**
|
|
19782
|
-
|
|
19832
|
+
/** The snapshot's media row id (D482); resolve via `listTrackMedia({ trackId })`. */
|
|
19833
|
+
mediaId: number().int()
|
|
19783
19834
|
});
|
|
19784
19835
|
/**
|
|
19785
19836
|
* Normalized 0..1 trajectory envelope (min/max over every position bbox,
|
|
@@ -20383,14 +20434,14 @@ var ObjectEventSchema = object({
|
|
|
20383
20434
|
* pixel-space `bbox` onto a displayed image. Omitted in slim projection. */
|
|
20384
20435
|
frameWidth: number().optional(),
|
|
20385
20436
|
frameHeight: number().optional(),
|
|
20386
|
-
/**
|
|
20387
|
-
|
|
20388
|
-
/** Design B:
|
|
20437
|
+
/** Media row id of the crop attached to this event (if any) — D482. */
|
|
20438
|
+
mediaId: number().int().optional(),
|
|
20439
|
+
/** Design B: media row id of the track's native-resolution key frame (the
|
|
20389
20440
|
* best-detection full frame). Resolve via the event-media data-plane
|
|
20390
|
-
* (`/addon/<addonId>/event-media/<
|
|
20441
|
+
* (`/addon/<addonId>/event-media/m/<keyFrameMediaId>`) for a detail view that
|
|
20391
20442
|
* draws `bbox` over the native frame. Absent on legacy rows / non-decoded
|
|
20392
|
-
* sources — consumers fall back to `
|
|
20393
|
-
|
|
20443
|
+
* sources — consumers fall back to `mediaId` (the tight crop). */
|
|
20444
|
+
keyFrameMediaId: number().int().optional(),
|
|
20394
20445
|
/** Populated by B5 (recording playback URL for this event). */
|
|
20395
20446
|
mediaUrl: string().optional(),
|
|
20396
20447
|
/** The parent track's key-event importance [0,1], propagated to every object
|
|
@@ -20440,7 +20491,7 @@ var MediaFileKindEnum = _enum([
|
|
|
20440
20491
|
* hub-main's heap on the way past — for an `<img>` that would have cached it.
|
|
20441
20492
|
*
|
|
20442
20493
|
* `url` points at the `event-media` data plane
|
|
20443
|
-
* (`/addon/<addonId>/event-media/<
|
|
20494
|
+
* (`/addon/<addonId>/event-media/m/<mediaId>` — D482), which serves the same blob
|
|
20444
20495
|
* with an ETag and `Cache-Control: immutable`, honours conditional GETs, can
|
|
20445
20496
|
* render a `?variant=thumb`, and streams. The hub gate in front of it requires
|
|
20446
20497
|
* a bearer or the session cookie (`access: 'authenticated'`), so the bytes are
|
|
@@ -20448,10 +20499,13 @@ var MediaFileKindEnum = _enum([
|
|
|
20448
20499
|
* `data-plane-access.ts` for the rule and the one gap it does not close
|
|
20449
20500
|
* (per-device scoping).
|
|
20450
20501
|
*
|
|
20451
|
-
* The URL is built from the row's
|
|
20452
|
-
*
|
|
20502
|
+
* The URL is built from the row's own id, which since D482 says nothing about
|
|
20503
|
+
* the row's owner or kind — and that is the point. The published `kind` is not
|
|
20504
|
+
* the stored one (a track's face/plate crop is stored as `crop` under
|
|
20453
20505
|
* `('face'|'plate', '<prefix>-<trackId>')` and published as
|
|
20454
|
-
* `faceCrop`/`plateCrop
|
|
20506
|
+
* `faceCrop`/`plateCrop`), and under the old composite key the URL had to be
|
|
20507
|
+
* taken from `row.key` verbatim or it 404'd exactly those two rows. An id
|
|
20508
|
+
* cannot be mis-reconstructed, because there is nothing in it to reconstruct.
|
|
20455
20509
|
*
|
|
20456
20510
|
* ## `base64` is TRANSITIONAL and is going away
|
|
20457
20511
|
*
|
|
@@ -20464,7 +20518,19 @@ var MediaFileKindEnum = _enum([
|
|
|
20464
20518
|
* `analytics-query-facade.ts`; nothing else reads it.
|
|
20465
20519
|
*/
|
|
20466
20520
|
var MediaFileSchema = object({
|
|
20467
|
-
|
|
20521
|
+
/**
|
|
20522
|
+
* The media row's OWN id — the rowid SQLite assigned it (D482).
|
|
20523
|
+
*
|
|
20524
|
+
* It used to be the row's composite key, `<ownerType>:<ownerId>:<fileKind>
|
|
20525
|
+
* [:<timestampMs>]`, which embedded a FOREIGN id. D474 made event ids
|
|
20526
|
+
* per-table rowid aliases, so `object:101314` and `motion:101314` are two
|
|
20527
|
+
* different rows that spell the same number, and a track whose
|
|
20528
|
+
* `bestEventId` was an object event was served a motion event's snapshot —
|
|
20529
|
+
* a night-time thumbnail on an afternoon track, with no error anywhere. A
|
|
20530
|
+
* surrogate id cannot name the wrong row's owner, because it names no owner
|
|
20531
|
+
* at all.
|
|
20532
|
+
*/
|
|
20533
|
+
mediaId: number().int(),
|
|
20468
20534
|
kind: MediaFileKindEnum,
|
|
20469
20535
|
sizeBytes: number(),
|
|
20470
20536
|
timestamp: number()
|
|
@@ -20572,7 +20638,7 @@ var RetrainTrackSchema = object({
|
|
|
20572
20638
|
});
|
|
20573
20639
|
/** A frame the picker may offer — an index row, no blob was read to produce it. */
|
|
20574
20640
|
var RetrainFrameCandidateSchema = object({
|
|
20575
|
-
|
|
20641
|
+
mediaId: number().int(),
|
|
20576
20642
|
kind: MediaFileKindEnum,
|
|
20577
20643
|
timestamp: number(),
|
|
20578
20644
|
sizeBytes: number().int(),
|
|
@@ -20586,7 +20652,7 @@ var RetrainFrameSchema = object({
|
|
|
20586
20652
|
deviceId: number(),
|
|
20587
20653
|
trackId: string(),
|
|
20588
20654
|
/** Provenance only. It may already point at nothing — that is expected. */
|
|
20589
|
-
|
|
20655
|
+
sourceMediaId: number().int(),
|
|
20590
20656
|
sourceKind: MediaFileKindEnum,
|
|
20591
20657
|
sizeBytes: number().int(),
|
|
20592
20658
|
width: number().int(),
|
|
@@ -20602,7 +20668,7 @@ var RetrainCopyRefusalSchema = _enum([
|
|
|
20602
20668
|
var RetrainFrameSelectionSchema = object({
|
|
20603
20669
|
copied: array(RetrainFrameSchema).readonly(),
|
|
20604
20670
|
refused: array(object({
|
|
20605
|
-
|
|
20671
|
+
sourceMediaId: number().int(),
|
|
20606
20672
|
reason: RetrainCopyRefusalSchema
|
|
20607
20673
|
})).readonly()
|
|
20608
20674
|
});
|
|
@@ -20610,7 +20676,7 @@ var RetrainFrameListSchema = object({
|
|
|
20610
20676
|
candidates: array(RetrainFrameCandidateSchema).readonly(),
|
|
20611
20677
|
copies: array(RetrainFrameSchema).readonly(),
|
|
20612
20678
|
/** What the page pre-selects — the native key frame when one survives. */
|
|
20613
|
-
|
|
20679
|
+
autoPickMediaId: number().int().optional()
|
|
20614
20680
|
});
|
|
20615
20681
|
/** What the operator asked the assist to look for. */
|
|
20616
20682
|
var RetrainAssistSubjectSchema = discriminatedUnion("kind", [object({
|
|
@@ -20705,9 +20771,11 @@ var RecentTracksQueryInput = object({
|
|
|
20705
20771
|
});
|
|
20706
20772
|
/**
|
|
20707
20773
|
* A Summary (D359): the per-camera session envelope that references tracks.
|
|
20708
|
-
* `
|
|
20709
|
-
* served by the event-media plane
|
|
20710
|
-
* member visible has been materialised
|
|
20774
|
+
* `groupShotMediaId` is the media ROW id of its group shot (`ownerKind:
|
|
20775
|
+
* 'summary'`, served by the event-media plane at `/m/<id>`), null until the
|
|
20776
|
+
* first frame with a member visible has been materialised (D482 — it was the
|
|
20777
|
+
* row's composite key, which embedded the owner and could name another table's
|
|
20778
|
+
* row once event ids became per-table rowids).
|
|
20711
20779
|
*/
|
|
20712
20780
|
var SummarySchema = object({
|
|
20713
20781
|
id: string(),
|
|
@@ -20716,19 +20784,115 @@ var SummarySchema = object({
|
|
|
20716
20784
|
lastActiveAt: number(),
|
|
20717
20785
|
sealedAt: number().nullable(),
|
|
20718
20786
|
memberCount: number().int().nonnegative(),
|
|
20719
|
-
|
|
20787
|
+
groupShotMediaId: number().int().nullable()
|
|
20720
20788
|
});
|
|
20721
20789
|
var SummariesQueryInput = object({
|
|
20722
20790
|
deviceIds: array(number()).min(1),
|
|
20723
20791
|
since: number().optional(),
|
|
20724
20792
|
until: number().optional(),
|
|
20725
|
-
limit: number().int().min(1).max(200).default(50)
|
|
20793
|
+
limit: number().int().min(1).max(200).default(50),
|
|
20794
|
+
/** The same member-wise filter {@link listRecentSummaries} takes — one
|
|
20795
|
+
* meaning of "dog" on every summary surface. */
|
|
20796
|
+
classes: array(string().min(1).max(60)).max(40).optional()
|
|
20726
20797
|
});
|
|
20727
|
-
var SummariesPageSchema = object({ summaries: array(SummarySchema).readonly() });
|
|
20728
20798
|
var SummaryDetailSchema = object({
|
|
20729
20799
|
summary: SummarySchema,
|
|
20730
|
-
/**
|
|
20731
|
-
|
|
20800
|
+
/** Members in absorption order, oldest join first. */
|
|
20801
|
+
members: array(object({
|
|
20802
|
+
trackId: string(),
|
|
20803
|
+
/**
|
|
20804
|
+
* The track's class at the time it JOINED, or `null` when it was unresolved
|
|
20805
|
+
* and the track no longer exists to fill it.
|
|
20806
|
+
*
|
|
20807
|
+
* The join, not the latest opinion: class voting can re-decide a track's
|
|
20808
|
+
* class afterwards, and a group's composition is the history of who came
|
|
20809
|
+
* together. A consumer counts these to badge a thumbnail — "two people and a
|
|
20810
|
+
* dog" — rather than being handed a second, denormalised tally that would
|
|
20811
|
+
* drift from the members it claims to describe.
|
|
20812
|
+
*/
|
|
20813
|
+
className: string().nullable(),
|
|
20814
|
+
/** `primary` is the one member that carries the group's identity. */
|
|
20815
|
+
role: _enum([
|
|
20816
|
+
"primary",
|
|
20817
|
+
"sibling",
|
|
20818
|
+
"child"
|
|
20819
|
+
]).nullable(),
|
|
20820
|
+
joinedAt: number(),
|
|
20821
|
+
/** Tier 1 — the sub-class (`dog`, `van`), resolved from the member's track
|
|
20822
|
+
* at read time. Absent when nothing resolved, never an empty string. */
|
|
20823
|
+
label: string().optional(),
|
|
20824
|
+
/** Tier 2 — the instance: a person's name, a plate. Absent when the pipeline
|
|
20825
|
+
* recognised nobody, and absent for a member whose track has been pruned —
|
|
20826
|
+
* a thumbnail that names the wrong person is worse than one naming nobody. */
|
|
20827
|
+
subLabel: string().optional()
|
|
20828
|
+
})).readonly()
|
|
20829
|
+
});
|
|
20830
|
+
/**
|
|
20831
|
+
* What a LIST of groups carries: the envelope plus what it is MADE OF.
|
|
20832
|
+
*
|
|
20833
|
+
* Coarse on purpose — the operator's rule is "only the rough data on the list,
|
|
20834
|
+
* we extend when we notice we need more". Enough to draw the card ("two people
|
|
20835
|
+
* and a dog") and no more. The MEMBERS, their names and the per-member links
|
|
20836
|
+
* are on {@link getSummary}: shipping every member of every group so a client
|
|
20837
|
+
* can count them turns a page of two hundred groups into a thousand records to
|
|
20838
|
+
* draw two hundred badges.
|
|
20839
|
+
*/
|
|
20840
|
+
var SummaryListItemSchema = object({
|
|
20841
|
+
summary: SummarySchema,
|
|
20842
|
+
/** Class counts, most numerous first; `className: null` is a member whose
|
|
20843
|
+
* class never resolved, counted so the counts add up to `memberCount`. */
|
|
20844
|
+
classes: array(object({
|
|
20845
|
+
className: string().nullable(),
|
|
20846
|
+
count: number().int().positive()
|
|
20847
|
+
})).readonly()
|
|
20848
|
+
});
|
|
20849
|
+
var SummariesPageSchema = object({ summaries: array(SummaryListItemSchema).readonly() });
|
|
20850
|
+
/**
|
|
20851
|
+
* The paged feed, deliberately the SAME shape as {@link RecentTracksQueryInput}.
|
|
20852
|
+
*
|
|
20853
|
+
* The reel on the cameras page and the Events gallery both ride a cursor, so a
|
|
20854
|
+
* summaries feed that could only answer "the last N for these cameras"
|
|
20855
|
+
* (`listSummaries`) would make groups available in the timeline and nowhere
|
|
20856
|
+
* else. Two feeds with different ordering contracts would be two ideas of what
|
|
20857
|
+
* "newest" means, on one screen.
|
|
20858
|
+
*/
|
|
20859
|
+
var RecentSummariesQueryInput = object({
|
|
20860
|
+
/** Devices to merge. An empty array yields an empty page. */
|
|
20861
|
+
deviceIds: array(number()),
|
|
20862
|
+
/** Window lower bound on `lastActiveAt` (inclusive). */
|
|
20863
|
+
since: number().optional(),
|
|
20864
|
+
/** Window upper bound on `lastActiveAt` (inclusive). */
|
|
20865
|
+
until: number().optional(),
|
|
20866
|
+
limit: number().int().min(1).max(500).default(100),
|
|
20867
|
+
/** Opaque continuation cursor from a previous page's `nextCursor`. */
|
|
20868
|
+
cursor: string().optional(),
|
|
20869
|
+
/**
|
|
20870
|
+
* Restrict to these classes — THE SAME FIELD `listRecentTracks` takes, and
|
|
20871
|
+
* deliberately the same name: the events filter tree emits one list of ticked
|
|
20872
|
+
* taxonomy nodes, and a summaries feed that called it something else would
|
|
20873
|
+
* make the operator's one filter component produce two shapes.
|
|
20874
|
+
*
|
|
20875
|
+
* A question about the MEMBERS: a group matches when ANY of them does. "Show
|
|
20876
|
+
* me the arrivals with a dog" has to return the group of four people who had
|
|
20877
|
+
* one with them; a filter on the group's own fields could only ever answer
|
|
20878
|
+
* about its primary.
|
|
20879
|
+
*
|
|
20880
|
+
* Matched against all THREE tiers of a member — the class (`animal`), the
|
|
20881
|
+
* sub-class (`dog`) and the instance (a name, a plate) — because which tier a
|
|
20882
|
+
* ticked node lives on is the taxonomy's business, not the caller's. `dog` is
|
|
20883
|
+
* an event kind in the tree and a tier-1 label on an `animal` track; a filter
|
|
20884
|
+
* that read only the class would answer "animal" and never "dog".
|
|
20885
|
+
*
|
|
20886
|
+
* ABSENT or EMPTY means no filter — absent is not a selection of none.
|
|
20887
|
+
*/
|
|
20888
|
+
classes: array(string().min(1).max(60)).max(40).optional()
|
|
20889
|
+
});
|
|
20890
|
+
var RecentSummariesPageSchema = object({
|
|
20891
|
+
/** Ordered by (`lastActiveAt` DESC, id DESC). Same light item as
|
|
20892
|
+
* {@link listSummaries} — one list shape, so a card renders the same
|
|
20893
|
+
* whichever feed drew it. */
|
|
20894
|
+
summaries: array(SummaryListItemSchema).readonly(),
|
|
20895
|
+
nextCursor: string().nullable()
|
|
20732
20896
|
});
|
|
20733
20897
|
var RecentTracksPageSchema = object({
|
|
20734
20898
|
/** Merged page, ordered by (`lastSeen` DESC, `trackId` DESC). */
|
|
@@ -21142,7 +21306,7 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
|
|
|
21142
21306
|
classes: array(string()).optional(),
|
|
21143
21307
|
/** See {@link ExcludeSourcesDoc}. */
|
|
21144
21308
|
excludeSources: array(TrackSourceSchema).optional()
|
|
21145
|
-
}), array(TrackSchema).readonly()), method(RecentTracksQueryInput, RecentTracksPageSchema), method(SummariesQueryInput, SummariesPageSchema), method(object({ id: string() }), SummaryDetailSchema.nullable()), method(object({ deviceId: number() }), _void(), {
|
|
21309
|
+
}), array(TrackSchema).readonly()), method(RecentTracksQueryInput, RecentTracksPageSchema), method(SummariesQueryInput, SummariesPageSchema), method(RecentSummariesQueryInput, RecentSummariesPageSchema), method(object({ id: string() }), SummaryDetailSchema.nullable()), method(object({ deviceId: number() }), _void(), {
|
|
21146
21310
|
kind: "mutation",
|
|
21147
21311
|
auth: "admin"
|
|
21148
21312
|
}), 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({
|
|
@@ -21270,7 +21434,7 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
|
|
|
21270
21434
|
}), method(object({
|
|
21271
21435
|
deviceId: number(),
|
|
21272
21436
|
trackId: string(),
|
|
21273
|
-
|
|
21437
|
+
mediaIds: array(number().int()).min(1)
|
|
21274
21438
|
}), RetrainFrameSelectionSchema, {
|
|
21275
21439
|
kind: "mutation",
|
|
21276
21440
|
auth: "admin"
|
|
@@ -21338,7 +21502,10 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
|
|
|
21338
21502
|
kind: "query",
|
|
21339
21503
|
auth: "admin"
|
|
21340
21504
|
}), method(object({
|
|
21341
|
-
|
|
21505
|
+
/** Which of the three event tables owns the row. */
|
|
21506
|
+
ownerType: EventOwnerTypeSchema,
|
|
21507
|
+
/** The event's rowid in that table (D474: an event id is a number). */
|
|
21508
|
+
eventId: number().int(),
|
|
21342
21509
|
kind: MediaFileKindEnum.optional(),
|
|
21343
21510
|
deviceId: number()
|
|
21344
21511
|
}), array(MediaFileSchema).readonly()), method(object({
|
|
@@ -21349,7 +21516,8 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
|
|
|
21349
21516
|
trackId: string(),
|
|
21350
21517
|
deviceId: number()
|
|
21351
21518
|
}), array(MediaFileInfoSchema).readonly()), method(object({
|
|
21352
|
-
|
|
21519
|
+
ownerType: EventOwnerTypeSchema,
|
|
21520
|
+
eventId: number().int(),
|
|
21353
21521
|
deviceId: number()
|
|
21354
21522
|
}), array(MediaFileInfoSchema).readonly()), method(SearchObjectEventsInput, array(ScoredObjectEventSchema).readonly()), method(object({}), WipeObjectEmbeddingsResultSchema, {
|
|
21355
21523
|
kind: "mutation",
|
|
@@ -26646,8 +26814,8 @@ var IdentitySchema = object({
|
|
|
26646
26814
|
id: string(),
|
|
26647
26815
|
name: string(),
|
|
26648
26816
|
sampleCount: number().int().nonnegative(),
|
|
26649
|
-
|
|
26650
|
-
/** Inline base64 of the cover sample's crop, resolved from `
|
|
26817
|
+
coverMediaId: number().int().optional(),
|
|
26818
|
+
/** Inline base64 of the cover sample's crop, resolved from `coverMediaId`.
|
|
26651
26819
|
* Lets the UI render the person's face avatar instead of a placeholder icon. */
|
|
26652
26820
|
coverBase64: string().optional()
|
|
26653
26821
|
});
|
|
@@ -26673,8 +26841,8 @@ var IdentitySampleAuditRowSchema = object({
|
|
|
26673
26841
|
enrolledAt: number().int(),
|
|
26674
26842
|
deviceId: number().int().optional(),
|
|
26675
26843
|
source: _enum(["detected", "photo"]),
|
|
26676
|
-
/** The enrolled crop's media
|
|
26677
|
-
|
|
26844
|
+
/** The enrolled crop's media row id, so the panel can show the evidence. */
|
|
26845
|
+
mediaId: number().int().optional(),
|
|
26678
26846
|
/**
|
|
26679
26847
|
* False = the sample is stamped with a DIFFERENT face model, and a cosine
|
|
26680
26848
|
* across feature spaces is a well-formed float with no meaning. Every number
|
|
@@ -26743,15 +26911,15 @@ var FaceInfoSchema = object({
|
|
|
26743
26911
|
*/
|
|
26744
26912
|
cropUrl: string().optional(),
|
|
26745
26913
|
/** Design B: the face bbox (pixel space) on the key frame — lets a detail
|
|
26746
|
-
* view draw the box over the native `
|
|
26914
|
+
* view draw the box over the native `keyFrameMediaId` frame. Absent on
|
|
26747
26915
|
* legacy rows written before design B. */
|
|
26748
26916
|
faceBbox: BoundingBoxSchema.optional(),
|
|
26749
26917
|
/** Design B: MediaStore key of the track's native-resolution key frame.
|
|
26750
26918
|
* Fetch the native JPEG via the event-media data-plane
|
|
26751
|
-
* (`/addon/<addonId>/event-media/<
|
|
26919
|
+
* (`/addon/<addonId>/event-media/m/<keyFrameMediaId>`). Absent when the
|
|
26752
26920
|
* track produced no key frame (e.g. native/onboard source) — the UI falls
|
|
26753
26921
|
* back to the inline `base64` face crop. */
|
|
26754
|
-
|
|
26922
|
+
keyFrameMediaId: number().int().optional(),
|
|
26755
26923
|
/** Winning identity-match cosine (0..1) for this face's track, when an
|
|
26756
26924
|
* identity was auto-confirmed. Lets the UI surface WHY a face was assigned
|
|
26757
26925
|
* (confidence badge / low-confidence audit). Absent on legacy rows and on
|
|
@@ -26820,11 +26988,14 @@ var FaceClusterSchema = object({
|
|
|
26820
26988
|
* `data:image/jpeg;base64,…` from a row whose `key` sat right beside it, in a
|
|
26821
26989
|
* dialog already rendering its key FRAME from the `event-media` plane.
|
|
26822
26990
|
*
|
|
26823
|
-
* `url` is `/addon/<addonId>/event-media/<
|
|
26824
|
-
* media
|
|
26991
|
+
* `url` is `/addon/<addonId>/event-media/m/<mediaId>` (D482). The plane
|
|
26992
|
+
* resolves a media row by its own id, so this needed no new plane and no new
|
|
26993
|
+
* access decision.
|
|
26825
26994
|
*/
|
|
26826
26995
|
var MediaFileLiteSchema$1 = object({
|
|
26827
|
-
|
|
26996
|
+
/** The media row's own id — the same address `MediaFileRef.mediaId` carries
|
|
26997
|
+
* (D482). It was the row's composite key, which embedded the owner. */
|
|
26998
|
+
mediaId: number().int(),
|
|
26828
26999
|
kind: string(),
|
|
26829
27000
|
url: string(),
|
|
26830
27001
|
sizeBytes: number(),
|
|
@@ -26841,7 +27012,7 @@ method(object({
|
|
|
26841
27012
|
* covers inline, ~10 KB of base64 per row, on a query this UI mounts
|
|
26842
27013
|
* four times and the viewer holds at `staleTime: 30_000`.
|
|
26843
27014
|
*
|
|
26844
|
-
* Nothing loses its avatar: `
|
|
27015
|
+
* Nothing loses its avatar: `coverMediaId` is already on every row and
|
|
26845
27016
|
* the `event-media` plane serves that key `immutable` with an ETag.
|
|
26846
27017
|
*
|
|
26847
27018
|
* **This is an INPUT field, so it does not reach the addon until the
|
|
@@ -30224,8 +30395,8 @@ var VehicleSchema = object({
|
|
|
30224
30395
|
id: string(),
|
|
30225
30396
|
name: string(),
|
|
30226
30397
|
sampleCount: number().int().nonnegative(),
|
|
30227
|
-
|
|
30228
|
-
/** Inline base64 of the cover sample's plate crop, resolved from `
|
|
30398
|
+
coverMediaId: number().int().optional(),
|
|
30399
|
+
/** Inline base64 of the cover sample's plate crop, resolved from `coverMediaId`. */
|
|
30229
30400
|
coverBase64: string().optional()
|
|
30230
30401
|
});
|
|
30231
30402
|
var VehicleSampleInfoSchema = object({
|
|
@@ -30258,7 +30429,7 @@ var PlateInfoSchema = object({
|
|
|
30258
30429
|
/** keyFrame parity: the plate bbox (pixel space) on the native key frame. */
|
|
30259
30430
|
plateBbox: BoundingBoxSchema.optional(),
|
|
30260
30431
|
/** keyFrame parity: MediaStore key of the track's native-resolution key frame. */
|
|
30261
|
-
|
|
30432
|
+
keyFrameMediaId: number().int().optional(),
|
|
30262
30433
|
base64: string().optional(),
|
|
30263
30434
|
/**
|
|
30264
30435
|
* Same crop as a data-plane URL, always present when the plate has a stored
|
|
@@ -30279,11 +30450,14 @@ var PlateInfoSchema = object({
|
|
|
30279
30450
|
* `data:image/jpeg;base64,…` from a row whose `key` sat right beside it, in a
|
|
30280
30451
|
* dialog already rendering its key FRAME from the `event-media` plane.
|
|
30281
30452
|
*
|
|
30282
|
-
* `url` is `/addon/<addonId>/event-media/<
|
|
30283
|
-
* media
|
|
30453
|
+
* `url` is `/addon/<addonId>/event-media/m/<mediaId>` (D482). The plane
|
|
30454
|
+
* resolves a media row by its own id, so this needed no new plane and no new
|
|
30455
|
+
* access decision.
|
|
30284
30456
|
*/
|
|
30285
30457
|
var MediaFileLiteSchema = object({
|
|
30286
|
-
|
|
30458
|
+
/** The media row's own id — the same address `MediaFileRef.mediaId` carries
|
|
30459
|
+
* (D482). It was the row's composite key, which embedded the owner. */
|
|
30460
|
+
mediaId: number().int(),
|
|
30287
30461
|
kind: string(),
|
|
30288
30462
|
url: string(),
|
|
30289
30463
|
sizeBytes: number(),
|
|
@@ -30342,7 +30516,7 @@ method(object({
|
|
|
30342
30516
|
}), method(object({
|
|
30343
30517
|
/** Inline {@link VehicleSchema.coverBase64} on every row. Default
|
|
30344
30518
|
* `false` — the vehicle twin of `faceGallery.listIdentities`'s
|
|
30345
|
-
* option; `
|
|
30519
|
+
* option; `coverMediaId` + the `event-media` plane carry the picture.
|
|
30346
30520
|
* INPUT field: stripped by the hub router until the train ships, which
|
|
30347
30521
|
* resolves to `false` and is exactly the intended default. */
|
|
30348
30522
|
includeCrops: boolean().optional() }).optional(), array(VehicleSchema).readonly()), method(object({ name: string().min(1) }), VehicleSchema, {
|
|
@@ -31998,7 +32172,14 @@ var SceneReferenceSchema = object({
|
|
|
31998
32172
|
modelId: string(),
|
|
31999
32173
|
condition: SceneConditionSchema,
|
|
32000
32174
|
capturedAt: number(),
|
|
32001
|
-
|
|
32175
|
+
/**
|
|
32176
|
+
* The reference thumbnail's media ROW id (D482).
|
|
32177
|
+
*
|
|
32178
|
+
* The name already said `mediaId` while the value was the row's composite
|
|
32179
|
+
* key — a leftover that read as done and was not. It is the row's own id
|
|
32180
|
+
* now, addressed at `/addon/<addonId>/event-media/m/<id>`.
|
|
32181
|
+
*/
|
|
32182
|
+
thumbnailMediaId: number().int().optional(),
|
|
32002
32183
|
/** Whole-frame (downscaled) embedding captured alongside the ROI crop. The
|
|
32003
32184
|
* anti-view-shift anchor: a bumped camera, a PTZ preset or a re-aim makes the
|
|
32004
32185
|
* normalized rect frame a different piece of world, and the scene would
|
|
@@ -33287,7 +33468,29 @@ var LoggingSettingsPatchSchema = object({
|
|
|
33287
33468
|
* disarmed the channels it did not mention would make the Levels page and
|
|
33288
33469
|
* the Diagnostics page fight over the same value.
|
|
33289
33470
|
*/
|
|
33290
|
-
channels: array(LogChannelWindowPatchSchema).readonly().optional()
|
|
33471
|
+
channels: array(LogChannelWindowPatchSchema).readonly().optional(),
|
|
33472
|
+
/**
|
|
33473
|
+
* How many days the analytics OPS LOG is kept — the audit trail of what
|
|
33474
|
+
* retention actually deleted.
|
|
33475
|
+
*
|
|
33476
|
+
* It lives HERE, on the logging document, and not on the analytics addon's
|
|
33477
|
+
* settings form, on the operator's instruction: every other log-ish window in
|
|
33478
|
+
* this system is configured through this one document, and a retention audit
|
|
33479
|
+
* configured somewhere else is a second place to look when the question is
|
|
33480
|
+
* "what happened to my data".
|
|
33481
|
+
*
|
|
33482
|
+
* That placement has a cost worth stating: this document ships in the
|
|
33483
|
+
* framework closure, so this knob needs a published `@camstack/server` while
|
|
33484
|
+
* the four windows beside it (D485) reach a node on `camstack deploy`.
|
|
33485
|
+
*
|
|
33486
|
+
* `retention-model.ts` argued this one must NOT follow a device window,
|
|
33487
|
+
* because the audit trail is the history of the SWEEP and not of the camera.
|
|
33488
|
+
* That argument stands and is untouched — what changes is that 30 days stops
|
|
33489
|
+
* being a constant nobody can reach. `0` keeps it forever. The floor is 1 day
|
|
33490
|
+
* rather than 0-as-delete: an audit log truncated to nothing is precisely the
|
|
33491
|
+
* state in which the next 9.5 GiB leak cannot be explained.
|
|
33492
|
+
*/
|
|
33493
|
+
opsLogRetentionDays: number().int().min(0).max(3650).optional()
|
|
33291
33494
|
});
|
|
33292
33495
|
/**
|
|
33293
33496
|
* Which LAYER of the hierarchy is addressed. Absent = the cluster layer.
|
|
@@ -33360,6 +33563,14 @@ var LoggingSettingsStateSchema = object({
|
|
|
33360
33563
|
channels: array(LogChannelDescriptorSchema).readonly(),
|
|
33361
33564
|
/** The channels ARMED right now, each with its deadline. */
|
|
33362
33565
|
activeChannels: array(LogChannelWindowStateSchema).readonly(),
|
|
33566
|
+
/**
|
|
33567
|
+
* The ops-log window in days, as it is in force. `0` = kept forever.
|
|
33568
|
+
*
|
|
33569
|
+
* Reported rather than left to the caller's memory of what it wrote: this is
|
|
33570
|
+
* the value the analytics sweep will actually use, and an operator asking how
|
|
33571
|
+
* long their audit trail lives should not have to infer it from a default.
|
|
33572
|
+
*/
|
|
33573
|
+
opsLogRetentionDays: number().int().min(0),
|
|
33363
33574
|
persisted: boolean()
|
|
33364
33575
|
});
|
|
33365
33576
|
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(), {
|
|
@@ -34180,7 +34391,7 @@ var StationaryObjectSchema = object({
|
|
|
34180
34391
|
/** Enrichment label carried from the source track (identity / plate). */
|
|
34181
34392
|
label: string().optional(),
|
|
34182
34393
|
/** Native-resolution key-frame media key for the parked object's best image. */
|
|
34183
|
-
|
|
34394
|
+
keyFrameMediaId: number().int().optional()
|
|
34184
34395
|
});
|
|
34185
34396
|
var CameraOccupancySnapshotSchema = object({
|
|
34186
34397
|
/** Frame timestamp of the inference result that produced this snapshot. */
|
|
@@ -37096,6 +37307,12 @@ Object.freeze({
|
|
|
37096
37307
|
addonId: null,
|
|
37097
37308
|
access: "create"
|
|
37098
37309
|
},
|
|
37310
|
+
"dataStoreProvider.upsert": {
|
|
37311
|
+
capName: "data-store-provider",
|
|
37312
|
+
capScope: "system",
|
|
37313
|
+
addonId: null,
|
|
37314
|
+
access: "create"
|
|
37315
|
+
},
|
|
37099
37316
|
"dayNight.getOptions": {
|
|
37100
37317
|
capName: "day-night",
|
|
37101
37318
|
capScope: "device",
|
|
@@ -39532,6 +39749,12 @@ Object.freeze({
|
|
|
39532
39749
|
addonId: null,
|
|
39533
39750
|
access: "view"
|
|
39534
39751
|
},
|
|
39752
|
+
"pipelineAnalytics.listRecentSummaries": {
|
|
39753
|
+
capName: "pipeline-analytics",
|
|
39754
|
+
capScope: "device",
|
|
39755
|
+
addonId: null,
|
|
39756
|
+
access: "view"
|
|
39757
|
+
},
|
|
39535
39758
|
"pipelineAnalytics.listRecentTracks": {
|
|
39536
39759
|
capName: "pipeline-analytics",
|
|
39537
39760
|
capScope: "device",
|
|
@@ -40960,6 +41183,12 @@ Object.freeze({
|
|
|
40960
41183
|
addonId: null,
|
|
40961
41184
|
access: "create"
|
|
40962
41185
|
},
|
|
41186
|
+
"settingsStore.upsert": {
|
|
41187
|
+
capName: "settings-store",
|
|
41188
|
+
capScope: "system",
|
|
41189
|
+
addonId: null,
|
|
41190
|
+
access: "create"
|
|
41191
|
+
},
|
|
40963
41192
|
"smtpProvider.getStatus": {
|
|
40964
41193
|
capName: "smtp-provider",
|
|
40965
41194
|
capScope: "system",
|
|
@@ -43353,6 +43582,11 @@ Object.freeze({
|
|
|
43353
43582
|
form: "single",
|
|
43354
43583
|
optional: true
|
|
43355
43584
|
}],
|
|
43585
|
+
"pipelineAnalytics.listRecentSummaries": [{
|
|
43586
|
+
name: "deviceIds",
|
|
43587
|
+
form: "array",
|
|
43588
|
+
optional: false
|
|
43589
|
+
}],
|
|
43356
43590
|
"pipelineAnalytics.listRecentTracks": [{
|
|
43357
43591
|
name: "deviceIds",
|
|
43358
43592
|
form: "array",
|
package/dist/addon.mjs
CHANGED
|
@@ -20,7 +20,7 @@ import * as net2 from "net";
|
|
|
20
20
|
import netImpl from "net";
|
|
21
21
|
import { mkdir } from "fs/promises";
|
|
22
22
|
import os from "node:os";
|
|
23
|
-
//#region ../types/dist/event-category-
|
|
23
|
+
//#region ../types/dist/event-category-ZyX6jcse.mjs
|
|
24
24
|
var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
25
25
|
EventCategory["SystemBoot"] = "system.boot";
|
|
26
26
|
EventCategory["SystemAddonsReady"] = "system.addons-ready";
|
|
@@ -581,7 +581,7 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
|
581
581
|
* a package zone — a newly-appeared stationary object of a package class
|
|
582
582
|
* that cleared the class / zone / dwell / size gates. Payload:
|
|
583
583
|
* `PipelineAnalyticsPackageDeliveredPayload` carrying `{ deviceId,
|
|
584
|
-
* entryId, className, zoneIds,
|
|
584
|
+
* entryId, className, zoneIds, keyFrameMediaId?, bbox, timestamp }`.
|
|
585
585
|
* Telemetry (D8): the durable record is the `package-events` store row;
|
|
586
586
|
* this bus topic drives notifier rules + live UI. See
|
|
587
587
|
* docs/superpowers/specs/2026-07-17-package-zones-design.md §5.1.
|
|
@@ -5367,7 +5367,7 @@ var ZodIssueCode = {
|
|
|
5367
5367
|
var ZodFirstPartyTypeKind;
|
|
5368
5368
|
ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
|
|
5369
5369
|
//#endregion
|
|
5370
|
-
//#region ../types/dist/sleep-
|
|
5370
|
+
//#region ../types/dist/sleep-DBKu2-U5.mjs
|
|
5371
5371
|
/**
|
|
5372
5372
|
* The audio chunk plane's byte format, and the ONE expansion from a coded
|
|
5373
5373
|
* window to float samples (D455).
|
|
@@ -7346,13 +7346,30 @@ new Set([
|
|
|
7346
7346
|
"scene",
|
|
7347
7347
|
"motion",
|
|
7348
7348
|
"object",
|
|
7349
|
-
"audio"
|
|
7349
|
+
"audio",
|
|
7350
|
+
"mosaic"
|
|
7350
7351
|
]);
|
|
7351
|
-
|
|
7352
|
+
/**
|
|
7353
|
+
* The owner types that are event tables, in the order the event-media resolver
|
|
7354
|
+
* should consider them. Exported so a consumer asking "is this key an event?"
|
|
7355
|
+
* does not re-spell the list and drift from it.
|
|
7356
|
+
*/
|
|
7357
|
+
var EVENT_OWNER_TYPES = [
|
|
7352
7358
|
"motion",
|
|
7353
7359
|
"object",
|
|
7354
7360
|
"audio"
|
|
7355
|
-
]
|
|
7361
|
+
];
|
|
7362
|
+
/**
|
|
7363
|
+
* The same list as a Zod enum, for the cap inputs that must NAME the table
|
|
7364
|
+
* (D482: `getEventMedia` / `listEventMedia` take an owner, and an owner is
|
|
7365
|
+
* `(table, id)`).
|
|
7366
|
+
*
|
|
7367
|
+
* Built FROM {@link EVENT_OWNER_TYPES} rather than re-spelled: a fourth event
|
|
7368
|
+
* table would otherwise be accepted by the codec and refused at the door, with
|
|
7369
|
+
* nothing failing until a caller asked.
|
|
7370
|
+
*/
|
|
7371
|
+
var EventOwnerTypeSchema = _enum(EVENT_OWNER_TYPES);
|
|
7372
|
+
new Set(EVENT_OWNER_TYPES);
|
|
7356
7373
|
var EncodeProfileSchema = object({
|
|
7357
7374
|
video: object({
|
|
7358
7375
|
codec: _enum([
|
|
@@ -7391,7 +7408,23 @@ var EncodeProfileSchema = object({
|
|
|
7391
7408
|
"zerolatency",
|
|
7392
7409
|
"film",
|
|
7393
7410
|
"animation"
|
|
7394
|
-
]).optional()
|
|
7411
|
+
]).optional(),
|
|
7412
|
+
/**
|
|
7413
|
+
* ONE slice per access unit.
|
|
7414
|
+
*
|
|
7415
|
+
* `-tune zerolatency` turns on x264's sliced threads, and a frame then leaves
|
|
7416
|
+
* the encoder as five NAL slices that share one RTP timestamp and carry one
|
|
7417
|
+
* marker bit. A libwebrtc depacketiser sees five frame-starts and one
|
|
7418
|
+
* frame-end per frame: the first pictures render and the video then freezes
|
|
7419
|
+
* for good while the audio, on its own plane, plays on. Measured on this hub
|
|
7420
|
+
* 2026-09-13 against the Echo, and reduced to one slice by this flag alone.
|
|
7421
|
+
*
|
|
7422
|
+
* A NAMED field and not a raw flag, because {@link EgressEncodeSchema} omits
|
|
7423
|
+
* `outputArgs` on purpose: an opaque array is part of the sharing key, so two
|
|
7424
|
+
* consumers meaning the same thing spelled differently would stop sharing one
|
|
7425
|
+
* child. Absent means "whatever the encoder does" — today's behaviour.
|
|
7426
|
+
*/
|
|
7427
|
+
singleSlicePerFrame: boolean().optional()
|
|
7395
7428
|
}),
|
|
7396
7429
|
audio: union([literal("passthrough"), object({
|
|
7397
7430
|
codec: _enum([
|
|
@@ -7441,7 +7474,7 @@ var BASE_LIVE_EGRESS_PROFILE = {
|
|
|
7441
7474
|
audio: "passthrough"
|
|
7442
7475
|
};
|
|
7443
7476
|
({ ...BASE_LIVE_EGRESS_PROFILE }), { ...BASE_LIVE_EGRESS_PROFILE.video };
|
|
7444
|
-
({ ...BASE_LIVE_EGRESS_PROFILE });
|
|
7477
|
+
({ ...BASE_LIVE_EGRESS_PROFILE }), { ...BASE_LIVE_EGRESS_PROFILE.video };
|
|
7445
7478
|
/**
|
|
7446
7479
|
* Deep wiring healthcheck — snapshot of active reachability probes across
|
|
7447
7480
|
* every declared capability + widget of every installed plugin, on every
|
|
@@ -13117,6 +13150,16 @@ method(object({
|
|
|
13117
13150
|
filter: QueryFilterSchema.optional(),
|
|
13118
13151
|
columns: array(string()).readonly().optional()
|
|
13119
13152
|
}), array(SettingsRecordSchema).readonly()), method(object({
|
|
13153
|
+
namespace: string().optional(),
|
|
13154
|
+
collection: string(),
|
|
13155
|
+
/** Declared columns identifying the slot; must be covered by a UNIQUE
|
|
13156
|
+
* index on the collection. Never empty. */
|
|
13157
|
+
conflict: array(string()).readonly(),
|
|
13158
|
+
record: BulkRecordSchema
|
|
13159
|
+
}), object({
|
|
13160
|
+
/** The id the row HAS: assigned by SQLite on an insert, or the existing
|
|
13161
|
+
* row's own id on an update. */
|
|
13162
|
+
id: union([string(), number()]) }), { kind: "mutation" }), method(object({
|
|
13120
13163
|
namespace: string().optional(),
|
|
13121
13164
|
collection: string(),
|
|
13122
13165
|
record: object({
|
|
@@ -13251,6 +13294,14 @@ method(_void(), EngineInfoSchema, { auth: "admin" }), method(object({
|
|
|
13251
13294
|
id: union([string(), number()]) }), {
|
|
13252
13295
|
kind: "mutation",
|
|
13253
13296
|
auth: "admin"
|
|
13297
|
+
}), method(object({
|
|
13298
|
+
namespace: string().optional(),
|
|
13299
|
+
collection: string(),
|
|
13300
|
+
conflict: array(string()).readonly(),
|
|
13301
|
+
record: BulkRecordSchema
|
|
13302
|
+
}), object({ id: union([string(), number()]) }), {
|
|
13303
|
+
kind: "mutation",
|
|
13304
|
+
auth: "admin"
|
|
13254
13305
|
}), method(object({
|
|
13255
13306
|
namespace: string().optional(),
|
|
13256
13307
|
collection: string(),
|
|
@@ -19773,8 +19824,8 @@ var TrackPositionSchema = object({
|
|
|
19773
19824
|
var TrackSnapshotSchema = object({
|
|
19774
19825
|
timestamp: number(),
|
|
19775
19826
|
position: TrackPositionSchema,
|
|
19776
|
-
/**
|
|
19777
|
-
|
|
19827
|
+
/** The snapshot's media row id (D482); resolve via `listTrackMedia({ trackId })`. */
|
|
19828
|
+
mediaId: number().int()
|
|
19778
19829
|
});
|
|
19779
19830
|
/**
|
|
19780
19831
|
* Normalized 0..1 trajectory envelope (min/max over every position bbox,
|
|
@@ -20378,14 +20429,14 @@ var ObjectEventSchema = object({
|
|
|
20378
20429
|
* pixel-space `bbox` onto a displayed image. Omitted in slim projection. */
|
|
20379
20430
|
frameWidth: number().optional(),
|
|
20380
20431
|
frameHeight: number().optional(),
|
|
20381
|
-
/**
|
|
20382
|
-
|
|
20383
|
-
/** Design B:
|
|
20432
|
+
/** Media row id of the crop attached to this event (if any) — D482. */
|
|
20433
|
+
mediaId: number().int().optional(),
|
|
20434
|
+
/** Design B: media row id of the track's native-resolution key frame (the
|
|
20384
20435
|
* best-detection full frame). Resolve via the event-media data-plane
|
|
20385
|
-
* (`/addon/<addonId>/event-media/<
|
|
20436
|
+
* (`/addon/<addonId>/event-media/m/<keyFrameMediaId>`) for a detail view that
|
|
20386
20437
|
* draws `bbox` over the native frame. Absent on legacy rows / non-decoded
|
|
20387
|
-
* sources — consumers fall back to `
|
|
20388
|
-
|
|
20438
|
+
* sources — consumers fall back to `mediaId` (the tight crop). */
|
|
20439
|
+
keyFrameMediaId: number().int().optional(),
|
|
20389
20440
|
/** Populated by B5 (recording playback URL for this event). */
|
|
20390
20441
|
mediaUrl: string().optional(),
|
|
20391
20442
|
/** The parent track's key-event importance [0,1], propagated to every object
|
|
@@ -20435,7 +20486,7 @@ var MediaFileKindEnum = _enum([
|
|
|
20435
20486
|
* hub-main's heap on the way past — for an `<img>` that would have cached it.
|
|
20436
20487
|
*
|
|
20437
20488
|
* `url` points at the `event-media` data plane
|
|
20438
|
-
* (`/addon/<addonId>/event-media/<
|
|
20489
|
+
* (`/addon/<addonId>/event-media/m/<mediaId>` — D482), which serves the same blob
|
|
20439
20490
|
* with an ETag and `Cache-Control: immutable`, honours conditional GETs, can
|
|
20440
20491
|
* render a `?variant=thumb`, and streams. The hub gate in front of it requires
|
|
20441
20492
|
* a bearer or the session cookie (`access: 'authenticated'`), so the bytes are
|
|
@@ -20443,10 +20494,13 @@ var MediaFileKindEnum = _enum([
|
|
|
20443
20494
|
* `data-plane-access.ts` for the rule and the one gap it does not close
|
|
20444
20495
|
* (per-device scoping).
|
|
20445
20496
|
*
|
|
20446
|
-
* The URL is built from the row's
|
|
20447
|
-
*
|
|
20497
|
+
* The URL is built from the row's own id, which since D482 says nothing about
|
|
20498
|
+
* the row's owner or kind — and that is the point. The published `kind` is not
|
|
20499
|
+
* the stored one (a track's face/plate crop is stored as `crop` under
|
|
20448
20500
|
* `('face'|'plate', '<prefix>-<trackId>')` and published as
|
|
20449
|
-
* `faceCrop`/`plateCrop
|
|
20501
|
+
* `faceCrop`/`plateCrop`), and under the old composite key the URL had to be
|
|
20502
|
+
* taken from `row.key` verbatim or it 404'd exactly those two rows. An id
|
|
20503
|
+
* cannot be mis-reconstructed, because there is nothing in it to reconstruct.
|
|
20450
20504
|
*
|
|
20451
20505
|
* ## `base64` is TRANSITIONAL and is going away
|
|
20452
20506
|
*
|
|
@@ -20459,7 +20513,19 @@ var MediaFileKindEnum = _enum([
|
|
|
20459
20513
|
* `analytics-query-facade.ts`; nothing else reads it.
|
|
20460
20514
|
*/
|
|
20461
20515
|
var MediaFileSchema = object({
|
|
20462
|
-
|
|
20516
|
+
/**
|
|
20517
|
+
* The media row's OWN id — the rowid SQLite assigned it (D482).
|
|
20518
|
+
*
|
|
20519
|
+
* It used to be the row's composite key, `<ownerType>:<ownerId>:<fileKind>
|
|
20520
|
+
* [:<timestampMs>]`, which embedded a FOREIGN id. D474 made event ids
|
|
20521
|
+
* per-table rowid aliases, so `object:101314` and `motion:101314` are two
|
|
20522
|
+
* different rows that spell the same number, and a track whose
|
|
20523
|
+
* `bestEventId` was an object event was served a motion event's snapshot —
|
|
20524
|
+
* a night-time thumbnail on an afternoon track, with no error anywhere. A
|
|
20525
|
+
* surrogate id cannot name the wrong row's owner, because it names no owner
|
|
20526
|
+
* at all.
|
|
20527
|
+
*/
|
|
20528
|
+
mediaId: number().int(),
|
|
20463
20529
|
kind: MediaFileKindEnum,
|
|
20464
20530
|
sizeBytes: number(),
|
|
20465
20531
|
timestamp: number()
|
|
@@ -20567,7 +20633,7 @@ var RetrainTrackSchema = object({
|
|
|
20567
20633
|
});
|
|
20568
20634
|
/** A frame the picker may offer — an index row, no blob was read to produce it. */
|
|
20569
20635
|
var RetrainFrameCandidateSchema = object({
|
|
20570
|
-
|
|
20636
|
+
mediaId: number().int(),
|
|
20571
20637
|
kind: MediaFileKindEnum,
|
|
20572
20638
|
timestamp: number(),
|
|
20573
20639
|
sizeBytes: number().int(),
|
|
@@ -20581,7 +20647,7 @@ var RetrainFrameSchema = object({
|
|
|
20581
20647
|
deviceId: number(),
|
|
20582
20648
|
trackId: string(),
|
|
20583
20649
|
/** Provenance only. It may already point at nothing — that is expected. */
|
|
20584
|
-
|
|
20650
|
+
sourceMediaId: number().int(),
|
|
20585
20651
|
sourceKind: MediaFileKindEnum,
|
|
20586
20652
|
sizeBytes: number().int(),
|
|
20587
20653
|
width: number().int(),
|
|
@@ -20597,7 +20663,7 @@ var RetrainCopyRefusalSchema = _enum([
|
|
|
20597
20663
|
var RetrainFrameSelectionSchema = object({
|
|
20598
20664
|
copied: array(RetrainFrameSchema).readonly(),
|
|
20599
20665
|
refused: array(object({
|
|
20600
|
-
|
|
20666
|
+
sourceMediaId: number().int(),
|
|
20601
20667
|
reason: RetrainCopyRefusalSchema
|
|
20602
20668
|
})).readonly()
|
|
20603
20669
|
});
|
|
@@ -20605,7 +20671,7 @@ var RetrainFrameListSchema = object({
|
|
|
20605
20671
|
candidates: array(RetrainFrameCandidateSchema).readonly(),
|
|
20606
20672
|
copies: array(RetrainFrameSchema).readonly(),
|
|
20607
20673
|
/** What the page pre-selects — the native key frame when one survives. */
|
|
20608
|
-
|
|
20674
|
+
autoPickMediaId: number().int().optional()
|
|
20609
20675
|
});
|
|
20610
20676
|
/** What the operator asked the assist to look for. */
|
|
20611
20677
|
var RetrainAssistSubjectSchema = discriminatedUnion("kind", [object({
|
|
@@ -20700,9 +20766,11 @@ var RecentTracksQueryInput = object({
|
|
|
20700
20766
|
});
|
|
20701
20767
|
/**
|
|
20702
20768
|
* A Summary (D359): the per-camera session envelope that references tracks.
|
|
20703
|
-
* `
|
|
20704
|
-
* served by the event-media plane
|
|
20705
|
-
* member visible has been materialised
|
|
20769
|
+
* `groupShotMediaId` is the media ROW id of its group shot (`ownerKind:
|
|
20770
|
+
* 'summary'`, served by the event-media plane at `/m/<id>`), null until the
|
|
20771
|
+
* first frame with a member visible has been materialised (D482 — it was the
|
|
20772
|
+
* row's composite key, which embedded the owner and could name another table's
|
|
20773
|
+
* row once event ids became per-table rowids).
|
|
20706
20774
|
*/
|
|
20707
20775
|
var SummarySchema = object({
|
|
20708
20776
|
id: string(),
|
|
@@ -20711,19 +20779,115 @@ var SummarySchema = object({
|
|
|
20711
20779
|
lastActiveAt: number(),
|
|
20712
20780
|
sealedAt: number().nullable(),
|
|
20713
20781
|
memberCount: number().int().nonnegative(),
|
|
20714
|
-
|
|
20782
|
+
groupShotMediaId: number().int().nullable()
|
|
20715
20783
|
});
|
|
20716
20784
|
var SummariesQueryInput = object({
|
|
20717
20785
|
deviceIds: array(number()).min(1),
|
|
20718
20786
|
since: number().optional(),
|
|
20719
20787
|
until: number().optional(),
|
|
20720
|
-
limit: number().int().min(1).max(200).default(50)
|
|
20788
|
+
limit: number().int().min(1).max(200).default(50),
|
|
20789
|
+
/** The same member-wise filter {@link listRecentSummaries} takes — one
|
|
20790
|
+
* meaning of "dog" on every summary surface. */
|
|
20791
|
+
classes: array(string().min(1).max(60)).max(40).optional()
|
|
20721
20792
|
});
|
|
20722
|
-
var SummariesPageSchema = object({ summaries: array(SummarySchema).readonly() });
|
|
20723
20793
|
var SummaryDetailSchema = object({
|
|
20724
20794
|
summary: SummarySchema,
|
|
20725
|
-
/**
|
|
20726
|
-
|
|
20795
|
+
/** Members in absorption order, oldest join first. */
|
|
20796
|
+
members: array(object({
|
|
20797
|
+
trackId: string(),
|
|
20798
|
+
/**
|
|
20799
|
+
* The track's class at the time it JOINED, or `null` when it was unresolved
|
|
20800
|
+
* and the track no longer exists to fill it.
|
|
20801
|
+
*
|
|
20802
|
+
* The join, not the latest opinion: class voting can re-decide a track's
|
|
20803
|
+
* class afterwards, and a group's composition is the history of who came
|
|
20804
|
+
* together. A consumer counts these to badge a thumbnail — "two people and a
|
|
20805
|
+
* dog" — rather than being handed a second, denormalised tally that would
|
|
20806
|
+
* drift from the members it claims to describe.
|
|
20807
|
+
*/
|
|
20808
|
+
className: string().nullable(),
|
|
20809
|
+
/** `primary` is the one member that carries the group's identity. */
|
|
20810
|
+
role: _enum([
|
|
20811
|
+
"primary",
|
|
20812
|
+
"sibling",
|
|
20813
|
+
"child"
|
|
20814
|
+
]).nullable(),
|
|
20815
|
+
joinedAt: number(),
|
|
20816
|
+
/** Tier 1 — the sub-class (`dog`, `van`), resolved from the member's track
|
|
20817
|
+
* at read time. Absent when nothing resolved, never an empty string. */
|
|
20818
|
+
label: string().optional(),
|
|
20819
|
+
/** Tier 2 — the instance: a person's name, a plate. Absent when the pipeline
|
|
20820
|
+
* recognised nobody, and absent for a member whose track has been pruned —
|
|
20821
|
+
* a thumbnail that names the wrong person is worse than one naming nobody. */
|
|
20822
|
+
subLabel: string().optional()
|
|
20823
|
+
})).readonly()
|
|
20824
|
+
});
|
|
20825
|
+
/**
|
|
20826
|
+
* What a LIST of groups carries: the envelope plus what it is MADE OF.
|
|
20827
|
+
*
|
|
20828
|
+
* Coarse on purpose — the operator's rule is "only the rough data on the list,
|
|
20829
|
+
* we extend when we notice we need more". Enough to draw the card ("two people
|
|
20830
|
+
* and a dog") and no more. The MEMBERS, their names and the per-member links
|
|
20831
|
+
* are on {@link getSummary}: shipping every member of every group so a client
|
|
20832
|
+
* can count them turns a page of two hundred groups into a thousand records to
|
|
20833
|
+
* draw two hundred badges.
|
|
20834
|
+
*/
|
|
20835
|
+
var SummaryListItemSchema = object({
|
|
20836
|
+
summary: SummarySchema,
|
|
20837
|
+
/** Class counts, most numerous first; `className: null` is a member whose
|
|
20838
|
+
* class never resolved, counted so the counts add up to `memberCount`. */
|
|
20839
|
+
classes: array(object({
|
|
20840
|
+
className: string().nullable(),
|
|
20841
|
+
count: number().int().positive()
|
|
20842
|
+
})).readonly()
|
|
20843
|
+
});
|
|
20844
|
+
var SummariesPageSchema = object({ summaries: array(SummaryListItemSchema).readonly() });
|
|
20845
|
+
/**
|
|
20846
|
+
* The paged feed, deliberately the SAME shape as {@link RecentTracksQueryInput}.
|
|
20847
|
+
*
|
|
20848
|
+
* The reel on the cameras page and the Events gallery both ride a cursor, so a
|
|
20849
|
+
* summaries feed that could only answer "the last N for these cameras"
|
|
20850
|
+
* (`listSummaries`) would make groups available in the timeline and nowhere
|
|
20851
|
+
* else. Two feeds with different ordering contracts would be two ideas of what
|
|
20852
|
+
* "newest" means, on one screen.
|
|
20853
|
+
*/
|
|
20854
|
+
var RecentSummariesQueryInput = object({
|
|
20855
|
+
/** Devices to merge. An empty array yields an empty page. */
|
|
20856
|
+
deviceIds: array(number()),
|
|
20857
|
+
/** Window lower bound on `lastActiveAt` (inclusive). */
|
|
20858
|
+
since: number().optional(),
|
|
20859
|
+
/** Window upper bound on `lastActiveAt` (inclusive). */
|
|
20860
|
+
until: number().optional(),
|
|
20861
|
+
limit: number().int().min(1).max(500).default(100),
|
|
20862
|
+
/** Opaque continuation cursor from a previous page's `nextCursor`. */
|
|
20863
|
+
cursor: string().optional(),
|
|
20864
|
+
/**
|
|
20865
|
+
* Restrict to these classes — THE SAME FIELD `listRecentTracks` takes, and
|
|
20866
|
+
* deliberately the same name: the events filter tree emits one list of ticked
|
|
20867
|
+
* taxonomy nodes, and a summaries feed that called it something else would
|
|
20868
|
+
* make the operator's one filter component produce two shapes.
|
|
20869
|
+
*
|
|
20870
|
+
* A question about the MEMBERS: a group matches when ANY of them does. "Show
|
|
20871
|
+
* me the arrivals with a dog" has to return the group of four people who had
|
|
20872
|
+
* one with them; a filter on the group's own fields could only ever answer
|
|
20873
|
+
* about its primary.
|
|
20874
|
+
*
|
|
20875
|
+
* Matched against all THREE tiers of a member — the class (`animal`), the
|
|
20876
|
+
* sub-class (`dog`) and the instance (a name, a plate) — because which tier a
|
|
20877
|
+
* ticked node lives on is the taxonomy's business, not the caller's. `dog` is
|
|
20878
|
+
* an event kind in the tree and a tier-1 label on an `animal` track; a filter
|
|
20879
|
+
* that read only the class would answer "animal" and never "dog".
|
|
20880
|
+
*
|
|
20881
|
+
* ABSENT or EMPTY means no filter — absent is not a selection of none.
|
|
20882
|
+
*/
|
|
20883
|
+
classes: array(string().min(1).max(60)).max(40).optional()
|
|
20884
|
+
});
|
|
20885
|
+
var RecentSummariesPageSchema = object({
|
|
20886
|
+
/** Ordered by (`lastActiveAt` DESC, id DESC). Same light item as
|
|
20887
|
+
* {@link listSummaries} — one list shape, so a card renders the same
|
|
20888
|
+
* whichever feed drew it. */
|
|
20889
|
+
summaries: array(SummaryListItemSchema).readonly(),
|
|
20890
|
+
nextCursor: string().nullable()
|
|
20727
20891
|
});
|
|
20728
20892
|
var RecentTracksPageSchema = object({
|
|
20729
20893
|
/** Merged page, ordered by (`lastSeen` DESC, `trackId` DESC). */
|
|
@@ -21137,7 +21301,7 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
|
|
|
21137
21301
|
classes: array(string()).optional(),
|
|
21138
21302
|
/** See {@link ExcludeSourcesDoc}. */
|
|
21139
21303
|
excludeSources: array(TrackSourceSchema).optional()
|
|
21140
|
-
}), array(TrackSchema).readonly()), method(RecentTracksQueryInput, RecentTracksPageSchema), method(SummariesQueryInput, SummariesPageSchema), method(object({ id: string() }), SummaryDetailSchema.nullable()), method(object({ deviceId: number() }), _void(), {
|
|
21304
|
+
}), array(TrackSchema).readonly()), method(RecentTracksQueryInput, RecentTracksPageSchema), method(SummariesQueryInput, SummariesPageSchema), method(RecentSummariesQueryInput, RecentSummariesPageSchema), method(object({ id: string() }), SummaryDetailSchema.nullable()), method(object({ deviceId: number() }), _void(), {
|
|
21141
21305
|
kind: "mutation",
|
|
21142
21306
|
auth: "admin"
|
|
21143
21307
|
}), 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({
|
|
@@ -21265,7 +21429,7 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
|
|
|
21265
21429
|
}), method(object({
|
|
21266
21430
|
deviceId: number(),
|
|
21267
21431
|
trackId: string(),
|
|
21268
|
-
|
|
21432
|
+
mediaIds: array(number().int()).min(1)
|
|
21269
21433
|
}), RetrainFrameSelectionSchema, {
|
|
21270
21434
|
kind: "mutation",
|
|
21271
21435
|
auth: "admin"
|
|
@@ -21333,7 +21497,10 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
|
|
|
21333
21497
|
kind: "query",
|
|
21334
21498
|
auth: "admin"
|
|
21335
21499
|
}), method(object({
|
|
21336
|
-
|
|
21500
|
+
/** Which of the three event tables owns the row. */
|
|
21501
|
+
ownerType: EventOwnerTypeSchema,
|
|
21502
|
+
/** The event's rowid in that table (D474: an event id is a number). */
|
|
21503
|
+
eventId: number().int(),
|
|
21337
21504
|
kind: MediaFileKindEnum.optional(),
|
|
21338
21505
|
deviceId: number()
|
|
21339
21506
|
}), array(MediaFileSchema).readonly()), method(object({
|
|
@@ -21344,7 +21511,8 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
|
|
|
21344
21511
|
trackId: string(),
|
|
21345
21512
|
deviceId: number()
|
|
21346
21513
|
}), array(MediaFileInfoSchema).readonly()), method(object({
|
|
21347
|
-
|
|
21514
|
+
ownerType: EventOwnerTypeSchema,
|
|
21515
|
+
eventId: number().int(),
|
|
21348
21516
|
deviceId: number()
|
|
21349
21517
|
}), array(MediaFileInfoSchema).readonly()), method(SearchObjectEventsInput, array(ScoredObjectEventSchema).readonly()), method(object({}), WipeObjectEmbeddingsResultSchema, {
|
|
21350
21518
|
kind: "mutation",
|
|
@@ -26641,8 +26809,8 @@ var IdentitySchema = object({
|
|
|
26641
26809
|
id: string(),
|
|
26642
26810
|
name: string(),
|
|
26643
26811
|
sampleCount: number().int().nonnegative(),
|
|
26644
|
-
|
|
26645
|
-
/** Inline base64 of the cover sample's crop, resolved from `
|
|
26812
|
+
coverMediaId: number().int().optional(),
|
|
26813
|
+
/** Inline base64 of the cover sample's crop, resolved from `coverMediaId`.
|
|
26646
26814
|
* Lets the UI render the person's face avatar instead of a placeholder icon. */
|
|
26647
26815
|
coverBase64: string().optional()
|
|
26648
26816
|
});
|
|
@@ -26668,8 +26836,8 @@ var IdentitySampleAuditRowSchema = object({
|
|
|
26668
26836
|
enrolledAt: number().int(),
|
|
26669
26837
|
deviceId: number().int().optional(),
|
|
26670
26838
|
source: _enum(["detected", "photo"]),
|
|
26671
|
-
/** The enrolled crop's media
|
|
26672
|
-
|
|
26839
|
+
/** The enrolled crop's media row id, so the panel can show the evidence. */
|
|
26840
|
+
mediaId: number().int().optional(),
|
|
26673
26841
|
/**
|
|
26674
26842
|
* False = the sample is stamped with a DIFFERENT face model, and a cosine
|
|
26675
26843
|
* across feature spaces is a well-formed float with no meaning. Every number
|
|
@@ -26738,15 +26906,15 @@ var FaceInfoSchema = object({
|
|
|
26738
26906
|
*/
|
|
26739
26907
|
cropUrl: string().optional(),
|
|
26740
26908
|
/** Design B: the face bbox (pixel space) on the key frame — lets a detail
|
|
26741
|
-
* view draw the box over the native `
|
|
26909
|
+
* view draw the box over the native `keyFrameMediaId` frame. Absent on
|
|
26742
26910
|
* legacy rows written before design B. */
|
|
26743
26911
|
faceBbox: BoundingBoxSchema.optional(),
|
|
26744
26912
|
/** Design B: MediaStore key of the track's native-resolution key frame.
|
|
26745
26913
|
* Fetch the native JPEG via the event-media data-plane
|
|
26746
|
-
* (`/addon/<addonId>/event-media/<
|
|
26914
|
+
* (`/addon/<addonId>/event-media/m/<keyFrameMediaId>`). Absent when the
|
|
26747
26915
|
* track produced no key frame (e.g. native/onboard source) — the UI falls
|
|
26748
26916
|
* back to the inline `base64` face crop. */
|
|
26749
|
-
|
|
26917
|
+
keyFrameMediaId: number().int().optional(),
|
|
26750
26918
|
/** Winning identity-match cosine (0..1) for this face's track, when an
|
|
26751
26919
|
* identity was auto-confirmed. Lets the UI surface WHY a face was assigned
|
|
26752
26920
|
* (confidence badge / low-confidence audit). Absent on legacy rows and on
|
|
@@ -26815,11 +26983,14 @@ var FaceClusterSchema = object({
|
|
|
26815
26983
|
* `data:image/jpeg;base64,…` from a row whose `key` sat right beside it, in a
|
|
26816
26984
|
* dialog already rendering its key FRAME from the `event-media` plane.
|
|
26817
26985
|
*
|
|
26818
|
-
* `url` is `/addon/<addonId>/event-media/<
|
|
26819
|
-
* media
|
|
26986
|
+
* `url` is `/addon/<addonId>/event-media/m/<mediaId>` (D482). The plane
|
|
26987
|
+
* resolves a media row by its own id, so this needed no new plane and no new
|
|
26988
|
+
* access decision.
|
|
26820
26989
|
*/
|
|
26821
26990
|
var MediaFileLiteSchema$1 = object({
|
|
26822
|
-
|
|
26991
|
+
/** The media row's own id — the same address `MediaFileRef.mediaId` carries
|
|
26992
|
+
* (D482). It was the row's composite key, which embedded the owner. */
|
|
26993
|
+
mediaId: number().int(),
|
|
26823
26994
|
kind: string(),
|
|
26824
26995
|
url: string(),
|
|
26825
26996
|
sizeBytes: number(),
|
|
@@ -26836,7 +27007,7 @@ method(object({
|
|
|
26836
27007
|
* covers inline, ~10 KB of base64 per row, on a query this UI mounts
|
|
26837
27008
|
* four times and the viewer holds at `staleTime: 30_000`.
|
|
26838
27009
|
*
|
|
26839
|
-
* Nothing loses its avatar: `
|
|
27010
|
+
* Nothing loses its avatar: `coverMediaId` is already on every row and
|
|
26840
27011
|
* the `event-media` plane serves that key `immutable` with an ETag.
|
|
26841
27012
|
*
|
|
26842
27013
|
* **This is an INPUT field, so it does not reach the addon until the
|
|
@@ -30219,8 +30390,8 @@ var VehicleSchema = object({
|
|
|
30219
30390
|
id: string(),
|
|
30220
30391
|
name: string(),
|
|
30221
30392
|
sampleCount: number().int().nonnegative(),
|
|
30222
|
-
|
|
30223
|
-
/** Inline base64 of the cover sample's plate crop, resolved from `
|
|
30393
|
+
coverMediaId: number().int().optional(),
|
|
30394
|
+
/** Inline base64 of the cover sample's plate crop, resolved from `coverMediaId`. */
|
|
30224
30395
|
coverBase64: string().optional()
|
|
30225
30396
|
});
|
|
30226
30397
|
var VehicleSampleInfoSchema = object({
|
|
@@ -30253,7 +30424,7 @@ var PlateInfoSchema = object({
|
|
|
30253
30424
|
/** keyFrame parity: the plate bbox (pixel space) on the native key frame. */
|
|
30254
30425
|
plateBbox: BoundingBoxSchema.optional(),
|
|
30255
30426
|
/** keyFrame parity: MediaStore key of the track's native-resolution key frame. */
|
|
30256
|
-
|
|
30427
|
+
keyFrameMediaId: number().int().optional(),
|
|
30257
30428
|
base64: string().optional(),
|
|
30258
30429
|
/**
|
|
30259
30430
|
* Same crop as a data-plane URL, always present when the plate has a stored
|
|
@@ -30274,11 +30445,14 @@ var PlateInfoSchema = object({
|
|
|
30274
30445
|
* `data:image/jpeg;base64,…` from a row whose `key` sat right beside it, in a
|
|
30275
30446
|
* dialog already rendering its key FRAME from the `event-media` plane.
|
|
30276
30447
|
*
|
|
30277
|
-
* `url` is `/addon/<addonId>/event-media/<
|
|
30278
|
-
* media
|
|
30448
|
+
* `url` is `/addon/<addonId>/event-media/m/<mediaId>` (D482). The plane
|
|
30449
|
+
* resolves a media row by its own id, so this needed no new plane and no new
|
|
30450
|
+
* access decision.
|
|
30279
30451
|
*/
|
|
30280
30452
|
var MediaFileLiteSchema = object({
|
|
30281
|
-
|
|
30453
|
+
/** The media row's own id — the same address `MediaFileRef.mediaId` carries
|
|
30454
|
+
* (D482). It was the row's composite key, which embedded the owner. */
|
|
30455
|
+
mediaId: number().int(),
|
|
30282
30456
|
kind: string(),
|
|
30283
30457
|
url: string(),
|
|
30284
30458
|
sizeBytes: number(),
|
|
@@ -30337,7 +30511,7 @@ method(object({
|
|
|
30337
30511
|
}), method(object({
|
|
30338
30512
|
/** Inline {@link VehicleSchema.coverBase64} on every row. Default
|
|
30339
30513
|
* `false` — the vehicle twin of `faceGallery.listIdentities`'s
|
|
30340
|
-
* option; `
|
|
30514
|
+
* option; `coverMediaId` + the `event-media` plane carry the picture.
|
|
30341
30515
|
* INPUT field: stripped by the hub router until the train ships, which
|
|
30342
30516
|
* resolves to `false` and is exactly the intended default. */
|
|
30343
30517
|
includeCrops: boolean().optional() }).optional(), array(VehicleSchema).readonly()), method(object({ name: string().min(1) }), VehicleSchema, {
|
|
@@ -31993,7 +32167,14 @@ var SceneReferenceSchema = object({
|
|
|
31993
32167
|
modelId: string(),
|
|
31994
32168
|
condition: SceneConditionSchema,
|
|
31995
32169
|
capturedAt: number(),
|
|
31996
|
-
|
|
32170
|
+
/**
|
|
32171
|
+
* The reference thumbnail's media ROW id (D482).
|
|
32172
|
+
*
|
|
32173
|
+
* The name already said `mediaId` while the value was the row's composite
|
|
32174
|
+
* key — a leftover that read as done and was not. It is the row's own id
|
|
32175
|
+
* now, addressed at `/addon/<addonId>/event-media/m/<id>`.
|
|
32176
|
+
*/
|
|
32177
|
+
thumbnailMediaId: number().int().optional(),
|
|
31997
32178
|
/** Whole-frame (downscaled) embedding captured alongside the ROI crop. The
|
|
31998
32179
|
* anti-view-shift anchor: a bumped camera, a PTZ preset or a re-aim makes the
|
|
31999
32180
|
* normalized rect frame a different piece of world, and the scene would
|
|
@@ -33282,7 +33463,29 @@ var LoggingSettingsPatchSchema = object({
|
|
|
33282
33463
|
* disarmed the channels it did not mention would make the Levels page and
|
|
33283
33464
|
* the Diagnostics page fight over the same value.
|
|
33284
33465
|
*/
|
|
33285
|
-
channels: array(LogChannelWindowPatchSchema).readonly().optional()
|
|
33466
|
+
channels: array(LogChannelWindowPatchSchema).readonly().optional(),
|
|
33467
|
+
/**
|
|
33468
|
+
* How many days the analytics OPS LOG is kept — the audit trail of what
|
|
33469
|
+
* retention actually deleted.
|
|
33470
|
+
*
|
|
33471
|
+
* It lives HERE, on the logging document, and not on the analytics addon's
|
|
33472
|
+
* settings form, on the operator's instruction: every other log-ish window in
|
|
33473
|
+
* this system is configured through this one document, and a retention audit
|
|
33474
|
+
* configured somewhere else is a second place to look when the question is
|
|
33475
|
+
* "what happened to my data".
|
|
33476
|
+
*
|
|
33477
|
+
* That placement has a cost worth stating: this document ships in the
|
|
33478
|
+
* framework closure, so this knob needs a published `@camstack/server` while
|
|
33479
|
+
* the four windows beside it (D485) reach a node on `camstack deploy`.
|
|
33480
|
+
*
|
|
33481
|
+
* `retention-model.ts` argued this one must NOT follow a device window,
|
|
33482
|
+
* because the audit trail is the history of the SWEEP and not of the camera.
|
|
33483
|
+
* That argument stands and is untouched — what changes is that 30 days stops
|
|
33484
|
+
* being a constant nobody can reach. `0` keeps it forever. The floor is 1 day
|
|
33485
|
+
* rather than 0-as-delete: an audit log truncated to nothing is precisely the
|
|
33486
|
+
* state in which the next 9.5 GiB leak cannot be explained.
|
|
33487
|
+
*/
|
|
33488
|
+
opsLogRetentionDays: number().int().min(0).max(3650).optional()
|
|
33286
33489
|
});
|
|
33287
33490
|
/**
|
|
33288
33491
|
* Which LAYER of the hierarchy is addressed. Absent = the cluster layer.
|
|
@@ -33355,6 +33558,14 @@ var LoggingSettingsStateSchema = object({
|
|
|
33355
33558
|
channels: array(LogChannelDescriptorSchema).readonly(),
|
|
33356
33559
|
/** The channels ARMED right now, each with its deadline. */
|
|
33357
33560
|
activeChannels: array(LogChannelWindowStateSchema).readonly(),
|
|
33561
|
+
/**
|
|
33562
|
+
* The ops-log window in days, as it is in force. `0` = kept forever.
|
|
33563
|
+
*
|
|
33564
|
+
* Reported rather than left to the caller's memory of what it wrote: this is
|
|
33565
|
+
* the value the analytics sweep will actually use, and an operator asking how
|
|
33566
|
+
* long their audit trail lives should not have to infer it from a default.
|
|
33567
|
+
*/
|
|
33568
|
+
opsLogRetentionDays: number().int().min(0),
|
|
33358
33569
|
persisted: boolean()
|
|
33359
33570
|
});
|
|
33360
33571
|
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(), {
|
|
@@ -34175,7 +34386,7 @@ var StationaryObjectSchema = object({
|
|
|
34175
34386
|
/** Enrichment label carried from the source track (identity / plate). */
|
|
34176
34387
|
label: string().optional(),
|
|
34177
34388
|
/** Native-resolution key-frame media key for the parked object's best image. */
|
|
34178
|
-
|
|
34389
|
+
keyFrameMediaId: number().int().optional()
|
|
34179
34390
|
});
|
|
34180
34391
|
var CameraOccupancySnapshotSchema = object({
|
|
34181
34392
|
/** Frame timestamp of the inference result that produced this snapshot. */
|
|
@@ -37091,6 +37302,12 @@ Object.freeze({
|
|
|
37091
37302
|
addonId: null,
|
|
37092
37303
|
access: "create"
|
|
37093
37304
|
},
|
|
37305
|
+
"dataStoreProvider.upsert": {
|
|
37306
|
+
capName: "data-store-provider",
|
|
37307
|
+
capScope: "system",
|
|
37308
|
+
addonId: null,
|
|
37309
|
+
access: "create"
|
|
37310
|
+
},
|
|
37094
37311
|
"dayNight.getOptions": {
|
|
37095
37312
|
capName: "day-night",
|
|
37096
37313
|
capScope: "device",
|
|
@@ -39527,6 +39744,12 @@ Object.freeze({
|
|
|
39527
39744
|
addonId: null,
|
|
39528
39745
|
access: "view"
|
|
39529
39746
|
},
|
|
39747
|
+
"pipelineAnalytics.listRecentSummaries": {
|
|
39748
|
+
capName: "pipeline-analytics",
|
|
39749
|
+
capScope: "device",
|
|
39750
|
+
addonId: null,
|
|
39751
|
+
access: "view"
|
|
39752
|
+
},
|
|
39530
39753
|
"pipelineAnalytics.listRecentTracks": {
|
|
39531
39754
|
capName: "pipeline-analytics",
|
|
39532
39755
|
capScope: "device",
|
|
@@ -40955,6 +41178,12 @@ Object.freeze({
|
|
|
40955
41178
|
addonId: null,
|
|
40956
41179
|
access: "create"
|
|
40957
41180
|
},
|
|
41181
|
+
"settingsStore.upsert": {
|
|
41182
|
+
capName: "settings-store",
|
|
41183
|
+
capScope: "system",
|
|
41184
|
+
addonId: null,
|
|
41185
|
+
access: "create"
|
|
41186
|
+
},
|
|
40958
41187
|
"smtpProvider.getStatus": {
|
|
40959
41188
|
capName: "smtp-provider",
|
|
40960
41189
|
capScope: "system",
|
|
@@ -43348,6 +43577,11 @@ Object.freeze({
|
|
|
43348
43577
|
form: "single",
|
|
43349
43578
|
optional: true
|
|
43350
43579
|
}],
|
|
43580
|
+
"pipelineAnalytics.listRecentSummaries": [{
|
|
43581
|
+
name: "deviceIds",
|
|
43582
|
+
form: "array",
|
|
43583
|
+
optional: false
|
|
43584
|
+
}],
|
|
43351
43585
|
"pipelineAnalytics.listRecentTracks": [{
|
|
43352
43586
|
name: "deviceIds",
|
|
43353
43587
|
form: "array",
|