camstack 1.2.144 → 1.2.146

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.
@@ -23633,9 +23633,9 @@ var require_zod = __commonJS({
23633
23633
  }
23634
23634
  });
23635
23635
 
23636
- // ../system/dist/dist-DdRxWA7g.js
23637
- var require_dist_DdRxWA7g = __commonJS({
23638
- "../system/dist/dist-DdRxWA7g.js"(exports) {
23636
+ // ../system/dist/dist-DUSfUAgz.js
23637
+ var require_dist_DUSfUAgz = __commonJS({
23638
+ "../system/dist/dist-DUSfUAgz.js"(exports) {
23639
23639
  "use strict";
23640
23640
  var zod = require_zod();
23641
23641
  var EventCategory = /* @__PURE__ */ (function(EventCategory2) {
@@ -25845,6 +25845,13 @@ var require_dist_DdRxWA7g = __commonJS({
25845
25845
  if (typeof err === "string") return err;
25846
25846
  return String(err);
25847
25847
  }
25848
+ var EVENT_OWNER_TYPES = [
25849
+ "motion",
25850
+ "object",
25851
+ "audio"
25852
+ ];
25853
+ var EventOwnerTypeSchema = zod.z.enum(EVENT_OWNER_TYPES);
25854
+ new Set(EVENT_OWNER_TYPES);
25848
25855
  var VideoEncodeSchema = zod.z.object({
25849
25856
  codec: zod.z.enum([
25850
25857
  "h264",
@@ -25882,7 +25889,23 @@ var require_dist_DdRxWA7g = __commonJS({
25882
25889
  "zerolatency",
25883
25890
  "film",
25884
25891
  "animation"
25885
- ]).optional()
25892
+ ]).optional(),
25893
+ /**
25894
+ * ONE slice per access unit.
25895
+ *
25896
+ * `-tune zerolatency` turns on x264's sliced threads, and a frame then leaves
25897
+ * the encoder as five NAL slices that share one RTP timestamp and carry one
25898
+ * marker bit. A libwebrtc depacketiser sees five frame-starts and one
25899
+ * frame-end per frame: the first pictures render and the video then freezes
25900
+ * for good while the audio, on its own plane, plays on. Measured on this hub
25901
+ * 2026-09-13 against the Echo, and reduced to one slice by this flag alone.
25902
+ *
25903
+ * A NAMED field and not a raw flag, because {@link EgressEncodeSchema} omits
25904
+ * `outputArgs` on purpose: an opaque array is part of the sharing key, so two
25905
+ * consumers meaning the same thing spelled differently would stop sharing one
25906
+ * child. Absent means "whatever the encoder does" — today's behaviour.
25907
+ */
25908
+ singleSlicePerFrame: zod.z.boolean().optional()
25886
25909
  });
25887
25910
  var AudioEncodeSchema = zod.z.union([zod.z.literal("passthrough"), zod.z.object({
25888
25911
  codec: zod.z.enum([
@@ -25930,7 +25953,7 @@ var require_dist_DdRxWA7g = __commonJS({
25930
25953
  audio: "passthrough"
25931
25954
  };
25932
25955
  ({ ...BASE_LIVE_EGRESS_PROFILE }, { ...BASE_LIVE_EGRESS_PROFILE.video });
25933
- ({ ...BASE_LIVE_EGRESS_PROFILE });
25956
+ ({ ...BASE_LIVE_EGRESS_PROFILE }, { ...BASE_LIVE_EGRESS_PROFILE.video });
25934
25957
  var wiringProbeKindSchema = zod.z.enum([
25935
25958
  "singleton",
25936
25959
  "device",
@@ -30739,6 +30762,60 @@ var require_dist_DdRxWA7g = __commonJS({
30739
30762
  filter: QueryFilterSchema.optional(),
30740
30763
  columns: zod.z.array(zod.z.string()).readonly().optional()
30741
30764
  }), zod.z.array(SettingsRecordSchema).readonly()),
30765
+ /**
30766
+ * Make a SLOT hold this row — insert it, or update whatever already
30767
+ * occupies the slot — and answer with the id the row HAS.
30768
+ *
30769
+ * ## Why the store needed this
30770
+ *
30771
+ * {@link set} is already an upsert, but its slot is the PRIMARY KEY: the
30772
+ * caller has to know the id to address the row. That is exactly what a
30773
+ * collection keyed by an `INTEGER` rowid alias cannot do — SQLite assigns
30774
+ * the id, so a writer whose uniqueness rule is "one row per
30775
+ * `(ownerKind, ownerId, kind, slot)`" has no id to name and no way to
30776
+ * express the rule. {@link insert} can express it (a UNIQUE index
30777
+ * arbitrates) but only by THROWING at the loser of a race, and the loser
30778
+ * here is a legitimate re-capture, not an error.
30779
+ *
30780
+ * Getting there without this method means read-then-write: query the slot,
30781
+ * then `insert` or `update`. Two statements instead of one, a race between
30782
+ * them, and a recovery path that has to recognise a UNIQUE violation by its
30783
+ * MESSAGE — across a process boundary, because the store lives behind an
30784
+ * RPC door. A string match would be the whole gate, and a store that
30785
+ * rephrased its error would lose the row silently. One statement has no
30786
+ * such gate (D482).
30787
+ *
30788
+ * ## The contract
30789
+ *
30790
+ * `conflict` names the DECLARED columns that identify the slot. They must
30791
+ * be covered by a UNIQUE index on the collection — SQLite resolves an
30792
+ * `ON CONFLICT` target against its indexes and REFUSES the statement when
30793
+ * none matches, so a wrong list is a loud error on the first write, never a
30794
+ * silently duplicated row. An empty list is refused rather than passed on:
30795
+ * `ON CONFLICT()` is not valid SQL, and the intent it would most likely
30796
+ * encode ("no slot, just insert") is {@link insert}.
30797
+ *
30798
+ * Row shape is {@link insert}'s: `record.id` is used when the collection
30799
+ * needs a supplied key and IGNORED when the primary key is an `INTEGER`
30800
+ * rowid alias — exactly as `insert` and `insertMany` already treat it.
30801
+ *
30802
+ * Returns the id either way: the one SQLite assigned on an insert, or the
30803
+ * one the row it updated already had. A caller cannot tell which happened,
30804
+ * and deliberately — every caller wants the slot's id, and one that needed
30805
+ * to distinguish creation from replacement would have to read first anyway.
30806
+ */
30807
+ upsert: method(zod.z.object({
30808
+ namespace: zod.z.string().optional(),
30809
+ collection: zod.z.string(),
30810
+ /** Declared columns identifying the slot; must be covered by a UNIQUE
30811
+ * index on the collection. Never empty. */
30812
+ conflict: zod.z.array(zod.z.string()).readonly(),
30813
+ record: BulkRecordSchema
30814
+ }), zod.z.object({
30815
+ /** The id the row HAS: assigned by SQLite on an insert, or the existing
30816
+ * row's own id on an update. */
30817
+ id: zod.z.union([zod.z.string(), zod.z.number()])
30818
+ }), { kind: "mutation" }),
30742
30819
  /** Insert a new record. */
30743
30820
  insert: method(zod.z.object({
30744
30821
  namespace: zod.z.string().optional(),
@@ -30982,6 +31059,20 @@ var require_dist_DdRxWA7g = __commonJS({
30982
31059
  kind: "mutation",
30983
31060
  auth: "admin"
30984
31061
  }),
31062
+ /**
31063
+ * Make a slot hold this row, and answer with the id the row HAS. The
31064
+ * engine half of `settings-store.upsert` — read that docblock for why the
31065
+ * store needed a slot that is not the primary key (D482).
31066
+ */
31067
+ upsert: method(zod.z.object({
31068
+ namespace: zod.z.string().optional(),
31069
+ collection: zod.z.string(),
31070
+ conflict: zod.z.array(zod.z.string()).readonly(),
31071
+ record: BulkRecordSchema
31072
+ }), zod.z.object({ id: zod.z.union([zod.z.string(), zod.z.number()]) }), {
31073
+ kind: "mutation",
31074
+ auth: "admin"
31075
+ }),
30985
31076
  /** Insert many records in ONE transaction. All or nothing. */
30986
31077
  insertMany: method(zod.z.object({
30987
31078
  namespace: zod.z.string().optional(),
@@ -37311,8 +37402,8 @@ var require_dist_DdRxWA7g = __commonJS({
37311
37402
  var TrackSnapshotSchema = zod.z.object({
37312
37403
  timestamp: zod.z.number(),
37313
37404
  position: TrackPositionSchema,
37314
- /** MediaStore key; resolve via `getTrackMedia({ trackId })`. */
37315
- mediaKey: zod.z.string()
37405
+ /** The snapshot's media row id (D482); resolve via `listTrackMedia({ trackId })`. */
37406
+ mediaId: zod.z.number().int()
37316
37407
  });
37317
37408
  var TrackEnvelopeSchema = zod.z.object({
37318
37409
  minX: zod.z.number(),
@@ -37751,14 +37842,14 @@ var require_dist_DdRxWA7g = __commonJS({
37751
37842
  * pixel-space `bbox` onto a displayed image. Omitted in slim projection. */
37752
37843
  frameWidth: zod.z.number().optional(),
37753
37844
  frameHeight: zod.z.number().optional(),
37754
- /** MediaStore key for the crop attached to this event (if any). */
37755
- mediaKey: zod.z.string().optional(),
37756
- /** Design B: MediaStore key of the track's native-resolution key frame (the
37845
+ /** Media row id of the crop attached to this event (if any) — D482. */
37846
+ mediaId: zod.z.number().int().optional(),
37847
+ /** Design B: media row id of the track's native-resolution key frame (the
37757
37848
  * best-detection full frame). Resolve via the event-media data-plane
37758
- * (`/addon/<addonId>/event-media/<keyFrameMediaKey>`) for a detail view that
37849
+ * (`/addon/<addonId>/event-media/m/<keyFrameMediaId>`) for a detail view that
37759
37850
  * draws `bbox` over the native frame. Absent on legacy rows / non-decoded
37760
- * sources — consumers fall back to `mediaKey` (the tight crop). */
37761
- keyFrameMediaKey: zod.z.string().optional(),
37851
+ * sources — consumers fall back to `mediaId` (the tight crop). */
37852
+ keyFrameMediaId: zod.z.number().int().optional(),
37762
37853
  /** Populated by B5 (recording playback URL for this event). */
37763
37854
  mediaUrl: zod.z.string().optional(),
37764
37855
  /** The parent track's key-event importance [0,1], propagated to every object
@@ -37795,7 +37886,19 @@ var require_dist_DdRxWA7g = __commonJS({
37795
37886
  "sceneFrame"
37796
37887
  ]);
37797
37888
  var MediaFileSchema = zod.z.object({
37798
- key: zod.z.string(),
37889
+ /**
37890
+ * The media row's OWN id — the rowid SQLite assigned it (D482).
37891
+ *
37892
+ * It used to be the row's composite key, `<ownerType>:<ownerId>:<fileKind>
37893
+ * [:<timestampMs>]`, which embedded a FOREIGN id. D474 made event ids
37894
+ * per-table rowid aliases, so `object:101314` and `motion:101314` are two
37895
+ * different rows that spell the same number, and a track whose
37896
+ * `bestEventId` was an object event was served a motion event's snapshot —
37897
+ * a night-time thumbnail on an afternoon track, with no error anywhere. A
37898
+ * surrogate id cannot name the wrong row's owner, because it names no owner
37899
+ * at all.
37900
+ */
37901
+ mediaId: zod.z.number().int(),
37799
37902
  kind: MediaFileKindEnum,
37800
37903
  sizeBytes: zod.z.number(),
37801
37904
  timestamp: zod.z.number()
@@ -37862,7 +37965,7 @@ var require_dist_DdRxWA7g = __commonJS({
37862
37965
  annotationCount: zod.z.number().int()
37863
37966
  });
37864
37967
  var RetrainFrameCandidateSchema = zod.z.object({
37865
- mediaKey: zod.z.string(),
37968
+ mediaId: zod.z.number().int(),
37866
37969
  kind: MediaFileKindEnum,
37867
37970
  timestamp: zod.z.number(),
37868
37971
  sizeBytes: zod.z.number().int(),
@@ -37875,7 +37978,7 @@ var require_dist_DdRxWA7g = __commonJS({
37875
37978
  deviceId: zod.z.number(),
37876
37979
  trackId: zod.z.string(),
37877
37980
  /** Provenance only. It may already point at nothing — that is expected. */
37878
- sourceMediaKey: zod.z.string(),
37981
+ sourceMediaId: zod.z.number().int(),
37879
37982
  sourceKind: MediaFileKindEnum,
37880
37983
  sizeBytes: zod.z.number().int(),
37881
37984
  width: zod.z.number().int(),
@@ -37890,7 +37993,7 @@ var require_dist_DdRxWA7g = __commonJS({
37890
37993
  var RetrainFrameSelectionSchema = zod.z.object({
37891
37994
  copied: zod.z.array(RetrainFrameSchema).readonly(),
37892
37995
  refused: zod.z.array(zod.z.object({
37893
- sourceMediaKey: zod.z.string(),
37996
+ sourceMediaId: zod.z.number().int(),
37894
37997
  reason: RetrainCopyRefusalSchema
37895
37998
  })).readonly()
37896
37999
  });
@@ -37898,7 +38001,7 @@ var require_dist_DdRxWA7g = __commonJS({
37898
38001
  candidates: zod.z.array(RetrainFrameCandidateSchema).readonly(),
37899
38002
  copies: zod.z.array(RetrainFrameSchema).readonly(),
37900
38003
  /** What the page pre-selects — the native key frame when one survives. */
37901
- autoPickMediaKey: zod.z.string().optional()
38004
+ autoPickMediaId: zod.z.number().int().optional()
37902
38005
  });
37903
38006
  var RetrainAssistSubjectSchema = zod.z.discriminatedUnion("kind", [zod.z.object({
37904
38007
  kind: zod.z.literal("package"),
@@ -37991,19 +38094,97 @@ var require_dist_DdRxWA7g = __commonJS({
37991
38094
  lastActiveAt: zod.z.number(),
37992
38095
  sealedAt: zod.z.number().nullable(),
37993
38096
  memberCount: zod.z.number().int().nonnegative(),
37994
- groupShotKey: zod.z.string().nullable()
38097
+ groupShotMediaId: zod.z.number().int().nullable()
37995
38098
  });
37996
38099
  var SummariesQueryInput = zod.z.object({
37997
38100
  deviceIds: zod.z.array(zod.z.number()).min(1),
37998
38101
  since: zod.z.number().optional(),
37999
38102
  until: zod.z.number().optional(),
38000
- limit: zod.z.number().int().min(1).max(200).default(50)
38103
+ limit: zod.z.number().int().min(1).max(200).default(50),
38104
+ /** The same member-wise filter {@link listRecentSummaries} takes — one
38105
+ * meaning of "dog" on every summary surface. */
38106
+ classes: zod.z.array(zod.z.string().min(1).max(60)).max(40).optional()
38107
+ });
38108
+ var SummaryMemberSchema = zod.z.object({
38109
+ trackId: zod.z.string(),
38110
+ /**
38111
+ * The track's class at the time it JOINED, or `null` when it was unresolved
38112
+ * and the track no longer exists to fill it.
38113
+ *
38114
+ * The join, not the latest opinion: class voting can re-decide a track's
38115
+ * class afterwards, and a group's composition is the history of who came
38116
+ * together. A consumer counts these to badge a thumbnail — "two people and a
38117
+ * dog" — rather than being handed a second, denormalised tally that would
38118
+ * drift from the members it claims to describe.
38119
+ */
38120
+ className: zod.z.string().nullable(),
38121
+ /** `primary` is the one member that carries the group's identity. */
38122
+ role: zod.z.enum([
38123
+ "primary",
38124
+ "sibling",
38125
+ "child"
38126
+ ]).nullable(),
38127
+ joinedAt: zod.z.number(),
38128
+ /** Tier 1 — the sub-class (`dog`, `van`), resolved from the member's track
38129
+ * at read time. Absent when nothing resolved, never an empty string. */
38130
+ label: zod.z.string().optional(),
38131
+ /** Tier 2 — the instance: a person's name, a plate. Absent when the pipeline
38132
+ * recognised nobody, and absent for a member whose track has been pruned —
38133
+ * a thumbnail that names the wrong person is worse than one naming nobody. */
38134
+ subLabel: zod.z.string().optional()
38001
38135
  });
38002
- var SummariesPageSchema = zod.z.object({ summaries: zod.z.array(SummarySchema).readonly() });
38003
38136
  var SummaryDetailSchema = zod.z.object({
38004
38137
  summary: SummarySchema,
38005
- /** Member track ids, in absorption order. */
38006
- trackIds: zod.z.array(zod.z.string()).readonly()
38138
+ /** Members in absorption order, oldest join first. */
38139
+ members: zod.z.array(SummaryMemberSchema).readonly()
38140
+ });
38141
+ var SummaryListItemSchema = zod.z.object({
38142
+ summary: SummarySchema,
38143
+ /** Class counts, most numerous first; `className: null` is a member whose
38144
+ * class never resolved, counted so the counts add up to `memberCount`. */
38145
+ classes: zod.z.array(zod.z.object({
38146
+ className: zod.z.string().nullable(),
38147
+ count: zod.z.number().int().positive()
38148
+ })).readonly()
38149
+ });
38150
+ var SummariesPageSchema = zod.z.object({ summaries: zod.z.array(SummaryListItemSchema).readonly() });
38151
+ var RecentSummariesQueryInput = zod.z.object({
38152
+ /** Devices to merge. An empty array yields an empty page. */
38153
+ deviceIds: zod.z.array(zod.z.number()),
38154
+ /** Window lower bound on `lastActiveAt` (inclusive). */
38155
+ since: zod.z.number().optional(),
38156
+ /** Window upper bound on `lastActiveAt` (inclusive). */
38157
+ until: zod.z.number().optional(),
38158
+ limit: zod.z.number().int().min(1).max(500).default(100),
38159
+ /** Opaque continuation cursor from a previous page's `nextCursor`. */
38160
+ cursor: zod.z.string().optional(),
38161
+ /**
38162
+ * Restrict to these classes — THE SAME FIELD `listRecentTracks` takes, and
38163
+ * deliberately the same name: the events filter tree emits one list of ticked
38164
+ * taxonomy nodes, and a summaries feed that called it something else would
38165
+ * make the operator's one filter component produce two shapes.
38166
+ *
38167
+ * A question about the MEMBERS: a group matches when ANY of them does. "Show
38168
+ * me the arrivals with a dog" has to return the group of four people who had
38169
+ * one with them; a filter on the group's own fields could only ever answer
38170
+ * about its primary.
38171
+ *
38172
+ * Matched against all THREE tiers of a member — the class (`animal`), the
38173
+ * sub-class (`dog`) and the instance (a name, a plate) — because which tier a
38174
+ * ticked node lives on is the taxonomy's business, not the caller's. `dog` is
38175
+ * an event kind in the tree and a tier-1 label on an `animal` track; a filter
38176
+ * that read only the class would answer "animal" and never "dog".
38177
+ *
38178
+ * ABSENT or EMPTY means no filter — absent is not a selection of none.
38179
+ */
38180
+ classes: zod.z.array(zod.z.string().min(1).max(60)).max(40).optional()
38181
+ });
38182
+ var RecentSummariesPageSchema = zod.z.object({
38183
+ /** Ordered by (`lastActiveAt` DESC, id DESC). Same light item as
38184
+ * {@link listSummaries} — one list shape, so a card renders the same
38185
+ * whichever feed drew it. */
38186
+ summaries: zod.z.array(SummaryListItemSchema).readonly(),
38187
+ nextCursor: zod.z.string().nullable()
38007
38188
  });
38008
38189
  var RecentTracksPageSchema = zod.z.object({
38009
38190
  /** Merged page, ordered by (`lastSeen` DESC, `trackId` DESC). */
@@ -38355,6 +38536,11 @@ var require_dist_DdRxWA7g = __commonJS({
38355
38536
  listRecentTracks: method(RecentTracksQueryInput, RecentTracksPageSchema),
38356
38537
  /** Newest first by `openedAt`, for a camera set, inside an optional window. */
38357
38538
  listSummaries: method(SummariesQueryInput, SummariesPageSchema),
38539
+ /**
38540
+ * The PAGED feed — the reel and the Events gallery. Same cursor contract as
38541
+ * {@link listRecentTracks}, so one screen cannot hold two ideas of newest.
38542
+ */
38543
+ listRecentSummaries: method(RecentSummariesQueryInput, RecentSummariesPageSchema),
38358
38544
  /** One summary with its member track ids; `null` for an id nobody wrote. */
38359
38545
  getSummary: method(zod.z.object({ id: zod.z.string() }), SummaryDetailSchema.nullable()),
38360
38546
  clearTracks: method(zod.z.object({ deviceId: zod.z.number() }), zod.z.void(), {
@@ -38884,7 +39070,7 @@ var require_dist_DdRxWA7g = __commonJS({
38884
39070
  selectRetrainFrames: method(zod.z.object({
38885
39071
  deviceId: zod.z.number(),
38886
39072
  trackId: zod.z.string(),
38887
- mediaKeys: zod.z.array(zod.z.string()).min(1)
39073
+ mediaIds: zod.z.array(zod.z.number().int()).min(1)
38888
39074
  }), RetrainFrameSelectionSchema, {
38889
39075
  kind: "mutation",
38890
39076
  auth: "admin"
@@ -39048,8 +39234,29 @@ var require_dist_DdRxWA7g = __commonJS({
39048
39234
  kind: "query",
39049
39235
  auth: "admin"
39050
39236
  }),
39237
+ /**
39238
+ * The media an EVENT owns.
39239
+ *
39240
+ * `ownerType` is REQUIRED, and that is the whole correction (D482). An
39241
+ * event is a row in ONE of three tables, and since D474 each numbers from
39242
+ * 1 independently: `motion:101314` and `object:101314` both exist. This
39243
+ * method took a bare `eventId` and the provider probed motion → object →
39244
+ * audio, stopping at the first hit — so on the live hub, where object
39245
+ * events own no media of their own and 299 883 of 300 559 media rows are
39246
+ * motion-owned, EVERY object event resolved to its motion namesake. A
39247
+ * track from 17:34 on camera 615 was served a snapshot from 22:35 eleven
39248
+ * days earlier, silently.
39249
+ *
39250
+ * D476 had already disambiguated the KEY (`motion:` vs `object:`); this is
39251
+ * the API catching up to it. Naming the table is not a "qualification" of
39252
+ * the ambiguity — a listing BY OWNER has no address to make surrogate: the
39253
+ * owner IS (table, id), and half of it is not a question.
39254
+ */
39051
39255
  getEventMedia: method(zod.z.object({
39052
- eventId: zod.z.string(),
39256
+ /** Which of the three event tables owns the row. */
39257
+ ownerType: EventOwnerTypeSchema,
39258
+ /** The event's rowid in that table (D474: an event id is a number). */
39259
+ eventId: zod.z.number().int(),
39053
39260
  kind: MediaFileKindEnum.optional(),
39054
39261
  deviceId: zod.z.number()
39055
39262
  }), zod.z.array(MediaFileSchema).readonly()),
@@ -39094,11 +39301,14 @@ var require_dist_DdRxWA7g = __commonJS({
39094
39301
  * the live hub: one event's `fullFrameBoxed` is 2 824 077 B, base64'd to
39095
39302
  * ~3.8 MB, allocated whole in hub-main's heap, for a list of keys.
39096
39303
  *
39097
- * Same `deviceId` authorization subject as `getEventMedia`, and the same
39098
- * rows — this is a projection of that method, never a different question.
39304
+ * Same `deviceId` authorization subject as `getEventMedia`, the same
39305
+ * REQUIRED `ownerType` (read that method's docblock for the night-time
39306
+ * thumbnail this closes — D482), and the same rows: this is a projection
39307
+ * of that method, never a different question.
39099
39308
  */
39100
39309
  listEventMedia: method(zod.z.object({
39101
- eventId: zod.z.string(),
39310
+ ownerType: EventOwnerTypeSchema,
39311
+ eventId: zod.z.number().int(),
39102
39312
  deviceId: zod.z.number()
39103
39313
  }), zod.z.array(MediaFileInfoSchema).readonly()),
39104
39314
  /**
@@ -44602,8 +44812,8 @@ var require_dist_DdRxWA7g = __commonJS({
44602
44812
  id: zod.z.string(),
44603
44813
  name: zod.z.string(),
44604
44814
  sampleCount: zod.z.number().int().nonnegative(),
44605
- coverMediaKey: zod.z.string().optional(),
44606
- /** Inline base64 of the cover sample's crop, resolved from `coverMediaKey`.
44815
+ coverMediaId: zod.z.number().int().optional(),
44816
+ /** Inline base64 of the cover sample's crop, resolved from `coverMediaId`.
44607
44817
  * Lets the UI render the person's face avatar instead of a placeholder icon. */
44608
44818
  coverBase64: zod.z.string().optional()
44609
44819
  });
@@ -44619,8 +44829,8 @@ var require_dist_DdRxWA7g = __commonJS({
44619
44829
  enrolledAt: zod.z.number().int(),
44620
44830
  deviceId: zod.z.number().int().optional(),
44621
44831
  source: zod.z.enum(["detected", "photo"]),
44622
- /** The enrolled crop's media key, so the panel can show the evidence. */
44623
- mediaKey: zod.z.string().optional(),
44832
+ /** The enrolled crop's media row id, so the panel can show the evidence. */
44833
+ mediaId: zod.z.number().int().optional(),
44624
44834
  /**
44625
44835
  * False = the sample is stamped with a DIFFERENT face model, and a cosine
44626
44836
  * across feature spaces is a well-formed float with no meaning. Every number
@@ -44689,15 +44899,15 @@ var require_dist_DdRxWA7g = __commonJS({
44689
44899
  */
44690
44900
  cropUrl: zod.z.string().optional(),
44691
44901
  /** Design B: the face bbox (pixel space) on the key frame — lets a detail
44692
- * view draw the box over the native `keyFrameMediaKey` frame. Absent on
44902
+ * view draw the box over the native `keyFrameMediaId` frame. Absent on
44693
44903
  * legacy rows written before design B. */
44694
44904
  faceBbox: BoundingBoxSchema.optional(),
44695
44905
  /** Design B: MediaStore key of the track's native-resolution key frame.
44696
44906
  * Fetch the native JPEG via the event-media data-plane
44697
- * (`/addon/<addonId>/event-media/<keyFrameMediaKey>`). Absent when the
44907
+ * (`/addon/<addonId>/event-media/m/<keyFrameMediaId>`). Absent when the
44698
44908
  * track produced no key frame (e.g. native/onboard source) — the UI falls
44699
44909
  * back to the inline `base64` face crop. */
44700
- keyFrameMediaKey: zod.z.string().optional(),
44910
+ keyFrameMediaId: zod.z.number().int().optional(),
44701
44911
  /** Winning identity-match cosine (0..1) for this face's track, when an
44702
44912
  * identity was auto-confirmed. Lets the UI surface WHY a face was assigned
44703
44913
  * (confidence badge / low-confidence audit). Absent on legacy rows and on
@@ -44735,7 +44945,9 @@ var require_dist_DdRxWA7g = __commonJS({
44735
44945
  cohesion: zod.z.number()
44736
44946
  });
44737
44947
  var MediaFileLiteSchema$1 = zod.z.object({
44738
- key: zod.z.string(),
44948
+ /** The media row's own id — the same address `MediaFileRef.mediaId` carries
44949
+ * (D482). It was the row's composite key, which embedded the owner. */
44950
+ mediaId: zod.z.number().int(),
44739
44951
  kind: zod.z.string(),
44740
44952
  url: zod.z.string(),
44741
44953
  sizeBytes: zod.z.number(),
@@ -44757,7 +44969,7 @@ var require_dist_DdRxWA7g = __commonJS({
44757
44969
  * covers inline, ~10 KB of base64 per row, on a query this UI mounts
44758
44970
  * four times and the viewer holds at `staleTime: 30_000`.
44759
44971
  *
44760
- * Nothing loses its avatar: `coverMediaKey` is already on every row and
44972
+ * Nothing loses its avatar: `coverMediaId` is already on every row and
44761
44973
  * the `event-media` plane serves that key `immutable` with an ETag.
44762
44974
  *
44763
44975
  * **This is an INPUT field, so it does not reach the addon until the
@@ -47885,8 +48097,8 @@ var require_dist_DdRxWA7g = __commonJS({
47885
48097
  id: zod.z.string(),
47886
48098
  name: zod.z.string(),
47887
48099
  sampleCount: zod.z.number().int().nonnegative(),
47888
- coverMediaKey: zod.z.string().optional(),
47889
- /** Inline base64 of the cover sample's plate crop, resolved from `coverMediaKey`. */
48100
+ coverMediaId: zod.z.number().int().optional(),
48101
+ /** Inline base64 of the cover sample's plate crop, resolved from `coverMediaId`. */
47890
48102
  coverBase64: zod.z.string().optional()
47891
48103
  });
47892
48104
  var VehicleSampleInfoSchema = zod.z.object({
@@ -47919,7 +48131,7 @@ var require_dist_DdRxWA7g = __commonJS({
47919
48131
  /** keyFrame parity: the plate bbox (pixel space) on the native key frame. */
47920
48132
  plateBbox: BoundingBoxSchema.optional(),
47921
48133
  /** keyFrame parity: MediaStore key of the track's native-resolution key frame. */
47922
- keyFrameMediaKey: zod.z.string().optional(),
48134
+ keyFrameMediaId: zod.z.number().int().optional(),
47923
48135
  base64: zod.z.string().optional(),
47924
48136
  /**
47925
48137
  * Same crop as a data-plane URL, always present when the plate has a stored
@@ -47930,7 +48142,9 @@ var require_dist_DdRxWA7g = __commonJS({
47930
48142
  cropUrl: zod.z.string().optional()
47931
48143
  });
47932
48144
  var MediaFileLiteSchema = zod.z.object({
47933
- key: zod.z.string(),
48145
+ /** The media row's own id — the same address `MediaFileRef.mediaId` carries
48146
+ * (D482). It was the row's composite key, which embedded the owner. */
48147
+ mediaId: zod.z.number().int(),
47934
48148
  kind: zod.z.string(),
47935
48149
  url: zod.z.string(),
47936
48150
  sizeBytes: zod.z.number(),
@@ -48004,7 +48218,7 @@ var require_dist_DdRxWA7g = __commonJS({
48004
48218
  listVehicles: method(zod.z.object({
48005
48219
  /** Inline {@link VehicleSchema.coverBase64} on every row. Default
48006
48220
  * `false` — the vehicle twin of `faceGallery.listIdentities`'s
48007
- * option; `coverMediaKey` + the `event-media` plane carry the picture.
48221
+ * option; `coverMediaId` + the `event-media` plane carry the picture.
48008
48222
  * INPUT field: stripped by the hub router until the train ships, which
48009
48223
  * resolves to `false` and is exactly the intended default. */
48010
48224
  includeCrops: zod.z.boolean().optional()
@@ -49501,7 +49715,14 @@ var require_dist_DdRxWA7g = __commonJS({
49501
49715
  modelId: zod.z.string(),
49502
49716
  condition: SceneConditionSchema,
49503
49717
  capturedAt: zod.z.number(),
49504
- thumbnailMediaId: zod.z.string().optional(),
49718
+ /**
49719
+ * The reference thumbnail's media ROW id (D482).
49720
+ *
49721
+ * The name already said `mediaId` while the value was the row's composite
49722
+ * key — a leftover that read as done and was not. It is the row's own id
49723
+ * now, addressed at `/addon/<addonId>/event-media/m/<id>`.
49724
+ */
49725
+ thumbnailMediaId: zod.z.number().int().optional(),
49505
49726
  /** Whole-frame (downscaled) embedding captured alongside the ROI crop. The
49506
49727
  * anti-view-shift anchor: a bumped camera, a PTZ preset or a re-aim makes the
49507
49728
  * normalized rect frame a different piece of world, and the scene would
@@ -50561,7 +50782,29 @@ var require_dist_DdRxWA7g = __commonJS({
50561
50782
  * disarmed the channels it did not mention would make the Levels page and
50562
50783
  * the Diagnostics page fight over the same value.
50563
50784
  */
50564
- channels: zod.z.array(LogChannelWindowPatchSchema).readonly().optional()
50785
+ channels: zod.z.array(LogChannelWindowPatchSchema).readonly().optional(),
50786
+ /**
50787
+ * How many days the analytics OPS LOG is kept — the audit trail of what
50788
+ * retention actually deleted.
50789
+ *
50790
+ * It lives HERE, on the logging document, and not on the analytics addon's
50791
+ * settings form, on the operator's instruction: every other log-ish window in
50792
+ * this system is configured through this one document, and a retention audit
50793
+ * configured somewhere else is a second place to look when the question is
50794
+ * "what happened to my data".
50795
+ *
50796
+ * That placement has a cost worth stating: this document ships in the
50797
+ * framework closure, so this knob needs a published `@camstack/server` while
50798
+ * the four windows beside it (D485) reach a node on `camstack deploy`.
50799
+ *
50800
+ * `retention-model.ts` argued this one must NOT follow a device window,
50801
+ * because the audit trail is the history of the SWEEP and not of the camera.
50802
+ * That argument stands and is untouched — what changes is that 30 days stops
50803
+ * being a constant nobody can reach. `0` keeps it forever. The floor is 1 day
50804
+ * rather than 0-as-delete: an audit log truncated to nothing is precisely the
50805
+ * state in which the next 9.5 GiB leak cannot be explained.
50806
+ */
50807
+ opsLogRetentionDays: zod.z.number().int().min(0).max(3650).optional()
50565
50808
  });
50566
50809
  var ReportedLoadContributionSchema = LoadContributionSchema.extend({ addonId: zod.z.string() });
50567
50810
  var ReportedFailureContributionSchema = FailureContributionSchema.extend({ addonId: zod.z.string() });
@@ -50600,6 +50843,14 @@ var require_dist_DdRxWA7g = __commonJS({
50600
50843
  channels: zod.z.array(LogChannelDescriptorSchema).readonly(),
50601
50844
  /** The channels ARMED right now, each with its deadline. */
50602
50845
  activeChannels: zod.z.array(LogChannelWindowStateSchema).readonly(),
50846
+ /**
50847
+ * The ops-log window in days, as it is in force. `0` = kept forever.
50848
+ *
50849
+ * Reported rather than left to the caller's memory of what it wrote: this is
50850
+ * the value the analytics sweep will actually use, and an operator asking how
50851
+ * long their audit trail lives should not have to infer it from a default.
50852
+ */
50853
+ opsLogRetentionDays: zod.z.number().int().min(0),
50603
50854
  persisted: zod.z.boolean()
50604
50855
  });
50605
50856
  var systemCapability = {
@@ -51423,7 +51674,7 @@ var require_dist_DdRxWA7g = __commonJS({
51423
51674
  /** Enrichment label carried from the source track (identity / plate). */
51424
51675
  label: zod.z.string().optional(),
51425
51676
  /** Native-resolution key-frame media key for the parked object's best image. */
51426
- keyFrameMediaKey: zod.z.string().optional()
51677
+ keyFrameMediaId: zod.z.number().int().optional()
51427
51678
  });
51428
51679
  var CameraOccupancySnapshotSchema = zod.z.object({
51429
51680
  /** Frame timestamp of the inference result that produced this snapshot. */
@@ -53287,6 +53538,12 @@ var require_dist_DdRxWA7g = __commonJS({
53287
53538
  addonId: null,
53288
53539
  access: "create"
53289
53540
  },
53541
+ "dataStoreProvider.upsert": {
53542
+ capName: "data-store-provider",
53543
+ capScope: "system",
53544
+ addonId: null,
53545
+ access: "create"
53546
+ },
53290
53547
  "dayNight.getOptions": {
53291
53548
  capName: "day-night",
53292
53549
  capScope: "device",
@@ -55723,6 +55980,12 @@ var require_dist_DdRxWA7g = __commonJS({
55723
55980
  addonId: null,
55724
55981
  access: "view"
55725
55982
  },
55983
+ "pipelineAnalytics.listRecentSummaries": {
55984
+ capName: "pipeline-analytics",
55985
+ capScope: "device",
55986
+ addonId: null,
55987
+ access: "view"
55988
+ },
55726
55989
  "pipelineAnalytics.listRecentTracks": {
55727
55990
  capName: "pipeline-analytics",
55728
55991
  capScope: "device",
@@ -57151,6 +57414,12 @@ var require_dist_DdRxWA7g = __commonJS({
57151
57414
  addonId: null,
57152
57415
  access: "create"
57153
57416
  },
57417
+ "settingsStore.upsert": {
57418
+ capName: "settings-store",
57419
+ capScope: "system",
57420
+ addonId: null,
57421
+ access: "create"
57422
+ },
57154
57423
  "smtpProvider.getStatus": {
57155
57424
  capName: "smtp-provider",
57156
57425
  capScope: "system",
@@ -59544,6 +59813,11 @@ var require_dist_DdRxWA7g = __commonJS({
59544
59813
  form: "single",
59545
59814
  optional: true
59546
59815
  }],
59816
+ "pipelineAnalytics.listRecentSummaries": [{
59817
+ name: "deviceIds",
59818
+ form: "array",
59819
+ optional: false
59820
+ }],
59547
59821
  "pipelineAnalytics.listRecentTracks": [{
59548
59822
  name: "deviceIds",
59549
59823
  form: "array",
@@ -61865,7 +62139,7 @@ var require_alerts_addon = __commonJS({
61865
62139
  [Symbol.toStringTag]: { value: "Module" }
61866
62140
  });
61867
62141
  require_chunk_Cek0wNdY();
61868
- var require_dist10 = require_dist_DdRxWA7g();
62142
+ var require_dist10 = require_dist_DUSfUAgz();
61869
62143
  function selectExpired(alerts, cutoffMs) {
61870
62144
  return alerts.filter((a) => a.createdAt < cutoffMs).sort((a, b) => a.createdAt - b.createdAt).map((a) => a.id);
61871
62145
  }
@@ -62684,7 +62958,7 @@ var require_console_logging = __commonJS({
62684
62958
  [Symbol.toStringTag]: { value: "Module" }
62685
62959
  });
62686
62960
  require_chunk_Cek0wNdY();
62687
- var require_dist10 = require_dist_DdRxWA7g();
62961
+ var require_dist10 = require_dist_DUSfUAgz();
62688
62962
  var require_formatter = require_formatter_DqAKDlvN();
62689
62963
  var LEVEL_RANK = {
62690
62964
  debug: 0,
@@ -62778,7 +63052,7 @@ var require_core_blocks_addon = __commonJS({
62778
63052
  "use strict";
62779
63053
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
62780
63054
  var require_chunk = require_chunk_Cek0wNdY();
62781
- var require_dist10 = require_dist_DdRxWA7g();
63055
+ var require_dist10 = require_dist_DUSfUAgz();
62782
63056
  var node_crypto = __require("crypto");
62783
63057
  var node_fs_promises = __require("fs/promises");
62784
63058
  node_fs_promises = require_chunk.__toESM(node_fs_promises);
@@ -63675,11 +63949,11 @@ var require_core_blocks = __commonJS({
63675
63949
  }
63676
63950
  });
63677
63951
 
63678
- // ../system/dist/retired-settings-keys-C-jOWHI0.js
63679
- var require_retired_settings_keys_C_jOWHI0 = __commonJS({
63680
- "../system/dist/retired-settings-keys-C-jOWHI0.js"(exports) {
63952
+ // ../system/dist/retired-settings-keys-D61PxN8L.js
63953
+ var require_retired_settings_keys_D61PxN8L = __commonJS({
63954
+ "../system/dist/retired-settings-keys-D61PxN8L.js"(exports) {
63681
63955
  "use strict";
63682
- var require_dist10 = require_dist_DdRxWA7g();
63956
+ var require_dist10 = require_dist_DUSfUAgz();
63683
63957
  function settingsStoreIsAuthoritativeHere(env) {
63684
63958
  const raw = (env["CAMSTACK_ROLE"] ?? "").trim().toLowerCase();
63685
63959
  return raw === "" || raw === "hub";
@@ -63959,9 +64233,9 @@ var require_retired_settings_keys_C_jOWHI0 = __commonJS({
63959
64233
  }
63960
64234
  });
63961
64235
 
63962
- // ../types/dist/canonical-hash-DNV8S5ET.js
63963
- var require_canonical_hash_DNV8S5ET = __commonJS({
63964
- "../types/dist/canonical-hash-DNV8S5ET.js"(exports) {
64236
+ // ../types/dist/canonical-hash-9lydiEzx.js
64237
+ var require_canonical_hash_9lydiEzx = __commonJS({
64238
+ "../types/dist/canonical-hash-9lydiEzx.js"(exports) {
63965
64239
  "use strict";
63966
64240
  var node_crypto = __require("crypto");
63967
64241
  var AUDIO_ENCODER_BY_CODEC = {
@@ -64048,6 +64322,7 @@ var require_canonical_hash_DNV8S5ET = __commonJS({
64048
64322
  ];
64049
64323
  if (video.preset !== void 0) args.push("-preset", video.preset);
64050
64324
  if (video.tune !== void 0) args.push("-tune", video.tune);
64325
+ if (video.singleSlicePerFrame === true && video.encoder === "libx264") args.push("-x264-params", "sliced-threads=0");
64051
64326
  if (video.profile !== void 0) args.push("-profile:v", video.profile);
64052
64327
  if (video.level !== void 0) args.push("-level", video.level);
64053
64328
  if (video.pixelFormat !== void 0) args.push("-pix_fmt", video.pixelFormat);
@@ -64231,6 +64506,7 @@ var require_canonical_hash_DNV8S5ET = __commonJS({
64231
64506
  scale,
64232
64507
  ...v.preset !== void 0 ? { preset: v.preset } : {},
64233
64508
  ...v.tune !== void 0 ? { tune: v.tune } : {},
64509
+ ...v.singleSlicePerFrame !== void 0 ? { singleSlicePerFrame: v.singleSlicePerFrame } : {},
64234
64510
  ...v.profile !== void 0 ? { profile: v.profile } : {},
64235
64511
  ...v.level !== void 0 ? { level: v.level } : {},
64236
64512
  ...input.pixelFormat !== void 0 ? { pixelFormat: input.pixelFormat } : {},
@@ -64561,7 +64837,7 @@ var require_node = __commonJS({
64561
64837
  value: mod,
64562
64838
  enumerable: true
64563
64839
  }) : target, mod));
64564
- var require_canonical_hash = require_canonical_hash_DNV8S5ET();
64840
+ var require_canonical_hash = require_canonical_hash_9lydiEzx();
64565
64841
  var require_err_msg = require_err_msg_COpsHMw2();
64566
64842
  var node_crypto = __require("crypto");
64567
64843
  var node_fs = __require("fs");
@@ -65914,8 +66190,8 @@ var require_device_manager_addon = __commonJS({
65914
66190
  [Symbol.toStringTag]: { value: "Module" }
65915
66191
  });
65916
66192
  require_chunk_Cek0wNdY();
65917
- var require_dist10 = require_dist_DdRxWA7g();
65918
- var require_retired_settings_keys = require_retired_settings_keys_C_jOWHI0();
66193
+ var require_dist10 = require_dist_DUSfUAgz();
66194
+ var require_retired_settings_keys = require_retired_settings_keys_D61PxN8L();
65919
66195
  var node_crypto = __require("crypto");
65920
66196
  var _camstack_types_node = require_node();
65921
66197
  var JOB_HISTORY = 20;
@@ -71540,7 +71816,7 @@ var require_hub_forwarder = __commonJS({
71540
71816
  [Symbol.toStringTag]: { value: "Module" }
71541
71817
  });
71542
71818
  require_chunk_Cek0wNdY();
71543
- var require_dist10 = require_dist_DdRxWA7g();
71819
+ var require_dist10 = require_dist_DUSfUAgz();
71544
71820
  var require_formatter = require_formatter_DqAKDlvN();
71545
71821
  var DEFAULT_OUTBOUND_BUFFER_SIZE = 500;
71546
71822
  var HubForwarderDestination = class {
@@ -71677,7 +71953,7 @@ var require_liveness_monitor_addon = __commonJS({
71677
71953
  "use strict";
71678
71954
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
71679
71955
  require_chunk_Cek0wNdY();
71680
- var require_dist10 = require_dist_DdRxWA7g();
71956
+ var require_dist10 = require_dist_DUSfUAgz();
71681
71957
  var NO_DEVICES = "liveness:no-devices";
71682
71958
  var ALL_OFFLINE = "liveness:all-devices-offline";
71683
71959
  var NO_FOOTAGE_PREFIX = "liveness:no-footage:";
@@ -71873,7 +72149,7 @@ var require_local_auth_addon = __commonJS({
71873
72149
  [Symbol.toStringTag]: { value: "Module" }
71874
72150
  });
71875
72151
  var require_chunk = require_chunk_Cek0wNdY();
71876
- var require_dist10 = require_dist_DdRxWA7g();
72152
+ var require_dist10 = require_dist_DUSfUAgz();
71877
72153
  var node_crypto = __require("crypto");
71878
72154
  node_crypto = require_chunk.__toESM(node_crypto);
71879
72155
  var crypto$1 = __require("crypto");
@@ -79686,7 +79962,7 @@ var require_loki_logging = __commonJS({
79686
79962
  [Symbol.toStringTag]: { value: "Module" }
79687
79963
  });
79688
79964
  require_chunk_Cek0wNdY();
79689
- var require_dist10 = require_dist_DdRxWA7g();
79965
+ var require_dist10 = require_dist_DUSfUAgz();
79690
79966
  function sanitizeLabelName(raw) {
79691
79967
  const replaced = raw.replaceAll(/[^a-zA-Z0-9_]/g, "_");
79692
79968
  return /^[a-zA-Z_]/.test(replaced) ? replaced : `_${replaced}`;
@@ -80273,7 +80549,7 @@ var require_native_metrics_addon = __commonJS({
80273
80549
  [Symbol.toStringTag]: { value: "Module" }
80274
80550
  });
80275
80551
  var require_chunk = require_chunk_Cek0wNdY();
80276
- var require_dist10 = require_dist_DdRxWA7g();
80552
+ var require_dist10 = require_dist_DUSfUAgz();
80277
80553
  var node_fs_promises = __require("fs/promises");
80278
80554
  var node_fs = __require("fs");
80279
80555
  node_fs = require_chunk.__toESM(node_fs);
@@ -83026,7 +83302,7 @@ var require_filesystem_storage_addon = __commonJS({
83026
83302
  [Symbol.toStringTag]: { value: "Module" }
83027
83303
  });
83028
83304
  var require_chunk = require_chunk_Cek0wNdY();
83029
- var require_dist10 = require_dist_DdRxWA7g();
83305
+ var require_dist10 = require_dist_DUSfUAgz();
83030
83306
  var node_crypto = __require("crypto");
83031
83307
  var node_fs_promises = __require("fs/promises");
83032
83308
  var node_path = __require("path");
@@ -84253,8 +84529,8 @@ var require_sqlite_settings_addon = __commonJS({
84253
84529
  [Symbol.toStringTag]: { value: "Module" }
84254
84530
  });
84255
84531
  var require_chunk = require_chunk_Cek0wNdY();
84256
- var require_dist10 = require_dist_DdRxWA7g();
84257
- var require_retired_settings_keys = require_retired_settings_keys_C_jOWHI0();
84532
+ var require_dist10 = require_dist_DUSfUAgz();
84533
+ var require_retired_settings_keys = require_retired_settings_keys_D61PxN8L();
84258
84534
  var require_wal_checkpoint_policy = require_wal_checkpoint_policy_CCJZngds();
84259
84535
  var node_crypto = __require("crypto");
84260
84536
  var node_path = __require("path");
@@ -85082,6 +85358,54 @@ var require_sqlite_settings_addon = __commonJS({
85082
85358
  return { id: suppliedOrMinted ?? Number(rowid) };
85083
85359
  }
85084
85360
  /**
85361
+ * Make a SLOT hold this row, and answer with the id the row HAS — one
85362
+ * statement, `INSERT … ON CONFLICT(<slot>) DO UPDATE … RETURNING <pk>`.
85363
+ *
85364
+ * See `settings-store.cap.ts`'s `upsert` docblock for why the store needed a
85365
+ * slot that is not the primary key (D482). Three things are load-bearing
85366
+ * here:
85367
+ *
85368
+ * - **`RETURNING` and not `lastInsertRowid`.** On the UPDATE branch
85369
+ * `lastInsertRowid` is whatever the connection last inserted — a
85370
+ * different row, or a different TABLE. It answers confidently and wrongly,
85371
+ * which is worse than not answering. `RETURNING` names the row this
85372
+ * statement actually touched, on both branches.
85373
+ * - **The conflict columns are checked against the declaration** before they
85374
+ * reach the SQL. An undeclared name would be interpolated into DDL-shaped
85375
+ * text; it is refused, by the same rule and for the same reason
85376
+ * {@link resolveProjection} throws on an unprojectable column.
85377
+ * - **The primary key is never part of the SET list.** An `INTEGER` rowid
85378
+ * alias is not in `row` at all, and on a TEXT key rewriting the id of the
85379
+ * row we just matched is the one update that cannot be right.
85380
+ */
85381
+ async upsert({ namespace, collection, conflict, record }) {
85382
+ const scoped = this.scopedName(namespace, collection);
85383
+ const decl = this.requireDeclared(scoped);
85384
+ if (conflict.length === 0) throw new UnprojectableColumnError(`upsert on "${scoped}" was given an EMPTY conflict target \u2014 "ON CONFLICT()" is not valid SQL, and "no slot, just insert" is insert()`);
85385
+ const unknownCols = conflict.filter((name) => !decl.columns.has(name) && name !== decl.primaryKey);
85386
+ if (unknownCols.length > 0) throw new UnprojectableColumnError(`upsert on "${scoped}" names conflict column(s) the collection does not declare: ${unknownCols.join(", ")}`);
85387
+ const suppliedOrMinted = decl.autoPrimaryKey ? null : record.id || (0, node_crypto.randomUUID)();
85388
+ const row = decl.autoPrimaryKey ? {} : { [decl.primaryKey]: suppliedOrMinted };
85389
+ if (decl.columns.size === 1 && decl.columns.has("data")) row["data"] = JSON.stringify(record.data);
85390
+ else for (const [k, v] of Object.entries(record.data)) if (decl.columns.has(k)) row[k] = this.serializeColumnValue(v);
85391
+ const keys = Object.keys(row);
85392
+ const cols = keys.map((k) => `"${k}"`).join(", ");
85393
+ const placeholders = keys.map(() => "?").join(", ");
85394
+ const target = conflict.map((k) => `"${k}"`).join(", ");
85395
+ const updates = keys.filter((k) => k !== decl.primaryKey && !conflict.includes(k)).map((k) => `"${k}" = excluded."${k}"`);
85396
+ const sql = `INSERT INTO "${scoped}" (${cols}) VALUES (${placeholders}) ON CONFLICT(${target}) DO UPDATE SET ${updates.length > 0 ? updates.join(", ") : `"${conflict[0]}" = excluded."${conflict[0]}"`} RETURNING "${decl.primaryKey}"`;
85397
+ const values = keys.map((k) => row[k] ?? null);
85398
+ const id = this.measured({
85399
+ op: "upsert",
85400
+ collection: scoped,
85401
+ sql,
85402
+ params: values
85403
+ }, () => this.getDb().prepare(sql).get(...values))?.[decl.primaryKey];
85404
+ if (typeof id === "number" || typeof id === "bigint") return { id: Number(id) };
85405
+ if (typeof id === "string") return { id };
85406
+ throw new Error(`upsert on "${scoped}" returned no row \u2014 the ON CONFLICT target (${target}) resolved to no unique index, or the write was rejected`);
85407
+ }
85408
+ /**
85085
85409
  * Insert a batch in ONE transaction, on ONE prepared statement.
85086
85410
  *
85087
85411
  * The write-side twin of {@link deleteWhere}. Every row in the batch shares
@@ -86993,7 +87317,7 @@ var require_storage_orchestrator_addon = __commonJS({
86993
87317
  [Symbol.toStringTag]: { value: "Module" }
86994
87318
  });
86995
87319
  var require_chunk = require_chunk_Cek0wNdY();
86996
- var require_dist10 = require_dist_DdRxWA7g();
87320
+ var require_dist10 = require_dist_DUSfUAgz();
86997
87321
  var require_hub_cap_forward = require_hub_cap_forward_DmHNjbB0();
86998
87322
  var zod = require_zod();
86999
87323
  var node_crypto = __require("crypto");
@@ -88030,6 +88354,7 @@ var require_storage_orchestrator_addon = __commonJS({
88030
88354
  set: async (input) => (await engine()).set(input),
88031
88355
  query: async (input) => (await engine()).query(input),
88032
88356
  insert: async (input) => (await engine()).insert(input),
88357
+ upsert: async (input) => (await engine()).upsert(input),
88033
88358
  insertMany: async (input) => (await engine()).insertMany(input),
88034
88359
  update: async (input) => (await engine()).update(input),
88035
88360
  delete: async (input) => (await engine()).delete(input),
@@ -88177,6 +88502,7 @@ var require_storage_orchestrator_addon = __commonJS({
88177
88502
  set: (input) => send("set", input),
88178
88503
  query: (input) => send("query", input),
88179
88504
  insert: (input) => send("insert", input),
88505
+ upsert: (input) => send("upsert", input),
88180
88506
  insertMany: (input) => send("insertMany", input),
88181
88507
  update: (input) => send("update", input),
88182
88508
  delete: (input) => send("delete", input),
@@ -88336,6 +88662,57 @@ var require_storage_orchestrator_addon = __commonJS({
88336
88662
  const percent = require_dist10.gbToBytes(minFreeGb) / totalBytes * 100;
88337
88663
  return Math.min(100, percent);
88338
88664
  }
88665
+ function unknown(reason) {
88666
+ return {
88667
+ kind: "unknown",
88668
+ reason
88669
+ };
88670
+ }
88671
+ function freePercentOf(capacity) {
88672
+ if (capacity === null || capacity.totalBytes <= 0) return 100;
88673
+ return capacity.availableBytes / capacity.totalBytes * 100;
88674
+ }
88675
+ function volumeTotalBytesOf(capacity) {
88676
+ return capacity === null ? 0 : capacity.totalBytes;
88677
+ }
88678
+ function probePathFor(location, locality, localNodeId, cwd) {
88679
+ if (locality !== true) {
88680
+ const why = locality === false ? `is served by the remote provider "${location.providerId}" (nodeLocal: false) \u2014 its bytes live on the remote host and no local statfs describes them` : `is served by "${location.providerId}", which this node has not classified yet (no getProviderInfo answer) \u2014 a local statfs would be a guess`;
88681
+ return { reason: `location "${location.id}" ${why}` };
88682
+ }
88683
+ if (location.nodeId !== void 0 && location.nodeId !== localNodeId) return { reason: `location "${location.id}" lives on node "${location.nodeId}" and this is "${localNodeId}" \u2014 only the owning node can statfs its own volumes` };
88684
+ const basePath = location.config["basePath"];
88685
+ if (typeof basePath !== "string" || basePath.length === 0) return { reason: `location "${location.id}" declares no basePath to measure` };
88686
+ if (!node_path.default.isAbsolute(basePath)) return { reason: `location "${location.id}" declares a RELATIVE basePath ("${basePath}") \u2014 that is a path inside its provider's own namespace, not on this node's filesystem, and resolving it against "${cwd}" would measure an unrelated volume` };
88687
+ return { path: node_path.default.resolve(basePath) };
88688
+ }
88689
+ async function readLocalVolumeCapacity(location, locality, localNodeId, deps) {
88690
+ const target = probePathFor(location, locality, localNodeId, deps.cwd);
88691
+ if ("reason" in target) return unknown(target.reason);
88692
+ const root = node_path.default.parse(target.path).root;
88693
+ let probed = target.path;
88694
+ for (; ; ) try {
88695
+ await deps.probe.access(probed);
88696
+ break;
88697
+ } catch {
88698
+ const parent = node_path.default.dirname(probed);
88699
+ if (parent === probed) return unknown(`nothing on the path "${target.path}" exists on this node \u2014 the volume is not mounted, so the root filesystem's size is not an answer about it`);
88700
+ probed = parent;
88701
+ }
88702
+ if (probed === root && target.path !== root) return unknown(`only the filesystem root exists on the path "${target.path}" \u2014 the volume is not mounted, so the root filesystem's size is not an answer about it`);
88703
+ try {
88704
+ const st = await deps.probe.statfs(probed);
88705
+ return {
88706
+ kind: "measured",
88707
+ path: probed,
88708
+ totalBytes: st.blocks * st.bsize,
88709
+ availableBytes: st.bavail * st.bsize
88710
+ };
88711
+ } catch (err) {
88712
+ const reason = err instanceof Error ? err.message : String(err);
88713
+ return unknown(`statfs("${probed}") failed: ${reason}`);
88714
+ }
88715
+ }
88339
88716
  var FRAMEWORK_CONFIG_KEYS = /* @__PURE__ */ new Set([
88340
88717
  "basePath",
88341
88718
  "readOnly",
@@ -90388,31 +90765,53 @@ var require_storage_orchestrator_addon = __commonJS({
90388
90765
  } });
90389
90766
  throw new Error(refusal);
90390
90767
  }
90391
- /** statfs capacity of a location's basePath, walking up to the nearest
90392
- * existing ancestor. Null for remote-node locations or unstattable paths. */
90768
+ /**
90769
+ * The volume figures for one location, or `null` when this node cannot take
90770
+ * a measurement that is genuinely about it.
90771
+ *
90772
+ * The decision lives in `location-volume-capacity.ts` — including why a
90773
+ * remote-provider location (the SMB share that was reporting the hub's own
90774
+ * disk) gets nothing rather than a number. Here we only supply the node id,
90775
+ * the provider's declared locality and the real filesystem, and log the
90776
+ * reason once per distinct fault: `listLocations` is on the admin UI's poll,
90777
+ * so a line per call would be a line per second.
90778
+ */
90393
90779
  async localCapacityOf(loc) {
90394
- const localNode = this.service?.getLocalNodeId() ?? "hub";
90395
- if (loc.nodeId !== void 0 && loc.nodeId !== localNode) return null;
90396
- const bp = loc.config["basePath"];
90397
- if (typeof bp !== "string" || bp.length === 0) return null;
90398
- try {
90399
- let target = node_path.resolve(bp);
90400
- for (; ; ) try {
90401
- await node_fs_promises.access(target);
90402
- break;
90403
- } catch {
90404
- const parent = node_path.dirname(target);
90405
- if (!parent || parent === target) return null;
90406
- target = parent;
90407
- }
90408
- const st = await node_fs_promises.statfs(target);
90409
- return {
90410
- totalBytes: st.blocks * st.bsize,
90411
- availableBytes: st.bavail * st.bsize
90412
- };
90413
- } catch {
90780
+ const localNode = this.service?.getLocalNodeId() ?? HUB_NODE_ID;
90781
+ const result = await readLocalVolumeCapacity(loc, this.providerIsNodeLocal(loc), localNode, {
90782
+ probe: {
90783
+ access: (target) => node_fs_promises.access(target),
90784
+ statfs: async (target) => node_fs_promises.statfs(target)
90785
+ },
90786
+ cwd: node_path.resolve(".")
90787
+ });
90788
+ if (result.kind === "unknown") {
90789
+ this.logCapacityUnknownOnce(loc.id, result.reason);
90414
90790
  return null;
90415
90791
  }
90792
+ this.clearCapacityUnknown(loc.id, result.path);
90793
+ return {
90794
+ totalBytes: result.totalBytes,
90795
+ availableBytes: result.availableBytes
90796
+ };
90797
+ }
90798
+ /** locationId → the last unmeasurable reason logged for it. */
90799
+ capacityUnknownLogged = /* @__PURE__ */ new Map();
90800
+ logCapacityUnknownOnce(locationId, reason) {
90801
+ if (this.capacityUnknownLogged.get(locationId) === reason) return;
90802
+ this.capacityUnknownLogged.set(locationId, reason);
90803
+ this.ctx.logger.warn("storage-orchestrator: capacity is UNKNOWN for a location \u2014 reporting nothing rather than another volume\u2019s figures", { meta: {
90804
+ locationId,
90805
+ reason
90806
+ } });
90807
+ }
90808
+ clearCapacityUnknown(locationId, measuredPath) {
90809
+ if (!this.capacityUnknownLogged.has(locationId)) return;
90810
+ this.capacityUnknownLogged.delete(locationId);
90811
+ this.ctx.logger.info("storage-orchestrator: capacity is measurable again", { meta: {
90812
+ locationId,
90813
+ measuredPath
90814
+ } });
90416
90815
  }
90417
90816
  /** Per-location cap on EVICTABLE bytes (`config.maxUsedGb`): the operator's
90418
90817
  * "recordings may use at most N GB in total" — enforced by the pressure
@@ -90501,28 +90900,30 @@ var require_storage_orchestrator_addon = __commonJS({
90501
90900
  } });
90502
90901
  return occupancy;
90503
90902
  }
90504
- /** Free capacity (%) on a location's volume via `statfs`; 100 (guard inert) when unstattable. */
90903
+ /**
90904
+ * The pressure guard's two readings come from the SAME probe the UI's
90905
+ * capacity does — one capacity truth per location, not two.
90906
+ *
90907
+ * They used to `statfs` the raw `basePath` themselves, which on this node
90908
+ * answers for whatever local path happens to carry that name: a location
90909
+ * owned by another node, or served by a remote provider, could decide
90910
+ * eviction from the hub's own disk. Both now degrade exactly as they did
90911
+ * when the path was unstattable — `100` (guard inert) and `0` (no byte
90912
+ * target) — but they do so for every reading that is not ABOUT the location,
90913
+ * not only for the ones that threw.
90914
+ */
90915
+ async volumeCapacityOf(locationId) {
90916
+ const loc = this.service?.listLocations().find((l) => l.id === locationId);
90917
+ if (!loc) return null;
90918
+ return this.localCapacityOf(loc);
90919
+ }
90920
+ /** Free capacity (%) on a location's volume; 100 (guard inert) when unmeasurable. */
90505
90921
  async locationFreePercent(locationId) {
90506
- const bp = this.locationBasePath(locationId);
90507
- if (!bp) return 100;
90508
- try {
90509
- const st = await node_fs_promises.statfs(bp);
90510
- if (st.blocks <= 0) return 100;
90511
- return st.bavail / st.blocks * 100;
90512
- } catch {
90513
- return 100;
90514
- }
90922
+ return freePercentOf(await this.volumeCapacityOf(locationId));
90515
90923
  }
90516
- /** Total bytes on a location's volume via `statfs`; 0 when unstattable. */
90924
+ /** Total bytes on a location's volume; 0 when unmeasurable. */
90517
90925
  async locationVolumeTotalBytes(locationId) {
90518
- const bp = this.locationBasePath(locationId);
90519
- if (!bp) return 0;
90520
- try {
90521
- const st = await node_fs_promises.statfs(bp);
90522
- return st.blocks * st.bsize;
90523
- } catch {
90524
- return 0;
90525
- }
90926
+ return volumeTotalBytesOf(await this.volumeCapacityOf(locationId));
90526
90927
  }
90527
90928
  /**
90528
90929
  * Seed default storage locations from the addon-declared
@@ -90643,7 +91044,7 @@ var require_system_config_addon = __commonJS({
90643
91044
  [Symbol.toStringTag]: { value: "Module" }
90644
91045
  });
90645
91046
  require_chunk_Cek0wNdY();
90646
- var require_dist10 = require_dist_DdRxWA7g();
91047
+ var require_dist10 = require_dist_DUSfUAgz();
90647
91048
  var SECTION_TITLES = {
90648
91049
  server: "Server",
90649
91050
  auth: "Authentication"
@@ -108704,7 +109105,7 @@ var require_winston_logging = __commonJS({
108704
109105
  [Symbol.toStringTag]: { value: "Module" }
108705
109106
  });
108706
109107
  var require_chunk = require_chunk_Cek0wNdY();
108707
- var require_dist10 = require_dist_DdRxWA7g();
109108
+ var require_dist10 = require_dist_DUSfUAgz();
108708
109109
  var require_formatter = require_formatter_DqAKDlvN();
108709
109110
  var node_path = __require("path");
108710
109111
  node_path = require_chunk.__toESM(node_path);
@@ -110573,9 +110974,9 @@ ${(0, node_fs.readFileSync)(ca.caCertPath, "utf-8").trimEnd()}
110573
110974
  }
110574
110975
  });
110575
110976
 
110576
- // ../types/dist/event-category-BNJ9EE5B.js
110577
- var require_event_category_BNJ9EE5B = __commonJS({
110578
- "../types/dist/event-category-BNJ9EE5B.js"(exports) {
110977
+ // ../types/dist/event-category-yW4s1MGD.js
110978
+ var require_event_category_yW4s1MGD = __commonJS({
110979
+ "../types/dist/event-category-yW4s1MGD.js"(exports) {
110579
110980
  "use strict";
110580
110981
  var EventCategory = /* @__PURE__ */ (function(EventCategory2) {
110581
110982
  EventCategory2["SystemBoot"] = "system.boot";
@@ -110741,11 +111142,11 @@ var require_event_category_BNJ9EE5B = __commonJS({
110741
111142
  }
110742
111143
  });
110743
111144
 
110744
- // ../types/dist/sleep-B1ZwxAhh.js
110745
- var require_sleep_B1ZwxAhh = __commonJS({
110746
- "../types/dist/sleep-B1ZwxAhh.js"(exports) {
111145
+ // ../types/dist/sleep-DXsYD0RX.js
111146
+ var require_sleep_DXsYD0RX = __commonJS({
111147
+ "../types/dist/sleep-DXsYD0RX.js"(exports) {
110747
111148
  "use strict";
110748
- var require_event_category = require_event_category_BNJ9EE5B();
111149
+ var require_event_category = require_event_category_yW4s1MGD();
110749
111150
  var zod = require_zod();
110750
111151
  var AUDIO_CHUNK_FORMATS = [
110751
111152
  "f32le",
@@ -113522,6 +113923,7 @@ var require_sleep_B1ZwxAhh = __commonJS({
113522
113923
  listTracks: (input) => dispatch("pipeline-analytics", "pipelineAnalytics", "listTracks", "query", input),
113523
113924
  listRecentTracks: (input) => dispatch("pipeline-analytics", "pipelineAnalytics", "listRecentTracks", "query", input),
113524
113925
  listSummaries: (input) => dispatch("pipeline-analytics", "pipelineAnalytics", "listSummaries", "query", input),
113926
+ listRecentSummaries: (input) => dispatch("pipeline-analytics", "pipelineAnalytics", "listRecentSummaries", "query", input),
113525
113927
  getSummary: (input) => dispatch("pipeline-analytics", "pipelineAnalytics", "getSummary", "query", input),
113526
113928
  clearTracks: (input) => dispatch("pipeline-analytics", "pipelineAnalytics", "clearTracks", "mutation", input),
113527
113929
  getMotionEvents: (input) => dispatch("pipeline-analytics", "pipelineAnalytics", "getMotionEvents", "query", input),
@@ -114575,8 +114977,8 @@ var require_addon = __commonJS({
114575
114977
  "../types/dist/addon.js"(exports) {
114576
114978
  "use strict";
114577
114979
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
114578
- var require_sleep = require_sleep_B1ZwxAhh();
114579
- var require_event_category = require_event_category_BNJ9EE5B();
114980
+ var require_sleep = require_sleep_DXsYD0RX();
114981
+ var require_event_category = require_event_category_yW4s1MGD();
114580
114982
  var require_err_msg = require_err_msg_COpsHMw2();
114581
114983
  var CAP_INPUT_DEFAULTS = Object.freeze({
114582
114984
  "addons": { "getLogs": { "limit": 100 } },
@@ -114696,6 +115098,7 @@ var require_addon = __commonJS({
114696
115098
  "getMotionEvents": { "limit": 1e3 },
114697
115099
  "getObjectEvents": { "limit": 1e3 },
114698
115100
  "getSensorEvents": { "limit": 1e3 },
115101
+ "listRecentSummaries": { "limit": 100 },
114699
115102
  "listRecentTracks": { "limit": 200 },
114700
115103
  "listSummaries": { "limit": 50 },
114701
115104
  "reclaimDebugMedia": { "mode": "report" },
@@ -121440,9 +121843,9 @@ var require_dist2 = __commonJS({
121440
121843
  }
121441
121844
  });
121442
121845
 
121443
- // ../system/dist/manifest-system-deps-8x1jgPz_.js
121444
- var require_manifest_system_deps_8x1jgPz = __commonJS({
121445
- "../system/dist/manifest-system-deps-8x1jgPz_.js"(exports) {
121846
+ // ../system/dist/manifest-system-deps-CrSP0Kkp.js
121847
+ var require_manifest_system_deps_CrSP0Kkp = __commonJS({
121848
+ "../system/dist/manifest-system-deps-CrSP0Kkp.js"(exports) {
121446
121849
  "use strict";
121447
121850
  var require_chunk = require_chunk_Cek0wNdY();
121448
121851
  require_hub_cap_forward_DmHNjbB0();
@@ -122886,6 +123289,19 @@ var require_manifest_system_deps_8x1jgPz = __commonJS({
122886
123289
  });
122887
123290
  return cachedInvocation;
122888
123291
  }
123292
+ function buildNpmChildEnv(env, execPath) {
123293
+ const nodeDir = node_path.dirname(execPath);
123294
+ const current = env["PATH"];
123295
+ if (current === void 0 || current.length === 0) return {
123296
+ ...env,
123297
+ PATH: nodeDir
123298
+ };
123299
+ if (current === nodeDir || current.startsWith(`${nodeDir}${node_path.delimiter}`)) return { ...env };
123300
+ return {
123301
+ ...env,
123302
+ PATH: `${nodeDir}${node_path.delimiter}${current}`
123303
+ };
123304
+ }
122889
123305
  async function runNpm(args, options) {
122890
123306
  const invocation = await resolveNpmInvocation({
122891
123307
  cacheDir: options.cacheDir,
@@ -122894,7 +123310,8 @@ var require_manifest_system_deps_8x1jgPz = __commonJS({
122894
123310
  });
122895
123311
  return execFileAsync$2(invocation.command, [...invocation.argsPrefix, ...args], {
122896
123312
  ...options.cwd !== void 0 ? { cwd: options.cwd } : {},
122897
- timeout: options.timeout ?? 3e5
123313
+ timeout: options.timeout ?? 3e5,
123314
+ env: buildNpmChildEnv(options.env ?? process.env, process.execPath)
122898
123315
  });
122899
123316
  }
122900
123317
  async function resolveUncached(options) {
@@ -130397,6 +130814,12 @@ var require_manifest_system_deps_8x1jgPz = __commonJS({
130397
130814
  return buildNativeCapProxy;
130398
130815
  }
130399
130816
  });
130817
+ Object.defineProperty(exports, "buildNpmChildEnv", {
130818
+ enumerable: true,
130819
+ get: function() {
130820
+ return buildNpmChildEnv;
130821
+ }
130822
+ });
130400
130823
  Object.defineProperty(exports, "buildUdsNativeCapProxy", {
130401
130824
  enumerable: true,
130402
130825
  get: function() {
@@ -130964,11 +131387,11 @@ var require_manifest_system_deps_8x1jgPz = __commonJS({
130964
131387
  }
130965
131388
  });
130966
131389
 
130967
- // ../system/dist/custom-action-registry-BTB-LgGN.js
130968
- var require_custom_action_registry_BTB_LgGN = __commonJS({
130969
- "../system/dist/custom-action-registry-BTB-LgGN.js"(exports) {
131390
+ // ../system/dist/custom-action-registry-DAFhWd0h.js
131391
+ var require_custom_action_registry_DAFhWd0h = __commonJS({
131392
+ "../system/dist/custom-action-registry-DAFhWd0h.js"(exports) {
130970
131393
  "use strict";
130971
- var require_dist10 = require_dist_DdRxWA7g();
131394
+ var require_dist10 = require_dist_DUSfUAgz();
130972
131395
  var CustomActionRegistry = class {
130973
131396
  byAddon = /* @__PURE__ */ new Map();
130974
131397
  registerAddon(addonId, catalog, handler) {
@@ -134782,7 +135205,7 @@ var require_dist3 = __commonJS({
134782
135205
  "use strict";
134783
135206
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
134784
135207
  var require_chunk = require_chunk_Cek0wNdY();
134785
- var require_dist10 = require_dist_DdRxWA7g();
135208
+ var require_dist10 = require_dist_DUSfUAgz();
134786
135209
  var require_builtins_alerts_alerts_addon = require_alerts_addon();
134787
135210
  require_alerts();
134788
135211
  var require_formatter = require_formatter_DqAKDlvN();
@@ -134809,9 +135232,9 @@ var require_dist3 = __commonJS({
134809
135232
  var require_builtins_winston_logging_index = require_winston_logging();
134810
135233
  var require_event_loop_stall_monitor = require_event_loop_stall_monitor_CAsHdMwP();
134811
135234
  var require_tls$1 = require_tls_BFs4PzoW();
134812
- var require_manifest_system_deps = require_manifest_system_deps_8x1jgPz();
135235
+ var require_manifest_system_deps = require_manifest_system_deps_CrSP0Kkp();
134813
135236
  var require_resource_monitor = require_resource_monitor_LVE1BoLs();
134814
- var require_custom_action_registry = require_custom_action_registry_BTB_LgGN();
135237
+ var require_custom_action_registry = require_custom_action_registry_DAFhWd0h();
134815
135238
  var zod = require_zod();
134816
135239
  var node_crypto = __require("crypto");
134817
135240
  var _camstack_types_node = require_node();
@@ -215657,6 +216080,7 @@ globstar while`, t, d, e, f, m), this.matchOne(t.slice(d), e.slice(f), s)) retur
215657
216080
  exports.buildLinkChain = require_manifest_system_deps.buildLinkChain;
215658
216081
  exports.buildNativeCapProxy = require_manifest_system_deps.buildNativeCapProxy;
215659
216082
  exports.buildNodeManifest = buildNodeManifest;
216083
+ exports.buildNpmChildEnv = require_manifest_system_deps.buildNpmChildEnv;
215660
216084
  exports.buildStorageLocationRegistry = require_builtins_storage_orchestrator_storage_orchestrator_addon.buildStorageLocationRegistry;
215661
216085
  exports.buildUdsNativeCapProxy = require_manifest_system_deps.buildUdsNativeCapProxy;
215662
216086
  exports.builderMountedCapNames = builderMountedCapNames;
@@ -215899,7 +216323,7 @@ var require_enums = __commonJS({
215899
216323
  "../types/dist/enums.js"(exports) {
215900
216324
  "use strict";
215901
216325
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
215902
- var require_event_category = require_event_category_BNJ9EE5B();
216326
+ var require_event_category = require_event_category_yW4s1MGD();
215903
216327
  var EventSourceType = /* @__PURE__ */ (function(EventSourceType2) {
215904
216328
  EventSourceType2["Addon"] = "addon";
215905
216329
  EventSourceType2["Core"] = "core";
@@ -215919,9 +216343,9 @@ var require_dist4 = __commonJS({
215919
216343
  "../types/dist/index.js"(exports) {
215920
216344
  "use strict";
215921
216345
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
215922
- var require_sleep = require_sleep_B1ZwxAhh();
215923
- var require_event_category = require_event_category_BNJ9EE5B();
215924
- var require_canonical_hash = require_canonical_hash_DNV8S5ET();
216346
+ var require_sleep = require_sleep_DXsYD0RX();
216347
+ var require_event_category = require_event_category_yW4s1MGD();
216348
+ var require_canonical_hash = require_canonical_hash_9lydiEzx();
215925
216349
  var require_enums2 = require_enums();
215926
216350
  var require_err_msg = require_err_msg_COpsHMw2();
215927
216351
  var zod = require_zod();
@@ -215935,18 +216359,19 @@ var require_dist4 = __commonJS({
215935
216359
  "scene",
215936
216360
  "motion",
215937
216361
  "object",
215938
- "audio"
216362
+ "audio",
216363
+ "mosaic"
215939
216364
  ];
215940
216365
  var OWNER_TYPES = new Set(MEDIA_OWNER_TYPES);
215941
216366
  var DIGITS = /^\d+$/;
215942
- function isOwnerType(value) {
216367
+ function isMediaOwnerType(value) {
215943
216368
  return OWNER_TYPES.has(value);
215944
216369
  }
215945
216370
  function parseMediaOwnerKey(key) {
215946
216371
  const parts = key.split(":");
215947
216372
  if (parts.length !== 3 && parts.length !== 4) return null;
215948
216373
  const [ownerType, ownerId, fileKind, timestamp] = parts;
215949
- if (ownerType === void 0 || !isOwnerType(ownerType)) return null;
216374
+ if (ownerType === void 0 || !isMediaOwnerType(ownerType)) return null;
215950
216375
  if (ownerId === void 0 || ownerId.length === 0) return null;
215951
216376
  if (fileKind === void 0 || fileKind.length === 0) return null;
215952
216377
  if (timestamp === void 0) return {
@@ -215971,6 +216396,7 @@ var require_dist4 = __commonJS({
215971
216396
  "object",
215972
216397
  "audio"
215973
216398
  ];
216399
+ var EventOwnerTypeSchema = zod.z.enum(EVENT_OWNER_TYPES);
215974
216400
  var EVENT_OWNER_TYPE_SET = new Set(EVENT_OWNER_TYPES);
215975
216401
  function isEventOwnerType(ownerType) {
215976
216402
  return EVENT_OWNER_TYPE_SET.has(ownerType);
@@ -216099,7 +216525,23 @@ var require_dist4 = __commonJS({
216099
216525
  "zerolatency",
216100
216526
  "film",
216101
216527
  "animation"
216102
- ]).optional()
216528
+ ]).optional(),
216529
+ /**
216530
+ * ONE slice per access unit.
216531
+ *
216532
+ * `-tune zerolatency` turns on x264's sliced threads, and a frame then leaves
216533
+ * the encoder as five NAL slices that share one RTP timestamp and carry one
216534
+ * marker bit. A libwebrtc depacketiser sees five frame-starts and one
216535
+ * frame-end per frame: the first pictures render and the video then freezes
216536
+ * for good while the audio, on its own plane, plays on. Measured on this hub
216537
+ * 2026-09-13 against the Echo, and reduced to one slice by this flag alone.
216538
+ *
216539
+ * A NAMED field and not a raw flag, because {@link EgressEncodeSchema} omits
216540
+ * `outputArgs` on purpose: an opaque array is part of the sharing key, so two
216541
+ * consumers meaning the same thing spelled differently would stop sharing one
216542
+ * child. Absent means "whatever the encoder does" — today's behaviour.
216543
+ */
216544
+ singleSlicePerFrame: zod.z.boolean().optional()
216103
216545
  });
216104
216546
  var AudioEncodeSchema = zod.z.union([zod.z.literal("passthrough"), zod.z.object({
216105
216547
  codec: zod.z.enum([
@@ -216172,7 +216614,11 @@ var require_dist4 = __commonJS({
216172
216614
  };
216173
216615
  var ALEXA_EGRESS_PROFILE = {
216174
216616
  ...BASE_LIVE_EGRESS_PROFILE,
216175
- audio: { codec: "opus" }
216617
+ audio: { codec: "opus" },
216618
+ video: {
216619
+ ...BASE_LIVE_EGRESS_PROFILE.video,
216620
+ singleSlicePerFrame: true
216621
+ }
216176
216622
  };
216177
216623
  var RATE_CONTROL_TIGHT = {
216178
216624
  kind: "cbr",
@@ -216260,7 +216706,8 @@ var require_dist4 = __commonJS({
216260
216706
  gopFrames: video.gopFrames ?? -1,
216261
216707
  bf: video.bf ?? -1,
216262
216708
  preset: video.preset ?? UNSET,
216263
- tune: video.tune ?? UNSET
216709
+ tune: video.tune ?? UNSET,
216710
+ singleSlicePerFrame: video.singleSlicePerFrame === void 0 ? UNSET : String(video.singleSlicePerFrame)
216264
216711
  };
216265
216712
  }
216266
216713
  function canonicalAudio(audio) {
@@ -222875,6 +223322,60 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
222875
223322
  filter: QueryFilterSchema.optional(),
222876
223323
  columns: zod.z.array(zod.z.string()).readonly().optional()
222877
223324
  }), zod.z.array(SettingsRecordSchema).readonly()),
223325
+ /**
223326
+ * Make a SLOT hold this row — insert it, or update whatever already
223327
+ * occupies the slot — and answer with the id the row HAS.
223328
+ *
223329
+ * ## Why the store needed this
223330
+ *
223331
+ * {@link set} is already an upsert, but its slot is the PRIMARY KEY: the
223332
+ * caller has to know the id to address the row. That is exactly what a
223333
+ * collection keyed by an `INTEGER` rowid alias cannot do — SQLite assigns
223334
+ * the id, so a writer whose uniqueness rule is "one row per
223335
+ * `(ownerKind, ownerId, kind, slot)`" has no id to name and no way to
223336
+ * express the rule. {@link insert} can express it (a UNIQUE index
223337
+ * arbitrates) but only by THROWING at the loser of a race, and the loser
223338
+ * here is a legitimate re-capture, not an error.
223339
+ *
223340
+ * Getting there without this method means read-then-write: query the slot,
223341
+ * then `insert` or `update`. Two statements instead of one, a race between
223342
+ * them, and a recovery path that has to recognise a UNIQUE violation by its
223343
+ * MESSAGE — across a process boundary, because the store lives behind an
223344
+ * RPC door. A string match would be the whole gate, and a store that
223345
+ * rephrased its error would lose the row silently. One statement has no
223346
+ * such gate (D482).
223347
+ *
223348
+ * ## The contract
223349
+ *
223350
+ * `conflict` names the DECLARED columns that identify the slot. They must
223351
+ * be covered by a UNIQUE index on the collection — SQLite resolves an
223352
+ * `ON CONFLICT` target against its indexes and REFUSES the statement when
223353
+ * none matches, so a wrong list is a loud error on the first write, never a
223354
+ * silently duplicated row. An empty list is refused rather than passed on:
223355
+ * `ON CONFLICT()` is not valid SQL, and the intent it would most likely
223356
+ * encode ("no slot, just insert") is {@link insert}.
223357
+ *
223358
+ * Row shape is {@link insert}'s: `record.id` is used when the collection
223359
+ * needs a supplied key and IGNORED when the primary key is an `INTEGER`
223360
+ * rowid alias — exactly as `insert` and `insertMany` already treat it.
223361
+ *
223362
+ * Returns the id either way: the one SQLite assigned on an insert, or the
223363
+ * one the row it updated already had. A caller cannot tell which happened,
223364
+ * and deliberately — every caller wants the slot's id, and one that needed
223365
+ * to distinguish creation from replacement would have to read first anyway.
223366
+ */
223367
+ upsert: require_sleep.method(zod.z.object({
223368
+ namespace: zod.z.string().optional(),
223369
+ collection: zod.z.string(),
223370
+ /** Declared columns identifying the slot; must be covered by a UNIQUE
223371
+ * index on the collection. Never empty. */
223372
+ conflict: zod.z.array(zod.z.string()).readonly(),
223373
+ record: BulkRecordSchema
223374
+ }), zod.z.object({
223375
+ /** The id the row HAS: assigned by SQLite on an insert, or the existing
223376
+ * row's own id on an update. */
223377
+ id: zod.z.union([zod.z.string(), zod.z.number()])
223378
+ }), { kind: "mutation" }),
222878
223379
  /** Insert a new record. */
222879
223380
  insert: require_sleep.method(zod.z.object({
222880
223381
  namespace: zod.z.string().optional(),
@@ -223118,6 +223619,20 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
223118
223619
  kind: "mutation",
223119
223620
  auth: "admin"
223120
223621
  }),
223622
+ /**
223623
+ * Make a slot hold this row, and answer with the id the row HAS. The
223624
+ * engine half of `settings-store.upsert` — read that docblock for why the
223625
+ * store needed a slot that is not the primary key (D482).
223626
+ */
223627
+ upsert: require_sleep.method(zod.z.object({
223628
+ namespace: zod.z.string().optional(),
223629
+ collection: zod.z.string(),
223630
+ conflict: zod.z.array(zod.z.string()).readonly(),
223631
+ record: BulkRecordSchema
223632
+ }), zod.z.object({ id: zod.z.union([zod.z.string(), zod.z.number()]) }), {
223633
+ kind: "mutation",
223634
+ auth: "admin"
223635
+ }),
223121
223636
  /** Insert many records in ONE transaction. All or nothing. */
223122
223637
  insertMany: require_sleep.method(zod.z.object({
223123
223638
  namespace: zod.z.string().optional(),
@@ -230347,8 +230862,8 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
230347
230862
  var TrackSnapshotSchema = zod.z.object({
230348
230863
  timestamp: zod.z.number(),
230349
230864
  position: TrackPositionSchema,
230350
- /** MediaStore key; resolve via `getTrackMedia({ trackId })`. */
230351
- mediaKey: zod.z.string()
230865
+ /** The snapshot's media row id (D482); resolve via `listTrackMedia({ trackId })`. */
230866
+ mediaId: zod.z.number().int()
230352
230867
  });
230353
230868
  var TrackEnvelopeSchema = zod.z.object({
230354
230869
  minX: zod.z.number(),
@@ -230788,14 +231303,14 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
230788
231303
  * pixel-space `bbox` onto a displayed image. Omitted in slim projection. */
230789
231304
  frameWidth: zod.z.number().optional(),
230790
231305
  frameHeight: zod.z.number().optional(),
230791
- /** MediaStore key for the crop attached to this event (if any). */
230792
- mediaKey: zod.z.string().optional(),
230793
- /** Design B: MediaStore key of the track's native-resolution key frame (the
231306
+ /** Media row id of the crop attached to this event (if any) — D482. */
231307
+ mediaId: zod.z.number().int().optional(),
231308
+ /** Design B: media row id of the track's native-resolution key frame (the
230794
231309
  * best-detection full frame). Resolve via the event-media data-plane
230795
- * (`/addon/<addonId>/event-media/<keyFrameMediaKey>`) for a detail view that
231310
+ * (`/addon/<addonId>/event-media/m/<keyFrameMediaId>`) for a detail view that
230796
231311
  * draws `bbox` over the native frame. Absent on legacy rows / non-decoded
230797
- * sources — consumers fall back to `mediaKey` (the tight crop). */
230798
- keyFrameMediaKey: zod.z.string().optional(),
231312
+ * sources — consumers fall back to `mediaId` (the tight crop). */
231313
+ keyFrameMediaId: zod.z.number().int().optional(),
230799
231314
  /** Populated by B5 (recording playback URL for this event). */
230800
231315
  mediaUrl: zod.z.string().optional(),
230801
231316
  /** The parent track's key-event importance [0,1], propagated to every object
@@ -230832,7 +231347,19 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
230832
231347
  "sceneFrame"
230833
231348
  ]);
230834
231349
  var MediaFileRefSchema = zod.z.object({
230835
- key: zod.z.string(),
231350
+ /**
231351
+ * The media row's OWN id — the rowid SQLite assigned it (D482).
231352
+ *
231353
+ * It used to be the row's composite key, `<ownerType>:<ownerId>:<fileKind>
231354
+ * [:<timestampMs>]`, which embedded a FOREIGN id. D474 made event ids
231355
+ * per-table rowid aliases, so `object:101314` and `motion:101314` are two
231356
+ * different rows that spell the same number, and a track whose
231357
+ * `bestEventId` was an object event was served a motion event's snapshot —
231358
+ * a night-time thumbnail on an afternoon track, with no error anywhere. A
231359
+ * surrogate id cannot name the wrong row's owner, because it names no owner
231360
+ * at all.
231361
+ */
231362
+ mediaId: zod.z.number().int(),
230836
231363
  kind: MediaFileKindEnum,
230837
231364
  sizeBytes: zod.z.number(),
230838
231365
  timestamp: zod.z.number()
@@ -230900,7 +231427,7 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
230900
231427
  annotationCount: zod.z.number().int()
230901
231428
  });
230902
231429
  var RetrainFrameCandidateSchema = zod.z.object({
230903
- mediaKey: zod.z.string(),
231430
+ mediaId: zod.z.number().int(),
230904
231431
  kind: MediaFileKindEnum,
230905
231432
  timestamp: zod.z.number(),
230906
231433
  sizeBytes: zod.z.number().int(),
@@ -230913,7 +231440,7 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
230913
231440
  deviceId: zod.z.number(),
230914
231441
  trackId: zod.z.string(),
230915
231442
  /** Provenance only. It may already point at nothing — that is expected. */
230916
- sourceMediaKey: zod.z.string(),
231443
+ sourceMediaId: zod.z.number().int(),
230917
231444
  sourceKind: MediaFileKindEnum,
230918
231445
  sizeBytes: zod.z.number().int(),
230919
231446
  width: zod.z.number().int(),
@@ -230928,7 +231455,7 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
230928
231455
  var RetrainFrameSelectionSchema = zod.z.object({
230929
231456
  copied: zod.z.array(RetrainFrameSchema).readonly(),
230930
231457
  refused: zod.z.array(zod.z.object({
230931
- sourceMediaKey: zod.z.string(),
231458
+ sourceMediaId: zod.z.number().int(),
230932
231459
  reason: RetrainCopyRefusalSchema
230933
231460
  })).readonly()
230934
231461
  });
@@ -230936,7 +231463,7 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
230936
231463
  candidates: zod.z.array(RetrainFrameCandidateSchema).readonly(),
230937
231464
  copies: zod.z.array(RetrainFrameSchema).readonly(),
230938
231465
  /** What the page pre-selects — the native key frame when one survives. */
230939
- autoPickMediaKey: zod.z.string().optional()
231466
+ autoPickMediaId: zod.z.number().int().optional()
230940
231467
  });
230941
231468
  var RetrainAssistSubjectSchema = zod.z.discriminatedUnion("kind", [zod.z.object({
230942
231469
  kind: zod.z.literal("package"),
@@ -231029,7 +231556,7 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
231029
231556
  lastActiveAt: zod.z.number(),
231030
231557
  sealedAt: zod.z.number().nullable(),
231031
231558
  memberCount: zod.z.number().int().nonnegative(),
231032
- groupShotKey: zod.z.string().nullable()
231559
+ groupShotMediaId: zod.z.number().int().nullable()
231033
231560
  });
231034
231561
  var SUMMARIES_MAX_LIMIT = 200;
231035
231562
  var SUMMARIES_DEFAULT_LIMIT = 50;
@@ -231037,13 +231564,91 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
231037
231564
  deviceIds: zod.z.array(zod.z.number()).min(1),
231038
231565
  since: zod.z.number().optional(),
231039
231566
  until: zod.z.number().optional(),
231040
- limit: zod.z.number().int().min(1).max(200).default(50)
231567
+ limit: zod.z.number().int().min(1).max(200).default(50),
231568
+ /** The same member-wise filter {@link listRecentSummaries} takes — one
231569
+ * meaning of "dog" on every summary surface. */
231570
+ classes: zod.z.array(zod.z.string().min(1).max(60)).max(40).optional()
231571
+ });
231572
+ var SummaryMemberSchema = zod.z.object({
231573
+ trackId: zod.z.string(),
231574
+ /**
231575
+ * The track's class at the time it JOINED, or `null` when it was unresolved
231576
+ * and the track no longer exists to fill it.
231577
+ *
231578
+ * The join, not the latest opinion: class voting can re-decide a track's
231579
+ * class afterwards, and a group's composition is the history of who came
231580
+ * together. A consumer counts these to badge a thumbnail — "two people and a
231581
+ * dog" — rather than being handed a second, denormalised tally that would
231582
+ * drift from the members it claims to describe.
231583
+ */
231584
+ className: zod.z.string().nullable(),
231585
+ /** `primary` is the one member that carries the group's identity. */
231586
+ role: zod.z.enum([
231587
+ "primary",
231588
+ "sibling",
231589
+ "child"
231590
+ ]).nullable(),
231591
+ joinedAt: zod.z.number(),
231592
+ /** Tier 1 — the sub-class (`dog`, `van`), resolved from the member's track
231593
+ * at read time. Absent when nothing resolved, never an empty string. */
231594
+ label: zod.z.string().optional(),
231595
+ /** Tier 2 — the instance: a person's name, a plate. Absent when the pipeline
231596
+ * recognised nobody, and absent for a member whose track has been pruned —
231597
+ * a thumbnail that names the wrong person is worse than one naming nobody. */
231598
+ subLabel: zod.z.string().optional()
231041
231599
  });
231042
- var SummariesPageSchema = zod.z.object({ summaries: zod.z.array(SummarySchema).readonly() });
231043
231600
  var SummaryDetailSchema = zod.z.object({
231044
231601
  summary: SummarySchema,
231045
- /** Member track ids, in absorption order. */
231046
- trackIds: zod.z.array(zod.z.string()).readonly()
231602
+ /** Members in absorption order, oldest join first. */
231603
+ members: zod.z.array(SummaryMemberSchema).readonly()
231604
+ });
231605
+ var SummaryListItemSchema = zod.z.object({
231606
+ summary: SummarySchema,
231607
+ /** Class counts, most numerous first; `className: null` is a member whose
231608
+ * class never resolved, counted so the counts add up to `memberCount`. */
231609
+ classes: zod.z.array(zod.z.object({
231610
+ className: zod.z.string().nullable(),
231611
+ count: zod.z.number().int().positive()
231612
+ })).readonly()
231613
+ });
231614
+ var SummariesPageSchema = zod.z.object({ summaries: zod.z.array(SummaryListItemSchema).readonly() });
231615
+ var RecentSummariesQueryInput = zod.z.object({
231616
+ /** Devices to merge. An empty array yields an empty page. */
231617
+ deviceIds: zod.z.array(zod.z.number()),
231618
+ /** Window lower bound on `lastActiveAt` (inclusive). */
231619
+ since: zod.z.number().optional(),
231620
+ /** Window upper bound on `lastActiveAt` (inclusive). */
231621
+ until: zod.z.number().optional(),
231622
+ limit: zod.z.number().int().min(1).max(500).default(100),
231623
+ /** Opaque continuation cursor from a previous page's `nextCursor`. */
231624
+ cursor: zod.z.string().optional(),
231625
+ /**
231626
+ * Restrict to these classes — THE SAME FIELD `listRecentTracks` takes, and
231627
+ * deliberately the same name: the events filter tree emits one list of ticked
231628
+ * taxonomy nodes, and a summaries feed that called it something else would
231629
+ * make the operator's one filter component produce two shapes.
231630
+ *
231631
+ * A question about the MEMBERS: a group matches when ANY of them does. "Show
231632
+ * me the arrivals with a dog" has to return the group of four people who had
231633
+ * one with them; a filter on the group's own fields could only ever answer
231634
+ * about its primary.
231635
+ *
231636
+ * Matched against all THREE tiers of a member — the class (`animal`), the
231637
+ * sub-class (`dog`) and the instance (a name, a plate) — because which tier a
231638
+ * ticked node lives on is the taxonomy's business, not the caller's. `dog` is
231639
+ * an event kind in the tree and a tier-1 label on an `animal` track; a filter
231640
+ * that read only the class would answer "animal" and never "dog".
231641
+ *
231642
+ * ABSENT or EMPTY means no filter — absent is not a selection of none.
231643
+ */
231644
+ classes: zod.z.array(zod.z.string().min(1).max(60)).max(40).optional()
231645
+ });
231646
+ var RecentSummariesPageSchema = zod.z.object({
231647
+ /** Ordered by (`lastActiveAt` DESC, id DESC). Same light item as
231648
+ * {@link listSummaries} — one list shape, so a card renders the same
231649
+ * whichever feed drew it. */
231650
+ summaries: zod.z.array(SummaryListItemSchema).readonly(),
231651
+ nextCursor: zod.z.string().nullable()
231047
231652
  });
231048
231653
  var RecentTracksPageSchema = zod.z.object({
231049
231654
  /** Merged page, ordered by (`lastSeen` DESC, `trackId` DESC). */
@@ -231396,6 +232001,11 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
231396
232001
  listRecentTracks: require_sleep.method(RecentTracksQueryInput, RecentTracksPageSchema),
231397
232002
  /** Newest first by `openedAt`, for a camera set, inside an optional window. */
231398
232003
  listSummaries: require_sleep.method(SummariesQueryInput, SummariesPageSchema),
232004
+ /**
232005
+ * The PAGED feed — the reel and the Events gallery. Same cursor contract as
232006
+ * {@link listRecentTracks}, so one screen cannot hold two ideas of newest.
232007
+ */
232008
+ listRecentSummaries: require_sleep.method(RecentSummariesQueryInput, RecentSummariesPageSchema),
231399
232009
  /** One summary with its member track ids; `null` for an id nobody wrote. */
231400
232010
  getSummary: require_sleep.method(zod.z.object({ id: zod.z.string() }), SummaryDetailSchema.nullable()),
231401
232011
  clearTracks: require_sleep.method(zod.z.object({ deviceId: zod.z.number() }), zod.z.void(), {
@@ -231925,7 +232535,7 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
231925
232535
  selectRetrainFrames: require_sleep.method(zod.z.object({
231926
232536
  deviceId: zod.z.number(),
231927
232537
  trackId: zod.z.string(),
231928
- mediaKeys: zod.z.array(zod.z.string()).min(1)
232538
+ mediaIds: zod.z.array(zod.z.number().int()).min(1)
231929
232539
  }), RetrainFrameSelectionSchema, {
231930
232540
  kind: "mutation",
231931
232541
  auth: "admin"
@@ -232089,8 +232699,29 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
232089
232699
  kind: "query",
232090
232700
  auth: "admin"
232091
232701
  }),
232702
+ /**
232703
+ * The media an EVENT owns.
232704
+ *
232705
+ * `ownerType` is REQUIRED, and that is the whole correction (D482). An
232706
+ * event is a row in ONE of three tables, and since D474 each numbers from
232707
+ * 1 independently: `motion:101314` and `object:101314` both exist. This
232708
+ * method took a bare `eventId` and the provider probed motion → object →
232709
+ * audio, stopping at the first hit — so on the live hub, where object
232710
+ * events own no media of their own and 299 883 of 300 559 media rows are
232711
+ * motion-owned, EVERY object event resolved to its motion namesake. A
232712
+ * track from 17:34 on camera 615 was served a snapshot from 22:35 eleven
232713
+ * days earlier, silently.
232714
+ *
232715
+ * D476 had already disambiguated the KEY (`motion:` vs `object:`); this is
232716
+ * the API catching up to it. Naming the table is not a "qualification" of
232717
+ * the ambiguity — a listing BY OWNER has no address to make surrogate: the
232718
+ * owner IS (table, id), and half of it is not a question.
232719
+ */
232092
232720
  getEventMedia: require_sleep.method(zod.z.object({
232093
- eventId: zod.z.string(),
232721
+ /** Which of the three event tables owns the row. */
232722
+ ownerType: EventOwnerTypeSchema,
232723
+ /** The event's rowid in that table (D474: an event id is a number). */
232724
+ eventId: zod.z.number().int(),
232094
232725
  kind: MediaFileKindEnum.optional(),
232095
232726
  deviceId: zod.z.number()
232096
232727
  }), zod.z.array(MediaFileSchema).readonly()),
@@ -232135,11 +232766,14 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
232135
232766
  * the live hub: one event's `fullFrameBoxed` is 2 824 077 B, base64'd to
232136
232767
  * ~3.8 MB, allocated whole in hub-main's heap, for a list of keys.
232137
232768
  *
232138
- * Same `deviceId` authorization subject as `getEventMedia`, and the same
232139
- * rows — this is a projection of that method, never a different question.
232769
+ * Same `deviceId` authorization subject as `getEventMedia`, the same
232770
+ * REQUIRED `ownerType` (read that method's docblock for the night-time
232771
+ * thumbnail this closes — D482), and the same rows: this is a projection
232772
+ * of that method, never a different question.
232140
232773
  */
232141
232774
  listEventMedia: require_sleep.method(zod.z.object({
232142
- eventId: zod.z.string(),
232775
+ ownerType: EventOwnerTypeSchema,
232776
+ eventId: zod.z.number().int(),
232143
232777
  deviceId: zod.z.number()
232144
232778
  }), zod.z.array(MediaFileInfoSchema).readonly()),
232145
232779
  /**
@@ -237840,8 +238474,8 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
237840
238474
  id: zod.z.string(),
237841
238475
  name: zod.z.string(),
237842
238476
  sampleCount: zod.z.number().int().nonnegative(),
237843
- coverMediaKey: zod.z.string().optional(),
237844
- /** Inline base64 of the cover sample's crop, resolved from `coverMediaKey`.
238477
+ coverMediaId: zod.z.number().int().optional(),
238478
+ /** Inline base64 of the cover sample's crop, resolved from `coverMediaId`.
237845
238479
  * Lets the UI render the person's face avatar instead of a placeholder icon. */
237846
238480
  coverBase64: zod.z.string().optional()
237847
238481
  });
@@ -237857,8 +238491,8 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
237857
238491
  enrolledAt: zod.z.number().int(),
237858
238492
  deviceId: zod.z.number().int().optional(),
237859
238493
  source: zod.z.enum(["detected", "photo"]),
237860
- /** The enrolled crop's media key, so the panel can show the evidence. */
237861
- mediaKey: zod.z.string().optional(),
238494
+ /** The enrolled crop's media row id, so the panel can show the evidence. */
238495
+ mediaId: zod.z.number().int().optional(),
237862
238496
  /**
237863
238497
  * False = the sample is stamped with a DIFFERENT face model, and a cosine
237864
238498
  * across feature spaces is a well-formed float with no meaning. Every number
@@ -237927,15 +238561,15 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
237927
238561
  */
237928
238562
  cropUrl: zod.z.string().optional(),
237929
238563
  /** Design B: the face bbox (pixel space) on the key frame — lets a detail
237930
- * view draw the box over the native `keyFrameMediaKey` frame. Absent on
238564
+ * view draw the box over the native `keyFrameMediaId` frame. Absent on
237931
238565
  * legacy rows written before design B. */
237932
238566
  faceBbox: BoundingBoxSchema.optional(),
237933
238567
  /** Design B: MediaStore key of the track's native-resolution key frame.
237934
238568
  * Fetch the native JPEG via the event-media data-plane
237935
- * (`/addon/<addonId>/event-media/<keyFrameMediaKey>`). Absent when the
238569
+ * (`/addon/<addonId>/event-media/m/<keyFrameMediaId>`). Absent when the
237936
238570
  * track produced no key frame (e.g. native/onboard source) — the UI falls
237937
238571
  * back to the inline `base64` face crop. */
237938
- keyFrameMediaKey: zod.z.string().optional(),
238572
+ keyFrameMediaId: zod.z.number().int().optional(),
237939
238573
  /** Winning identity-match cosine (0..1) for this face's track, when an
237940
238574
  * identity was auto-confirmed. Lets the UI surface WHY a face was assigned
237941
238575
  * (confidence badge / low-confidence audit). Absent on legacy rows and on
@@ -237973,7 +238607,9 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
237973
238607
  cohesion: zod.z.number()
237974
238608
  });
237975
238609
  var MediaFileLiteSchema$1 = zod.z.object({
237976
- key: zod.z.string(),
238610
+ /** The media row's own id — the same address `MediaFileRef.mediaId` carries
238611
+ * (D482). It was the row's composite key, which embedded the owner. */
238612
+ mediaId: zod.z.number().int(),
237977
238613
  kind: zod.z.string(),
237978
238614
  url: zod.z.string(),
237979
238615
  sizeBytes: zod.z.number(),
@@ -237995,7 +238631,7 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
237995
238631
  * covers inline, ~10 KB of base64 per row, on a query this UI mounts
237996
238632
  * four times and the viewer holds at `staleTime: 30_000`.
237997
238633
  *
237998
- * Nothing loses its avatar: `coverMediaKey` is already on every row and
238634
+ * Nothing loses its avatar: `coverMediaId` is already on every row and
237999
238635
  * the `event-media` plane serves that key `immutable` with an ETag.
238000
238636
  *
238001
238637
  * **This is an INPUT field, so it does not reach the addon until the
@@ -241265,8 +241901,8 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
241265
241901
  id: zod.z.string(),
241266
241902
  name: zod.z.string(),
241267
241903
  sampleCount: zod.z.number().int().nonnegative(),
241268
- coverMediaKey: zod.z.string().optional(),
241269
- /** Inline base64 of the cover sample's plate crop, resolved from `coverMediaKey`. */
241904
+ coverMediaId: zod.z.number().int().optional(),
241905
+ /** Inline base64 of the cover sample's plate crop, resolved from `coverMediaId`. */
241270
241906
  coverBase64: zod.z.string().optional()
241271
241907
  });
241272
241908
  var VehicleSampleInfoSchema = zod.z.object({
@@ -241299,7 +241935,7 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
241299
241935
  /** keyFrame parity: the plate bbox (pixel space) on the native key frame. */
241300
241936
  plateBbox: BoundingBoxSchema.optional(),
241301
241937
  /** keyFrame parity: MediaStore key of the track's native-resolution key frame. */
241302
- keyFrameMediaKey: zod.z.string().optional(),
241938
+ keyFrameMediaId: zod.z.number().int().optional(),
241303
241939
  base64: zod.z.string().optional(),
241304
241940
  /**
241305
241941
  * Same crop as a data-plane URL, always present when the plate has a stored
@@ -241310,7 +241946,9 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
241310
241946
  cropUrl: zod.z.string().optional()
241311
241947
  });
241312
241948
  var MediaFileLiteSchema = zod.z.object({
241313
- key: zod.z.string(),
241949
+ /** The media row's own id — the same address `MediaFileRef.mediaId` carries
241950
+ * (D482). It was the row's composite key, which embedded the owner. */
241951
+ mediaId: zod.z.number().int(),
241314
241952
  kind: zod.z.string(),
241315
241953
  url: zod.z.string(),
241316
241954
  sizeBytes: zod.z.number(),
@@ -241384,7 +242022,7 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
241384
242022
  listVehicles: require_sleep.method(zod.z.object({
241385
242023
  /** Inline {@link VehicleSchema.coverBase64} on every row. Default
241386
242024
  * `false` — the vehicle twin of `faceGallery.listIdentities`'s
241387
- * option; `coverMediaKey` + the `event-media` plane carry the picture.
242025
+ * option; `coverMediaId` + the `event-media` plane carry the picture.
241388
242026
  * INPUT field: stripped by the hub router until the train ships, which
241389
242027
  * resolves to `false` and is exactly the intended default. */
241390
242028
  includeCrops: zod.z.boolean().optional()
@@ -242897,7 +243535,14 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
242897
243535
  modelId: zod.z.string(),
242898
243536
  condition: SceneConditionSchema,
242899
243537
  capturedAt: zod.z.number(),
242900
- thumbnailMediaId: zod.z.string().optional(),
243538
+ /**
243539
+ * The reference thumbnail's media ROW id (D482).
243540
+ *
243541
+ * The name already said `mediaId` while the value was the row's composite
243542
+ * key — a leftover that read as done and was not. It is the row's own id
243543
+ * now, addressed at `/addon/<addonId>/event-media/m/<id>`.
243544
+ */
243545
+ thumbnailMediaId: zod.z.number().int().optional(),
242901
243546
  /** Whole-frame (downscaled) embedding captured alongside the ROI crop. The
242902
243547
  * anti-view-shift anchor: a bumped camera, a PTZ preset or a re-aim makes the
242903
243548
  * normalized rect frame a different piece of world, and the scene would
@@ -243964,7 +244609,29 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
243964
244609
  * disarmed the channels it did not mention would make the Levels page and
243965
244610
  * the Diagnostics page fight over the same value.
243966
244611
  */
243967
- channels: zod.z.array(LogChannelWindowPatchSchema).readonly().optional()
244612
+ channels: zod.z.array(LogChannelWindowPatchSchema).readonly().optional(),
244613
+ /**
244614
+ * How many days the analytics OPS LOG is kept — the audit trail of what
244615
+ * retention actually deleted.
244616
+ *
244617
+ * It lives HERE, on the logging document, and not on the analytics addon's
244618
+ * settings form, on the operator's instruction: every other log-ish window in
244619
+ * this system is configured through this one document, and a retention audit
244620
+ * configured somewhere else is a second place to look when the question is
244621
+ * "what happened to my data".
244622
+ *
244623
+ * That placement has a cost worth stating: this document ships in the
244624
+ * framework closure, so this knob needs a published `@camstack/server` while
244625
+ * the four windows beside it (D485) reach a node on `camstack deploy`.
244626
+ *
244627
+ * `retention-model.ts` argued this one must NOT follow a device window,
244628
+ * because the audit trail is the history of the SWEEP and not of the camera.
244629
+ * That argument stands and is untouched — what changes is that 30 days stops
244630
+ * being a constant nobody can reach. `0` keeps it forever. The floor is 1 day
244631
+ * rather than 0-as-delete: an audit log truncated to nothing is precisely the
244632
+ * state in which the next 9.5 GiB leak cannot be explained.
244633
+ */
244634
+ opsLogRetentionDays: zod.z.number().int().min(0).max(3650).optional()
243968
244635
  });
243969
244636
  var ReportedLoadContributionSchema = LoadContributionSchema.extend({ addonId: zod.z.string() });
243970
244637
  var ReportedFailureContributionSchema = FailureContributionSchema.extend({ addonId: zod.z.string() });
@@ -244003,6 +244670,14 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
244003
244670
  channels: zod.z.array(LogChannelDescriptorSchema).readonly(),
244004
244671
  /** The channels ARMED right now, each with its deadline. */
244005
244672
  activeChannels: zod.z.array(LogChannelWindowStateSchema).readonly(),
244673
+ /**
244674
+ * The ops-log window in days, as it is in force. `0` = kept forever.
244675
+ *
244676
+ * Reported rather than left to the caller's memory of what it wrote: this is
244677
+ * the value the analytics sweep will actually use, and an operator asking how
244678
+ * long their audit trail lives should not have to infer it from a default.
244679
+ */
244680
+ opsLogRetentionDays: zod.z.number().int().min(0),
244006
244681
  persisted: zod.z.boolean()
244007
244682
  });
244008
244683
  var systemCapability = {
@@ -244826,7 +245501,7 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
244826
245501
  /** Enrichment label carried from the source track (identity / plate). */
244827
245502
  label: zod.z.string().optional(),
244828
245503
  /** Native-resolution key-frame media key for the parked object's best image. */
244829
- keyFrameMediaKey: zod.z.string().optional()
245504
+ keyFrameMediaId: zod.z.number().int().optional()
244830
245505
  });
244831
245506
  var CameraOccupancySnapshotSchema = zod.z.object({
244832
245507
  /** Frame timestamp of the inference result that produced this snapshot. */
@@ -250039,6 +250714,12 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
250039
250714
  addonId: null,
250040
250715
  access: "create"
250041
250716
  },
250717
+ "dataStoreProvider.upsert": {
250718
+ capName: "data-store-provider",
250719
+ capScope: "system",
250720
+ addonId: null,
250721
+ access: "create"
250722
+ },
250042
250723
  "dayNight.getOptions": {
250043
250724
  capName: "day-night",
250044
250725
  capScope: "device",
@@ -252475,6 +253156,12 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
252475
253156
  addonId: null,
252476
253157
  access: "view"
252477
253158
  },
253159
+ "pipelineAnalytics.listRecentSummaries": {
253160
+ capName: "pipeline-analytics",
253161
+ capScope: "device",
253162
+ addonId: null,
253163
+ access: "view"
253164
+ },
252478
253165
  "pipelineAnalytics.listRecentTracks": {
252479
253166
  capName: "pipeline-analytics",
252480
253167
  capScope: "device",
@@ -253903,6 +254590,12 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
253903
254590
  addonId: null,
253904
254591
  access: "create"
253905
254592
  },
254593
+ "settingsStore.upsert": {
254594
+ capName: "settings-store",
254595
+ capScope: "system",
254596
+ addonId: null,
254597
+ access: "create"
254598
+ },
253906
254599
  "smtpProvider.getStatus": {
253907
254600
  capName: "smtp-provider",
253908
254601
  capScope: "system",
@@ -256560,6 +257253,11 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
256560
257253
  form: "single",
256561
257254
  optional: true
256562
257255
  }],
257256
+ "pipelineAnalytics.listRecentSummaries": [{
257257
+ name: "deviceIds",
257258
+ form: "array",
257259
+ optional: false
257260
+ }],
256563
257261
  "pipelineAnalytics.listRecentTracks": [{
256564
257262
  name: "deviceIds",
256565
257263
  form: "array",
@@ -258420,6 +259118,7 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
258420
259118
  get: (input) => dispatch("settingsStore", "get", "query", input),
258421
259119
  set: (input) => dispatch("settingsStore", "set", "mutation", input),
258422
259120
  query: (input) => dispatch("settingsStore", "query", "query", input),
259121
+ upsert: (input) => dispatch("settingsStore", "upsert", "mutation", input),
258423
259122
  insert: (input) => dispatch("settingsStore", "insert", "mutation", input),
258424
259123
  insertMany: (input) => dispatch("settingsStore", "insertMany", "mutation", input),
258425
259124
  update: (input) => dispatch("settingsStore", "update", "mutation", input),
@@ -261567,6 +262266,7 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
261567
262266
  exports.EventMediaCoverageSchema = EventMediaCoverageSchema;
261568
262267
  exports.EventMediaKindSchema = EventMediaKindSchema;
261569
262268
  exports.EventMediaProductionSchema = EventMediaProductionSchema;
262269
+ exports.EventOwnerTypeSchema = EventOwnerTypeSchema;
261570
262270
  exports.EventSourceType = require_enums2.EventSourceType$1;
261571
262271
  exports.ExportBytesSchema = ExportBytesSchema;
261572
262272
  exports.ExportDenseRangeSchema = ExportDenseRangeSchema;
@@ -262539,6 +263239,7 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
262539
263239
  exports.isFirstLevelMacroClass = isFirstLevelMacroClass;
262540
263240
  exports.isIsolatedBuiltin = isIsolatedBuiltin;
262541
263241
  exports.isLocationEnabled = isLocationEnabled;
263242
+ exports.isMediaOwnerType = isMediaOwnerType;
262542
263243
  exports.isNode = isNode;
262543
263244
  exports.isObjectInput = isObjectInput;
262544
263245
  exports.isOccupancyRule = isOccupancyRule;
@@ -264364,6 +265065,15 @@ var require_server_root = __commonJS({
264364
265065
  __name(buildNpmRegistryArgs, "buildNpmRegistryArgs");
264365
265066
  var NPM_VIEW_TIMEOUT_MS = 2e4;
264366
265067
  var NPM_INSTALL_TIMEOUT_MS = 15 * 6e4;
265068
+ var CLOSURE_ALLOW_SCRIPTS = {
265069
+ "@camstack/server": true,
265070
+ "better-sqlite3": true,
265071
+ "node-av": true,
265072
+ "node-pty": true,
265073
+ ssh2: true,
265074
+ "cpu-features": true,
265075
+ esbuild: true
265076
+ };
264367
265077
  var RESTART_REASON_PREFIX = "server-update";
264368
265078
  var STALE_TRANSIENT_MS = 24 * 60 * 60 * 1e3;
264369
265079
  function readWrapperProbes() {
@@ -264411,6 +265121,7 @@ var require_server_root = __commonJS({
264411
265121
  dataDir;
264412
265122
  execNpm;
264413
265123
  ensureNativePrebuildsFn;
265124
+ applyClosurePatchesFn;
264414
265125
  env;
264415
265126
  readWrapperProbesFn;
264416
265127
  now;
@@ -264439,6 +265150,7 @@ var require_server_root = __commonJS({
264439
265150
  };
264440
265151
  });
264441
265152
  this.ensureNativePrebuildsFn = options.ensureNativePrebuilds ?? (async () => void 0);
265153
+ this.applyClosurePatchesFn = options.applyClosurePatches ?? (async () => void 0);
264442
265154
  this.env = options.env ?? process.env;
264443
265155
  this.readWrapperProbesFn = options.readWrapperProbes ?? readWrapperProbes;
264444
265156
  this.now = options.now ?? Date.now;
@@ -264754,7 +265466,8 @@ var require_server_root = __commonJS({
264754
265466
  } else {
264755
265467
  fs6.writeFileSync(path6.join(stagingDir, "package.json"), JSON.stringify({
264756
265468
  name: "camstack-node-root",
264757
- private: true
265469
+ private: true,
265470
+ allowScripts: CLOSURE_ALLOW_SCRIPTS
264758
265471
  }, null, 2), "utf-8");
264759
265472
  await this.execNpm([
264760
265473
  ...installArgs,
@@ -264787,6 +265500,15 @@ var require_server_root = __commonJS({
264787
265500
  if (missingNatives.length > 0) {
264788
265501
  throw new Error(`staged closure missing native prebuilds: ${missingNatives.join(", ")} \u2014 refusing to arm a swap that would break the forked runners`);
264789
265502
  }
265503
+ try {
265504
+ await this.applyClosurePatchesFn(stagingDir);
265505
+ } catch (err) {
265506
+ this.logger.warn("closure-patch apply step failed \u2014 validator will decide", {
265507
+ meta: {
265508
+ error: err instanceof Error ? err.message : String(err)
265509
+ }
265510
+ });
265511
+ }
264790
265512
  const unpatched = findUnappliedClosurePatches(stagingDir);
264791
265513
  if (unpatched.length > 0) {
264792
265514
  throw new Error(`staged closure did not apply its shipped patches: ${unpatched.join(", ")} \u2014 refusing to arm a swap into an unpatched closure`);
@@ -264834,6 +265556,7 @@ var require_server_root = __commonJS({
264834
265556
  return {
264835
265557
  name: "camstack-node-root",
264836
265558
  private: true,
265559
+ allowScripts: CLOSURE_ALLOW_SCRIPTS,
264837
265560
  dependencies: {
264838
265561
  [this.spec.packageName]: fileRef(rootTgz)
264839
265562
  },
@@ -395791,6 +396514,78 @@ var require_system_ensure_prebuilds = __commonJS({
395791
396514
  }
395792
396515
  });
395793
396516
 
396517
+ // ../../server/backend/dist/core/server-update/system-apply-closure-patches.js
396518
+ var require_system_apply_closure_patches = __commonJS({
396519
+ "../../server/backend/dist/core/server-update/system-apply-closure-patches.js"(exports) {
396520
+ "use strict";
396521
+ var __createBinding = exports && exports.__createBinding || (Object.create ? (function(o, m, k, k2) {
396522
+ if (k2 === void 0) k2 = k;
396523
+ var desc = Object.getOwnPropertyDescriptor(m, k);
396524
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
396525
+ desc = { enumerable: true, get: function() {
396526
+ return m[k];
396527
+ } };
396528
+ }
396529
+ Object.defineProperty(o, k2, desc);
396530
+ }) : (function(o, m, k, k2) {
396531
+ if (k2 === void 0) k2 = k;
396532
+ o[k2] = m[k];
396533
+ }));
396534
+ var __setModuleDefault = exports && exports.__setModuleDefault || (Object.create ? (function(o, v) {
396535
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
396536
+ }) : function(o, v) {
396537
+ o["default"] = v;
396538
+ });
396539
+ var __importStar = exports && exports.__importStar || /* @__PURE__ */ (function() {
396540
+ var ownKeys = function(o) {
396541
+ ownKeys = Object.getOwnPropertyNames || function(o2) {
396542
+ var ar = [];
396543
+ for (var k in o2) if (Object.prototype.hasOwnProperty.call(o2, k)) ar[ar.length] = k;
396544
+ return ar;
396545
+ };
396546
+ return ownKeys(o);
396547
+ };
396548
+ return function(mod) {
396549
+ if (mod && mod.__esModule) return mod;
396550
+ var result = {};
396551
+ if (mod != null) {
396552
+ for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
396553
+ }
396554
+ __setModuleDefault(result, mod);
396555
+ return result;
396556
+ };
396557
+ })();
396558
+ Object.defineProperty(exports, "__esModule", { value: true });
396559
+ exports.buildSystemApplyClosurePatches = buildSystemApplyClosurePatches;
396560
+ var node_child_process_1 = __require("child_process");
396561
+ var fs = __importStar(__require("fs"));
396562
+ var path = __importStar(__require("path"));
396563
+ var node_util_1 = __require("util");
396564
+ var execFileAsync = (0, node_util_1.promisify)(node_child_process_1.execFile);
396565
+ var APPLIER_REL = ["node_modules", "@camstack", "server", "scripts", "closure-postinstall.mjs"];
396566
+ var APPLY_TIMEOUT_MS = 6e4;
396567
+ function buildSystemApplyClosurePatches(logger) {
396568
+ return async (closureDir) => {
396569
+ const applier = path.join(closureDir, ...APPLIER_REL);
396570
+ if (!fs.existsSync(applier)) {
396571
+ logger.debug("closure ships no patch applier \u2014 nothing to apply", {
396572
+ meta: { applier }
396573
+ });
396574
+ return;
396575
+ }
396576
+ const { stdout, stderr } = await execFileAsync(process.execPath, [applier], {
396577
+ cwd: path.dirname(path.dirname(applier)),
396578
+ timeout: APPLY_TIMEOUT_MS
396579
+ });
396580
+ const output = `${stdout}${stderr}`.trim();
396581
+ if (output.length > 0) {
396582
+ logger.info("closure patches applied", { meta: { output } });
396583
+ }
396584
+ };
396585
+ }
396586
+ }
396587
+ });
396588
+
395794
396589
  // ../../server/backend/dist/core/server-update/system-exec-npm.js
395795
396590
  var require_system_exec_npm = __commonJS({
395796
396591
  "../../server/backend/dist/core/server-update/system-exec-npm.js"(exports) {
@@ -396178,6 +396973,7 @@ var require_agent_update_service = __commonJS({
396178
396973
  var system_1 = require_dist3();
396179
396974
  var types_1 = require_dist4();
396180
396975
  var system_ensure_prebuilds_js_1 = require_system_ensure_prebuilds();
396976
+ var system_apply_closure_patches_js_1 = require_system_apply_closure_patches();
396181
396977
  var system_exec_npm_js_1 = require_system_exec_npm();
396182
396978
  var update_availability_emitter_js_1 = require_update_availability_emitter();
396183
396979
  var update_availability_store_js_1 = require_update_availability_store();
@@ -396266,6 +397062,11 @@ var require_agent_update_service = __commonJS({
396266
397062
  // ships the identical bare Node, so its `applyServerUpdate` staging would
396267
397063
  // hit the same source-only `better-sqlite3` miss without this.
396268
397064
  ensureNativePrebuilds: options.ensureNativePrebuilds ?? (0, system_ensure_prebuilds_js_1.buildSystemEnsureNativePrebuilds)(options.logger),
397065
+ // Apply the closure patches ourselves. npm 12 blocks the root package's
397066
+ // postinstall by default, and a silently-unpatched closure is refused by
397067
+ // the validator — an update that can never apply. Idempotent, so this
397068
+ // costs nothing where npm did run the lifecycle.
397069
+ applyClosurePatches: options.applyClosurePatches ?? (0, system_apply_closure_patches_js_1.buildSystemApplyClosurePatches)(options.logger),
396269
397070
  env: options.env,
396270
397071
  now: options.now
396271
397072
  });
@@ -420705,7 +421506,7 @@ var require_logging_settings = __commonJS({
420705
421506
  "../../server/backend/dist/api/core/logging-settings.js"(exports) {
420706
421507
  "use strict";
420707
421508
  Object.defineProperty(exports, "__esModule", { value: true });
420708
- exports.LoggingSettingsService = exports.MAX_CHANNEL_WINDOW_MS = exports.EMPTY_LOG_CHANNEL_PLANE = exports.HUB_NODE_ID = exports.LOGGING_SETTINGS_KEY = void 0;
421509
+ exports.LoggingSettingsService = exports.MAX_CHANNEL_WINDOW_MS = exports.EMPTY_LOG_CHANNEL_PLANE = exports.OPS_LOG_RETENTION_DEFAULT_DAYS = exports.HUB_NODE_ID = exports.LOGGING_SETTINGS_KEY = void 0;
420709
421510
  exports.buildLogChannelPlane = buildLogChannelPlane;
420710
421511
  exports.toLoggingSettingsRecord = toLoggingSettingsRecord;
420711
421512
  exports.resolveLevel = resolveLevel;
@@ -420721,6 +421522,7 @@ var require_logging_settings = __commonJS({
420721
421522
  var SYSTEM_SETTINGS_COLLECTION = "system-settings";
420722
421523
  exports.HUB_NODE_ID = "hub";
420723
421524
  var LOG_LEVELS = ["debug", "info", "warn", "error"];
421525
+ exports.OPS_LOG_RETENTION_DEFAULT_DAYS = 30;
420724
421526
  exports.EMPTY_LOG_CHANNEL_PLANE = {
420725
421527
  declarations: async () => [],
420726
421528
  apply: async () => {
@@ -420802,6 +421604,9 @@ var require_logging_settings = __commonJS({
420802
421604
  if (levelChanged) {
420803
421605
  next = mergeLevel(next, scope, component, patch.level ?? null, this.now());
420804
421606
  }
421607
+ if (patch.opsLogRetentionDays !== void 0) {
421608
+ next = { ...next, opsLogRetentionDays: patch.opsLogRetentionDays, updatedAt: this.now() };
421609
+ }
420805
421610
  if (channelsChanged) {
420806
421611
  const declared = await this.channels.declarations();
420807
421612
  const rejected = validateChannelPatch(patch.channels ?? [], declared);
@@ -420891,6 +421696,7 @@ var require_logging_settings = __commonJS({
420891
421696
  activeWindows: await this.describeWindows(),
420892
421697
  channels: await this.declaredChannels(),
420893
421698
  activeChannels: describeChannelWindows(record ?? {}, this.now()),
421699
+ opsLogRetentionDays: record?.opsLogRetentionDays ?? exports.OPS_LOG_RETENTION_DEFAULT_DAYS,
420894
421700
  persisted: record !== null
420895
421701
  };
420896
421702
  }
@@ -434339,6 +435145,7 @@ var require_server_update_service = __commonJS({
434339
435145
  var index_js_1 = require_server_root();
434340
435146
  var update_availability_emitter_js_1 = require_update_availability_emitter();
434341
435147
  var system_ensure_prebuilds_js_1 = require_system_ensure_prebuilds();
435148
+ var system_apply_closure_patches_js_1 = require_system_apply_closure_patches();
434342
435149
  var system_exec_npm_js_1 = require_system_exec_npm();
434343
435150
  var ServerUpdateService = class extends index_js_1.RootUpdateService {
434344
435151
  updateAvailability;
@@ -434372,6 +435179,11 @@ var require_server_update_service = __commonJS({
434372
435179
  // native-prebuild validator refuses the swap (toolchain-less packaged
434373
435180
  // desktop). No-op on docker where the install already carried it.
434374
435181
  ensureNativePrebuilds: options.ensureNativePrebuilds ?? (0, system_ensure_prebuilds_js_1.buildSystemEnsureNativePrebuilds)(options.logger),
435182
+ // Apply the closure patches ourselves. npm 12 blocks the root package's
435183
+ // postinstall by default, and a silently-unpatched closure is refused by
435184
+ // the validator — an update that can never apply. Idempotent, so this
435185
+ // costs nothing where npm did run the lifecycle.
435186
+ applyClosurePatches: options.applyClosurePatches ?? (0, system_apply_closure_patches_js_1.buildSystemApplyClosurePatches)(options.logger),
434375
435187
  env: options.env,
434376
435188
  now: options.now
434377
435189
  });