@camstack/addon-mqtt-broker 1.2.99 → 1.2.101

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.
@@ -44,7 +44,7 @@ let crypto$10 = __toESM(crypto$1, 1);
44
44
  crypto$1 = __toESM(crypto$1);
45
45
  let node_fs = require("node:fs");
46
46
  let node_path = require("node:path");
47
- //#region ../types/dist/event-category-DAXzJeTX.mjs
47
+ //#region ../types/dist/event-category-ZyX6jcse.mjs
48
48
  var EventCategory = /* @__PURE__ */ function(EventCategory) {
49
49
  EventCategory["SystemBoot"] = "system.boot";
50
50
  EventCategory["SystemAddonsReady"] = "system.addons-ready";
@@ -605,7 +605,7 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
605
605
  * a package zone — a newly-appeared stationary object of a package class
606
606
  * that cleared the class / zone / dwell / size gates. Payload:
607
607
  * `PipelineAnalyticsPackageDeliveredPayload` carrying `{ deviceId,
608
- * entryId, className, zoneIds, keyFrameMediaKey?, bbox, timestamp }`.
608
+ * entryId, className, zoneIds, keyFrameMediaId?, bbox, timestamp }`.
609
609
  * Telemetry (D8): the durable record is the `package-events` store row;
610
610
  * this bus topic drives notifier rules + live UI. See
611
611
  * docs/superpowers/specs/2026-07-17-package-zones-design.md §5.1.
@@ -5391,7 +5391,7 @@ var ZodIssueCode = {
5391
5391
  var ZodFirstPartyTypeKind;
5392
5392
  ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
5393
5393
  //#endregion
5394
- //#region ../types/dist/sleep-BnujYGPe.mjs
5394
+ //#region ../types/dist/sleep-DBKu2-U5.mjs
5395
5395
  /**
5396
5396
  * The audio chunk plane's byte format, and the ONE expansion from a coded
5397
5397
  * window to float samples (D455).
@@ -7342,13 +7342,30 @@ new Set([
7342
7342
  "scene",
7343
7343
  "motion",
7344
7344
  "object",
7345
- "audio"
7345
+ "audio",
7346
+ "mosaic"
7346
7347
  ]);
7347
- new Set([
7348
+ /**
7349
+ * The owner types that are event tables, in the order the event-media resolver
7350
+ * should consider them. Exported so a consumer asking "is this key an event?"
7351
+ * does not re-spell the list and drift from it.
7352
+ */
7353
+ var EVENT_OWNER_TYPES = [
7348
7354
  "motion",
7349
7355
  "object",
7350
7356
  "audio"
7351
- ]);
7357
+ ];
7358
+ /**
7359
+ * The same list as a Zod enum, for the cap inputs that must NAME the table
7360
+ * (D482: `getEventMedia` / `listEventMedia` take an owner, and an owner is
7361
+ * `(table, id)`).
7362
+ *
7363
+ * Built FROM {@link EVENT_OWNER_TYPES} rather than re-spelled: a fourth event
7364
+ * table would otherwise be accepted by the codec and refused at the door, with
7365
+ * nothing failing until a caller asked.
7366
+ */
7367
+ var EventOwnerTypeSchema = _enum(EVENT_OWNER_TYPES);
7368
+ new Set(EVENT_OWNER_TYPES);
7352
7369
  var EncodeProfileSchema = object({
7353
7370
  video: object({
7354
7371
  codec: _enum([
@@ -7387,7 +7404,23 @@ var EncodeProfileSchema = object({
7387
7404
  "zerolatency",
7388
7405
  "film",
7389
7406
  "animation"
7390
- ]).optional()
7407
+ ]).optional(),
7408
+ /**
7409
+ * ONE slice per access unit.
7410
+ *
7411
+ * `-tune zerolatency` turns on x264's sliced threads, and a frame then leaves
7412
+ * the encoder as five NAL slices that share one RTP timestamp and carry one
7413
+ * marker bit. A libwebrtc depacketiser sees five frame-starts and one
7414
+ * frame-end per frame: the first pictures render and the video then freezes
7415
+ * for good while the audio, on its own plane, plays on. Measured on this hub
7416
+ * 2026-09-13 against the Echo, and reduced to one slice by this flag alone.
7417
+ *
7418
+ * A NAMED field and not a raw flag, because {@link EgressEncodeSchema} omits
7419
+ * `outputArgs` on purpose: an opaque array is part of the sharing key, so two
7420
+ * consumers meaning the same thing spelled differently would stop sharing one
7421
+ * child. Absent means "whatever the encoder does" — today's behaviour.
7422
+ */
7423
+ singleSlicePerFrame: boolean().optional()
7391
7424
  }),
7392
7425
  audio: union([literal("passthrough"), object({
7393
7426
  codec: _enum([
@@ -7437,7 +7470,7 @@ var BASE_LIVE_EGRESS_PROFILE = {
7437
7470
  audio: "passthrough"
7438
7471
  };
7439
7472
  ({ ...BASE_LIVE_EGRESS_PROFILE }), { ...BASE_LIVE_EGRESS_PROFILE.video };
7440
- ({ ...BASE_LIVE_EGRESS_PROFILE });
7473
+ ({ ...BASE_LIVE_EGRESS_PROFILE }), { ...BASE_LIVE_EGRESS_PROFILE.video };
7441
7474
  /**
7442
7475
  * Deep wiring healthcheck — snapshot of active reachability probes across
7443
7476
  * every declared capability + widget of every installed plugin, on every
@@ -12494,6 +12527,16 @@ method(object({
12494
12527
  filter: QueryFilterSchema.optional(),
12495
12528
  columns: array(string()).readonly().optional()
12496
12529
  }), array(SettingsRecordSchema).readonly()), method(object({
12530
+ namespace: string().optional(),
12531
+ collection: string(),
12532
+ /** Declared columns identifying the slot; must be covered by a UNIQUE
12533
+ * index on the collection. Never empty. */
12534
+ conflict: array(string()).readonly(),
12535
+ record: BulkRecordSchema
12536
+ }), object({
12537
+ /** The id the row HAS: assigned by SQLite on an insert, or the existing
12538
+ * row's own id on an update. */
12539
+ id: union([string(), number()]) }), { kind: "mutation" }), method(object({
12497
12540
  namespace: string().optional(),
12498
12541
  collection: string(),
12499
12542
  record: object({
@@ -12628,6 +12671,14 @@ method(_void(), EngineInfoSchema, { auth: "admin" }), method(object({
12628
12671
  id: union([string(), number()]) }), {
12629
12672
  kind: "mutation",
12630
12673
  auth: "admin"
12674
+ }), method(object({
12675
+ namespace: string().optional(),
12676
+ collection: string(),
12677
+ conflict: array(string()).readonly(),
12678
+ record: BulkRecordSchema
12679
+ }), object({ id: union([string(), number()]) }), {
12680
+ kind: "mutation",
12681
+ auth: "admin"
12631
12682
  }), method(object({
12632
12683
  namespace: string().optional(),
12633
12684
  collection: string(),
@@ -18863,8 +18914,8 @@ var TrackPositionSchema = object({
18863
18914
  var TrackSnapshotSchema = object({
18864
18915
  timestamp: number(),
18865
18916
  position: TrackPositionSchema,
18866
- /** MediaStore key; resolve via `getTrackMedia({ trackId })`. */
18867
- mediaKey: string()
18917
+ /** The snapshot's media row id (D482); resolve via `listTrackMedia({ trackId })`. */
18918
+ mediaId: number().int()
18868
18919
  });
18869
18920
  /**
18870
18921
  * Normalized 0..1 trajectory envelope (min/max over every position bbox,
@@ -19468,14 +19519,14 @@ var ObjectEventSchema = object({
19468
19519
  * pixel-space `bbox` onto a displayed image. Omitted in slim projection. */
19469
19520
  frameWidth: number().optional(),
19470
19521
  frameHeight: number().optional(),
19471
- /** MediaStore key for the crop attached to this event (if any). */
19472
- mediaKey: string().optional(),
19473
- /** Design B: MediaStore key of the track's native-resolution key frame (the
19522
+ /** Media row id of the crop attached to this event (if any) — D482. */
19523
+ mediaId: number().int().optional(),
19524
+ /** Design B: media row id of the track's native-resolution key frame (the
19474
19525
  * best-detection full frame). Resolve via the event-media data-plane
19475
- * (`/addon/<addonId>/event-media/<keyFrameMediaKey>`) for a detail view that
19526
+ * (`/addon/<addonId>/event-media/m/<keyFrameMediaId>`) for a detail view that
19476
19527
  * draws `bbox` over the native frame. Absent on legacy rows / non-decoded
19477
- * sources — consumers fall back to `mediaKey` (the tight crop). */
19478
- keyFrameMediaKey: string().optional(),
19528
+ * sources — consumers fall back to `mediaId` (the tight crop). */
19529
+ keyFrameMediaId: number().int().optional(),
19479
19530
  /** Populated by B5 (recording playback URL for this event). */
19480
19531
  mediaUrl: string().optional(),
19481
19532
  /** The parent track's key-event importance [0,1], propagated to every object
@@ -19525,7 +19576,7 @@ var MediaFileKindEnum = _enum([
19525
19576
  * hub-main's heap on the way past — for an `<img>` that would have cached it.
19526
19577
  *
19527
19578
  * `url` points at the `event-media` data plane
19528
- * (`/addon/<addonId>/event-media/<storedKey>`), which serves the same blob
19579
+ * (`/addon/<addonId>/event-media/m/<mediaId>` — D482), which serves the same blob
19529
19580
  * with an ETag and `Cache-Control: immutable`, honours conditional GETs, can
19530
19581
  * render a `?variant=thumb`, and streams. The hub gate in front of it requires
19531
19582
  * a bearer or the session cookie (`access: 'authenticated'`), so the bytes are
@@ -19533,10 +19584,13 @@ var MediaFileKindEnum = _enum([
19533
19584
  * `data-plane-access.ts` for the rule and the one gap it does not close
19534
19585
  * (per-device scoping).
19535
19586
  *
19536
- * The URL is built from the row's **stored** key, which is not always its
19537
- * published `kind`: a track's face/plate crop is stored as `crop` under
19587
+ * The URL is built from the row's own id, which since D482 says nothing about
19588
+ * the row's owner or kind — and that is the point. The published `kind` is not
19589
+ * the stored one (a track's face/plate crop is stored as `crop` under
19538
19590
  * `('face'|'plate', '<prefix>-<trackId>')` and published as
19539
- * `faceCrop`/`plateCrop`. `MediaStore.getByKey` knows only the stored key.
19591
+ * `faceCrop`/`plateCrop`), and under the old composite key the URL had to be
19592
+ * taken from `row.key` verbatim or it 404'd exactly those two rows. An id
19593
+ * cannot be mis-reconstructed, because there is nothing in it to reconstruct.
19540
19594
  *
19541
19595
  * ## `base64` is TRANSITIONAL and is going away
19542
19596
  *
@@ -19549,7 +19603,19 @@ var MediaFileKindEnum = _enum([
19549
19603
  * `analytics-query-facade.ts`; nothing else reads it.
19550
19604
  */
19551
19605
  var MediaFileSchema = object({
19552
- key: string(),
19606
+ /**
19607
+ * The media row's OWN id — the rowid SQLite assigned it (D482).
19608
+ *
19609
+ * It used to be the row's composite key, `<ownerType>:<ownerId>:<fileKind>
19610
+ * [:<timestampMs>]`, which embedded a FOREIGN id. D474 made event ids
19611
+ * per-table rowid aliases, so `object:101314` and `motion:101314` are two
19612
+ * different rows that spell the same number, and a track whose
19613
+ * `bestEventId` was an object event was served a motion event's snapshot —
19614
+ * a night-time thumbnail on an afternoon track, with no error anywhere. A
19615
+ * surrogate id cannot name the wrong row's owner, because it names no owner
19616
+ * at all.
19617
+ */
19618
+ mediaId: number().int(),
19553
19619
  kind: MediaFileKindEnum,
19554
19620
  sizeBytes: number(),
19555
19621
  timestamp: number()
@@ -19657,7 +19723,7 @@ var RetrainTrackSchema = object({
19657
19723
  });
19658
19724
  /** A frame the picker may offer — an index row, no blob was read to produce it. */
19659
19725
  var RetrainFrameCandidateSchema = object({
19660
- mediaKey: string(),
19726
+ mediaId: number().int(),
19661
19727
  kind: MediaFileKindEnum,
19662
19728
  timestamp: number(),
19663
19729
  sizeBytes: number().int(),
@@ -19671,7 +19737,7 @@ var RetrainFrameSchema = object({
19671
19737
  deviceId: number(),
19672
19738
  trackId: string(),
19673
19739
  /** Provenance only. It may already point at nothing — that is expected. */
19674
- sourceMediaKey: string(),
19740
+ sourceMediaId: number().int(),
19675
19741
  sourceKind: MediaFileKindEnum,
19676
19742
  sizeBytes: number().int(),
19677
19743
  width: number().int(),
@@ -19687,7 +19753,7 @@ var RetrainCopyRefusalSchema = _enum([
19687
19753
  var RetrainFrameSelectionSchema = object({
19688
19754
  copied: array(RetrainFrameSchema).readonly(),
19689
19755
  refused: array(object({
19690
- sourceMediaKey: string(),
19756
+ sourceMediaId: number().int(),
19691
19757
  reason: RetrainCopyRefusalSchema
19692
19758
  })).readonly()
19693
19759
  });
@@ -19695,7 +19761,7 @@ var RetrainFrameListSchema = object({
19695
19761
  candidates: array(RetrainFrameCandidateSchema).readonly(),
19696
19762
  copies: array(RetrainFrameSchema).readonly(),
19697
19763
  /** What the page pre-selects — the native key frame when one survives. */
19698
- autoPickMediaKey: string().optional()
19764
+ autoPickMediaId: number().int().optional()
19699
19765
  });
19700
19766
  /** What the operator asked the assist to look for. */
19701
19767
  var RetrainAssistSubjectSchema = discriminatedUnion("kind", [object({
@@ -19790,9 +19856,11 @@ var RecentTracksQueryInput = object({
19790
19856
  });
19791
19857
  /**
19792
19858
  * A Summary (D359): the per-camera session envelope that references tracks.
19793
- * `groupShotKey` is the media key of its group shot (`ownerKind: 'summary'`,
19794
- * served by the event-media plane by key), null until the first frame with a
19795
- * member visible has been materialised.
19859
+ * `groupShotMediaId` is the media ROW id of its group shot (`ownerKind:
19860
+ * 'summary'`, served by the event-media plane at `/m/<id>`), null until the
19861
+ * first frame with a member visible has been materialised (D482 — it was the
19862
+ * row's composite key, which embedded the owner and could name another table's
19863
+ * row once event ids became per-table rowids).
19796
19864
  */
19797
19865
  var SummarySchema = object({
19798
19866
  id: string(),
@@ -19801,19 +19869,115 @@ var SummarySchema = object({
19801
19869
  lastActiveAt: number(),
19802
19870
  sealedAt: number().nullable(),
19803
19871
  memberCount: number().int().nonnegative(),
19804
- groupShotKey: string().nullable()
19872
+ groupShotMediaId: number().int().nullable()
19805
19873
  });
19806
19874
  var SummariesQueryInput = object({
19807
19875
  deviceIds: array(number()).min(1),
19808
19876
  since: number().optional(),
19809
19877
  until: number().optional(),
19810
- limit: number().int().min(1).max(200).default(50)
19878
+ limit: number().int().min(1).max(200).default(50),
19879
+ /** The same member-wise filter {@link listRecentSummaries} takes — one
19880
+ * meaning of "dog" on every summary surface. */
19881
+ classes: array(string().min(1).max(60)).max(40).optional()
19811
19882
  });
19812
- var SummariesPageSchema = object({ summaries: array(SummarySchema).readonly() });
19813
19883
  var SummaryDetailSchema = object({
19814
19884
  summary: SummarySchema,
19815
- /** Member track ids, in absorption order. */
19816
- trackIds: array(string()).readonly()
19885
+ /** Members in absorption order, oldest join first. */
19886
+ members: array(object({
19887
+ trackId: string(),
19888
+ /**
19889
+ * The track's class at the time it JOINED, or `null` when it was unresolved
19890
+ * and the track no longer exists to fill it.
19891
+ *
19892
+ * The join, not the latest opinion: class voting can re-decide a track's
19893
+ * class afterwards, and a group's composition is the history of who came
19894
+ * together. A consumer counts these to badge a thumbnail — "two people and a
19895
+ * dog" — rather than being handed a second, denormalised tally that would
19896
+ * drift from the members it claims to describe.
19897
+ */
19898
+ className: string().nullable(),
19899
+ /** `primary` is the one member that carries the group's identity. */
19900
+ role: _enum([
19901
+ "primary",
19902
+ "sibling",
19903
+ "child"
19904
+ ]).nullable(),
19905
+ joinedAt: number(),
19906
+ /** Tier 1 — the sub-class (`dog`, `van`), resolved from the member's track
19907
+ * at read time. Absent when nothing resolved, never an empty string. */
19908
+ label: string().optional(),
19909
+ /** Tier 2 — the instance: a person's name, a plate. Absent when the pipeline
19910
+ * recognised nobody, and absent for a member whose track has been pruned —
19911
+ * a thumbnail that names the wrong person is worse than one naming nobody. */
19912
+ subLabel: string().optional()
19913
+ })).readonly()
19914
+ });
19915
+ /**
19916
+ * What a LIST of groups carries: the envelope plus what it is MADE OF.
19917
+ *
19918
+ * Coarse on purpose — the operator's rule is "only the rough data on the list,
19919
+ * we extend when we notice we need more". Enough to draw the card ("two people
19920
+ * and a dog") and no more. The MEMBERS, their names and the per-member links
19921
+ * are on {@link getSummary}: shipping every member of every group so a client
19922
+ * can count them turns a page of two hundred groups into a thousand records to
19923
+ * draw two hundred badges.
19924
+ */
19925
+ var SummaryListItemSchema = object({
19926
+ summary: SummarySchema,
19927
+ /** Class counts, most numerous first; `className: null` is a member whose
19928
+ * class never resolved, counted so the counts add up to `memberCount`. */
19929
+ classes: array(object({
19930
+ className: string().nullable(),
19931
+ count: number().int().positive()
19932
+ })).readonly()
19933
+ });
19934
+ var SummariesPageSchema = object({ summaries: array(SummaryListItemSchema).readonly() });
19935
+ /**
19936
+ * The paged feed, deliberately the SAME shape as {@link RecentTracksQueryInput}.
19937
+ *
19938
+ * The reel on the cameras page and the Events gallery both ride a cursor, so a
19939
+ * summaries feed that could only answer "the last N for these cameras"
19940
+ * (`listSummaries`) would make groups available in the timeline and nowhere
19941
+ * else. Two feeds with different ordering contracts would be two ideas of what
19942
+ * "newest" means, on one screen.
19943
+ */
19944
+ var RecentSummariesQueryInput = object({
19945
+ /** Devices to merge. An empty array yields an empty page. */
19946
+ deviceIds: array(number()),
19947
+ /** Window lower bound on `lastActiveAt` (inclusive). */
19948
+ since: number().optional(),
19949
+ /** Window upper bound on `lastActiveAt` (inclusive). */
19950
+ until: number().optional(),
19951
+ limit: number().int().min(1).max(500).default(100),
19952
+ /** Opaque continuation cursor from a previous page's `nextCursor`. */
19953
+ cursor: string().optional(),
19954
+ /**
19955
+ * Restrict to these classes — THE SAME FIELD `listRecentTracks` takes, and
19956
+ * deliberately the same name: the events filter tree emits one list of ticked
19957
+ * taxonomy nodes, and a summaries feed that called it something else would
19958
+ * make the operator's one filter component produce two shapes.
19959
+ *
19960
+ * A question about the MEMBERS: a group matches when ANY of them does. "Show
19961
+ * me the arrivals with a dog" has to return the group of four people who had
19962
+ * one with them; a filter on the group's own fields could only ever answer
19963
+ * about its primary.
19964
+ *
19965
+ * Matched against all THREE tiers of a member — the class (`animal`), the
19966
+ * sub-class (`dog`) and the instance (a name, a plate) — because which tier a
19967
+ * ticked node lives on is the taxonomy's business, not the caller's. `dog` is
19968
+ * an event kind in the tree and a tier-1 label on an `animal` track; a filter
19969
+ * that read only the class would answer "animal" and never "dog".
19970
+ *
19971
+ * ABSENT or EMPTY means no filter — absent is not a selection of none.
19972
+ */
19973
+ classes: array(string().min(1).max(60)).max(40).optional()
19974
+ });
19975
+ var RecentSummariesPageSchema = object({
19976
+ /** Ordered by (`lastActiveAt` DESC, id DESC). Same light item as
19977
+ * {@link listSummaries} — one list shape, so a card renders the same
19978
+ * whichever feed drew it. */
19979
+ summaries: array(SummaryListItemSchema).readonly(),
19980
+ nextCursor: string().nullable()
19817
19981
  });
19818
19982
  var RecentTracksPageSchema = object({
19819
19983
  /** Merged page, ordered by (`lastSeen` DESC, `trackId` DESC). */
@@ -20227,7 +20391,7 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
20227
20391
  classes: array(string()).optional(),
20228
20392
  /** See {@link ExcludeSourcesDoc}. */
20229
20393
  excludeSources: array(TrackSourceSchema).optional()
20230
- }), array(TrackSchema).readonly()), method(RecentTracksQueryInput, RecentTracksPageSchema), method(SummariesQueryInput, SummariesPageSchema), method(object({ id: string() }), SummaryDetailSchema.nullable()), method(object({ deviceId: number() }), _void(), {
20394
+ }), array(TrackSchema).readonly()), method(RecentTracksQueryInput, RecentTracksPageSchema), method(SummariesQueryInput, SummariesPageSchema), method(RecentSummariesQueryInput, RecentSummariesPageSchema), method(object({ id: string() }), SummaryDetailSchema.nullable()), method(object({ deviceId: number() }), _void(), {
20231
20395
  kind: "mutation",
20232
20396
  auth: "admin"
20233
20397
  }), 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({
@@ -20355,7 +20519,7 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
20355
20519
  }), method(object({
20356
20520
  deviceId: number(),
20357
20521
  trackId: string(),
20358
- mediaKeys: array(string()).min(1)
20522
+ mediaIds: array(number().int()).min(1)
20359
20523
  }), RetrainFrameSelectionSchema, {
20360
20524
  kind: "mutation",
20361
20525
  auth: "admin"
@@ -20423,7 +20587,10 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
20423
20587
  kind: "query",
20424
20588
  auth: "admin"
20425
20589
  }), method(object({
20426
- eventId: string(),
20590
+ /** Which of the three event tables owns the row. */
20591
+ ownerType: EventOwnerTypeSchema,
20592
+ /** The event's rowid in that table (D474: an event id is a number). */
20593
+ eventId: number().int(),
20427
20594
  kind: MediaFileKindEnum.optional(),
20428
20595
  deviceId: number()
20429
20596
  }), array(MediaFileSchema).readonly()), method(object({
@@ -20434,7 +20601,8 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
20434
20601
  trackId: string(),
20435
20602
  deviceId: number()
20436
20603
  }), array(MediaFileInfoSchema).readonly()), method(object({
20437
- eventId: string(),
20604
+ ownerType: EventOwnerTypeSchema,
20605
+ eventId: number().int(),
20438
20606
  deviceId: number()
20439
20607
  }), array(MediaFileInfoSchema).readonly()), method(SearchObjectEventsInput, array(ScoredObjectEventSchema).readonly()), method(object({}), WipeObjectEmbeddingsResultSchema, {
20440
20608
  kind: "mutation",
@@ -24897,8 +25065,8 @@ var IdentitySchema = object({
24897
25065
  id: string(),
24898
25066
  name: string(),
24899
25067
  sampleCount: number().int().nonnegative(),
24900
- coverMediaKey: string().optional(),
24901
- /** Inline base64 of the cover sample's crop, resolved from `coverMediaKey`.
25068
+ coverMediaId: number().int().optional(),
25069
+ /** Inline base64 of the cover sample's crop, resolved from `coverMediaId`.
24902
25070
  * Lets the UI render the person's face avatar instead of a placeholder icon. */
24903
25071
  coverBase64: string().optional()
24904
25072
  });
@@ -24924,8 +25092,8 @@ var IdentitySampleAuditRowSchema = object({
24924
25092
  enrolledAt: number().int(),
24925
25093
  deviceId: number().int().optional(),
24926
25094
  source: _enum(["detected", "photo"]),
24927
- /** The enrolled crop's media key, so the panel can show the evidence. */
24928
- mediaKey: string().optional(),
25095
+ /** The enrolled crop's media row id, so the panel can show the evidence. */
25096
+ mediaId: number().int().optional(),
24929
25097
  /**
24930
25098
  * False = the sample is stamped with a DIFFERENT face model, and a cosine
24931
25099
  * across feature spaces is a well-formed float with no meaning. Every number
@@ -24994,15 +25162,15 @@ var FaceInfoSchema = object({
24994
25162
  */
24995
25163
  cropUrl: string().optional(),
24996
25164
  /** Design B: the face bbox (pixel space) on the key frame — lets a detail
24997
- * view draw the box over the native `keyFrameMediaKey` frame. Absent on
25165
+ * view draw the box over the native `keyFrameMediaId` frame. Absent on
24998
25166
  * legacy rows written before design B. */
24999
25167
  faceBbox: BoundingBoxSchema.optional(),
25000
25168
  /** Design B: MediaStore key of the track's native-resolution key frame.
25001
25169
  * Fetch the native JPEG via the event-media data-plane
25002
- * (`/addon/<addonId>/event-media/<keyFrameMediaKey>`). Absent when the
25170
+ * (`/addon/<addonId>/event-media/m/<keyFrameMediaId>`). Absent when the
25003
25171
  * track produced no key frame (e.g. native/onboard source) — the UI falls
25004
25172
  * back to the inline `base64` face crop. */
25005
- keyFrameMediaKey: string().optional(),
25173
+ keyFrameMediaId: number().int().optional(),
25006
25174
  /** Winning identity-match cosine (0..1) for this face's track, when an
25007
25175
  * identity was auto-confirmed. Lets the UI surface WHY a face was assigned
25008
25176
  * (confidence badge / low-confidence audit). Absent on legacy rows and on
@@ -25071,11 +25239,14 @@ var FaceClusterSchema = object({
25071
25239
  * `data:image/jpeg;base64,…` from a row whose `key` sat right beside it, in a
25072
25240
  * dialog already rendering its key FRAME from the `event-media` plane.
25073
25241
  *
25074
- * `url` is `/addon/<addonId>/event-media/<encoded key>`. The plane resolves a
25075
- * media key directly, so this needed no new plane and no new access decision.
25242
+ * `url` is `/addon/<addonId>/event-media/m/<mediaId>` (D482). The plane
25243
+ * resolves a media row by its own id, so this needed no new plane and no new
25244
+ * access decision.
25076
25245
  */
25077
25246
  var MediaFileLiteSchema$1 = object({
25078
- key: string(),
25247
+ /** The media row's own id — the same address `MediaFileRef.mediaId` carries
25248
+ * (D482). It was the row's composite key, which embedded the owner. */
25249
+ mediaId: number().int(),
25079
25250
  kind: string(),
25080
25251
  url: string(),
25081
25252
  sizeBytes: number(),
@@ -25092,7 +25263,7 @@ method(object({
25092
25263
  * covers inline, ~10 KB of base64 per row, on a query this UI mounts
25093
25264
  * four times and the viewer holds at `staleTime: 30_000`.
25094
25265
  *
25095
- * Nothing loses its avatar: `coverMediaKey` is already on every row and
25266
+ * Nothing loses its avatar: `coverMediaId` is already on every row and
25096
25267
  * the `event-media` plane serves that key `immutable` with an ETag.
25097
25268
  *
25098
25269
  * **This is an INPUT field, so it does not reach the addon until the
@@ -27560,8 +27731,8 @@ var VehicleSchema = object({
27560
27731
  id: string(),
27561
27732
  name: string(),
27562
27733
  sampleCount: number().int().nonnegative(),
27563
- coverMediaKey: string().optional(),
27564
- /** Inline base64 of the cover sample's plate crop, resolved from `coverMediaKey`. */
27734
+ coverMediaId: number().int().optional(),
27735
+ /** Inline base64 of the cover sample's plate crop, resolved from `coverMediaId`. */
27565
27736
  coverBase64: string().optional()
27566
27737
  });
27567
27738
  var VehicleSampleInfoSchema = object({
@@ -27594,7 +27765,7 @@ var PlateInfoSchema = object({
27594
27765
  /** keyFrame parity: the plate bbox (pixel space) on the native key frame. */
27595
27766
  plateBbox: BoundingBoxSchema.optional(),
27596
27767
  /** keyFrame parity: MediaStore key of the track's native-resolution key frame. */
27597
- keyFrameMediaKey: string().optional(),
27768
+ keyFrameMediaId: number().int().optional(),
27598
27769
  base64: string().optional(),
27599
27770
  /**
27600
27771
  * Same crop as a data-plane URL, always present when the plate has a stored
@@ -27615,11 +27786,14 @@ var PlateInfoSchema = object({
27615
27786
  * `data:image/jpeg;base64,…` from a row whose `key` sat right beside it, in a
27616
27787
  * dialog already rendering its key FRAME from the `event-media` plane.
27617
27788
  *
27618
- * `url` is `/addon/<addonId>/event-media/<encoded key>`. The plane resolves a
27619
- * media key directly, so this needed no new plane and no new access decision.
27789
+ * `url` is `/addon/<addonId>/event-media/m/<mediaId>` (D482). The plane
27790
+ * resolves a media row by its own id, so this needed no new plane and no new
27791
+ * access decision.
27620
27792
  */
27621
27793
  var MediaFileLiteSchema = object({
27622
- key: string(),
27794
+ /** The media row's own id — the same address `MediaFileRef.mediaId` carries
27795
+ * (D482). It was the row's composite key, which embedded the owner. */
27796
+ mediaId: number().int(),
27623
27797
  kind: string(),
27624
27798
  url: string(),
27625
27799
  sizeBytes: number(),
@@ -27678,7 +27852,7 @@ method(object({
27678
27852
  }), method(object({
27679
27853
  /** Inline {@link VehicleSchema.coverBase64} on every row. Default
27680
27854
  * `false` — the vehicle twin of `faceGallery.listIdentities`'s
27681
- * option; `coverMediaKey` + the `event-media` plane carry the picture.
27855
+ * option; `coverMediaId` + the `event-media` plane carry the picture.
27682
27856
  * INPUT field: stripped by the hub router until the train ships, which
27683
27857
  * resolves to `false` and is exactly the intended default. */
27684
27858
  includeCrops: boolean().optional() }).optional(), array(VehicleSchema).readonly()), method(object({ name: string().min(1) }), VehicleSchema, {
@@ -29002,7 +29176,14 @@ var SceneReferenceSchema = object({
29002
29176
  modelId: string(),
29003
29177
  condition: SceneConditionSchema,
29004
29178
  capturedAt: number(),
29005
- thumbnailMediaId: string().optional(),
29179
+ /**
29180
+ * The reference thumbnail's media ROW id (D482).
29181
+ *
29182
+ * The name already said `mediaId` while the value was the row's composite
29183
+ * key — a leftover that read as done and was not. It is the row's own id
29184
+ * now, addressed at `/addon/<addonId>/event-media/m/<id>`.
29185
+ */
29186
+ thumbnailMediaId: number().int().optional(),
29006
29187
  /** Whole-frame (downscaled) embedding captured alongside the ROI crop. The
29007
29188
  * anti-view-shift anchor: a bumped camera, a PTZ preset or a re-aim makes the
29008
29189
  * normalized rect frame a different piece of world, and the scene would
@@ -29816,7 +29997,29 @@ var LoggingSettingsPatchSchema = object({
29816
29997
  * disarmed the channels it did not mention would make the Levels page and
29817
29998
  * the Diagnostics page fight over the same value.
29818
29999
  */
29819
- channels: array(LogChannelWindowPatchSchema).readonly().optional()
30000
+ channels: array(LogChannelWindowPatchSchema).readonly().optional(),
30001
+ /**
30002
+ * How many days the analytics OPS LOG is kept — the audit trail of what
30003
+ * retention actually deleted.
30004
+ *
30005
+ * It lives HERE, on the logging document, and not on the analytics addon's
30006
+ * settings form, on the operator's instruction: every other log-ish window in
30007
+ * this system is configured through this one document, and a retention audit
30008
+ * configured somewhere else is a second place to look when the question is
30009
+ * "what happened to my data".
30010
+ *
30011
+ * That placement has a cost worth stating: this document ships in the
30012
+ * framework closure, so this knob needs a published `@camstack/server` while
30013
+ * the four windows beside it (D485) reach a node on `camstack deploy`.
30014
+ *
30015
+ * `retention-model.ts` argued this one must NOT follow a device window,
30016
+ * because the audit trail is the history of the SWEEP and not of the camera.
30017
+ * That argument stands and is untouched — what changes is that 30 days stops
30018
+ * being a constant nobody can reach. `0` keeps it forever. The floor is 1 day
30019
+ * rather than 0-as-delete: an audit log truncated to nothing is precisely the
30020
+ * state in which the next 9.5 GiB leak cannot be explained.
30021
+ */
30022
+ opsLogRetentionDays: number().int().min(0).max(3650).optional()
29820
30023
  });
29821
30024
  /**
29822
30025
  * Which LAYER of the hierarchy is addressed. Absent = the cluster layer.
@@ -29889,6 +30092,14 @@ var LoggingSettingsStateSchema = object({
29889
30092
  channels: array(LogChannelDescriptorSchema).readonly(),
29890
30093
  /** The channels ARMED right now, each with its deadline. */
29891
30094
  activeChannels: array(LogChannelWindowStateSchema).readonly(),
30095
+ /**
30096
+ * The ops-log window in days, as it is in force. `0` = kept forever.
30097
+ *
30098
+ * Reported rather than left to the caller's memory of what it wrote: this is
30099
+ * the value the analytics sweep will actually use, and an operator asking how
30100
+ * long their audit trail lives should not have to infer it from a default.
30101
+ */
30102
+ opsLogRetentionDays: number().int().min(0),
29892
30103
  persisted: boolean()
29893
30104
  });
29894
30105
  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(), {
@@ -30450,7 +30661,7 @@ var StationaryObjectSchema = object({
30450
30661
  /** Enrichment label carried from the source track (identity / plate). */
30451
30662
  label: string().optional(),
30452
30663
  /** Native-resolution key-frame media key for the parked object's best image. */
30453
- keyFrameMediaKey: string().optional()
30664
+ keyFrameMediaId: number().int().optional()
30454
30665
  });
30455
30666
  var CameraOccupancySnapshotSchema = object({
30456
30667
  /** Frame timestamp of the inference result that produced this snapshot. */
@@ -31606,6 +31817,12 @@ Object.freeze({
31606
31817
  addonId: null,
31607
31818
  access: "create"
31608
31819
  },
31820
+ "dataStoreProvider.upsert": {
31821
+ capName: "data-store-provider",
31822
+ capScope: "system",
31823
+ addonId: null,
31824
+ access: "create"
31825
+ },
31609
31826
  "dayNight.getOptions": {
31610
31827
  capName: "day-night",
31611
31828
  capScope: "device",
@@ -34042,6 +34259,12 @@ Object.freeze({
34042
34259
  addonId: null,
34043
34260
  access: "view"
34044
34261
  },
34262
+ "pipelineAnalytics.listRecentSummaries": {
34263
+ capName: "pipeline-analytics",
34264
+ capScope: "device",
34265
+ addonId: null,
34266
+ access: "view"
34267
+ },
34045
34268
  "pipelineAnalytics.listRecentTracks": {
34046
34269
  capName: "pipeline-analytics",
34047
34270
  capScope: "device",
@@ -35470,6 +35693,12 @@ Object.freeze({
35470
35693
  addonId: null,
35471
35694
  access: "create"
35472
35695
  },
35696
+ "settingsStore.upsert": {
35697
+ capName: "settings-store",
35698
+ capScope: "system",
35699
+ addonId: null,
35700
+ access: "create"
35701
+ },
35473
35702
  "smtpProvider.getStatus": {
35474
35703
  capName: "smtp-provider",
35475
35704
  capScope: "system",
@@ -37863,6 +38092,11 @@ Object.freeze({
37863
38092
  form: "single",
37864
38093
  optional: true
37865
38094
  }],
38095
+ "pipelineAnalytics.listRecentSummaries": [{
38096
+ name: "deviceIds",
38097
+ form: "array",
38098
+ optional: false
38099
+ }],
37866
38100
  "pipelineAnalytics.listRecentTracks": [{
37867
38101
  name: "deviceIds",
37868
38102
  form: "array",
@@ -39,7 +39,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
39
39
  var __toCommonJS = (mod) => __hasOwnProp.call(mod, "module.exports") ? mod["module.exports"] : __copyProps(__defProp({}, "__esModule", { value: true }), mod);
40
40
  var __require = /* @__PURE__ */ createRequire(import.meta.url);
41
41
  //#endregion
42
- //#region ../types/dist/event-category-DAXzJeTX.mjs
42
+ //#region ../types/dist/event-category-ZyX6jcse.mjs
43
43
  var EventCategory = /* @__PURE__ */ function(EventCategory) {
44
44
  EventCategory["SystemBoot"] = "system.boot";
45
45
  EventCategory["SystemAddonsReady"] = "system.addons-ready";
@@ -600,7 +600,7 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
600
600
  * a package zone — a newly-appeared stationary object of a package class
601
601
  * that cleared the class / zone / dwell / size gates. Payload:
602
602
  * `PipelineAnalyticsPackageDeliveredPayload` carrying `{ deviceId,
603
- * entryId, className, zoneIds, keyFrameMediaKey?, bbox, timestamp }`.
603
+ * entryId, className, zoneIds, keyFrameMediaId?, bbox, timestamp }`.
604
604
  * Telemetry (D8): the durable record is the `package-events` store row;
