@camstack/addon-provider-reolink 1.2.122 → 1.2.124

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