@camstack/addon-smtp-nodemailer 1.2.98 → 1.2.100

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.
@@ -36,7 +36,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
36
36
  }) : target, mod));
37
37
  var __toCommonJS = (mod) => __hasOwnProp.call(mod, "module.exports") ? mod["module.exports"] : __copyProps(__defProp({}, "__esModule", { value: true }), mod);
38
38
  //#endregion
39
- //#region ../types/dist/event-category-DAXzJeTX.mjs
39
+ //#region ../types/dist/event-category-ZyX6jcse.mjs
40
40
  var EventCategory = /* @__PURE__ */ function(EventCategory) {
41
41
  EventCategory["SystemBoot"] = "system.boot";
42
42
  EventCategory["SystemAddonsReady"] = "system.addons-ready";
@@ -597,7 +597,7 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
597
597
  * a package zone — a newly-appeared stationary object of a package class
598
598
  * that cleared the class / zone / dwell / size gates. Payload:
599
599
  * `PipelineAnalyticsPackageDeliveredPayload` carrying `{ deviceId,
600
- * entryId, className, zoneIds, keyFrameMediaKey?, bbox, timestamp }`.
600
+ * entryId, className, zoneIds, keyFrameMediaId?, bbox, timestamp }`.
601
601
  * Telemetry (D8): the durable record is the `package-events` store row;
602
602
  * this bus topic drives notifier rules + live UI. See
603
603
  * docs/superpowers/specs/2026-07-17-package-zones-design.md §5.1.
@@ -5383,7 +5383,7 @@ var ZodIssueCode = {
5383
5383
  var ZodFirstPartyTypeKind;
5384
5384
  ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
5385
5385
  //#endregion
5386
- //#region ../types/dist/sleep-BnujYGPe.mjs
5386
+ //#region ../types/dist/sleep-DBKu2-U5.mjs
5387
5387
  /**
5388
5388
  * The audio chunk plane's byte format, and the ONE expansion from a coded
5389
5389
  * window to float samples (D455).
@@ -7334,13 +7334,30 @@ new Set([
7334
7334
  "scene",
7335
7335
  "motion",
7336
7336
  "object",
7337
- "audio"
7337
+ "audio",
7338
+ "mosaic"
7338
7339
  ]);
7339
- new Set([
7340
+ /**
7341
+ * The owner types that are event tables, in the order the event-media resolver
7342
+ * should consider them. Exported so a consumer asking "is this key an event?"
7343
+ * does not re-spell the list and drift from it.
7344
+ */
7345
+ var EVENT_OWNER_TYPES = [
7340
7346
  "motion",
7341
7347
  "object",
7342
7348
  "audio"
7343
- ]);
7349
+ ];
7350
+ /**
7351
+ * The same list as a Zod enum, for the cap inputs that must NAME the table
7352
+ * (D482: `getEventMedia` / `listEventMedia` take an owner, and an owner is
7353
+ * `(table, id)`).
7354
+ *
7355
+ * Built FROM {@link EVENT_OWNER_TYPES} rather than re-spelled: a fourth event
7356
+ * table would otherwise be accepted by the codec and refused at the door, with
7357
+ * nothing failing until a caller asked.
7358
+ */
7359
+ var EventOwnerTypeSchema = _enum(EVENT_OWNER_TYPES);
7360
+ new Set(EVENT_OWNER_TYPES);
7344
7361
  var EncodeProfileSchema = object({
7345
7362
  video: object({
7346
7363
  codec: _enum([
@@ -7379,7 +7396,23 @@ var EncodeProfileSchema = object({
7379
7396
  "zerolatency",
7380
7397
  "film",
7381
7398
  "animation"
7382
- ]).optional()
7399
+ ]).optional(),
7400
+ /**
7401
+ * ONE slice per access unit.
7402
+ *
7403
+ * `-tune zerolatency` turns on x264's sliced threads, and a frame then leaves
7404
+ * the encoder as five NAL slices that share one RTP timestamp and carry one
7405
+ * marker bit. A libwebrtc depacketiser sees five frame-starts and one
7406
+ * frame-end per frame: the first pictures render and the video then freezes
7407
+ * for good while the audio, on its own plane, plays on. Measured on this hub
7408
+ * 2026-09-13 against the Echo, and reduced to one slice by this flag alone.
7409
+ *
7410
+ * A NAMED field and not a raw flag, because {@link EgressEncodeSchema} omits
7411
+ * `outputArgs` on purpose: an opaque array is part of the sharing key, so two
7412
+ * consumers meaning the same thing spelled differently would stop sharing one
7413
+ * child. Absent means "whatever the encoder does" — today's behaviour.
7414
+ */
7415
+ singleSlicePerFrame: boolean().optional()
7383
7416
  }),
7384
7417
  audio: union([literal("passthrough"), object({
7385
7418
  codec: _enum([
@@ -7429,7 +7462,7 @@ var BASE_LIVE_EGRESS_PROFILE = {
7429
7462
  audio: "passthrough"
7430
7463
  };
7431
7464
  ({ ...BASE_LIVE_EGRESS_PROFILE }), { ...BASE_LIVE_EGRESS_PROFILE.video };
7432
- ({ ...BASE_LIVE_EGRESS_PROFILE });
7465
+ ({ ...BASE_LIVE_EGRESS_PROFILE }), { ...BASE_LIVE_EGRESS_PROFILE.video };
7433
7466
  /**
7434
7467
  * Deep wiring healthcheck — snapshot of active reachability probes across
7435
7468
  * every declared capability + widget of every installed plugin, on every
@@ -12437,6 +12470,16 @@ method(object({
12437
12470
  filter: QueryFilterSchema.optional(),
12438
12471
  columns: array(string()).readonly().optional()
12439
12472
  }), array(SettingsRecordSchema).readonly()), method(object({
12473
+ namespace: string().optional(),
12474
+ collection: string(),
12475
+ /** Declared columns identifying the slot; must be covered by a UNIQUE
12476
+ * index on the collection. Never empty. */
12477
+ conflict: array(string()).readonly(),
12478
+ record: BulkRecordSchema
12479
+ }), object({
12480
+ /** The id the row HAS: assigned by SQLite on an insert, or the existing
12481
+ * row's own id on an update. */
12482
+ id: union([string(), number()]) }), { kind: "mutation" }), method(object({
12440
12483
  namespace: string().optional(),
12441
12484
  collection: string(),
12442
12485
  record: object({
@@ -12571,6 +12614,14 @@ method(_void(), EngineInfoSchema, { auth: "admin" }), method(object({
12571
12614
  id: union([string(), number()]) }), {
12572
12615
  kind: "mutation",
12573
12616
  auth: "admin"
12617
+ }), method(object({
12618
+ namespace: string().optional(),
12619
+ collection: string(),
12620
+ conflict: array(string()).readonly(),
12621
+ record: BulkRecordSchema
12622
+ }), object({ id: union([string(), number()]) }), {
12623
+ kind: "mutation",
12624
+ auth: "admin"
12574
12625
  }), method(object({
12575
12626
  namespace: string().optional(),
12576
12627
  collection: string(),
@@ -18787,8 +18838,8 @@ var TrackPositionSchema = object({
18787
18838
  var TrackSnapshotSchema = object({
18788
18839
  timestamp: number(),
18789
18840
  position: TrackPositionSchema,
18790
- /** MediaStore key; resolve via `getTrackMedia({ trackId })`. */
18791
- mediaKey: string()
18841
+ /** The snapshot's media row id (D482); resolve via `listTrackMedia({ trackId })`. */
18842
+ mediaId: number().int()
18792
18843
  });
18793
18844
  /**
18794
18845
  * Normalized 0..1 trajectory envelope (min/max over every position bbox,
@@ -19392,14 +19443,14 @@ var ObjectEventSchema = object({
19392
19443
  * pixel-space `bbox` onto a displayed image. Omitted in slim projection. */
19393
19444
  frameWidth: number().optional(),
19394
19445
  frameHeight: number().optional(),
19395
- /** MediaStore key for the crop attached to this event (if any). */
19396
- mediaKey: string().optional(),
19397
- /** Design B: MediaStore key of the track's native-resolution key frame (the
19446
+ /** Media row id of the crop attached to this event (if any) — D482. */
19447
+ mediaId: number().int().optional(),
19448
+ /** Design B: media row id of the track's native-resolution key frame (the
19398
19449
  * best-detection full frame). Resolve via the event-media data-plane
19399
- * (`/addon/<addonId>/event-media/<keyFrameMediaKey>`) for a detail view that
19450
+ * (`/addon/<addonId>/event-media/m/<keyFrameMediaId>`) for a detail view that
19400
19451
  * draws `bbox` over the native frame. Absent on legacy rows / non-decoded
19401
- * sources — consumers fall back to `mediaKey` (the tight crop). */
19402
- keyFrameMediaKey: string().optional(),
19452
+ * sources — consumers fall back to `mediaId` (the tight crop). */
19453
+ keyFrameMediaId: number().int().optional(),
19403
19454
  /** Populated by B5 (recording playback URL for this event). */
19404
19455
  mediaUrl: string().optional(),
19405
19456
  /** The parent track's key-event importance [0,1], propagated to every object
@@ -19449,7 +19500,7 @@ var MediaFileKindEnum = _enum([
19449
19500
  * hub-main's heap on the way past — for an `<img>` that would have cached it.
19450
19501
  *
19451
19502
  * `url` points at the `event-media` data plane
19452
- * (`/addon/<addonId>/event-media/<storedKey>`), which serves the same blob
19503
+ * (`/addon/<addonId>/event-media/m/<mediaId>` — D482), which serves the same blob
19453
19504
  * with an ETag and `Cache-Control: immutable`, honours conditional GETs, can
19454
19505
  * render a `?variant=thumb`, and streams. The hub gate in front of it requires
19455
19506
  * a bearer or the session cookie (`access: 'authenticated'`), so the bytes are
@@ -19457,10 +19508,13 @@ var MediaFileKindEnum = _enum([
19457
19508
  * `data-plane-access.ts` for the rule and the one gap it does not close
19458
19509
  * (per-device scoping).
19459
19510
  *
19460
- * The URL is built from the row's **stored** key, which is not always its
19461
- * published `kind`: a track's face/plate crop is stored as `crop` under
19511
+ * The URL is built from the row's own id, which since D482 says nothing about
19512
+ * the row's owner or kind and that is the point. The published `kind` is not
19513
+ * the stored one (a track's face/plate crop is stored as `crop` under
19462
19514
  * `('face'|'plate', '<prefix>-<trackId>')` and published as
19463
- * `faceCrop`/`plateCrop`. `MediaStore.getByKey` knows only the stored key.
19515
+ * `faceCrop`/`plateCrop`), and under the old composite key the URL had to be
19516
+ * taken from `row.key` verbatim or it 404'd exactly those two rows. An id
19517
+ * cannot be mis-reconstructed, because there is nothing in it to reconstruct.
19464
19518
  *
19465
19519
  * ## `base64` is TRANSITIONAL and is going away
19466
19520
  *
@@ -19473,7 +19527,19 @@ var MediaFileKindEnum = _enum([
19473
19527
  * `analytics-query-facade.ts`; nothing else reads it.
19474
19528
  */
19475
19529
  var MediaFileSchema = object({
19476
- key: string(),
19530
+ /**
19531
+ * The media row's OWN id — the rowid SQLite assigned it (D482).
19532
+ *
19533
+ * It used to be the row's composite key, `<ownerType>:<ownerId>:<fileKind>
19534
+ * [:<timestampMs>]`, which embedded a FOREIGN id. D474 made event ids
19535
+ * per-table rowid aliases, so `object:101314` and `motion:101314` are two
19536
+ * different rows that spell the same number, and a track whose
19537
+ * `bestEventId` was an object event was served a motion event's snapshot —
19538
+ * a night-time thumbnail on an afternoon track, with no error anywhere. A
19539
+ * surrogate id cannot name the wrong row's owner, because it names no owner
19540
+ * at all.
19541
+ */
19542
+ mediaId: number().int(),
19477
19543
  kind: MediaFileKindEnum,
19478
19544
  sizeBytes: number(),
19479
19545
  timestamp: number()
@@ -19581,7 +19647,7 @@ var RetrainTrackSchema = object({
19581
19647
  });
19582
19648
  /** A frame the picker may offer — an index row, no blob was read to produce it. */
19583
19649
  var RetrainFrameCandidateSchema = object({
19584
- mediaKey: string(),
19650
+ mediaId: number().int(),
19585
19651
  kind: MediaFileKindEnum,
19586
19652
  timestamp: number(),
19587
19653
  sizeBytes: number().int(),
@@ -19595,7 +19661,7 @@ var RetrainFrameSchema = object({
19595
19661
  deviceId: number(),
19596
19662
  trackId: string(),
19597
19663
  /** Provenance only. It may already point at nothing — that is expected. */
19598
- sourceMediaKey: string(),
19664
+ sourceMediaId: number().int(),
19599
19665
  sourceKind: MediaFileKindEnum,
19600
19666
  sizeBytes: number().int(),
19601
19667
  width: number().int(),
@@ -19611,7 +19677,7 @@ var RetrainCopyRefusalSchema = _enum([
19611
19677
  var RetrainFrameSelectionSchema = object({
19612
19678
  copied: array(RetrainFrameSchema).readonly(),
19613
19679
  refused: array(object({
19614
- sourceMediaKey: string(),
19680
+ sourceMediaId: number().int(),
19615
19681
  reason: RetrainCopyRefusalSchema
19616
19682
  })).readonly()
19617
19683
  });
@@ -19619,7 +19685,7 @@ var RetrainFrameListSchema = object({
19619
19685
  candidates: array(RetrainFrameCandidateSchema).readonly(),
19620
19686
  copies: array(RetrainFrameSchema).readonly(),
19621
19687
  /** What the page pre-selects — the native key frame when one survives. */
19622
- autoPickMediaKey: string().optional()
19688
+ autoPickMediaId: number().int().optional()
19623
19689
  });
19624
19690
  /** What the operator asked the assist to look for. */
19625
19691
  var RetrainAssistSubjectSchema = discriminatedUnion("kind", [object({
@@ -19714,9 +19780,11 @@ var RecentTracksQueryInput = object({
19714
19780
  });
19715
19781
  /**
19716
19782
  * A Summary (D359): the per-camera session envelope that references tracks.
19717
- * `groupShotKey` is the media key of its group shot (`ownerKind: 'summary'`,
19718
- * served by the event-media plane by key), null until the first frame with a
19719
- * member visible has been materialised.
19783
+ * `groupShotMediaId` is the media ROW id of its group shot (`ownerKind:
19784
+ * 'summary'`, served by the event-media plane at `/m/<id>`), null until the
19785
+ * first frame with a member visible has been materialised (D482 — it was the
19786
+ * row's composite key, which embedded the owner and could name another table's
19787
+ * row once event ids became per-table rowids).
19720
19788
  */
19721
19789
  var SummarySchema = object({
19722
19790
  id: string(),
@@ -19725,19 +19793,115 @@ var SummarySchema = object({
19725
19793
  lastActiveAt: number(),
19726
19794
  sealedAt: number().nullable(),
19727
19795
  memberCount: number().int().nonnegative(),
19728
- groupShotKey: string().nullable()
19796
+ groupShotMediaId: number().int().nullable()
19729
19797
  });
19730
19798
  var SummariesQueryInput = object({
19731
19799
  deviceIds: array(number()).min(1),
19732
19800
  since: number().optional(),
19733
19801
  until: number().optional(),
19734
- limit: number().int().min(1).max(200).default(50)
19802
+ limit: number().int().min(1).max(200).default(50),
19803
+ /** The same member-wise filter {@link listRecentSummaries} takes — one
19804
+ * meaning of "dog" on every summary surface. */
19805
+ classes: array(string().min(1).max(60)).max(40).optional()
19735
19806
  });
19736
- var SummariesPageSchema = object({ summaries: array(SummarySchema).readonly() });
19737
19807
  var SummaryDetailSchema = object({
19738
19808
  summary: SummarySchema,
19739
- /** Member track ids, in absorption order. */
19740
- trackIds: array(string()).readonly()
19809
+ /** Members in absorption order, oldest join first. */
19810
+ members: array(object({
19811
+ trackId: string(),
19812
+ /**
19813
+ * The track's class at the time it JOINED, or `null` when it was unresolved
19814
+ * and the track no longer exists to fill it.
19815
+ *
19816
+ * The join, not the latest opinion: class voting can re-decide a track's
19817
+ * class afterwards, and a group's composition is the history of who came
19818
+ * together. A consumer counts these to badge a thumbnail — "two people and a
19819
+ * dog" — rather than being handed a second, denormalised tally that would
19820
+ * drift from the members it claims to describe.
19821
+ */
19822
+ className: string().nullable(),
19823
+ /** `primary` is the one member that carries the group's identity. */
19824
+ role: _enum([
19825
+ "primary",
19826
+ "sibling",
19827
+ "child"
19828
+ ]).nullable(),
19829
+ joinedAt: number(),
19830
+ /** Tier 1 — the sub-class (`dog`, `van`), resolved from the member's track
19831
+ * at read time. Absent when nothing resolved, never an empty string. */
19832
+ label: string().optional(),
19833
+ /** Tier 2 — the instance: a person's name, a plate. Absent when the pipeline
19834
+ * recognised nobody, and absent for a member whose track has been pruned —
19835
+ * a thumbnail that names the wrong person is worse than one naming nobody. */
19836
+ subLabel: string().optional()
19837
+ })).readonly()
19838
+ });
19839
+ /**
19840
+ * What a LIST of groups carries: the envelope plus what it is MADE OF.
19841
+ *
19842
+ * Coarse on purpose — the operator's rule is "only the rough data on the list,
19843
+ * we extend when we notice we need more". Enough to draw the card ("two people
19844
+ * and a dog") and no more. The MEMBERS, their names and the per-member links
19845
+ * are on {@link getSummary}: shipping every member of every group so a client
19846
+ * can count them turns a page of two hundred groups into a thousand records to
19847
+ * draw two hundred badges.
19848
+ */
19849
+ var SummaryListItemSchema = object({
19850
+ summary: SummarySchema,
19851
+ /** Class counts, most numerous first; `className: null` is a member whose
19852
+ * class never resolved, counted so the counts add up to `memberCount`. */
19853
+ classes: array(object({
19854
+ className: string().nullable(),
19855
+ count: number().int().positive()
19856
+ })).readonly()
19857
+ });
19858
+ var SummariesPageSchema = object({ summaries: array(SummaryListItemSchema).readonly() });
19859
+ /**
19860
+ * The paged feed, deliberately the SAME shape as {@link RecentTracksQueryInput}.
19861
+ *
19862
+ * The reel on the cameras page and the Events gallery both ride a cursor, so a
19863
+ * summaries feed that could only answer "the last N for these cameras"
19864
+ * (`listSummaries`) would make groups available in the timeline and nowhere
19865
+ * else. Two feeds with different ordering contracts would be two ideas of what
19866
+ * "newest" means, on one screen.
19867
+ */
19868
+ var RecentSummariesQueryInput = object({
19869
+ /** Devices to merge. An empty array yields an empty page. */
19870
+ deviceIds: array(number()),
19871
+ /** Window lower bound on `lastActiveAt` (inclusive). */
19872
+ since: number().optional(),
19873
+ /** Window upper bound on `lastActiveAt` (inclusive). */
19874
+ until: number().optional(),
19875
+ limit: number().int().min(1).max(500).default(100),
19876
+ /** Opaque continuation cursor from a previous page's `nextCursor`. */
19877
+ cursor: string().optional(),
19878
+ /**
19879
+ * Restrict to these classes — THE SAME FIELD `listRecentTracks` takes, and
19880
+ * deliberately the same name: the events filter tree emits one list of ticked
19881
+ * taxonomy nodes, and a summaries feed that called it something else would
19882
+ * make the operator's one filter component produce two shapes.
19883
+ *
19884
+ * A question about the MEMBERS: a group matches when ANY of them does. "Show
19885
+ * me the arrivals with a dog" has to return the group of four people who had
19886
+ * one with them; a filter on the group's own fields could only ever answer
19887
+ * about its primary.
19888
+ *
19889
+ * Matched against all THREE tiers of a member — the class (`animal`), the
19890
+ * sub-class (`dog`) and the instance (a name, a plate) — because which tier a
19891
+ * ticked node lives on is the taxonomy's business, not the caller's. `dog` is
19892
+ * an event kind in the tree and a tier-1 label on an `animal` track; a filter
19893
+ * that read only the class would answer "animal" and never "dog".
19894
+ *
19895
+ * ABSENT or EMPTY means no filter — absent is not a selection of none.
19896
+ */
19897
+ classes: array(string().min(1).max(60)).max(40).optional()
19898
+ });
19899
+ var RecentSummariesPageSchema = object({
19900
+ /** Ordered by (`lastActiveAt` DESC, id DESC). Same light item as
19901
+ * {@link listSummaries} — one list shape, so a card renders the same
19902
+ * whichever feed drew it. */
19903
+ summaries: array(SummaryListItemSchema).readonly(),
19904
+ nextCursor: string().nullable()
19741
19905
  });
19742
19906
  var RecentTracksPageSchema = object({
19743
19907
  /** Merged page, ordered by (`lastSeen` DESC, `trackId` DESC). */
@@ -20151,7 +20315,7 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
20151
20315
  classes: array(string()).optional(),
20152
20316
  /** See {@link ExcludeSourcesDoc}. */
20153
20317
  excludeSources: array(TrackSourceSchema).optional()
20154
- }), array(TrackSchema).readonly()), method(RecentTracksQueryInput, RecentTracksPageSchema), method(SummariesQueryInput, SummariesPageSchema), method(object({ id: string() }), SummaryDetailSchema.nullable()), method(object({ deviceId: number() }), _void(), {
20318
+ }), array(TrackSchema).readonly()), method(RecentTracksQueryInput, RecentTracksPageSchema), method(SummariesQueryInput, SummariesPageSchema), method(RecentSummariesQueryInput, RecentSummariesPageSchema), method(object({ id: string() }), SummaryDetailSchema.nullable()), method(object({ deviceId: number() }), _void(), {
20155
20319
  kind: "mutation",
20156
20320
  auth: "admin"
20157
20321
  }), 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({
@@ -20279,7 +20443,7 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
20279
20443
  }), method(object({
20280
20444
  deviceId: number(),
20281
20445
  trackId: string(),
20282
- mediaKeys: array(string()).min(1)
20446
+ mediaIds: array(number().int()).min(1)
20283
20447
  }), RetrainFrameSelectionSchema, {
20284
20448
  kind: "mutation",
20285
20449
  auth: "admin"
@@ -20347,7 +20511,10 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
20347
20511
  kind: "query",
20348
20512
  auth: "admin"
20349
20513
  }), method(object({
20350
- eventId: string(),
20514
+ /** Which of the three event tables owns the row. */
20515
+ ownerType: EventOwnerTypeSchema,
20516
+ /** The event's rowid in that table (D474: an event id is a number). */
20517
+ eventId: number().int(),
20351
20518
  kind: MediaFileKindEnum.optional(),
20352
20519
  deviceId: number()
20353
20520
  }), array(MediaFileSchema).readonly()), method(object({
@@ -20358,7 +20525,8 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
20358
20525
  trackId: string(),
20359
20526
  deviceId: number()
20360
20527
  }), array(MediaFileInfoSchema).readonly()), method(object({
20361
- eventId: string(),
20528
+ ownerType: EventOwnerTypeSchema,
20529
+ eventId: number().int(),
20362
20530
  deviceId: number()
20363
20531
  }), array(MediaFileInfoSchema).readonly()), method(SearchObjectEventsInput, array(ScoredObjectEventSchema).readonly()), method(object({}), WipeObjectEmbeddingsResultSchema, {
20364
20532
  kind: "mutation",
@@ -24834,8 +25002,8 @@ var IdentitySchema = object({
24834
25002
  id: string(),
24835
25003
  name: string(),
24836
25004
  sampleCount: number().int().nonnegative(),
24837
- coverMediaKey: string().optional(),
24838
- /** Inline base64 of the cover sample's crop, resolved from `coverMediaKey`.
25005
+ coverMediaId: number().int().optional(),
25006
+ /** Inline base64 of the cover sample's crop, resolved from `coverMediaId`.
24839
25007
  * Lets the UI render the person's face avatar instead of a placeholder icon. */
24840
25008
  coverBase64: string().optional()
24841
25009
  });
@@ -24861,8 +25029,8 @@ var IdentitySampleAuditRowSchema = object({
24861
25029
  enrolledAt: number().int(),
24862
25030
  deviceId: number().int().optional(),
24863
25031
  source: _enum(["detected", "photo"]),
24864
- /** The enrolled crop's media key, so the panel can show the evidence. */
24865
- mediaKey: string().optional(),
25032
+ /** The enrolled crop's media row id, so the panel can show the evidence. */
25033
+ mediaId: number().int().optional(),
24866
25034
  /**
24867
25035
  * False = the sample is stamped with a DIFFERENT face model, and a cosine
24868
25036
  * across feature spaces is a well-formed float with no meaning. Every number
@@ -24931,15 +25099,15 @@ var FaceInfoSchema = object({
24931
25099
  */
24932
25100
  cropUrl: string().optional(),
24933
25101
  /** Design B: the face bbox (pixel space) on the key frame — lets a detail
24934
- * view draw the box over the native `keyFrameMediaKey` frame. Absent on
25102
+ * view draw the box over the native `keyFrameMediaId` frame. Absent on
24935
25103
  * legacy rows written before design B. */
24936
25104
  faceBbox: BoundingBoxSchema.optional(),
24937
25105
  /** Design B: MediaStore key of the track's native-resolution key frame.
24938
25106
  * Fetch the native JPEG via the event-media data-plane
24939
- * (`/addon/<addonId>/event-media/<keyFrameMediaKey>`). Absent when the
25107
+ * (`/addon/<addonId>/event-media/m/<keyFrameMediaId>`). Absent when the
24940
25108
  * track produced no key frame (e.g. native/onboard source) — the UI falls
24941
25109
  * back to the inline `base64` face crop. */
24942
- keyFrameMediaKey: string().optional(),
25110
+ keyFrameMediaId: number().int().optional(),
24943
25111
  /** Winning identity-match cosine (0..1) for this face's track, when an
24944
25112
  * identity was auto-confirmed. Lets the UI surface WHY a face was assigned
24945
25113
  * (confidence badge / low-confidence audit). Absent on legacy rows and on
@@ -25008,11 +25176,14 @@ var FaceClusterSchema = object({
25008
25176
  * `data:image/jpeg;base64,…` from a row whose `key` sat right beside it, in a
25009
25177
  * dialog already rendering its key FRAME from the `event-media` plane.
25010
25178
  *
25011
- * `url` is `/addon/<addonId>/event-media/<encoded key>`. The plane resolves a
25012
- * media key directly, so this needed no new plane and no new access decision.
25179
+ * `url` is `/addon/<addonId>/event-media/m/<mediaId>` (D482). The plane
25180
+ * resolves a media row by its own id, so this needed no new plane and no new
25181
+ * access decision.
25013
25182
  */
25014
25183
  var MediaFileLiteSchema$1 = object({
25015
- key: string(),
25184
+ /** The media row's own id — the same address `MediaFileRef.mediaId` carries
25185
+ * (D482). It was the row's composite key, which embedded the owner. */
25186
+ mediaId: number().int(),
25016
25187
  kind: string(),
25017
25188
  url: string(),
25018
25189
  sizeBytes: number(),
@@ -25029,7 +25200,7 @@ method(object({
25029
25200
  * covers inline, ~10 KB of base64 per row, on a query this UI mounts
25030
25201
  * four times and the viewer holds at `staleTime: 30_000`.
25031
25202
  *
25032
- * Nothing loses its avatar: `coverMediaKey` is already on every row and
25203
+ * Nothing loses its avatar: `coverMediaId` is already on every row and
25033
25204
  * the `event-media` plane serves that key `immutable` with an ETag.
25034
25205
  *
25035
25206
  * **This is an INPUT field, so it does not reach the addon until the
@@ -27497,8 +27668,8 @@ var VehicleSchema = object({
27497
27668
  id: string(),
27498
27669
  name: string(),
27499
27670
  sampleCount: number().int().nonnegative(),
27500
- coverMediaKey: string().optional(),
27501
- /** Inline base64 of the cover sample's plate crop, resolved from `coverMediaKey`. */
27671
+ coverMediaId: number().int().optional(),
27672
+ /** Inline base64 of the cover sample's plate crop, resolved from `coverMediaId`. */
27502
27673
  coverBase64: string().optional()
27503
27674
  });
27504
27675
  var VehicleSampleInfoSchema = object({
@@ -27531,7 +27702,7 @@ var PlateInfoSchema = object({
27531
27702
  /** keyFrame parity: the plate bbox (pixel space) on the native key frame. */
27532
27703
  plateBbox: BoundingBoxSchema.optional(),
27533
27704
  /** keyFrame parity: MediaStore key of the track's native-resolution key frame. */
27534
- keyFrameMediaKey: string().optional(),
27705
+ keyFrameMediaId: number().int().optional(),
27535
27706
  base64: string().optional(),
27536
27707
  /**
27537
27708
  * Same crop as a data-plane URL, always present when the plate has a stored
@@ -27552,11 +27723,14 @@ var PlateInfoSchema = object({
27552
27723
  * `data:image/jpeg;base64,…` from a row whose `key` sat right beside it, in a
27553
27724
  * dialog already rendering its key FRAME from the `event-media` plane.
27554
27725
  *
27555
- * `url` is `/addon/<addonId>/event-media/<encoded key>`. The plane resolves a
27556
- * media key directly, so this needed no new plane and no new access decision.
27726
+ * `url` is `/addon/<addonId>/event-media/m/<mediaId>` (D482). The plane
27727
+ * resolves a media row by its own id, so this needed no new plane and no new
27728
+ * access decision.
27557
27729
  */
27558
27730
  var MediaFileLiteSchema = object({
27559
- key: string(),
27731
+ /** The media row's own id — the same address `MediaFileRef.mediaId` carries
27732
+ * (D482). It was the row's composite key, which embedded the owner. */
27733
+ mediaId: number().int(),
27560
27734
  kind: string(),
27561
27735
  url: string(),
27562
27736
  sizeBytes: number(),
@@ -27615,7 +27789,7 @@ method(object({
27615
27789
  }), method(object({
27616
27790
  /** Inline {@link VehicleSchema.coverBase64} on every row. Default
27617
27791
  * `false` — the vehicle twin of `faceGallery.listIdentities`'s
27618
- * option; `coverMediaKey` + the `event-media` plane carry the picture.
27792
+ * option; `coverMediaId` + the `event-media` plane carry the picture.
27619
27793
  * INPUT field: stripped by the hub router until the train ships, which
27620
27794
  * resolves to `false` and is exactly the intended default. */
27621
27795
  includeCrops: boolean().optional() }).optional(), array(VehicleSchema).readonly()), method(object({ name: string().min(1) }), VehicleSchema, {
@@ -28939,7 +29113,14 @@ var SceneReferenceSchema = object({
28939
29113
  modelId: string(),
28940
29114
  condition: SceneConditionSchema,
28941
29115
  capturedAt: number(),
28942
- thumbnailMediaId: string().optional(),
29116
+ /**
29117
+ * The reference thumbnail's media ROW id (D482).
29118
+ *
29119
+ * The name already said `mediaId` while the value was the row's composite
29120
+ * key — a leftover that read as done and was not. It is the row's own id
29121
+ * now, addressed at `/addon/<addonId>/event-media/m/<id>`.
29122
+ */
29123
+ thumbnailMediaId: number().int().optional(),
28943
29124
  /** Whole-frame (downscaled) embedding captured alongside the ROI crop. The
28944
29125
  * anti-view-shift anchor: a bumped camera, a PTZ preset or a re-aim makes the
28945
29126
  * normalized rect frame a different piece of world, and the scene would
@@ -29753,7 +29934,29 @@ var LoggingSettingsPatchSchema = object({
29753
29934
  * disarmed the channels it did not mention would make the Levels page and
29754
29935
  * the Diagnostics page fight over the same value.
29755
29936
  */
29756
- channels: array(LogChannelWindowPatchSchema).readonly().optional()
29937
+ channels: array(LogChannelWindowPatchSchema).readonly().optional(),
29938
+ /**
29939
+ * How many days the analytics OPS LOG is kept — the audit trail of what
29940
+ * retention actually deleted.
29941
+ *
29942
+ * It lives HERE, on the logging document, and not on the analytics addon's
29943
+ * settings form, on the operator's instruction: every other log-ish window in
29944
+ * this system is configured through this one document, and a retention audit
29945
+ * configured somewhere else is a second place to look when the question is
29946
+ * "what happened to my data".
29947
+ *
29948
+ * That placement has a cost worth stating: this document ships in the
29949
+ * framework closure, so this knob needs a published `@camstack/server` while
29950
+ * the four windows beside it (D485) reach a node on `camstack deploy`.
29951
+ *
29952
+ * `retention-model.ts` argued this one must NOT follow a device window,
29953
+ * because the audit trail is the history of the SWEEP and not of the camera.
29954
+ * That argument stands and is untouched — what changes is that 30 days stops
29955
+ * being a constant nobody can reach. `0` keeps it forever. The floor is 1 day
29956
+ * rather than 0-as-delete: an audit log truncated to nothing is precisely the
29957
+ * state in which the next 9.5 GiB leak cannot be explained.
29958
+ */
29959
+ opsLogRetentionDays: number().int().min(0).max(3650).optional()
29757
29960
  });
29758
29961
  /**
29759
29962
  * Which LAYER of the hierarchy is addressed. Absent = the cluster layer.
@@ -29826,6 +30029,14 @@ var LoggingSettingsStateSchema = object({
29826
30029
  channels: array(LogChannelDescriptorSchema).readonly(),
29827
30030
  /** The channels ARMED right now, each with its deadline. */
29828
30031
  activeChannels: array(LogChannelWindowStateSchema).readonly(),
30032
+ /**
30033
+ * The ops-log window in days, as it is in force. `0` = kept forever.
30034
+ *
30035
+ * Reported rather than left to the caller's memory of what it wrote: this is
30036
+ * the value the analytics sweep will actually use, and an operator asking how
30037
+ * long their audit trail lives should not have to infer it from a default.
30038
+ */
30039
+ opsLogRetentionDays: number().int().min(0),
29829
30040
  persisted: boolean()
29830
30041
  });
29831
30042
  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(), {
@@ -30387,7 +30598,7 @@ var StationaryObjectSchema = object({
30387
30598
  /** Enrichment label carried from the source track (identity / plate). */
30388
30599
  label: string().optional(),
30389
30600
  /** Native-resolution key-frame media key for the parked object's best image. */
30390
- keyFrameMediaKey: string().optional()
30601
+ keyFrameMediaId: number().int().optional()
30391
30602
  });
30392
30603
  var CameraOccupancySnapshotSchema = object({
30393
30604
  /** Frame timestamp of the inference result that produced this snapshot. */
@@ -31543,6 +31754,12 @@ Object.freeze({
31543
31754
  addonId: null,
31544
31755
  access: "create"
31545
31756
  },
31757
+ "dataStoreProvider.upsert": {
31758
+ capName: "data-store-provider",
31759
+ capScope: "system",
31760
+ addonId: null,
31761
+ access: "create"
31762
+ },
31546
31763
  "dayNight.getOptions": {
31547
31764
  capName: "day-night",
31548
31765
  capScope: "device",
@@ -33979,6 +34196,12 @@ Object.freeze({
33979
34196
  addonId: null,
33980
34197
  access: "view"
33981
34198
  },
34199
+ "pipelineAnalytics.listRecentSummaries": {
34200
+ capName: "pipeline-analytics",
34201
+ capScope: "device",
34202
+ addonId: null,
34203
+ access: "view"
34204
+ },
33982
34205
  "pipelineAnalytics.listRecentTracks": {
33983
34206
  capName: "pipeline-analytics",
33984
34207
  capScope: "device",
@@ -35407,6 +35630,12 @@ Object.freeze({
35407
35630
  addonId: null,
35408
35631
  access: "create"
35409
35632
  },
35633
+ "settingsStore.upsert": {
35634
+ capName: "settings-store",
35635
+ capScope: "system",
35636
+ addonId: null,
35637
+ access: "create"
35638
+ },
35410
35639
  "smtpProvider.getStatus": {
35411
35640
  capName: "smtp-provider",
35412
35641
  capScope: "system",
@@ -37800,6 +38029,11 @@ Object.freeze({
37800
38029
  form: "single",
37801
38030
  optional: true
37802
38031
  }],
38032
+ "pipelineAnalytics.listRecentSummaries": [{
38033
+ name: "deviceIds",
38034
+ form: "array",
38035
+ optional: false
38036
+ }],
37803
38037
  "pipelineAnalytics.listRecentTracks": [{
37804
38038
  name: "deviceIds",
37805
38039
  form: "array",
@@ -34,7 +34,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
34
34
  var __toCommonJS = (mod) => __hasOwnProp.call(mod, "module.exports") ? mod["module.exports"] : __copyProps(__defProp({}, "__esModule", { value: true }), mod);
35
35
  var __require = /* @__PURE__ */ createRequire(import.meta.url);
36
36
  //#endregion
37
- //#region ../types/dist/event-category-DAXzJeTX.mjs
37
+ //#region ../types/dist/event-category-ZyX6jcse.mjs
38
38
  var EventCategory = /* @__PURE__ */ function(EventCategory) {
39
39
  EventCategory["SystemBoot"] = "system.boot";
40
40
  EventCategory["SystemAddonsReady"] = "system.addons-ready";
@@ -595,7 +595,7 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
595
595
  * a package zone — a newly-appeared stationary object of a package class
596
596
  * that cleared the class / zone / dwell / size gates. Payload:
597
597
  * `PipelineAnalyticsPackageDeliveredPayload` carrying `{ deviceId,
598
- * entryId, className, zoneIds, keyFrameMediaKey?, bbox, timestamp }`.
598
+ * entryId, className, zoneIds, keyFrameMediaId?, bbox, timestamp }`.
599
599
  * Telemetry (D8): the durable record is the `package-events` store row;
