@camstack/addon-pipeline 1.1.59 → 1.1.61

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 +2 -2
  2. package/dist/audio-analyzer/index.mjs +2 -2
  3. package/dist/detection-pipeline/index.js +42 -4
  4. package/dist/detection-pipeline/index.mjs +42 -4
  5. package/dist/{dist-DKeNH_5z.mjs → dist-D16_dBsr.mjs} +281 -7
  6. package/dist/{dist-B1u-QN05.js → dist-p_JqOxtk.js} +298 -6
  7. package/dist/{model-download-service-Cp9f4dk6-0wh7OK3s.mjs → model-download-service-Cp9f4dk6-CwUb5v3Y.mjs} +1 -1
  8. package/dist/{model-download-service-Cp9f4dk6-Cp_GTKTw.js → model-download-service-Cp9f4dk6-Dv-oFwjN.js} +12 -0
  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 +4 -4
  12. package/dist/pipeline-runner/index.mjs +4 -4
  13. package/dist/recorder/index.js +685 -30
  14. package/dist/recorder/index.mjs +686 -31
  15. package/dist/{sheet-geometry-BN80zpCa.js → sheet-geometry-BR-ip0CP.js} +2 -2
  16. package/dist/{sheet-geometry-Bk3fR4s7.mjs → sheet-geometry-DcpuGTCm.mjs} +2 -2
  17. package/dist/{step-definitions-CPch37vh.js → step-definitions-CoxF5G31.js} +18 -2
  18. package/dist/{step-definitions-DUB27V8Y.mjs → step-definitions-DxAcpUV-.mjs} +18 -2
  19. package/dist/stream-broker/_stub.js +2 -2
  20. package/dist/stream-broker/{_virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-DdkfKDgw.mjs → _virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-Wu4TlSuq.mjs} +3 -3
  21. package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-BPujpbZ0.mjs +26 -0
  22. package/dist/stream-broker/{_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js-DSXctoaw.mjs → _virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js-DGxcX3Wf.mjs} +1 -1
  23. package/dist/stream-broker/{hostInit-BLn2Pv8Q.mjs → hostInit-D_dSciqF.mjs} +3 -3
  24. package/dist/stream-broker/index.js +29 -9
  25. package/dist/stream-broker/index.mjs +29 -9
  26. package/dist/stream-broker/remoteEntry.js +1 -1
  27. package/embed-dist/assets/{MaskShapeCanvas-DI4BY7W2-B0_nx15B.js → MaskShapeCanvas-DI4BY7W2-BldL9_Ee.js} +1 -1
  28. package/embed-dist/assets/{MotionZonesSettings-NcxxQN8r-B8uM-VeO.js → MotionZonesSettings-NcxxQN8r-BgWqMe4f.js} +1 -1
  29. package/embed-dist/assets/{PrivacyMaskSettings-APgPLF7p-DMOs4Hj9.js → PrivacyMaskSettings-APgPLF7p-YBgaXffP.js} +1 -1
  30. package/embed-dist/assets/index-e0bQ8yep.js +81 -0
  31. package/embed-dist/index.html +1 -1
  32. package/package.json +5 -1
  33. package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-D3h_W9uu.mjs +0 -26
  34. package/embed-dist/assets/index-W9-H5LTj.js +0 -81
