@camstack/addon-pipeline 1.2.40 → 1.2.41

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. package/dist/audio-analyzer/index.js +1 -1
  2. package/dist/audio-analyzer/index.mjs +1 -1
  3. package/dist/detection-pipeline/index.js +2 -2
  4. package/dist/detection-pipeline/index.mjs +2 -2
  5. package/dist/{dist-DcMBfoCg.js → dist-BS7wLqoV.js} +264 -5
  6. package/dist/{dist-C6p8jcji.mjs → dist-DvUTPZ8J.mjs} +264 -5
  7. package/dist/{event-loop-stall-monitor-oL9xanvX.js → event-loop-stall-monitor-C5P2bcwP.js} +1 -1
  8. package/dist/{event-loop-stall-monitor-BHqCesa1.mjs → event-loop-stall-monitor-a2u9e1qx.mjs} +1 -1
  9. package/dist/motion-wasm/index.js +1 -1
  10. package/dist/motion-wasm/index.mjs +1 -1
  11. package/dist/pipeline-runner/index.js +2 -2
  12. package/dist/pipeline-runner/index.mjs +2 -2
  13. package/dist/recorder/index.js +1 -1
  14. package/dist/recorder/index.mjs +1 -1
  15. package/dist/session-decode/decode-worker-child.js +39 -2
  16. package/dist/session-decode/decode-worker-child.mjs +39 -2
  17. package/dist/stream-broker/_stub.js +2 -2
  18. package/dist/stream-broker/{_virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-Bt1YkfUW.mjs → _virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-CS82x0lt.mjs} +3 -3
  19. package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-CDzxDzcv.mjs +26 -0
  20. package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js-CciPNnL7.mjs +26 -0
  21. package/dist/stream-broker/{hostInit-Dyj8Vaql.mjs → hostInit-lj4kKHrb.mjs} +3 -3
  22. package/dist/stream-broker/index.js +1 -1
  23. package/dist/stream-broker/index.mjs +1 -1
  24. package/dist/stream-broker/remoteEntry.js +1 -1
  25. package/embed-dist/assets/{MaskShapeCanvas-DI4BY7W2-m1RaK_7F.js → MaskShapeCanvas-DI4BY7W2-BRQ5u_mo.js} +1 -1
  26. package/embed-dist/assets/{MotionZonesSettings-NcxxQN8r-C00UIgFo.js → MotionZonesSettings-NcxxQN8r-KbOg5nD9.js} +1 -1
  27. package/embed-dist/assets/{PrivacyMaskSettings-APgPLF7p-DWYllToj.js → PrivacyMaskSettings-APgPLF7p-CKSPn3_D.js} +1 -1
  28. package/embed-dist/assets/index-CGdwTcwE.css +2 -0
  29. package/embed-dist/assets/{index-BaUgbxWl.js → index-CbrEyYGW.js} +12 -12
  30. package/embed-dist/index.html +2 -2
  31. package/package.json +1 -1
  32. package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-DJnh97n9.mjs +0 -26
  33. package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js-BsNhZnfZ.mjs +0 -26
  34. package/embed-dist/assets/index-4fJzjj4H.css +0 -2
