@camstack/addon-export-alexa 1.2.105 → 1.2.107
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/export-alexa.addon.js +300 -57
- package/dist/export-alexa.addon.mjs +300 -57
- package/package.json +1 -1
|
@@ -26,7 +26,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
26
26
|
//#endregion
|
|
27
27
|
let node_crypto = require("node:crypto");
|
|
28
28
|
node_crypto = __toESM(node_crypto);
|
|
29
|
-
//#region ../types/dist/event-category-
|
|
29
|
+
//#region ../types/dist/event-category-ZyX6jcse.mjs
|
|
30
30
|
var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
31
31
|
EventCategory["SystemBoot"] = "system.boot";
|
|
32
32
|
EventCategory["SystemAddonsReady"] = "system.addons-ready";
|
|
@@ -587,7 +587,7 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
|
587
587
|
* a package zone — a newly-appeared stationary object of a package class
|
|
588
588
|
* that cleared the class / zone / dwell / size gates. Payload:
|
|
589
589
|
* `PipelineAnalyticsPackageDeliveredPayload` carrying `{ deviceId,
|
|
590
|
-
* entryId, className, zoneIds,
|
|
590
|
+
* entryId, className, zoneIds, keyFrameMediaId?, bbox, timestamp }`.
|
|
591
591
|
* Telemetry (D8): the durable record is the `package-events` store row;
|
|
592
592
|
* this bus topic drives notifier rules + live UI. See
|
|
593
593
|
* docs/superpowers/specs/2026-07-17-package-zones-design.md §5.1.
|
|
@@ -5373,7 +5373,7 @@ var ZodIssueCode = {
|
|
|
5373
5373
|
var ZodFirstPartyTypeKind;
|
|
5374
5374
|
ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
|
|
5375
5375
|
//#endregion
|
|
5376
|
-
//#region ../types/dist/sleep-
|
|
5376
|
+
//#region ../types/dist/sleep-DBKu2-U5.mjs
|
|
5377
5377
|
/**
|
|
5378
5378
|
* The audio chunk plane's byte format, and the ONE expansion from a coded
|
|
5379
5379
|
* window to float samples (D455).
|
|
@@ -7336,13 +7336,30 @@ new Set([
|
|
|
7336
7336
|
"scene",
|
|
7337
7337
|
"motion",
|
|
7338
7338
|
"object",
|
|
7339
|
-
"audio"
|
|
7339
|
+
"audio",
|
|
7340
|
+
"mosaic"
|
|
7340
7341
|
]);
|
|
7341
|
-
|
|
7342
|
+
/**
|
|
7343
|
+
* The owner types that are event tables, in the order the event-media resolver
|
|
7344
|
+
* should consider them. Exported so a consumer asking "is this key an event?"
|
|
7345
|
+
* does not re-spell the list and drift from it.
|
|
7346
|
+
*/
|
|
7347
|
+
var EVENT_OWNER_TYPES = [
|
|
7342
7348
|
"motion",
|
|
7343
7349
|
"object",
|
|
7344
7350
|
"audio"
|
|
7345
|
-
]
|
|
7351
|
+
];
|
|
7352
|
+
/**
|
|
7353
|
+
* The same list as a Zod enum, for the cap inputs that must NAME the table
|
|
7354
|
+
* (D482: `getEventMedia` / `listEventMedia` take an owner, and an owner is
|
|
7355
|
+
* `(table, id)`).
|
|
7356
|
+
*
|
|
7357
|
+
* Built FROM {@link EVENT_OWNER_TYPES} rather than re-spelled: a fourth event
|
|
7358
|
+
* table would otherwise be accepted by the codec and refused at the door, with
|
|
7359
|
+
* nothing failing until a caller asked.
|
|
7360
|
+
*/
|
|
7361
|
+
var EventOwnerTypeSchema = _enum(EVENT_OWNER_TYPES);
|
|
7362
|
+
new Set(EVENT_OWNER_TYPES);
|
|
7346
7363
|
/**
|
|
7347
7364
|
* Build an `IAddonRouteProvider` from a list of routes. Implements
|
|
7348
7365
|
* both the operator-facing `getRoutes` (returning route descriptors
|
|
@@ -7573,7 +7590,32 @@ var BASE_LIVE_EGRESS_PROFILE = {
|
|
|
7573
7590
|
*/
|
|
7574
7591
|
var ALEXA_EGRESS_PROFILE = {
|
|
7575
7592
|
...BASE_LIVE_EGRESS_PROFILE,
|
|
7576
|
-
audio: { codec: "opus" }
|
|
7593
|
+
audio: { codec: "opus" },
|
|
7594
|
+
/**
|
|
7595
|
+
* ONE slice per access unit.
|
|
7596
|
+
*
|
|
7597
|
+
* `-tune zerolatency` turns on x264's sliced threads, and every access unit
|
|
7598
|
+
* came out of this encode as FIVE slices — measured on the hub 2026-09-13 on
|
|
7599
|
+
* the exact argv this path spawns, and reduced to one by this single flag.
|
|
7600
|
+
*
|
|
7601
|
+
* Five slices share one RTP timestamp and carry one marker bit, so a
|
|
7602
|
+
* libwebrtc depacketiser sees five frame-starts and one frame-end per frame.
|
|
7603
|
+
* The Echo renders the first pictures and then freezes for good, while the
|
|
7604
|
+
* audio — a separate plane — plays on. It is the only structural property
|
|
7605
|
+
* that survived the elimination: the same freeze reproduced at 2304×1296
|
|
7606
|
+
* HEVC with 217 KB keyframes AND at 640×360 H.264 with 67 KB keyframes and a
|
|
7607
|
+
* fifth of the bitrate, so source, resolution, bitrate, keyframe burst,
|
|
7608
|
+
* hardware decode, parameter sets, drift and bitstream conformance are all
|
|
7609
|
+
* out — each ruled out by a measurement, not by elimination.
|
|
7610
|
+
*
|
|
7611
|
+
* The tune STAYS: it also drops the lookahead and the B-frames, which a live
|
|
7612
|
+
* path wants. Only the slicing is unwanted, and this is the flag that says so.
|
|
7613
|
+
*
|
|
7614
|
+
* Scoped to Alexa deliberately. HomeKit and the browser transcode inherit
|
|
7615
|
+
* {@link BASE_LIVE_EGRESS_PROFILE}; whether they want the same shape is a
|
|
7616
|
+
* question for their own evidence, and the browser has not been measured.
|
|
7617
|
+
*/
|
|
7618
|
+
outputArgs: ["-x264-params", "sliced-threads=0"]
|
|
7577
7619
|
};
|
|
7578
7620
|
/**
|
|
7579
7621
|
* Deep wiring healthcheck — snapshot of active reachability probes across
|
|
@@ -12684,6 +12726,16 @@ method(object({
|
|
|
12684
12726
|
filter: QueryFilterSchema.optional(),
|
|
12685
12727
|
columns: array(string()).readonly().optional()
|
|
12686
12728
|
}), array(SettingsRecordSchema).readonly()), method(object({
|
|
12729
|
+
namespace: string().optional(),
|
|
12730
|
+
collection: string(),
|
|
12731
|
+
/** Declared columns identifying the slot; must be covered by a UNIQUE
|
|
12732
|
+
* index on the collection. Never empty. */
|
|
12733
|
+
conflict: array(string()).readonly(),
|
|
12734
|
+
record: BulkRecordSchema
|
|
12735
|
+
}), object({
|
|
12736
|
+
/** The id the row HAS: assigned by SQLite on an insert, or the existing
|
|
12737
|
+
* row's own id on an update. */
|
|
12738
|
+
id: union([string(), number()]) }), { kind: "mutation" }), method(object({
|
|
12687
12739
|
namespace: string().optional(),
|
|
12688
12740
|
collection: string(),
|
|
12689
12741
|
record: object({
|
|
@@ -12818,6 +12870,14 @@ method(_void(), EngineInfoSchema, { auth: "admin" }), method(object({
|
|
|
12818
12870
|
id: union([string(), number()]) }), {
|
|
12819
12871
|
kind: "mutation",
|
|
12820
12872
|
auth: "admin"
|
|
12873
|
+
}), method(object({
|
|
12874
|
+
namespace: string().optional(),
|
|
12875
|
+
collection: string(),
|
|
12876
|
+
conflict: array(string()).readonly(),
|
|
12877
|
+
record: BulkRecordSchema
|
|
12878
|
+
}), object({ id: union([string(), number()]) }), {
|
|
12879
|
+
kind: "mutation",
|
|
12880
|
+
auth: "admin"
|
|
12821
12881
|
}), method(object({
|
|
12822
12882
|
namespace: string().optional(),
|
|
12823
12883
|
collection: string(),
|
|
@@ -19075,8 +19135,8 @@ var TrackPositionSchema = object({
|
|
|
19075
19135
|
var TrackSnapshotSchema = object({
|
|
19076
19136
|
timestamp: number(),
|
|
19077
19137
|
position: TrackPositionSchema,
|
|
19078
|
-
/**
|
|
19079
|
-
|
|
19138
|
+
/** The snapshot's media row id (D482); resolve via `listTrackMedia({ trackId })`. */
|
|
19139
|
+
mediaId: number().int()
|
|
19080
19140
|
});
|
|
19081
19141
|
/**
|
|
19082
19142
|
* Normalized 0..1 trajectory envelope (min/max over every position bbox,
|
|
@@ -19680,14 +19740,14 @@ var ObjectEventSchema = object({
|
|
|
19680
19740
|
* pixel-space `bbox` onto a displayed image. Omitted in slim projection. */
|
|
19681
19741
|
frameWidth: number().optional(),
|
|
19682
19742
|
frameHeight: number().optional(),
|
|
19683
|
-
/**
|
|
19684
|
-
|
|
19685
|
-
/** Design B:
|
|
19743
|
+
/** Media row id of the crop attached to this event (if any) — D482. */
|
|
19744
|
+
mediaId: number().int().optional(),
|
|
19745
|
+
/** Design B: media row id of the track's native-resolution key frame (the
|
|
19686
19746
|
* best-detection full frame). Resolve via the event-media data-plane
|
|
19687
|
-
* (`/addon/<addonId>/event-media/<
|
|
19747
|
+
* (`/addon/<addonId>/event-media/m/<keyFrameMediaId>`) for a detail view that
|
|
19688
19748
|
* draws `bbox` over the native frame. Absent on legacy rows / non-decoded
|
|
19689
|
-
* sources — consumers fall back to `
|
|
19690
|
-
|
|
19749
|
+
* sources — consumers fall back to `mediaId` (the tight crop). */
|
|
19750
|
+
keyFrameMediaId: number().int().optional(),
|
|
19691
19751
|
/** Populated by B5 (recording playback URL for this event). */
|
|
19692
19752
|
mediaUrl: string().optional(),
|
|
19693
19753
|
/** The parent track's key-event importance [0,1], propagated to every object
|
|
@@ -19737,7 +19797,7 @@ var MediaFileKindEnum = _enum([
|
|
|
19737
19797
|
* hub-main's heap on the way past — for an `<img>` that would have cached it.
|
|
19738
19798
|
*
|
|
19739
19799
|
* `url` points at the `event-media` data plane
|
|
19740
|
-
* (`/addon/<addonId>/event-media/<
|
|
19800
|
+
* (`/addon/<addonId>/event-media/m/<mediaId>` — D482), which serves the same blob
|
|
19741
19801
|
* with an ETag and `Cache-Control: immutable`, honours conditional GETs, can
|
|
19742
19802
|
* render a `?variant=thumb`, and streams. The hub gate in front of it requires
|
|
19743
19803
|
* a bearer or the session cookie (`access: 'authenticated'`), so the bytes are
|
|
@@ -19745,10 +19805,13 @@ var MediaFileKindEnum = _enum([
|
|
|
19745
19805
|
* `data-plane-access.ts` for the rule and the one gap it does not close
|
|
19746
19806
|
* (per-device scoping).
|
|
19747
19807
|
*
|
|
19748
|
-
* The URL is built from the row's
|
|
19749
|
-
*
|
|
19808
|
+
* The URL is built from the row's own id, which since D482 says nothing about
|
|
19809
|
+
* the row's owner or kind — and that is the point. The published `kind` is not
|
|
19810
|
+
* the stored one (a track's face/plate crop is stored as `crop` under
|
|
19750
19811
|
* `('face'|'plate', '<prefix>-<trackId>')` and published as
|
|
19751
|
-
* `faceCrop`/`plateCrop
|
|
19812
|
+
* `faceCrop`/`plateCrop`), and under the old composite key the URL had to be
|
|
19813
|
+
* taken from `row.key` verbatim or it 404'd exactly those two rows. An id
|
|
19814
|
+
* cannot be mis-reconstructed, because there is nothing in it to reconstruct.
|
|
19752
19815
|
*
|
|
19753
19816
|
* ## `base64` is TRANSITIONAL and is going away
|
|
19754
19817
|
*
|
|
@@ -19761,7 +19824,19 @@ var MediaFileKindEnum = _enum([
|
|
|
19761
19824
|
* `analytics-query-facade.ts`; nothing else reads it.
|
|
19762
19825
|
*/
|
|
19763
19826
|
var MediaFileSchema = object({
|
|
19764
|
-
|
|
19827
|
+
/**
|
|
19828
|
+
* The media row's OWN id — the rowid SQLite assigned it (D482).
|
|
19829
|
+
*
|
|
19830
|
+
* It used to be the row's composite key, `<ownerType>:<ownerId>:<fileKind>
|
|
19831
|
+
* [:<timestampMs>]`, which embedded a FOREIGN id. D474 made event ids
|
|
19832
|
+
* per-table rowid aliases, so `object:101314` and `motion:101314` are two
|
|
19833
|
+
* different rows that spell the same number, and a track whose
|
|
19834
|
+
* `bestEventId` was an object event was served a motion event's snapshot —
|
|
19835
|
+
* a night-time thumbnail on an afternoon track, with no error anywhere. A
|
|
19836
|
+
* surrogate id cannot name the wrong row's owner, because it names no owner
|
|
19837
|
+
* at all.
|
|
19838
|
+
*/
|
|
19839
|
+
mediaId: number().int(),
|
|
19765
19840
|
kind: MediaFileKindEnum,
|
|
19766
19841
|
sizeBytes: number(),
|
|
19767
19842
|
timestamp: number()
|
|
@@ -19869,7 +19944,7 @@ var RetrainTrackSchema = object({
|
|
|
19869
19944
|
});
|
|
19870
19945
|
/** A frame the picker may offer — an index row, no blob was read to produce it. */
|
|
19871
19946
|
var RetrainFrameCandidateSchema = object({
|
|
19872
|
-
|
|
19947
|
+
mediaId: number().int(),
|
|
19873
19948
|
kind: MediaFileKindEnum,
|
|
19874
19949
|
timestamp: number(),
|
|
19875
19950
|
sizeBytes: number().int(),
|
|
@@ -19883,7 +19958,7 @@ var RetrainFrameSchema = object({
|
|
|
19883
19958
|
deviceId: number(),
|
|
19884
19959
|
trackId: string(),
|
|
19885
19960
|
/** Provenance only. It may already point at nothing — that is expected. */
|
|
19886
|
-
|
|
19961
|
+
sourceMediaId: number().int(),
|
|
19887
19962
|
sourceKind: MediaFileKindEnum,
|
|
19888
19963
|
sizeBytes: number().int(),
|
|
19889
19964
|
width: number().int(),
|
|
@@ -19899,7 +19974,7 @@ var RetrainCopyRefusalSchema = _enum([
|
|
|
19899
19974
|
var RetrainFrameSelectionSchema = object({
|
|
19900
19975
|
copied: array(RetrainFrameSchema).readonly(),
|
|
19901
19976
|
refused: array(object({
|
|
19902
|
-
|
|
19977
|
+
sourceMediaId: number().int(),
|
|
19903
19978
|
reason: RetrainCopyRefusalSchema
|
|
19904
19979
|
})).readonly()
|
|
19905
19980
|
});
|
|
@@ -19907,7 +19982,7 @@ var RetrainFrameListSchema = object({
|
|
|
19907
19982
|
candidates: array(RetrainFrameCandidateSchema).readonly(),
|
|
19908
19983
|
copies: array(RetrainFrameSchema).readonly(),
|
|
19909
19984
|
/** What the page pre-selects — the native key frame when one survives. */
|
|
19910
|
-
|
|
19985
|
+
autoPickMediaId: number().int().optional()
|
|
19911
19986
|
});
|
|
19912
19987
|
/** What the operator asked the assist to look for. */
|
|
19913
19988
|
var RetrainAssistSubjectSchema = discriminatedUnion("kind", [object({
|
|
@@ -20002,9 +20077,11 @@ var RecentTracksQueryInput = object({
|
|
|
20002
20077
|
});
|
|
20003
20078
|
/**
|
|
20004
20079
|
* A Summary (D359): the per-camera session envelope that references tracks.
|
|
20005
|
-
* `
|
|
20006
|
-
* served by the event-media plane
|
|
20007
|
-
* member visible has been materialised
|
|
20080
|
+
* `groupShotMediaId` is the media ROW id of its group shot (`ownerKind:
|
|
20081
|
+
* 'summary'`, served by the event-media plane at `/m/<id>`), null until the
|
|
20082
|
+
* first frame with a member visible has been materialised (D482 — it was the
|
|
20083
|
+
* row's composite key, which embedded the owner and could name another table's
|
|
20084
|
+
* row once event ids became per-table rowids).
|
|
20008
20085
|
*/
|
|
20009
20086
|
var SummarySchema = object({
|
|
20010
20087
|
id: string(),
|
|
@@ -20013,19 +20090,115 @@ var SummarySchema = object({
|
|
|
20013
20090
|
lastActiveAt: number(),
|
|
20014
20091
|
sealedAt: number().nullable(),
|
|
20015
20092
|
memberCount: number().int().nonnegative(),
|
|
20016
|
-
|
|
20093
|
+
groupShotMediaId: number().int().nullable()
|
|
20017
20094
|
});
|
|
20018
20095
|
var SummariesQueryInput = object({
|
|
20019
20096
|
deviceIds: array(number()).min(1),
|
|
20020
20097
|
since: number().optional(),
|
|
20021
20098
|
until: number().optional(),
|
|
20022
|
-
limit: number().int().min(1).max(200).default(50)
|
|
20099
|
+
limit: number().int().min(1).max(200).default(50),
|
|
20100
|
+
/** The same member-wise filter {@link listRecentSummaries} takes — one
|
|
20101
|
+
* meaning of "dog" on every summary surface. */
|
|
20102
|
+
classes: array(string().min(1).max(60)).max(40).optional()
|
|
20023
20103
|
});
|
|
20024
|
-
var SummariesPageSchema = object({ summaries: array(SummarySchema).readonly() });
|
|
20025
20104
|
var SummaryDetailSchema = object({
|
|
20026
20105
|
summary: SummarySchema,
|
|
20027
|
-
/**
|
|
20028
|
-
|
|
20106
|
+
/** Members in absorption order, oldest join first. */
|
|
20107
|
+
members: array(object({
|
|
20108
|
+
trackId: string(),
|
|
20109
|
+
/**
|
|
20110
|
+
* The track's class at the time it JOINED, or `null` when it was unresolved
|
|
20111
|
+
* and the track no longer exists to fill it.
|
|
20112
|
+
*
|
|
20113
|
+
* The join, not the latest opinion: class voting can re-decide a track's
|
|
20114
|
+
* class afterwards, and a group's composition is the history of who came
|
|
20115
|
+
* together. A consumer counts these to badge a thumbnail — "two people and a
|
|
20116
|
+
* dog" — rather than being handed a second, denormalised tally that would
|
|
20117
|
+
* drift from the members it claims to describe.
|
|
20118
|
+
*/
|
|
20119
|
+
className: string().nullable(),
|
|
20120
|
+
/** `primary` is the one member that carries the group's identity. */
|
|
20121
|
+
role: _enum([
|
|
20122
|
+
"primary",
|
|
20123
|
+
"sibling",
|
|
20124
|
+
"child"
|
|
20125
|
+
]).nullable(),
|
|
20126
|
+
joinedAt: number(),
|
|
20127
|
+
/** Tier 1 — the sub-class (`dog`, `van`), resolved from the member's track
|
|
20128
|
+
* at read time. Absent when nothing resolved, never an empty string. */
|
|
20129
|
+
label: string().optional(),
|
|
20130
|
+
/** Tier 2 — the instance: a person's name, a plate. Absent when the pipeline
|
|
20131
|
+
* recognised nobody, and absent for a member whose track has been pruned —
|
|
20132
|
+
* a thumbnail that names the wrong person is worse than one naming nobody. */
|
|
20133
|
+
subLabel: string().optional()
|
|
20134
|
+
})).readonly()
|
|
20135
|
+
});
|
|
20136
|
+
/**
|
|
20137
|
+
* What a LIST of groups carries: the envelope plus what it is MADE OF.
|
|
20138
|
+
*
|
|
20139
|
+
* Coarse on purpose — the operator's rule is "only the rough data on the list,
|
|
20140
|
+
* we extend when we notice we need more". Enough to draw the card ("two people
|
|
20141
|
+
* and a dog") and no more. The MEMBERS, their names and the per-member links
|
|
20142
|
+
* are on {@link getSummary}: shipping every member of every group so a client
|
|
20143
|
+
* can count them turns a page of two hundred groups into a thousand records to
|
|
20144
|
+
* draw two hundred badges.
|
|
20145
|
+
*/
|
|
20146
|
+
var SummaryListItemSchema = object({
|
|
20147
|
+
summary: SummarySchema,
|
|
20148
|
+
/** Class counts, most numerous first; `className: null` is a member whose
|
|
20149
|
+
* class never resolved, counted so the counts add up to `memberCount`. */
|
|
20150
|
+
classes: array(object({
|
|
20151
|
+
className: string().nullable(),
|
|
20152
|
+
count: number().int().positive()
|
|
20153
|
+
})).readonly()
|
|
20154
|
+
});
|
|
20155
|
+
var SummariesPageSchema = object({ summaries: array(SummaryListItemSchema).readonly() });
|
|
20156
|
+
/**
|
|
20157
|
+
* The paged feed, deliberately the SAME shape as {@link RecentTracksQueryInput}.
|
|
20158
|
+
*
|
|
20159
|
+
* The reel on the cameras page and the Events gallery both ride a cursor, so a
|
|
20160
|
+
* summaries feed that could only answer "the last N for these cameras"
|
|
20161
|
+
* (`listSummaries`) would make groups available in the timeline and nowhere
|
|
20162
|
+
* else. Two feeds with different ordering contracts would be two ideas of what
|
|
20163
|
+
* "newest" means, on one screen.
|
|
20164
|
+
*/
|
|
20165
|
+
var RecentSummariesQueryInput = object({
|
|
20166
|
+
/** Devices to merge. An empty array yields an empty page. */
|
|
20167
|
+
deviceIds: array(number()),
|
|
20168
|
+
/** Window lower bound on `lastActiveAt` (inclusive). */
|
|
20169
|
+
since: number().optional(),
|
|
20170
|
+
/** Window upper bound on `lastActiveAt` (inclusive). */
|
|
20171
|
+
until: number().optional(),
|
|
20172
|
+
limit: number().int().min(1).max(500).default(100),
|
|
20173
|
+
/** Opaque continuation cursor from a previous page's `nextCursor`. */
|
|
20174
|
+
cursor: string().optional(),
|
|
20175
|
+
/**
|
|
20176
|
+
* Restrict to these classes — THE SAME FIELD `listRecentTracks` takes, and
|
|
20177
|
+
* deliberately the same name: the events filter tree emits one list of ticked
|
|
20178
|
+
* taxonomy nodes, and a summaries feed that called it something else would
|
|
20179
|
+
* make the operator's one filter component produce two shapes.
|
|
20180
|
+
*
|
|
20181
|
+
* A question about the MEMBERS: a group matches when ANY of them does. "Show
|
|
20182
|
+
* me the arrivals with a dog" has to return the group of four people who had
|
|
20183
|
+
* one with them; a filter on the group's own fields could only ever answer
|
|
20184
|
+
* about its primary.
|
|
20185
|
+
*
|
|
20186
|
+
* Matched against all THREE tiers of a member — the class (`animal`), the
|
|
20187
|
+
* sub-class (`dog`) and the instance (a name, a plate) — because which tier a
|
|
20188
|
+
* ticked node lives on is the taxonomy's business, not the caller's. `dog` is
|
|
20189
|
+
* an event kind in the tree and a tier-1 label on an `animal` track; a filter
|
|
20190
|
+
* that read only the class would answer "animal" and never "dog".
|
|
20191
|
+
*
|
|
20192
|
+
* ABSENT or EMPTY means no filter — absent is not a selection of none.
|
|
20193
|
+
*/
|
|
20194
|
+
classes: array(string().min(1).max(60)).max(40).optional()
|
|
20195
|
+
});
|
|
20196
|
+
var RecentSummariesPageSchema = object({
|
|
20197
|
+
/** Ordered by (`lastActiveAt` DESC, id DESC). Same light item as
|
|
20198
|
+
* {@link listSummaries} — one list shape, so a card renders the same
|
|
20199
|
+
* whichever feed drew it. */
|
|
20200
|
+
summaries: array(SummaryListItemSchema).readonly(),
|
|
20201
|
+
nextCursor: string().nullable()
|
|
20029
20202
|
});
|
|
20030
20203
|
var RecentTracksPageSchema = object({
|
|
20031
20204
|
/** Merged page, ordered by (`lastSeen` DESC, `trackId` DESC). */
|
|
@@ -20439,7 +20612,7 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
|
|
|
20439
20612
|
classes: array(string()).optional(),
|
|
20440
20613
|
/** See {@link ExcludeSourcesDoc}. */
|
|
20441
20614
|
excludeSources: array(TrackSourceSchema).optional()
|
|
20442
|
-
}), array(TrackSchema).readonly()), method(RecentTracksQueryInput, RecentTracksPageSchema), method(SummariesQueryInput, SummariesPageSchema), method(object({ id: string() }), SummaryDetailSchema.nullable()), method(object({ deviceId: number() }), _void(), {
|
|
20615
|
+
}), array(TrackSchema).readonly()), method(RecentTracksQueryInput, RecentTracksPageSchema), method(SummariesQueryInput, SummariesPageSchema), method(RecentSummariesQueryInput, RecentSummariesPageSchema), method(object({ id: string() }), SummaryDetailSchema.nullable()), method(object({ deviceId: number() }), _void(), {
|
|
20443
20616
|
kind: "mutation",
|
|
20444
20617
|
auth: "admin"
|
|
20445
20618
|
}), 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({
|
|
@@ -20567,7 +20740,7 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
|
|
|
20567
20740
|
}), method(object({
|
|
20568
20741
|
deviceId: number(),
|
|
20569
20742
|
trackId: string(),
|
|
20570
|
-
|
|
20743
|
+
mediaIds: array(number().int()).min(1)
|
|
20571
20744
|
}), RetrainFrameSelectionSchema, {
|
|
20572
20745
|
kind: "mutation",
|
|
20573
20746
|
auth: "admin"
|
|
@@ -20635,7 +20808,10 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
|
|
|
20635
20808
|
kind: "query",
|
|
20636
20809
|
auth: "admin"
|
|
20637
20810
|
}), method(object({
|
|
20638
|
-
|
|
20811
|
+
/** Which of the three event tables owns the row. */
|
|
20812
|
+
ownerType: EventOwnerTypeSchema,
|
|
20813
|
+
/** The event's rowid in that table (D474: an event id is a number). */
|
|
20814
|
+
eventId: number().int(),
|
|
20639
20815
|
kind: MediaFileKindEnum.optional(),
|
|
20640
20816
|
deviceId: number()
|
|
20641
20817
|
}), array(MediaFileSchema).readonly()), method(object({
|
|
@@ -20646,7 +20822,8 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
|
|
|
20646
20822
|
trackId: string(),
|
|
20647
20823
|
deviceId: number()
|
|
20648
20824
|
}), array(MediaFileInfoSchema).readonly()), method(object({
|
|
20649
|
-
|
|
20825
|
+
ownerType: EventOwnerTypeSchema,
|
|
20826
|
+
eventId: number().int(),
|
|
20650
20827
|
deviceId: number()
|
|
20651
20828
|
}), array(MediaFileInfoSchema).readonly()), method(SearchObjectEventsInput, array(ScoredObjectEventSchema).readonly()), method(object({}), WipeObjectEmbeddingsResultSchema, {
|
|
20652
20829
|
kind: "mutation",
|
|
@@ -25109,8 +25286,8 @@ var IdentitySchema = object({
|
|
|
25109
25286
|
id: string(),
|
|
25110
25287
|
name: string(),
|
|
25111
25288
|
sampleCount: number().int().nonnegative(),
|
|
25112
|
-
|
|
25113
|
-
/** Inline base64 of the cover sample's crop, resolved from `
|
|
25289
|
+
coverMediaId: number().int().optional(),
|
|
25290
|
+
/** Inline base64 of the cover sample's crop, resolved from `coverMediaId`.
|
|
25114
25291
|
* Lets the UI render the person's face avatar instead of a placeholder icon. */
|
|
25115
25292
|
coverBase64: string().optional()
|
|
25116
25293
|
});
|
|
@@ -25136,8 +25313,8 @@ var IdentitySampleAuditRowSchema = object({
|
|
|
25136
25313
|
enrolledAt: number().int(),
|
|
25137
25314
|
deviceId: number().int().optional(),
|
|
25138
25315
|
source: _enum(["detected", "photo"]),
|
|
25139
|
-
/** The enrolled crop's media
|
|
25140
|
-
|
|
25316
|
+
/** The enrolled crop's media row id, so the panel can show the evidence. */
|
|
25317
|
+
mediaId: number().int().optional(),
|
|
25141
25318
|
/**
|
|
25142
25319
|
* False = the sample is stamped with a DIFFERENT face model, and a cosine
|
|
25143
25320
|
* across feature spaces is a well-formed float with no meaning. Every number
|
|
@@ -25206,15 +25383,15 @@ var FaceInfoSchema = object({
|
|
|
25206
25383
|
*/
|
|
25207
25384
|
cropUrl: string().optional(),
|
|
25208
25385
|
/** Design B: the face bbox (pixel space) on the key frame — lets a detail
|
|
25209
|
-
* view draw the box over the native `
|
|
25386
|
+
* view draw the box over the native `keyFrameMediaId` frame. Absent on
|
|
25210
25387
|
* legacy rows written before design B. */
|
|
25211
25388
|
faceBbox: BoundingBoxSchema.optional(),
|
|
25212
25389
|
/** Design B: MediaStore key of the track's native-resolution key frame.
|
|
25213
25390
|
* Fetch the native JPEG via the event-media data-plane
|
|
25214
|
-
* (`/addon/<addonId>/event-media/<
|
|
25391
|
+
* (`/addon/<addonId>/event-media/m/<keyFrameMediaId>`). Absent when the
|
|
25215
25392
|
* track produced no key frame (e.g. native/onboard source) — the UI falls
|
|
25216
25393
|
* back to the inline `base64` face crop. */
|
|
25217
|
-
|
|
25394
|
+
keyFrameMediaId: number().int().optional(),
|
|
25218
25395
|
/** Winning identity-match cosine (0..1) for this face's track, when an
|
|
25219
25396
|
* identity was auto-confirmed. Lets the UI surface WHY a face was assigned
|
|
25220
25397
|
* (confidence badge / low-confidence audit). Absent on legacy rows and on
|
|
@@ -25283,11 +25460,14 @@ var FaceClusterSchema = object({
|
|
|
25283
25460
|
* `data:image/jpeg;base64,…` from a row whose `key` sat right beside it, in a
|
|
25284
25461
|
* dialog already rendering its key FRAME from the `event-media` plane.
|
|
25285
25462
|
*
|
|
25286
|
-
* `url` is `/addon/<addonId>/event-media/<
|
|
25287
|
-
* media
|
|
25463
|
+
* `url` is `/addon/<addonId>/event-media/m/<mediaId>` (D482). The plane
|
|
25464
|
+
* resolves a media row by its own id, so this needed no new plane and no new
|
|
25465
|
+
* access decision.
|
|
25288
25466
|
*/
|
|
25289
25467
|
var MediaFileLiteSchema$1 = object({
|
|
25290
|
-
|
|
25468
|
+
/** The media row's own id — the same address `MediaFileRef.mediaId` carries
|
|
25469
|
+
* (D482). It was the row's composite key, which embedded the owner. */
|
|
25470
|
+
mediaId: number().int(),
|
|
25291
25471
|
kind: string(),
|
|
25292
25472
|
url: string(),
|
|
25293
25473
|
sizeBytes: number(),
|
|
@@ -25304,7 +25484,7 @@ method(object({
|
|
|
25304
25484
|
* covers inline, ~10 KB of base64 per row, on a query this UI mounts
|
|
25305
25485
|
* four times and the viewer holds at `staleTime: 30_000`.
|
|
25306
25486
|
*
|
|
25307
|
-
* Nothing loses its avatar: `
|
|
25487
|
+
* Nothing loses its avatar: `coverMediaId` is already on every row and
|
|
25308
25488
|
* the `event-media` plane serves that key `immutable` with an ETag.
|
|
25309
25489
|
*
|
|
25310
25490
|
* **This is an INPUT field, so it does not reach the addon until the
|
|
@@ -27772,8 +27952,8 @@ var VehicleSchema = object({
|
|
|
27772
27952
|
id: string(),
|
|
27773
27953
|
name: string(),
|
|
27774
27954
|
sampleCount: number().int().nonnegative(),
|
|
27775
|
-
|
|
27776
|
-
/** Inline base64 of the cover sample's plate crop, resolved from `
|
|
27955
|
+
coverMediaId: number().int().optional(),
|
|
27956
|
+
/** Inline base64 of the cover sample's plate crop, resolved from `coverMediaId`. */
|
|
27777
27957
|
coverBase64: string().optional()
|
|
27778
27958
|
});
|
|
27779
27959
|
var VehicleSampleInfoSchema = object({
|
|
@@ -27806,7 +27986,7 @@ var PlateInfoSchema = object({
|
|
|
27806
27986
|
/** keyFrame parity: the plate bbox (pixel space) on the native key frame. */
|
|
27807
27987
|
plateBbox: BoundingBoxSchema.optional(),
|
|
27808
27988
|
/** keyFrame parity: MediaStore key of the track's native-resolution key frame. */
|
|
27809
|
-
|
|
27989
|
+
keyFrameMediaId: number().int().optional(),
|
|
27810
27990
|
base64: string().optional(),
|
|
27811
27991
|
/**
|
|
27812
27992
|
* Same crop as a data-plane URL, always present when the plate has a stored
|
|
@@ -27827,11 +28007,14 @@ var PlateInfoSchema = object({
|
|
|
27827
28007
|
* `data:image/jpeg;base64,…` from a row whose `key` sat right beside it, in a
|
|
27828
28008
|
* dialog already rendering its key FRAME from the `event-media` plane.
|
|
27829
28009
|
*
|
|
27830
|
-
* `url` is `/addon/<addonId>/event-media/<
|
|
27831
|
-
* media
|
|
28010
|
+
* `url` is `/addon/<addonId>/event-media/m/<mediaId>` (D482). The plane
|
|
28011
|
+
* resolves a media row by its own id, so this needed no new plane and no new
|
|
28012
|
+
* access decision.
|
|
27832
28013
|
*/
|
|
27833
28014
|
var MediaFileLiteSchema = object({
|
|
27834
|
-
|
|
28015
|
+
/** The media row's own id — the same address `MediaFileRef.mediaId` carries
|
|
28016
|
+
* (D482). It was the row's composite key, which embedded the owner. */
|
|
28017
|
+
mediaId: number().int(),
|
|
27835
28018
|
kind: string(),
|
|
27836
28019
|
url: string(),
|
|
27837
28020
|
sizeBytes: number(),
|
|
@@ -27890,7 +28073,7 @@ method(object({
|
|
|
27890
28073
|
}), method(object({
|
|
27891
28074
|
/** Inline {@link VehicleSchema.coverBase64} on every row. Default
|
|
27892
28075
|
* `false` — the vehicle twin of `faceGallery.listIdentities`'s
|
|
27893
|
-
* option; `
|
|
28076
|
+
* option; `coverMediaId` + the `event-media` plane carry the picture.
|
|
27894
28077
|
* INPUT field: stripped by the hub router until the train ships, which
|
|
27895
28078
|
* resolves to `false` and is exactly the intended default. */
|
|
27896
28079
|
includeCrops: boolean().optional() }).optional(), array(VehicleSchema).readonly()), method(object({ name: string().min(1) }), VehicleSchema, {
|
|
@@ -29214,7 +29397,14 @@ var SceneReferenceSchema = object({
|
|
|
29214
29397
|
modelId: string(),
|
|
29215
29398
|
condition: SceneConditionSchema,
|
|
29216
29399
|
capturedAt: number(),
|
|
29217
|
-
|
|
29400
|
+
/**
|
|
29401
|
+
* The reference thumbnail's media ROW id (D482).
|
|
29402
|
+
*
|
|
29403
|
+
* The name already said `mediaId` while the value was the row's composite
|
|
29404
|
+
* key — a leftover that read as done and was not. It is the row's own id
|
|
29405
|
+
* now, addressed at `/addon/<addonId>/event-media/m/<id>`.
|
|
29406
|
+
*/
|
|
29407
|
+
thumbnailMediaId: number().int().optional(),
|
|
29218
29408
|
/** Whole-frame (downscaled) embedding captured alongside the ROI crop. The
|
|
29219
29409
|
* anti-view-shift anchor: a bumped camera, a PTZ preset or a re-aim makes the
|
|
29220
29410
|
* normalized rect frame a different piece of world, and the scene would
|
|
@@ -30028,7 +30218,29 @@ var LoggingSettingsPatchSchema = object({
|
|
|
30028
30218
|
* disarmed the channels it did not mention would make the Levels page and
|
|
30029
30219
|
* the Diagnostics page fight over the same value.
|
|
30030
30220
|
*/
|
|
30031
|
-
channels: array(LogChannelWindowPatchSchema).readonly().optional()
|
|
30221
|
+
channels: array(LogChannelWindowPatchSchema).readonly().optional(),
|
|
30222
|
+
/**
|
|
30223
|
+
* How many days the analytics OPS LOG is kept — the audit trail of what
|
|
30224
|
+
* retention actually deleted.
|
|
30225
|
+
*
|
|
30226
|
+
* It lives HERE, on the logging document, and not on the analytics addon's
|
|
30227
|
+
* settings form, on the operator's instruction: every other log-ish window in
|
|
30228
|
+
* this system is configured through this one document, and a retention audit
|
|
30229
|
+
* configured somewhere else is a second place to look when the question is
|
|
30230
|
+
* "what happened to my data".
|
|
30231
|
+
*
|
|
30232
|
+
* That placement has a cost worth stating: this document ships in the
|
|
30233
|
+
* framework closure, so this knob needs a published `@camstack/server` while
|
|
30234
|
+
* the four windows beside it (D485) reach a node on `camstack deploy`.
|
|
30235
|
+
*
|
|
30236
|
+
* `retention-model.ts` argued this one must NOT follow a device window,
|
|
30237
|
+
* because the audit trail is the history of the SWEEP and not of the camera.
|
|
30238
|
+
* That argument stands and is untouched — what changes is that 30 days stops
|
|
30239
|
+
* being a constant nobody can reach. `0` keeps it forever. The floor is 1 day
|
|
30240
|
+
* rather than 0-as-delete: an audit log truncated to nothing is precisely the
|
|
30241
|
+
* state in which the next 9.5 GiB leak cannot be explained.
|
|
30242
|
+
*/
|
|
30243
|
+
opsLogRetentionDays: number().int().min(0).max(3650).optional()
|
|
30032
30244
|
});
|
|
30033
30245
|
/**
|
|
30034
30246
|
* Which LAYER of the hierarchy is addressed. Absent = the cluster layer.
|
|
@@ -30101,6 +30313,14 @@ var LoggingSettingsStateSchema = object({
|
|
|
30101
30313
|
channels: array(LogChannelDescriptorSchema).readonly(),
|
|
30102
30314
|
/** The channels ARMED right now, each with its deadline. */
|
|
30103
30315
|
activeChannels: array(LogChannelWindowStateSchema).readonly(),
|
|
30316
|
+
/**
|
|
30317
|
+
* The ops-log window in days, as it is in force. `0` = kept forever.
|
|
30318
|
+
*
|
|
30319
|
+
* Reported rather than left to the caller's memory of what it wrote: this is
|
|
30320
|
+
* the value the analytics sweep will actually use, and an operator asking how
|
|
30321
|
+
* long their audit trail lives should not have to infer it from a default.
|
|
30322
|
+
*/
|
|
30323
|
+
opsLogRetentionDays: number().int().min(0),
|
|
30104
30324
|
persisted: boolean()
|
|
30105
30325
|
});
|
|
30106
30326
|
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(), {
|
|
@@ -30662,7 +30882,7 @@ var StationaryObjectSchema = object({
|
|
|
30662
30882
|
/** Enrichment label carried from the source track (identity / plate). */
|
|
30663
30883
|
label: string().optional(),
|
|
30664
30884
|
/** Native-resolution key-frame media key for the parked object's best image. */
|
|
30665
|
-
|
|
30885
|
+
keyFrameMediaId: number().int().optional()
|
|
30666
30886
|
});
|
|
30667
30887
|
var CameraOccupancySnapshotSchema = object({
|
|
30668
30888
|
/** Frame timestamp of the inference result that produced this snapshot. */
|
|
@@ -31818,6 +32038,12 @@ Object.freeze({
|
|
|
31818
32038
|
addonId: null,
|
|
31819
32039
|
access: "create"
|
|
31820
32040
|
},
|
|
32041
|
+
"dataStoreProvider.upsert": {
|
|
32042
|
+
capName: "data-store-provider",
|
|
32043
|
+
capScope: "system",
|
|
32044
|
+
addonId: null,
|
|
32045
|
+
access: "create"
|
|
32046
|
+
},
|
|
31821
32047
|
"dayNight.getOptions": {
|
|
31822
32048
|
capName: "day-night",
|
|
31823
32049
|
capScope: "device",
|
|
@@ -34254,6 +34480,12 @@ Object.freeze({
|
|
|
34254
34480
|
addonId: null,
|
|
34255
34481
|
access: "view"
|
|
34256
34482
|
},
|
|
34483
|
+
"pipelineAnalytics.listRecentSummaries": {
|
|
34484
|
+
capName: "pipeline-analytics",
|
|
34485
|
+
capScope: "device",
|
|
34486
|
+
addonId: null,
|
|
34487
|
+
access: "view"
|
|
34488
|
+
},
|
|
34257
34489
|
"pipelineAnalytics.listRecentTracks": {
|
|
34258
34490
|
capName: "pipeline-analytics",
|
|
34259
34491
|
capScope: "device",
|
|
@@ -35682,6 +35914,12 @@ Object.freeze({
|
|
|
35682
35914
|
addonId: null,
|
|
35683
35915
|
access: "create"
|
|
35684
35916
|
},
|
|
35917
|
+
"settingsStore.upsert": {
|
|
35918
|
+
capName: "settings-store",
|
|
35919
|
+
capScope: "system",
|
|
35920
|
+
addonId: null,
|
|
35921
|
+
access: "create"
|
|
35922
|
+
},
|
|
35685
35923
|
"smtpProvider.getStatus": {
|
|
35686
35924
|
capName: "smtp-provider",
|
|
35687
35925
|
capScope: "system",
|
|
@@ -38075,6 +38313,11 @@ Object.freeze({
|
|
|
38075
38313
|
form: "single",
|
|
38076
38314
|
optional: true
|
|
38077
38315
|
}],
|
|
38316
|
+
"pipelineAnalytics.listRecentSummaries": [{
|
|
38317
|
+
name: "deviceIds",
|
|
38318
|
+
form: "array",
|
|
38319
|
+
optional: false
|
|
38320
|
+
}],
|
|
38078
38321
|
"pipelineAnalytics.listRecentTracks": [{
|
|
38079
38322
|
name: "deviceIds",
|
|
38080
38323
|
form: "array",
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as crypto$1 from "node:crypto";
|
|
2
|
-
//#region ../types/dist/event-category-
|
|
2
|
+
//#region ../types/dist/event-category-ZyX6jcse.mjs
|
|
3
3
|
var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
4
4
|
EventCategory["SystemBoot"] = "system.boot";
|
|
5
5
|
EventCategory["SystemAddonsReady"] = "system.addons-ready";
|
|
@@ -560,7 +560,7 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
|
560
560
|
* a package zone — a newly-appeared stationary object of a package class
|
|
561
561
|
* that cleared the class / zone / dwell / size gates. Payload:
|
|
562
562
|
* `PipelineAnalyticsPackageDeliveredPayload` carrying `{ deviceId,
|
|
563
|
-
* entryId, className, zoneIds,
|
|
563
|
+
* entryId, className, zoneIds, keyFrameMediaId?, bbox, timestamp }`.
|
|
564
564
|
* Telemetry (D8): the durable record is the `package-events` store row;
|
|
565
565
|
* this bus topic drives notifier rules + live UI. See
|
|
566
566
|
* docs/superpowers/specs/2026-07-17-package-zones-design.md §5.1.
|
|
@@ -5346,7 +5346,7 @@ var ZodIssueCode = {
|
|
|
5346
5346
|
var ZodFirstPartyTypeKind;
|
|
5347
5347
|
ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
|
|
5348
5348
|
//#endregion
|
|
5349
|
-
//#region ../types/dist/sleep-
|
|
5349
|
+
//#region ../types/dist/sleep-DBKu2-U5.mjs
|
|
5350
5350
|
/**
|
|
5351
5351
|
* The audio chunk plane's byte format, and the ONE expansion from a coded
|
|
5352
5352
|
* window to float samples (D455).
|
|
@@ -7309,13 +7309,30 @@ new Set([
|
|
|
7309
7309
|
"scene",
|
|
7310
7310
|
"motion",
|
|
7311
7311
|
"object",
|
|
7312
|
-
"audio"
|
|
7312
|
+
"audio",
|
|
7313
|
+
"mosaic"
|
|
7313
7314
|
]);
|
|
7314
|
-
|
|
7315
|
+
/**
|
|
7316
|
+
* The owner types that are event tables, in the order the event-media resolver
|
|
7317
|
+
* should consider them. Exported so a consumer asking "is this key an event?"
|
|
7318
|
+
* does not re-spell the list and drift from it.
|
|
7319
|
+
*/
|
|
7320
|
+
var EVENT_OWNER_TYPES = [
|
|
7315
7321
|
"motion",
|
|
7316
7322
|
"object",
|
|
7317
7323
|
"audio"
|
|
7318
|
-
]
|
|
7324
|
+
];
|
|
7325
|
+
/**
|
|
7326
|
+
* The same list as a Zod enum, for the cap inputs that must NAME the table
|
|
7327
|
+
* (D482: `getEventMedia` / `listEventMedia` take an owner, and an owner is
|
|
7328
|
+
* `(table, id)`).
|
|
7329
|
+
*
|
|
7330
|
+
* Built FROM {@link EVENT_OWNER_TYPES} rather than re-spelled: a fourth event
|
|
7331
|
+
* table would otherwise be accepted by the codec and refused at the door, with
|
|
7332
|
+
* nothing failing until a caller asked.
|
|
7333
|
+
*/
|
|
7334
|
+
var EventOwnerTypeSchema = _enum(EVENT_OWNER_TYPES);
|
|
7335
|
+
new Set(EVENT_OWNER_TYPES);
|
|
7319
7336
|
/**
|
|
7320
7337
|
* Build an `IAddonRouteProvider` from a list of routes. Implements
|
|
7321
7338
|
* both the operator-facing `getRoutes` (returning route descriptors
|
|
@@ -7546,7 +7563,32 @@ var BASE_LIVE_EGRESS_PROFILE = {
|
|
|
7546
7563
|
*/
|
|
7547
7564
|
var ALEXA_EGRESS_PROFILE = {
|
|
7548
7565
|
...BASE_LIVE_EGRESS_PROFILE,
|
|
7549
|
-
audio: { codec: "opus" }
|
|
7566
|
+
audio: { codec: "opus" },
|
|
7567
|
+
/**
|
|
7568
|
+
* ONE slice per access unit.
|
|
7569
|
+
*
|
|
7570
|
+
* `-tune zerolatency` turns on x264's sliced threads, and every access unit
|
|
7571
|
+
* came out of this encode as FIVE slices — measured on the hub 2026-09-13 on
|
|
7572
|
+
* the exact argv this path spawns, and reduced to one by this single flag.
|
|
7573
|
+
*
|
|
7574
|
+
* Five slices share one RTP timestamp and carry one marker bit, so a
|
|
7575
|
+
* libwebrtc depacketiser sees five frame-starts and one frame-end per frame.
|
|
7576
|
+
* The Echo renders the first pictures and then freezes for good, while the
|
|
7577
|
+
* audio — a separate plane — plays on. It is the only structural property
|
|
7578
|
+
* that survived the elimination: the same freeze reproduced at 2304×1296
|
|
7579
|
+
* HEVC with 217 KB keyframes AND at 640×360 H.264 with 67 KB keyframes and a
|
|
7580
|
+
* fifth of the bitrate, so source, resolution, bitrate, keyframe burst,
|
|
7581
|
+
* hardware decode, parameter sets, drift and bitstream conformance are all
|
|
7582
|
+
* out — each ruled out by a measurement, not by elimination.
|
|
7583
|
+
*
|
|
7584
|
+
* The tune STAYS: it also drops the lookahead and the B-frames, which a live
|
|
7585
|
+
* path wants. Only the slicing is unwanted, and this is the flag that says so.
|
|
7586
|
+
*
|
|
7587
|
+
* Scoped to Alexa deliberately. HomeKit and the browser transcode inherit
|
|
7588
|
+
* {@link BASE_LIVE_EGRESS_PROFILE}; whether they want the same shape is a
|
|
7589
|
+
* question for their own evidence, and the browser has not been measured.
|
|
7590
|
+
*/
|
|
7591
|
+
outputArgs: ["-x264-params", "sliced-threads=0"]
|
|
7550
7592
|
};
|
|
7551
7593
|
/**
|
|
7552
7594
|
* Deep wiring healthcheck — snapshot of active reachability probes across
|
|
@@ -12657,6 +12699,16 @@ method(object({
|
|
|
12657
12699
|
filter: QueryFilterSchema.optional(),
|
|
12658
12700
|
columns: array(string()).readonly().optional()
|
|
12659
12701
|
}), array(SettingsRecordSchema).readonly()), method(object({
|
|
12702
|
+
namespace: string().optional(),
|
|
12703
|
+
collection: string(),
|
|
12704
|
+
/** Declared columns identifying the slot; must be covered by a UNIQUE
|
|
12705
|
+
* index on the collection. Never empty. */
|
|
12706
|
+
conflict: array(string()).readonly(),
|
|
12707
|
+
record: BulkRecordSchema
|
|
12708
|
+
}), object({
|
|
12709
|
+
/** The id the row HAS: assigned by SQLite on an insert, or the existing
|
|
12710
|
+
* row's own id on an update. */
|
|
12711
|
+
id: union([string(), number()]) }), { kind: "mutation" }), method(object({
|
|
12660
12712
|
namespace: string().optional(),
|
|
12661
12713
|
collection: string(),
|
|
12662
12714
|
record: object({
|
|
@@ -12791,6 +12843,14 @@ method(_void(), EngineInfoSchema, { auth: "admin" }), method(object({
|
|
|
12791
12843
|
id: union([string(), number()]) }), {
|
|
12792
12844
|
kind: "mutation",
|
|
12793
12845
|
auth: "admin"
|
|
12846
|
+
}), method(object({
|
|
12847
|
+
namespace: string().optional(),
|
|
12848
|
+
collection: string(),
|
|
12849
|
+
conflict: array(string()).readonly(),
|
|
12850
|
+
record: BulkRecordSchema
|
|
12851
|
+
}), object({ id: union([string(), number()]) }), {
|
|
12852
|
+
kind: "mutation",
|
|
12853
|
+
auth: "admin"
|
|
12794
12854
|
}), method(object({
|
|
12795
12855
|
namespace: string().optional(),
|
|
12796
12856
|
collection: string(),
|
|
@@ -19048,8 +19108,8 @@ var TrackPositionSchema = object({
|
|
|
19048
19108
|
var TrackSnapshotSchema = object({
|
|
19049
19109
|
timestamp: number(),
|
|
19050
19110
|
position: TrackPositionSchema,
|
|
19051
|
-
/**
|
|
19052
|
-
|
|
19111
|
+
/** The snapshot's media row id (D482); resolve via `listTrackMedia({ trackId })`. */
|
|
19112
|
+
mediaId: number().int()
|
|
19053
19113
|
});
|
|
19054
19114
|
/**
|
|
19055
19115
|
* Normalized 0..1 trajectory envelope (min/max over every position bbox,
|
|
@@ -19653,14 +19713,14 @@ var ObjectEventSchema = object({
|
|
|
19653
19713
|
* pixel-space `bbox` onto a displayed image. Omitted in slim projection. */
|
|
19654
19714
|
frameWidth: number().optional(),
|
|
19655
19715
|
frameHeight: number().optional(),
|
|
19656
|
-
/**
|
|
19657
|
-
|
|
19658
|
-
/** Design B:
|
|
19716
|
+
/** Media row id of the crop attached to this event (if any) — D482. */
|
|
19717
|
+
mediaId: number().int().optional(),
|
|
19718
|
+
/** Design B: media row id of the track's native-resolution key frame (the
|
|
19659
19719
|
* best-detection full frame). Resolve via the event-media data-plane
|
|
19660
|
-
* (`/addon/<addonId>/event-media/<
|
|
19720
|
+
* (`/addon/<addonId>/event-media/m/<keyFrameMediaId>`) for a detail view that
|
|
19661
19721
|
* draws `bbox` over the native frame. Absent on legacy rows / non-decoded
|
|
19662
|
-
* sources — consumers fall back to `
|
|
19663
|
-
|
|
19722
|
+
* sources — consumers fall back to `mediaId` (the tight crop). */
|
|
19723
|
+
keyFrameMediaId: number().int().optional(),
|
|
19664
19724
|
/** Populated by B5 (recording playback URL for this event). */
|
|
19665
19725
|
mediaUrl: string().optional(),
|
|
19666
19726
|
/** The parent track's key-event importance [0,1], propagated to every object
|
|
@@ -19710,7 +19770,7 @@ var MediaFileKindEnum = _enum([
|
|
|
19710
19770
|
* hub-main's heap on the way past — for an `<img>` that would have cached it.
|
|
19711
19771
|
*
|
|
19712
19772
|
* `url` points at the `event-media` data plane
|
|
19713
|
-
* (`/addon/<addonId>/event-media/<
|
|
19773
|
+
* (`/addon/<addonId>/event-media/m/<mediaId>` — D482), which serves the same blob
|
|
19714
19774
|
* with an ETag and `Cache-Control: immutable`, honours conditional GETs, can
|
|
19715
19775
|
* render a `?variant=thumb`, and streams. The hub gate in front of it requires
|
|
19716
19776
|
* a bearer or the session cookie (`access: 'authenticated'`), so the bytes are
|
|
@@ -19718,10 +19778,13 @@ var MediaFileKindEnum = _enum([
|
|
|
19718
19778
|
* `data-plane-access.ts` for the rule and the one gap it does not close
|
|
19719
19779
|
* (per-device scoping).
|
|
19720
19780
|
*
|
|
19721
|
-
* The URL is built from the row's
|
|
19722
|
-
*
|
|
19781
|
+
* The URL is built from the row's own id, which since D482 says nothing about
|
|
19782
|
+
* the row's owner or kind — and that is the point. The published `kind` is not
|
|
19783
|
+
* the stored one (a track's face/plate crop is stored as `crop` under
|
|
19723
19784
|
* `('face'|'plate', '<prefix>-<trackId>')` and published as
|
|
19724
|
-
* `faceCrop`/`plateCrop
|
|
19785
|
+
* `faceCrop`/`plateCrop`), and under the old composite key the URL had to be
|
|
19786
|
+
* taken from `row.key` verbatim or it 404'd exactly those two rows. An id
|
|
19787
|
+
* cannot be mis-reconstructed, because there is nothing in it to reconstruct.
|
|
19725
19788
|
*
|
|
19726
19789
|
* ## `base64` is TRANSITIONAL and is going away
|
|
19727
19790
|
*
|
|
@@ -19734,7 +19797,19 @@ var MediaFileKindEnum = _enum([
|
|
|
19734
19797
|
* `analytics-query-facade.ts`; nothing else reads it.
|
|
19735
19798
|
*/
|
|
19736
19799
|
var MediaFileSchema = object({
|
|
19737
|
-
|
|
19800
|
+
/**
|
|
19801
|
+
* The media row's OWN id — the rowid SQLite assigned it (D482).
|
|
19802
|
+
*
|
|
19803
|
+
* It used to be the row's composite key, `<ownerType>:<ownerId>:<fileKind>
|
|
19804
|
+
* [:<timestampMs>]`, which embedded a FOREIGN id. D474 made event ids
|
|
19805
|
+
* per-table rowid aliases, so `object:101314` and `motion:101314` are two
|
|
19806
|
+
* different rows that spell the same number, and a track whose
|
|
19807
|
+
* `bestEventId` was an object event was served a motion event's snapshot —
|
|
19808
|
+
* a night-time thumbnail on an afternoon track, with no error anywhere. A
|
|
19809
|
+
* surrogate id cannot name the wrong row's owner, because it names no owner
|
|
19810
|
+
* at all.
|
|
19811
|
+
*/
|
|
19812
|
+
mediaId: number().int(),
|
|
19738
19813
|
kind: MediaFileKindEnum,
|
|
19739
19814
|
sizeBytes: number(),
|
|
19740
19815
|
timestamp: number()
|
|
@@ -19842,7 +19917,7 @@ var RetrainTrackSchema = object({
|
|
|
19842
19917
|
});
|
|
19843
19918
|
/** A frame the picker may offer — an index row, no blob was read to produce it. */
|
|
19844
19919
|
var RetrainFrameCandidateSchema = object({
|
|
19845
|
-
|
|
19920
|
+
mediaId: number().int(),
|
|
19846
19921
|
kind: MediaFileKindEnum,
|
|
19847
19922
|
timestamp: number(),
|
|
19848
19923
|
sizeBytes: number().int(),
|
|
@@ -19856,7 +19931,7 @@ var RetrainFrameSchema = object({
|
|
|
19856
19931
|
deviceId: number(),
|
|
19857
19932
|
trackId: string(),
|
|
19858
19933
|
/** Provenance only. It may already point at nothing — that is expected. */
|
|
19859
|
-
|
|
19934
|
+
sourceMediaId: number().int(),
|
|
19860
19935
|
sourceKind: MediaFileKindEnum,
|
|
19861
19936
|
sizeBytes: number().int(),
|
|
19862
19937
|
width: number().int(),
|
|
@@ -19872,7 +19947,7 @@ var RetrainCopyRefusalSchema = _enum([
|
|
|
19872
19947
|
var RetrainFrameSelectionSchema = object({
|
|
19873
19948
|
copied: array(RetrainFrameSchema).readonly(),
|
|
19874
19949
|
refused: array(object({
|
|
19875
|
-
|
|
19950
|
+
sourceMediaId: number().int(),
|
|
19876
19951
|
reason: RetrainCopyRefusalSchema
|
|
19877
19952
|
})).readonly()
|
|
19878
19953
|
});
|
|
@@ -19880,7 +19955,7 @@ var RetrainFrameListSchema = object({
|
|
|
19880
19955
|
candidates: array(RetrainFrameCandidateSchema).readonly(),
|
|
19881
19956
|
copies: array(RetrainFrameSchema).readonly(),
|
|
19882
19957
|
/** What the page pre-selects — the native key frame when one survives. */
|
|
19883
|
-
|
|
19958
|
+
autoPickMediaId: number().int().optional()
|
|
19884
19959
|
});
|
|
19885
19960
|
/** What the operator asked the assist to look for. */
|
|
19886
19961
|
var RetrainAssistSubjectSchema = discriminatedUnion("kind", [object({
|
|
@@ -19975,9 +20050,11 @@ var RecentTracksQueryInput = object({
|
|
|
19975
20050
|
});
|
|
19976
20051
|
/**
|
|
19977
20052
|
* A Summary (D359): the per-camera session envelope that references tracks.
|
|
19978
|
-
* `
|
|
19979
|
-
* served by the event-media plane
|
|
19980
|
-
* member visible has been materialised
|
|
20053
|
+
* `groupShotMediaId` is the media ROW id of its group shot (`ownerKind:
|
|
20054
|
+
* 'summary'`, served by the event-media plane at `/m/<id>`), null until the
|
|
20055
|
+
* first frame with a member visible has been materialised (D482 — it was the
|
|
20056
|
+
* row's composite key, which embedded the owner and could name another table's
|
|
20057
|
+
* row once event ids became per-table rowids).
|
|
19981
20058
|
*/
|
|
19982
20059
|
var SummarySchema = object({
|
|
19983
20060
|
id: string(),
|
|
@@ -19986,19 +20063,115 @@ var SummarySchema = object({
|
|
|
19986
20063
|
lastActiveAt: number(),
|
|
19987
20064
|
sealedAt: number().nullable(),
|
|
19988
20065
|
memberCount: number().int().nonnegative(),
|
|
19989
|
-
|
|
20066
|
+
groupShotMediaId: number().int().nullable()
|
|
19990
20067
|
});
|
|
19991
20068
|
var SummariesQueryInput = object({
|
|
19992
20069
|
deviceIds: array(number()).min(1),
|
|
19993
20070
|
since: number().optional(),
|
|
19994
20071
|
until: number().optional(),
|
|
19995
|
-
limit: number().int().min(1).max(200).default(50)
|
|
20072
|
+
limit: number().int().min(1).max(200).default(50),
|
|
20073
|
+
/** The same member-wise filter {@link listRecentSummaries} takes — one
|
|
20074
|
+
* meaning of "dog" on every summary surface. */
|
|
20075
|
+
classes: array(string().min(1).max(60)).max(40).optional()
|
|
19996
20076
|
});
|
|
19997
|
-
var SummariesPageSchema = object({ summaries: array(SummarySchema).readonly() });
|
|
19998
20077
|
var SummaryDetailSchema = object({
|
|
19999
20078
|
summary: SummarySchema,
|
|
20000
|
-
/**
|
|
20001
|
-
|
|
20079
|
+
/** Members in absorption order, oldest join first. */
|
|
20080
|
+
members: array(object({
|
|
20081
|
+
trackId: string(),
|
|
20082
|
+
/**
|
|
20083
|
+
* The track's class at the time it JOINED, or `null` when it was unresolved
|
|
20084
|
+
* and the track no longer exists to fill it.
|
|
20085
|
+
*
|
|
20086
|
+
* The join, not the latest opinion: class voting can re-decide a track's
|
|
20087
|
+
* class afterwards, and a group's composition is the history of who came
|
|
20088
|
+
* together. A consumer counts these to badge a thumbnail — "two people and a
|
|
20089
|
+
* dog" — rather than being handed a second, denormalised tally that would
|
|
20090
|
+
* drift from the members it claims to describe.
|
|
20091
|
+
*/
|
|
20092
|
+
className: string().nullable(),
|
|
20093
|
+
/** `primary` is the one member that carries the group's identity. */
|
|
20094
|
+
role: _enum([
|
|
20095
|
+
"primary",
|
|
20096
|
+
"sibling",
|
|
20097
|
+
"child"
|
|
20098
|
+
]).nullable(),
|
|
20099
|
+
joinedAt: number(),
|
|
20100
|
+
/** Tier 1 — the sub-class (`dog`, `van`), resolved from the member's track
|
|
20101
|
+
* at read time. Absent when nothing resolved, never an empty string. */
|
|
20102
|
+
label: string().optional(),
|
|
20103
|
+
/** Tier 2 — the instance: a person's name, a plate. Absent when the pipeline
|
|
20104
|
+
* recognised nobody, and absent for a member whose track has been pruned —
|
|
20105
|
+
* a thumbnail that names the wrong person is worse than one naming nobody. */
|
|
20106
|
+
subLabel: string().optional()
|
|
20107
|
+
})).readonly()
|
|
20108
|
+
});
|
|
20109
|
+
/**
|
|
20110
|
+
* What a LIST of groups carries: the envelope plus what it is MADE OF.
|
|
20111
|
+
*
|
|
20112
|
+
* Coarse on purpose — the operator's rule is "only the rough data on the list,
|
|
20113
|
+
* we extend when we notice we need more". Enough to draw the card ("two people
|
|
20114
|
+
* and a dog") and no more. The MEMBERS, their names and the per-member links
|
|
20115
|
+
* are on {@link getSummary}: shipping every member of every group so a client
|
|
20116
|
+
* can count them turns a page of two hundred groups into a thousand records to
|
|
20117
|
+
* draw two hundred badges.
|
|
20118
|
+
*/
|
|
20119
|
+
var SummaryListItemSchema = object({
|
|
20120
|
+
summary: SummarySchema,
|
|
20121
|
+
/** Class counts, most numerous first; `className: null` is a member whose
|
|
20122
|
+
* class never resolved, counted so the counts add up to `memberCount`. */
|
|
20123
|
+
classes: array(object({
|
|
20124
|
+
className: string().nullable(),
|
|
20125
|
+
count: number().int().positive()
|
|
20126
|
+
})).readonly()
|
|
20127
|
+
});
|
|
20128
|
+
var SummariesPageSchema = object({ summaries: array(SummaryListItemSchema).readonly() });
|
|
20129
|
+
/**
|
|
20130
|
+
* The paged feed, deliberately the SAME shape as {@link RecentTracksQueryInput}.
|
|
20131
|
+
*
|
|
20132
|
+
* The reel on the cameras page and the Events gallery both ride a cursor, so a
|
|
20133
|
+
* summaries feed that could only answer "the last N for these cameras"
|
|
20134
|
+
* (`listSummaries`) would make groups available in the timeline and nowhere
|
|
20135
|
+
* else. Two feeds with different ordering contracts would be two ideas of what
|
|
20136
|
+
* "newest" means, on one screen.
|
|
20137
|
+
*/
|
|
20138
|
+
var RecentSummariesQueryInput = object({
|
|
20139
|
+
/** Devices to merge. An empty array yields an empty page. */
|
|
20140
|
+
deviceIds: array(number()),
|
|
20141
|
+
/** Window lower bound on `lastActiveAt` (inclusive). */
|
|
20142
|
+
since: number().optional(),
|
|
20143
|
+
/** Window upper bound on `lastActiveAt` (inclusive). */
|
|
20144
|
+
until: number().optional(),
|
|
20145
|
+
limit: number().int().min(1).max(500).default(100),
|
|
20146
|
+
/** Opaque continuation cursor from a previous page's `nextCursor`. */
|
|
20147
|
+
cursor: string().optional(),
|
|
20148
|
+
/**
|
|
20149
|
+
* Restrict to these classes — THE SAME FIELD `listRecentTracks` takes, and
|
|
20150
|
+
* deliberately the same name: the events filter tree emits one list of ticked
|
|
20151
|
+
* taxonomy nodes, and a summaries feed that called it something else would
|
|
20152
|
+
* make the operator's one filter component produce two shapes.
|
|
20153
|
+
*
|
|
20154
|
+
* A question about the MEMBERS: a group matches when ANY of them does. "Show
|
|
20155
|
+
* me the arrivals with a dog" has to return the group of four people who had
|
|
20156
|
+
* one with them; a filter on the group's own fields could only ever answer
|
|
20157
|
+
* about its primary.
|
|
20158
|
+
*
|
|
20159
|
+
* Matched against all THREE tiers of a member — the class (`animal`), the
|
|
20160
|
+
* sub-class (`dog`) and the instance (a name, a plate) — because which tier a
|
|
20161
|
+
* ticked node lives on is the taxonomy's business, not the caller's. `dog` is
|
|
20162
|
+
* an event kind in the tree and a tier-1 label on an `animal` track; a filter
|
|
20163
|
+
* that read only the class would answer "animal" and never "dog".
|
|
20164
|
+
*
|
|
20165
|
+
* ABSENT or EMPTY means no filter — absent is not a selection of none.
|
|
20166
|
+
*/
|
|
20167
|
+
classes: array(string().min(1).max(60)).max(40).optional()
|
|
20168
|
+
});
|
|
20169
|
+
var RecentSummariesPageSchema = object({
|
|
20170
|
+
/** Ordered by (`lastActiveAt` DESC, id DESC). Same light item as
|
|
20171
|
+
* {@link listSummaries} — one list shape, so a card renders the same
|
|
20172
|
+
* whichever feed drew it. */
|
|
20173
|
+
summaries: array(SummaryListItemSchema).readonly(),
|
|
20174
|
+
nextCursor: string().nullable()
|
|
20002
20175
|
});
|
|
20003
20176
|
var RecentTracksPageSchema = object({
|
|
20004
20177
|
/** Merged page, ordered by (`lastSeen` DESC, `trackId` DESC). */
|
|
@@ -20412,7 +20585,7 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
|
|
|
20412
20585
|
classes: array(string()).optional(),
|
|
20413
20586
|
/** See {@link ExcludeSourcesDoc}. */
|
|
20414
20587
|
excludeSources: array(TrackSourceSchema).optional()
|
|
20415
|
-
}), array(TrackSchema).readonly()), method(RecentTracksQueryInput, RecentTracksPageSchema), method(SummariesQueryInput, SummariesPageSchema), method(object({ id: string() }), SummaryDetailSchema.nullable()), method(object({ deviceId: number() }), _void(), {
|
|
20588
|
+
}), array(TrackSchema).readonly()), method(RecentTracksQueryInput, RecentTracksPageSchema), method(SummariesQueryInput, SummariesPageSchema), method(RecentSummariesQueryInput, RecentSummariesPageSchema), method(object({ id: string() }), SummaryDetailSchema.nullable()), method(object({ deviceId: number() }), _void(), {
|
|
20416
20589
|
kind: "mutation",
|
|
20417
20590
|
auth: "admin"
|
|
20418
20591
|
}), 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({
|
|
@@ -20540,7 +20713,7 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
|
|
|
20540
20713
|
}), method(object({
|
|
20541
20714
|
deviceId: number(),
|
|
20542
20715
|
trackId: string(),
|
|
20543
|
-
|
|
20716
|
+
mediaIds: array(number().int()).min(1)
|
|
20544
20717
|
}), RetrainFrameSelectionSchema, {
|
|
20545
20718
|
kind: "mutation",
|
|
20546
20719
|
auth: "admin"
|
|
@@ -20608,7 +20781,10 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
|
|
|
20608
20781
|
kind: "query",
|
|
20609
20782
|
auth: "admin"
|
|
20610
20783
|
}), method(object({
|
|
20611
|
-
|
|
20784
|
+
/** Which of the three event tables owns the row. */
|
|
20785
|
+
ownerType: EventOwnerTypeSchema,
|
|
20786
|
+
/** The event's rowid in that table (D474: an event id is a number). */
|
|
20787
|
+
eventId: number().int(),
|
|
20612
20788
|
kind: MediaFileKindEnum.optional(),
|
|
20613
20789
|
deviceId: number()
|
|
20614
20790
|
}), array(MediaFileSchema).readonly()), method(object({
|
|
@@ -20619,7 +20795,8 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
|
|
|
20619
20795
|
trackId: string(),
|
|
20620
20796
|
deviceId: number()
|
|
20621
20797
|
}), array(MediaFileInfoSchema).readonly()), method(object({
|
|
20622
|
-
|
|
20798
|
+
ownerType: EventOwnerTypeSchema,
|
|
20799
|
+
eventId: number().int(),
|
|
20623
20800
|
deviceId: number()
|
|
20624
20801
|
}), array(MediaFileInfoSchema).readonly()), method(SearchObjectEventsInput, array(ScoredObjectEventSchema).readonly()), method(object({}), WipeObjectEmbeddingsResultSchema, {
|
|
20625
20802
|
kind: "mutation",
|
|
@@ -25082,8 +25259,8 @@ var IdentitySchema = object({
|
|
|
25082
25259
|
id: string(),
|
|
25083
25260
|
name: string(),
|
|
25084
25261
|
sampleCount: number().int().nonnegative(),
|
|
25085
|
-
|
|
25086
|
-
/** Inline base64 of the cover sample's crop, resolved from `
|
|
25262
|
+
coverMediaId: number().int().optional(),
|
|
25263
|
+
/** Inline base64 of the cover sample's crop, resolved from `coverMediaId`.
|
|
25087
25264
|
* Lets the UI render the person's face avatar instead of a placeholder icon. */
|
|
25088
25265
|
coverBase64: string().optional()
|
|
25089
25266
|
});
|
|
@@ -25109,8 +25286,8 @@ var IdentitySampleAuditRowSchema = object({
|
|
|
25109
25286
|
enrolledAt: number().int(),
|
|
25110
25287
|
deviceId: number().int().optional(),
|
|
25111
25288
|
source: _enum(["detected", "photo"]),
|
|
25112
|
-
/** The enrolled crop's media
|
|
25113
|
-
|
|
25289
|
+
/** The enrolled crop's media row id, so the panel can show the evidence. */
|
|
25290
|
+
mediaId: number().int().optional(),
|
|
25114
25291
|
/**
|
|
25115
25292
|
* False = the sample is stamped with a DIFFERENT face model, and a cosine
|
|
25116
25293
|
* across feature spaces is a well-formed float with no meaning. Every number
|
|
@@ -25179,15 +25356,15 @@ var FaceInfoSchema = object({
|
|
|
25179
25356
|
*/
|
|
25180
25357
|
cropUrl: string().optional(),
|
|
25181
25358
|
/** Design B: the face bbox (pixel space) on the key frame — lets a detail
|
|
25182
|
-
* view draw the box over the native `
|
|
25359
|
+
* view draw the box over the native `keyFrameMediaId` frame. Absent on
|
|
25183
25360
|
* legacy rows written before design B. */
|
|
25184
25361
|
faceBbox: BoundingBoxSchema.optional(),
|
|
25185
25362
|
/** Design B: MediaStore key of the track's native-resolution key frame.
|
|
25186
25363
|
* Fetch the native JPEG via the event-media data-plane
|
|
25187
|
-
* (`/addon/<addonId>/event-media/<
|
|
25364
|
+
* (`/addon/<addonId>/event-media/m/<keyFrameMediaId>`). Absent when the
|
|
25188
25365
|
* track produced no key frame (e.g. native/onboard source) — the UI falls
|
|
25189
25366
|
* back to the inline `base64` face crop. */
|
|
25190
|
-
|
|
25367
|
+
keyFrameMediaId: number().int().optional(),
|
|
25191
25368
|
/** Winning identity-match cosine (0..1) for this face's track, when an
|
|
25192
25369
|
* identity was auto-confirmed. Lets the UI surface WHY a face was assigned
|
|
25193
25370
|
* (confidence badge / low-confidence audit). Absent on legacy rows and on
|
|
@@ -25256,11 +25433,14 @@ var FaceClusterSchema = object({
|
|
|
25256
25433
|
* `data:image/jpeg;base64,…` from a row whose `key` sat right beside it, in a
|
|
25257
25434
|
* dialog already rendering its key FRAME from the `event-media` plane.
|
|
25258
25435
|
*
|
|
25259
|
-
* `url` is `/addon/<addonId>/event-media/<
|
|
25260
|
-
* media
|
|
25436
|
+
* `url` is `/addon/<addonId>/event-media/m/<mediaId>` (D482). The plane
|
|
25437
|
+
* resolves a media row by its own id, so this needed no new plane and no new
|
|
25438
|
+
* access decision.
|
|
25261
25439
|
*/
|
|
25262
25440
|
var MediaFileLiteSchema$1 = object({
|
|
25263
|
-
|
|
25441
|
+
/** The media row's own id — the same address `MediaFileRef.mediaId` carries
|
|
25442
|
+
* (D482). It was the row's composite key, which embedded the owner. */
|
|
25443
|
+
mediaId: number().int(),
|
|
25264
25444
|
kind: string(),
|
|
25265
25445
|
url: string(),
|
|
25266
25446
|
sizeBytes: number(),
|
|
@@ -25277,7 +25457,7 @@ method(object({
|
|
|
25277
25457
|
* covers inline, ~10 KB of base64 per row, on a query this UI mounts
|
|
25278
25458
|
* four times and the viewer holds at `staleTime: 30_000`.
|
|
25279
25459
|
*
|
|
25280
|
-
* Nothing loses its avatar: `
|
|
25460
|
+
* Nothing loses its avatar: `coverMediaId` is already on every row and
|
|
25281
25461
|
* the `event-media` plane serves that key `immutable` with an ETag.
|
|
25282
25462
|
*
|
|
25283
25463
|
* **This is an INPUT field, so it does not reach the addon until the
|
|
@@ -27745,8 +27925,8 @@ var VehicleSchema = object({
|
|
|
27745
27925
|
id: string(),
|
|
27746
27926
|
name: string(),
|
|
27747
27927
|
sampleCount: number().int().nonnegative(),
|
|
27748
|
-
|
|
27749
|
-
/** Inline base64 of the cover sample's plate crop, resolved from `
|
|
27928
|
+
coverMediaId: number().int().optional(),
|
|
27929
|
+
/** Inline base64 of the cover sample's plate crop, resolved from `coverMediaId`. */
|
|
27750
27930
|
coverBase64: string().optional()
|
|
27751
27931
|
});
|
|
27752
27932
|
var VehicleSampleInfoSchema = object({
|
|
@@ -27779,7 +27959,7 @@ var PlateInfoSchema = object({
|
|
|
27779
27959
|
/** keyFrame parity: the plate bbox (pixel space) on the native key frame. */
|
|
27780
27960
|
plateBbox: BoundingBoxSchema.optional(),
|
|
27781
27961
|
/** keyFrame parity: MediaStore key of the track's native-resolution key frame. */
|
|
27782
|
-
|
|
27962
|
+
keyFrameMediaId: number().int().optional(),
|
|
27783
27963
|
base64: string().optional(),
|
|
27784
27964
|
/**
|
|
27785
27965
|
* Same crop as a data-plane URL, always present when the plate has a stored
|
|
@@ -27800,11 +27980,14 @@ var PlateInfoSchema = object({
|
|
|
27800
27980
|
* `data:image/jpeg;base64,…` from a row whose `key` sat right beside it, in a
|
|
27801
27981
|
* dialog already rendering its key FRAME from the `event-media` plane.
|
|
27802
27982
|
*
|
|
27803
|
-
* `url` is `/addon/<addonId>/event-media/<
|
|
27804
|
-
* media
|
|
27983
|
+
* `url` is `/addon/<addonId>/event-media/m/<mediaId>` (D482). The plane
|
|
27984
|
+
* resolves a media row by its own id, so this needed no new plane and no new
|
|
27985
|
+
* access decision.
|
|
27805
27986
|
*/
|
|
27806
27987
|
var MediaFileLiteSchema = object({
|
|
27807
|
-
|
|
27988
|
+
/** The media row's own id — the same address `MediaFileRef.mediaId` carries
|
|
27989
|
+
* (D482). It was the row's composite key, which embedded the owner. */
|
|
27990
|
+
mediaId: number().int(),
|
|
27808
27991
|
kind: string(),
|
|
27809
27992
|
url: string(),
|
|
27810
27993
|
sizeBytes: number(),
|
|
@@ -27863,7 +28046,7 @@ method(object({
|
|
|
27863
28046
|
}), method(object({
|
|
27864
28047
|
/** Inline {@link VehicleSchema.coverBase64} on every row. Default
|
|
27865
28048
|
* `false` — the vehicle twin of `faceGallery.listIdentities`'s
|
|
27866
|
-
* option; `
|
|
28049
|
+
* option; `coverMediaId` + the `event-media` plane carry the picture.
|
|
27867
28050
|
* INPUT field: stripped by the hub router until the train ships, which
|
|
27868
28051
|
* resolves to `false` and is exactly the intended default. */
|
|
27869
28052
|
includeCrops: boolean().optional() }).optional(), array(VehicleSchema).readonly()), method(object({ name: string().min(1) }), VehicleSchema, {
|
|
@@ -29187,7 +29370,14 @@ var SceneReferenceSchema = object({
|
|
|
29187
29370
|
modelId: string(),
|
|
29188
29371
|
condition: SceneConditionSchema,
|
|
29189
29372
|
capturedAt: number(),
|
|
29190
|
-
|
|
29373
|
+
/**
|
|
29374
|
+
* The reference thumbnail's media ROW id (D482).
|
|
29375
|
+
*
|
|
29376
|
+
* The name already said `mediaId` while the value was the row's composite
|
|
29377
|
+
* key — a leftover that read as done and was not. It is the row's own id
|
|
29378
|
+
* now, addressed at `/addon/<addonId>/event-media/m/<id>`.
|
|
29379
|
+
*/
|
|
29380
|
+
thumbnailMediaId: number().int().optional(),
|
|
29191
29381
|
/** Whole-frame (downscaled) embedding captured alongside the ROI crop. The
|
|
29192
29382
|
* anti-view-shift anchor: a bumped camera, a PTZ preset or a re-aim makes the
|
|
29193
29383
|
* normalized rect frame a different piece of world, and the scene would
|
|
@@ -30001,7 +30191,29 @@ var LoggingSettingsPatchSchema = object({
|
|
|
30001
30191
|
* disarmed the channels it did not mention would make the Levels page and
|
|
30002
30192
|
* the Diagnostics page fight over the same value.
|
|
30003
30193
|
*/
|
|
30004
|
-
channels: array(LogChannelWindowPatchSchema).readonly().optional()
|
|
30194
|
+
channels: array(LogChannelWindowPatchSchema).readonly().optional(),
|
|
30195
|
+
/**
|
|
30196
|
+
* How many days the analytics OPS LOG is kept — the audit trail of what
|
|
30197
|
+
* retention actually deleted.
|
|
30198
|
+
*
|
|
30199
|
+
* It lives HERE, on the logging document, and not on the analytics addon's
|
|
30200
|
+
* settings form, on the operator's instruction: every other log-ish window in
|
|
30201
|
+
* this system is configured through this one document, and a retention audit
|
|
30202
|
+
* configured somewhere else is a second place to look when the question is
|
|
30203
|
+
* "what happened to my data".
|
|
30204
|
+
*
|
|
30205
|
+
* That placement has a cost worth stating: this document ships in the
|
|
30206
|
+
* framework closure, so this knob needs a published `@camstack/server` while
|
|
30207
|
+
* the four windows beside it (D485) reach a node on `camstack deploy`.
|
|
30208
|
+
*
|
|
30209
|
+
* `retention-model.ts` argued this one must NOT follow a device window,
|
|
30210
|
+
* because the audit trail is the history of the SWEEP and not of the camera.
|
|
30211
|
+
* That argument stands and is untouched — what changes is that 30 days stops
|
|
30212
|
+
* being a constant nobody can reach. `0` keeps it forever. The floor is 1 day
|
|
30213
|
+
* rather than 0-as-delete: an audit log truncated to nothing is precisely the
|
|
30214
|
+
* state in which the next 9.5 GiB leak cannot be explained.
|
|
30215
|
+
*/
|
|
30216
|
+
opsLogRetentionDays: number().int().min(0).max(3650).optional()
|
|
30005
30217
|
});
|
|
30006
30218
|
/**
|
|
30007
30219
|
* Which LAYER of the hierarchy is addressed. Absent = the cluster layer.
|
|
@@ -30074,6 +30286,14 @@ var LoggingSettingsStateSchema = object({
|
|
|
30074
30286
|
channels: array(LogChannelDescriptorSchema).readonly(),
|
|
30075
30287
|
/** The channels ARMED right now, each with its deadline. */
|
|
30076
30288
|
activeChannels: array(LogChannelWindowStateSchema).readonly(),
|
|
30289
|
+
/**
|
|
30290
|
+
* The ops-log window in days, as it is in force. `0` = kept forever.
|
|
30291
|
+
*
|
|
30292
|
+
* Reported rather than left to the caller's memory of what it wrote: this is
|
|
30293
|
+
* the value the analytics sweep will actually use, and an operator asking how
|
|
30294
|
+
* long their audit trail lives should not have to infer it from a default.
|
|
30295
|
+
*/
|
|
30296
|
+
opsLogRetentionDays: number().int().min(0),
|
|
30077
30297
|
persisted: boolean()
|
|
30078
30298
|
});
|
|
30079
30299
|
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(), {
|
|
@@ -30635,7 +30855,7 @@ var StationaryObjectSchema = object({
|
|
|
30635
30855
|
/** Enrichment label carried from the source track (identity / plate). */
|
|
30636
30856
|
label: string().optional(),
|
|
30637
30857
|
/** Native-resolution key-frame media key for the parked object's best image. */
|
|
30638
|
-
|
|
30858
|
+
keyFrameMediaId: number().int().optional()
|
|
30639
30859
|
});
|
|
30640
30860
|
var CameraOccupancySnapshotSchema = object({
|
|
30641
30861
|
/** Frame timestamp of the inference result that produced this snapshot. */
|
|
@@ -31791,6 +32011,12 @@ Object.freeze({
|
|
|
31791
32011
|
addonId: null,
|
|
31792
32012
|
access: "create"
|
|
31793
32013
|
},
|
|
32014
|
+
"dataStoreProvider.upsert": {
|
|
32015
|
+
capName: "data-store-provider",
|
|
32016
|
+
capScope: "system",
|
|
32017
|
+
addonId: null,
|
|
32018
|
+
access: "create"
|
|
32019
|
+
},
|
|
31794
32020
|
"dayNight.getOptions": {
|
|
31795
32021
|
capName: "day-night",
|
|
31796
32022
|
capScope: "device",
|
|
@@ -34227,6 +34453,12 @@ Object.freeze({
|
|
|
34227
34453
|
addonId: null,
|
|
34228
34454
|
access: "view"
|
|
34229
34455
|
},
|
|
34456
|
+
"pipelineAnalytics.listRecentSummaries": {
|
|
34457
|
+
capName: "pipeline-analytics",
|
|
34458
|
+
capScope: "device",
|
|
34459
|
+
addonId: null,
|
|
34460
|
+
access: "view"
|
|
34461
|
+
},
|
|
34230
34462
|
"pipelineAnalytics.listRecentTracks": {
|
|
34231
34463
|
capName: "pipeline-analytics",
|
|
34232
34464
|
capScope: "device",
|
|
@@ -35655,6 +35887,12 @@ Object.freeze({
|
|
|
35655
35887
|
addonId: null,
|
|
35656
35888
|
access: "create"
|
|
35657
35889
|
},
|
|
35890
|
+
"settingsStore.upsert": {
|
|
35891
|
+
capName: "settings-store",
|
|
35892
|
+
capScope: "system",
|
|
35893
|
+
addonId: null,
|
|
35894
|
+
access: "create"
|
|
35895
|
+
},
|
|
35658
35896
|
"smtpProvider.getStatus": {
|
|
35659
35897
|
capName: "smtp-provider",
|
|
35660
35898
|
capScope: "system",
|
|
@@ -38048,6 +38286,11 @@ Object.freeze({
|
|
|
38048
38286
|
form: "single",
|
|
38049
38287
|
optional: true
|
|
38050
38288
|
}],
|
|
38289
|
+
"pipelineAnalytics.listRecentSummaries": [{
|
|
38290
|
+
name: "deviceIds",
|
|
38291
|
+
form: "array",
|
|
38292
|
+
optional: false
|
|
38293
|
+
}],
|
|
38051
38294
|
"pipelineAnalytics.listRecentTracks": [{
|
|
38052
38295
|
name: "deviceIds",
|
|
38053
38296
|
form: "array",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@camstack/addon-export-alexa",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.107",
|
|
4
4
|
"description": "Alexa Smart Home Skill export — hub-side OAuth provider + directive handler. The companion AWS Lambda forwards Alexa directives to this addon's /addon/export-alexa/directive endpoint.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"camstack",
|