@camstack/addon-provider-wyze 0.2.103 → 0.2.105

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.
Files changed (3) hide show
  1. package/dist/addon.js +292 -58
  2. package/dist/addon.mjs +292 -58
  3. package/package.json +1 -1
package/dist/addon.js CHANGED
@@ -31,7 +31,7 @@ let net = require("net");
31
31
  net = __toESM(net, 1);
32
32
  let node_child_process = require("node:child_process");
33
33
  let node_tls = require("node:tls");
34
- //#region ../types/dist/event-category-DAXzJeTX.mjs
34
+ //#region ../types/dist/event-category-ZyX6jcse.mjs
35
35
  var EventCategory = /* @__PURE__ */ function(EventCategory) {
36
36
  EventCategory["SystemBoot"] = "system.boot";
37
37
  EventCategory["SystemAddonsReady"] = "system.addons-ready";
@@ -592,7 +592,7 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
592
592
  * a package zone — a newly-appeared stationary object of a package class
593
593
  * that cleared the class / zone / dwell / size gates. Payload:
594
594
  * `PipelineAnalyticsPackageDeliveredPayload` carrying `{ deviceId,
595
- * entryId, className, zoneIds, keyFrameMediaKey?, bbox, timestamp }`.
595
+ * entryId, className, zoneIds, keyFrameMediaId?, bbox, timestamp }`.
596
596
  * Telemetry (D8): the durable record is the `package-events` store row;
597
597
  * this bus topic drives notifier rules + live UI. See
598
598
  * docs/superpowers/specs/2026-07-17-package-zones-design.md §5.1.
@@ -5378,7 +5378,7 @@ var ZodIssueCode = {
5378
5378
  var ZodFirstPartyTypeKind;
5379
5379
  ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
5380
5380
  //#endregion
5381
- //#region ../types/dist/sleep-BnujYGPe.mjs
5381
+ //#region ../types/dist/sleep-DBKu2-U5.mjs
5382
5382
  /**
5383
5383
  * The audio chunk plane's byte format, and the ONE expansion from a coded
5384
5384
  * window to float samples (D455).
@@ -7345,13 +7345,30 @@ new Set([
7345
7345
  "scene",
7346
7346
  "motion",
7347
7347
  "object",
7348
- "audio"
7348
+ "audio",
7349
+ "mosaic"
7349
7350
  ]);
7350
- new Set([
7351
+ /**
7352
+ * The owner types that are event tables, in the order the event-media resolver
7353
+ * should consider them. Exported so a consumer asking "is this key an event?"
7354
+ * does not re-spell the list and drift from it.
7355
+ */
7356
+ var EVENT_OWNER_TYPES = [
7351
7357
  "motion",
7352
7358
  "object",
7353
7359
  "audio"
7354
- ]);
7360
+ ];
7361
+ /**
7362
+ * The same list as a Zod enum, for the cap inputs that must NAME the table
7363
+ * (D482: `getEventMedia` / `listEventMedia` take an owner, and an owner is
7364
+ * `(table, id)`).
7365
+ *
7366
+ * Built FROM {@link EVENT_OWNER_TYPES} rather than re-spelled: a fourth event
7367
+ * table would otherwise be accepted by the codec and refused at the door, with
7368
+ * nothing failing until a caller asked.
7369
+ */
7370
+ var EventOwnerTypeSchema = _enum(EVENT_OWNER_TYPES);
7371
+ new Set(EVENT_OWNER_TYPES);
7355
7372
  var EncodeProfileSchema = object({
7356
7373
  video: object({
7357
7374
  codec: _enum([
@@ -7390,7 +7407,23 @@ var EncodeProfileSchema = object({
7390
7407
  "zerolatency",
7391
7408
  "film",
7392
7409
  "animation"
7393
- ]).optional()
7410
+ ]).optional(),
7411
+ /**
7412
+ * ONE slice per access unit.
7413
+ *
7414
+ * `-tune zerolatency` turns on x264's sliced threads, and a frame then leaves
7415
+ * the encoder as five NAL slices that share one RTP timestamp and carry one
7416
+ * marker bit. A libwebrtc depacketiser sees five frame-starts and one
7417
+ * frame-end per frame: the first pictures render and the video then freezes
7418
+ * for good while the audio, on its own plane, plays on. Measured on this hub
7419
+ * 2026-09-13 against the Echo, and reduced to one slice by this flag alone.
7420
+ *
7421
+ * A NAMED field and not a raw flag, because {@link EgressEncodeSchema} omits
7422
+ * `outputArgs` on purpose: an opaque array is part of the sharing key, so two
7423
+ * consumers meaning the same thing spelled differently would stop sharing one
7424
+ * child. Absent means "whatever the encoder does" — today's behaviour.
7425
+ */
7426
+ singleSlicePerFrame: boolean().optional()
7394
7427
  }),
7395
7428
  audio: union([literal("passthrough"), object({
7396
7429
  codec: _enum([
@@ -7440,7 +7473,7 @@ var BASE_LIVE_EGRESS_PROFILE = {
7440
7473
  audio: "passthrough"
7441
7474
  };
7442
7475
  ({ ...BASE_LIVE_EGRESS_PROFILE }), { ...BASE_LIVE_EGRESS_PROFILE.video };
7443
- ({ ...BASE_LIVE_EGRESS_PROFILE });
7476
+ ({ ...BASE_LIVE_EGRESS_PROFILE }), { ...BASE_LIVE_EGRESS_PROFILE.video };
7444
7477
  /**
7445
7478
  * Deep wiring healthcheck — snapshot of active reachability probes across
7446
7479
  * every declared capability + widget of every installed plugin, on every
@@ -12550,6 +12583,16 @@ method(object({
12550
12583
  filter: QueryFilterSchema.optional(),
12551
12584
  columns: array(string()).readonly().optional()
12552
12585
  }), array(SettingsRecordSchema).readonly()), method(object({
12586
+ namespace: string().optional(),
12587
+ collection: string(),
12588
+ /** Declared columns identifying the slot; must be covered by a UNIQUE
12589
+ * index on the collection. Never empty. */
12590
+ conflict: array(string()).readonly(),
12591
+ record: BulkRecordSchema
12592
+ }), object({
12593
+ /** The id the row HAS: assigned by SQLite on an insert, or the existing
12594
+ * row's own id on an update. */
12595
+ id: union([string(), number()]) }), { kind: "mutation" }), method(object({
12553
12596
  namespace: string().optional(),
12554
12597
  collection: string(),
12555
12598
  record: object({
@@ -12684,6 +12727,14 @@ method(_void(), EngineInfoSchema, { auth: "admin" }), method(object({
12684
12727
  id: union([string(), number()]) }), {
12685
12728
  kind: "mutation",
12686
12729
  auth: "admin"
12730
+ }), method(object({
12731
+ namespace: string().optional(),
12732
+ collection: string(),
12733
+ conflict: array(string()).readonly(),
12734
+ record: BulkRecordSchema
12735
+ }), object({ id: union([string(), number()]) }), {
12736
+ kind: "mutation",
12737
+ auth: "admin"
12687
12738
  }), method(object({
12688
12739
  namespace: string().optional(),
12689
12740
  collection: string(),
@@ -19183,8 +19234,8 @@ var TrackPositionSchema = object({
19183
19234
  var TrackSnapshotSchema = object({
19184
19235
  timestamp: number(),
19185
19236
  position: TrackPositionSchema,
19186
- /** MediaStore key; resolve via `getTrackMedia({ trackId })`. */
19187
- mediaKey: string()
19237
+ /** The snapshot's media row id (D482); resolve via `listTrackMedia({ trackId })`. */
19238
+ mediaId: number().int()
19188
19239
  });
19189
19240
  /**
19190
19241
  * Normalized 0..1 trajectory envelope (min/max over every position bbox,
@@ -19788,14 +19839,14 @@ var ObjectEventSchema = object({
19788
19839
  * pixel-space `bbox` onto a displayed image. Omitted in slim projection. */
19789
19840
  frameWidth: number().optional(),
19790
19841
  frameHeight: number().optional(),
19791
- /** MediaStore key for the crop attached to this event (if any). */
19792
- mediaKey: string().optional(),
19793
- /** Design B: MediaStore key of the track's native-resolution key frame (the
19842
+ /** Media row id of the crop attached to this event (if any) — D482. */
19843
+ mediaId: number().int().optional(),
19844
+ /** Design B: media row id of the track's native-resolution key frame (the
19794
19845
  * best-detection full frame). Resolve via the event-media data-plane
19795
- * (`/addon/<addonId>/event-media/<keyFrameMediaKey>`) for a detail view that
19846
+ * (`/addon/<addonId>/event-media/m/<keyFrameMediaId>`) for a detail view that
19796
19847
  * draws `bbox` over the native frame. Absent on legacy rows / non-decoded
19797
- * sources — consumers fall back to `mediaKey` (the tight crop). */
19798
- keyFrameMediaKey: string().optional(),
19848
+ * sources — consumers fall back to `mediaId` (the tight crop). */
19849
+ keyFrameMediaId: number().int().optional(),
19799
19850
  /** Populated by B5 (recording playback URL for this event). */
19800
19851
  mediaUrl: string().optional(),
19801
19852
  /** The parent track's key-event importance [0,1], propagated to every object
@@ -19845,7 +19896,7 @@ var MediaFileKindEnum = _enum([
19845
19896
  * hub-main's heap on the way past — for an `<img>` that would have cached it.
19846
19897
  *
19847
19898
  * `url` points at the `event-media` data plane
19848
- * (`/addon/<addonId>/event-media/<storedKey>`), which serves the same blob
19899
+ * (`/addon/<addonId>/event-media/m/<mediaId>` — D482), which serves the same blob
19849
19900
  * with an ETag and `Cache-Control: immutable`, honours conditional GETs, can
19850
19901
  * render a `?variant=thumb`, and streams. The hub gate in front of it requires
19851
19902
  * a bearer or the session cookie (`access: 'authenticated'`), so the bytes are
@@ -19853,10 +19904,13 @@ var MediaFileKindEnum = _enum([
19853
19904
  * `data-plane-access.ts` for the rule and the one gap it does not close
19854
19905
  * (per-device scoping).
19855
19906
  *
19856
- * The URL is built from the row's **stored** key, which is not always its
19857
- * published `kind`: a track's face/plate crop is stored as `crop` under
19907
+ * The URL is built from the row's own id, which since D482 says nothing about
19908
+ * the row's owner or kind — and that is the point. The published `kind` is not
19909
+ * the stored one (a track's face/plate crop is stored as `crop` under
19858
19910
  * `('face'|'plate', '<prefix>-<trackId>')` and published as
19859
- * `faceCrop`/`plateCrop`. `MediaStore.getByKey` knows only the stored key.
19911
+ * `faceCrop`/`plateCrop`), and under the old composite key the URL had to be
19912
+ * taken from `row.key` verbatim or it 404'd exactly those two rows. An id
19913
+ * cannot be mis-reconstructed, because there is nothing in it to reconstruct.
19860
19914
  *
19861
19915
  * ## `base64` is TRANSITIONAL and is going away
19862
19916
  *
@@ -19869,7 +19923,19 @@ var MediaFileKindEnum = _enum([
19869
19923
  * `analytics-query-facade.ts`; nothing else reads it.
19870
19924
  */
19871
19925
  var MediaFileSchema = object({
19872
- key: string(),
19926
+ /**
19927
+ * The media row's OWN id — the rowid SQLite assigned it (D482).
19928
+ *
19929
+ * It used to be the row's composite key, `<ownerType>:<ownerId>:<fileKind>
19930
+ * [:<timestampMs>]`, which embedded a FOREIGN id. D474 made event ids
19931
+ * per-table rowid aliases, so `object:101314` and `motion:101314` are two
19932
+ * different rows that spell the same number, and a track whose
19933
+ * `bestEventId` was an object event was served a motion event's snapshot —
19934
+ * a night-time thumbnail on an afternoon track, with no error anywhere. A
19935
+ * surrogate id cannot name the wrong row's owner, because it names no owner
19936
+ * at all.
19937
+ */
19938
+ mediaId: number().int(),
19873
19939
  kind: MediaFileKindEnum,
19874
19940
  sizeBytes: number(),
19875
19941
  timestamp: number()
@@ -19977,7 +20043,7 @@ var RetrainTrackSchema = object({
19977
20043
  });
19978
20044
  /** A frame the picker may offer — an index row, no blob was read to produce it. */
19979
20045
  var RetrainFrameCandidateSchema = object({
19980
- mediaKey: string(),
20046
+ mediaId: number().int(),
19981
20047
  kind: MediaFileKindEnum,
19982
20048
  timestamp: number(),
19983
20049
  sizeBytes: number().int(),
@@ -19991,7 +20057,7 @@ var RetrainFrameSchema = object({
19991
20057
  deviceId: number(),
19992
20058
  trackId: string(),
19993
20059
  /** Provenance only. It may already point at nothing — that is expected. */
19994
- sourceMediaKey: string(),
20060
+ sourceMediaId: number().int(),
19995
20061
  sourceKind: MediaFileKindEnum,
19996
20062
  sizeBytes: number().int(),
19997
20063
  width: number().int(),
@@ -20007,7 +20073,7 @@ var RetrainCopyRefusalSchema = _enum([
20007
20073
  var RetrainFrameSelectionSchema = object({
20008
20074
  copied: array(RetrainFrameSchema).readonly(),
20009
20075
  refused: array(object({
20010
- sourceMediaKey: string(),
20076
+ sourceMediaId: number().int(),
20011
20077
  reason: RetrainCopyRefusalSchema
20012
20078
  })).readonly()
20013
20079
  });
@@ -20015,7 +20081,7 @@ var RetrainFrameListSchema = object({
20015
20081
  candidates: array(RetrainFrameCandidateSchema).readonly(),
20016
20082
  copies: array(RetrainFrameSchema).readonly(),
20017
20083
  /** What the page pre-selects — the native key frame when one survives. */
20018
- autoPickMediaKey: string().optional()
20084
+ autoPickMediaId: number().int().optional()
20019
20085
  });
20020
20086
  /** What the operator asked the assist to look for. */
20021
20087
  var RetrainAssistSubjectSchema = discriminatedUnion("kind", [object({
@@ -20110,9 +20176,11 @@ var RecentTracksQueryInput = object({
20110
20176
  });
20111
20177
  /**
20112
20178
  * A Summary (D359): the per-camera session envelope that references tracks.
20113
- * `groupShotKey` is the media key of its group shot (`ownerKind: 'summary'`,
20114
- * served by the event-media plane by key), null until the first frame with a
20115
- * member visible has been materialised.
20179
+ * `groupShotMediaId` is the media ROW id of its group shot (`ownerKind:
20180
+ * 'summary'`, served by the event-media plane at `/m/<id>`), null until the
20181
+ * first frame with a member visible has been materialised (D482 — it was the
20182
+ * row's composite key, which embedded the owner and could name another table's
20183
+ * row once event ids became per-table rowids).
20116
20184
  */
20117
20185
  var SummarySchema = object({
20118
20186
  id: string(),
@@ -20121,19 +20189,115 @@ var SummarySchema = object({
20121
20189
  lastActiveAt: number(),
20122
20190
  sealedAt: number().nullable(),
20123
20191
  memberCount: number().int().nonnegative(),
20124
- groupShotKey: string().nullable()
20192
+ groupShotMediaId: number().int().nullable()
20125
20193
  });
20126
20194
  var SummariesQueryInput = object({
20127
20195
  deviceIds: array(number()).min(1),
20128
20196
  since: number().optional(),
20129
20197
  until: number().optional(),
20130
- limit: number().int().min(1).max(200).default(50)
20198
+ limit: number().int().min(1).max(200).default(50),
20199
+ /** The same member-wise filter {@link listRecentSummaries} takes — one
20200
+ * meaning of "dog" on every summary surface. */
20201
+ classes: array(string().min(1).max(60)).max(40).optional()
20131
20202
  });
20132
- var SummariesPageSchema = object({ summaries: array(SummarySchema).readonly() });
20133
20203
  var SummaryDetailSchema = object({
20134
20204
  summary: SummarySchema,
20135
- /** Member track ids, in absorption order. */
20136
- trackIds: array(string()).readonly()
20205
+ /** Members in absorption order, oldest join first. */
20206
+ members: array(object({
20207
+ trackId: string(),
20208
+ /**
20209
+ * The track's class at the time it JOINED, or `null` when it was unresolved
20210
+ * and the track no longer exists to fill it.
20211
+ *
20212
+ * The join, not the latest opinion: class voting can re-decide a track's
20213
+ * class afterwards, and a group's composition is the history of who came
20214
+ * together. A consumer counts these to badge a thumbnail — "two people and a
20215
+ * dog" — rather than being handed a second, denormalised tally that would
20216
+ * drift from the members it claims to describe.
20217
+ */
20218
+ className: string().nullable(),
20219
+ /** `primary` is the one member that carries the group's identity. */
20220
+ role: _enum([
20221
+ "primary",
20222
+ "sibling",
20223
+ "child"
20224
+ ]).nullable(),
20225
+ joinedAt: number(),
20226
+ /** Tier 1 — the sub-class (`dog`, `van`), resolved from the member's track
20227
+ * at read time. Absent when nothing resolved, never an empty string. */
20228
+ label: string().optional(),
20229
+ /** Tier 2 — the instance: a person's name, a plate. Absent when the pipeline
20230
+ * recognised nobody, and absent for a member whose track has been pruned —
20231
+ * a thumbnail that names the wrong person is worse than one naming nobody. */
20232
+ subLabel: string().optional()
20233
+ })).readonly()
20234
+ });
20235
+ /**
20236
+ * What a LIST of groups carries: the envelope plus what it is MADE OF.
20237
+ *
20238
+ * Coarse on purpose — the operator's rule is "only the rough data on the list,
20239
+ * we extend when we notice we need more". Enough to draw the card ("two people
20240
+ * and a dog") and no more. The MEMBERS, their names and the per-member links
20241
+ * are on {@link getSummary}: shipping every member of every group so a client
20242
+ * can count them turns a page of two hundred groups into a thousand records to
20243
+ * draw two hundred badges.
20244
+ */
20245
+ var SummaryListItemSchema = object({
20246
+ summary: SummarySchema,
20247
+ /** Class counts, most numerous first; `className: null` is a member whose
20248
+ * class never resolved, counted so the counts add up to `memberCount`. */
20249
+ classes: array(object({
20250
+ className: string().nullable(),
20251
+ count: number().int().positive()
20252
+ })).readonly()
20253
+ });
20254
+ var SummariesPageSchema = object({ summaries: array(SummaryListItemSchema).readonly() });
20255
+ /**
20256
+ * The paged feed, deliberately the SAME shape as {@link RecentTracksQueryInput}.
20257
+ *
20258
+ * The reel on the cameras page and the Events gallery both ride a cursor, so a
20259
+ * summaries feed that could only answer "the last N for these cameras"
20260
+ * (`listSummaries`) would make groups available in the timeline and nowhere
20261
+ * else. Two feeds with different ordering contracts would be two ideas of what
20262
+ * "newest" means, on one screen.
20263
+ */
20264
+ var RecentSummariesQueryInput = object({
20265
+ /** Devices to merge. An empty array yields an empty page. */
20266
+ deviceIds: array(number()),
20267
+ /** Window lower bound on `lastActiveAt` (inclusive). */
20268
+ since: number().optional(),
20269
+ /** Window upper bound on `lastActiveAt` (inclusive). */
20270
+ until: number().optional(),
20271
+ limit: number().int().min(1).max(500).default(100),
20272
+ /** Opaque continuation cursor from a previous page's `nextCursor`. */
20273
+ cursor: string().optional(),
20274
+ /**
20275
+ * Restrict to these classes — THE SAME FIELD `listRecentTracks` takes, and
20276
+ * deliberately the same name: the events filter tree emits one list of ticked
20277
+ * taxonomy nodes, and a summaries feed that called it something else would
20278
+ * make the operator's one filter component produce two shapes.
20279
+ *
20280
+ * A question about the MEMBERS: a group matches when ANY of them does. "Show
20281
+ * me the arrivals with a dog" has to return the group of four people who had
20282
+ * one with them; a filter on the group's own fields could only ever answer
20283
+ * about its primary.
20284
+ *
20285
+ * Matched against all THREE tiers of a member — the class (`animal`), the
20286
+ * sub-class (`dog`) and the instance (a name, a plate) — because which tier a
20287
+ * ticked node lives on is the taxonomy's business, not the caller's. `dog` is
20288
+ * an event kind in the tree and a tier-1 label on an `animal` track; a filter
20289
+ * that read only the class would answer "animal" and never "dog".
20290
+ *
20291
+ * ABSENT or EMPTY means no filter — absent is not a selection of none.
20292
+ */
20293
+ classes: array(string().min(1).max(60)).max(40).optional()
20294
+ });
20295
+ var RecentSummariesPageSchema = object({
20296
+ /** Ordered by (`lastActiveAt` DESC, id DESC). Same light item as
20297
+ * {@link listSummaries} — one list shape, so a card renders the same
20298
+ * whichever feed drew it. */
20299
+ summaries: array(SummaryListItemSchema).readonly(),
20300
+ nextCursor: string().nullable()
20137
20301
  });
20138
20302
  var RecentTracksPageSchema = object({
20139
20303
  /** Merged page, ordered by (`lastSeen` DESC, `trackId` DESC). */
@@ -20547,7 +20711,7 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
20547
20711
  classes: array(string()).optional(),
20548
20712
  /** See {@link ExcludeSourcesDoc}. */
20549
20713
  excludeSources: array(TrackSourceSchema).optional()
20550
- }), array(TrackSchema).readonly()), method(RecentTracksQueryInput, RecentTracksPageSchema), method(SummariesQueryInput, SummariesPageSchema), method(object({ id: string() }), SummaryDetailSchema.nullable()), method(object({ deviceId: number() }), _void(), {
20714
+ }), array(TrackSchema).readonly()), method(RecentTracksQueryInput, RecentTracksPageSchema), method(SummariesQueryInput, SummariesPageSchema), method(RecentSummariesQueryInput, RecentSummariesPageSchema), method(object({ id: string() }), SummaryDetailSchema.nullable()), method(object({ deviceId: number() }), _void(), {
20551
20715
  kind: "mutation",
20552
20716
  auth: "admin"
20553
20717
  }), 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({
@@ -20675,7 +20839,7 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
20675
20839
  }), method(object({
20676
20840
  deviceId: number(),
20677
20841
  trackId: string(),
20678
- mediaKeys: array(string()).min(1)
20842
+ mediaIds: array(number().int()).min(1)
20679
20843
  }), RetrainFrameSelectionSchema, {
20680
20844
  kind: "mutation",
20681
20845
  auth: "admin"
@@ -20743,7 +20907,10 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
20743
20907
  kind: "query",
20744
20908
  auth: "admin"
20745
20909
  }), method(object({
20746
- eventId: string(),
20910
+ /** Which of the three event tables owns the row. */
20911
+ ownerType: EventOwnerTypeSchema,
20912
+ /** The event's rowid in that table (D474: an event id is a number). */
20913
+ eventId: number().int(),
20747
20914
  kind: MediaFileKindEnum.optional(),
20748
20915
  deviceId: number()
20749
20916
  }), array(MediaFileSchema).readonly()), method(object({
@@ -20754,7 +20921,8 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
20754
20921
  trackId: string(),
20755
20922
  deviceId: number()
20756
20923
  }), array(MediaFileInfoSchema).readonly()), method(object({
20757
- eventId: string(),
20924
+ ownerType: EventOwnerTypeSchema,
20925
+ eventId: number().int(),
20758
20926
  deviceId: number()
20759
20927
  }), array(MediaFileInfoSchema).readonly()), method(SearchObjectEventsInput, array(ScoredObjectEventSchema).readonly()), method(object({}), WipeObjectEmbeddingsResultSchema, {
20760
20928
  kind: "mutation",
@@ -26059,8 +26227,8 @@ var IdentitySchema = object({
26059
26227
  id: string(),
26060
26228
  name: string(),
26061
26229
  sampleCount: number().int().nonnegative(),
26062
- coverMediaKey: string().optional(),
26063
- /** Inline base64 of the cover sample's crop, resolved from `coverMediaKey`.
26230
+ coverMediaId: number().int().optional(),
26231
+ /** Inline base64 of the cover sample's crop, resolved from `coverMediaId`.
26064
26232
  * Lets the UI render the person's face avatar instead of a placeholder icon. */
26065
26233
  coverBase64: string().optional()
26066
26234
  });
@@ -26086,8 +26254,8 @@ var IdentitySampleAuditRowSchema = object({
26086
26254
  enrolledAt: number().int(),
26087
26255
  deviceId: number().int().optional(),
26088
26256
  source: _enum(["detected", "photo"]),
26089
- /** The enrolled crop's media key, so the panel can show the evidence. */
26090
- mediaKey: string().optional(),
26257
+ /** The enrolled crop's media row id, so the panel can show the evidence. */
26258
+ mediaId: number().int().optional(),
26091
26259
  /**
26092
26260
  * False = the sample is stamped with a DIFFERENT face model, and a cosine
26093
26261
  * across feature spaces is a well-formed float with no meaning. Every number
@@ -26156,15 +26324,15 @@ var FaceInfoSchema = object({
26156
26324
  */
26157
26325
  cropUrl: string().optional(),
26158
26326
  /** Design B: the face bbox (pixel space) on the key frame — lets a detail
26159
- * view draw the box over the native `keyFrameMediaKey` frame. Absent on
26327
+ * view draw the box over the native `keyFrameMediaId` frame. Absent on
26160
26328
  * legacy rows written before design B. */
26161
26329
  faceBbox: BoundingBoxSchema.optional(),
26162
26330
  /** Design B: MediaStore key of the track's native-resolution key frame.
26163
26331
  * Fetch the native JPEG via the event-media data-plane
26164
- * (`/addon/<addonId>/event-media/<keyFrameMediaKey>`). Absent when the
26332
+ * (`/addon/<addonId>/event-media/m/<keyFrameMediaId>`). Absent when the
26165
26333
  * track produced no key frame (e.g. native/onboard source) — the UI falls
26166
26334
  * back to the inline `base64` face crop. */
26167
- keyFrameMediaKey: string().optional(),
26335
+ keyFrameMediaId: number().int().optional(),
26168
26336
  /** Winning identity-match cosine (0..1) for this face's track, when an
26169
26337
  * identity was auto-confirmed. Lets the UI surface WHY a face was assigned
26170
26338
  * (confidence badge / low-confidence audit). Absent on legacy rows and on
@@ -26233,11 +26401,14 @@ var FaceClusterSchema = object({
26233
26401
  * `data:image/jpeg;base64,…` from a row whose `key` sat right beside it, in a
26234
26402
  * dialog already rendering its key FRAME from the `event-media` plane.
26235
26403
  *
26236
- * `url` is `/addon/<addonId>/event-media/<encoded key>`. The plane resolves a
26237
- * media key directly, so this needed no new plane and no new access decision.
26404
+ * `url` is `/addon/<addonId>/event-media/m/<mediaId>` (D482). The plane
26405
+ * resolves a media row by its own id, so this needed no new plane and no new
26406
+ * access decision.
26238
26407
  */
26239
26408
  var MediaFileLiteSchema$1 = object({
26240
- key: string(),
26409
+ /** The media row's own id — the same address `MediaFileRef.mediaId` carries
26410
+ * (D482). It was the row's composite key, which embedded the owner. */
26411
+ mediaId: number().int(),
26241
26412
  kind: string(),
26242
26413
  url: string(),
26243
26414
  sizeBytes: number(),
@@ -26254,7 +26425,7 @@ method(object({
26254
26425
  * covers inline, ~10 KB of base64 per row, on a query this UI mounts
26255
26426
  * four times and the viewer holds at `staleTime: 30_000`.
26256
26427
  *
26257
- * Nothing loses its avatar: `coverMediaKey` is already on every row and
26428
+ * Nothing loses its avatar: `coverMediaId` is already on every row and
26258
26429
  * the `event-media` plane serves that key `immutable` with an ETag.
26259
26430
  *
26260
26431
  * **This is an INPUT field, so it does not reach the addon until the
@@ -29617,8 +29788,8 @@ var VehicleSchema = object({
29617
29788
  id: string(),
29618
29789
  name: string(),
29619
29790
  sampleCount: number().int().nonnegative(),
29620
- coverMediaKey: string().optional(),
29621
- /** Inline base64 of the cover sample's plate crop, resolved from `coverMediaKey`. */
29791
+ coverMediaId: number().int().optional(),
29792
+ /** Inline base64 of the cover sample's plate crop, resolved from `coverMediaId`. */
29622
29793
  coverBase64: string().optional()
29623
29794
  });
29624
29795
  var VehicleSampleInfoSchema = object({
@@ -29651,7 +29822,7 @@ var PlateInfoSchema = object({
29651
29822
  /** keyFrame parity: the plate bbox (pixel space) on the native key frame. */
29652
29823
  plateBbox: BoundingBoxSchema.optional(),
29653
29824
  /** keyFrame parity: MediaStore key of the track's native-resolution key frame. */
29654
- keyFrameMediaKey: string().optional(),
29825
+ keyFrameMediaId: number().int().optional(),
29655
29826
  base64: string().optional(),
29656
29827
  /**
29657
29828
  * Same crop as a data-plane URL, always present when the plate has a stored
@@ -29672,11 +29843,14 @@ var PlateInfoSchema = object({
29672
29843
  * `data:image/jpeg;base64,…` from a row whose `key` sat right beside it, in a
29673
29844
  * dialog already rendering its key FRAME from the `event-media` plane.
29674
29845
  *
29675
- * `url` is `/addon/<addonId>/event-media/<encoded key>`. The plane resolves a
29676
- * media key directly, so this needed no new plane and no new access decision.
29846
+ * `url` is `/addon/<addonId>/event-media/m/<mediaId>` (D482). The plane
29847
+ * resolves a media row by its own id, so this needed no new plane and no new
29848
+ * access decision.
29677
29849
  */
29678
29850
  var MediaFileLiteSchema = object({
29679
- key: string(),
29851
+ /** The media row's own id — the same address `MediaFileRef.mediaId` carries
29852
+ * (D482). It was the row's composite key, which embedded the owner. */
29853
+ mediaId: number().int(),
29680
29854
  kind: string(),
29681
29855
  url: string(),
29682
29856
  sizeBytes: number(),
@@ -29735,7 +29909,7 @@ method(object({
29735
29909
  }), method(object({
29736
29910
  /** Inline {@link VehicleSchema.coverBase64} on every row. Default
29737
29911
  * `false` — the vehicle twin of `faceGallery.listIdentities`'s
29738
- * option; `coverMediaKey` + the `event-media` plane carry the picture.
29912
+ * option; `coverMediaId` + the `event-media` plane carry the picture.
29739
29913
  * INPUT field: stripped by the hub router until the train ships, which
29740
29914
  * resolves to `false` and is exactly the intended default. */
29741
29915
  includeCrops: boolean().optional() }).optional(), array(VehicleSchema).readonly()), method(object({ name: string().min(1) }), VehicleSchema, {
@@ -31304,7 +31478,14 @@ var SceneReferenceSchema = object({
31304
31478
  modelId: string(),
31305
31479
  condition: SceneConditionSchema,
31306
31480
  capturedAt: number(),
31307
- thumbnailMediaId: string().optional(),
31481
+ /**
31482
+ * The reference thumbnail's media ROW id (D482).
31483
+ *
31484
+ * The name already said `mediaId` while the value was the row's composite
31485
+ * key — a leftover that read as done and was not. It is the row's own id
31486
+ * now, addressed at `/addon/<addonId>/event-media/m/<id>`.
31487
+ */
31488
+ thumbnailMediaId: number().int().optional(),
31308
31489
  /** Whole-frame (downscaled) embedding captured alongside the ROI crop. The
31309
31490
  * anti-view-shift anchor: a bumped camera, a PTZ preset or a re-aim makes the
31310
31491
  * normalized rect frame a different piece of world, and the scene would
@@ -32395,7 +32576,29 @@ var LoggingSettingsPatchSchema = object({
32395
32576
  * disarmed the channels it did not mention would make the Levels page and
32396
32577
  * the Diagnostics page fight over the same value.
32397
32578
  */
32398
- channels: array(LogChannelWindowPatchSchema).readonly().optional()
32579
+ channels: array(LogChannelWindowPatchSchema).readonly().optional(),
32580
+ /**
32581
+ * How many days the analytics OPS LOG is kept — the audit trail of what
32582
+ * retention actually deleted.
32583
+ *
32584
+ * It lives HERE, on the logging document, and not on the analytics addon's
32585
+ * settings form, on the operator's instruction: every other log-ish window in
32586
+ * this system is configured through this one document, and a retention audit
32587
+ * configured somewhere else is a second place to look when the question is
32588
+ * "what happened to my data".
32589
+ *
32590
+ * That placement has a cost worth stating: this document ships in the
32591
+ * framework closure, so this knob needs a published `@camstack/server` while
32592
+ * the four windows beside it (D485) reach a node on `camstack deploy`.
32593
+ *
32594
+ * `retention-model.ts` argued this one must NOT follow a device window,
32595
+ * because the audit trail is the history of the SWEEP and not of the camera.
32596
+ * That argument stands and is untouched — what changes is that 30 days stops
32597
+ * being a constant nobody can reach. `0` keeps it forever. The floor is 1 day
32598
+ * rather than 0-as-delete: an audit log truncated to nothing is precisely the
32599
+ * state in which the next 9.5 GiB leak cannot be explained.
32600
+ */
32601
+ opsLogRetentionDays: number().int().min(0).max(3650).optional()
32399
32602
  });
32400
32603
  /**
32401
32604
  * Which LAYER of the hierarchy is addressed. Absent = the cluster layer.
@@ -32468,6 +32671,14 @@ var LoggingSettingsStateSchema = object({
32468
32671
  channels: array(LogChannelDescriptorSchema).readonly(),
32469
32672
  /** The channels ARMED right now, each with its deadline. */
32470
32673
  activeChannels: array(LogChannelWindowStateSchema).readonly(),
32674
+ /**
32675
+ * The ops-log window in days, as it is in force. `0` = kept forever.
32676
+ *
32677
+ * Reported rather than left to the caller's memory of what it wrote: this is
32678
+ * the value the analytics sweep will actually use, and an operator asking how
32679
+ * long their audit trail lives should not have to infer it from a default.
32680
+ */
32681
+ opsLogRetentionDays: number().int().min(0),
32471
32682
  persisted: boolean()
32472
32683
  });
32473
32684
  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(), {
@@ -33288,7 +33499,7 @@ var StationaryObjectSchema = object({
33288
33499
  /** Enrichment label carried from the source track (identity / plate). */
33289
33500
  label: string().optional(),
33290
33501
  /** Native-resolution key-frame media key for the parked object's best image. */
33291
- keyFrameMediaKey: string().optional()
33502
+ keyFrameMediaId: number().int().optional()
33292
33503
  });
33293
33504
  var CameraOccupancySnapshotSchema = object({
33294
33505
  /** Frame timestamp of the inference result that produced this snapshot. */
@@ -36026,6 +36237,12 @@ Object.freeze({
36026
36237
  addonId: null,
36027
36238
  access: "create"
36028
36239
  },
36240
+ "dataStoreProvider.upsert": {
36241
+ capName: "data-store-provider",
36242
+ capScope: "system",
36243
+ addonId: null,
36244
+ access: "create"
36245
+ },
36029
36246
  "dayNight.getOptions": {
36030
36247
  capName: "day-night",
36031
36248
  capScope: "device",
@@ -38462,6 +38679,12 @@ Object.freeze({
38462
38679
  addonId: null,
38463
38680
  access: "view"
38464
38681
  },
38682
+ "pipelineAnalytics.listRecentSummaries": {
38683
+ capName: "pipeline-analytics",
38684
+ capScope: "device",
38685
+ addonId: null,
38686
+ access: "view"
38687
+ },
38465
38688
  "pipelineAnalytics.listRecentTracks": {
38466
38689
  capName: "pipeline-analytics",
38467
38690
  capScope: "device",
@@ -39890,6 +40113,12 @@ Object.freeze({
39890
40113
  addonId: null,
39891
40114
  access: "create"
39892
40115
  },
40116
+ "settingsStore.upsert": {
40117
+ capName: "settings-store",
40118
+ capScope: "system",
40119
+ addonId: null,
40120
+ access: "create"
40121
+ },
39893
40122
  "smtpProvider.getStatus": {
39894
40123
  capName: "smtp-provider",
39895
40124
  capScope: "system",
@@ -42283,6 +42512,11 @@ Object.freeze({
42283
42512
  form: "single",
42284
42513
  optional: true
42285
42514
  }],
42515
+ "pipelineAnalytics.listRecentSummaries": [{
42516
+ name: "deviceIds",
42517
+ form: "array",
42518
+ optional: false
42519
+ }],
42286
42520
  "pipelineAnalytics.listRecentTracks": [{
42287
42521
  name: "deviceIds",
42288
42522
  form: "array",
package/dist/addon.mjs CHANGED
@@ -10,7 +10,7 @@ import { getCACertificates, setDefaultCACertificates } from "node:tls";
10
10
  //#region \0rolldown/runtime.js
11
11
  var __require$1 = /* @__PURE__ */ createRequire(import.meta.url);
12
12
  //#endregion
13
- //#region ../types/dist/event-category-DAXzJeTX.mjs
13
+ //#region ../types/dist/event-category-ZyX6jcse.mjs
14
14
  var EventCategory = /* @__PURE__ */ function(EventCategory) {
15
15
  EventCategory["SystemBoot"] = "system.boot";
16
16
  EventCategory["SystemAddonsReady"] = "system.addons-ready";
@@ -571,7 +571,7 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
571
571
  * a package zone — a newly-appeared stationary object of a package class
572
572
  * that cleared the class / zone / dwell / size gates. Payload:
573
573
  * `PipelineAnalyticsPackageDeliveredPayload` carrying `{ deviceId,
574
- * entryId, className, zoneIds, keyFrameMediaKey?, bbox, timestamp }`.
574
+ * entryId, className, zoneIds, keyFrameMediaId?, bbox, timestamp }`.
575
575
  * Telemetry (D8): the durable record is the `package-events` store row;