600
600
  * this bus topic drives notifier rules + live UI. See
601
601
  * docs/superpowers/specs/2026-07-17-package-zones-design.md §5.1.
@@ -5381,7 +5381,7 @@ var ZodIssueCode = {
5381
5381
  var ZodFirstPartyTypeKind;
5382
5382
  ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
5383
5383
  //#endregion
5384
- //#region ../types/dist/sleep-BnujYGPe.mjs
5384
+ //#region ../types/dist/sleep-DBKu2-U5.mjs
5385
5385
  /**
5386
5386
  * The audio chunk plane's byte format, and the ONE expansion from a coded
5387
5387
  * window to float samples (D455).
@@ -7332,13 +7332,30 @@ new Set([
7332
7332
  "scene",
7333
7333
  "motion",
7334
7334
  "object",
7335
- "audio"
7335
+ "audio",
7336
+ "mosaic"
7336
7337
  ]);
7337
- new Set([
7338
+ /**
7339
+ * The owner types that are event tables, in the order the event-media resolver
7340
+ * should consider them. Exported so a consumer asking "is this key an event?"
7341
+ * does not re-spell the list and drift from it.
7342
+ */
7343
+ var EVENT_OWNER_TYPES = [
7338
7344
  "motion",
7339
7345
  "object",
7340
7346
  "audio"
7341
- ]);
7347
+ ];
7348
+ /**
7349
+ * The same list as a Zod enum, for the cap inputs that must NAME the table
7350
+ * (D482: `getEventMedia` / `listEventMedia` take an owner, and an owner is
7351
+ * `(table, id)`).
7352
+ *
7353
+ * Built FROM {@link EVENT_OWNER_TYPES} rather than re-spelled: a fourth event
7354
+ * table would otherwise be accepted by the codec and refused at the door, with
7355
+ * nothing failing until a caller asked.
7356
+ */
7357
+ var EventOwnerTypeSchema = _enum(EVENT_OWNER_TYPES);
7358
+ new Set(EVENT_OWNER_TYPES);
7342
7359
  var EncodeProfileSchema = object({
7343
7360
  video: object({
7344
7361
  codec: _enum([
@@ -7377,7 +7394,23 @@ var EncodeProfileSchema = object({
7377
7394
  "zerolatency",
7378
7395
  "film",
7379
7396
  "animation"
7380
- ]).optional()
7397
+ ]).optional(),
7398
+ /**
7399
+ * ONE slice per access unit.
7400
+ *
7401
+ * `-tune zerolatency` turns on x264's sliced threads, and a frame then leaves
7402
+ * the encoder as five NAL slices that share one RTP timestamp and carry one
7403
+ * marker bit. A libwebrtc depacketiser sees five frame-starts and one
7404
+ * frame-end per frame: the first pictures render and the video then freezes
7405
+ * for good while the audio, on its own plane, plays on. Measured on this hub
7406
+ * 2026-09-13 against the Echo, and reduced to one slice by this flag alone.
7407
+ *
7408
+ * A NAMED field and not a raw flag, because {@link EgressEncodeSchema} omits
7409
+ * `outputArgs` on purpose: an opaque array is part of the sharing key, so two
7410
+ * consumers meaning the same thing spelled differently would stop sharing one
7411
+ * child. Absent means "whatever the encoder does" — today's behaviour.
7412
+ */
7413
+ singleSlicePerFrame: boolean().optional()
7381
7414
  }),
7382
7415
  audio: union([literal("passthrough"), object({
7383
7416
  codec: _enum([
@@ -7427,7 +7460,7 @@ var BASE_LIVE_EGRESS_PROFILE = {
7427
7460
  audio: "passthrough"
7428
7461
  };
7429
7462
  ({ ...BASE_LIVE_EGRESS_PROFILE }), { ...BASE_LIVE_EGRESS_PROFILE.video };
7430
- ({ ...BASE_LIVE_EGRESS_PROFILE });
7463
+ ({ ...BASE_LIVE_EGRESS_PROFILE }), { ...BASE_LIVE_EGRESS_PROFILE.video };
7431
7464
  /**
7432
7465
  * Deep wiring healthcheck — snapshot of active reachability probes across
7433
7466
  * every declared capability + widget of every installed plugin, on every
@@ -12435,6 +12468,16 @@ method(object({
12435
12468
  filter: QueryFilterSchema.optional(),
12436
12469
  columns: array(string()).readonly().optional()
12437
12470
  }), array(SettingsRecordSchema).readonly()), method(object({
12471
+ namespace: string().optional(),
12472
+ collection: string(),
12473
+ /** Declared columns identifying the slot; must be covered by a UNIQUE
12474
+ * index on the collection. Never empty. */
12475
+ conflict: array(string()).readonly(),
12476
+ record: BulkRecordSchema
12477
+ }), object({
12478
+ /** The id the row HAS: assigned by SQLite on an insert, or the existing
12479
+ * row's own id on an update. */
12480
+ id: union([string(), number()]) }), { kind: "mutation" }), method(object({
12438
12481
  namespace: string().optional(),
12439
12482
  collection: string(),
12440
12483
  record: object({
@@ -12569,6 +12612,14 @@ method(_void(), EngineInfoSchema, { auth: "admin" }), method(object({
12569
12612
  id: union([string(), number()]) }), {
12570
12613
  kind: "mutation",
12571
12614
  auth: "admin"
12615
+ }), method(object({
12616
+ namespace: string().optional(),
12617
+ collection: string(),
12618
+ conflict: array(string()).readonly(),
12619
+ record: BulkRecordSchema
12620
+ }), object({ id: union([string(), number()]) }), {
12621
+ kind: "mutation",
12622
+ auth: "admin"
12572
12623
  }), method(object({
12573
12624
  namespace: string().optional(),
12574
12625
  collection: string(),
@@ -18785,8 +18836,8 @@ var TrackPositionSchema = object({
18785
18836
  var TrackSnapshotSchema = object({
18786
18837
  timestamp: number(),
18787
18838
  position: TrackPositionSchema,
18788
- /** MediaStore key; resolve via `getTrackMedia({ trackId })`. */
18789
- mediaKey: string()
18839
+ /** The snapshot's media row id (D482); resolve via `listTrackMedia({ trackId })`. */
18840
+ mediaId: number().int()
18790
18841
  });
18791
18842
  /**
18792
18843
  * Normalized 0..1 trajectory envelope (min/max over every position bbox,
@@ -19390,14 +19441,14 @@ var ObjectEventSchema = object({
19390
19441
  * pixel-space `bbox` onto a displayed image. Omitted in slim projection. */
19391
19442
  frameWidth: number().optional(),
19392
19443
  frameHeight: number().optional(),
19393
- /** MediaStore key for the crop attached to this event (if any). */
19394
- mediaKey: string().optional(),
19395
- /** Design B: MediaStore key of the track's native-resolution key frame (the
19444
+ /** Media row id of the crop attached to this event (if any) — D482. */
19445
+ mediaId: number().int().optional(),
19446
+ /** Design B: media row id of the track's native-resolution key frame (the
19396
19447
  * best-detection full frame). Resolve via the event-media data-plane
19397
- * (`/addon/<addonId>/event-media/<keyFrameMediaKey>`) for a detail view that
19448
+ * (`/addon/<addonId>/event-media/m/<keyFrameMediaId>`) for a detail view that
19398
19449
  * draws `bbox` over the native frame. Absent on legacy rows / non-decoded
19399
- * sources — consumers fall back to `mediaKey` (the tight crop). */
19400
- keyFrameMediaKey: string().optional(),
19450
+ * sources — consumers fall back to `mediaId` (the tight crop). */
19451
+ keyFrameMediaId: number().int().optional(),
19401
19452
  /** Populated by B5 (recording playback URL for this event). */
19402
19453
  mediaUrl: string().optional(),
19403
19454
  /** The parent track's key-event importance [0,1], propagated to every object
@@ -19447,7 +19498,7 @@ var MediaFileKindEnum = _enum([
19447
19498
  * hub-main's heap on the way past — for an `<img>` that would have cached it.
19448
19499
  *
19449
19500
  * `url` points at the `event-media` data plane
19450
- * (`/addon/<addonId>/event-media/<storedKey>`), which serves the same blob
19501
+ * (`/addon/<addonId>/event-media/m/<mediaId>` — D482), which serves the same blob
19451
19502
  * with an ETag and `Cache-Control: immutable`, honours conditional GETs, can
19452
19503
  * render a `?variant=thumb`, and streams. The hub gate in front of it requires
19453
19504
  * a bearer or the session cookie (`access: 'authenticated'`), so the bytes are
@@ -19455,10 +19506,13 @@ var MediaFileKindEnum = _enum([
19455
19506
  * `data-plane-access.ts` for the rule and the one gap it does not close
19456
19507
  * (per-device scoping).
19457
19508
  *
19458
- * The URL is built from the row's **stored** key, which is not always its
19459
- * published `kind`: a track's face/plate crop is stored as `crop` under
19509
+ * The URL is built from the row's own id, which since D482 says nothing about
19510
+ * the row's owner or kind and that is the point. The published `kind` is not
19511
+ * the stored one (a track's face/plate crop is stored as `crop` under
19460
19512
  * `('face'|'plate', '<prefix>-<trackId>')` and published as
19461
- * `faceCrop`/`plateCrop`. `MediaStore.getByKey` knows only the stored key.
19513
+ * `faceCrop`/`plateCrop`), and under the old composite key the URL had to be
19514
+ * taken from `row.key` verbatim or it 404'd exactly those two rows. An id
19515
+ * cannot be mis-reconstructed, because there is nothing in it to reconstruct.
19462
19516
  *
19463
19517
  * ## `base64` is TRANSITIONAL and is going away
19464
19518
  *
@@ -19471,7 +19525,19 @@ var MediaFileKindEnum = _enum([
19471
19525
  * `analytics-query-facade.ts`; nothing else reads it.
19472
19526
  */
19473
19527
  var MediaFileSchema = object({
19474
- key: string(),
19528
+ /**
19529
+ * The media row's OWN id — the rowid SQLite assigned it (D482).
19530
+ *
19531
+ * It used to be the row's composite key, `<ownerType>:<ownerId>:<fileKind>
19532
+ * [:<timestampMs>]`, which embedded a FOREIGN id. D474 made event ids
19533
+ * per-table rowid aliases, so `object:101314` and `motion:101314` are two
19534
+ * different rows that spell the same number, and a track whose
19535
+ * `bestEventId` was an object event was served a motion event's snapshot —
19536
+ * a night-time thumbnail on an afternoon track, with no error anywhere. A
19537
+ * surrogate id cannot name the wrong row's owner, because it names no owner
19538
+ * at all.
19539
+ */
19540
+ mediaId: number().int(),
19475
19541
  kind: MediaFileKindEnum,
19476
19542
  sizeBytes: number(),
19477
19543
  timestamp: number()
@@ -19579,7 +19645,7 @@ var RetrainTrackSchema = object({
19579
19645
  });
19580
19646
  /** A frame the picker may offer — an index row, no blob was read to produce it. */
19581
19647
  var RetrainFrameCandidateSchema = object({
19582
- mediaKey: string(),
19648
+ mediaId: number().int(),
19583
19649
  kind: MediaFileKindEnum,
19584
19650
  timestamp: number(),
19585
19651
  sizeBytes: number().int(),
@@ -19593,7 +19659,7 @@ var RetrainFrameSchema = object({
19593
19659
  deviceId: number(),
19594
19660
  trackId: string(),
19595
19661
  /** Provenance only. It may already point at nothing — that is expected. */
19596
- sourceMediaKey: string(),
19662
+ sourceMediaId: number().int(),
19597
19663
  sourceKind: MediaFileKindEnum,
19598
19664
  sizeBytes: number().int(),
19599
19665
  width: number().int(),
@@ -19609,7 +19675,7 @@ var RetrainCopyRefusalSchema = _enum([
19609
19675
  var RetrainFrameSelectionSchema = object({
19610
19676
  copied: array(RetrainFrameSchema).readonly(),
19611
19677
  refused: array(object({
19612
- sourceMediaKey: string(),
19678
+ sourceMediaId: number().int(),
19613
19679
  reason: RetrainCopyRefusalSchema
19614
19680
  })).readonly()
19615
19681
  });
@@ -19617,7 +19683,7 @@ var RetrainFrameListSchema = object({
19617
19683
  candidates: array(RetrainFrameCandidateSchema).readonly(),
19618
19684
  copies: array(RetrainFrameSchema).readonly(),
19619
19685
  /** What the page pre-selects — the native key frame when one survives. */
19620
- autoPickMediaKey: string().optional()
19686
+ autoPickMediaId: number().int().optional()
19621
19687
  });
19622
19688
  /** What the operator asked the assist to look for. */
19623
19689
  var RetrainAssistSubjectSchema = discriminatedUnion("kind", [object({
@@ -19712,9 +19778,11 @@ var RecentTracksQueryInput = object({
19712
19778
  });
19713
19779
  /**
19714
19780
  * A Summary (D359): the per-camera session envelope that references tracks.
19715
- * `groupShotKey` is the media key of its group shot (`ownerKind: 'summary'`,
19716
- * served by the event-media plane by key), null until the first frame with a
19717
- * member visible has been materialised.
19781
+ * `groupShotMediaId` is the media ROW id of its group shot (`ownerKind:
19782
+ * 'summary'`, served by the event-media plane at `/m/<id>`), null until the
19783
+ * first frame with a member visible has been materialised (D482 — it was the
19784
+ * row's composite key, which embedded the owner and could name another table's
19785
+ * row once event ids became per-table rowids).
19718
19786
  */
19719
19787
  var SummarySchema = object({
19720
19788
  id: string(),
@@ -19723,19 +19791,115 @@ var SummarySchema = object({
19723
19791
  lastActiveAt: number(),
19724
19792
  sealedAt: number().nullable(),
19725
19793
  memberCount: number().int().nonnegative(),
19726
- groupShotKey: string().nullable()
19794
+ groupShotMediaId: number().int().nullable()
19727
19795
  });
19728
19796
  var SummariesQueryInput = object({
19729
19797
  deviceIds: array(number()).min(1),
19730
19798
  since: number().optional(),
19731
19799
  until: number().optional(),
19732
- limit: number().int().min(1).max(200).default(50)
19800
+ limit: number().int().min(1).max(200).default(50),
19801
+ /** The same member-wise filter {@link listRecentSummaries} takes — one
19802
+ * meaning of "dog" on every summary surface. */
19803
+ classes: array(string().min(1).max(60)).max(40).optional()
19733
19804
  });
19734
- var SummariesPageSchema = object({ summaries: array(SummarySchema).readonly() });
19735
19805
  var SummaryDetailSchema = object({
19736
19806
  summary: SummarySchema,
19737
- /** Member track ids, in absorption order. */
19738
- trackIds: array(string()).readonly()
19807
+ /** Members in absorption order, oldest join first. */
19808
+ members: array(object({
19809
+ trackId: string(),
19810
+ /**
19811
+ * The track's class at the time it JOINED, or `null` when it was unresolved
19812
+ * and the track no longer exists to fill it.
19813
+ *
19814
+ * The join, not the latest opinion: class voting can re-decide a track's
19815
+ * class afterwards, and a group's composition is the history of who came
19816
+ * together. A consumer counts these to badge a thumbnail — "two people and a
19817
+ * dog" — rather than being handed a second, denormalised tally that would
19818
+ * drift from the members it claims to describe.
19819
+ */
19820
+ className: string().nullable(),
19821
+ /** `primary` is the one member that carries the group's identity. */
19822
+ role: _enum([
19823
+ "primary",
19824
+ "sibling",
19825
+ "child"
19826
+ ]).nullable(),
19827
+ joinedAt: number(),
19828
+ /** Tier 1 — the sub-class (`dog`, `van`), resolved from the member's track
19829
+ * at read time. Absent when nothing resolved, never an empty string. */
19830
+ label: string().optional(),
19831
+ /** Tier 2 — the instance: a person's name, a plate. Absent when the pipeline
19832
+ * recognised nobody, and absent for a member whose track has been pruned —
19833
+ * a thumbnail that names the wrong person is worse than one naming nobody. */
19834
+ subLabel: string().optional()
19835
+ })).readonly()
19836
+ });
19837
+ /**
19838
+ * What a LIST of groups carries: the envelope plus what it is MADE OF.
19839
+ *
19840
+ * Coarse on purpose — the operator's rule is "only the rough data on the list,
19841
+ * we extend when we notice we need more". Enough to draw the card ("two people
19842
+ * and a dog") and no more. The MEMBERS, their names and the per-member links
19843
+ * are on {@link getSummary}: shipping every member of every group so a client
19844
+ * can count them turns a page of two hundred groups into a thousand records to
19845
+ * draw two hundred badges.
19846
+ */
19847
+ var SummaryListItemSchema = object({
19848
+ summary: SummarySchema,
19849
+ /** Class counts, most numerous first; `className: null` is a member whose
19850
+ * class never resolved, counted so the counts add up to `memberCount`. */
19851
+ classes: array(object({
19852
+ className: string().nullable(),
19853
+ count: number().int().positive()
19854
+ })).readonly()
19855
+ });
19856
+ var SummariesPageSchema = object({ summaries: array(SummaryListItemSchema).readonly() });
19857
+ /**
19858
+ * The paged feed, deliberately the SAME shape as {@link RecentTracksQueryInput}.
19859
+ *
19860
+ * The reel on the cameras page and the Events gallery both ride a cursor, so a
19861
+ * summaries feed that could only answer "the last N for these cameras"
19862
+ * (`listSummaries`) would make groups available in the timeline and nowhere
19863
+ * else. Two feeds with different ordering contracts would be two ideas of what
19864
+ * "newest" means, on one screen.
19865
+ */
19866
+ var RecentSummariesQueryInput = object({
19867
+ /** Devices to merge. An empty array yields an empty page. */
19868
+ deviceIds: array(number()),
19869
+ /** Window lower bound on `lastActiveAt` (inclusive). */
19870
+ since: number().optional(),
19871
+ /** Window upper bound on `lastActiveAt` (inclusive). */
19872
+ until: number().optional(),
19873
+ limit: number().int().min(1).max(500).default(100),
19874
+ /** Opaque continuation cursor from a previous page's `nextCursor`. */
19875
+ cursor: string().optional(),
19876
+ /**
19877
+ * Restrict to these classes — THE SAME FIELD `listRecentTracks` takes, and
19878
+ * deliberately the same name: the events filter tree emits one list of ticked
19879
+ * taxonomy nodes, and a summaries feed that called it something else would
19880
+ * make the operator's one filter component produce two shapes.
19881
+ *
19882
+ * A question about the MEMBERS: a group matches when ANY of them does. "Show
19883
+ * me the arrivals with a dog" has to return the group of four people who had
19884
+ * one with them; a filter on the group's own fields could only ever answer
19885
+ * about its primary.
19886
+ *
19887
+ * Matched against all THREE tiers of a member — the class (`animal`), the
19888
+ * sub-class (`dog`) and the instance (a name, a plate) — because which tier a
19889
+ * ticked node lives on is the taxonomy's business, not the caller's. `dog` is
19890
+ * an event kind in the tree and a tier-1 label on an `animal` track; a filter
19891
+ * that read only the class would answer "animal" and never "dog".
19892
+ *
19893
+ * ABSENT or EMPTY means no filter — absent is not a selection of none.
19894
+ */
19895
+ classes: array(string().min(1).max(60)).max(40).optional()
19896
+ });
19897
+ var RecentSummariesPageSchema = object({
19898
+ /** Ordered by (`lastActiveAt` DESC, id DESC). Same light item as
19899
+ * {@link listSummaries} — one list shape, so a card renders the same
19900
+ * whichever feed drew it. */
19901
+ summaries: array(SummaryListItemSchema).readonly(),
19902
+ nextCursor: string().nullable()
19739
19903
  });
19740
19904
  var RecentTracksPageSchema = object({
19741
19905
  /** Merged page, ordered by (`lastSeen` DESC, `trackId` DESC). */
@@ -20149,7 +20313,7 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
20149
20313
  classes: array(string()).optional(),
20150
20314
  /** See {@link ExcludeSourcesDoc}. */
20151
20315
  excludeSources: array(TrackSourceSchema).optional()
20152
- }), array(TrackSchema).readonly()), method(RecentTracksQueryInput, RecentTracksPageSchema), method(SummariesQueryInput, SummariesPageSchema), method(object({ id: string() }), SummaryDetailSchema.nullable()), method(object({ deviceId: number() }), _void(), {
20316
+ }), array(TrackSchema).readonly()), method(RecentTracksQueryInput, RecentTracksPageSchema), method(SummariesQueryInput, SummariesPageSchema), method(RecentSummariesQueryInput, RecentSummariesPageSchema), method(object({ id: string() }), SummaryDetailSchema.nullable()), method(object({ deviceId: number() }), _void(), {
20153
20317
  kind: "mutation",
20154
20318
  auth: "admin"
20155
20319
  }), 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({
@@ -20277,7 +20441,7 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
20277
20441
  }), method(object({
20278
20442
  deviceId: number(),
20279
20443
  trackId: string(),
20280
- mediaKeys: array(string()).min(1)
20444
+ mediaIds: array(number().int()).min(1)
20281
20445
  }), RetrainFrameSelectionSchema, {
20282
20446
  kind: "mutation",
20283
20447
  auth: "admin"
@@ -20345,7 +20509,10 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
20345
20509
  kind: "query",
20346
20510
  auth: "admin"
20347
20511
  }), method(object({
20348
- eventId: string(),
20512
+ /** Which of the three event tables owns the row. */
20513
+ ownerType: EventOwnerTypeSchema,
20514
+ /** The event's rowid in that table (D474: an event id is a number). */
20515
+ eventId: number().int(),
20349
20516
  kind: MediaFileKindEnum.optional(),
20350
20517
  deviceId: number()
20351
20518
  }), array(MediaFileSchema).readonly()), method(object({
@@ -20356,7 +20523,8 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
20356
20523
  trackId: string(),
20357
20524
  deviceId: number()
20358
20525
  }), array(MediaFileInfoSchema).readonly()), method(object({
20359
- eventId: string(),
20526
+ ownerType: EventOwnerTypeSchema,
20527
+ eventId: number().int(),
20360
20528
  deviceId: number()
20361
20529
  }), array(MediaFileInfoSchema).readonly()), method(SearchObjectEventsInput, array(ScoredObjectEventSchema).readonly()), method(object({}), WipeObjectEmbeddingsResultSchema, {
20362
20530
  kind: "mutation",
@@ -24832,8 +25000,8 @@ var IdentitySchema = object({
24832
25000
  id: string(),
24833
25001
  name: string(),
24834
25002
  sampleCount: number().int().nonnegative(),
24835
- coverMediaKey: string().optional(),
24836
- /** Inline base64 of the cover sample's crop, resolved from `coverMediaKey`.
25003
+ coverMediaId: number().int().optional(),
25004
+ /** Inline base64 of the cover sample's crop, resolved from `coverMediaId`.
24837
25005
  * Lets the UI render the person's face avatar instead of a placeholder icon. */
24838
25006
  coverBase64: string().optional()
24839
25007
  });
@@ -24859,8 +25027,8 @@ var IdentitySampleAuditRowSchema = object({
24859
25027
  enrolledAt: number().int(),
24860
25028
  deviceId: number().int().optional(),
24861
25029
  source: _enum(["detected", "photo"]),
24862
- /** The enrolled crop's media key, so the panel can show the evidence. */
24863
- mediaKey: string().optional(),
25030
+ /** The enrolled crop's media row id, so the panel can show the evidence. */
25031
+ mediaId: number().int().optional(),
24864
25032
  /**
24865
25033
  * False = the sample is stamped with a DIFFERENT face model, and a cosine
24866
25034
  * across feature spaces is a well-formed float with no meaning. Every number
@@ -24929,15 +25097,15 @@ var FaceInfoSchema = object({
24929
25097
  */
24930
25098
  cropUrl: string().optional(),
24931
25099
  /** Design B: the face bbox (pixel space) on the key frame — lets a detail
24932
- * view draw the box over the native `keyFrameMediaKey` frame. Absent on
25100
+ * view draw the box over the native `keyFrameMediaId` frame. Absent on
24933
25101
  * legacy rows written before design B. */
24934
25102
  faceBbox: BoundingBoxSchema.optional(),
24935
25103
  /** Design B: MediaStore key of the track's native-resolution key frame.
24936
25104
  * Fetch the native JPEG via the event-media data-plane
24937
- * (`/addon/<addonId>/event-media/<keyFrameMediaKey>`). Absent when the
25105
+ * (`/addon/<addonId>/event-media/m/<keyFrameMediaId>`). Absent when the
24938
25106
  * track produced no key frame (e.g. native/onboard source) — the UI falls
24939
25107
  * back to the inline `base64` face crop. */
24940
- keyFrameMediaKey: string().optional(),
25108
+ keyFrameMediaId: number().int().optional(),
24941
25109
  /** Winning identity-match cosine (0..1) for this face's track, when an
24942
25110
  * identity was auto-confirmed. Lets the UI surface WHY a face was assigned
24943
25111
  * (confidence badge / low-confidence audit). Absent on legacy rows and on
@@ -25006,11 +25174,14 @@ var FaceClusterSchema = object({
25006
25174
  * `data:image/jpeg;base64,…` from a row whose `key` sat right beside it, in a
25007
25175
  * dialog already rendering its key FRAME from the `event-media` plane.
25008
25176
  *
25009
- * `url` is `/addon/<addonId>/event-media/<encoded key>`. The plane resolves a
25010
- * media key directly, so this needed no new plane and no new access decision.
25177
+ * `url` is `/addon/<addonId>/event-media/m/<mediaId>` (D482). The plane
25178
+ * resolves a media row by its own id, so this needed no new plane and no new
25179
+ * access decision.
25011
25180
  */
25012
25181
  var MediaFileLiteSchema$1 = object({
25013
- key: string(),
25182
+ /** The media row's own id — the same address `MediaFileRef.mediaId` carries
25183
+ * (D482). It was the row's composite key, which embedded the owner. */
25184
+ mediaId: number().int(),
25014
25185
  kind: string(),
25015
25186
  url: string(),
25016
25187
  sizeBytes: number(),
@@ -25027,7 +25198,7 @@ method(object({
25027
25198
  * covers inline, ~10 KB of base64 per row, on a query this UI mounts
25028
25199
  * four times and the viewer holds at `staleTime: 30_000`.
25029
25200
  *
25030
- * Nothing loses its avatar: `coverMediaKey` is already on every row and
25201
+ * Nothing loses its avatar: `coverMediaId` is already on every row and
25031
25202
  * the `event-media` plane serves that key `immutable` with an ETag.
25032
25203
  *
25033
25204
  * **This is an INPUT field, so it does not reach the addon until the
@@ -27495,8 +27666,8 @@ var VehicleSchema = object({
27495
27666
  id: string(),
27496
27667
  name: string(),
27497
27668
  sampleCount: number().int().nonnegative(),
27498
- coverMediaKey: string().optional(),
27499
- /** Inline base64 of the cover sample's plate crop, resolved from `coverMediaKey`. */
27669
+ coverMediaId: number().int().optional(),
27670
+ /** Inline base64 of the cover sample's plate crop, resolved from `coverMediaId`. */
27500
27671
  coverBase64: string().optional()
27501
27672
  });
27502
27673
  var VehicleSampleInfoSchema = object({
@@ -27529,7 +27700,7 @@ var PlateInfoSchema = object({
27529
27700
  /** keyFrame parity: the plate bbox (pixel space) on the native key frame. */
27530
27701
  plateBbox: BoundingBoxSchema.optional(),
27531
27702
  /** keyFrame parity: MediaStore key of the track's native-resolution key frame. */
27532
- keyFrameMediaKey: string().optional(),
27703
+ keyFrameMediaId: number().int().optional(),
27533
27704
  base64: string().optional(),
27534
27705
  /**
27535
27706
  * Same crop as a data-plane URL, always present when the plate has a stored
@@ -27550,11 +27721,14 @@ var PlateInfoSchema = object({
27550
27721
  * `data:image/jpeg;base64,…` from a row whose `key` sat right beside it, in a
27551
27722
  * dialog already rendering its key FRAME from the `event-media` plane.
27552
27723
  *
27553
- * `url` is `/addon/<addonId>/event-media/<encoded key>`. The plane resolves a
27554
- * media key directly, so this needed no new plane and no new access decision.
27724
+ * `url` is `/addon/<addonId>/event-media/m/<mediaId>` (D482). The plane
27725
+ * resolves a media row by its own id, so this needed no new plane and no new
27726
+ * access decision.
27555
27727
  */
27556
27728
  var MediaFileLiteSchema = object({
27557
- key: string(),
27729
+ /** The media row's own id — the same address `MediaFileRef.mediaId` carries
27730
+ * (D482). It was the row's composite key, which embedded the owner. */
27731
+ mediaId: number().int(),
27558
27732
  kind: string(),
27559
27733
  url: string(),
27560
27734
  sizeBytes: number(),
@@ -27613,7 +27787,7 @@ method(object({
27613
27787
  }), method(object({
27614
27788
  /** Inline {@link VehicleSchema.coverBase64} on every row. Default
27615
27789
  * `false` — the vehicle twin of `faceGallery.listIdentities`'s
27616
- * option; `coverMediaKey` + the `event-media` plane carry the picture.
27790
+ * option; `coverMediaId` + the `event-media` plane carry the picture.
27617
27791
  * INPUT field: stripped by the hub router until the train ships, which
27618
27792
  * resolves to `false` and is exactly the intended default. */
27619
27793
  includeCrops: boolean().optional() }).optional(), array(VehicleSchema).readonly()), method(object({ name: string().min(1) }), VehicleSchema, {
@@ -28937,7 +29111,14 @@ var SceneReferenceSchema = object({
28937
29111
  modelId: string(),
28938
29112
  condition: SceneConditionSchema,
28939
29113
  capturedAt: number(),
28940
- thumbnailMediaId: string().optional(),
29114
+ /**
29115
+ * The reference thumbnail's media ROW id (D482).
29116
+ *
29117
+ * The name already said `mediaId` while the value was the row's composite
29118
+ * key — a leftover that read as done and was not. It is the row's own id
29119
+ * now, addressed at `/addon/<addonId>/event-media/m/<id>`.
29120
+ */
29121
+ thumbnailMediaId: number().int().optional(),
28941
29122
  /** Whole-frame (downscaled) embedding captured alongside the ROI crop. The
28942
29123
  * anti-view-shift anchor: a bumped camera, a PTZ preset or a re-aim makes the
28943
29124
  * normalized rect frame a different piece of world, and the scene would
@@ -29751,7 +29932,29 @@ var LoggingSettingsPatchSchema = object({
29751
29932
  * disarmed the channels it did not mention would make the Levels page and
29752
29933
  * the Diagnostics page fight over the same value.
29753
29934
  */
29754
- channels: array(LogChannelWindowPatchSchema).readonly().optional()
29935
+ channels: array(LogChannelWindowPatchSchema).readonly().optional(),
29936
+ /**
29937
+ * How many days the analytics OPS LOG is kept — the audit trail of what
29938
+ * retention actually deleted.
29939
+ *
29940
+ * It lives HERE, on the logging document, and not on the analytics addon's
29941
+ * settings form, on the operator's instruction: every other log-ish window in
29942
+ * this system is configured through this one document, and a retention audit
29943
+ * configured somewhere else is a second place to look when the question is
29944
+ * "what happened to my data".
29945
+ *
29946
+ * That placement has a cost worth stating: this document ships in the
29947
+ * framework closure, so this knob needs a published `@camstack/server` while
29948
+ * the four windows beside it (D485) reach a node on `camstack deploy`.
29949
+ *
29950
+ * `retention-model.ts` argued this one must NOT follow a device window,
29951
+ * because the audit trail is the history of the SWEEP and not of the camera.
29952
+ * That argument stands and is untouched — what changes is that 30 days stops
29953
+ * being a constant nobody can reach. `0` keeps it forever. The floor is 1 day
29954
+ * rather than 0-as-delete: an audit log truncated to nothing is precisely the
29955
+ * state in which the next 9.5 GiB leak cannot be explained.
29956
+ */
29957
+ opsLogRetentionDays: number().int().min(0).max(3650).optional()
29755
29958
  });
29756
29959
  /**
29757
29960
  * Which LAYER of the hierarchy is addressed. Absent = the cluster layer.
@@ -29824,6 +30027,14 @@ var LoggingSettingsStateSchema = object({
29824
30027
  channels: array(LogChannelDescriptorSchema).readonly(),
29825
30028
  /** The channels ARMED right now, each with its deadline. */
29826
30029
  activeChannels: array(LogChannelWindowStateSchema).readonly(),
30030
+ /**
30031
+ * The ops-log window in days, as it is in force. `0` = kept forever.
30032
+ *
30033
+ * Reported rather than left to the caller's memory of what it wrote: this is
30034
+ * the value the analytics sweep will actually use, and an operator asking how
30035
+ * long their audit trail lives should not have to infer it from a default.
30036
+ */
30037
+ opsLogRetentionDays: number().int().min(0),
29827
30038
  persisted: boolean()
29828
30039
  });
29829
30040
  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(), {
@@ -30385,7 +30596,7 @@ var StationaryObjectSchema = object({
30385
30596
  /** Enrichment label carried from the source track (identity / plate). */
30386
30597
  label: string().optional(),
30387
30598
  /** Native-resolution key-frame media key for the parked object's best image. */
30388
- keyFrameMediaKey: string().optional()
30599
+ keyFrameMediaId: number().int().optional()
30389
30600
  });
30390
30601
  var CameraOccupancySnapshotSchema = object({
30391
30602
  /** Frame timestamp of the inference result that produced this snapshot. */
@@ -31541,6 +31752,12 @@ Object.freeze({
31541
31752
  addonId: null,
31542
31753
  access: "create"
31543
31754
  },
31755
+ "dataStoreProvider.upsert": {
31756
+ capName: "data-store-provider",
31757
+ capScope: "system",
31758
+ addonId: null,
31759
+ access: "create"
31760
+ },
31544
31761
  "dayNight.getOptions": {
31545
31762
  capName: "day-night",
31546
31763
  capScope: "device",
@@ -33977,6 +34194,12 @@ Object.freeze({
33977
34194
  addonId: null,
33978
34195
  access: "view"
33979
34196
  },
34197
+ "pipelineAnalytics.listRecentSummaries": {
34198
+ capName: "pipeline-analytics",
34199
+ capScope: "device",
34200
+ addonId: null,
34201
+ access: "view"
34202
+ },
33980
34203
  "pipelineAnalytics.listRecentTracks": {
33981
34204
  capName: "pipeline-analytics",
33982
34205
  capScope: "device",
@@ -35405,6 +35628,12 @@ Object.freeze({
35405
35628
  addonId: null,
35406
35629
  access: "create"
35407
35630
  },
35631
+ "settingsStore.upsert": {
35632
+ capName: "settings-store",
35633
+ capScope: "system",
35634
+ addonId: null,
35635
+ access: "create"
35636
+ },
35408
35637
  "smtpProvider.getStatus": {
35409
35638
  capName: "smtp-provider",
35410
35639
  capScope: "system",
@@ -37798,6 +38027,11 @@ Object.freeze({
37798
38027
  form: "single",
37799
38028
  optional: true
37800
38029
  }],
38030
+ "pipelineAnalytics.listRecentSummaries": [{
38031
+ name: "deviceIds",
38032
+ form: "array",
38033
+ optional: false
38034
+ }],
37801
38035
  "pipelineAnalytics.listRecentTracks": [{
37802
38036
  name: "deviceIds",
37803
38037
  form: "array",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/addon-smtp-nodemailer",
3
- "version": "1.2.98",
3
+ "version": "1.2.100",
4
4
  "description": "SMTP email provider addon for CamStack — wraps `nodemailer` and registers a `smtp-provider` cap collection entry. Used by magic-link login + notifier addons.",
5
5
  "keywords": [
6
6
  "camstack",