camstack 1.2.131 → 1.2.134

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.
@@ -14522,7 +14522,7 @@ function date4(params) {
14522
14522
  // ../../node_modules/zod/v4/classic/external.js
14523
14523
  config(en_default());
14524
14524
 
14525
- // ../types/dist/sleep-DMghvp8F.mjs
14525
+ // ../types/dist/sleep-ox21Ig4I.mjs
14526
14526
  var WELL_KNOWN_TABS = [
14527
14527
  {
14528
14528
  id: "overview",
@@ -20299,7 +20299,7 @@ var detectionPipelineCapability = {
20299
20299
  var SourceInfoSchema = external_exports.object({
20300
20300
  /** Live dispatch key — mutable when the source system allows rename. */
20301
20301
  id: external_exports.string(),
20302
- /** Source system tag — e.g. 'homeassistant' | 'reolink' | 'frigate'. */
20302
+ /** Source system tag — e.g. 'homeassistant' | 'reolink' | 'onvif'. */
20303
20303
  system: external_exports.string(),
20304
20304
  /** Immutable upstream identifier when available (HA `unique_id`, … ).
20305
20305
  * Used to detect rename when `id` changes. */
@@ -24872,7 +24872,7 @@ var NcRuleInputSchema = external_exports.object({
24872
24872
  * The measured seven-person arrival on device 590 spans 110 s with every
24873
24873
  * internal gap under 30 s. A 12 s fixed window cuts it into three groups; an
24874
24874
  * idle cutoff holds it as one and ends it when the arrival actually ends.
24875
- * 30 is Frigate's shipped value for the same decision.
24875
+ * 30 s is a widely shipped value for the same decision.
24876
24876
  *
24877
24877
  * ### What it replaces
24878
24878
  *
@@ -26729,6 +26729,12 @@ var ZoneCrossingSchema = external_exports.object({
26729
26729
  /** Zone display name at crossing time (falls back to the id). */
26730
26730
  zoneName: external_exports.string().optional()
26731
26731
  });
26732
+ var ZoneOverlapSchema = external_exports.object({
26733
+ zoneId: external_exports.string(),
26734
+ zoneName: external_exports.string().optional(),
26735
+ /** Percentage of the BOX area inside the zone, 0–100. */
26736
+ overlapPct: external_exports.number()
26737
+ });
26732
26738
  var ObjectEventSchema = external_exports.object({
26733
26739
  ...BaseEventFields,
26734
26740
  kind: external_exports.literal("object"),
@@ -26753,6 +26759,35 @@ var ObjectEventSchema = external_exports.object({
26753
26759
  bbox: BoundingBoxSchema.optional(),
26754
26760
  /** Heavy JSON — omitted in slim projection. */
26755
26761
  zones: external_exports.array(external_exports.string()).readonly().optional(),
26762
+ /**
26763
+ * How far inside each stamped zone the box actually was, as a percentage of
26764
+ * the BOX area.
26765
+ *
26766
+ * Membership alone cannot express "at least a third of it inside", which is
26767
+ * the bar an operator argues with — and the number already existed: the
26768
+ * engine computed it, the pipeline logged it, and then discarded it. It
26769
+ * matters most on the events that carry no track, where a rule has nothing
26770
+ * else to judge by.
26771
+ */
26772
+ zoneOverlaps: external_exports.array(ZoneOverlapSchema).readonly().optional(),
26773
+ /**
26774
+ * Present when this event describes a detection the TRACKER refused, so it
26775
+ * has no track and never will.
26776
+ *
26777
+ * A zone-scoped immediate rule asks "is there an animal in the flowerbed
26778
+ * NOW?"; tracking answers a different question ("is this the same subject as
26779
+ * before?") whose confirmation threshold presumes continuity. On 2026-09-09 a
26780
+ * dog at 0.7729, 100% inside a watched zone, was refused three times in six
26781
+ * seconds with three different candidate ids — seven analysed frames in the
26782
+ * window, the subject in a handful of them, metres apart — and produced no
26783
+ * event at all.
26784
+ *
26785
+ * It is NAMED rather than merely implied by a missing `trackId`: an event
26786
+ * with no track and no reason is indistinguishable from a track whose media
26787
+ * went missing, and a consumer that asks this one for a best shot or a
26788
+ * history is asking for something that never existed.
26789
+ */
26790
+ spawnRefused: external_exports.string().optional(),
26756
26791
  /** Omitted in slim projection. */
26757
26792
  state: TrackStateSchema.optional(),
26758
26793
  /**
@@ -28232,6 +28267,35 @@ var NativeCropResultSchema = external_exports.object({
28232
28267
  */
28233
28268
  tier: external_exports.enum(["native", "ram-fullframe"]).optional()
28234
28269
  });
28270
+ var ParkedFrameKindSchema = external_exports.enum(["keyFrame", "thumbnail"]);
28271
+ var ParkRefusalSchema = external_exports.enum(["handle-gone", "encode-failed"]);
28272
+ var ParkTrackFrameResultSchema = external_exports.discriminatedUnion("parked", [external_exports.object({
28273
+ parked: external_exports.literal(true),
28274
+ /** The node holding the parcel — what a later retrieval must be pinned to. */
28275
+ nodeId: external_exports.string(),
28276
+ width: external_exports.number().int().positive(),
28277
+ height: external_exports.number().int().positive(),
28278
+ /** JPEG bytes the parcel costs on the node. */
28279
+ bytes: external_exports.number().int().nonnegative(),
28280
+ /** Whether this park replaced a parcel already held for the key. */
28281
+ replaced: external_exports.boolean()
28282
+ }), external_exports.object({
28283
+ parked: external_exports.literal(false),
28284
+ nodeId: external_exports.string(),
28285
+ reason: ParkRefusalSchema,
28286
+ /** Age of the handle at the park, on the runner's clock; null if unknown. */
28287
+ handleAgeMs: external_exports.number().nullable(),
28288
+ detail: external_exports.string().optional()
28289
+ })]);
28290
+ var ParkedTrackFrameSchema = external_exports.object({
28291
+ jpeg: external_exports.string(),
28292
+ width: external_exports.number().int().positive(),
28293
+ height: external_exports.number().int().positive(),
28294
+ /** The frame instant the parcel shows (the caller's clock, echoed back). */
28295
+ timestamp: external_exports.number(),
28296
+ /** When the node stored it (the node's clock). */
28297
+ parkedAt: external_exports.number()
28298
+ });
28235
28299
  var DetailParentSchema = external_exports.object({
28236
28300
  bbox: NativeCropBboxSchema,
28237
28301
  className: external_exports.string()
@@ -28477,7 +28541,7 @@ var RunnerCameraConfigSchema = external_exports.object({
28477
28541
  * - `analyzer`: ML/frame-diff motion detection (motion-wasm or other
28478
28542
  * analyzer providers) running on decoded frames in this runner.
28479
28543
  * - `onboard`: camera-native motion pushes (Reolink Baichuan, ONVIF
28480
- * analytics, Frigate motion). The provider emits ProviderMotion
28544
+ * analytics). The provider emits ProviderMotion
28481
28545
  * events; the orchestrator forwards to `reportMotion`.
28482
28546
  */
28483
28547
  motionSources: MotionSourcesSchema.default(["analyzer"]),
@@ -29008,7 +29072,60 @@ var pipelineRunnerCapability = {
29008
29072
  className: external_exports.string(),
29009
29073
  /** Camera the pixels came from. Diagnostics + log tags ONLY — never routing. */
29010
29074
  sourceDeviceId: external_exports.number()
29011
- }), RunStatelessStepResultSchema, { kind: "mutation" })
29075
+ }), RunStatelessStepResultSchema, { kind: "mutation" }),
29076
+ /**
29077
+ * PARK a frame for a track at the instant it is judged to matter
29078
+ * ([D422](../../../docs/decisions/adr-0422-a-relevant-frame-is-parked-when-it-becomes-relevant.md)).
29079
+ *
29080
+ * The hub's `BestDetectionTracker` — the single "best per track" policy —
29081
+ * concludes a frame is a track's best and calls this on the node that
29082
+ * owns `handle` (`nodePin(handle.nodeId)`), while the handle is young. The
29083
+ * runner cuts `bbox` from the native surface it already holds (a full
29084
+ * frame for `keyFrame`, the caller's subject window for `thumbnail`),
29085
+ * encodes ONE JPEG, and keeps it under `(deviceId, trackId, kind)`. Every
29086
+ * later consumer retrieves by that key (`getParkedTrackFrame`) — a lookup
29087
+ * that cannot miss on age. D52 holds: the rectangle is cut by the runner,
29088
+ * never a pre-cut tile the caller decided. D9/D18 hold: one compressed
29089
+ * encode at a decision point, never a stream.
29090
+ *
29091
+ * Idempotent per `(trackId, kind)`: a later park replaces (the ranking is
29092
+ * the hub's; this adds no second opinion), an out-of-order older instant
29093
+ * is ignored. Bounded per device and per node on the runner
29094
+ * (`parked-frame-store.ts`), oldest-first eviction, never a refusal for
29095
+ * space. A refusal names its reason and is logged on the runner with the
29096
+ * handle's measured age — it is never retried into a loop.
29097
+ */
29098
+ parkTrackFrame: method(external_exports.object({
29099
+ deviceId: external_exports.number(),
29100
+ /** Opaque to the runner — the hub's track id. */
29101
+ trackId: external_exports.string(),
29102
+ kind: ParkedFrameKindSchema,
29103
+ handle: FrameHandleSchema,
29104
+ /** Normalized [0,1] window to cut. `{0,0,1,1}` for a full frame. */
29105
+ bbox: NativeCropBboxSchema,
29106
+ /** Width cap for a full-frame park (the `keyFrame` native cap). */
29107
+ maxWidth: external_exports.number().int().positive().optional(),
29108
+ /** The frame instant (caller's clock) — orders parks for one key. */
29109
+ timestamp: external_exports.number()
29110
+ }), ParkTrackFrameResultSchema, { kind: "mutation" }),
29111
+ /**
29112
+ * Retrieve a parked parcel by `(deviceId, trackId, kind)`. Pinned to the
29113
+ * node that answered the park (`ParkTrackFrameResult.nodeId`). `null` means
29114
+ * nothing was parked under that key on this node — never "too old".
29115
+ */
29116
+ getParkedTrackFrame: method(external_exports.object({
29117
+ deviceId: external_exports.number(),
29118
+ trackId: external_exports.string(),
29119
+ kind: ParkedFrameKindSchema
29120
+ }), ParkedTrackFrameSchema.nullable()),
29121
+ /**
29122
+ * Drop every parcel of a track — the hub closed it. Idempotent. A track
29123
+ * whose release is lost ages out on the runner under a hard ceiling.
29124
+ */
29125
+ releaseParkedTrackFrames: method(external_exports.object({
29126
+ deviceId: external_exports.number(),
29127
+ trackId: external_exports.string()
29128
+ }), external_exports.object({ released: external_exports.number().int().nonnegative() }), { kind: "mutation" })
29012
29129
  }
29013
29130
  };
29014
29131
  var CameraPipelineConfigSchema = external_exports.object({
@@ -32606,8 +32723,8 @@ var batteryCapability = {
32606
32723
  /**
32607
32724
  * Runtime-state slice — every provider that registers this cap
32608
32725
  * stores the same shape under `device.runtimeState[battery]`.
32609
- * Cross-provider uniformity: a Reolink Argus, a Frigate sensor
32610
- * proxy, an ONVIF battery cam all read/write the same keys.
32726
+ * Cross-provider uniformity: a Reolink Argus, a sensor proxy,
32727
+ * an ONVIF battery cam all read/write the same keys.
32611
32728
  * Consumers (BatteryBadge, snapshot wrapper sleep gate) read once
32612
32729
  * via `device.runtimeState.getCapState('battery')` regardless of
32613
32730
  * the underlying driver.
@@ -34460,7 +34577,7 @@ var AvailableIntegrationTypeSchema = external_exports.object({
34460
34577
  * Which integration-marker cap the addon declared, so the wizard can
34461
34578
  * branch on CAP — never on addon name. `device-adoption` integrations
34462
34579
  * (Home Assistant, …) route through the broker step (Approach A);
34463
- * `device-provider` integrations (Reolink/Frigate/ONVIF) keep the
34580
+ * `device-provider` integrations (Reolink/ONVIF) keep the
34464
34581
  * legacy config → discovery flow.
34465
34582
  */
34466
34583
  kind: external_exports.enum(["device-adoption", "device-provider"]),
@@ -37714,9 +37831,11 @@ var RecordingManifestSchema = external_exports.object({
37714
37831
  });
37715
37832
  var RecordingDeviceUsageSchema = external_exports.object({
37716
37833
  deviceId: external_exports.number(),
37834
+ /** Bytes the ARCHIVE holds for this camera on this node's resolvable
37835
+ * recordings locations. */
37717
37836
  usedBytes: external_exports.number(),
37718
37837
  /**
37719
- * Start of this camera's OLDEST indexed segment, across every profile and
37838
+ * Start of this camera's OLDEST ARCHIVED segment, across every profile and
37720
37839
  * location — the "Oldest footage" column in Recordings → Storage, and the
37721
37840
  * only honest answer to "is retention actually holding?" per camera.
37722
37841
  *
@@ -37726,7 +37845,24 @@ var RecordingDeviceUsageSchema = external_exports.object({
37726
37845
  * (types) and the addon ship on different trains, and the addon is usually
37727
37846
  * the later of the two.
37728
37847
  */
37729
- oldestMs: external_exports.number().nullable().optional()
37848
+ oldestMs: external_exports.number().nullable().optional(),
37849
+ /** Segments the archive holds for this camera — the "M" beside `usedBytes`.
37850
+ * OPTIONAL for the same train-skew reason as `oldestMs`. */
37851
+ segments: external_exports.number().optional(),
37852
+ /**
37853
+ * RESIDENCY, not the archive: bytes the recorder process currently holds in
37854
+ * its RAM index — the live tail plus the hours a reader hydrated.
37855
+ *
37856
+ * It answers "what can be served without touching the disk", never "how much
37857
+ * footage this camera has". A UI that renders it must label it as such, and
37858
+ * must never total it as storage. OPTIONAL: a recorder predating D418 omits
37859
+ * it, and so does a node whose ledger could not answer.
37860
+ */
37861
+ residentBytes: external_exports.number().optional(),
37862
+ /** The residency counterpart of `oldestMs` — the oldest segment currently in
37863
+ * RAM, which on a healthy recorder is minutes ago and means nothing about
37864
+ * retention. `null` = nothing resident. */
37865
+ residentOldestMs: external_exports.number().nullable().optional()
37730
37866
  });
37731
37867
  var RecordingLocationUsageSchema = external_exports.object({
37732
37868
  /** StorageLocation id; null for the legacy/degraded single-root fallback. */
@@ -37760,6 +37896,17 @@ var RecordingStorageUsageSchema = external_exports.object({
37760
37896
  totalUsedBytes: external_exports.number(),
37761
37897
  devices: external_exports.array(RecordingDeviceUsageSchema),
37762
37898
  /**
37899
+ * WHERE `devices[]` came from, so an empty table is never mistaken for empty
37900
+ * disks (D418).
37901
+ *
37902
+ * `archive` = the durable hour ledger answered. `unavailable` = this node
37903
+ * declared no ledger and the recorder REFUSED rather than answering the
37904
+ * question with the resident index (D295 rule 3) — the rows are UNKNOWN, not
37905
+ * zero, and a UI must say so. OPTIONAL: a recorder predating D418 omits it,
37906
+ * and its rows are residency.
37907
+ */
37908
+ devicesRead: external_exports.enum(["archive", "unavailable"]).optional(),
37909
+ /**
37763
37910
  * Per-physical-volume capacity. OPTIONAL, and consumers must render the rest
37764
37911
  * of the payload without it: the hub serves this method through a BAKED
37765
37912
  * router, so a hub whose framework train predates a change to this array
@@ -44528,6 +44675,24 @@ var METHOD_ACCESS_MAP = Object.freeze({
44528
44675
  addonId: null,
44529
44676
  access: "view"
44530
44677
  },
44678
+ "pipelineRunner.getParkedTrackFrame": {
44679
+ capName: "pipeline-runner",
44680
+ capScope: "system",
44681
+ addonId: null,
44682
+ access: "view"
44683
+ },
44684
+ "pipelineRunner.parkTrackFrame": {
44685
+ capName: "pipeline-runner",
44686
+ capScope: "system",
44687
+ addonId: null,
44688
+ access: "create"
44689
+ },
44690
+ "pipelineRunner.releaseParkedTrackFrames": {
44691
+ capName: "pipeline-runner",
44692
+ capScope: "system",
44693
+ addonId: null,
44694
+ access: "create"
44695
+ },
44531
44696
  "pipelineRunner.reportMotion": {
44532
44697
  capName: "pipeline-runner",
44533
44698
  capScope: "system",
@@ -47805,6 +47970,21 @@ var METHOD_DEVICE_SELECTORS = Object.freeze({
47805
47970
  form: "single",
47806
47971
  optional: false
47807
47972
  }],
47973
+ "pipelineRunner.getParkedTrackFrame": [{
47974
+ name: "deviceId",
47975
+ form: "single",
47976
+ optional: false
47977
+ }],
47978
+ "pipelineRunner.parkTrackFrame": [{
47979
+ name: "deviceId",
47980
+ form: "single",
47981
+ optional: false
47982
+ }],
47983
+ "pipelineRunner.releaseParkedTrackFrames": [{
47984
+ name: "deviceId",
47985
+ form: "single",
47986
+ optional: false
47987
+ }],
47808
47988
  "pipelineRunner.reportMotion": [{
47809
47989
  name: "deviceId",
47810
47990
  form: "single",
package/dist/cli.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  runDiscover
4
- } from "./chunk-FK6R4ZJQ.js";
4
+ } from "./chunk-LMISNMUF.js";
5
5
  import "./chunk-LMMQX4CK.js";
6
6
 
7
7
  // src/cli.ts
@@ -38,7 +38,7 @@ async function runServe(args) {
38
38
  ...typeof values.data === "string" ? { data: values.data } : {}
39
39
  };
40
40
  Object.assign(process.env, buildServeEnv(opts));
41
- await import("./launcher-XH2NRTWF.js");
41
+ await import("./launcher-CGCHY5QF.js");
42
42
  }
43
43
 
44
44
  // src/commands/agent.ts
@@ -83,7 +83,7 @@ async function runAgent(args) {
83
83
  ...typeof values.port === "string" ? { port: values.port } : {}
84
84
  };
85
85
  Object.assign(process.env, buildAgentEnv(opts));
86
- await import("./launcher-XH2NRTWF.js");
86
+ await import("./launcher-CGCHY5QF.js");
87
87
  }
88
88
 
89
89
  // src/commands/setup.ts
@@ -1130,7 +1130,7 @@ function isUnknown(_value) {
1130
1130
  return true;
1131
1131
  }
1132
1132
  async function resolveServerInteractive(presetNamespace) {
1133
- const { discoverNodes, resolveHubFromDiscovered, filterHubNodes, DEFAULT_HUB_HTTPS_PORT } = await import("./discover-Q75B3UUE.js");
1133
+ const { discoverNodes, resolveHubFromDiscovered, filterHubNodes, DEFAULT_HUB_HTTPS_PORT } = await import("./discover-R4IJGYTA.js");
1134
1134
  if (presetNamespace) {
1135
1135
  const spinner4 = clack.spinner();
1136
1136
  spinner4.start(`Discovering hub on LAN (namespace "${presetNamespace}")`);
@@ -5,7 +5,7 @@ import {
5
5
  filterHubNodes,
6
6
  resolveHubFromDiscovered,
7
7
  runDiscover
8
- } from "./chunk-FK6R4ZJQ.js";
8
+ } from "./chunk-LMISNMUF.js";
9
9
  import "./chunk-LMMQX4CK.js";
10
10
  export {
11
11
  DEFAULT_HUB_HTTPS_PORT,
@@ -23633,9 +23633,9 @@ var require_zod = __commonJS({
23633
23633
  }
23634
23634
  });
23635
23635
 
23636
- // ../system/dist/dist-9GQQ9F3s.js
23637
- var require_dist_9GQQ9F3s = __commonJS({
23638
- "../system/dist/dist-9GQQ9F3s.js"(exports) {
23636
+ // ../system/dist/dist-DYWqXngV.js
23637
+ var require_dist_DYWqXngV = __commonJS({
23638
+ "../system/dist/dist-DYWqXngV.js"(exports) {
23639
23639
  "use strict";
23640
23640
  var zod = require_zod();
23641
23641
  var EventCategory = /* @__PURE__ */ (function(EventCategory2) {
@@ -23768,7 +23768,6 @@ var require_dist_9GQQ9F3s = __commonJS({
23768
23768
  EventCategory2["PipelineAnalyticsPackagePickedUp"] = "pipeline-analytics.package-picked-up";
23769
23769
  EventCategory2["PipelineAnalyticsFaceGalleryChanged"] = "pipeline-analytics.face-gallery-changed";
23770
23770
  EventCategory2["PipelineAnalyticsPlateGalleryChanged"] = "pipeline-analytics.plate-gallery-changed";
23771
- EventCategory2["FrigateLiveEvent"] = "frigate.live-event";
23772
23771
  EventCategory2["CameraStreamsProfileSlotsChanged"] = "camera-streams.onProfileSlotsChanged";
23773
23772
  EventCategory2["StreamOnline"] = "stream.online";
23774
23773
  EventCategory2["StreamOffline"] = "stream.offline";
@@ -31042,7 +31041,7 @@ var require_dist_9GQQ9F3s = __commonJS({
31042
31041
  var SourceInfoSchema = zod.z.object({
31043
31042
  /** Live dispatch key — mutable when the source system allows rename. */
31044
31043
  id: zod.z.string(),
31045
- /** Source system tag — e.g. 'homeassistant' | 'reolink' | 'frigate'. */
31044
+ /** Source system tag — e.g. 'homeassistant' | 'reolink' | 'onvif'. */
31046
31045
  system: zod.z.string(),
31047
31046
  /** Immutable upstream identifier when available (HA `unique_id`, … ).
31048
31047
  * Used to detect rename when `id` changes. */
@@ -35642,7 +35641,7 @@ var require_dist_9GQQ9F3s = __commonJS({
35642
35641
  * The measured seven-person arrival on device 590 spans 110 s with every
35643
35642
  * internal gap under 30 s. A 12 s fixed window cuts it into three groups; an
35644
35643
  * idle cutoff holds it as one and ends it when the arrival actually ends.
35645
- * 30 is Frigate's shipped value for the same decision.
35644
+ * 30 s is a widely shipped value for the same decision.
35646
35645
  *
35647
35646
  * ### What it replaces
35648
35647
  *
@@ -37499,6 +37498,12 @@ var require_dist_9GQQ9F3s = __commonJS({
37499
37498
  /** Zone display name at crossing time (falls back to the id). */
37500
37499
  zoneName: zod.z.string().optional()
37501
37500
  });
37501
+ var ZoneOverlapSchema = zod.z.object({
37502
+ zoneId: zod.z.string(),
37503
+ zoneName: zod.z.string().optional(),
37504
+ /** Percentage of the BOX area inside the zone, 0–100. */
37505
+ overlapPct: zod.z.number()
37506
+ });
37502
37507
  var ObjectEventSchema = zod.z.object({
37503
37508
  ...BaseEventFields,
37504
37509
  kind: zod.z.literal("object"),
@@ -37523,6 +37528,35 @@ var require_dist_9GQQ9F3s = __commonJS({
37523
37528
  bbox: BoundingBoxSchema.optional(),
37524
37529
  /** Heavy JSON — omitted in slim projection. */
37525
37530
  zones: zod.z.array(zod.z.string()).readonly().optional(),
37531
+ /**
37532
+ * How far inside each stamped zone the box actually was, as a percentage of
37533
+ * the BOX area.
37534
+ *
37535
+ * Membership alone cannot express "at least a third of it inside", which is
37536
+ * the bar an operator argues with — and the number already existed: the
37537
+ * engine computed it, the pipeline logged it, and then discarded it. It
37538
+ * matters most on the events that carry no track, where a rule has nothing
37539
+ * else to judge by.
37540
+ */
37541
+ zoneOverlaps: zod.z.array(ZoneOverlapSchema).readonly().optional(),
37542
+ /**
37543
+ * Present when this event describes a detection the TRACKER refused, so it
37544
+ * has no track and never will.
37545
+ *
37546
+ * A zone-scoped immediate rule asks "is there an animal in the flowerbed
37547
+ * NOW?"; tracking answers a different question ("is this the same subject as
37548
+ * before?") whose confirmation threshold presumes continuity. On 2026-09-09 a
37549
+ * dog at 0.7729, 100% inside a watched zone, was refused three times in six
37550
+ * seconds with three different candidate ids — seven analysed frames in the
37551
+ * window, the subject in a handful of them, metres apart — and produced no
37552
+ * event at all.
37553
+ *
37554
+ * It is NAMED rather than merely implied by a missing `trackId`: an event
37555
+ * with no track and no reason is indistinguishable from a track whose media
37556
+ * went missing, and a consumer that asks this one for a best shot or a
37557
+ * history is asking for something that never existed.
37558
+ */
37559
+ spawnRefused: zod.z.string().optional(),
37526
37560
  /** Omitted in slim projection. */
37527
37561
  state: TrackStateSchema.optional(),
37528
37562
  /**
@@ -39001,6 +39035,35 @@ var require_dist_9GQQ9F3s = __commonJS({
39001
39035
  */
39002
39036
  tier: zod.z.enum(["native", "ram-fullframe"]).optional()
39003
39037
  });
39038
+ var ParkedFrameKindSchema = zod.z.enum(["keyFrame", "thumbnail"]);
39039
+ var ParkRefusalSchema = zod.z.enum(["handle-gone", "encode-failed"]);
39040
+ var ParkTrackFrameResultSchema = zod.z.discriminatedUnion("parked", [zod.z.object({
39041
+ parked: zod.z.literal(true),
39042
+ /** The node holding the parcel — what a later retrieval must be pinned to. */
39043
+ nodeId: zod.z.string(),
39044
+ width: zod.z.number().int().positive(),
39045
+ height: zod.z.number().int().positive(),
39046
+ /** JPEG bytes the parcel costs on the node. */
39047
+ bytes: zod.z.number().int().nonnegative(),
39048
+ /** Whether this park replaced a parcel already held for the key. */
39049
+ replaced: zod.z.boolean()
39050
+ }), zod.z.object({
39051
+ parked: zod.z.literal(false),
39052
+ nodeId: zod.z.string(),
39053
+ reason: ParkRefusalSchema,
39054
+ /** Age of the handle at the park, on the runner's clock; null if unknown. */
39055
+ handleAgeMs: zod.z.number().nullable(),
39056
+ detail: zod.z.string().optional()
39057
+ })]);
39058
+ var ParkedTrackFrameSchema = zod.z.object({
39059
+ jpeg: zod.z.string(),
39060
+ width: zod.z.number().int().positive(),
39061
+ height: zod.z.number().int().positive(),
39062
+ /** The frame instant the parcel shows (the caller's clock, echoed back). */
39063
+ timestamp: zod.z.number(),
39064
+ /** When the node stored it (the node's clock). */
39065
+ parkedAt: zod.z.number()
39066
+ });
39004
39067
  var DetailParentSchema = zod.z.object({
39005
39068
  bbox: NativeCropBboxSchema,
39006
39069
  className: zod.z.string()
@@ -39246,7 +39309,7 @@ var require_dist_9GQQ9F3s = __commonJS({
39246
39309
  * - `analyzer`: ML/frame-diff motion detection (motion-wasm or other
39247
39310
  * analyzer providers) running on decoded frames in this runner.
39248
39311
  * - `onboard`: camera-native motion pushes (Reolink Baichuan, ONVIF
39249
- * analytics, Frigate motion). The provider emits ProviderMotion
39312
+ * analytics). The provider emits ProviderMotion
39250
39313
  * events; the orchestrator forwards to `reportMotion`.
39251
39314
  */
39252
39315
  motionSources: MotionSourcesSchema.default(["analyzer"]),
@@ -39604,7 +39667,60 @@ var require_dist_9GQQ9F3s = __commonJS({
39604
39667
  className: zod.z.string(),
39605
39668
  /** Camera the pixels came from. Diagnostics + log tags ONLY — never routing. */
39606
39669
  sourceDeviceId: zod.z.number()
39607
- }), RunStatelessStepResultSchema, { kind: "mutation" })
39670
+ }), RunStatelessStepResultSchema, { kind: "mutation" }),
39671
+ /**
39672
+ * PARK a frame for a track at the instant it is judged to matter
39673
+ * ([D422](../../../docs/decisions/adr-0422-a-relevant-frame-is-parked-when-it-becomes-relevant.md)).
39674
+ *
39675
+ * The hub's `BestDetectionTracker` — the single "best per track" policy —
39676
+ * concludes a frame is a track's best and calls this on the node that
39677
+ * owns `handle` (`nodePin(handle.nodeId)`), while the handle is young. The
39678
+ * runner cuts `bbox` from the native surface it already holds (a full
39679
+ * frame for `keyFrame`, the caller's subject window for `thumbnail`),
39680
+ * encodes ONE JPEG, and keeps it under `(deviceId, trackId, kind)`. Every
39681
+ * later consumer retrieves by that key (`getParkedTrackFrame`) — a lookup
39682
+ * that cannot miss on age. D52 holds: the rectangle is cut by the runner,
39683
+ * never a pre-cut tile the caller decided. D9/D18 hold: one compressed
39684
+ * encode at a decision point, never a stream.
39685
+ *
39686
+ * Idempotent per `(trackId, kind)`: a later park replaces (the ranking is
39687
+ * the hub's; this adds no second opinion), an out-of-order older instant
39688
+ * is ignored. Bounded per device and per node on the runner
39689
+ * (`parked-frame-store.ts`), oldest-first eviction, never a refusal for
39690
+ * space. A refusal names its reason and is logged on the runner with the
39691
+ * handle's measured age — it is never retried into a loop.
39692
+ */
39693
+ parkTrackFrame: method(zod.z.object({
39694
+ deviceId: zod.z.number(),
39695
+ /** Opaque to the runner — the hub's track id. */
39696
+ trackId: zod.z.string(),
39697
+ kind: ParkedFrameKindSchema,
39698
+ handle: FrameHandleSchema,
39699
+ /** Normalized [0,1] window to cut. `{0,0,1,1}` for a full frame. */
39700
+ bbox: NativeCropBboxSchema,
39701
+ /** Width cap for a full-frame park (the `keyFrame` native cap). */
39702
+ maxWidth: zod.z.number().int().positive().optional(),
39703
+ /** The frame instant (caller's clock) — orders parks for one key. */
39704
+ timestamp: zod.z.number()
39705
+ }), ParkTrackFrameResultSchema, { kind: "mutation" }),
39706
+ /**
39707
+ * Retrieve a parked parcel by `(deviceId, trackId, kind)`. Pinned to the
39708
+ * node that answered the park (`ParkTrackFrameResult.nodeId`). `null` means
39709
+ * nothing was parked under that key on this node — never "too old".
39710
+ */
39711
+ getParkedTrackFrame: method(zod.z.object({
39712
+ deviceId: zod.z.number(),
39713
+ trackId: zod.z.string(),
39714
+ kind: ParkedFrameKindSchema
39715
+ }), ParkedTrackFrameSchema.nullable()),
39716
+ /**
39717
+ * Drop every parcel of a track — the hub closed it. Idempotent. A track
39718
+ * whose release is lost ages out on the runner under a hard ceiling.
39719
+ */
39720
+ releaseParkedTrackFrames: method(zod.z.object({
39721
+ deviceId: zod.z.number(),
39722
+ trackId: zod.z.string()
39723
+ }), zod.z.object({ released: zod.z.number().int().nonnegative() }), { kind: "mutation" })
39608
39724
  }
39609
39725
  };
39610
39726
  var CameraPipelineConfigSchema = zod.z.object({
@@ -43200,8 +43316,8 @@ var require_dist_9GQQ9F3s = __commonJS({
43200
43316
  /**
43201
43317
  * Runtime-state slice — every provider that registers this cap
43202
43318
  * stores the same shape under `device.runtimeState[battery]`.
43203
- * Cross-provider uniformity: a Reolink Argus, a Frigate sensor
43204
- * proxy, an ONVIF battery cam all read/write the same keys.
43319
+ * Cross-provider uniformity: a Reolink Argus, a sensor proxy,
43320
+ * an ONVIF battery cam all read/write the same keys.
43205
43321
  * Consumers (BatteryBadge, snapshot wrapper sleep gate) read once
43206
43322
  * via `device.runtimeState.getCapState('battery')` regardless of
43207
43323
  * the underlying driver.
@@ -45054,7 +45170,7 @@ var require_dist_9GQQ9F3s = __commonJS({
45054
45170
  * Which integration-marker cap the addon declared, so the wizard can
45055
45171
  * branch on CAP — never on addon name. `device-adoption` integrations
45056
45172
  * (Home Assistant, …) route through the broker step (Approach A);
45057
- * `device-provider` integrations (Reolink/Frigate/ONVIF) keep the
45173
+ * `device-provider` integrations (Reolink/ONVIF) keep the
45058
45174
  * legacy config → discovery flow.
45059
45175
  */
45060
45176
  kind: zod.z.enum(["device-adoption", "device-provider"]),
@@ -48306,9 +48422,11 @@ var require_dist_9GQQ9F3s = __commonJS({
48306
48422
  });
48307
48423
  var RecordingDeviceUsageSchema = zod.z.object({
48308
48424
  deviceId: zod.z.number(),
48425
+ /** Bytes the ARCHIVE holds for this camera on this node's resolvable
48426
+ * recordings locations. */
48309
48427
  usedBytes: zod.z.number(),
48310
48428
  /**
48311
- * Start of this camera's OLDEST indexed segment, across every profile and
48429
+ * Start of this camera's OLDEST ARCHIVED segment, across every profile and
48312
48430
  * location — the "Oldest footage" column in Recordings → Storage, and the
48313
48431
  * only honest answer to "is retention actually holding?" per camera.
48314
48432
  *
@@ -48318,7 +48436,24 @@ var require_dist_9GQQ9F3s = __commonJS({
48318
48436
  * (types) and the addon ship on different trains, and the addon is usually
48319
48437
  * the later of the two.
48320
48438
  */
48321
- oldestMs: zod.z.number().nullable().optional()
48439
+ oldestMs: zod.z.number().nullable().optional(),
48440
+ /** Segments the archive holds for this camera — the "M" beside `usedBytes`.
48441
+ * OPTIONAL for the same train-skew reason as `oldestMs`. */
48442
+ segments: zod.z.number().optional(),
48443
+ /**
48444
+ * RESIDENCY, not the archive: bytes the recorder process currently holds in
48445
+ * its RAM index — the live tail plus the hours a reader hydrated.
48446
+ *
48447
+ * It answers "what can be served without touching the disk", never "how much
48448
+ * footage this camera has". A UI that renders it must label it as such, and
48449
+ * must never total it as storage. OPTIONAL: a recorder predating D418 omits
48450
+ * it, and so does a node whose ledger could not answer.
48451
+ */
48452
+ residentBytes: zod.z.number().optional(),
48453
+ /** The residency counterpart of `oldestMs` — the oldest segment currently in
48454
+ * RAM, which on a healthy recorder is minutes ago and means nothing about
48455
+ * retention. `null` = nothing resident. */
48456
+ residentOldestMs: zod.z.number().nullable().optional()
48322
48457
  });
48323
48458
  var RecordingLocationUsageSchema = zod.z.object({
48324
48459
  /** StorageLocation id; null for the legacy/degraded single-root fallback. */
@@ -48352,6 +48487,17 @@ var require_dist_9GQQ9F3s = __commonJS({
48352
48487
  totalUsedBytes: zod.z.number(),
48353
48488
  devices: zod.z.array(RecordingDeviceUsageSchema),
48354
48489
  /**
48490
+ * WHERE `devices[]` came from, so an empty table is never mistaken for empty
48491
+ * disks (D418).
48492
+ *
48493
+ * `archive` = the durable hour ledger answered. `unavailable` = this node
48494
+ * declared no ledger and the recorder REFUSED rather than answering the
48495
+ * question with the resident index (D295 rule 3) — the rows are UNKNOWN, not
48496
+ * zero, and a UI must say so. OPTIONAL: a recorder predating D418 omits it,
48497
+ * and its rows are residency.
48498
+ */
48499
+ devicesRead: zod.z.enum(["archive", "unavailable"]).optional(),
48500
+ /**
48355
48501
  * Per-physical-volume capacity. OPTIONAL, and consumers must render the rest
48356
48502
  * of the payload without it: the hub serves this method through a BAKED
48357
48503
  * router, so a hub whose framework train predates a change to this array
@@ -55949,6 +56095,24 @@ var require_dist_9GQQ9F3s = __commonJS({
55949
56095
  addonId: null,
55950
56096
  access: "view"
55951
56097
  },
56098
+ "pipelineRunner.getParkedTrackFrame": {
56099
+ capName: "pipeline-runner",
56100
+ capScope: "system",
56101
+ addonId: null,
56102
+ access: "view"
56103
+ },
56104
+ "pipelineRunner.parkTrackFrame": {
56105
+ capName: "pipeline-runner",
56106
+ capScope: "system",
56107
+ addonId: null,
56108
+ access: "create"
56109
+ },
56110
+ "pipelineRunner.releaseParkedTrackFrames": {
56111
+ capName: "pipeline-runner",
56112
+ capScope: "system",
56113
+ addonId: null,
56114
+ access: "create"
56115
+ },
55952
56116
  "pipelineRunner.reportMotion": {
55953
56117
  capName: "pipeline-runner",
55954
56118
  capScope: "system",
@@ -59226,6 +59390,21 @@ var require_dist_9GQQ9F3s = __commonJS({
59226
59390
  form: "single",
59227
59391
  optional: false
59228
59392
  }],
59393
+ "pipelineRunner.getParkedTrackFrame": [{
59394
+ name: "deviceId",
59395
+ form: "single",
59396
+ optional: false
59397
+ }],
59398
+ "pipelineRunner.parkTrackFrame": [{
59399
+ name: "deviceId",
59400
+ form: "single",
59401
+ optional: false
59402
+ }],
59403
+ "pipelineRunner.releaseParkedTrackFrames": [{
59404
+ name: "deviceId",
59405
+ form: "single",
59406
+ optional: false
59407
+ }],
59229
59408
  "pipelineRunner.reportMotion": [{
59230
59409
  name: "deviceId",
59231
59410
  form: "single",
@@ -61308,7 +61487,7 @@ var require_alerts_addon = __commonJS({
61308
61487
  [Symbol.toStringTag]: { value: "Module" }
61309
61488
  });
61310
61489
  require_chunk_Cek0wNdY();
61311
- var require_dist10 = require_dist_9GQQ9F3s();
61490
+ var require_dist10 = require_dist_DYWqXngV();
61312
61491
  function selectExpired(alerts, cutoffMs) {
61313
61492
  return alerts.filter((a) => a.createdAt < cutoffMs).sort((a, b) => a.createdAt - b.createdAt).map((a) => a.id);
61314
61493
  }
@@ -62127,7 +62306,7 @@ var require_console_logging = __commonJS({
62127
62306
  [Symbol.toStringTag]: { value: "Module" }
62128
62307
  });
62129
62308
  require_chunk_Cek0wNdY();
62130
- var require_dist10 = require_dist_9GQQ9F3s();
62309
+ var require_dist10 = require_dist_DYWqXngV();
62131
62310
  var require_formatter = require_formatter_DqAKDlvN();
62132
62311
  var LEVEL_RANK = {
62133
62312
  debug: 0,
@@ -62221,7 +62400,7 @@ var require_core_blocks_addon = __commonJS({
62221
62400
  "use strict";
62222
62401
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
62223
62402
  var require_chunk = require_chunk_Cek0wNdY();
62224
- var require_dist10 = require_dist_9GQQ9F3s();
62403
+ var require_dist10 = require_dist_DYWqXngV();
62225
62404
  var node_crypto = __require("crypto");
62226
62405
  var node_fs_promises = __require("fs/promises");
62227
62406
  node_fs_promises = require_chunk.__toESM(node_fs_promises);
@@ -63118,11 +63297,11 @@ var require_core_blocks = __commonJS({
63118
63297
  }
63119
63298
  });
63120
63299
 
63121
- // ../system/dist/retired-settings-keys-DfdSH46H.js
63122
- var require_retired_settings_keys_DfdSH46H = __commonJS({
63123
- "../system/dist/retired-settings-keys-DfdSH46H.js"(exports) {
63300
+ // ../system/dist/retired-settings-keys-CXLIB19R.js
63301
+ var require_retired_settings_keys_CXLIB19R = __commonJS({
63302
+ "../system/dist/retired-settings-keys-CXLIB19R.js"(exports) {
63124
63303
  "use strict";
63125
- var require_dist10 = require_dist_9GQQ9F3s();
63304
+ var require_dist10 = require_dist_DYWqXngV();
63126
63305
  function settingsStoreIsAuthoritativeHere(env) {
63127
63306
  const raw = (env["CAMSTACK_ROLE"] ?? "").trim().toLowerCase();
63128
63307
  return raw === "" || raw === "hub";
@@ -65357,8 +65536,8 @@ var require_device_manager_addon = __commonJS({
65357
65536
  [Symbol.toStringTag]: { value: "Module" }
65358
65537
  });
65359
65538
  require_chunk_Cek0wNdY();
65360
- var require_dist10 = require_dist_9GQQ9F3s();
65361
- var require_retired_settings_keys = require_retired_settings_keys_DfdSH46H();
65539
+ var require_dist10 = require_dist_DYWqXngV();
65540
+ var require_retired_settings_keys = require_retired_settings_keys_CXLIB19R();
65362
65541
  var node_crypto = __require("crypto");
65363
65542
  var _camstack_types_node = require_node();
65364
65543
  var JOB_HISTORY = 20;
@@ -70983,7 +71162,7 @@ var require_hub_forwarder = __commonJS({
70983
71162
  [Symbol.toStringTag]: { value: "Module" }
70984
71163
  });
70985
71164
  require_chunk_Cek0wNdY();
70986
- var require_dist10 = require_dist_9GQQ9F3s();
71165
+ var require_dist10 = require_dist_DYWqXngV();
70987
71166
  var require_formatter = require_formatter_DqAKDlvN();
70988
71167
  var DEFAULT_OUTBOUND_BUFFER_SIZE = 500;
70989
71168
  var HubForwarderDestination = class {
@@ -71120,7 +71299,7 @@ var require_liveness_monitor_addon = __commonJS({
71120
71299
  "use strict";
71121
71300
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
71122
71301
  require_chunk_Cek0wNdY();
71123
- var require_dist10 = require_dist_9GQQ9F3s();
71302
+ var require_dist10 = require_dist_DYWqXngV();
71124
71303
  var NO_DEVICES = "liveness:no-devices";
71125
71304
  var ALL_OFFLINE = "liveness:all-devices-offline";
71126
71305
  var NO_FOOTAGE_PREFIX = "liveness:no-footage:";
@@ -71316,7 +71495,7 @@ var require_local_auth_addon = __commonJS({
71316
71495
  [Symbol.toStringTag]: { value: "Module" }
71317
71496
  });
71318
71497
  var require_chunk = require_chunk_Cek0wNdY();
71319
- var require_dist10 = require_dist_9GQQ9F3s();
71498
+ var require_dist10 = require_dist_DYWqXngV();
71320
71499
  var node_crypto = __require("crypto");
71321
71500
  node_crypto = require_chunk.__toESM(node_crypto);
71322
71501
  var crypto$1 = __require("crypto");
@@ -79129,7 +79308,7 @@ var require_loki_logging = __commonJS({
79129
79308
  [Symbol.toStringTag]: { value: "Module" }
79130
79309
  });
79131
79310
  require_chunk_Cek0wNdY();
79132
- var require_dist10 = require_dist_9GQQ9F3s();
79311
+ var require_dist10 = require_dist_DYWqXngV();
79133
79312
  function sanitizeLabelName(raw) {
79134
79313
  const replaced = raw.replaceAll(/[^a-zA-Z0-9_]/g, "_");
79135
79314
  return /^[a-zA-Z_]/.test(replaced) ? replaced : `_${replaced}`;
@@ -79694,7 +79873,7 @@ var require_native_metrics_addon = __commonJS({
79694
79873
  [Symbol.toStringTag]: { value: "Module" }
79695
79874
  });
79696
79875
  var require_chunk = require_chunk_Cek0wNdY();
79697
- var require_dist10 = require_dist_9GQQ9F3s();
79876
+ var require_dist10 = require_dist_DYWqXngV();
79698
79877
  var node_fs_promises = __require("fs/promises");
79699
79878
  var node_child_process = __require("child_process");
79700
79879
  var node_util = __require("util");
@@ -82278,7 +82457,7 @@ var require_filesystem_storage_addon = __commonJS({
82278
82457
  [Symbol.toStringTag]: { value: "Module" }
82279
82458
  });
82280
82459
  var require_chunk = require_chunk_Cek0wNdY();
82281
- var require_dist10 = require_dist_9GQQ9F3s();
82460
+ var require_dist10 = require_dist_DYWqXngV();
82282
82461
  var node_crypto = __require("crypto");
82283
82462
  var node_fs_promises = __require("fs/promises");
82284
82463
  var node_path = __require("path");
@@ -83394,8 +83573,8 @@ var require_sqlite_settings_addon = __commonJS({
83394
83573
  [Symbol.toStringTag]: { value: "Module" }
83395
83574
  });
83396
83575
  var require_chunk = require_chunk_Cek0wNdY();
83397
- var require_dist10 = require_dist_9GQQ9F3s();
83398
- var require_retired_settings_keys = require_retired_settings_keys_DfdSH46H();
83576
+ var require_dist10 = require_dist_DYWqXngV();
83577
+ var require_retired_settings_keys = require_retired_settings_keys_CXLIB19R();
83399
83578
  var node_crypto = __require("crypto");
83400
83579
  var node_fs = __require("fs");
83401
83580
  var node_module = __require("module");
@@ -85899,7 +86078,7 @@ var require_storage_orchestrator_addon = __commonJS({
85899
86078
  [Symbol.toStringTag]: { value: "Module" }
85900
86079
  });
85901
86080
  var require_chunk = require_chunk_Cek0wNdY();
85902
- var require_dist10 = require_dist_9GQQ9F3s();
86081
+ var require_dist10 = require_dist_DYWqXngV();
85903
86082
  var require_hub_cap_forward = require_hub_cap_forward_DmHNjbB0();
85904
86083
  var zod = require_zod();
85905
86084
  var node_crypto = __require("crypto");
@@ -89549,7 +89728,7 @@ var require_system_config_addon = __commonJS({
89549
89728
  [Symbol.toStringTag]: { value: "Module" }
89550
89729
  });
89551
89730
  require_chunk_Cek0wNdY();
89552
- var require_dist10 = require_dist_9GQQ9F3s();
89731
+ var require_dist10 = require_dist_DYWqXngV();
89553
89732
  var SECTION_TITLES = {
89554
89733
  server: "Server",
89555
89734
  auth: "Authentication"
@@ -107610,7 +107789,7 @@ var require_winston_logging = __commonJS({
107610
107789
  [Symbol.toStringTag]: { value: "Module" }
107611
107790
  });
107612
107791
  var require_chunk = require_chunk_Cek0wNdY();
107613
- var require_dist10 = require_dist_9GQQ9F3s();
107792
+ var require_dist10 = require_dist_DYWqXngV();
107614
107793
  var require_formatter = require_formatter_DqAKDlvN();
107615
107794
  var node_path = __require("path");
107616
107795
  node_path = require_chunk.__toESM(node_path);
@@ -109479,9 +109658,9 @@ ${(0, node_fs.readFileSync)(ca.caCertPath, "utf-8").trimEnd()}
109479
109658
  }
109480
109659
  });
109481
109660
 
109482
- // ../types/dist/event-category-BVo6ta6_.js
109483
- var require_event_category_BVo6ta6 = __commonJS({
109484
- "../types/dist/event-category-BVo6ta6_.js"(exports) {
109661
+ // ../types/dist/event-category-BNJ9EE5B.js
109662
+ var require_event_category_BNJ9EE5B = __commonJS({
109663
+ "../types/dist/event-category-BNJ9EE5B.js"(exports) {
109485
109664
  "use strict";
109486
109665
  var EventCategory = /* @__PURE__ */ (function(EventCategory2) {
109487
109666
  EventCategory2["SystemBoot"] = "system.boot";
@@ -109613,7 +109792,6 @@ var require_event_category_BVo6ta6 = __commonJS({
109613
109792
  EventCategory2["PipelineAnalyticsPackagePickedUp"] = "pipeline-analytics.package-picked-up";
109614
109793
  EventCategory2["PipelineAnalyticsFaceGalleryChanged"] = "pipeline-analytics.face-gallery-changed";
109615
109794
  EventCategory2["PipelineAnalyticsPlateGalleryChanged"] = "pipeline-analytics.plate-gallery-changed";
109616
- EventCategory2["FrigateLiveEvent"] = "frigate.live-event";
109617
109795
  EventCategory2["CameraStreamsProfileSlotsChanged"] = "camera-streams.onProfileSlotsChanged";
109618
109796
  EventCategory2["StreamOnline"] = "stream.online";
109619
109797
  EventCategory2["StreamOffline"] = "stream.offline";
@@ -109648,11 +109826,11 @@ var require_event_category_BVo6ta6 = __commonJS({
109648
109826
  }
109649
109827
  });
109650
109828
 
109651
- // ../types/dist/sleep-Bo9cUOXp.js
109652
- var require_sleep_Bo9cUOXp = __commonJS({
109653
- "../types/dist/sleep-Bo9cUOXp.js"(exports) {
109829
+ // ../types/dist/sleep-CTHjJilA.js
109830
+ var require_sleep_CTHjJilA = __commonJS({
109831
+ "../types/dist/sleep-CTHjJilA.js"(exports) {
109654
109832
  "use strict";
109655
- var require_event_category = require_event_category_BVo6ta6();
109833
+ var require_event_category = require_event_category_BNJ9EE5B();
109656
109834
  var zod = require_zod();
109657
109835
  var WELL_KNOWN_TABS = [
109658
109836
  {
@@ -112672,7 +112850,10 @@ var require_sleep_Bo9cUOXp = __commonJS({
112672
112850
  pipelineRunner: {
112673
112851
  detachCamera: (input) => dispatchSystem("pipelineRunner", "detachCamera", "mutation", input),
112674
112852
  getCameraMetrics: (input) => dispatchSystem("pipelineRunner", "getCameraMetrics", "query", input),
112675
- runDetailSubtree: (input) => dispatchSystem("pipelineRunner", "runDetailSubtree", "mutation", input)
112853
+ runDetailSubtree: (input) => dispatchSystem("pipelineRunner", "runDetailSubtree", "mutation", input),
112854
+ parkTrackFrame: (input) => dispatchSystem("pipelineRunner", "parkTrackFrame", "mutation", input),
112855
+ getParkedTrackFrame: (input) => dispatchSystem("pipelineRunner", "getParkedTrackFrame", "query", input),
112856
+ releaseParkedTrackFrames: (input) => dispatchSystem("pipelineRunner", "releaseParkedTrackFrames", "mutation", input)
112676
112857
  },
112677
112858
  plateGallery: {
112678
112859
  listPlates: (input) => dispatchSystem("plateGallery", "listPlates", "query", input),
@@ -113383,8 +113564,8 @@ var require_addon = __commonJS({
113383
113564
  "../types/dist/addon.js"(exports) {
113384
113565
  "use strict";
113385
113566
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
113386
- var require_event_category = require_event_category_BVo6ta6();
113387
- var require_sleep = require_sleep_Bo9cUOXp();
113567
+ var require_event_category = require_event_category_BNJ9EE5B();
113568
+ var require_sleep = require_sleep_CTHjJilA();
113388
113569
  var require_err_msg = require_err_msg_COpsHMw2();
113389
113570
  var CAP_INPUT_DEFAULTS = Object.freeze({
113390
113571
  "addons": { "getLogs": { "limit": 100 } },
@@ -132317,7 +132498,7 @@ var require_dist3 = __commonJS({
132317
132498
  "use strict";
132318
132499
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
132319
132500
  var require_chunk = require_chunk_Cek0wNdY();
132320
- var require_dist10 = require_dist_9GQQ9F3s();
132501
+ var require_dist10 = require_dist_DYWqXngV();
132321
132502
  var require_builtins_alerts_alerts_addon = require_alerts_addon();
132322
132503
  require_alerts();
132323
132504
  var require_formatter = require_formatter_DqAKDlvN();
@@ -213417,7 +213598,7 @@ var require_enums = __commonJS({
213417
213598
  "../types/dist/enums.js"(exports) {
213418
213599
  "use strict";
213419
213600
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
213420
- var require_event_category = require_event_category_BVo6ta6();
213601
+ var require_event_category = require_event_category_BNJ9EE5B();
213421
213602
  var EventSourceType = /* @__PURE__ */ (function(EventSourceType2) {
213422
213603
  EventSourceType2["Addon"] = "addon";
213423
213604
  EventSourceType2["Core"] = "core";
@@ -213437,8 +213618,8 @@ var require_dist4 = __commonJS({
213437
213618
  "../types/dist/index.js"(exports) {
213438
213619
  "use strict";
213439
213620
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
213440
- var require_event_category = require_event_category_BVo6ta6();
213441
- var require_sleep = require_sleep_Bo9cUOXp();
213621
+ var require_event_category = require_event_category_BNJ9EE5B();
213622
+ var require_sleep = require_sleep_CTHjJilA();
213442
213623
  var require_canonical_hash = require_canonical_hash_DNV8S5ET();
213443
213624
  var require_enums2 = require_enums();
213444
213625
  var require_err_msg = require_err_msg_COpsHMw2();
@@ -220746,7 +220927,7 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
220746
220927
  var SourceInfoSchema = zod.z.object({
220747
220928
  /** Live dispatch key — mutable when the source system allows rename. */
220748
220929
  id: zod.z.string(),
220749
- /** Source system tag — e.g. 'homeassistant' | 'reolink' | 'frigate'. */
220930
+ /** Source system tag — e.g. 'homeassistant' | 'reolink' | 'onvif'. */
220750
220931
  system: zod.z.string(),
220751
220932
  /** Immutable upstream identifier when available (HA `unique_id`, … ).
220752
220933
  * Used to detect rename when `id` changes. */
@@ -225747,7 +225928,7 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
225747
225928
  * The measured seven-person arrival on device 590 spans 110 s with every
225748
225929
  * internal gap under 30 s. A 12 s fixed window cuts it into three groups; an
225749
225930
  * idle cutoff holds it as one and ends it when the arrival actually ends.
225750
- * 30 is Frigate's shipped value for the same decision.
225931
+ * 30 s is a widely shipped value for the same decision.
225751
225932
  *
225752
225933
  * ### What it replaces
225753
225934
  *
@@ -228046,6 +228227,12 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
228046
228227
  /** Zone display name at crossing time (falls back to the id). */
228047
228228
  zoneName: zod.z.string().optional()
228048
228229
  });
228230
+ var ZoneOverlapSchema = zod.z.object({
228231
+ zoneId: zod.z.string(),
228232
+ zoneName: zod.z.string().optional(),
228233
+ /** Percentage of the BOX area inside the zone, 0–100. */
228234
+ overlapPct: zod.z.number()
228235
+ });
228049
228236
  var ObjectEventSchema = zod.z.object({
228050
228237
  ...BaseEventFields,
228051
228238
  kind: zod.z.literal("object"),
@@ -228070,6 +228257,35 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
228070
228257
  bbox: BoundingBoxSchema.optional(),
228071
228258
  /** Heavy JSON — omitted in slim projection. */
228072
228259
  zones: zod.z.array(zod.z.string()).readonly().optional(),
228260
+ /**
228261
+ * How far inside each stamped zone the box actually was, as a percentage of
228262
+ * the BOX area.
228263
+ *
228264
+ * Membership alone cannot express "at least a third of it inside", which is
228265
+ * the bar an operator argues with — and the number already existed: the
228266
+ * engine computed it, the pipeline logged it, and then discarded it. It
228267
+ * matters most on the events that carry no track, where a rule has nothing
228268
+ * else to judge by.
228269
+ */
228270
+ zoneOverlaps: zod.z.array(ZoneOverlapSchema).readonly().optional(),
228271
+ /**
228272
+ * Present when this event describes a detection the TRACKER refused, so it
228273
+ * has no track and never will.
228274
+ *
228275
+ * A zone-scoped immediate rule asks "is there an animal in the flowerbed
228276
+ * NOW?"; tracking answers a different question ("is this the same subject as
228277
+ * before?") whose confirmation threshold presumes continuity. On 2026-09-09 a
228278
+ * dog at 0.7729, 100% inside a watched zone, was refused three times in six
228279
+ * seconds with three different candidate ids — seven analysed frames in the
228280
+ * window, the subject in a handful of them, metres apart — and produced no
228281
+ * event at all.
228282
+ *
228283
+ * It is NAMED rather than merely implied by a missing `trackId`: an event
228284
+ * with no track and no reason is indistinguishable from a track whose media
228285
+ * went missing, and a consumer that asks this one for a best shot or a
228286
+ * history is asking for something that never existed.
228287
+ */
228288
+ spawnRefused: zod.z.string().optional(),
228073
228289
  /** Omitted in slim projection. */
228074
228290
  state: TrackStateSchema.optional(),
228075
228291
  /**
@@ -229552,6 +229768,35 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
229552
229768
  */
229553
229769
  tier: zod.z.enum(["native", "ram-fullframe"]).optional()
229554
229770
  });
229771
+ var ParkedFrameKindSchema = zod.z.enum(["keyFrame", "thumbnail"]);
229772
+ var ParkRefusalSchema = zod.z.enum(["handle-gone", "encode-failed"]);
229773
+ var ParkTrackFrameResultSchema = zod.z.discriminatedUnion("parked", [zod.z.object({
229774
+ parked: zod.z.literal(true),
229775
+ /** The node holding the parcel — what a later retrieval must be pinned to. */
229776
+ nodeId: zod.z.string(),
229777
+ width: zod.z.number().int().positive(),
229778
+ height: zod.z.number().int().positive(),
229779
+ /** JPEG bytes the parcel costs on the node. */
229780
+ bytes: zod.z.number().int().nonnegative(),
229781
+ /** Whether this park replaced a parcel already held for the key. */
229782
+ replaced: zod.z.boolean()
229783
+ }), zod.z.object({
229784
+ parked: zod.z.literal(false),
229785
+ nodeId: zod.z.string(),
229786
+ reason: ParkRefusalSchema,
229787
+ /** Age of the handle at the park, on the runner's clock; null if unknown. */
229788
+ handleAgeMs: zod.z.number().nullable(),
229789
+ detail: zod.z.string().optional()
229790
+ })]);
229791
+ var ParkedTrackFrameSchema = zod.z.object({
229792
+ jpeg: zod.z.string(),
229793
+ width: zod.z.number().int().positive(),
229794
+ height: zod.z.number().int().positive(),
229795
+ /** The frame instant the parcel shows (the caller's clock, echoed back). */
229796
+ timestamp: zod.z.number(),
229797
+ /** When the node stored it (the node's clock). */
229798
+ parkedAt: zod.z.number()
229799
+ });
229555
229800
  var DetailParentSchema = zod.z.object({
229556
229801
  bbox: NativeCropBboxSchema,
229557
229802
  className: zod.z.string()
@@ -229797,7 +230042,7 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
229797
230042
  * - `analyzer`: ML/frame-diff motion detection (motion-wasm or other
229798
230043
  * analyzer providers) running on decoded frames in this runner.
229799
230044
  * - `onboard`: camera-native motion pushes (Reolink Baichuan, ONVIF
229800
- * analytics, Frigate motion). The provider emits ProviderMotion
230045
+ * analytics). The provider emits ProviderMotion
229801
230046
  * events; the orchestrator forwards to `reportMotion`.
229802
230047
  */
229803
230048
  motionSources: MotionSourcesSchema.default(["analyzer"]),
@@ -230328,7 +230573,60 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
230328
230573
  className: zod.z.string(),
230329
230574
  /** Camera the pixels came from. Diagnostics + log tags ONLY — never routing. */
230330
230575
  sourceDeviceId: zod.z.number()
230331
- }), RunStatelessStepResultSchema, { kind: "mutation" })
230576
+ }), RunStatelessStepResultSchema, { kind: "mutation" }),
230577
+ /**
230578
+ * PARK a frame for a track at the instant it is judged to matter
230579
+ * ([D422](../../../docs/decisions/adr-0422-a-relevant-frame-is-parked-when-it-becomes-relevant.md)).
230580
+ *
230581
+ * The hub's `BestDetectionTracker` — the single "best per track" policy —
230582
+ * concludes a frame is a track's best and calls this on the node that
230583
+ * owns `handle` (`nodePin(handle.nodeId)`), while the handle is young. The
230584
+ * runner cuts `bbox` from the native surface it already holds (a full
230585
+ * frame for `keyFrame`, the caller's subject window for `thumbnail`),
230586
+ * encodes ONE JPEG, and keeps it under `(deviceId, trackId, kind)`. Every
230587
+ * later consumer retrieves by that key (`getParkedTrackFrame`) — a lookup
230588
+ * that cannot miss on age. D52 holds: the rectangle is cut by the runner,
230589
+ * never a pre-cut tile the caller decided. D9/D18 hold: one compressed
230590
+ * encode at a decision point, never a stream.
230591
+ *
230592
+ * Idempotent per `(trackId, kind)`: a later park replaces (the ranking is
230593
+ * the hub's; this adds no second opinion), an out-of-order older instant
230594
+ * is ignored. Bounded per device and per node on the runner
230595
+ * (`parked-frame-store.ts`), oldest-first eviction, never a refusal for
230596
+ * space. A refusal names its reason and is logged on the runner with the
230597
+ * handle's measured age — it is never retried into a loop.
230598
+ */
230599
+ parkTrackFrame: require_sleep.method(zod.z.object({
230600
+ deviceId: zod.z.number(),
230601
+ /** Opaque to the runner — the hub's track id. */
230602
+ trackId: zod.z.string(),
230603
+ kind: ParkedFrameKindSchema,
230604
+ handle: require_sleep.FrameHandleSchema,
230605
+ /** Normalized [0,1] window to cut. `{0,0,1,1}` for a full frame. */
230606
+ bbox: NativeCropBboxSchema,
230607
+ /** Width cap for a full-frame park (the `keyFrame` native cap). */
230608
+ maxWidth: zod.z.number().int().positive().optional(),
230609
+ /** The frame instant (caller's clock) — orders parks for one key. */
230610
+ timestamp: zod.z.number()
230611
+ }), ParkTrackFrameResultSchema, { kind: "mutation" }),
230612
+ /**
230613
+ * Retrieve a parked parcel by `(deviceId, trackId, kind)`. Pinned to the
230614
+ * node that answered the park (`ParkTrackFrameResult.nodeId`). `null` means
230615
+ * nothing was parked under that key on this node — never "too old".
230616
+ */
230617
+ getParkedTrackFrame: require_sleep.method(zod.z.object({
230618
+ deviceId: zod.z.number(),
230619
+ trackId: zod.z.string(),
230620
+ kind: ParkedFrameKindSchema
230621
+ }), ParkedTrackFrameSchema.nullable()),
230622
+ /**
230623
+ * Drop every parcel of a track — the hub closed it. Idempotent. A track
230624
+ * whose release is lost ages out on the runner under a hard ceiling.
230625
+ */
230626
+ releaseParkedTrackFrames: require_sleep.method(zod.z.object({
230627
+ deviceId: zod.z.number(),
230628
+ trackId: zod.z.string()
230629
+ }), zod.z.object({ released: zod.z.number().int().nonnegative() }), { kind: "mutation" })
230332
230630
  }
230333
230631
  };
230334
230632
  var CameraPipelineConfigSchema = zod.z.object({
@@ -233947,8 +234245,8 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
233947
234245
  /**
233948
234246
  * Runtime-state slice — every provider that registers this cap
233949
234247
  * stores the same shape under `device.runtimeState[battery]`.
233950
- * Cross-provider uniformity: a Reolink Argus, a Frigate sensor
233951
- * proxy, an ONVIF battery cam all read/write the same keys.
234248
+ * Cross-provider uniformity: a Reolink Argus, a sensor proxy,
234249
+ * an ONVIF battery cam all read/write the same keys.
233952
234250
  * Consumers (BatteryBadge, snapshot wrapper sleep gate) read once
233953
234251
  * via `device.runtimeState.getCapState('battery')` regardless of
233954
234252
  * the underlying driver.
@@ -235802,7 +236100,7 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
235802
236100
  * Which integration-marker cap the addon declared, so the wizard can
235803
236101
  * branch on CAP — never on addon name. `device-adoption` integrations
235804
236102
  * (Home Assistant, …) route through the broker step (Approach A);
235805
- * `device-provider` integrations (Reolink/Frigate/ONVIF) keep the
236103
+ * `device-provider` integrations (Reolink/ONVIF) keep the
235806
236104
  * legacy config → discovery flow.
235807
236105
  */
235808
236106
  kind: zod.z.enum(["device-adoption", "device-provider"]),
@@ -239200,9 +239498,11 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
239200
239498
  });
239201
239499
  var RecordingDeviceUsageSchema = zod.z.object({
239202
239500
  deviceId: zod.z.number(),
239501
+ /** Bytes the ARCHIVE holds for this camera on this node's resolvable
239502
+ * recordings locations. */
239203
239503
  usedBytes: zod.z.number(),
239204
239504
  /**
239205
- * Start of this camera's OLDEST indexed segment, across every profile and
239505
+ * Start of this camera's OLDEST ARCHIVED segment, across every profile and
239206
239506
  * location — the "Oldest footage" column in Recordings → Storage, and the
239207
239507
  * only honest answer to "is retention actually holding?" per camera.
239208
239508
  *
@@ -239212,7 +239512,24 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
239212
239512
  * (types) and the addon ship on different trains, and the addon is usually
239213
239513
  * the later of the two.
239214
239514
  */
239215
- oldestMs: zod.z.number().nullable().optional()
239515
+ oldestMs: zod.z.number().nullable().optional(),
239516
+ /** Segments the archive holds for this camera — the "M" beside `usedBytes`.
239517
+ * OPTIONAL for the same train-skew reason as `oldestMs`. */
239518
+ segments: zod.z.number().optional(),
239519
+ /**
239520
+ * RESIDENCY, not the archive: bytes the recorder process currently holds in
239521
+ * its RAM index — the live tail plus the hours a reader hydrated.
239522
+ *
239523
+ * It answers "what can be served without touching the disk", never "how much
239524
+ * footage this camera has". A UI that renders it must label it as such, and
239525
+ * must never total it as storage. OPTIONAL: a recorder predating D418 omits
239526
+ * it, and so does a node whose ledger could not answer.
239527
+ */
239528
+ residentBytes: zod.z.number().optional(),
239529
+ /** The residency counterpart of `oldestMs` — the oldest segment currently in
239530
+ * RAM, which on a healthy recorder is minutes ago and means nothing about
239531
+ * retention. `null` = nothing resident. */
239532
+ residentOldestMs: zod.z.number().nullable().optional()
239216
239533
  });
239217
239534
  var RecordingLocationUsageSchema = zod.z.object({
239218
239535
  /** StorageLocation id; null for the legacy/degraded single-root fallback. */
@@ -239246,6 +239563,17 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
239246
239563
  totalUsedBytes: zod.z.number(),
239247
239564
  devices: zod.z.array(RecordingDeviceUsageSchema),
239248
239565
  /**
239566
+ * WHERE `devices[]` came from, so an empty table is never mistaken for empty
239567
+ * disks (D418).
239568
+ *
239569
+ * `archive` = the durable hour ledger answered. `unavailable` = this node
239570
+ * declared no ledger and the recorder REFUSED rather than answering the
239571
+ * question with the resident index (D295 rule 3) — the rows are UNKNOWN, not
239572
+ * zero, and a UI must say so. OPTIONAL: a recorder predating D418 omits it,
239573
+ * and its rows are residency.
239574
+ */
239575
+ devicesRead: zod.z.enum(["archive", "unavailable"]).optional(),
239576
+ /**
239249
239577
  * Per-physical-volume capacity. OPTIONAL, and consumers must render the rest
239250
239578
  * of the payload without it: the hub serves this method through a BAKED
239251
239579
  * router, so a hub whose framework train predates a change to this array
@@ -250210,6 +250538,24 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
250210
250538
  addonId: null,
250211
250539
  access: "view"
250212
250540
  },
250541
+ "pipelineRunner.getParkedTrackFrame": {
250542
+ capName: "pipeline-runner",
250543
+ capScope: "system",
250544
+ addonId: null,
250545
+ access: "view"
250546
+ },
250547
+ "pipelineRunner.parkTrackFrame": {
250548
+ capName: "pipeline-runner",
250549
+ capScope: "system",
250550
+ addonId: null,
250551
+ access: "create"
250552
+ },
250553
+ "pipelineRunner.releaseParkedTrackFrames": {
250554
+ capName: "pipeline-runner",
250555
+ capScope: "system",
250556
+ addonId: null,
250557
+ access: "create"
250558
+ },
250213
250559
  "pipelineRunner.reportMotion": {
250214
250560
  capName: "pipeline-runner",
250215
250561
  capScope: "system",
@@ -253751,6 +254097,21 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
253751
254097
  form: "single",
253752
254098
  optional: false
253753
254099
  }],
254100
+ "pipelineRunner.getParkedTrackFrame": [{
254101
+ name: "deviceId",
254102
+ form: "single",
254103
+ optional: false
254104
+ }],
254105
+ "pipelineRunner.parkTrackFrame": [{
254106
+ name: "deviceId",
254107
+ form: "single",
254108
+ optional: false
254109
+ }],
254110
+ "pipelineRunner.releaseParkedTrackFrames": [{
254111
+ name: "deviceId",
254112
+ form: "single",
254113
+ optional: false
254114
+ }],
253754
254115
  "pipelineRunner.reportMotion": [{
253755
254116
  name: "deviceId",
253756
254117
  form: "single",
@@ -254428,6 +254789,9 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
254428
254789
  "pipelineRunner.attachCamera",
254429
254790
  "pipelineRunner.detachCamera",
254430
254791
  "pipelineRunner.getCameraMetrics",
254792
+ "pipelineRunner.getParkedTrackFrame",
254793
+ "pipelineRunner.parkTrackFrame",
254794
+ "pipelineRunner.releaseParkedTrackFrames",
254431
254795
  "pipelineRunner.reportMotion",
254432
254796
  "pipelineRunner.runDetailSubtree",
254433
254797
  "pipelineRunner.runStatelessStep",
@@ -258881,6 +259245,10 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
258881
259245
  exports.PYTHON_SCRIPT = PYTHON_SCRIPT;
258882
259246
  exports.PackageUpdateSchema = PackageUpdateSchema;
258883
259247
  exports.PackageVersionInfoSchema = PackageVersionInfoSchema;
259248
+ exports.ParkRefusalSchema = ParkRefusalSchema;
259249
+ exports.ParkTrackFrameResultSchema = ParkTrackFrameResultSchema;
259250
+ exports.ParkedFrameKindSchema = ParkedFrameKindSchema;
259251
+ exports.ParkedTrackFrameSchema = ParkedTrackFrameSchema;
258884
259252
  exports.PasskeyLoginMethodSchema = PasskeyLoginMethodSchema;
258885
259253
  exports.PasskeySummarySchema = PasskeySummarySchema;
258886
259254
  exports.PcmSampleFormatSchema = PcmSampleFormatSchema;
@@ -416420,6 +416788,32 @@ var require_spa_mount = __commonJS({
416420
416788
  }
416421
416789
  });
416422
416790
 
416791
+ // ../../server/backend/dist/api/static/frame-policy.js
416792
+ var require_frame_policy = __commonJS({
416793
+ "../../server/backend/dist/api/static/frame-policy.js"(exports) {
416794
+ "use strict";
416795
+ Object.defineProperty(exports, "__esModule", { value: true });
416796
+ exports.FRAME_ANCESTORS_POLICY = void 0;
416797
+ exports.isFramePolicyTarget = isFramePolicyTarget;
416798
+ exports.registerFramePolicy = registerFramePolicy;
416799
+ exports.FRAME_ANCESTORS_POLICY = "frame-ancestors 'self'";
416800
+ var CSP_HEADER = "content-security-policy";
416801
+ function isFramePolicyTarget(contentType) {
416802
+ return typeof contentType === "string" && contentType.trim().toLowerCase().startsWith("text/html");
416803
+ }
416804
+ function registerFramePolicy(fastify) {
416805
+ fastify.addHook("onSend", async (_request, reply, payload) => {
416806
+ if (!isFramePolicyTarget(reply.getHeader("content-type")))
416807
+ return payload;
416808
+ if (reply.getHeader(CSP_HEADER) !== void 0)
416809
+ return payload;
416810
+ reply.header(CSP_HEADER, exports.FRAME_ANCESTORS_POLICY);
416811
+ return payload;
416812
+ });
416813
+ }
416814
+ }
416815
+ });
416816
+
416423
416817
  // ../../server/backend/dist/boot/integration-id-backfill.js
416424
416818
  var require_integration_id_backfill = __commonJS({
416425
416819
  "../../server/backend/dist/boot/integration-id-backfill.js"(exports) {
@@ -432042,6 +432436,7 @@ var require_main4 = __commonJS({
432042
432436
  var precompressed_asset_js_1 = require_precompressed_asset();
432043
432437
  var spa_static_1 = require_spa_static();
432044
432438
  var spa_mount_1 = require_spa_mount();
432439
+ var frame_policy_1 = require_frame_policy();
432045
432440
  var cap_providers_1 = require_cap_providers();
432046
432441
  var logging_settings_1 = require_logging_settings();
432047
432442
  var request_census_settings_1 = require_request_census_settings();
@@ -432193,6 +432588,7 @@ var require_main4 = __commonJS({
432193
432588
  app.enableCors();
432194
432589
  const fastify = app.getHttpAdapter().getInstance();
432195
432590
  await fastify.register(cookie_1.default);
432591
+ (0, frame_policy_1.registerFramePolicy)(fastify);
432196
432592
  fastify.addHook("onRequest", async (request) => {
432197
432593
  (0, sse_no_compression_js_1.markSseRequestNoCompression)(request);
432198
432594
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "camstack",
3
- "version": "1.2.131",
3
+ "version": "1.2.134",
4
4
  "description": "CLI tool for managing and running CamStack server",
5
5
  "keywords": [
6
6
  "camstack",