605
605
  * this bus topic drives notifier rules + live UI. See
606
606
  * docs/superpowers/specs/2026-07-17-package-zones-design.md §5.1.
@@ -5386,7 +5386,7 @@ var ZodIssueCode = {
5386
5386
  var ZodFirstPartyTypeKind;
5387
5387
  ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
5388
5388
  //#endregion
5389
- //#region ../types/dist/sleep-BnujYGPe.mjs
5389
+ //#region ../types/dist/sleep-DBKu2-U5.mjs
5390
5390
  /**
5391
5391
  * The audio chunk plane's byte format, and the ONE expansion from a coded
5392
5392
  * window to float samples (D455).
@@ -7337,13 +7337,30 @@ new Set([
7337
7337
  "scene",
7338
7338
  "motion",
7339
7339
  "object",
7340
- "audio"
7340
+ "audio",
7341
+ "mosaic"
7341
7342
  ]);
7342
- new Set([
7343
+ /**
7344
+ * The owner types that are event tables, in the order the event-media resolver
7345
+ * should consider them. Exported so a consumer asking "is this key an event?"
7346
+ * does not re-spell the list and drift from it.
7347
+ */
7348
+ var EVENT_OWNER_TYPES = [
7343
7349
  "motion",
7344
7350
  "object",
7345
7351
  "audio"
7346
- ]);
7352
+ ];
7353
+ /**
7354
+ * The same list as a Zod enum, for the cap inputs that must NAME the table
7355
+ * (D482: `getEventMedia` / `listEventMedia` take an owner, and an owner is
7356
+ * `(table, id)`).
7357
+ *
7358
+ * Built FROM {@link EVENT_OWNER_TYPES} rather than re-spelled: a fourth event
7359
+ * table would otherwise be accepted by the codec and refused at the door, with
7360
+ * nothing failing until a caller asked.
7361
+ */
7362
+ var EventOwnerTypeSchema = _enum(EVENT_OWNER_TYPES);
7363
+ new Set(EVENT_OWNER_TYPES);
7347
7364
  var EncodeProfileSchema = object({
7348
7365
  video: object({
7349
7366
  codec: _enum([
@@ -7382,7 +7399,23 @@ var EncodeProfileSchema = object({
7382
7399
  "zerolatency",
7383
7400
  "film",
7384
7401
  "animation"
7385
- ]).optional()
7402
+ ]).optional(),
7403
+ /**
7404
+ * ONE slice per access unit.
7405
+ *
7406
+ * `-tune zerolatency` turns on x264's sliced threads, and a frame then leaves
7407
+ * the encoder as five NAL slices that share one RTP timestamp and carry one
7408
+ * marker bit. A libwebrtc depacketiser sees five frame-starts and one
7409
+ * frame-end per frame: the first pictures render and the video then freezes
7410
+ * for good while the audio, on its own plane, plays on. Measured on this hub
7411
+ * 2026-09-13 against the Echo, and reduced to one slice by this flag alone.
7412
+ *
7413
+ * A NAMED field and not a raw flag, because {@link EgressEncodeSchema} omits
7414
+ * `outputArgs` on purpose: an opaque array is part of the sharing key, so two
7415
+ * consumers meaning the same thing spelled differently would stop sharing one
7416
+ * child. Absent means "whatever the encoder does" — today's behaviour.
7417
+ */
7418
+ singleSlicePerFrame: boolean().optional()
7386
7419
  }),
7387
7420
  audio: union([literal("passthrough"), object({
7388
7421
  codec: _enum([
@@ -7432,7 +7465,7 @@ var BASE_LIVE_EGRESS_PROFILE = {
7432
7465
  audio: "passthrough"
7433
7466
  };
7434
7467
  ({ ...BASE_LIVE_EGRESS_PROFILE }), { ...BASE_LIVE_EGRESS_PROFILE.video };
7435
- ({ ...BASE_LIVE_EGRESS_PROFILE });
7468
+ ({ ...BASE_LIVE_EGRESS_PROFILE }), { ...BASE_LIVE_EGRESS_PROFILE.video };
7436
7469
  /**
7437
7470
  * Deep wiring healthcheck — snapshot of active reachability probes across
7438
7471
  * every declared capability + widget of every installed plugin, on every
@@ -12489,6 +12522,16 @@ method(object({
12489
12522
  filter: QueryFilterSchema.optional(),
12490
12523
  columns: array(string()).readonly().optional()
12491
12524
  }), array(SettingsRecordSchema).readonly()), method(object({
12525
+ namespace: string().optional(),
12526
+ collection: string(),
12527
+ /** Declared columns identifying the slot; must be covered by a UNIQUE
12528
+ * index on the collection. Never empty. */
12529
+ conflict: array(string()).readonly(),
12530
+ record: BulkRecordSchema
12531
+ }), object({
12532
+ /** The id the row HAS: assigned by SQLite on an insert, or the existing
12533
+ * row's own id on an update. */
12534
+ id: union([string(), number()]) }), { kind: "mutation" }), method(object({
12492
12535
  namespace: string().optional(),
12493
12536
  collection: string(),
12494
12537
  record: object({
@@ -12623,6 +12666,14 @@ method(_void(), EngineInfoSchema, { auth: "admin" }), method(object({
12623
12666
  id: union([string(), number()]) }), {
12624
12667
  kind: "mutation",
12625
12668
  auth: "admin"
12669
+ }), method(object({
12670
+ namespace: string().optional(),
12671
+ collection: string(),
12672
+ conflict: array(string()).readonly(),
12673
+ record: BulkRecordSchema
12674
+ }), object({ id: union([string(), number()]) }), {
12675
+ kind: "mutation",
12676
+ auth: "admin"
12626
12677
  }), method(object({
12627
12678
  namespace: string().optional(),
12628
12679
  collection: string(),
@@ -18858,8 +18909,8 @@ var TrackPositionSchema = object({
18858
18909
  var TrackSnapshotSchema = object({
18859
18910
  timestamp: number(),
18860
18911
  position: TrackPositionSchema,
18861
- /** MediaStore key; resolve via `getTrackMedia({ trackId })`. */
18862
- mediaKey: string()
18912
+ /** The snapshot's media row id (D482); resolve via `listTrackMedia({ trackId })`. */
18913
+ mediaId: number().int()
18863
18914
  });
18864
18915
  /**
18865
18916
  * Normalized 0..1 trajectory envelope (min/max over every position bbox,
@@ -19463,14 +19514,14 @@ var ObjectEventSchema = object({
19463
19514
  * pixel-space `bbox` onto a displayed image. Omitted in slim projection. */
19464
19515
  frameWidth: number().optional(),
19465
19516
  frameHeight: number().optional(),
19466
- /** MediaStore key for the crop attached to this event (if any). */
19467
- mediaKey: string().optional(),
19468
- /** Design B: MediaStore key of the track's native-resolution key frame (the
19517
+ /** Media row id of the crop attached to this event (if any) — D482. */
19518
+ mediaId: number().int().optional(),
19519
+ /** Design B: media row id of the track's native-resolution key frame (the
19469
19520
  * best-detection full frame). Resolve via the event-media data-plane
19470
- * (`/addon/<addonId>/event-media/<keyFrameMediaKey>`) for a detail view that
19521
+ * (`/addon/<addonId>/event-media/m/<keyFrameMediaId>`) for a detail view that
19471
19522
  * draws `bbox` over the native frame. Absent on legacy rows / non-decoded
19472
- * sources — consumers fall back to `mediaKey` (the tight crop). */
19473
- keyFrameMediaKey: string().optional(),
19523
+ * sources — consumers fall back to `mediaId` (the tight crop). */
19524
+ keyFrameMediaId: number().int().optional(),
19474
19525
  /** Populated by B5 (recording playback URL for this event). */
19475
19526
  mediaUrl: string().optional(),
19476
19527
  /** The parent track's key-event importance [0,1], propagated to every object
@@ -19520,7 +19571,7 @@ var MediaFileKindEnum = _enum([
19520
19571
  * hub-main's heap on the way past — for an `<img>` that would have cached it.
19521
19572
  *
19522
19573
  * `url` points at the `event-media` data plane
19523
- * (`/addon/<addonId>/event-media/<storedKey>`), which serves the same blob
19574
+ * (`/addon/<addonId>/event-media/m/<mediaId>` — D482), which serves the same blob
19524
19575
  * with an ETag and `Cache-Control: immutable`, honours conditional GETs, can
19525
19576
  * render a `?variant=thumb`, and streams. The hub gate in front of it requires
19526
19577
  * a bearer or the session cookie (`access: 'authenticated'`), so the bytes are
@@ -19528,10 +19579,13 @@ var MediaFileKindEnum = _enum([
19528
19579
  * `data-plane-access.ts` for the rule and the one gap it does not close
19529
19580
  * (per-device scoping).
19530
19581
  *
19531
- * The URL is built from the row's **stored** key, which is not always its
19532
- * published `kind`: a track's face/plate crop is stored as `crop` under
19582
+ * The URL is built from the row's own id, which since D482 says nothing about
19583
+ * the row's owner or kind — and that is the point. The published `kind` is not
19584
+ * the stored one (a track's face/plate crop is stored as `crop` under
19533
19585
  * `('face'|'plate', '<prefix>-<trackId>')` and published as
19534
- * `faceCrop`/`plateCrop`. `MediaStore.getByKey` knows only the stored key.
19586
+ * `faceCrop`/`plateCrop`), and under the old composite key the URL had to be
19587
+ * taken from `row.key` verbatim or it 404'd exactly those two rows. An id
19588
+ * cannot be mis-reconstructed, because there is nothing in it to reconstruct.
19535
19589
  *
19536
19590
  * ## `base64` is TRANSITIONAL and is going away
19537
19591
  *
@@ -19544,7 +19598,19 @@ var MediaFileKindEnum = _enum([
19544
19598
  * `analytics-query-facade.ts`; nothing else reads it.
19545
19599
  */
19546
19600
  var MediaFileSchema = object({
19547
- key: string(),
19601
+ /**
19602
+ * The media row's OWN id — the rowid SQLite assigned it (D482).
19603
+ *
19604
+ * It used to be the row's composite key, `<ownerType>:<ownerId>:<fileKind>
19605
+ * [:<timestampMs>]`, which embedded a FOREIGN id. D474 made event ids
19606
+ * per-table rowid aliases, so `object:101314` and `motion:101314` are two
19607
+ * different rows that spell the same number, and a track whose
19608
+ * `bestEventId` was an object event was served a motion event's snapshot —
19609
+ * a night-time thumbnail on an afternoon track, with no error anywhere. A
19610
+ * surrogate id cannot name the wrong row's owner, because it names no owner
19611
+ * at all.
19612
+ */
19613
+ mediaId: number().int(),
19548
19614
  kind: MediaFileKindEnum,
19549
19615
  sizeBytes: number(),
19550
19616
  timestamp: number()
@@ -19652,7 +19718,7 @@ var RetrainTrackSchema = object({
19652
19718
  });
19653
19719
  /** A frame the picker may offer — an index row, no blob was read to produce it. */
19654
19720
  var RetrainFrameCandidateSchema = object({
19655
- mediaKey: string(),
19721
+ mediaId: number().int(),
19656
19722
  kind: MediaFileKindEnum,
19657
19723
  timestamp: number(),
19658
19724
  sizeBytes: number().int(),
@@ -19666,7 +19732,7 @@ var RetrainFrameSchema = object({
19666
19732
  deviceId: number(),
19667
19733
  trackId: string(),
19668
19734
  /** Provenance only. It may already point at nothing — that is expected. */
19669
- sourceMediaKey: string(),
19735
+ sourceMediaId: number().int(),
19670
19736
  sourceKind: MediaFileKindEnum,
19671
19737
  sizeBytes: number().int(),
19672
19738
  width: number().int(),
@@ -19682,7 +19748,7 @@ var RetrainCopyRefusalSchema = _enum([
19682
19748
  var RetrainFrameSelectionSchema = object({
19683
19749
  copied: array(RetrainFrameSchema).readonly(),
19684
19750
  refused: array(object({
19685
- sourceMediaKey: string(),
19751
+ sourceMediaId: number().int(),
19686
19752
  reason: RetrainCopyRefusalSchema
19687
19753
  })).readonly()
19688
19754
  });
@@ -19690,7 +19756,7 @@ var RetrainFrameListSchema = object({
19690
19756
  candidates: array(RetrainFrameCandidateSchema).readonly(),
19691
19757
  copies: array(RetrainFrameSchema).readonly(),
19692
19758
  /** What the page pre-selects — the native key frame when one survives. */
19693
- autoPickMediaKey: string().optional()
19759
+ autoPickMediaId: number().int().optional()
19694
19760
  });
19695
19761
  /** What the operator asked the assist to look for. */
19696
19762
  var RetrainAssistSubjectSchema = discriminatedUnion("kind", [object({
@@ -19785,9 +19851,11 @@ var RecentTracksQueryInput = object({
19785
19851
  });
19786
19852
  /**
19787
19853
  * A Summary (D359): the per-camera session envelope that references tracks.
19788
- * `groupShotKey` is the media key of its group shot (`ownerKind: 'summary'`,
19789
- * served by the event-media plane by key), null until the first frame with a
19790
- * member visible has been materialised.
19854
+ * `groupShotMediaId` is the media ROW id of its group shot (`ownerKind:
19855
+ * 'summary'`, served by the event-media plane at `/m/<id>`), null until the
19856
+ * first frame with a member visible has been materialised (D482 — it was the
19857
+ * row's composite key, which embedded the owner and could name another table's
19858
+ * row once event ids became per-table rowids).
19791
19859
  */
19792
19860
  var SummarySchema = object({
19793
19861
  id: string(),
@@ -19796,19 +19864,115 @@ var SummarySchema = object({
19796
19864
  lastActiveAt: number(),
19797
19865
  sealedAt: number().nullable(),
19798
19866
  memberCount: number().int().nonnegative(),
19799
- groupShotKey: string().nullable()
19867
+ groupShotMediaId: number().int().nullable()
19800
19868
  });
19801
19869
  var SummariesQueryInput = object({
19802
19870
  deviceIds: array(number()).min(1),
19803
19871
  since: number().optional(),
19804
19872
  until: number().optional(),
19805
- limit: number().int().min(1).max(200).default(50)
19873
+ limit: number().int().min(1).max(200).default(50),
19874
+ /** The same member-wise filter {@link listRecentSummaries} takes — one
19875
+ * meaning of "dog" on every summary surface. */
19876
+ classes: array(string().min(1).max(60)).max(40).optional()
19806
19877
  });
19807
- var SummariesPageSchema = object({ summaries: array(SummarySchema).readonly() });
19808
19878
  var SummaryDetailSchema = object({
19809
19879
  summary: SummarySchema,
19810
- /** Member track ids, in absorption order. */
19811
- trackIds: array(string()).readonly()
19880
+ /** Members in absorption order, oldest join first. */
19881
+ members: array(object({
19882
+ trackId: string(),
19883
+ /**
19884
+ * The track's class at the time it JOINED, or `null` when it was unresolved
19885
+ * and the track no longer exists to fill it.
19886
+ *
19887
+ * The join, not the latest opinion: class voting can re-decide a track's
19888
+ * class afterwards, and a group's composition is the history of who came
19889
+ * together. A consumer counts these to badge a thumbnail — "two people and a
19890
+ * dog" — rather than being handed a second, denormalised tally that would
19891
+ * drift from the members it claims to describe.
19892
+ */
19893
+ className: string().nullable(),
19894
+ /** `primary` is the one member that carries the group's identity. */
19895
+ role: _enum([
19896
+ "primary",
19897
+ "sibling",
19898
+ "child"
19899
+ ]).nullable(),
19900
+ joinedAt: number(),
19901
+ /** Tier 1 — the sub-class (`dog`, `van`), resolved from the member's track
19902
+ * at read time. Absent when nothing resolved, never an empty string. */
19903
+ label: string().optional(),
19904
+ /** Tier 2 — the instance: a person's name, a plate. Absent when the pipeline
19905
+ * recognised nobody, and absent for a member whose track has been pruned —
19906
+ * a thumbnail that names the wrong person is worse than one naming nobody. */
19907
+ subLabel: string().optional()
19908
+ })).readonly()
19909
+ });
19910
+ /**
19911
+ * What a LIST of groups carries: the envelope plus what it is MADE OF.
19912
+ *
19913
+ * Coarse on purpose — the operator's rule is "only the rough data on the list,
19914
+ * we extend when we notice we need more". Enough to draw the card ("two people
19915
+ * and a dog") and no more. The MEMBERS, their names and the per-member links
19916
+ * are on {@link getSummary}: shipping every member of every group so a client
19917
+ * can count them turns a page of two hundred groups into a thousand records to
19918
+ * draw two hundred badges.
19919
+ */
19920
+ var SummaryListItemSchema = object({
19921
+ summary: SummarySchema,
19922
+ /** Class counts, most numerous first; `className: null` is a member whose
19923
+ * class never resolved, counted so the counts add up to `memberCount`. */
19924
+ classes: array(object({
19925
+ className: string().nullable(),
19926
+ count: number().int().positive()
19927
+ })).readonly()
19928
+ });
19929
+ var SummariesPageSchema = object({ summaries: array(SummaryListItemSchema).readonly() });
19930
+ /**
19931
+ * The paged feed, deliberately the SAME shape as {@link RecentTracksQueryInput}.
19932
+ *
19933
+ * The reel on the cameras page and the Events gallery both ride a cursor, so a
19934
+ * summaries feed that could only answer "the last N for these cameras"
19935
+ * (`listSummaries`) would make groups available in the timeline and nowhere
19936
+ * else. Two feeds with different ordering contracts would be two ideas of what
19937
+ * "newest" means, on one screen.
19938
+ */
19939
+ var RecentSummariesQueryInput = object({
19940
+ /** Devices to merge. An empty array yields an empty page. */
19941
+ deviceIds: array(number()),
19942
+ /** Window lower bound on `lastActiveAt` (inclusive). */
19943
+ since: number().optional(),
19944
+ /** Window upper bound on `lastActiveAt` (inclusive). */
19945
+ until: number().optional(),
19946
+ limit: number().int().min(1).max(500).default(100),
19947
+ /** Opaque continuation cursor from a previous page's `nextCursor`. */
19948
+ cursor: string().optional(),
19949
+ /**
19950
+ * Restrict to these classes — THE SAME FIELD `listRecentTracks` takes, and
19951
+ * deliberately the same name: the events filter tree emits one list of ticked
19952
+ * taxonomy nodes, and a summaries feed that called it something else would
19953
+ * make the operator's one filter component produce two shapes.
19954
+ *
19955
+ * A question about the MEMBERS: a group matches when ANY of them does. "Show
19956
+ * me the arrivals with a dog" has to return the group of four people who had
19957
+ * one with them; a filter on the group's own fields could only ever answer
19958
+ * about its primary.
19959
+ *
19960
+ * Matched against all THREE tiers of a member — the class (`animal`), the
19961
+ * sub-class (`dog`) and the instance (a name, a plate) — because which tier a
19962
+ * ticked node lives on is the taxonomy's business, not the caller's. `dog` is
19963
+ * an event kind in the tree and a tier-1 label on an `animal` track; a filter
19964
+ * that read only the class would answer "animal" and never "dog".
19965
+ *
19966
+ * ABSENT or EMPTY means no filter — absent is not a selection of none.
19967
+ */
19968
+ classes: array(string().min(1).max(60)).max(40).optional()
19969
+ });
19970
+ var RecentSummariesPageSchema = object({
19971
+ /** Ordered by (`lastActiveAt` DESC, id DESC). Same light item as
19972
+ * {@link listSummaries} — one list shape, so a card renders the same
19973
+ * whichever feed drew it. */
19974
+ summaries: array(SummaryListItemSchema).readonly(),
19975
+ nextCursor: string().nullable()
19812
19976
  });
19813
19977
  var RecentTracksPageSchema = object({
19814
19978
  /** Merged page, ordered by (`lastSeen` DESC, `trackId` DESC). */
@@ -20222,7 +20386,7 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
20222
20386
  classes: array(string()).optional(),
20223
20387
  /** See {@link ExcludeSourcesDoc}. */
20224
20388
  excludeSources: array(TrackSourceSchema).optional()
20225
- }), array(TrackSchema).readonly()), method(RecentTracksQueryInput, RecentTracksPageSchema), method(SummariesQueryInput, SummariesPageSchema), method(object({ id: string() }), SummaryDetailSchema.nullable()), method(object({ deviceId: number() }), _void(), {
20389
+ }), array(TrackSchema).readonly()), method(RecentTracksQueryInput, RecentTracksPageSchema), method(SummariesQueryInput, SummariesPageSchema), method(RecentSummariesQueryInput, RecentSummariesPageSchema), method(object({ id: string() }), SummaryDetailSchema.nullable()), method(object({ deviceId: number() }), _void(), {
20226
20390
  kind: "mutation",
20227
20391
  auth: "admin"
20228
20392
  }), 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({
@@ -20350,7 +20514,7 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
20350
20514
  }), method(object({
20351
20515
  deviceId: number(),
20352
20516
  trackId: string(),
20353
- mediaKeys: array(string()).min(1)
20517
+ mediaIds: array(number().int()).min(1)
20354
20518
  }), RetrainFrameSelectionSchema, {
20355
20519
  kind: "mutation",
20356
20520
  auth: "admin"
@@ -20418,7 +20582,10 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
20418
20582
  kind: "query",
20419
20583
  auth: "admin"
20420
20584
  }), method(object({
20421
- eventId: string(),
20585
+ /** Which of the three event tables owns the row. */
20586
+ ownerType: EventOwnerTypeSchema,
20587
+ /** The event's rowid in that table (D474: an event id is a number). */
20588
+ eventId: number().int(),
20422
20589
  kind: MediaFileKindEnum.optional(),
20423
20590
  deviceId: number()
20424
20591
  }), array(MediaFileSchema).readonly()), method(object({
@@ -20429,7 +20596,8 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
20429
20596
  trackId: string(),
20430
20597
  deviceId: number()
20431
20598
  }), array(MediaFileInfoSchema).readonly()), method(object({
20432
- eventId: string(),
20599
+ ownerType: EventOwnerTypeSchema,
20600
+ eventId: number().int(),
20433
20601
  deviceId: number()
20434
20602
  }), array(MediaFileInfoSchema).readonly()), method(SearchObjectEventsInput, array(ScoredObjectEventSchema).readonly()), method(object({}), WipeObjectEmbeddingsResultSchema, {
20435
20603
  kind: "mutation",
@@ -24892,8 +25060,8 @@ var IdentitySchema = object({
24892
25060
  id: string(),
24893
25061
  name: string(),
24894
25062
  sampleCount: number().int().nonnegative(),
24895
- coverMediaKey: string().optional(),
24896
- /** Inline base64 of the cover sample's crop, resolved from `coverMediaKey`.
25063
+ coverMediaId: number().int().optional(),
25064
+ /** Inline base64 of the cover sample's crop, resolved from `coverMediaId`.
24897
25065
  * Lets the UI render the person's face avatar instead of a placeholder icon. */
24898
25066
  coverBase64: string().optional()
24899
25067
  });
@@ -24919,8 +25087,8 @@ var IdentitySampleAuditRowSchema = object({
24919
25087
  enrolledAt: number().int(),
24920
25088
  deviceId: number().int().optional(),
24921
25089
  source: _enum(["detected", "photo"]),
24922
- /** The enrolled crop's media key, so the panel can show the evidence. */
24923
- mediaKey: string().optional(),
25090
+ /** The enrolled crop's media row id, so the panel can show the evidence. */
25091
+ mediaId: number().int().optional(),
24924
25092
  /**
24925
25093
  * False = the sample is stamped with a DIFFERENT face model, and a cosine
24926
25094
  * across feature spaces is a well-formed float with no meaning. Every number
@@ -24989,15 +25157,15 @@ var FaceInfoSchema = object({
24989
25157
  */
24990
25158
  cropUrl: string().optional(),
24991
25159
  /** Design B: the face bbox (pixel space) on the key frame — lets a detail
24992
- * view draw the box over the native `keyFrameMediaKey` frame. Absent on
25160
+ * view draw the box over the native `keyFrameMediaId` frame. Absent on
24993
25161
  * legacy rows written before design B. */
24994
25162
  faceBbox: BoundingBoxSchema.optional(),
24995
25163
  /** Design B: MediaStore key of the track's native-resolution key frame.
24996
25164
  * Fetch the native JPEG via the event-media data-plane
24997
- * (`/addon/<addonId>/event-media/<keyFrameMediaKey>`). Absent when the
25165
+ * (`/addon/<addonId>/event-media/m/<keyFrameMediaId>`). Absent when the
24998
25166
  * track produced no key frame (e.g. native/onboard source) — the UI falls
24999
25167
  * back to the inline `base64` face crop. */
25000
- keyFrameMediaKey: string().optional(),
25168
+ keyFrameMediaId: number().int().optional(),
25001
25169
  /** Winning identity-match cosine (0..1) for this face's track, when an
25002
25170
  * identity was auto-confirmed. Lets the UI surface WHY a face was assigned
25003
25171
  * (confidence badge / low-confidence audit). Absent on legacy rows and on
@@ -25066,11 +25234,14 @@ var FaceClusterSchema = object({
25066
25234
  * `data:image/jpeg;base64,…` from a row whose `key` sat right beside it, in a
25067
25235
  * dialog already rendering its key FRAME from the `event-media` plane.
25068
25236
  *
25069
- * `url` is `/addon/<addonId>/event-media/<encoded key>`. The plane resolves a
25070
- * media key directly, so this needed no new plane and no new access decision.
25237
+ * `url` is `/addon/<addonId>/event-media/m/<mediaId>` (D482). The plane
25238
+ * resolves a media row by its own id, so this needed no new plane and no new
25239
+ * access decision.
25071
25240
  */
25072
25241
  var MediaFileLiteSchema$1 = object({
25073
- key: string(),
25242
+ /** The media row's own id — the same address `MediaFileRef.mediaId` carries
25243
+ * (D482). It was the row's composite key, which embedded the owner. */
25244
+ mediaId: number().int(),
25074
25245
  kind: string(),
25075
25246
  url: string(),
25076
25247
  sizeBytes: number(),
@@ -25087,7 +25258,7 @@ method(object({
25087
25258
  * covers inline, ~10 KB of base64 per row, on a query this UI mounts
25088
25259
  * four times and the viewer holds at `staleTime: 30_000`.
25089
25260
  *
25090
- * Nothing loses its avatar: `coverMediaKey` is already on every row and
25261
+ * Nothing loses its avatar: `coverMediaId` is already on every row and
25091
25262
  * the `event-media` plane serves that key `immutable` with an ETag.
25092
25263
  *
25093
25264
  * **This is an INPUT field, so it does not reach the addon until the
@@ -27555,8 +27726,8 @@ var VehicleSchema = object({
27555
27726
  id: string(),
27556
27727
  name: string(),
27557
27728
  sampleCount: number().int().nonnegative(),
27558
- coverMediaKey: string().optional(),
27559
- /** Inline base64 of the cover sample's plate crop, resolved from `coverMediaKey`. */
27729
+ coverMediaId: number().int().optional(),
27730
+ /** Inline base64 of the cover sample's plate crop, resolved from `coverMediaId`. */
27560
27731
  coverBase64: string().optional()
27561
27732
  });
27562
27733
  var VehicleSampleInfoSchema = object({
@@ -27589,7 +27760,7 @@ var PlateInfoSchema = object({
27589
27760
  /** keyFrame parity: the plate bbox (pixel space) on the native key frame. */
27590
27761
  plateBbox: BoundingBoxSchema.optional(),
27591
27762
  /** keyFrame parity: MediaStore key of the track's native-resolution key frame. */
27592
- keyFrameMediaKey: string().optional(),
27763
+ keyFrameMediaId: number().int().optional(),
27593
27764
  base64: string().optional(),
27594
27765
  /**
27595
27766
  * Same crop as a data-plane URL, always present when the plate has a stored
@@ -27610,11 +27781,14 @@ var PlateInfoSchema = object({
27610
27781
  * `data:image/jpeg;base64,…` from a row whose `key` sat right beside it, in a
27611
27782
  * dialog already rendering its key FRAME from the `event-media` plane.
27612
27783
  *
27613
- * `url` is `/addon/<addonId>/event-media/<encoded key>`. The plane resolves a
27614
- * media key directly, so this needed no new plane and no new access decision.
27784
+ * `url` is `/addon/<addonId>/event-media/m/<mediaId>` (D482). The plane
27785
+ * resolves a media row by its own id, so this needed no new plane and no new
27786
+ * access decision.
27615
27787
  */
27616
27788
  var MediaFileLiteSchema = object({
27617
- key: string(),
27789
+ /** The media row's own id — the same address `MediaFileRef.mediaId` carries
27790
+ * (D482). It was the row's composite key, which embedded the owner. */
27791
+ mediaId: number().int(),
27618
27792
  kind: string(),
27619
27793
  url: string(),
27620
27794
  sizeBytes: number(),
@@ -27673,7 +27847,7 @@ method(object({
27673
27847
  }), method(object({
27674
27848
  /** Inline {@link VehicleSchema.coverBase64} on every row. Default
27675
27849
  * `false` — the vehicle twin of `faceGallery.listIdentities`'s
27676
- * option; `coverMediaKey` + the `event-media` plane carry the picture.
27850
+ * option; `coverMediaId` + the `event-media` plane carry the picture.
27677
27851
  * INPUT field: stripped by the hub router until the train ships, which
27678
27852
  * resolves to `false` and is exactly the intended default. */
27679
27853
  includeCrops: boolean().optional() }).optional(), array(VehicleSchema).readonly()), method(object({ name: string().min(1) }), VehicleSchema, {
@@ -28997,7 +29171,14 @@ var SceneReferenceSchema = object({
28997
29171
  modelId: string(),
28998
29172
  condition: SceneConditionSchema,
28999
29173
  capturedAt: number(),
29000
- thumbnailMediaId: string().optional(),
29174
+ /**
29175
+ * The reference thumbnail's media ROW id (D482).
29176
+ *
29177
+ * The name already said `mediaId` while the value was the row's composite
29178
+ * key — a leftover that read as done and was not. It is the row's own id
29179
+ * now, addressed at `/addon/<addonId>/event-media/m/<id>`.
29180
+ */
29181
+ thumbnailMediaId: number().int().optional(),
29001
29182
  /** Whole-frame (downscaled) embedding captured alongside the ROI crop. The
29002
29183
  * anti-view-shift anchor: a bumped camera, a PTZ preset or a re-aim makes the
29003
29184
  * normalized rect frame a different piece of world, and the scene would
@@ -29811,7 +29992,29 @@ var LoggingSettingsPatchSchema = object({
29811
29992
  * disarmed the channels it did not mention would make the Levels page and
29812
29993
  * the Diagnostics page fight over the same value.
29813
29994
  */
29814
- channels: array(LogChannelWindowPatchSchema).readonly().optional()
29995
+ channels: array(LogChannelWindowPatchSchema).readonly().optional(),
29996
+ /**
29997
+ * How many days the analytics OPS LOG is kept — the audit trail of what
29998
+ * retention actually deleted.
29999
+ *
30000
+ * It lives HERE, on the logging document, and not on the analytics addon's
30001
+ * settings form, on the operator's instruction: every other log-ish window in
30002
+ * this system is configured through this one document, and a retention audit
30003
+ * configured somewhere else is a second place to look when the question is
30004
+ * "what happened to my data".
30005
+ *
30006
+ * That placement has a cost worth stating: this document ships in the
30007
+ * framework closure, so this knob needs a published `@camstack/server` while
30008
+ * the four windows beside it (D485) reach a node on `camstack deploy`.
30009
+ *
30010
+ * `retention-model.ts` argued this one must NOT follow a device window,
30011
+ * because the audit trail is the history of the SWEEP and not of the camera.
30012
+ * That argument stands and is untouched — what changes is that 30 days stops
30013
+ * being a constant nobody can reach. `0` keeps it forever. The floor is 1 day
30014
+ * rather than 0-as-delete: an audit log truncated to nothing is precisely the
30015
+ * state in which the next 9.5 GiB leak cannot be explained.
30016
+ */
30017
+ opsLogRetentionDays: number().int().min(0).max(3650).optional()
29815
30018
  });
29816
30019
  /**
29817
30020
  * Which LAYER of the hierarchy is addressed. Absent = the cluster layer.
@@ -29884,6 +30087,14 @@ var LoggingSettingsStateSchema = object({
29884
30087
  channels: array(LogChannelDescriptorSchema).readonly(),
29885
30088
  /** The channels ARMED right now, each with its deadline. */
29886
30089
  activeChannels: array(LogChannelWindowStateSchema).readonly(),
30090
+ /**
30091
+ * The ops-log window in days, as it is in force. `0` = kept forever.
30092
+ *
30093
+ * Reported rather than left to the caller's memory of what it wrote: this is
30094
+ * the value the analytics sweep will actually use, and an operator asking how
30095
+ * long their audit trail lives should not have to infer it from a default.
30096
+ */
30097
+ opsLogRetentionDays: number().int().min(0),
29887
30098
  persisted: boolean()
29888
30099
  });
29889
30100
  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(), {
@@ -30445,7 +30656,7 @@ var StationaryObjectSchema = object({
30445
30656
  /** Enrichment label carried from the source track (identity / plate). */
30446
30657
  label: string().optional(),
30447
30658
  /** Native-resolution key-frame media key for the parked object's best image. */
30448
- keyFrameMediaKey: string().optional()
30659
+ keyFrameMediaId: number().int().optional()
30449
30660
  });
30450
30661
  var CameraOccupancySnapshotSchema = object({
30451
30662
  /** Frame timestamp of the inference result that produced this snapshot. */
@@ -31601,6 +31812,12 @@ Object.freeze({
31601
31812
  addonId: null,
31602
31813
  access: "create"
31603
31814
  },
31815
+ "dataStoreProvider.upsert": {
31816
+ capName: "data-store-provider",
31817
+ capScope: "system",
31818
+ addonId: null,
31819
+ access: "create"
31820
+ },
31604
31821
  "dayNight.getOptions": {
31605
31822
  capName: "day-night",
31606
31823
  capScope: "device",
@@ -34037,6 +34254,12 @@ Object.freeze({
34037
34254
  addonId: null,
34038
34255
  access: "view"
34039
34256
  },
34257
+ "pipelineAnalytics.listRecentSummaries": {
34258
+ capName: "pipeline-analytics",
34259
+ capScope: "device",
34260
+ addonId: null,
34261
+ access: "view"
34262
+ },
34040
34263
  "pipelineAnalytics.listRecentTracks": {
34041
34264
  capName: "pipeline-analytics",
34042
34265
  capScope: "device",
@@ -35465,6 +35688,12 @@ Object.freeze({
35465
35688
  addonId: null,
35466
35689
  access: "create"
35467
35690
  },
35691
+ "settingsStore.upsert": {
35692
+ capName: "settings-store",
35693
+ capScope: "system",
35694
+ addonId: null,
35695
+ access: "create"
35696
+ },
35468
35697
  "smtpProvider.getStatus": {
35469
35698
  capName: "smtp-provider",
35470
35699
  capScope: "system",
@@ -37858,6 +38087,11 @@ Object.freeze({
37858
38087
  form: "single",
37859
38088
  optional: true
37860
38089
  }],
38090
+ "pipelineAnalytics.listRecentSummaries": [{
38091
+ name: "deviceIds",
38092
+ form: "array",
38093
+ optional: false
38094
+ }],
37861
38095
  "pipelineAnalytics.listRecentTracks": [{
37862
38096
  name: "deviceIds",
37863
38097
  form: "array",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/addon-mqtt-broker",
3
- "version": "1.2.99",
3
+ "version": "1.2.101",
4
4
  "description": "MQTT broker registry addon for CamStack — manages external broker entries + an optional embedded aedes broker. Consumers spin up their own `mqtt.js` clients via the `mqtt-broker` cap.",
5
5
  "keywords": [
6
6
  "camstack",