576
576
  * this bus topic drives notifier rules + live UI. See
577
577
  * docs/superpowers/specs/2026-07-17-package-zones-design.md §5.1.
@@ -5357,7 +5357,7 @@ var ZodIssueCode = {
5357
5357
  var ZodFirstPartyTypeKind;
5358
5358
  ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
5359
5359
  //#endregion
5360
- //#region ../types/dist/sleep-BnujYGPe.mjs
5360
+ //#region ../types/dist/sleep-DBKu2-U5.mjs
5361
5361
  /**
5362
5362
  * The audio chunk plane's byte format, and the ONE expansion from a coded
5363
5363
  * window to float samples (D455).
@@ -7324,13 +7324,30 @@ new Set([
7324
7324
  "scene",
7325
7325
  "motion",
7326
7326
  "object",
7327
- "audio"
7327
+ "audio",
7328
+ "mosaic"
7328
7329
  ]);
7329
- new Set([
7330
+ /**
7331
+ * The owner types that are event tables, in the order the event-media resolver
7332
+ * should consider them. Exported so a consumer asking "is this key an event?"
7333
+ * does not re-spell the list and drift from it.
7334
+ */
7335
+ var EVENT_OWNER_TYPES = [
7330
7336
  "motion",
7331
7337
  "object",
7332
7338
  "audio"
7333
- ]);
7339
+ ];
7340
+ /**
7341
+ * The same list as a Zod enum, for the cap inputs that must NAME the table
7342
+ * (D482: `getEventMedia` / `listEventMedia` take an owner, and an owner is
7343
+ * `(table, id)`).
7344
+ *
7345
+ * Built FROM {@link EVENT_OWNER_TYPES} rather than re-spelled: a fourth event
7346
+ * table would otherwise be accepted by the codec and refused at the door, with
7347
+ * nothing failing until a caller asked.
7348
+ */
7349
+ var EventOwnerTypeSchema = _enum(EVENT_OWNER_TYPES);
7350
+ new Set(EVENT_OWNER_TYPES);
7334
7351
  var EncodeProfileSchema = object({
7335
7352
  video: object({
7336
7353
  codec: _enum([
@@ -7369,7 +7386,23 @@ var EncodeProfileSchema = object({
7369
7386
  "zerolatency",
7370
7387
  "film",
7371
7388
  "animation"
7372
- ]).optional()
7389
+ ]).optional(),
7390
+ /**
7391
+ * ONE slice per access unit.
7392
+ *
7393
+ * `-tune zerolatency` turns on x264's sliced threads, and a frame then leaves
7394
+ * the encoder as five NAL slices that share one RTP timestamp and carry one
7395
+ * marker bit. A libwebrtc depacketiser sees five frame-starts and one
7396
+ * frame-end per frame: the first pictures render and the video then freezes
7397
+ * for good while the audio, on its own plane, plays on. Measured on this hub
7398
+ * 2026-09-13 against the Echo, and reduced to one slice by this flag alone.
7399
+ *
7400
+ * A NAMED field and not a raw flag, because {@link EgressEncodeSchema} omits
7401
+ * `outputArgs` on purpose: an opaque array is part of the sharing key, so two
7402
+ * consumers meaning the same thing spelled differently would stop sharing one
7403
+ * child. Absent means "whatever the encoder does" — today's behaviour.
7404
+ */
7405
+ singleSlicePerFrame: boolean().optional()
7373
7406
  }),
7374
7407
  audio: union([literal("passthrough"), object({
7375
7408
  codec: _enum([
@@ -7419,7 +7452,7 @@ var BASE_LIVE_EGRESS_PROFILE = {
7419
7452
  audio: "passthrough"
7420
7453
  };
7421
7454
  ({ ...BASE_LIVE_EGRESS_PROFILE }), { ...BASE_LIVE_EGRESS_PROFILE.video };
7422
- ({ ...BASE_LIVE_EGRESS_PROFILE });
7455
+ ({ ...BASE_LIVE_EGRESS_PROFILE }), { ...BASE_LIVE_EGRESS_PROFILE.video };
7423
7456
  /**
7424
7457
  * Deep wiring healthcheck — snapshot of active reachability probes across
7425
7458
  * every declared capability + widget of every installed plugin, on every
@@ -12529,6 +12562,16 @@ method(object({
12529
12562
  filter: QueryFilterSchema.optional(),
12530
12563
  columns: array(string()).readonly().optional()
12531
12564
  }), array(SettingsRecordSchema).readonly()), method(object({
12565
+ namespace: string().optional(),
12566
+ collection: string(),
12567
+ /** Declared columns identifying the slot; must be covered by a UNIQUE
12568
+ * index on the collection. Never empty. */
12569
+ conflict: array(string()).readonly(),
12570
+ record: BulkRecordSchema
12571
+ }), object({
12572
+ /** The id the row HAS: assigned by SQLite on an insert, or the existing
12573
+ * row's own id on an update. */
12574
+ id: union([string(), number()]) }), { kind: "mutation" }), method(object({
12532
12575
  namespace: string().optional(),
12533
12576
  collection: string(),
12534
12577
  record: object({
@@ -12663,6 +12706,14 @@ method(_void(), EngineInfoSchema, { auth: "admin" }), method(object({
12663
12706
  id: union([string(), number()]) }), {
12664
12707
  kind: "mutation",
12665
12708
  auth: "admin"
12709
+ }), method(object({
12710
+ namespace: string().optional(),
12711
+ collection: string(),
12712
+ conflict: array(string()).readonly(),
12713
+ record: BulkRecordSchema
12714
+ }), object({ id: union([string(), number()]) }), {
12715
+ kind: "mutation",
12716
+ auth: "admin"
12666
12717
  }), method(object({
12667
12718
  namespace: string().optional(),
12668
12719
  collection: string(),
@@ -19162,8 +19213,8 @@ var TrackPositionSchema = object({
19162
19213
  var TrackSnapshotSchema = object({
19163
19214
  timestamp: number(),
19164
19215
  position: TrackPositionSchema,
19165
- /** MediaStore key; resolve via `getTrackMedia({ trackId })`. */
19166
- mediaKey: string()
19216
+ /** The snapshot's media row id (D482); resolve via `listTrackMedia({ trackId })`. */
19217
+ mediaId: number().int()
19167
19218
  });
19168
19219
  /**
19169
19220
  * Normalized 0..1 trajectory envelope (min/max over every position bbox,
@@ -19767,14 +19818,14 @@ var ObjectEventSchema = object({
19767
19818
  * pixel-space `bbox` onto a displayed image. Omitted in slim projection. */
19768
19819
  frameWidth: number().optional(),
19769
19820
  frameHeight: number().optional(),
19770
- /** MediaStore key for the crop attached to this event (if any). */
19771
- mediaKey: string().optional(),
19772
- /** Design B: MediaStore key of the track's native-resolution key frame (the
19821
+ /** Media row id of the crop attached to this event (if any) — D482. */
19822
+ mediaId: number().int().optional(),
19823
+ /** Design B: media row id of the track's native-resolution key frame (the
19773
19824
  * best-detection full frame). Resolve via the event-media data-plane
19774
- * (`/addon/<addonId>/event-media/<keyFrameMediaKey>`) for a detail view that
19825
+ * (`/addon/<addonId>/event-media/m/<keyFrameMediaId>`) for a detail view that
19775
19826
  * draws `bbox` over the native frame. Absent on legacy rows / non-decoded
19776
- * sources — consumers fall back to `mediaKey` (the tight crop). */
19777
- keyFrameMediaKey: string().optional(),
19827
+ * sources — consumers fall back to `mediaId` (the tight crop). */
19828
+ keyFrameMediaId: number().int().optional(),
19778
19829
  /** Populated by B5 (recording playback URL for this event). */
19779
19830
  mediaUrl: string().optional(),
19780
19831
  /** The parent track's key-event importance [0,1], propagated to every object
@@ -19824,7 +19875,7 @@ var MediaFileKindEnum = _enum([
19824
19875
  * hub-main's heap on the way past — for an `<img>` that would have cached it.
19825
19876
  *
19826
19877
  * `url` points at the `event-media` data plane
19827
- * (`/addon/<addonId>/event-media/<storedKey>`), which serves the same blob
19878
+ * (`/addon/<addonId>/event-media/m/<mediaId>` — D482), which serves the same blob
19828
19879
  * with an ETag and `Cache-Control: immutable`, honours conditional GETs, can
19829
19880
  * render a `?variant=thumb`, and streams. The hub gate in front of it requires
19830
19881
  * a bearer or the session cookie (`access: 'authenticated'`), so the bytes are
@@ -19832,10 +19883,13 @@ var MediaFileKindEnum = _enum([
19832
19883
  * `data-plane-access.ts` for the rule and the one gap it does not close
19833
19884
  * (per-device scoping).
19834
19885
  *
19835
- * The URL is built from the row's **stored** key, which is not always its
19836
- * published `kind`: a track's face/plate crop is stored as `crop` under
19886
+ * The URL is built from the row's own id, which since D482 says nothing about
19887
+ * the row's owner or kind — and that is the point. The published `kind` is not
19888
+ * the stored one (a track's face/plate crop is stored as `crop` under
19837
19889
  * `('face'|'plate', '<prefix>-<trackId>')` and published as
19838
- * `faceCrop`/`plateCrop`. `MediaStore.getByKey` knows only the stored key.
19890
+ * `faceCrop`/`plateCrop`), and under the old composite key the URL had to be
19891
+ * taken from `row.key` verbatim or it 404'd exactly those two rows. An id
19892
+ * cannot be mis-reconstructed, because there is nothing in it to reconstruct.
19839
19893
  *
19840
19894
  * ## `base64` is TRANSITIONAL and is going away
19841
19895
  *
@@ -19848,7 +19902,19 @@ var MediaFileKindEnum = _enum([
19848
19902
  * `analytics-query-facade.ts`; nothing else reads it.
19849
19903
  */
19850
19904
  var MediaFileSchema = object({
19851
- key: string(),
19905
+ /**
19906
+ * The media row's OWN id — the rowid SQLite assigned it (D482).
19907
+ *
19908
+ * It used to be the row's composite key, `<ownerType>:<ownerId>:<fileKind>
19909
+ * [:<timestampMs>]`, which embedded a FOREIGN id. D474 made event ids
19910
+ * per-table rowid aliases, so `object:101314` and `motion:101314` are two
19911
+ * different rows that spell the same number, and a track whose
19912
+ * `bestEventId` was an object event was served a motion event's snapshot —
19913
+ * a night-time thumbnail on an afternoon track, with no error anywhere. A
19914
+ * surrogate id cannot name the wrong row's owner, because it names no owner
19915
+ * at all.
19916
+ */
19917
+ mediaId: number().int(),
19852
19918
  kind: MediaFileKindEnum,
19853
19919
  sizeBytes: number(),
19854
19920
  timestamp: number()
@@ -19956,7 +20022,7 @@ var RetrainTrackSchema = object({
19956
20022
  });
19957
20023
  /** A frame the picker may offer — an index row, no blob was read to produce it. */
19958
20024
  var RetrainFrameCandidateSchema = object({
19959
- mediaKey: string(),
20025
+ mediaId: number().int(),
19960
20026
  kind: MediaFileKindEnum,
19961
20027
  timestamp: number(),
19962
20028
  sizeBytes: number().int(),
@@ -19970,7 +20036,7 @@ var RetrainFrameSchema = object({
19970
20036
  deviceId: number(),
19971
20037
  trackId: string(),
19972
20038
  /** Provenance only. It may already point at nothing — that is expected. */
19973
- sourceMediaKey: string(),
20039
+ sourceMediaId: number().int(),
19974
20040
  sourceKind: MediaFileKindEnum,
19975
20041
  sizeBytes: number().int(),
19976
20042
  width: number().int(),
@@ -19986,7 +20052,7 @@ var RetrainCopyRefusalSchema = _enum([
19986
20052
  var RetrainFrameSelectionSchema = object({
19987
20053
  copied: array(RetrainFrameSchema).readonly(),
19988
20054
  refused: array(object({
19989
- sourceMediaKey: string(),
20055
+ sourceMediaId: number().int(),
19990
20056
  reason: RetrainCopyRefusalSchema
19991
20057
  })).readonly()
19992
20058
  });
@@ -19994,7 +20060,7 @@ var RetrainFrameListSchema = object({
19994
20060
  candidates: array(RetrainFrameCandidateSchema).readonly(),
19995
20061
  copies: array(RetrainFrameSchema).readonly(),
19996
20062
  /** What the page pre-selects — the native key frame when one survives. */
19997
- autoPickMediaKey: string().optional()
20063
+ autoPickMediaId: number().int().optional()
19998
20064
  });
19999
20065
  /** What the operator asked the assist to look for. */
20000
20066
  var RetrainAssistSubjectSchema = discriminatedUnion("kind", [object({
@@ -20089,9 +20155,11 @@ var RecentTracksQueryInput = object({
20089
20155
  });
20090
20156
  /**
20091
20157
  * A Summary (D359): the per-camera session envelope that references tracks.
20092
- * `groupShotKey` is the media key of its group shot (`ownerKind: 'summary'`,
20093
- * served by the event-media plane by key), null until the first frame with a
20094
- * member visible has been materialised.
20158
+ * `groupShotMediaId` is the media ROW id of its group shot (`ownerKind:
20159
+ * 'summary'`, served by the event-media plane at `/m/<id>`), null until the
20160
+ * first frame with a member visible has been materialised (D482 — it was the
20161
+ * row's composite key, which embedded the owner and could name another table's
20162
+ * row once event ids became per-table rowids).
20095
20163
  */
20096
20164
  var SummarySchema = object({
20097
20165
  id: string(),
@@ -20100,19 +20168,115 @@ var SummarySchema = object({
20100
20168
  lastActiveAt: number(),
20101
20169
  sealedAt: number().nullable(),
20102
20170
  memberCount: number().int().nonnegative(),
20103
- groupShotKey: string().nullable()
20171
+ groupShotMediaId: number().int().nullable()
20104
20172
  });
20105
20173
  var SummariesQueryInput = object({
20106
20174
  deviceIds: array(number()).min(1),
20107
20175
  since: number().optional(),
20108
20176
  until: number().optional(),
20109
- limit: number().int().min(1).max(200).default(50)
20177
+ limit: number().int().min(1).max(200).default(50),
20178
+ /** The same member-wise filter {@link listRecentSummaries} takes — one
20179
+ * meaning of "dog" on every summary surface. */
20180
+ classes: array(string().min(1).max(60)).max(40).optional()
20110
20181
  });
20111
- var SummariesPageSchema = object({ summaries: array(SummarySchema).readonly() });
20112
20182
  var SummaryDetailSchema = object({
20113
20183
  summary: SummarySchema,
20114
- /** Member track ids, in absorption order. */
20115
- trackIds: array(string()).readonly()
20184
+ /** Members in absorption order, oldest join first. */
20185
+ members: array(object({
20186
+ trackId: string(),
20187
+ /**
20188
+ * The track's class at the time it JOINED, or `null` when it was unresolved
20189
+ * and the track no longer exists to fill it.
20190
+ *
20191
+ * The join, not the latest opinion: class voting can re-decide a track's
20192
+ * class afterwards, and a group's composition is the history of who came
20193
+ * together. A consumer counts these to badge a thumbnail — "two people and a
20194
+ * dog" — rather than being handed a second, denormalised tally that would
20195
+ * drift from the members it claims to describe.
20196
+ */
20197
+ className: string().nullable(),
20198
+ /** `primary` is the one member that carries the group's identity. */
20199
+ role: _enum([
20200
+ "primary",
20201
+ "sibling",
20202
+ "child"
20203
+ ]).nullable(),
20204
+ joinedAt: number(),
20205
+ /** Tier 1 — the sub-class (`dog`, `van`), resolved from the member's track
20206
+ * at read time. Absent when nothing resolved, never an empty string. */
20207
+ label: string().optional(),
20208
+ /** Tier 2 — the instance: a person's name, a plate. Absent when the pipeline
20209
+ * recognised nobody, and absent for a member whose track has been pruned —
20210
+ * a thumbnail that names the wrong person is worse than one naming nobody. */
20211
+ subLabel: string().optional()
20212
+ })).readonly()
20213
+ });
20214
+ /**
20215
+ * What a LIST of groups carries: the envelope plus what it is MADE OF.
20216
+ *
20217
+ * Coarse on purpose — the operator's rule is "only the rough data on the list,
20218
+ * we extend when we notice we need more". Enough to draw the card ("two people
20219
+ * and a dog") and no more. The MEMBERS, their names and the per-member links
20220
+ * are on {@link getSummary}: shipping every member of every group so a client
20221
+ * can count them turns a page of two hundred groups into a thousand records to
20222
+ * draw two hundred badges.
20223
+ */
20224
+ var SummaryListItemSchema = object({
20225
+ summary: SummarySchema,
20226
+ /** Class counts, most numerous first; `className: null` is a member whose
20227
+ * class never resolved, counted so the counts add up to `memberCount`. */
20228
+ classes: array(object({
20229
+ className: string().nullable(),
20230
+ count: number().int().positive()
20231
+ })).readonly()
20232
+ });
20233
+ var SummariesPageSchema = object({ summaries: array(SummaryListItemSchema).readonly() });
20234
+ /**
20235
+ * The paged feed, deliberately the SAME shape as {@link RecentTracksQueryInput}.
20236
+ *
20237
+ * The reel on the cameras page and the Events gallery both ride a cursor, so a
20238
+ * summaries feed that could only answer "the last N for these cameras"
20239
+ * (`listSummaries`) would make groups available in the timeline and nowhere
20240
+ * else. Two feeds with different ordering contracts would be two ideas of what
20241
+ * "newest" means, on one screen.
20242
+ */
20243
+ var RecentSummariesQueryInput = object({
20244
+ /** Devices to merge. An empty array yields an empty page. */
20245
+ deviceIds: array(number()),
20246
+ /** Window lower bound on `lastActiveAt` (inclusive). */
20247
+ since: number().optional(),
20248
+ /** Window upper bound on `lastActiveAt` (inclusive). */
20249
+ until: number().optional(),
20250
+ limit: number().int().min(1).max(500).default(100),
20251
+ /** Opaque continuation cursor from a previous page's `nextCursor`. */
20252
+ cursor: string().optional(),
20253
+ /**
20254
+ * Restrict to these classes — THE SAME FIELD `listRecentTracks` takes, and
20255
+ * deliberately the same name: the events filter tree emits one list of ticked
20256
+ * taxonomy nodes, and a summaries feed that called it something else would
20257
+ * make the operator's one filter component produce two shapes.
20258
+ *
20259
+ * A question about the MEMBERS: a group matches when ANY of them does. "Show
20260
+ * me the arrivals with a dog" has to return the group of four people who had
20261
+ * one with them; a filter on the group's own fields could only ever answer
20262
+ * about its primary.
20263
+ *
20264
+ * Matched against all THREE tiers of a member — the class (`animal`), the
20265
+ * sub-class (`dog`) and the instance (a name, a plate) — because which tier a
20266
+ * ticked node lives on is the taxonomy's business, not the caller's. `dog` is
20267
+ * an event kind in the tree and a tier-1 label on an `animal` track; a filter
20268
+ * that read only the class would answer "animal" and never "dog".
20269
+ *
20270
+ * ABSENT or EMPTY means no filter — absent is not a selection of none.
20271
+ */
20272
+ classes: array(string().min(1).max(60)).max(40).optional()
20273
+ });
20274
+ var RecentSummariesPageSchema = object({
20275
+ /** Ordered by (`lastActiveAt` DESC, id DESC). Same light item as
20276
+ * {@link listSummaries} — one list shape, so a card renders the same
20277
+ * whichever feed drew it. */
20278
+ summaries: array(SummaryListItemSchema).readonly(),
20279
+ nextCursor: string().nullable()
20116
20280
  });
20117
20281
  var RecentTracksPageSchema = object({
20118
20282
  /** Merged page, ordered by (`lastSeen` DESC, `trackId` DESC). */
@@ -20526,7 +20690,7 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
20526
20690
  classes: array(string()).optional(),
20527
20691
  /** See {@link ExcludeSourcesDoc}. */
20528
20692
  excludeSources: array(TrackSourceSchema).optional()
20529
- }), array(TrackSchema).readonly()), method(RecentTracksQueryInput, RecentTracksPageSchema), method(SummariesQueryInput, SummariesPageSchema), method(object({ id: string() }), SummaryDetailSchema.nullable()), method(object({ deviceId: number() }), _void(), {
20693
+ }), array(TrackSchema).readonly()), method(RecentTracksQueryInput, RecentTracksPageSchema), method(SummariesQueryInput, SummariesPageSchema), method(RecentSummariesQueryInput, RecentSummariesPageSchema), method(object({ id: string() }), SummaryDetailSchema.nullable()), method(object({ deviceId: number() }), _void(), {
20530
20694
  kind: "mutation",
20531
20695
  auth: "admin"
20532
20696
  }), 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({
@@ -20654,7 +20818,7 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
20654
20818
  }), method(object({
20655
20819
  deviceId: number(),
20656
20820
  trackId: string(),
20657
- mediaKeys: array(string()).min(1)
20821
+ mediaIds: array(number().int()).min(1)
20658
20822
  }), RetrainFrameSelectionSchema, {
20659
20823
  kind: "mutation",
20660
20824
  auth: "admin"
@@ -20722,7 +20886,10 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
20722
20886
  kind: "query",
20723
20887
  auth: "admin"
20724
20888
  }), method(object({
20725
- eventId: string(),
20889
+ /** Which of the three event tables owns the row. */
20890
+ ownerType: EventOwnerTypeSchema,
20891
+ /** The event's rowid in that table (D474: an event id is a number). */
20892
+ eventId: number().int(),
20726
20893
  kind: MediaFileKindEnum.optional(),
20727
20894
  deviceId: number()
20728
20895
  }), array(MediaFileSchema).readonly()), method(object({
@@ -20733,7 +20900,8 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
20733
20900
  trackId: string(),
20734
20901
  deviceId: number()
20735
20902
  }), array(MediaFileInfoSchema).readonly()), method(object({
20736
- eventId: string(),
20903
+ ownerType: EventOwnerTypeSchema,
20904
+ eventId: number().int(),
20737
20905
  deviceId: number()
20738
20906
  }), array(MediaFileInfoSchema).readonly()), method(SearchObjectEventsInput, array(ScoredObjectEventSchema).readonly()), method(object({}), WipeObjectEmbeddingsResultSchema, {
20739
20907
  kind: "mutation",
@@ -26038,8 +26206,8 @@ var IdentitySchema = object({
26038
26206
  id: string(),
26039
26207
  name: string(),
26040
26208
  sampleCount: number().int().nonnegative(),
26041
- coverMediaKey: string().optional(),
26042
- /** Inline base64 of the cover sample's crop, resolved from `coverMediaKey`.
26209
+ coverMediaId: number().int().optional(),
26210
+ /** Inline base64 of the cover sample's crop, resolved from `coverMediaId`.
26043
26211
  * Lets the UI render the person's face avatar instead of a placeholder icon. */
26044
26212
  coverBase64: string().optional()
26045
26213
  });
@@ -26065,8 +26233,8 @@ var IdentitySampleAuditRowSchema = object({
26065
26233
  enrolledAt: number().int(),
26066
26234
  deviceId: number().int().optional(),
26067
26235
  source: _enum(["detected", "photo"]),
26068
- /** The enrolled crop's media key, so the panel can show the evidence. */
26069
- mediaKey: string().optional(),
26236
+ /** The enrolled crop's media row id, so the panel can show the evidence. */
26237
+ mediaId: number().int().optional(),
26070
26238
  /**
26071
26239
  * False = the sample is stamped with a DIFFERENT face model, and a cosine
26072
26240
  * across feature spaces is a well-formed float with no meaning. Every number
@@ -26135,15 +26303,15 @@ var FaceInfoSchema = object({
26135
26303
  */
26136
26304
  cropUrl: string().optional(),
26137
26305
  /** Design B: the face bbox (pixel space) on the key frame — lets a detail
26138
- * view draw the box over the native `keyFrameMediaKey` frame. Absent on
26306
+ * view draw the box over the native `keyFrameMediaId` frame. Absent on
26139
26307
  * legacy rows written before design B. */
26140
26308
  faceBbox: BoundingBoxSchema.optional(),
26141
26309
  /** Design B: MediaStore key of the track's native-resolution key frame.
26142
26310
  * Fetch the native JPEG via the event-media data-plane
26143
- * (`/addon/<addonId>/event-media/<keyFrameMediaKey>`). Absent when the
26311
+ * (`/addon/<addonId>/event-media/m/<keyFrameMediaId>`). Absent when the
26144
26312
  * track produced no key frame (e.g. native/onboard source) — the UI falls
26145
26313
  * back to the inline `base64` face crop. */
26146
- keyFrameMediaKey: string().optional(),
26314
+ keyFrameMediaId: number().int().optional(),
26147
26315
  /** Winning identity-match cosine (0..1) for this face's track, when an
26148
26316
  * identity was auto-confirmed. Lets the UI surface WHY a face was assigned
26149
26317
  * (confidence badge / low-confidence audit). Absent on legacy rows and on
@@ -26212,11 +26380,14 @@ var FaceClusterSchema = object({
26212
26380
  * `data:image/jpeg;base64,…` from a row whose `key` sat right beside it, in a
26213
26381
  * dialog already rendering its key FRAME from the `event-media` plane.
26214
26382
  *
26215
- * `url` is `/addon/<addonId>/event-media/<encoded key>`. The plane resolves a
26216
- * media key directly, so this needed no new plane and no new access decision.
26383
+ * `url` is `/addon/<addonId>/event-media/m/<mediaId>` (D482). The plane
26384
+ * resolves a media row by its own id, so this needed no new plane and no new
26385
+ * access decision.
26217
26386
  */
26218
26387
  var MediaFileLiteSchema$1 = object({
26219
- key: string(),
26388
+ /** The media row's own id — the same address `MediaFileRef.mediaId` carries
26389
+ * (D482). It was the row's composite key, which embedded the owner. */
26390
+ mediaId: number().int(),
26220
26391
  kind: string(),
26221
26392
  url: string(),
26222
26393
  sizeBytes: number(),
@@ -26233,7 +26404,7 @@ method(object({
26233
26404
  * covers inline, ~10 KB of base64 per row, on a query this UI mounts
26234
26405
  * four times and the viewer holds at `staleTime: 30_000`.
26235
26406
  *
26236
- * Nothing loses its avatar: `coverMediaKey` is already on every row and
26407
+ * Nothing loses its avatar: `coverMediaId` is already on every row and
26237
26408
  * the `event-media` plane serves that key `immutable` with an ETag.
26238
26409
  *
26239
26410
  * **This is an INPUT field, so it does not reach the addon until the
@@ -29596,8 +29767,8 @@ var VehicleSchema = object({
29596
29767
  id: string(),
29597
29768
  name: string(),
29598
29769
  sampleCount: number().int().nonnegative(),
29599
- coverMediaKey: string().optional(),
29600
- /** Inline base64 of the cover sample's plate crop, resolved from `coverMediaKey`. */
29770
+ coverMediaId: number().int().optional(),
29771
+ /** Inline base64 of the cover sample's plate crop, resolved from `coverMediaId`. */
29601
29772
  coverBase64: string().optional()
29602
29773
  });
29603
29774
  var VehicleSampleInfoSchema = object({
@@ -29630,7 +29801,7 @@ var PlateInfoSchema = object({
29630
29801
  /** keyFrame parity: the plate bbox (pixel space) on the native key frame. */
29631
29802
  plateBbox: BoundingBoxSchema.optional(),
29632
29803
  /** keyFrame parity: MediaStore key of the track's native-resolution key frame. */
29633
- keyFrameMediaKey: string().optional(),
29804
+ keyFrameMediaId: number().int().optional(),
29634
29805
  base64: string().optional(),
29635
29806
  /**
29636
29807
  * Same crop as a data-plane URL, always present when the plate has a stored
@@ -29651,11 +29822,14 @@ var PlateInfoSchema = object({
29651
29822
  * `data:image/jpeg;base64,…` from a row whose `key` sat right beside it, in a
29652
29823
  * dialog already rendering its key FRAME from the `event-media` plane.
29653
29824
  *
29654
- * `url` is `/addon/<addonId>/event-media/<encoded key>`. The plane resolves a
29655
- * media key directly, so this needed no new plane and no new access decision.
29825
+ * `url` is `/addon/<addonId>/event-media/m/<mediaId>` (D482). The plane
29826
+ * resolves a media row by its own id, so this needed no new plane and no new
29827
+ * access decision.
29656
29828
  */
29657
29829
  var MediaFileLiteSchema = object({
29658
- key: string(),
29830
+ /** The media row's own id — the same address `MediaFileRef.mediaId` carries
29831
+ * (D482). It was the row's composite key, which embedded the owner. */
29832
+ mediaId: number().int(),
29659
29833
  kind: string(),
29660
29834
  url: string(),
29661
29835
  sizeBytes: number(),
@@ -29714,7 +29888,7 @@ method(object({
29714
29888
  }), method(object({
29715
29889
  /** Inline {@link VehicleSchema.coverBase64} on every row. Default
29716
29890
  * `false` — the vehicle twin of `faceGallery.listIdentities`'s
29717
- * option; `coverMediaKey` + the `event-media` plane carry the picture.
29891
+ * option; `coverMediaId` + the `event-media` plane carry the picture.
29718
29892
  * INPUT field: stripped by the hub router until the train ships, which
29719
29893
  * resolves to `false` and is exactly the intended default. */
29720
29894
  includeCrops: boolean().optional() }).optional(), array(VehicleSchema).readonly()), method(object({ name: string().min(1) }), VehicleSchema, {
@@ -31283,7 +31457,14 @@ var SceneReferenceSchema = object({
31283
31457
  modelId: string(),
31284
31458
  condition: SceneConditionSchema,
31285
31459
  capturedAt: number(),
31286
- thumbnailMediaId: string().optional(),
31460
+ /**
31461
+ * The reference thumbnail's media ROW id (D482).
31462
+ *
31463
+ * The name already said `mediaId` while the value was the row's composite
31464
+ * key — a leftover that read as done and was not. It is the row's own id
31465
+ * now, addressed at `/addon/<addonId>/event-media/m/<id>`.
31466
+ */
31467
+ thumbnailMediaId: number().int().optional(),
31287
31468
  /** Whole-frame (downscaled) embedding captured alongside the ROI crop. The
31288
31469
  * anti-view-shift anchor: a bumped camera, a PTZ preset or a re-aim makes the
31289
31470
  * normalized rect frame a different piece of world, and the scene would
@@ -32374,7 +32555,29 @@ var LoggingSettingsPatchSchema = object({
32374
32555
  * disarmed the channels it did not mention would make the Levels page and
32375
32556
  * the Diagnostics page fight over the same value.
32376
32557
  */
32377
- channels: array(LogChannelWindowPatchSchema).readonly().optional()
32558
+ channels: array(LogChannelWindowPatchSchema).readonly().optional(),
32559
+ /**
32560
+ * How many days the analytics OPS LOG is kept — the audit trail of what
32561
+ * retention actually deleted.
32562
+ *
32563
+ * It lives HERE, on the logging document, and not on the analytics addon's
32564
+ * settings form, on the operator's instruction: every other log-ish window in
32565
+ * this system is configured through this one document, and a retention audit
32566
+ * configured somewhere else is a second place to look when the question is
32567
+ * "what happened to my data".
32568
+ *
32569
+ * That placement has a cost worth stating: this document ships in the
32570
+ * framework closure, so this knob needs a published `@camstack/server` while
32571
+ * the four windows beside it (D485) reach a node on `camstack deploy`.
32572
+ *
32573
+ * `retention-model.ts` argued this one must NOT follow a device window,
32574
+ * because the audit trail is the history of the SWEEP and not of the camera.
32575
+ * That argument stands and is untouched — what changes is that 30 days stops
32576
+ * being a constant nobody can reach. `0` keeps it forever. The floor is 1 day
32577
+ * rather than 0-as-delete: an audit log truncated to nothing is precisely the
32578
+ * state in which the next 9.5 GiB leak cannot be explained.
32579
+ */
32580
+ opsLogRetentionDays: number().int().min(0).max(3650).optional()
32378
32581
  });
32379
32582
  /**
32380
32583
  * Which LAYER of the hierarchy is addressed. Absent = the cluster layer.
@@ -32447,6 +32650,14 @@ var LoggingSettingsStateSchema = object({
32447
32650
  channels: array(LogChannelDescriptorSchema).readonly(),
32448
32651
  /** The channels ARMED right now, each with its deadline. */
32449
32652
  activeChannels: array(LogChannelWindowStateSchema).readonly(),
32653
+ /**
32654
+ * The ops-log window in days, as it is in force. `0` = kept forever.
32655
+ *
32656
+ * Reported rather than left to the caller's memory of what it wrote: this is
32657
+ * the value the analytics sweep will actually use, and an operator asking how
32658
+ * long their audit trail lives should not have to infer it from a default.
32659
+ */
32660
+ opsLogRetentionDays: number().int().min(0),
32450
32661
  persisted: boolean()
32451
32662
  });
32452
32663
  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(), {
@@ -33267,7 +33478,7 @@ var StationaryObjectSchema = object({
33267
33478
  /** Enrichment label carried from the source track (identity / plate). */
33268
33479
  label: string().optional(),
33269
33480
  /** Native-resolution key-frame media key for the parked object's best image. */
33270
- keyFrameMediaKey: string().optional()
33481
+ keyFrameMediaId: number().int().optional()
33271
33482
  });
33272
33483
  var CameraOccupancySnapshotSchema = object({
33273
33484
  /** Frame timestamp of the inference result that produced this snapshot. */
@@ -36005,6 +36216,12 @@ Object.freeze({
36005
36216
  addonId: null,
36006
36217
  access: "create"
36007
36218
  },
36219
+ "dataStoreProvider.upsert": {
36220
+ capName: "data-store-provider",
36221
+ capScope: "system",
36222
+ addonId: null,
36223
+ access: "create"
36224
+ },
36008
36225
  "dayNight.getOptions": {
36009
36226
  capName: "day-night",
36010
36227
  capScope: "device",
@@ -38441,6 +38658,12 @@ Object.freeze({
38441
38658
  addonId: null,
38442
38659
  access: "view"
38443
38660
  },
38661
+ "pipelineAnalytics.listRecentSummaries": {
38662
+ capName: "pipeline-analytics",
38663
+ capScope: "device",
38664
+ addonId: null,
38665
+ access: "view"
38666
+ },
38444
38667
  "pipelineAnalytics.listRecentTracks": {
38445
38668
  capName: "pipeline-analytics",
38446
38669
  capScope: "device",
@@ -39869,6 +40092,12 @@ Object.freeze({
39869
40092
  addonId: null,
39870
40093
  access: "create"
39871
40094
  },
40095
+ "settingsStore.upsert": {
40096
+ capName: "settings-store",
40097
+ capScope: "system",
40098
+ addonId: null,
40099
+ access: "create"
40100
+ },
39872
40101
  "smtpProvider.getStatus": {
39873
40102
  capName: "smtp-provider",
39874
40103
  capScope: "system",
@@ -42262,6 +42491,11 @@ Object.freeze({
42262
42491
  form: "single",
42263
42492
  optional: true
42264
42493
  }],
42494
+ "pipelineAnalytics.listRecentSummaries": [{
42495
+ name: "deviceIds",
42496
+ form: "array",
42497
+ optional: false
42498
+ }],
42265
42499
  "pipelineAnalytics.listRecentTracks": [{
42266
42500
  name: "deviceIds",
42267
42501
  form: "array",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/addon-provider-wyze",
3
- "version": "0.2.103",
3
+ "version": "0.2.105",
4
4
  "description": "Wyze camera device-provider addon for CamStack — wraps the @apocaliss92/wyze-bridge-js P2P/DTLS client, feeding the stream-broker via the pull-rfc4571 lazy-publish path (a structural twin of addon-provider-reolink)",
5
5
  "keywords": [
6
6
  "camstack",