@@ -9666,7 +9666,68 @@ var NcZoneConditionSchema = object({
9666
9666
  * The P1 condition set — a flat AND of groups; absent group = pass;
9667
9667
  * membership lists are OR within the list (spec §2.3).
9668
9668
  */
9669
+ /**
9670
+ * What a rule may actuate.
9671
+ *
9672
+ * **No hand-maintained allowlist** (operator decision, and the right one — a
9673
+ * written list of methods is a third parallel map to keep aligned, and this
9674
+ * repo has paid for those). The boundary instead comes from a property the
9675
+ * capabilities already carry: an action may target only a **device-scoped**
9676
+ * capability method.
9677
+ *
9678
+ * That is not decoration. A rule can be authored by a NON-ADMIN — personal
9679
+ * rules are a supported flow — and the executor runs with the addon's
9680
+ * privileges, so an unbounded action is an arbitrary RPC channel with a
9681
+ * privilege escalation attached. Restricting to device scope excludes the
9682
+ * system caps (`device-manager.removeDevice` and friends) by construction,
9683
+ * costs nothing to maintain, and cannot rot: a cap that stops being
9684
+ * device-scoped stops being actuatable in the same change.
9685
+ *
9686
+ * The executor enforces it; {@link NcRuleActionSchema} carries the intent.
9687
+ */
9688
+ /**
9689
+ * One step of a sequence.
9690
+ *
9691
+ * `wait` is a first-class step rather than a property of the next action: it is
9692
+ * what makes a sequence a SEQUENCE and not a list — "unlock, wait 5s, open"
9693
+ * cannot be expressed otherwise.
9694
+ */
9695
+ var NcRuleActionSchema = discriminatedUnion("kind", [object({
9696
+ kind: literal("wait"),
9697
+ seconds: number().min(0).max(300)
9698
+ }), object({
9699
+ kind: literal("cap"),
9700
+ deviceId: number().int(),
9701
+ /** Capability name, e.g. `alarm-panel`. */
9702
+ cap: string().min(1),
9703
+ /** Method on it. The executor refuses a non-device-scoped cap. */
9704
+ method: string().min(1),
9705
+ /** Method arguments, minus `deviceId` (the executor injects it). */
9706
+ args: record(string(), unknown()).optional()
9707
+ })]);
9708
+ /**
9709
+ * Sequences a rule runs, by hook point.
9710
+ *
9711
+ * ONLY `onTrigger` is here, deliberately. The reference also has activation /
9712
+ * deactivation / reset / post-generation hooks, and they are wanted — but this
9713
+ * repo's expensive failure mode is declaring a surface nothing produces, so a
9714
+ * hook appears here in the same change that produces its edge, never before.
9715
+ */
9716
+ var NcRuleActionsSchema = object({
9717
+ /** Runs when the rule MATCHES. */
9718
+ onTrigger: array(object({
9719
+ name: string().min(1).max(120),
9720
+ enabled: boolean(),
9721
+ minDelaySec: number().int().min(0).max(86400).optional(),
9722
+ actions: array(NcRuleActionSchema).min(1)
9723
+ })).optional() });
9669
9724
  var NcConditionsSchema = object({
9725
+ /** Gate on ANOTHER device's current state (the alarm armed, a switch on). */
9726
+ deviceState: object({
9727
+ deviceId: number().int(),
9728
+ /** Any of these matches. */
9729
+ states: array(string().min(1)).min(1)
9730
+ }).optional(),
9670
9731
  /** Device scope — absent = all devices. */
9671
9732
  devices: array(number()).optional(),
9672
9733
  /** Detector class names (any overlap with the record's class set). */
@@ -9960,7 +10021,16 @@ var NcRuleInputSchema = object({
9960
10021
  * read as `false` by {@link canSetGlobal} in the engine. Admins are not bound
9961
10022
  * by this flag — see the scope rules on that function.
9962
10023
  */
9963
- snoozeAllowGlobal: boolean().optional()
10024
+ snoozeAllowGlobal: boolean().optional(),
10025
+ /**
10026
+ * Devices this rule ACTUATES — arm the alarm, open a gate, turn on a light.
10027
+ *
10028
+ * This is what makes the rule set the alarm's trigger set without the alarm
10029
+ * being a special case: arming is
10030
+ * `{ cap: 'alarm-panel', method: 'arm', args: { mode: 'away' } }`, the same
10031
+ * shape as every other actuation.
10032
+ */
10033
+ actions: NcRuleActionsSchema.optional()
9964
10034
  });
9965
10035
  /**
9966
10036
  * Partial patch for `updateRule` — any subset of the input fields, plus the
@@ -10031,7 +10101,8 @@ var NcConditionDescriptorSchema = object({
10031
10101
  "packagePhase",
10032
10102
  "crossingSelect",
10033
10103
  "polygonDraw",
10034
- "occupancy"
10104
+ "occupancy",
10105
+ "deviceState"
10035
10106
  ]),
10036
10107
  operator: _enum([
10037
10108
  "in",
@@ -17316,7 +17387,20 @@ method(object({
17316
17387
  }), _void(), {
17317
17388
  kind: "mutation",
17318
17389
  auth: "admin"
17319
- }), method(object({ addonId: string() }), array(SavedDeviceRowSchema)), method(object({ addonId: string().optional() }), array(DeviceInfoSchema)), method(object({ deviceId: number() }), DeviceInfoSchema.nullable()), method(object({ parentDeviceId: number() }), array(DeviceInfoSchema)), method(object({ deviceId: number() }), object({
17390
+ }), method(object({ addonId: string() }), array(SavedDeviceRowSchema)), method(object({
17391
+ addonId: string().optional(),
17392
+ /**
17393
+ * `slim` omits `config` (returned `{}`), `metadata` (null) and the
17394
+ * `sourceInfo` derived from config — and skips the per-device settings
17395
+ * read that produces them. Everything identifying a device (id, name,
17396
+ * type, online, features, isCamera, parent/link ids) is unchanged.
17397
+ * Do not use it for dispatch routing, which needs `sourceInfo`.
17398
+ */
17399
+ projection: _enum(["full", "slim"]).optional(),
17400
+ /** Return only camera devices. Filtering server-side instead of
17401
+ * shipping 293 rows to find 12. */
17402
+ isCamera: boolean().optional()
17403
+ }), array(DeviceInfoSchema)), method(object({ deviceId: number() }), DeviceInfoSchema.nullable()), method(object({ parentDeviceId: number() }), array(DeviceInfoSchema)), method(object({ deviceId: number() }), object({
17320
17404
  mode: DeviceLinkModeSchema,
17321
17405
  devices: array(LinkedDeviceSchema)
17322
17406
  })), method(object({ deviceId: number() }), array(StreamSourceEntrySchema$1)), method(object({ deviceId: number() }), array(ConfigEntrySchema)), method(object({ deviceId: number() }), ConfigUISchemaOutput), method(object({
@@ -18515,6 +18599,103 @@ method(object({}), array(TargetKindSchema)), method(object({}), array(TargetSche
18515
18599
  enabled: boolean()
18516
18600
  }), _void(), { kind: "mutation" });
18517
18601
  /**
18602
+ * core-blocks — user-authored TypeScript, stored in the kernel and executed in
18603
+ * its own process.
18604
+ *
18605
+ * Spec: `docs/superpowers/specs/2026-08-04-core-blocks-and-synthetic-devices-design.md`.
18606
+ *
18607
+ * The first use is **owning devices without being a device provider**: a block
18608
+ * declares devices under a system or custom integration and drives their state,
18609
+ * with the same `ctx` an addon gets. Automations come later; nothing here
18610
+ * models a trigger.
18611
+ *
18612
+ * **Stated plainly, because it does not change by being true:** a block has an
18613
+ * addon's powers — devices, storage, the event bus, `ctx.api`. It is a plugin
18614
+ * with no review step. What makes that survivable is not a sandbox, it is
18615
+ * PROCESS ISOLATION: one process per block, supervised by `CrashSupervisor`,
18616
+ * so a block that throws or never returns is marked `failed` and visible
18617
+ * instead of taking the hub with it (D6). Every method here is admin-only, and
18618
+ * must stay so.
18619
+ */
18620
+ /** Where a block runs. The operator chooses — a block driving a device on an
18621
+ * agent is the reason placement is not fixed to the hub. */
18622
+ var CoreBlockPlacementSchema = union([literal("hub"), string().min(1)]);
18623
+ /** What a block's process is doing. Mirrors the addon runner's own lifecycle so
18624
+ * a failing block reads the same way a failing addon does. */
18625
+ var CoreBlockStatusSchema = _enum([
18626
+ "stopped",
18627
+ "starting",
18628
+ "running",
18629
+ "failed"
18630
+ ]);
18631
+ /** Client-authored fields. */
18632
+ var CoreBlockInputSchema = object({
18633
+ name: string().min(1).max(120),
18634
+ /** TypeScript source. Compiled server-side before it is ever stored — a
18635
+ * block that does not compile is a fork failure the operator would meet
18636
+ * minutes later, in a log, instead of in the editor. */
18637
+ code: string().max(2e5),
18638
+ enabled: boolean(),
18639
+ placement: CoreBlockPlacementSchema,
18640
+ /**
18641
+ * Integration the block's devices hang from. Absent = the system integration
18642
+ * blocks share. A block may declare its own instead.
18643
+ */
18644
+ integrationId: string().optional()
18645
+ });
18646
+ /** A stored block. */
18647
+ var CoreBlockSchema = CoreBlockInputSchema.extend({
18648
+ id: string(),
18649
+ createdAt: number(),
18650
+ updatedAt: number(),
18651
+ /** Server-stamped author. */
18652
+ createdBy: string(),
18653
+ status: CoreBlockStatusSchema,
18654
+ /**
18655
+ * Why the block is not running, when it is not. The operator's ONLY window
18656
+ * into a block that failed at load — a block that is silently absent is the
18657
+ * failure mode this whole feature has to avoid.
18658
+ */
18659
+ lastError: string().optional(),
18660
+ /** Ms epoch of the last state change. */
18661
+ lastChangedAt: number()
18662
+ });
18663
+ /** What a compile attempt produced. */
18664
+ var CoreBlockCompileResultSchema = object({
18665
+ ok: boolean(),
18666
+ /** Present when `ok` is false — the first error, in the author's words. */
18667
+ error: string().optional(),
18668
+ line: number().optional(),
18669
+ column: number().optional()
18670
+ });
18671
+ method(object({}), object({ blocks: array(CoreBlockSchema) }), { auth: "admin" }), method(object({ blockId: string() }), object({ block: CoreBlockSchema.nullable() }), { auth: "admin" }), method(object({ block: CoreBlockInputSchema }), object({ block: CoreBlockSchema }), {
18672
+ kind: "mutation",
18673
+ auth: "admin",
18674
+ caller: "required"
18675
+ }), method(object({
18676
+ blockId: string(),
18677
+ block: CoreBlockInputSchema.partial()
18678
+ }), object({ block: CoreBlockSchema }), {
18679
+ kind: "mutation",
18680
+ auth: "admin",
18681
+ caller: "required"
18682
+ }), method(object({ blockId: string() }), object({ success: literal(true) }), {
18683
+ kind: "mutation",
18684
+ auth: "admin"
18685
+ }), method(object({
18686
+ blockId: string(),
18687
+ enabled: boolean()
18688
+ }), object({ block: CoreBlockSchema }), {
18689
+ kind: "mutation",
18690
+ auth: "admin"
18691
+ }), method(object({ code: string() }), CoreBlockCompileResultSchema, {
18692
+ kind: "mutation",
18693
+ auth: "admin"
18694
+ }), method(object({}), object({ libs: array(object({
18695
+ filePath: string(),
18696
+ content: string()
18697
+ })) }), { auth: "admin" });
18698
+ /**
18518
18699
  * Zod schemas for persisted record types.
18519
18700
  *
18520
18701
  * These schemas serve as the single source of truth for types that are
@@ -18761,6 +18942,11 @@ var EventKindDescriptorSchema = object({
18761
18942
  deviceId: number()
18762
18943
  })
18763
18944
  });
18945
+ /** One camera's event vocabulary, as returned by `listEventKindsBatch`. */
18946
+ var EventKindsForDeviceSchema = object({
18947
+ deviceId: number(),
18948
+ kinds: array(EventKindDescriptorSchema).readonly()
18949
+ });
18764
18950
  var SensorEventSchema = object({
18765
18951
  id: string(),
18766
18952
  /** The CAMERA the event is attributed to (a sensor linked to N cameras
@@ -19017,6 +19203,19 @@ var MediaFileSchema = object({
19017
19203
  sizeBytes: number(),
19018
19204
  timestamp: number()
19019
19205
  });
19206
+ /**
19207
+ * One media row WITHOUT its bytes.
19208
+ *
19209
+ * A track's media is 5-8 MB of base64 (measured: 7.67 MB across 23 files for a
19210
+ * 140 s track), and a client that renders tiles from the media data plane needs
19211
+ * to know only WHAT EXISTS — the bytes then arrive per tile, lazily, over HTTP
19212
+ * with an immutable cache, instead of all at once inside a tRPC response that
19213
+ * blocks the whole view.
19214
+ *
19215
+ * `sizeBytes` is carried because it is what lets a client decide between the
19216
+ * stored blob and a `?variant=thumb` rendering without fetching either.
19217
+ */
19218
+ var MediaFileInfoSchema = MediaFileSchema.omit({ base64: true });
19020
19219
  var DEFAULT_EVENT_QUERY_LIMIT = 1e3;
19021
19220
  var MAX_EVENT_QUERY_LIMIT = 5e3;
19022
19221
  var DeviceEventQueryInput = object({
@@ -19166,7 +19365,7 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
19166
19365
  }), array(TrackSchema).readonly()), method(RecentTracksQueryInput, RecentTracksPageSchema), method(object({ deviceId: number() }), _void(), {
19167
19366
  kind: "mutation",
19168
19367
  auth: "admin"
19169
- }), method(DeviceEventQueryInput, array(MotionEventSchema).readonly()), method(ObjectEventQueryInput, array(ObjectEventSchema).readonly()), method(DeviceEventQueryInput, array(AudioEventSchema).readonly()), method(object({ deviceId: number() }), array(EventKindDescriptorSchema).readonly()), method(object({
19368
+ }), method(DeviceEventQueryInput, array(MotionEventSchema).readonly()), method(ObjectEventQueryInput, array(ObjectEventSchema).readonly()), method(DeviceEventQueryInput, array(AudioEventSchema).readonly()), method(object({ deviceId: number() }), array(EventKindDescriptorSchema).readonly()), method(object({ deviceIds: array(number()).min(1).max(200) }), array(EventKindsForDeviceSchema).readonly()), method(object({
19170
19369
  deviceId: number(),
19171
19370
  since: number().optional(),
19172
19371
  until: number().optional(),
@@ -19240,7 +19439,7 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
19240
19439
  }), array(MediaFileSchema).readonly()), method(object({
19241
19440
  trackId: string(),
19242
19441
  kinds: array(MediaFileKindEnum).optional()
19243
- }), array(MediaFileSchema).readonly()), method(SearchObjectEventsInput, array(ScoredObjectEventSchema).readonly()), object({
19442
+ }), array(MediaFileSchema).readonly()), method(object({ trackId: string() }), array(MediaFileInfoSchema).readonly()), method(SearchObjectEventsInput, array(ScoredObjectEventSchema).readonly()), object({
19244
19443
  deviceId: number(),
19245
19444
  timestamp: number(),
19246
19445
  frameWidth: number(),
@@ -24021,6 +24220,54 @@ Object.freeze({
24021
24220
  addonId: null,
24022
24221
  access: "create"
24023
24222
  },
24223
+ "coreBlocks.compile": {
24224
+ capName: "core-blocks",
24225
+ capScope: "system",
24226
+ addonId: null,
24227
+ access: "create"
24228
+ },
24229
+ "coreBlocks.create": {
24230
+ capName: "core-blocks",
24231
+ capScope: "system",
24232
+ addonId: null,
24233
+ access: "create"
24234
+ },
24235
+ "coreBlocks.delete": {
24236
+ capName: "core-blocks",
24237
+ capScope: "system",
24238
+ addonId: null,
24239
+ access: "delete"
24240
+ },
24241
+ "coreBlocks.get": {
24242
+ capName: "core-blocks",
24243
+ capScope: "system",
24244
+ addonId: null,
24245
+ access: "view"
24246
+ },
24247
+ "coreBlocks.getTypeDefs": {
24248
+ capName: "core-blocks",
24249
+ capScope: "system",
24250
+ addonId: null,
24251
+ access: "view"
24252
+ },
24253
+ "coreBlocks.list": {
24254
+ capName: "core-blocks",
24255
+ capScope: "system",
24256
+ addonId: null,
24257
+ access: "view"
24258
+ },
24259
+ "coreBlocks.setEnabled": {
24260
+ capName: "core-blocks",
24261
+ capScope: "system",
24262
+ addonId: null,
24263
+ access: "create"
24264
+ },
24265
+ "coreBlocks.update": {
24266
+ capName: "core-blocks",
24267
+ capScope: "system",
24268
+ addonId: null,
24269
+ access: "create"
24270
+ },
24024
24271
  "cover.close": {
24025
24272
  capName: "cover",
24026
24273
  capScope: "device",
@@ -26187,6 +26434,12 @@ Object.freeze({
26187
26434
  addonId: null,
26188
26435
  access: "view"
26189
26436
  },
26437
+ "pipelineAnalytics.listEventKindsBatch": {
26438
+ capName: "pipeline-analytics",
26439
+ capScope: "device",
26440
+ addonId: null,
26441
+ access: "view"
26442
+ },
26190
26443
  "pipelineAnalytics.listOpsLog": {
26191
26444
  capName: "pipeline-analytics",
26192
26445
  capScope: "device",
@@ -26199,6 +26452,12 @@ Object.freeze({
26199
26452
  addonId: null,
26200
26453
  access: "view"
26201
26454
  },
26455
+ "pipelineAnalytics.listTrackMedia": {
26456
+ capName: "pipeline-analytics",
26457
+ capScope: "device",
26458
+ addonId: null,
26459
+ access: "view"
26460
+ },
26202
26461
  "pipelineAnalytics.listTracks": {
26203
26462
  capName: "pipeline-analytics",
26204
26463
  capScope: "device",
@@ -1,4 +1,4 @@
1
- const require_dist = require("./dist-DcMBfoCg.js");
1
+ const require_dist = require("./dist-BS7wLqoV.js");
2
2
  let node_perf_hooks = require("node:perf_hooks");
3
3
  //#region src/detection-pipeline/registry/model-catalogs.ts
4
4
  var HF_REPO = "camstack/camstack-models";
@@ -1,4 +1,4 @@
1
- import { D as hfModelUrl, a as COCO_TO_MACRO, i as COCO_80_LABELS, r as AUDIO_MACRO_LABELS } from "./dist-C6p8jcji.mjs";
1
+ import { D as hfModelUrl, a as COCO_TO_MACRO, i as COCO_80_LABELS, r as AUDIO_MACRO_LABELS } from "./dist-DvUTPZ8J.mjs";
2
2
  import { PerformanceObserver } from "node:perf_hooks";
3
3
  //#region src/detection-pipeline/registry/model-catalogs.ts
4
4
  var HF_REPO = "camstack/camstack-models";
@@ -2,7 +2,7 @@ Object.defineProperties(exports, {
2
2
  __esModule: { value: true },
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
- const require_dist = require("../dist-DcMBfoCg.js");
5
+ const require_dist = require("../dist-BS7wLqoV.js");
6
6
  const require_lazy_sharp = require("../lazy-sharp-CcYuXtsa.js");
7
7
  let node_fs = require("node:fs");
8
8
  let node_path = require("node:path");
@@ -1,4 +1,4 @@
1
- import { A as motionDetectionCapability, E as evaluateZoneRules, K as hydrateSchema, V as BaseAddon, W as DeviceType } from "../dist-C6p8jcji.mjs";
1
+ import { A as motionDetectionCapability, E as evaluateZoneRules, K as hydrateSchema, V as BaseAddon, W as DeviceType } from "../dist-DvUTPZ8J.mjs";
2
2
  import { t as getSharp } from "../lazy-sharp-B-mb8uWx.mjs";
3
3
  import { readFileSync } from "node:fs";
4
4
  import { join } from "node:path";
@@ -3,8 +3,8 @@ Object.defineProperties(exports, {
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
5
  const require_chunk = require("../chunk-emK7D4bc.js");
6
- const require_dist = require("../dist-DcMBfoCg.js");
7
- const require_event_loop_stall_monitor = require("../event-loop-stall-monitor-oL9xanvX.js");
6
+ const require_dist = require("../dist-BS7wLqoV.js");
7
+ const require_event_loop_stall_monitor = require("../event-loop-stall-monitor-C5P2bcwP.js");
8
8
  const require_worker_protocol = require("../worker-protocol-DextwlTX.js");
9
9
  const require_hub_hostname = require("../hub-hostname-DAJXlOgV.js");
10
10
  const require_lazy_sharp = require("../lazy-sharp-CcYuXtsa.js");
@@ -1,5 +1,5 @@
1
- import { B as errMsg, G as createEvent, M as pipelineRunnerCapability, S as defineCustomActions, V as BaseAddon, X as nodePin, at as lazy, b as customAction, ct as object, ft as EventCategory, nt as array, ot as literal, rt as boolean, s as DEVICE_BACKEND_TO_FORMAT, st as number, tt as _enum, ut as string } from "../dist-C6p8jcji.mjs";
2
- import { c as getStepDefinition, t as attributeStall } from "../event-loop-stall-monitor-BHqCesa1.mjs";
1
+ import { B as errMsg, G as createEvent, M as pipelineRunnerCapability, S as defineCustomActions, V as BaseAddon, X as nodePin, at as lazy, b as customAction, ct as object, ft as EventCategory, nt as array, ot as literal, rt as boolean, s as DEVICE_BACKEND_TO_FORMAT, st as number, tt as _enum, ut as string } from "../dist-DvUTPZ8J.mjs";
2
+ import { c as getStepDefinition, t as attributeStall } from "../event-loop-stall-monitor-a2u9e1qx.mjs";
3
3
  import { t as isWorkerReply } from "../worker-protocol-D7RzZIla.mjs";
4
4
  import { t as resolveHubHostname } from "../hub-hostname-cCknRYKj.mjs";
5
5
  import { t as getSharp } from "../lazy-sharp-B-mb8uWx.mjs";
@@ -1,5 +1,5 @@
1
1
  const require_chunk = require("../chunk-emK7D4bc.js");
2
- const require_dist = require("../dist-DcMBfoCg.js");
2
+ const require_dist = require("../dist-BS7wLqoV.js");
3
3
  const require_hub_hostname = require("../hub-hostname-DAJXlOgV.js");
4
4
  const require_model_download_service_Cp9f4dk6 = require("../model-download-service-Cp9f4dk6-fsdDExML.js");
5
5
  let node_child_process = require("node:child_process");
@@ -1,4 +1,4 @@
1
- import { $ as selectAssignedProfileSlots, B as errMsg, C as deriveRecordingMode, I as storageEvictableCapability, K as hydrateSchema, N as recordingCapability, P as recordingExportCapability, V as BaseAddon, W as DeviceType, X as nodePin, c as EVENT_PAD_MS, f as OpsLogEntrySchema, ft as EventCategory, lt as record, nt as array, p as RecordingConfigSchema, u as ExportRecordSchema, ut as string } from "../dist-C6p8jcji.mjs";
1
+ import { $ as selectAssignedProfileSlots, B as errMsg, C as deriveRecordingMode, I as storageEvictableCapability, K as hydrateSchema, N as recordingCapability, P as recordingExportCapability, V as BaseAddon, W as DeviceType, X as nodePin, c as EVENT_PAD_MS, f as OpsLogEntrySchema, ft as EventCategory, lt as record, nt as array, p as RecordingConfigSchema, u as ExportRecordSchema, ut as string } from "../dist-DvUTPZ8J.mjs";
2
2
  import { t as resolveHubHostname } from "../hub-hostname-cCknRYKj.mjs";
3
3
  import { n as createFileDataPlaneHandler, s as parseRangeHeader, t as contentTypeFor } from "../model-download-service-Cp9f4dk6-CwUb5v3Y.mjs";
4
4
  import { spawn } from "node:child_process";
@@ -682,6 +682,15 @@ function toLeasedRgbNavFrame(frame) {
682
682
  };
683
683
  }
684
684
  /** Re-dial backoff on a transient dial error/EOF (mirrors the decoder's PULL_REDIAL_MS). */
685
+ /**
686
+ * RSS at which a decode worker is reported anomalous.
687
+ *
688
+ * Chosen from the incident rather than from theory: on 2026-08-05 the healthy
689
+ * fleet sat at 1.1-1.3 GB per worker while the one that broke the host reached
690
+ * 4.9 GB. 2 GB is clear of the normal band and well below the point where it
691
+ * costs anyone anything.
692
+ */
693
+ var WORKER_RSS_WARN_MB = 2048;
685
694
  var REDIAL_MS = 3e3;
686
695
  /** How often the worker emits its `framesDecoded/framesSkipped/deliveredFps` line. */
687
696
  var METRICS_INTERVAL_MS = 1e4;
@@ -1079,6 +1088,12 @@ var DecodeWorkerChild = class {
1079
1088
  /** Frames actually handed to the parent as a `frame` reply. */
1080
1089
  framesDelivered = 0;
1081
1090
  lastMetricsAt = 0;
1091
+ /** Process start, for the `ageS` field. A worker that outlives its siblings
1092
+ * by two orders of magnitude is the signal this exists to surface. */
1093
+ startedAt = Date.now();
1094
+ /** One-shot, so a legitimately long session does not repeat the warning
1095
+ * every ten seconds. */
1096
+ warnedLarge = false;
1082
1097
  lastDeliveredSnapshot = 0;
1083
1098
  metricsTimer = null;
1084
1099
  demuxer = null;
@@ -1170,16 +1185,38 @@ var DecodeWorkerChild = class {
1170
1185
  this.send({ kind: "ended" });
1171
1186
  }
1172
1187
  }
1173
- /** Emit the compact throughput line (window `deliveredFps`); cheap, integer-only. */
1188
+ /**
1189
+ * Emit the compact throughput line (window `deliveredFps`); cheap,
1190
+ * integer-only.
1191
+ *
1192
+ * **`rssMb` and `ageS` are here because their absence cost a Home Assistant
1193
+ * outage.** On 2026-08-05 one worker stayed alive 1h58m and grew to 4.9 GiB
1194
+ * at ~46 MB/min while its eleven siblings recycled every ~30 s; the host ran
1195
+ * out of memory and the kernel killed the largest process on the box, which
1196
+ * was somebody else's VM. Nothing in any log said a decode worker was large,
1197
+ * or old — the leak was only found by sampling `ps` by hand.
1198
+ *
1199
+ * This line already runs every 10 s per session and is already grouped by
1200
+ * device in Loki, so carrying the worker's own RSS and age turns "a runner
1201
+ * is big" into "THIS camera's worker has been climbing for an hour", which
1202
+ * is the question that was unanswerable. Retained-store sizes ride along
1203
+ * because they are the first thing to suspect and they are free to read.
1204
+ */
1174
1205
  logMetrics(final) {
1175
1206
  const now = Date.now();
1176
1207
  const windowMs = Math.max(1, now - this.lastMetricsAt);
1177
1208
  const deliveredDelta = this.framesDelivered - this.lastDeliveredSnapshot;
1178
1209
  const deliveredFps = Math.round(deliveredDelta / windowMs * 1e3 * 10) / 10;
1179
1210
  const skipped = this.framesSkipped + this.frames.droppedCount;
1180
- this.emitStderr(`session-decode metrics {framesDecoded:${this.framesDecoded}, framesSkipped:${skipped}, deliveredFps:${deliveredFps}, nativeCropHits:${this.nativeCropHits}, nativeCropMisses:${this.nativeCropMisses}}${final ? " (final)" : ""}\n`);
1211
+ const rssMb = Math.round(process.memoryUsage().rss / 1048576);
1212
+ const ageS = Math.round((now - this.startedAt) / 1e3);
1213
+ this.emitStderr(`session-decode metrics {framesDecoded:${this.framesDecoded}, framesSkipped:${skipped}, deliveredFps:${deliveredFps}, nativeCropHits:${this.nativeCropHits}, nativeCropMisses:${this.nativeCropMisses}, rssMb:${rssMb}, ageS:${ageS}}${final ? " (final)" : ""}\n`);
1181
1214
  this.lastMetricsAt = now;
1182
1215
  this.lastDeliveredSnapshot = this.framesDelivered;
1216
+ if (!this.warnedLarge && rssMb >= WORKER_RSS_WARN_MB) {
1217
+ this.warnedLarge = true;
1218
+ this.emitStderr(`decode-worker-child: WORKER IS LARGE — rssMb=${rssMb} ageS=${ageS} framesDecoded=${this.framesDecoded}. Siblings normally recycle in ~30s; a worker this size at this age is how the host ran out of memory on 2026-08-05.\n`);
1219
+ }
1183
1220
  }
1184
1221
  handleStart(source, opts) {
1185
1222
  if (this.started) {
@@ -678,6 +678,15 @@ function toLeasedRgbNavFrame(frame) {
678
678
  };
679
679
  }
680
680
  /** Re-dial backoff on a transient dial error/EOF (mirrors the decoder's PULL_REDIAL_MS). */
681
+ /**
682
+ * RSS at which a decode worker is reported anomalous.
683
+ *
684
+ * Chosen from the incident rather than from theory: on 2026-08-05 the healthy
685
+ * fleet sat at 1.1-1.3 GB per worker while the one that broke the host reached
686
+ * 4.9 GB. 2 GB is clear of the normal band and well below the point where it
687
+ * costs anyone anything.
688
+ */
689
+ var WORKER_RSS_WARN_MB = 2048;
681
690
  var REDIAL_MS = 3e3;
682
691
  /** How often the worker emits its `framesDecoded/framesSkipped/deliveredFps` line. */
683
692
  var METRICS_INTERVAL_MS = 1e4;
@@ -1075,6 +1084,12 @@ var DecodeWorkerChild = class {
1075
1084
  /** Frames actually handed to the parent as a `frame` reply. */
1076
1085
  framesDelivered = 0;
1077
1086
  lastMetricsAt = 0;
1087
+ /** Process start, for the `ageS` field. A worker that outlives its siblings
1088
+ * by two orders of magnitude is the signal this exists to surface. */
1089
+ startedAt = Date.now();
1090
+ /** One-shot, so a legitimately long session does not repeat the warning
1091
+ * every ten seconds. */
1092
+ warnedLarge = false;
1078
1093
  lastDeliveredSnapshot = 0;
1079
1094
  metricsTimer = null;
1080
1095
  demuxer = null;
@@ -1166,16 +1181,38 @@ var DecodeWorkerChild = class {
1166
1181
  this.send({ kind: "ended" });
1167
1182
  }
1168
1183
  }
1169
- /** Emit the compact throughput line (window `deliveredFps`); cheap, integer-only. */
1184
+ /**
1185
+ * Emit the compact throughput line (window `deliveredFps`); cheap,
1186
+ * integer-only.
1187
+ *
1188
+ * **`rssMb` and `ageS` are here because their absence cost a Home Assistant
1189
+ * outage.** On 2026-08-05 one worker stayed alive 1h58m and grew to 4.9 GiB
1190
+ * at ~46 MB/min while its eleven siblings recycled every ~30 s; the host ran
1191
+ * out of memory and the kernel killed the largest process on the box, which
1192
+ * was somebody else's VM. Nothing in any log said a decode worker was large,
1193
+ * or old — the leak was only found by sampling `ps` by hand.
1194
+ *
1195
+ * This line already runs every 10 s per session and is already grouped by
1196
+ * device in Loki, so carrying the worker's own RSS and age turns "a runner
1197
+ * is big" into "THIS camera's worker has been climbing for an hour", which
1198
+ * is the question that was unanswerable. Retained-store sizes ride along
1199
+ * because they are the first thing to suspect and they are free to read.
1200
+ */
1170
1201
  logMetrics(final) {
1171
1202
  const now = Date.now();
1172
1203
  const windowMs = Math.max(1, now - this.lastMetricsAt);
1173
1204
  const deliveredDelta = this.framesDelivered - this.lastDeliveredSnapshot;
1174
1205
  const deliveredFps = Math.round(deliveredDelta / windowMs * 1e3 * 10) / 10;
1175
1206
  const skipped = this.framesSkipped + this.frames.droppedCount;
1176
- this.emitStderr(`session-decode metrics {framesDecoded:${this.framesDecoded}, framesSkipped:${skipped}, deliveredFps:${deliveredFps}, nativeCropHits:${this.nativeCropHits}, nativeCropMisses:${this.nativeCropMisses}}${final ? " (final)" : ""}\n`);
1207
+ const rssMb = Math.round(process.memoryUsage().rss / 1048576);
1208
+ const ageS = Math.round((now - this.startedAt) / 1e3);
1209
+ this.emitStderr(`session-decode metrics {framesDecoded:${this.framesDecoded}, framesSkipped:${skipped}, deliveredFps:${deliveredFps}, nativeCropHits:${this.nativeCropHits}, nativeCropMisses:${this.nativeCropMisses}, rssMb:${rssMb}, ageS:${ageS}}${final ? " (final)" : ""}\n`);
1177
1210
  this.lastMetricsAt = now;
1178
1211
  this.lastDeliveredSnapshot = this.framesDelivered;
1212
+ if (!this.warnedLarge && rssMb >= WORKER_RSS_WARN_MB) {
1213
+ this.warnedLarge = true;
1214
+ this.emitStderr(`decode-worker-child: WORKER IS LARGE — rssMb=${rssMb} ageS=${ageS} framesDecoded=${this.framesDecoded}. Siblings normally recycle in ~30s; a worker this size at this age is how the host ran out of memory on 2026-08-05.\n`);
1215
+ }
1179
1216
  }
1180
1217
  handleStart(source, opts) {
1181
1218
  if (this.started) {
@@ -1,8 +1,8 @@
1
- import { a as e, c as t, d as n, i as r, l as i, n as a, o, r as s, s as c, t as l, u } from "./_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js-BsNhZnfZ.mjs";
1
+ import { a as e, c as t, d as n, i as r, l as i, n as a, o, r as s, s as c, t as l, u } from "./_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js-CciPNnL7.mjs";
2
2
  import { a as d, i as f, n as p, o as m, r as h, t as g } from "./_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare__react__loadShare__.js-C9j-2lBe.mjs";
3
3
  import { n as _, r as v, t as y } from "./_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare__react_mf_1_jsx_mf_2_runtime__loadShare__.js-XO0-Pyu6.mjs";
4
4
  import { n as b, t as x } from "./_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_tanstack_mf_1_react_mf_2_query__loadShare__.js-BO7TIbJV.mjs";
5
- import { t as S } from "./_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-DJnh97n9.mjs";
5
+ import { t as S } from "./_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-CDzxDzcv.mjs";
6
6
  //#region ../../node_modules/lucide-react/dist/esm/shared/src/utils.js
7
7
  var C = (e) => e.replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase(), w = (e) => e.replace(/^([A-Z])|[\s-_]+(\w)/g, (e, t, n) => n ? n.toUpperCase() : t.toLowerCase()), T = (e) => {
8
8
  let t = w(e);
@@ -3,7 +3,7 @@ import "./dist-CYZr2fwk.mjs";
3
3
  var e = {
4
4
  "@camstack/sdk": {
5
5
  name: "@camstack/sdk",
6
- version: "1.2.9",
6
+ version: "1.2.10",
7
7
  scope: ["default"],
8
8
  loaded: !1,
9
9
  from: "addon_stream_broker_widgets",
@@ -18,7 +18,7 @@ var e = {
18
18
  },
19
19
  "@camstack/types": {
20
20
  name: "@camstack/types",
21
- version: "1.2.25",
21
+ version: "1.2.31",
22
22
  scope: ["default"],
23
23
  loaded: !1,
24
24
  from: "addon_stream_broker_widgets",
@@ -33,7 +33,7 @@ var e = {
33
33
  },
34
34
  "@camstack/ui-library": {
35
35
  name: "@camstack/ui-library",
36
- version: "1.2.19",
36
+ version: "1.2.25",
37
37
  scope: ["default"],
38
38
  loaded: !1,
39
39
  from: "addon_stream_broker_widgets",