@@ -3,9 +3,9 @@ Object.defineProperties(exports, {
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
5
  const require_chunk = require("../chunk-D6vf50IK.js");
6
- const require_dist = require("../dist-B1u-QN05.js");
6
+ const require_dist = require("../dist-p_JqOxtk.js");
7
7
  const require_node_topology_platform = require("../node-topology-platform-CFZ7F4xW.js");
8
- const require_model_download_service_Cp9f4dk6 = require("../model-download-service-Cp9f4dk6-Cp_GTKTw.js");
8
+ const require_model_download_service_Cp9f4dk6 = require("../model-download-service-Cp9f4dk6-Dv-oFwjN.js");
9
9
  let node_fs = require("node:fs");
10
10
  node_fs = require_chunk.__toESM(node_fs);
11
11
  let node_path = require("node:path");
@@ -1,7 +1,7 @@
1
1
  import { t as __require } from "../chunk-BdkLduGY.mjs";
2
- import { C as mapAudioLabelToMacro, H as hydrateSchema, I as errMsg, L as BaseAddon, h as audioAnalyzerCapability, l as HF_BASE_URL, m as audioAnalysisCapability, n as AUDIO_BACKEND_CHOICES, o as DEFAULT_AUDIO_ANALYZER_CONFIG } from "../dist-DKeNH_5z.mjs";
2
+ import { B as BaseAddon, G as hydrateSchema, g as audioAnalyzerCapability, h as audioAnalysisCapability, n as AUDIO_BACKEND_CHOICES, o as DEFAULT_AUDIO_ANALYZER_CONFIG, u as HF_BASE_URL, w as mapAudioLabelToMacro, z as errMsg } from "../dist-D16_dBsr.mjs";
3
3
  import { t as pickNodePlatformArch } from "../node-topology-platform-BkR_k6WT.mjs";
4
- import { r as downloadFile } from "../model-download-service-Cp9f4dk6-0wh7OK3s.mjs";
4
+ import { i as downloadFile } from "../model-download-service-Cp9f4dk6-CwUb5v3Y.mjs";
5
5
  import * as fs from "node:fs";
6
6
  import * as path$1 from "node:path";
7
7
  //#region src/audio-analyzer/audio-pipeline.ts
@@ -3,10 +3,10 @@ Object.defineProperties(exports, {
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
5
  const require_chunk = require("../chunk-D6vf50IK.js");
6
- const require_dist = require("../dist-B1u-QN05.js");
7
- const require_step_definitions = require("../step-definitions-CPch37vh.js");
6
+ const require_dist = require("../dist-p_JqOxtk.js");
7
+ const require_step_definitions = require("../step-definitions-CoxF5G31.js");
8
8
  const require_node_topology_platform = require("../node-topology-platform-CFZ7F4xW.js");
9
- const require_model_download_service_Cp9f4dk6 = require("../model-download-service-Cp9f4dk6-Cp_GTKTw.js");
9
+ const require_model_download_service_Cp9f4dk6 = require("../model-download-service-Cp9f4dk6-Dv-oFwjN.js");
10
10
  let node_child_process = require("node:child_process");
11
11
  let sharp = require("sharp");
12
12
  sharp = require_chunk.__toESM(sharp);
@@ -3690,6 +3690,15 @@ var ONNX_FLOOR = {
3690
3690
  */
3691
3691
  var PROBE_READY_TIMEOUT_MS = 12e4;
3692
3692
  /**
3693
+ * Bound for the direct `platformProbe.getCapabilities` reconcile RPC issued
3694
+ * when the readiness gate times out (D8: readiness events are telemetry —
3695
+ * lossy — so a timed-out registry wait is reconciled against the provider
3696
+ * itself before conceding to the conservative floor). `getCapabilities`
3697
+ * resolves only once the probe is complete, so an answer IS readiness; the
3698
+ * race bound keeps a wedged transport from wedging `setApi`.
3699
+ */
3700
+ var PROBE_DIRECT_RPC_TIMEOUT_MS = 6e4;
3701
+ /**
3693
3702
  * Build the onnx-cpu floor pick using `pickBestRuntime` with a null hardware
3694
3703
  * env. Used wherever the old `detectBestEngine()` sync probe fell back — the
3695
3704
  * result is identical (onnx / cpu) but is now derived through the shared rules
@@ -3922,7 +3931,11 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
3922
3931
  nodeId
3923
3932
  }, { timeoutMs: PROBE_READY_TIMEOUT_MS });
3924
3933
  } catch (err) {
3925
- this.log.warn("platform-probe readiness gate timed out conservative engine pick (floor is not persisted)", { meta: {
3934
+ if (await this.probePlatformReadinessDirect()) this.log.info("platform-probe readiness reconciled via direct probe RPC (ready event lost)", { meta: {
3935
+ nodeId,
3936
+ timeoutMs: PROBE_READY_TIMEOUT_MS
3937
+ } });
3938
+ else this.log.warn("platform-probe readiness gate timed out — conservative engine pick (floor is not persisted)", { meta: {
3926
3939
  nodeId,
3927
3940
  timeoutMs: PROBE_READY_TIMEOUT_MS,
3928
3941
  error: require_dist.errMsg(err)
@@ -3933,6 +3946,31 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
3933
3946
  this.startProvisioningForCurrentEngine();
3934
3947
  }
3935
3948
  /**
3949
+ * Authoritative platform-probe reconcile: query the probe provider
3950
+ * DIRECTLY over the cap plane. The RPC resolves only once the async
3951
+ * probe has completed (`getCapabilities` awaits the probe promise), so
3952
+ * a successful answer proves readiness independent of the (lossy)
3953
+ * `system.ready-state` event stream. Mirrors the local-node branch of
3954
+ * `resolveProbeHardware` — an unpinned `getCapabilities` routes to this
3955
+ * node's own in-process provider (agent parent / hub). Bounded by
3956
+ * {@link PROBE_DIRECT_RPC_TIMEOUT_MS}; `false` on any failure.
3957
+ */
3958
+ async probePlatformReadinessDirect() {
3959
+ const api = this.addonCtx?.api;
3960
+ if (!api) return false;
3961
+ let timer;
3962
+ try {
3963
+ const bound = new Promise((resolve) => {
3964
+ timer = setTimeout(() => resolve(null), PROBE_DIRECT_RPC_TIMEOUT_MS);
3965
+ });
3966
+ return await Promise.race([api.platformProbe.getCapabilities.query(), bound]) !== null;
3967
+ } catch {
3968
+ return false;
3969
+ } finally {
3970
+ if (timer !== void 0) clearTimeout(timer);
3971
+ }
3972
+ }
3973
+ /**
3936
3974
  * Resolve the `'auto'` engine LIVE from this node's own kernel inference
3937
3975
  * resolver (`ctx.kernel.inferenceEngine`) — the runtime mirror of
3938
3976
  * `ctx.kernel.hwaccel`. Each node (hub + forked worker + remote agent)
@@ -1,8 +1,8 @@
1
1
  import { t as __require } from "../chunk-BdkLduGY.mjs";
2
- import { D as nodePin, H as hydrateSchema, I as errMsg, K as parseJsonUnknown, L as BaseAddon, O as pipelineExecutorCapability, P as supportedRuntimes$1, V as createEvent, Y as sleep, b as detectionPipelineCapability, f as YAMNET_TO_MACRO, j as runtimeDevices$1, st as EventCategory, t as APPLE_SA_TO_MACRO, v as defaultDeviceFor$1, x as evaluateZoneRules } from "../dist-DKeNH_5z.mjs";
3
- import { a as getStepDefinition, i as getStep, n as ALL_STEPS, o as resolveModelForFormat, r as getDefaultModelForFormat, t as ALL_PIPELINE_STEPS } from "../step-definitions-DUB27V8Y.mjs";
2
+ import { B as BaseAddon, G as hydrateSchema, L as supportedRuntimes$1, O as nodePin, P as runtimeDevices$1, Q as sleep, S as evaluateZoneRules, W as createEvent, Y as parseJsonUnknown, k as pipelineExecutorCapability, p as YAMNET_TO_MACRO, t as APPLE_SA_TO_MACRO, ut as EventCategory, x as detectionPipelineCapability, y as defaultDeviceFor$1, z as errMsg } from "../dist-D16_dBsr.mjs";
3
+ import { a as getStepDefinition, i as getStep, n as ALL_STEPS, o as resolveModelForFormat, r as getDefaultModelForFormat, t as ALL_PIPELINE_STEPS } from "../step-definitions-DxAcpUV-.mjs";
4
4
  import { t as pickNodePlatformArch } from "../node-topology-platform-BkR_k6WT.mjs";
5
- import { a as isModelDownloaded, i as ensureModel, n as deleteModelFromDisk } from "../model-download-service-Cp9f4dk6-0wh7OK3s.mjs";
5
+ import { a as ensureModel, o as isModelDownloaded, r as deleteModelFromDisk } from "../model-download-service-Cp9f4dk6-CwUb5v3Y.mjs";
6
6
  import { spawn } from "node:child_process";
7
7
  import sharp from "sharp";
8
8
  import * as fs from "node:fs";
@@ -3682,6 +3682,15 @@ var ONNX_FLOOR = {
3682
3682
  */
3683
3683
  var PROBE_READY_TIMEOUT_MS = 12e4;
3684
3684
  /**
3685
+ * Bound for the direct `platformProbe.getCapabilities` reconcile RPC issued
3686
+ * when the readiness gate times out (D8: readiness events are telemetry —
3687
+ * lossy — so a timed-out registry wait is reconciled against the provider
3688
+ * itself before conceding to the conservative floor). `getCapabilities`
3689
+ * resolves only once the probe is complete, so an answer IS readiness; the
3690
+ * race bound keeps a wedged transport from wedging `setApi`.
3691
+ */
3692
+ var PROBE_DIRECT_RPC_TIMEOUT_MS = 6e4;
3693
+ /**
3685
3694
  * Build the onnx-cpu floor pick using `pickBestRuntime` with a null hardware
3686
3695
  * env. Used wherever the old `detectBestEngine()` sync probe fell back — the
3687
3696
  * result is identical (onnx / cpu) but is now derived through the shared rules
@@ -3914,7 +3923,11 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
3914
3923
  nodeId
3915
3924
  }, { timeoutMs: PROBE_READY_TIMEOUT_MS });
3916
3925
  } catch (err) {
3917
- this.log.warn("platform-probe readiness gate timed out conservative engine pick (floor is not persisted)", { meta: {
3926
+ if (await this.probePlatformReadinessDirect()) this.log.info("platform-probe readiness reconciled via direct probe RPC (ready event lost)", { meta: {
3927
+ nodeId,
3928
+ timeoutMs: PROBE_READY_TIMEOUT_MS
3929
+ } });
3930
+ else this.log.warn("platform-probe readiness gate timed out — conservative engine pick (floor is not persisted)", { meta: {
3918
3931
  nodeId,
3919
3932
  timeoutMs: PROBE_READY_TIMEOUT_MS,
3920
3933
  error: errMsg(err)
@@ -3925,6 +3938,31 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
3925
3938
  this.startProvisioningForCurrentEngine();
3926
3939
  }
3927
3940
  /**
3941
+ * Authoritative platform-probe reconcile: query the probe provider
3942
+ * DIRECTLY over the cap plane. The RPC resolves only once the async
3943
+ * probe has completed (`getCapabilities` awaits the probe promise), so
3944
+ * a successful answer proves readiness independent of the (lossy)
3945
+ * `system.ready-state` event stream. Mirrors the local-node branch of
3946
+ * `resolveProbeHardware` — an unpinned `getCapabilities` routes to this
3947
+ * node's own in-process provider (agent parent / hub). Bounded by
3948
+ * {@link PROBE_DIRECT_RPC_TIMEOUT_MS}; `false` on any failure.
3949
+ */
3950
+ async probePlatformReadinessDirect() {
3951
+ const api = this.addonCtx?.api;
3952
+ if (!api) return false;
3953
+ let timer;
3954
+ try {
3955
+ const bound = new Promise((resolve) => {
3956
+ timer = setTimeout(() => resolve(null), PROBE_DIRECT_RPC_TIMEOUT_MS);
3957
+ });
3958
+ return await Promise.race([api.platformProbe.getCapabilities.query(), bound]) !== null;
3959
+ } catch {
3960
+ return false;
3961
+ } finally {
3962
+ if (timer !== void 0) clearTimeout(timer);
3963
+ }
3964
+ }
3965
+ /**
3928
3966
  * Resolve the `'auto'` engine LIVE from this node's own kernel inference
3929
3967
  * resolver (`ctx.kernel.inferenceEngine`) — the runtime mirror of
3930
3968
  * `ctx.kernel.hwaccel`. Each node (hub + forked worker + remote agent)
@@ -1,4 +1,4 @@
1
- //#region ../types/dist/event-category-H4AVePnn.mjs
1
+ //#region ../types/dist/event-category-D4HJq7Mw.mjs
2
2
  var EventCategory = /* @__PURE__ */ function(EventCategory) {
3
3
  EventCategory["SystemBoot"] = "system.boot";
4
4
  EventCategory["SystemAddonsReady"] = "system.addons-ready";
@@ -151,6 +151,11 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
151
151
  /** Runner-sampled scrub thumbnail (~1/5 s/camera). Telemetry (D8): a lost
152
152
  * thumb is a scrub gap the recorder's keyframe backfill covers. */
153
153
  EventCategory["RecordingThumbSampled"] = "recording.thumb-sampled";
154
+ /** Export render progress (0–100). Telemetry (D8): a lost tick is a stale
155
+ * progress bar the client reconciles via `recordingExport.getExport`. */
156
+ EventCategory["RecordingExportProgress"] = "recording.export.progress";
157
+ EventCategory["RecordingExportCompleted"] = "recording.export.completed";
158
+ EventCategory["RecordingExportFailed"] = "recording.export.failed";
154
159
  EventCategory["DetectionEvent"] = "detection.event";
155
160
  EventCategory["SessionTrackNew"] = "session.track.new";
156
161
  EventCategory["SessionTrackExpired"] = "session.track.expired";
@@ -440,6 +445,25 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
440
445
  */
441
446
  EventCategory["PipelineAnalyticsStationaryChanged"] = "pipeline-analytics.stationary-changed";
442
447
  /**
448
+ * Fired by `addon-post-analysis` when a package-drop is confirmed inside
449
+ * a package zone — a newly-appeared stationary object of a package class
450
+ * that cleared the class / zone / dwell / size gates. Payload:
451
+ * `PipelineAnalyticsPackageDeliveredPayload` carrying `{ deviceId,
452
+ * entryId, className, zoneIds, keyFrameMediaKey?, bbox, timestamp }`.
453
+ * Telemetry (D8): the durable record is the `package-events` store row;
454
+ * this bus topic drives notifier rules + live UI. See
455
+ * docs/superpowers/specs/2026-07-17-package-zones-design.md §5.1.
456
+ */
457
+ EventCategory["PipelineAnalyticsPackageDelivered"] = "pipeline-analytics.package-delivered";
458
+ /**
459
+ * Fired by `addon-post-analysis` when a previously-delivered package
460
+ * leaves its zone (the stationary entry departed — moved or swept).
461
+ * Payload: `PipelineAnalyticsPackagePickedUpPayload` carrying
462
+ * `{ deviceId, entryId, deliveredEventId, className, timestamp }`.
463
+ * Telemetry (D8). See package-zones-design §5.2.
464
+ */
465
+ EventCategory["PipelineAnalyticsPackagePickedUp"] = "pipeline-analytics.package-picked-up";
466
+ /**
443
467
  * Fired by `addon-post-analysis` whenever a gallery face row changes:
444
468
  * `kind:'buffered'` a new detected face was persisted, `'assigned'` /
445
469
  * `'unassigned'` its identity link changed, `'deleted'` the row was
@@ -5178,6 +5202,25 @@ function _instanceof(cls, params = {}) {
5178
5202
  };
5179
5203
  return inst;
5180
5204
  }
5205
+ //#endregion
5206
+ //#region ../../node_modules/zod/v4/classic/compat.js
5207
+ /** @deprecated Use the raw string literal codes instead, e.g. "invalid_type". */
5208
+ var ZodIssueCode = {
5209
+ invalid_type: "invalid_type",
5210
+ too_big: "too_big",
5211
+ too_small: "too_small",
5212
+ invalid_format: "invalid_format",
5213
+ not_multiple_of: "not_multiple_of",
5214
+ unrecognized_keys: "unrecognized_keys",
5215
+ invalid_union: "invalid_union",
5216
+ invalid_key: "invalid_key",
5217
+ invalid_element: "invalid_element",
5218
+ invalid_value: "invalid_value",
5219
+ custom: "custom"
5220
+ };
5221
+ /** @deprecated Do not use. Stub definition, only included for zod-to-json-schema compatibility. */
5222
+ var ZodFirstPartyTypeKind;
5223
+ ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
5181
5224
  Object.fromEntries([
5182
5225
  {
5183
5226
  id: "overview",
@@ -7379,6 +7422,65 @@ var RecordingRetentionSchema = object({
7379
7422
  maxSizeGb: number().min(0).optional()
7380
7423
  });
7381
7424
  /**
7425
+ * Scrub-thumbnail fidelity preset — the single per-camera selector bundling the
7426
+ * sprite tile RESOLUTION + JPEG QUALITY the recorder packs timeline-scrub
7427
+ * previews at. Five graduated steps; absent on a config = `standard` (the
7428
+ * shipped default, matching `sheet-geometry`/`sheet-composer`).
7429
+ *
7430
+ * Existing sheets are IMMUTABLE — a changed preset applies to NEW windows only.
7431
+ * Each window's index sidecar carries its own tile dims, so a camera whose
7432
+ * preset changed over time renders every historical window at the dims it was
7433
+ * written with.
7434
+ */
7435
+ var ScrubThumbnailPresetSchema = _enum([
7436
+ "minimal",
7437
+ "low",
7438
+ "standard",
7439
+ "high",
7440
+ "max"
7441
+ ]);
7442
+ /**
7443
+ * Preset → tile geometry + JPEG quality. Every step is 16:9; the graduated
7444
+ * ladder trades sheet size (and remote fetch cost) for scrub crispness.
7445
+ * `standard` matches the shipped `sheet-geometry`/`sheet-composer` defaults
7446
+ * (480×270 q72), so an unset config is byte-identical to today. The map is
7447
+ * strictly monotone in resolution AND quality across the ordered steps.
7448
+ */
7449
+ var SCRUB_THUMBNAIL_PRESETS = {
7450
+ minimal: {
7451
+ tileWidth: 240,
7452
+ tileHeight: 135,
7453
+ quality: 55
7454
+ },
7455
+ low: {
7456
+ tileWidth: 320,
7457
+ tileHeight: 180,
7458
+ quality: 60
7459
+ },
7460
+ standard: {
7461
+ tileWidth: 480,
7462
+ tileHeight: 270,
7463
+ quality: 72
7464
+ },
7465
+ high: {
7466
+ tileWidth: 640,
7467
+ tileHeight: 360,
7468
+ quality: 80
7469
+ },
7470
+ max: {
7471
+ tileWidth: 960,
7472
+ tileHeight: 540,
7473
+ quality: 85
7474
+ }
7475
+ };
7476
+ /**
7477
+ * Resolve the geometry for a recording config's scrub-thumbnail preset,
7478
+ * defaulting to `standard` when unset. Pure — no I/O.
7479
+ */
7480
+ function resolveScrubThumbnailGeometry(preset) {
7481
+ return SCRUB_THUMBNAIL_PRESETS[preset ?? "standard"];
7482
+ }
7483
+ /**
7382
7484
  * The full per-camera recording intent — the wire shape of a RecordingTarget.
7383
7485
  *
7384
7486
  * `mode` is the authoritative storage choice; `schedule`/`triggers`/`pre`/`post`
@@ -7415,7 +7517,14 @@ var RecordingConfigSchema = object({
7415
7517
  * derived into bands once via `migrateConfigToBands`.
7416
7518
  */
7417
7519
  bands: array(RecordingBandSchema).optional(),
7418
- retention: RecordingRetentionSchema.optional()
7520
+ retention: RecordingRetentionSchema.optional(),
7521
+ /**
7522
+ * Per-camera scrub-thumbnail fidelity preset (resolution + JPEG quality for
7523
+ * timeline-scrub sprite previews). Absent = `standard`. Applies to NEW
7524
+ * windows only — existing sheets are immutable, and each window's index
7525
+ * carries its own tile dims so mixed-preset history renders correctly.
7526
+ */
7527
+ scrubThumbnails: ScrubThumbnailPresetSchema.optional()
7419
7528
  });
7420
7529
  /** All seven weekdays (0 = Sunday … 6 = Saturday), used when a schedule omits a
7421
7530
  * weekday filter. */
@@ -8090,7 +8199,10 @@ var COCO_TO_MACRO = {
8090
8199
  elephant: "animal",
8091
8200
  bear: "animal",
8092
8201
  zebra: "animal",
8093
- giraffe: "animal"
8202
+ giraffe: "animal",
8203
+ suitcase: "package",
8204
+ backpack: "package",
8205
+ handbag: "package"
8094
8206
  },
8095
8207
  preserveOriginal: false
8096
8208
  };
@@ -13685,7 +13797,11 @@ array(ZoneRuleSchema).readonly();
13685
13797
  * Extend the enum here when a new gating consumer comes online (audio
13686
13798
  * gating, alert filtering, …) — no other surface needs to change.
13687
13799
  */
13688
- var ZoneRuleStageEnum = _enum(["motion", "detection"]);
13800
+ var ZoneRuleStageEnum = _enum([
13801
+ "motion",
13802
+ "detection",
13803
+ "package"
13804
+ ]);
13689
13805
  DeviceType.Camera, method(object({
13690
13806
  deviceId: number(),
13691
13807
  stage: ZoneRuleStageEnum
@@ -13698,7 +13814,8 @@ DeviceType.Camera, method(object({
13698
13814
  auth: "admin"
13699
13815
  }), object({
13700
13816
  motion: array(ZoneRuleSchema).readonly(),
13701
- detection: array(ZoneRuleSchema).readonly()
13817
+ detection: array(ZoneRuleSchema).readonly(),
13818
+ package: array(ZoneRuleSchema).readonly()
13702
13819
  });
13703
13820
  var ProviderStatusSchema = object({
13704
13821
  connected: boolean(),
@@ -17091,6 +17208,7 @@ var EventKindIconSchema = _enum([
17091
17208
  "smoke",
17092
17209
  "water",
17093
17210
  "button",
17211
+ "package",
17094
17212
  "generic"
17095
17213
  ]);
17096
17214
  var EventKindCategorySchema = _enum([
@@ -17098,7 +17216,8 @@ var EventKindCategorySchema = _enum([
17098
17216
  "audio",
17099
17217
  "detection",
17100
17218
  "sensor",
17101
- "custom"
17219
+ "custom",
17220
+ "package"
17102
17221
  ]);
17103
17222
  var EventKindDescriptorSchema = object({
17104
17223
  /** Stable kind id (e.g. 'motion', 'person', 'contact'). */
@@ -20872,6 +20991,125 @@ var recordingCapability = {
20872
20991
  }
20873
20992
  };
20874
20993
  /**
20994
+ * `recordingExport` cap — render a footage time range into a single downloadable
20995
+ * MP4 (regular / accelerated / decelerated / timelapse, ± audio), kept for a
20996
+ * bounded lifetime with a durable history, auto-expiry, and optional
20997
+ * delete-after-download.
20998
+ *
20999
+ * Like `recording` this is a `scope:'system', mode:'singleton'` cap: the
21000
+ * recorder self-gates so exactly ONE node (the designated `recordingNodeId`,
21001
+ * default `hub`) registers it. Device-scoped methods carry `deviceId` in their
21002
+ * input and dispatch to that single provider; the render runs on the node that
21003
+ * owns the footage (no cross-node segment transfer). Download rides the
21004
+ * framework addon data-plane. State persists in a DurableState blob (NOT
21005
+ * SQLite); history rows survive file deletion for audit.
21006
+ */
21007
+ /** Playback-speed multiplier for the render (1 = realtime). */
21008
+ var ExportSpeedSchema = number().min(.25).max(32);
21009
+ /** Timelapse cadence — sample one source frame per `everyMs`, output at `outputFps`. */
21010
+ var ExportTimelapseSchema = object({
21011
+ everyMs: number().int().positive(),
21012
+ outputFps: number().int().min(1).max(60).optional()
21013
+ });
21014
+ /**
21015
+ * Render options. `speed` and `timelapse` are mutually exclusive. `includeAudio`
21016
+ * is honoured only for a realtime-ish speed (0.5–2×); timelapse is always
21017
+ * silent. `maxLifeMs` bounds how long the finished file is kept;
21018
+ * `deleteAfterDownload` removes it shortly after the first complete download.
21019
+ */
21020
+ var ExportOptionsSchema = object({
21021
+ speed: ExportSpeedSchema.optional(),
21022
+ timelapse: ExportTimelapseSchema.optional(),
21023
+ includeAudio: boolean(),
21024
+ maxLifeMs: number().int().positive(),
21025
+ deleteAfterDownload: boolean(),
21026
+ title: string().max(200).optional()
21027
+ }).superRefine((v, ctx) => {
21028
+ if (v.speed !== void 0 && v.timelapse !== void 0) ctx.addIssue({
21029
+ code: ZodIssueCode.custom,
21030
+ message: "speed and timelapse are mutually exclusive",
21031
+ path: ["timelapse"]
21032
+ });
21033
+ });
21034
+ var ExportStateSchema = _enum([
21035
+ "queued",
21036
+ "rendering",
21037
+ "ready",
21038
+ "failed",
21039
+ "expired",
21040
+ "deleted"
21041
+ ]);
21042
+ /** One export job / history row. */
21043
+ var ExportRecordSchema = object({
21044
+ id: string(),
21045
+ deviceId: number(),
21046
+ profile: string(),
21047
+ fromMs: number(),
21048
+ toMs: number(),
21049
+ options: ExportOptionsSchema,
21050
+ state: ExportStateSchema,
21051
+ /** 0–100 while rendering; null otherwise. */
21052
+ progressPct: number().nullable(),
21053
+ /** File size once ready; null before. */
21054
+ fileBytes: number().nullable(),
21055
+ expiresAt: number(),
21056
+ deleteAfterDownload: boolean(),
21057
+ /** Epoch of the first complete download; null until then. */
21058
+ downloadedAt: number().nullable(),
21059
+ createdAt: number(),
21060
+ /** User id/name that requested the export. */
21061
+ createdBy: string(),
21062
+ /** Failure reason when state is 'failed'; null otherwise. */
21063
+ error: string().nullable()
21064
+ });
21065
+ /** Candidate download URLs (LAN first, then operator extra hosts). */
21066
+ var ExportDownloadSchema = object({
21067
+ url: string(),
21068
+ endpoints: array(string())
21069
+ });
21070
+ var recordingExportCapability = {
21071
+ name: "recordingExport",
21072
+ scope: "system",
21073
+ mode: "singleton",
21074
+ methods: {
21075
+ /** Queue a render of `[fromMs,toMs)` for `deviceId`/`profile`. Fails fast
21076
+ * when no footage covers the range. Returns the queued record. */
21077
+ createExport: method(object({
21078
+ deviceId: number(),
21079
+ profile: string(),
21080
+ fromMs: number(),
21081
+ toMs: number(),
21082
+ options: ExportOptionsSchema
21083
+ }), ExportRecordSchema, {
21084
+ kind: "mutation",
21085
+ auth: "protected"
21086
+ }),
21087
+ /** All export rows (history included), optionally scoped to one device. */
21088
+ listExports: method(object({ deviceId: number().optional() }), array(ExportRecordSchema), {
21089
+ kind: "query",
21090
+ auth: "protected"
21091
+ }),
21092
+ getExport: method(object({ exportId: string() }), ExportRecordSchema, {
21093
+ kind: "query",
21094
+ auth: "protected"
21095
+ }),
21096
+ /** Abort a queued/rendering export; the partial file is removed. */
21097
+ cancelExport: method(object({ exportId: string() }), ExportRecordSchema, {
21098
+ kind: "mutation",
21099
+ auth: "protected"
21100
+ }),
21101
+ /** Remove the file but keep the history row (state → 'deleted'). */
21102
+ deleteExport: method(object({ exportId: string() }), ExportRecordSchema, {
21103
+ kind: "mutation",
21104
+ auth: "protected"
21105
+ }),
21106
+ getDownloadUrl: method(object({ exportId: string() }), ExportDownloadSchema, {
21107
+ kind: "query",
21108
+ auth: "protected"
21109
+ })
21110
+ }
21111
+ };
21112
+ /**
20875
21113
  * One publishable camera stream as its OWNING PROVIDER describes it — the same
20876
21114
  * payload the (legacy) push `streamBroker.publishCameraStream` carried, minus
20877
21115
  * `deviceId`.
@@ -24795,6 +25033,42 @@ Object.freeze({
24795
25033
  addonId: null,
24796
25034
  access: "create"
24797
25035
  },
25036
+ "recordingExport.cancelExport": {
25037
+ capName: "recordingExport",
25038
+ capScope: "system",
25039
+ addonId: null,
25040
+ access: "create"
25041
+ },
25042
+ "recordingExport.createExport": {
25043
+ capName: "recordingExport",
25044
+ capScope: "system",
25045
+ addonId: null,
25046
+ access: "create"
25047
+ },
25048
+ "recordingExport.deleteExport": {
25049
+ capName: "recordingExport",
25050
+ capScope: "system",
25051
+ addonId: null,
25052
+ access: "delete"
25053
+ },
25054
+ "recordingExport.getDownloadUrl": {
25055
+ capName: "recordingExport",
25056
+ capScope: "system",
25057
+ addonId: null,
25058
+ access: "view"
25059
+ },
25060
+ "recordingExport.getExport": {
25061
+ capName: "recordingExport",
25062
+ capScope: "system",
25063
+ addonId: null,
25064
+ access: "view"
25065
+ },
25066
+ "recordingExport.listExports": {
25067
+ capName: "recordingExport",
25068
+ capScope: "system",
25069
+ addonId: null,
25070
+ access: "view"
25071
+ },
24798
25072
  "sceneMonitor.captureReference": {
24799
25073
  capName: "scene-monitor",
24800
25074
  capScope: "device",
@@ -26156,4 +26430,4 @@ function defaultDeviceFor(id) {
26156
26430
  return def(id).defaultDevice;
26157
26431
  }
26158
26432
  //#endregion
26159
- export { discriminatedUnion as $, recordingCapability as A, DeviceType as B, mapAudioLabelToMacro as C, nodePin as D, motionDetectionCapability as E, webrtcSessionCapability as F, makeSourceBrokerId as G, hydrateSchema as H, errMsg as I, selectAssignedProfileSlots as J, parseJsonUnknown as K, BaseAddon as L, storageEvictableCapability as M, streamBrokerCapability as N, pipelineExecutorCapability as O, supportedRuntimes as P, boolean as Q, CAM_PROFILE_ORDER as R, hfModelUrl as S, migrateConfigToBands as T, isEvent as U, createEvent as V, makeProfileBrokerId as W, _enum as X, sleep as Y, array as Z, customAction as _, COCO_TO_MACRO as a, string as at, detectionPipelineCapability as b, EncodeProfileSchema as c, RingBuffer as d, lazy as et, YAMNET_TO_MACRO as f, cameraStreamsCapability as g, audioAnalyzerCapability as h, COCO_80_LABELS as i, record as it, runtimeDevices as j, pipelineRunnerCapability as k, HF_BASE_URL as l, audioAnalysisCapability as m, AUDIO_BACKEND_CHOICES as n, number as nt, DEFAULT_AUDIO_ANALYZER_CONFIG as o, union as ot, addonWidgetsSourceCapability as p, parseProfileBrokerId as q, AUDIO_MACRO_LABELS as r, object as rt, EVENT_PAD_MS as s, EventCategory as st, APPLE_SA_TO_MACRO as t, literal as tt, RecordingConfigSchema as u, defaultDeviceFor as v, maskUrlCredentials as w, evaluateZoneRules as x, defineCustomActions as y, DeviceFeature as z };
26433
+ export { _enum as $, pipelineRunnerCapability as A, BaseAddon as B, hfModelUrl as C, motionDetectionCapability as D, migrateConfigToBands as E, storageEvictableCapability as F, hydrateSchema as G, DeviceFeature as H, streamBrokerCapability as I, makeSourceBrokerId as J, isEvent as K, supportedRuntimes as L, recordingExportCapability as M, resolveScrubThumbnailGeometry as N, nodePin as O, runtimeDevices as P, sleep as Q, webrtcSessionCapability as R, evaluateZoneRules as S, maskUrlCredentials as T, DeviceType as U, CAM_PROFILE_ORDER as V, createEvent as W, parseProfileBrokerId as X, parseJsonUnknown as Y, selectAssignedProfileSlots as Z, cameraStreamsCapability as _, COCO_TO_MACRO as a, number as at, defineCustomActions as b, EncodeProfileSchema as c, string as ct, RecordingConfigSchema as d, array as et, RingBuffer as f, audioAnalyzerCapability as g, audioAnalysisCapability as h, COCO_80_LABELS as i, literal as it, recordingCapability as j, pipelineExecutorCapability as k, ExportRecordSchema as l, union as lt, addonWidgetsSourceCapability as m, AUDIO_BACKEND_CHOICES as n, discriminatedUnion as nt, DEFAULT_AUDIO_ANALYZER_CONFIG as o, object as ot, YAMNET_TO_MACRO as p, makeProfileBrokerId as q, AUDIO_MACRO_LABELS as r, lazy as rt, EVENT_PAD_MS as s, record as st, APPLE_SA_TO_MACRO as t, boolean as tt, HF_BASE_URL as u, EventCategory as ut, customAction as v, mapAudioLabelToMacro as w, detectionPipelineCapability as x, defaultDeviceFor as y, errMsg as z };