@camstack/types 1.2.16 → 1.2.18

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 (64) hide show
  1. package/dist/addon.d.ts +1 -0
  2. package/dist/addon.js +266 -2
  3. package/dist/addon.mjs +265 -3
  4. package/dist/capabilities/addons.cap.d.ts +7 -7
  5. package/dist/capabilities/broker.cap.d.ts +8 -8
  6. package/dist/capabilities/camera-streams.cap.d.ts +5 -5
  7. package/dist/capabilities/climate-control.cap.d.ts +8 -8
  8. package/dist/capabilities/day-night.cap.d.ts +8 -8
  9. package/dist/capabilities/decoder.cap.d.ts +2 -2
  10. package/dist/capabilities/device-manager.cap.d.ts +24 -2
  11. package/dist/capabilities/face-gallery.cap.d.ts +1 -1
  12. package/dist/capabilities/image-settings.cap.d.ts +16 -16
  13. package/dist/capabilities/index.d.ts +2 -2
  14. package/dist/capabilities/intercom.cap.d.ts +6 -6
  15. package/dist/capabilities/lawn-mower-control.cap.d.ts +4 -4
  16. package/dist/capabilities/llm-runtime.cap.d.ts +3 -3
  17. package/dist/capabilities/llm.cap.d.ts +4 -4
  18. package/dist/capabilities/local-network.cap.d.ts +38 -0
  19. package/dist/capabilities/media-player.cap.d.ts +9 -9
  20. package/dist/capabilities/metrics-provider.cap.d.ts +2 -2
  21. package/dist/capabilities/mqtt-broker.cap.d.ts +3 -3
  22. package/dist/capabilities/notification-output.cap.d.ts +4 -0
  23. package/dist/capabilities/notification-rules.cap.d.ts +378 -18
  24. package/dist/capabilities/pipeline-analytics.cap.d.ts +133 -27
  25. package/dist/capabilities/pipeline-executor.cap.d.ts +2 -2
  26. package/dist/capabilities/pipeline-orchestrator.cap.d.ts +15 -15
  27. package/dist/capabilities/pipeline-runner.cap.d.ts +2 -2
  28. package/dist/capabilities/recording-export.cap.d.ts +7 -7
  29. package/dist/capabilities/recording.cap.d.ts +102 -129
  30. package/dist/capabilities/schemas/orchestrator-metrics.d.ts +2 -2
  31. package/dist/capabilities/schemas/streaming-shared.d.ts +4 -4
  32. package/dist/capabilities/storage-provider.cap.d.ts +44 -0
  33. package/dist/capabilities/storage.cap.d.ts +17 -1
  34. package/dist/capabilities/stream-broker.cap.d.ts +58 -12
  35. package/dist/capabilities/webrtc-session.cap.d.ts +6 -6
  36. package/dist/enums/event-category.d.ts +13 -0
  37. package/dist/enums.js +1 -1
  38. package/dist/enums.mjs +1 -1
  39. package/dist/{event-category-Cdyife4p.js → event-category-39bpf1r_.js} +13 -0
  40. package/dist/{event-category-BLcNejAE.mjs → event-category-Bz24uP1U.mjs} +13 -0
  41. package/dist/generated/addon-api.d.ts +5358 -30965
  42. package/dist/generated/cap-input-defaults.d.ts +29 -0
  43. package/dist/generated/device-proxy.d.ts +2 -2
  44. package/dist/generated/method-access-map.d.ts +1 -1
  45. package/dist/generated/system-proxy.d.ts +3 -3
  46. package/dist/index.d.ts +2 -1
  47. package/dist/index.js +724 -138
  48. package/dist/index.mjs +711 -135
  49. package/dist/interfaces/addon.d.ts +9 -0
  50. package/dist/interfaces/ops-log.d.ts +2 -0
  51. package/dist/interfaces/recording-config.d.ts +33 -91
  52. package/dist/interfaces/relocate.d.ts +55 -0
  53. package/dist/interfaces/storage-location-declaration.d.ts +1 -1
  54. package/dist/interfaces/storage-location.d.ts +4 -0
  55. package/dist/interfaces/stream-broker.d.ts +1 -1
  56. package/dist/lifecycle/job.d.ts +6 -6
  57. package/dist/node.js +1 -0
  58. package/dist/node.mjs +1 -0
  59. package/dist/notification/condition-taxonomy.d.ts +61 -0
  60. package/dist/notification/format-transcode.d.ts +12 -1
  61. package/dist/{sleep-C3ceNSsf.mjs → sleep-B_Uaqbai.mjs} +7 -1
  62. package/dist/{sleep-DRg9F6JJ.js → sleep-DETsT9rJ.js} +7 -1
  63. package/package.json +1 -1
  64. package/dist/interfaces/recording-config-migrate.d.ts +0 -12
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_sleep = require("./sleep-DRg9F6JJ.js");
3
- const require_event_category = require("./event-category-Cdyife4p.js");
2
+ const require_sleep = require("./sleep-DETsT9rJ.js");
3
+ const require_event_category = require("./event-category-39bpf1r_.js");
4
4
  const require_enums = require("./enums.js");
5
5
  const require_err_msg = require("./err-msg-COpsHMw2.js");
6
6
  let zod = require("zod");
@@ -792,35 +792,22 @@ var EVENT_PAD_MS = {
792
792
  */
793
793
  var RecordingWeekdaySchema = zod.z.number().int().min(0).max(6);
794
794
  var HHMM = /^([01]\d|2[0-3]):[0-5]\d$/;
795
- var RecordingScheduleSchema = zod.z.discriminatedUnion("kind", [zod.z.object({ kind: zod.z.literal("always") }), zod.z.object({
796
- kind: zod.z.literal("timeOfDay"),
797
- start: zod.z.string().regex(HHMM),
798
- end: zod.z.string().regex(HHMM),
799
- /** Restrict to these weekdays; omit = every day. */
800
- days: zod.z.array(RecordingWeekdaySchema).optional()
801
- })]);
802
- var RecordingModeSchema = zod.z.enum([
803
- "continuous",
804
- "onMotion",
805
- "onAudioThreshold"
806
- ]);
807
795
  /**
808
- * First-class, authoritative per-camera storage mode — the explicit choice the
809
- * UI reads directly (never inferred from `rules`):
810
- * - `off` — not recording.
811
- * - `events` — record only around triggers (motion / audio threshold),
812
- * with pre/post-buffer.
813
- * - `continuous` — record 24/7 within the schedule.
796
+ * DERIVED per-camera storage summary — the single field cheap consumers read
797
+ * (the viewer's status dot, the camera list) instead of walking `bands`:
798
+ * - `off` — no band covers the camera (or it is disabled).
799
+ * - `events` — every band records around triggers only.
800
+ * - `continuous` — at least one band records continuously.
814
801
  *
815
- * `mode` compiles one-way to the internal `rules[]` consumed by the policy
816
- * engine (see `compileRules`); `rules[]` is never authored directly anymore.
802
+ * NEVER authored: the recorder stamps it from the authoritative `bands` on
803
+ * every save (`activeModeForConfig`). Writing it has no effect.
817
804
  */
818
805
  var RecordingStorageModeSchema = zod.z.enum([
819
806
  "off",
820
807
  "events",
821
808
  "continuous"
822
809
  ]);
823
- /** Which detectors trigger an `events`-mode recording. */
810
+ /** Which detectors trigger an `events`-mode band. */
824
811
  var RecordingTriggersSchema = zod.z.object({
825
812
  motion: zod.z.boolean().optional(),
826
813
  audioThresholdDbfs: zod.z.number().optional()
@@ -856,18 +843,6 @@ var RecordingBandSchema = zod.z.object({
856
843
  preBufferSec: zod.z.number().min(0).optional(),
857
844
  postBufferSec: zod.z.number().min(0).optional()
858
845
  });
859
- var RecordingRuleSchema = zod.z.object({
860
- schedule: RecordingScheduleSchema,
861
- mode: RecordingModeSchema,
862
- /** Seconds of footage to retain BEFORE a trigger (applied at keep/discard). */
863
- preBufferSec: zod.z.number().min(0).default(0),
864
- /** Keep recording until this many seconds after the last trigger. */
865
- postBufferSec: zod.z.number().min(0).default(0),
866
- /** Each new trigger restarts the post-buffer window. */
867
- resetTimeoutOnNewEvent: zod.z.boolean().default(true),
868
- /** onAudioThreshold only — dBFS level that counts as a trigger. */
869
- thresholdDbfs: zod.z.number().optional()
870
- });
871
846
  /**
872
847
  * Per-device retention overrides. Every field is optional; an unset or `0`
873
848
  * value inherits the node-wide recorder default. Only footage-lifetime limits
@@ -960,40 +935,28 @@ function resolveScrubThumbnailGeometry(preset) {
960
935
  /**
961
936
  * The full per-camera recording intent — the wire shape of a RecordingTarget.
962
937
  *
963
- * `mode` is the authoritative storage choice; `schedule`/`triggers`/`pre`/`post`
964
- * are its mode-specific parameters. `rules` is a DEPRECATED authoring input kept
965
- * only for transition + migration (`migrateRulesToMode`); the policy engine
966
- * consumes the compiled output of `compileRules(config)`, never `rules` directly.
938
+ * `bands` is the ONLY authored recording intent: what to record, when, and on
939
+ * which trigger. `mode` is a derived summary the recorder stamps on save; every
940
+ * other field is a storage knob (profiles, segment length, retention, scrub).
941
+ *
942
+ * STRICT on purpose: the legacy authoring surface (`schedule`/`schedules`/
943
+ * `triggers`/`preBufferSec`/`postBufferSec`/`rules`) was retired 2026-07-30.
944
+ * A stale caller must fail loudly — silently stripping its legacy intent would
945
+ * persist a band-less config, i.e. silently stop recording the camera.
967
946
  */
968
947
  var RecordingConfigSchema = zod.z.object({
969
948
  enabled: zod.z.boolean(),
970
- /** Authoritative storage mode. Absent on legacy targets derived once via
971
- * `migrateRulesToMode`, then persisted. */
949
+ /** DERIVED summary of `bands`, stamped by the recorder on every save.
950
+ * Authoring it has no effect — see {@link RecordingStorageModeSchema}. */
972
951
  mode: RecordingStorageModeSchema.optional(),
973
952
  profiles: zod.z.array(require_sleep.CamProfileSchema).optional(),
974
953
  segmentSeconds: zod.z.number().int().positive().optional(),
975
- /** Shared recording time-bands for `events` & `continuous` — record only when
976
- * the wall-clock falls inside one of these windows. Omit or empty = always.
977
- * `continuous` compiles to one rule per band; `events` to band × trigger. */
978
- schedules: zod.z.array(RecordingScheduleSchema).optional(),
979
- /** Legacy single-band predecessor of `schedules`. Read-compat only — it is
980
- * normalized into `schedules` on read and never written going forward. (Not
981
- * tagged `@deprecated`: the normalization paths must read it cast-free.) */
982
- schedule: RecordingScheduleSchema.optional(),
983
- /** `events`-mode only — which detectors trigger a recording. */
984
- triggers: RecordingTriggersSchema.optional(),
985
- /** `events`-mode only — seconds retained before / after a trigger. */
986
- preBufferSec: zod.z.number().min(0).optional(),
987
- postBufferSec: zod.z.number().min(0).optional(),
988
- /** DEPRECATED authoring input; retained for migration/transition. */
989
- rules: zod.z.array(RecordingRuleSchema).optional(),
990
954
  /**
991
- * AUTHORITATIVE mode-per-band recording model (recorder). When present it
992
- * is the single source of truth; the legacy `mode`/`schedules`/`schedule`/
993
- * `triggers`/`rules` fields above are kept for READ-COMPAT only and are
994
- * derived into bands once via `migrateConfigToBands`.
955
+ * AUTHORITATIVE mode-per-band recording model the single source of truth
956
+ * the recorder's band engine consumes. An empty array = record nothing;
957
+ * "off" is the absence of a covering band, never a band value.
995
958
  */
996
- bands: zod.z.array(RecordingBandSchema).optional(),
959
+ bands: zod.z.array(RecordingBandSchema).default([]),
997
960
  retention: RecordingRetentionSchema.optional(),
998
961
  /**
999
962
  * Per-camera scrub-thumbnail fidelity preset (resolution + JPEG quality for
@@ -1001,62 +964,30 @@ var RecordingConfigSchema = zod.z.object({
1001
964
  * windows only — existing sheets are immutable, and each window's index
1002
965
  * carries its own tile dims so mixed-preset history renders correctly.
1003
966
  */
1004
- scrubThumbnails: ScrubThumbnailPresetSchema.optional()
1005
- });
1006
- //#endregion
1007
- //#region src/interfaces/recording-config-migrate.ts
1008
- /** All seven weekdays (0 = Sunday 6 = Saturday), used when a schedule omits a
1009
- * weekday filter. */
1010
- var ALL_DAYS = [
1011
- 0,
1012
- 1,
1013
- 2,
1014
- 3,
1015
- 4,
1016
- 5,
1017
- 6
1018
- ];
1019
- /** Full-day span used to represent an `always` schedule as a band. The `HHMM`
1020
- * regex maxes out at 23:59, so a 00:00–23:59 same-day span all-day (the band
1021
- * engine treats `end > start` as a normal, non-wrapping span). */
1022
- var ALL_DAY_START = "00:00";
1023
- var ALL_DAY_END = "23:59";
1024
- function bandFromSchedule(schedule, mode, config) {
1025
- const days = schedule.kind === "timeOfDay" && schedule.days ? schedule.days : [...ALL_DAYS];
1026
- const start = schedule.kind === "timeOfDay" ? schedule.start : ALL_DAY_START;
1027
- const end = schedule.kind === "timeOfDay" ? schedule.end : ALL_DAY_END;
1028
- if (mode === "continuous") return {
1029
- days,
1030
- start,
1031
- end,
1032
- mode
1033
- };
1034
- return {
1035
- days,
1036
- start,
1037
- end,
1038
- mode,
1039
- ...config.triggers ? { triggers: config.triggers } : {},
1040
- ...config.preBufferSec !== void 0 ? { preBufferSec: config.preBufferSec } : {},
1041
- ...config.postBufferSec !== void 0 ? { postBufferSec: config.postBufferSec } : {}
1042
- };
1043
- }
1044
- /**
1045
- * One-way migration from the legacy recording-config shape to the authoritative
1046
- * mode-per-band model. Pure (no clock access).
1047
- *
1048
- * - If `config.bands` is present, it is authoritative and returned as-is.
1049
- * - Otherwise the result is derived from the legacy fields: a disabled config or
1050
- * `mode: 'off'` yields no bands; every legacy schedule maps to one band whose
1051
- * mode is `continuous` when `config.mode === 'continuous'`, else `events`
1052
- * (carrying `triggers`/`preBufferSec`/`postBufferSec`).
1053
- */
1054
- function migrateConfigToBands(config) {
1055
- if (config.bands) return config.bands;
1056
- if (!config.enabled || config.mode === "off") return [];
1057
- const schedules = config.schedules ?? (config.schedule ? [config.schedule] : [{ kind: "always" }]);
1058
- const bandMode = config.mode === "continuous" ? "continuous" : "events";
1059
- return schedules.map((schedule) => bandFromSchedule(schedule, bandMode, config));
967
+ scrubThumbnails: ScrubThumbnailPresetSchema.optional(),
968
+ /**
969
+ * OPT-IN thumbnail-strip generation for this camera: every keyframe of the
970
+ * low recording saved as a JPEG (the fast-drag scrub depth), a derived
971
+ * cache that eviction reclaims with the footage. Absent/false = no strips
972
+ * are written and scrub reads exact keyframes at every velocity.
973
+ */
974
+ stripsEnabled: zod.z.boolean().optional()
975
+ }).strict();
976
+ /**
977
+ * Derive the {@link RecordingStorageModeSchema} summary from the authoritative
978
+ * bands: `continuous` when any band records continuously, `events` when a band
979
+ * exists at all, else `off`. Pure.
980
+ *
981
+ * THE one definition: the recorder stamps `config.mode` with it on save and
982
+ * reports it as the cap's `activeMode`, and the settings UI reads it back to
983
+ * decide which authoring tab a config opens in. Two copies would drift, and the
984
+ * symptom (a status dot disagreeing with what is being recorded) is exactly the
985
+ * bug this field was added to fix.
986
+ */
987
+ function deriveRecordingMode(config) {
988
+ if (!config.enabled || config.bands.length === 0) return "off";
989
+ if (config.bands.some((band) => band.mode === "continuous")) return "continuous";
990
+ return "events";
1060
991
  }
1061
992
  //#endregion
1062
993
  //#region src/interfaces/ops-log.ts
@@ -1078,7 +1009,8 @@ var OpsLogOpSchema = zod.z.enum([
1078
1009
  "prune",
1079
1010
  "manual-delete",
1080
1011
  "rescan",
1081
- "retention-run"
1012
+ "retention-run",
1013
+ "relocate"
1082
1014
  ]);
1083
1015
  /** Why the operation ran. */
1084
1016
  var OpsLogReasonSchema = zod.z.enum([
@@ -1124,6 +1056,57 @@ var OPS_LOG_RING_DEFAULT_MAX = 500;
1124
1056
  /** Default page size for a `listOpsLog` query when the caller omits `limit`. */
1125
1057
  var OPS_LOG_DEFAULT_LIMIT = 200;
1126
1058
  //#endregion
1059
+ //#region src/interfaces/relocate.ts
1060
+ /**
1061
+ * Entity-relocation job state (storage entity-routing spec, Phase 4).
1062
+ *
1063
+ * One shape shared by the recorder's `relocateFootage` (segments + strips) and
1064
+ * pipeline-analytics' `relocateMedia` (event media blobs) so the admin Data
1065
+ * page renders both movers with one component. Jobs are in-RAM (a restart
1066
+ * forgets them — re-running is safe by construction: copy-if-absent, delete
1067
+ * after verify) and each completed/failed run also lands one durable ops-log
1068
+ * row on the owning addon's surface.
1069
+ */
1070
+ var RelocateJobStateSchema = zod.z.enum([
1071
+ "running",
1072
+ "done",
1073
+ "failed",
1074
+ "cancelled"
1075
+ ]);
1076
+ var RelocateJobSchema = zod.z.object({
1077
+ jobId: zod.z.string(),
1078
+ state: RelocateJobStateSchema,
1079
+ /** Source location — for media relocation this is informational ('*': rows
1080
+ * move from wherever they are to the target). */
1081
+ fromLocationId: zod.z.string(),
1082
+ toLocationId: zod.z.string(),
1083
+ /** Scoped device, or null = every device. */
1084
+ deviceId: zod.z.number().nullable(),
1085
+ /** What the job moves (owner-addon specific: segments/strips or media). */
1086
+ entities: zod.z.array(zod.z.string()),
1087
+ filesMoved: zod.z.number().int(),
1088
+ bytesMoved: zod.z.number().int(),
1089
+ /** Total files discovered up front; null while (or when) unknown. */
1090
+ filesTotal: zod.z.number().int().nullable(),
1091
+ startedAt: zod.z.number(),
1092
+ finishedAt: zod.z.number().nullable(),
1093
+ error: zod.z.string().nullable()
1094
+ });
1095
+ var RelocateFootageInputSchema = zod.z.object({
1096
+ deviceId: zod.z.number().optional(),
1097
+ fromLocationId: zod.z.string(),
1098
+ toLocationId: zod.z.string(),
1099
+ entities: zod.z.array(zod.z.enum(["segments", "strips"])).optional(),
1100
+ /** Copy throttle in MB/s (default 40) — the drain is a background chore,
1101
+ * never allowed to starve live writers. */
1102
+ throttleMbps: zod.z.number().min(1).max(1e3).optional()
1103
+ });
1104
+ var RelocateMediaInputSchema = zod.z.object({
1105
+ deviceId: zod.z.number().optional(),
1106
+ toLocationId: zod.z.string(),
1107
+ throttleMbps: zod.z.number().min(1).max(1e3).optional()
1108
+ });
1109
+ //#endregion
1127
1110
  //#region src/interfaces/logging.ts
1128
1111
  /**
1129
1112
  * Severity ordering. Declared once here because it had already been re-declared
@@ -1197,6 +1180,13 @@ var StorageLocationSchema = zod.z.object({
1197
1180
  nodeId: zod.z.string().optional(),
1198
1181
  isDefault: zod.z.boolean().default(false),
1199
1182
  isSystem: zod.z.boolean().default(false),
1183
+ /** COMPUTED at read time by the orchestrator (statfs of the backing volume
1184
+ * for node-local locations it can reach) — never persisted, absent when the
1185
+ * volume is remote/unreachable. The single capacity truth every UI reads. */
1186
+ capacity: zod.z.object({
1187
+ totalBytes: zod.z.number(),
1188
+ availableBytes: zod.z.number()
1189
+ }).nullable().optional(),
1200
1190
  createdAt: zod.z.number(),
1201
1191
  updatedAt: zod.z.number()
1202
1192
  });
@@ -4344,9 +4334,20 @@ var DEGRADE_ORDER = {
4344
4334
  "markdown"
4345
4335
  ]
4346
4336
  };
4347
- /** Pick the best target format the kind supports for a given source format. */
4337
+ /**
4338
+ * Pick the best target format the kind supports for a given source format.
4339
+ *
4340
+ * TOLERANT of a source outside the union. `NotificationSchema.format` carries
4341
+ * `.default('text')`, but that default only runs where the schema is PARSED —
4342
+ * the tRPC router. A cap call arriving from another addon (`ctx.api`) skips
4343
+ * that parse, so `format` reaches here `undefined`, and the bare
4344
+ * `DEGRADE_ORDER[source]` threw `is not iterable`. That broke the one promise
4345
+ * the degrade path makes ("never throws — degradation is reported, never
4346
+ * surfaced as an error") and dead-lettered every Notification-Center delivery
4347
+ * for a day (2026-07-30). An unknown source degrades like `text`.
4348
+ */
4348
4349
  function resolveFormat(source, supported) {
4349
- for (const candidate of DEGRADE_ORDER[source]) if (supported.includes(candidate)) return candidate;
4350
+ for (const candidate of DEGRADE_ORDER[source] ?? DEGRADE_ORDER.text) if (supported.includes(candidate)) return candidate;
4350
4351
  return supported[0] ?? "text";
4351
4352
  }
4352
4353
  /** Transcode a body between formats. */
@@ -4393,7 +4394,7 @@ function resolveLevel(levels, n) {
4393
4394
  })[0]);
4394
4395
  }
4395
4396
  function splitBody(body, maxLen) {
4396
- if (maxLen <= 0 || body.length <= maxLen) return [body];
4397
+ if (!Number.isFinite(maxLen) || maxLen <= 0 || body.length <= maxLen) return [body];
4397
4398
  const parts = [];
4398
4399
  for (let i = 0; i < body.length; i += maxLen) parts.push(body.slice(i, i + maxLen));
4399
4400
  return parts;
@@ -4477,6 +4478,114 @@ function prepareNotification(caps, n) {
4477
4478
  };
4478
4479
  }
4479
4480
  //#endregion
4481
+ //#region src/notification/condition-taxonomy.ts
4482
+ /** Condition ids that render the class picker (video macros/subs + audio). */
4483
+ var CLASS_CONDITION_IDS = new Set(["classes", "classesExclude"]);
4484
+ /** Condition ids that render the sensor/control label picker. */
4485
+ var LABEL_CONDITION_IDS = new Set(["sensorKinds"]);
4486
+ function toOption(entry) {
4487
+ return {
4488
+ value: entry.kind,
4489
+ label: entry.label
4490
+ };
4491
+ }
4492
+ /**
4493
+ * Group detection entries by their macro. A macro entry (`parentKind === null`)
4494
+ * opens its own group and is itself the first option in it; subs fall under
4495
+ * their `parentKind`. First-appearance order is preserved, which is why
4496
+ * `buildNcTaxonomy` emits macros before their subs.
4497
+ */
4498
+ function groupVideoClasses(videoClasses) {
4499
+ const order = [];
4500
+ const byKey = /* @__PURE__ */ new Map();
4501
+ const ensure = (key, fallbackLabel) => {
4502
+ const existing = byKey.get(key);
4503
+ if (existing !== void 0) return existing;
4504
+ const created = {
4505
+ fallbackLabel,
4506
+ options: []
4507
+ };
4508
+ byKey.set(key, created);
4509
+ order.push(key);
4510
+ return created;
4511
+ };
4512
+ for (const entry of videoClasses) {
4513
+ const key = entry.parentKind ?? entry.kind;
4514
+ const group = ensure(key, entry.parentKind === null ? entry.label : key);
4515
+ group.options.push(toOption(entry));
4516
+ if (entry.parentKind === null) group.fallbackLabel = entry.label;
4517
+ }
4518
+ return order.flatMap((key) => {
4519
+ const group = byKey.get(key);
4520
+ return group === void 0 ? [] : [{
4521
+ key,
4522
+ fallbackLabel: group.fallbackLabel,
4523
+ options: group.options
4524
+ }];
4525
+ });
4526
+ }
4527
+ /** Group sensor/control labels by their category parent (`sensor` | `control`). */
4528
+ function groupLabels(labels) {
4529
+ const order = [];
4530
+ const byKey = /* @__PURE__ */ new Map();
4531
+ for (const entry of labels) {
4532
+ const key = entry.parentKind ?? "other";
4533
+ const existing = byKey.get(key);
4534
+ if (existing === void 0) {
4535
+ byKey.set(key, [toOption(entry)]);
4536
+ order.push(key);
4537
+ } else existing.push(toOption(entry));
4538
+ }
4539
+ return order.flatMap((key) => {
4540
+ const options = byKey.get(key);
4541
+ return options === void 0 ? [] : [{
4542
+ key,
4543
+ fallbackLabel: key,
4544
+ options
4545
+ }];
4546
+ });
4547
+ }
4548
+ /**
4549
+ * Build the grouped picker model for a condition id, or `null` when the
4550
+ * condition has no fixed vocabulary (→ free-text tag input).
4551
+ */
4552
+ function pickerForCondition(conditionId, taxonomy) {
4553
+ if (!taxonomy) return null;
4554
+ if (CLASS_CONDITION_IDS.has(conditionId)) {
4555
+ const groups = groupVideoClasses(taxonomy.videoClasses);
4556
+ if (taxonomy.audioKinds.length > 0) groups.push({
4557
+ key: "audio",
4558
+ fallbackLabel: "Audio",
4559
+ options: taxonomy.audioKinds.map(toOption)
4560
+ });
4561
+ return groups.length > 0 ? { groups } : null;
4562
+ }
4563
+ if (LABEL_CONDITION_IDS.has(conditionId)) {
4564
+ const groups = groupLabels(taxonomy.labels);
4565
+ return groups.length > 0 ? { groups } : null;
4566
+ }
4567
+ return null;
4568
+ }
4569
+ /** All option values across a picker's groups (for custom-value detection). */
4570
+ function knownValues(picker) {
4571
+ const set = /* @__PURE__ */ new Set();
4572
+ for (const group of picker.groups) for (const option of group.options) set.add(option.value);
4573
+ return set;
4574
+ }
4575
+ /**
4576
+ * The condition ids shown in the ALWAYS-VISIBLE area of a rule editor. Every
4577
+ * other catalog descriptor is advanced and lives behind an expander.
4578
+ *
4579
+ * Shared for the same reason as the picker model: two surfaces disagreeing
4580
+ * about what counts as "basic" is a worse outcome than either choice.
4581
+ */
4582
+ var NC_BASE_CONDITION_KEYS = ["devices", "classes"];
4583
+ var BASE_CONDITION_SET = new Set(NC_BASE_CONDITION_KEYS);
4584
+ /** True when a condition key belongs to the BASE surface. */
4585
+ function isBaseConditionKey(key) {
4586
+ return BASE_CONDITION_SET.has(key);
4587
+ }
4588
+ //#endregion
4480
4589
  //#region src/capabilities/mask-shape.ts
4481
4590
  /**
4482
4591
  * Shared geometry vocabulary for on-frame shape caps — privacy-mask,
@@ -4649,6 +4758,29 @@ var NcOccupancyConditionSchema = zod.z.object({
4649
4758
  count: zod.z.number().int().min(0).default(1),
4650
4759
  sustainSeconds: zod.z.number().int().min(0).max(3600).default(15)
4651
4760
  });
4761
+ /**
4762
+ * Which zone-crossing DIRECTION a rule accepts (`ObjectEvent.zoneCrossing`).
4763
+ *
4764
+ * The values are not symmetric, and deliberately so — the absent value has to
4765
+ * mean exactly what every rule authored before this condition existed already
4766
+ * does:
4767
+ * - `enter` — entries and every NON-crossing record (movement state,
4768
+ * package, sensor). Exits are rejected. **This is the absent behaviour**:
4769
+ * an operator who never asked for exits must not start receiving them.
4770
+ * - `exit` — ONLY an exit crossing. A record that is not a crossing at all
4771
+ * fails closed, because "the car left the drive" is a question about a
4772
+ * boundary, not about a detection.
4773
+ * - `any` — no direction filter; entries, exits and non-crossings alike.
4774
+ *
4775
+ * A rule asking for a direction should normally also scope `zones`, which the
4776
+ * engine evaluates against the crossed zone as well as the current membership
4777
+ * (an exit's membership no longer contains the zone it just left).
4778
+ */
4779
+ var NcCrossingSchema = zod.z.enum([
4780
+ "enter",
4781
+ "exit",
4782
+ "any"
4783
+ ]);
4652
4784
  /** Admin-zone membership condition (zone IDs as stamped by the ZoneEngine). */
4653
4785
  var NcZoneConditionSchema = zod.z.object({
4654
4786
  ids: zod.z.array(zod.z.string().min(1)).min(1),
@@ -4673,6 +4805,13 @@ var NcConditionsSchema = zod.z.object({
4673
4805
  /** Veto zones — any hit fails the rule. */
4674
4806
  zonesExclude: zod.z.array(zod.z.string().min(1)).optional(),
4675
4807
  /**
4808
+ * Zone-crossing direction. IMMEDIATE only — a crossing is a per-event fact
4809
+ * and a closed track carries none, so a `track-end` rule asking for one
4810
+ * fails closed (use `zones`, which tests `zonesVisited`). ABSENT = `enter`,
4811
+ * which is exactly today's behaviour. See {@link NcCrossingSchema}.
4812
+ */
4813
+ crossing: NcCrossingSchema.optional(),
4814
+ /**
4676
4815
  * Exact (case-insensitive) match on the record's collapsed `label`
4677
4816
  * (identity name / plate text / subclass).
4678
4817
  */
@@ -4807,17 +4946,85 @@ var NcRuleTargetSchema = zod.z.object({
4807
4946
  * - `keyFrame` — the clean scene frame (no subject box).
4808
4947
  * - `none` — no attachment.
4809
4948
  */
4810
- var NcMediaPolicySchema = zod.z.object({ attach: zod.z.enum([
4811
- "best",
4812
- "best-matching",
4813
- "keyFrame",
4814
- "none"
4815
- ]).default("best") });
4949
+ /**
4950
+ * WHAT THE PICTURE SHOWS — chosen explicitly, because the implicit ladders
4951
+ * conflate it with the selection strategy and betray the request: asking for
4952
+ * the clean scene frame on an object-event owner used to start at
4953
+ * `fullFrameBoxed`, i.e. the annotated frame (2026-07-30).
4954
+ * - `cropped` — the subject, tight. What "who is at the door" wants.
4955
+ * - `full` — the clean scene, no annotation. What "what is going on" wants.
4956
+ * - `boxed` — the scene WITH the detection boxes drawn, for verifying what
4957
+ * the pipeline actually saw.
4958
+ */
4959
+ var NcMediaFrameSchema = zod.z.enum([
4960
+ "cropped",
4961
+ "full",
4962
+ "boxed"
4963
+ ]);
4964
+ var NcMediaPolicySchema = zod.z.object({
4965
+ attach: zod.z.enum([
4966
+ "best",
4967
+ "best-matching",
4968
+ "keyFrame",
4969
+ "none"
4970
+ ]).default("best"),
4971
+ /** What the still shows. Absent = `cropped` (the historical `best` shape). */
4972
+ frame: NcMediaFrameSchema.optional(),
4973
+ /** Crop the attached still to the rule's condition-zone bbox (padded) —
4974
+ * "show me the ZONE", not the whole scene or the subject crop. */
4975
+ zoneCrop: zod.z.boolean().optional(),
4976
+ /**
4977
+ * Also attach a short GIF cut from the stream broker's clip ring around the
4978
+ * event — NOT from the recording, so the camera does not have to be
4979
+ * recording, and the window sits AROUND the moment instead of a segment
4980
+ * behind it. Fail-closed: a window the ring does not cover contributes no
4981
+ * gif, never a failed notification.
4982
+ */
4983
+ gif: zod.z.boolean().optional(),
4984
+ /**
4985
+ * Also attach a short MP4 CLIP of the same cut. Same source and the same
4986
+ * fail-closed rule as `gif`. Prefer it where the backend takes video
4987
+ * (telegram, discord, zentik, webhook); backends that do not are handled by
4988
+ * the degrade engine, which drops the video and keeps the still.
4989
+ */
4990
+ clip: zod.z.boolean().optional(),
4991
+ /** Seconds of footage BEFORE / AFTER the event instant. Defaults 3 / 7. */
4992
+ clipPreRollSec: zod.z.number().int().min(0).max(30).optional(),
4993
+ clipPostRollSec: zod.z.number().int().min(0).max(30).optional(),
4994
+ /**
4995
+ * Which stream profile the footage is cut from. Absent = the CHEAPEST
4996
+ * assigned profile: a notification is watched on a phone, so the 4K
4997
+ * rendition would burn CPU to produce a file the client downscales anyway.
4998
+ * A profile that is not assigned falls back to the cheapest, and the render
4999
+ * reports which one actually ran.
5000
+ */
5001
+ profile: require_sleep.CamProfileSchema.optional()
5002
+ });
5003
+ /**
5004
+ * Cooldown GRANULARITY over the subject's class — how much a fired
5005
+ * notification suppresses.
5006
+ * - `shared` (default, and the absent value) — one window for the whole
5007
+ * rule/scope: a cat silences the next dog for `cooldownSec`.
5008
+ * - `per-class` — an independent window per detected class, so cat→dog fires
5009
+ * at once and cat→cat still waits.
5010
+ *
5011
+ * AUDIO subjects are ALWAYS per-class regardless of this setting: a scream
5012
+ * must not be swallowed by a bark's window (the precedent this generalizes —
5013
+ * see `cooldownKey` in the rule engine).
5014
+ */
5015
+ var NcThrottleGranularitySchema = zod.z.enum(["shared", "per-class"]);
4816
5016
  /** Throttle — cooldown survives restarts (rebuilt from the outbox on boot). */
4817
5017
  var NcThrottleSchema = zod.z.object({
4818
5018
  cooldownSec: zod.z.number().int().min(0).max(86400).default(60),
4819
5019
  /** `rule` = one shared cooldown; `rule-device` = per-camera cooldown. */
4820
- scope: zod.z.enum(["rule", "rule-device"]).default("rule-device")
5020
+ scope: zod.z.enum(["rule", "rule-device"]).default("rule-device"),
5021
+ /**
5022
+ * Class granularity of the cooldown key. Optional rather than defaulted:
5023
+ * a Zod default does NOT run on the addon→addon cap path, so a persisted
5024
+ * rule authored before this field simply carries none — and the engine
5025
+ * reads absent as `shared`, the pre-existing behaviour.
5026
+ */
5027
+ granularity: NcThrottleGranularitySchema.optional()
4821
5028
  });
4822
5029
  /** Client-supplied rule fields (server stamps id/createdBy/createdAt/updatedAt). */
4823
5030
  var NcRuleInputSchema = zod.z.object({
@@ -4826,7 +5033,19 @@ var NcRuleInputSchema = zod.z.object({
4826
5033
  delivery: NcDeliverySchema,
4827
5034
  conditions: NcConditionsSchema.default({}),
4828
5035
  schedule: NcScheduleSchema.optional(),
4829
- targets: zod.z.array(NcRuleTargetSchema).min(1),
5036
+ /** May be empty when `targetUsers` addresses at least one user — the
5037
+ * "at least one addressee" invariant is enforced by the provider, because
5038
+ * a cross-field refine here would break `NcRulePatchSchema.partial()`. */
5039
+ targets: zod.z.array(NcRuleTargetSchema),
5040
+ /**
5041
+ * USERS this rule addresses in addition to `targets` (Phase 4). At fire
5042
+ * time each user fans out to the personal targets they own
5043
+ * (`config.ownerUserId`), filtered by that user's `allowedDevices` for the
5044
+ * firing camera — a user is never notified about a device they cannot open.
5045
+ * Per-user opt-outs (`disabledTargetIds`) still apply to the fanned-out
5046
+ * targets.
5047
+ */
5048
+ targetUsers: zod.z.array(zod.z.string()).optional(),
4830
5049
  media: NcMediaPolicySchema.default({ attach: "best" }),
4831
5050
  throttle: NcThrottleSchema.default({
4832
5051
  cooldownSec: 60,
@@ -4913,6 +5132,7 @@ var NcConditionDescriptorSchema = zod.z.object({
4913
5132
  "schedule",
4914
5133
  "plateMatcher",
4915
5134
  "packagePhase",
5135
+ "crossingSelect",
4916
5136
  "polygonDraw",
4917
5137
  "occupancy"
4918
5138
  ]),
@@ -5017,6 +5237,16 @@ var NC_CONDITION_CATALOG = [
5017
5237
  ],
5018
5238
  phase: "P1"
5019
5239
  },
5240
+ {
5241
+ id: "crossing",
5242
+ group: "zones",
5243
+ label: "Zone crossing",
5244
+ valueType: "crossingSelect",
5245
+ operator: "in",
5246
+ appliesTo: ["immediate"],
5247
+ phase: "P1",
5248
+ description: "Direction of the zone crossing: enter (the default, and what every rule authored before this did) / exit / any. An exit rule matches only crossings."
5249
+ },
5020
5250
  {
5021
5251
  id: "labelEquals",
5022
5252
  group: "label",
@@ -5301,7 +5531,20 @@ var notificationRulesCapability = {
5301
5531
  kind: "mutation",
5302
5532
  auth: "admin"
5303
5533
  }),
5304
- getConditionCatalog: require_sleep.method(zod.z.object({}), zod.z.object({ catalog: zod.z.array(NcConditionDescriptorSchema) })),
5534
+ /**
5535
+ * The machine-readable condition surface a rule editor renders from, plus
5536
+ * the picker VOCABULARY those conditions draw on.
5537
+ *
5538
+ * `taxonomy` is optional so an older provider that only returns `catalog`
5539
+ * still validates; a client that receives none keeps free-text inputs.
5540
+ * It was previously served ONLY on the `nc.getConditionCatalog` bridge
5541
+ * action, which is why the viewer had grouped pickers and the admin UI —
5542
+ * which reaches this cap — was stuck typing `person` from memory.
5543
+ */
5544
+ getConditionCatalog: require_sleep.method(zod.z.object({}), zod.z.object({
5545
+ catalog: zod.z.array(NcConditionDescriptorSchema),
5546
+ taxonomy: NcTaxonomySchema.optional()
5547
+ })),
5305
5548
  /**
5306
5549
  * Queryable delivery history — a read-only view over the durable outbox
5307
5550
  * (fired rule, subject summary, target, status, timestamps, error on a
@@ -6390,6 +6633,48 @@ var streamBrokerCapability = {
6390
6633
  kind: "mutation",
6391
6634
  auth: "admin"
6392
6635
  }),
6636
+ /**
6637
+ * Render a short GIF or MP4 from the broker's PRE-BUFFER around an instant.
6638
+ *
6639
+ * The pre-buffer is the only source that already holds the seconds BEFORE
6640
+ * an event (it is what it exists for — "when an addon needs the last N
6641
+ * seconds of video for clip creation"). Cutting from recorded segments
6642
+ * cannot: only finalized segments are addressable and the one covering the
6643
+ * moment is still being written, so a segment-sourced clip is either
6644
+ * delayed or shows the approach instead of the event (operator,
6645
+ * 2026-07-30). It also means a camera does not have to be RECORDING to
6646
+ * produce a notification clip.
6647
+ *
6648
+ * Returns muxed BYTES, never packets: the frame plane never crosses a
6649
+ * process boundary at frame rate (D9/D18) — this is one compressed,
6650
+ * on-demand payload per notification.
6651
+ *
6652
+ * Waits up to `postRollSec` for the tail to accumulate, so the window is
6653
+ * CENTRED on `aroundMs`.
6654
+ */
6655
+ renderPreBufferClip: require_sleep.method(zod.z.object({
6656
+ deviceId: zod.z.number(),
6657
+ /** Absent = the LOWEST assigned profile — a notification attachment is
6658
+ * watched on a phone, and the cheap rendition is the right default. */
6659
+ profile: require_sleep.CamProfileSchema.optional(),
6660
+ aroundMs: zod.z.number(),
6661
+ preRollSec: zod.z.number().min(0).max(20).default(3),
6662
+ postRollSec: zod.z.number().min(0).max(20).default(5),
6663
+ format: zod.z.enum(["gif", "mp4"]).default("gif"),
6664
+ maxWidth: zod.z.number().int().min(120).max(1920).default(480),
6665
+ /** GIF only — MP4 keeps the source cadence. */
6666
+ fps: zod.z.number().int().min(1).max(15).default(5)
6667
+ }), zod.z.object({
6668
+ base64: zod.z.string(),
6669
+ mime: zod.z.string(),
6670
+ bytes: zod.z.number().int(),
6671
+ /** The profile actually rendered (what the default resolved to). */
6672
+ profile: require_sleep.CamProfileSchema,
6673
+ durationMs: zod.z.number()
6674
+ }), {
6675
+ kind: "mutation",
6676
+ auth: "admin"
6677
+ }),
6393
6678
  listAllCameraStreams: require_sleep.method(zod.z.void(), zod.z.array(require_sleep.CameraStreamSchema).readonly()),
6394
6679
  listAllProfileSlots: require_sleep.method(zod.z.void(), zod.z.array(require_sleep.ProfileSlotSchema).readonly()),
6395
6680
  getBrokerStats: require_sleep.method(zod.z.object({ brokerId: zod.z.string() }), require_sleep.BrokerStatsSchema),
@@ -14362,7 +14647,8 @@ function createSystemProxy(api) {
14362
14647
  discoverAllProviders: (input) => dispatch("deviceManager", "discoverAllProviders", "mutation", input),
14363
14648
  discoverProvider: (input) => dispatch("deviceManager", "discoverProvider", "mutation", input),
14364
14649
  providerCreationType: (input) => dispatch("deviceManager", "providerCreationType", "query", input),
14365
- providerDiscoveryParamsSchema: (input) => dispatch("deviceManager", "providerDiscoveryParamsSchema", "query", input)
14650
+ providerDiscoveryParamsSchema: (input) => dispatch("deviceManager", "providerDiscoveryParamsSchema", "query", input),
14651
+ getDeviceStatusAggregateBatch: (input) => dispatch("deviceManager", "getDeviceStatusAggregateBatch", "query", input)
14366
14652
  },
14367
14653
  deviceProvider: {
14368
14654
  start: (input) => dispatch("deviceProvider", "start", "mutation", input),
@@ -14433,6 +14719,8 @@ function createSystemProxy(api) {
14433
14719
  list: (input) => dispatch("localNetwork", "list", "query", input),
14434
14720
  getPreferred: (input) => dispatch("localNetwork", "getPreferred", "query", input),
14435
14721
  getConnectionEndpoints: (input) => dispatch("localNetwork", "getConnectionEndpoints", "query", input),
14722
+ getNotificationEndpoint: (input) => dispatch("localNetwork", "getNotificationEndpoint", "query", input),
14723
+ setNotificationEndpoint: (input) => dispatch("localNetwork", "setNotificationEndpoint", "mutation", input),
14436
14724
  getAllowedAddresses: (input) => dispatch("localNetwork", "getAllowedAddresses", "query", input),
14437
14725
  setAllowedAddresses: (input) => dispatch("localNetwork", "setAllowedAddresses", "mutation", input),
14438
14726
  resetAllowlistToBestMatch: (input) => dispatch("localNetwork", "resetAllowlistToBestMatch", "mutation", input)
@@ -14603,7 +14891,10 @@ function createSystemProxy(api) {
14603
14891
  },
14604
14892
  recording: {
14605
14893
  getStorageUsage: (input) => dispatch("recording", "getStorageUsage", "query", input),
14606
- listOpsLog: (input) => dispatch("recording", "listOpsLog", "query", input)
14894
+ listOpsLog: (input) => dispatch("recording", "listOpsLog", "query", input),
14895
+ relocateFootage: (input) => dispatch("recording", "relocateFootage", "mutation", input),
14896
+ getRelocateStatus: (input) => dispatch("recording", "getRelocateStatus", "query", input),
14897
+ cancelRelocate: (input) => dispatch("recording", "cancelRelocate", "mutation", input)
14607
14898
  },
14608
14899
  recordingExport: {
14609
14900
  getExport: (input) => dispatch("recordingExport", "getExport", "query", input),
@@ -18374,7 +18665,29 @@ var deviceManagerCapability = {
18374
18665
  getDeviceStatusAggregate: require_sleep.method(zod.z.object({
18375
18666
  deviceId: zod.z.number(),
18376
18667
  caps: zod.z.array(zod.z.string()).readonly().optional()
18377
- }), zod.z.record(zod.z.string(), zod.z.unknown().nullable()))
18668
+ }), zod.z.record(zod.z.string(), zod.z.unknown().nullable())),
18669
+ /**
18670
+ * The same aggregate, for a LIST of devices in one round-trip.
18671
+ *
18672
+ * The viewer's camera list is the caller this exists for. Each card asked
18673
+ * for its own badges — battery here, recording mode there — so a ten-camera
18674
+ * install issued N separate procedures per reconcile, each its own message
18675
+ * on the one WebSocket that also carries the WebRTC signalling (the client
18676
+ * has no `httpBatchLink`, so there is no transport-level batching to lean
18677
+ * on: collapsing has to happen at the procedure level, which is here).
18678
+ *
18679
+ * Keyed by device id as a STRING — a JSON object cannot key by number, and
18680
+ * pretending otherwise is how a record survives the wire only in tests.
18681
+ * The per-device value is exactly what `getDeviceStatusAggregate` returns,
18682
+ * so a caller can move between the two without reshaping anything.
18683
+ *
18684
+ * `caps` matters more here than in the single call: a client that needs two
18685
+ * caps should not pay for every status-carrying cap × every device.
18686
+ */
18687
+ getDeviceStatusAggregateBatch: require_sleep.method(zod.z.object({
18688
+ deviceIds: zod.z.array(zod.z.number()).readonly(),
18689
+ caps: zod.z.array(zod.z.string()).readonly().optional()
18690
+ }), zod.z.record(zod.z.string(), zod.z.record(zod.z.string(), zod.z.unknown().nullable())))
18378
18691
  }
18379
18692
  };
18380
18693
  //#endregion
@@ -19645,6 +19958,36 @@ var TargetKindSchema = zod.z.object({
19645
19958
  icon: zod.z.string(),
19646
19959
  /** Stamped by each provider so the concat-fanned catalog stays routable. */
19647
19960
  addonId: zod.z.string(),
19961
+ /**
19962
+ * URL of the kind's bundled BRAND icon, served by the providing addon over
19963
+ * its own `addon-routes` surface (`/addon/<addonId>/icons/<kind>`). Absent
19964
+ * when the addon bundles no icon for that kind — the client then falls back
19965
+ * to a neutral glyph rather than rendering the raw `icon` NAME as text.
19966
+ *
19967
+ * Root-relative on purpose: it resolves against whatever origin serves a web
19968
+ * client, and a native client joins it onto its own hub base.
19969
+ *
19970
+ * DECLARED here deliberately. It used to travel as an undeclared passthrough
19971
+ * field that survived only because the runtime cap-router forwards provider
19972
+ * output verbatim — so every consumer had to re-declare it by hand to stop
19973
+ * its own Zod parse from stripping it, and the whole arrangement would have
19974
+ * broken silently the moment output validation was tightened anywhere.
19975
+ */
19976
+ iconUrl: zod.z.string().optional(),
19977
+ /**
19978
+ * Media type of {@link iconUrl} (`image/svg+xml`, `image/png`, …).
19979
+ *
19980
+ * The server knows this and therefore says it, because the client cannot
19981
+ * safely guess: a React-Native client renders SVG and raster through two
19982
+ * DIFFERENT components (`react-native-svg` vs `expo-image` — expo-image does
19983
+ * not decode SVG on iOS/Android), so without this it silently fell back to a
19984
+ * placeholder glyph for every vector icon while the web build looked fine.
19985
+ *
19986
+ * Absent when {@link iconUrl} is absent, or for a legacy provider that has
19987
+ * not been updated — a client that cannot determine the type should prefer
19988
+ * its raster path, which is the safe default for an unknown image.
19989
+ */
19990
+ iconMediaType: zod.z.string().optional(),
19648
19991
  configSchema: ConfigSchemaPassthrough,
19649
19992
  supportsDiscovery: zod.z.boolean(),
19650
19993
  caps: TargetKindCapsSchema
@@ -20118,6 +20461,37 @@ var MotionEventSchema = zod.z.object({
20118
20461
  * Absent on legacy rows ⇒ treat as `pipeline`.
20119
20462
  */
20120
20463
  var DetectionSourceSchema = zod.z.enum(["pipeline", "onboard"]);
20464
+ /**
20465
+ * Which WAY a subject crossed a zone boundary. An entry and an exit are two
20466
+ * different notifications ("the parcel arrived" / "the car left the drive"),
20467
+ * and until this existed they were indistinguishable on the persisted record —
20468
+ * which is why exits were computed and dropped at the emit boundary rather
20469
+ * than doubling every zone-scoped rule.
20470
+ */
20471
+ var ZoneCrossingDirectionSchema = zod.z.enum(["enter", "exit"]);
20472
+ /**
20473
+ * The confirmed zone crossing that produced an object event. Present ONLY on
20474
+ * an event emitted BY a crossing (`zone.enter` / `zone.exit`); a movement-state
20475
+ * event (`object.entering` / `leaving` / `stationary` / `loitering`) and an
20476
+ * appearance event carry none, so a rule asking for a direction fails closed
20477
+ * on them.
20478
+ *
20479
+ * Exactly ONE crossing per event: the emitter turns each confirmed crossing
20480
+ * into its own event, so a frame in which a track enters A while leaving B
20481
+ * produces two events with two directions — never one ambiguous row.
20482
+ *
20483
+ * `zoneId` is load-bearing for an EXIT: the event's `zones` list is the
20484
+ * membership the box has NOW, and by definition it no longer contains the zone
20485
+ * that was just left. Without the id here, a zone-scoped rule could never match
20486
+ * the exit it asked for.
20487
+ */
20488
+ var ZoneCrossingSchema = zod.z.object({
20489
+ direction: ZoneCrossingDirectionSchema,
20490
+ /** Admin zone id crossed. */
20491
+ zoneId: zod.z.string(),
20492
+ /** Zone display name at crossing time (falls back to the id). */
20493
+ zoneName: zod.z.string().optional()
20494
+ });
20121
20495
  var ObjectEventSchema = zod.z.object({
20122
20496
  ...BaseEventFields,
20123
20497
  kind: zod.z.literal("object"),
@@ -20144,6 +20518,12 @@ var ObjectEventSchema = zod.z.object({
20144
20518
  zones: zod.z.array(zod.z.string()).readonly().optional(),
20145
20519
  /** Omitted in slim projection. */
20146
20520
  state: TrackStateSchema.optional(),
20521
+ /**
20522
+ * The zone crossing this event IS, when it is one. Absent on every other
20523
+ * event kind (movement state, appearance, package) — see
20524
+ * {@link ZoneCrossingSchema}. Omitted in slim projection.
20525
+ */
20526
+ zoneCrossing: ZoneCrossingSchema.optional(),
20147
20527
  /** Detection-frame dimensions in pixels — let consumers normalize the
20148
20528
  * pixel-space `bbox` onto a displayed image. Omitted in slim projection. */
20149
20529
  frameWidth: zod.z.number().optional(),
@@ -20523,6 +20903,23 @@ var pipelineAnalyticsCapability = {
20523
20903
  }),
20524
20904
  /** The events ops-log rows (newest-first), optionally scoped to one camera.
20525
20905
  * Backed by a declared pipeline-analytics SQLite collection. */
20906
+ /**
20907
+ * Move event-media blobs onto `toLocationId` (entity-routing spec Phase
20908
+ * 4): per-row copy → stamp row.locationId → delete old blob. Rows already
20909
+ * at the target are skipped, so a re-run resumes. Single-flight.
20910
+ */
20911
+ relocateMedia: require_sleep.method(RelocateMediaInputSchema, zod.z.object({ jobId: zod.z.string() }), {
20912
+ kind: "mutation",
20913
+ auth: "admin"
20914
+ }),
20915
+ getMediaRelocateStatus: require_sleep.method(zod.z.object({}), zod.z.array(RelocateJobSchema).readonly(), {
20916
+ kind: "query",
20917
+ auth: "admin"
20918
+ }),
20919
+ cancelMediaRelocate: require_sleep.method(zod.z.object({ jobId: zod.z.string() }), zod.z.object({ cancelled: zod.z.boolean() }), {
20920
+ kind: "mutation",
20921
+ auth: "admin"
20922
+ }),
20526
20923
  listOpsLog: require_sleep.method(OpsLogQueryInputSchema, zod.z.array(OpsLogEntrySchema).readonly(), {
20527
20924
  kind: "query",
20528
20925
  auth: "admin"
@@ -24160,6 +24557,17 @@ var ConnectionEndpointSchema = zod.z.object({
24160
24557
  priority: zod.z.number()
24161
24558
  });
24162
24559
  var GetConnectionEndpointsResultSchema = zod.z.object({ endpoints: zod.z.array(ConnectionEndpointSchema).readonly() });
24560
+ /**
24561
+ * The chosen outbound endpoint for notification artifacts. `baseUrl: null` =
24562
+ * AUTO (resolved from the candidate ranking at send time); `resolved` reports
24563
+ * what AUTO currently picks, so the UI can show the effective value either way.
24564
+ */
24565
+ var NotificationEndpointSchema = zod.z.object({
24566
+ /** The operator's explicit choice, or null for AUTO. */
24567
+ baseUrl: zod.z.string().nullable(),
24568
+ /** What the ranking currently resolves to (null when nothing is reachable). */
24569
+ resolved: zod.z.string().nullable()
24570
+ });
24163
24571
  var AllowedAddressesSchema = zod.z.object({
24164
24572
  /**
24165
24573
  * Allowlist of interface addresses operators have explicitly opted
@@ -24211,6 +24619,26 @@ var localNetworkCapability = {
24211
24619
  scheme: zod.z.enum(["http", "https"]).optional()
24212
24620
  }), GetConnectionEndpointsResultSchema),
24213
24621
  /**
24622
+ * The endpoint OUTBOUND artifacts must be addressed by — notification
24623
+ * attachment links and deep links. `baseUrl: null` means AUTO: the first
24624
+ * public candidate (a configured origin, then a connected tunnel, then the
24625
+ * LAN), never loopback.
24626
+ *
24627
+ * Why an explicit marker: the automatic ranking cannot know which of
24628
+ * several reachable addresses the RECIPIENT can actually open. A link is
24629
+ * consumed on someone's phone, off the LAN, possibly hours later — and a
24630
+ * link nobody can open is worse than no link, because the notification
24631
+ * arrives advertising media that 404s.
24632
+ */
24633
+ getNotificationEndpoint: require_sleep.method(zod.z.void(), NotificationEndpointSchema),
24634
+ /**
24635
+ * Mark which endpoint notification artifacts use. `baseUrl: null` restores
24636
+ * AUTO. The value is stored verbatim (not an index into the candidate
24637
+ * list): interfaces come and go, and an index would silently re-point at a
24638
+ * different address after a reboot.
24639
+ */
24640
+ setNotificationEndpoint: require_sleep.method(zod.z.object({ baseUrl: zod.z.string().nullable() }), NotificationEndpointSchema, { kind: "mutation" }),
24641
+ /**
24214
24642
  * Read the operator's allowlist. Empty = "auto" (no filter). Used
24215
24643
  * by the admin UI's address selector to seed its checkbox state.
24216
24644
  */
@@ -25322,7 +25750,12 @@ var RecordingDeviceUsageSchema = zod.z.object({
25322
25750
  var RecordingLocationUsageSchema = zod.z.object({
25323
25751
  /** StorageLocation id; null for the legacy/degraded single-root fallback. */
25324
25752
  locationId: zod.z.string().nullable(),
25325
- /** Bytes of recordings stored on this location. */
25753
+ /** Every location id sharing this row's PHYSICAL volume (aliases). One row
25754
+ * is emitted per physical disk (2026-07-29): two locations on one root
25755
+ * previously rendered as two identical "disks" with a nonsensical used
25756
+ * split — hydrate attribution across aliases is arbitrary by nature. */
25757
+ locationIds: zod.z.array(zod.z.string()).optional(),
25758
+ /** Bytes of recordings stored on this PHYSICAL volume (all aliases). */
25326
25759
  usedBytes: zod.z.number(),
25327
25760
  /** Free bytes on the location's volume; null when capacity is unknown (remote). */
25328
25761
  availableBytes: zod.z.number().nullable(),
@@ -25478,6 +25911,77 @@ var recordingCapability = {
25478
25911
  listOpsLog: require_sleep.method(OpsLogQueryInputSchema, zod.z.array(OpsLogEntrySchema).readonly(), {
25479
25912
  kind: "query",
25480
25913
  auth: "admin"
25914
+ }),
25915
+ /**
25916
+ * Move footage (segments and/or strips) from one recordings location to
25917
+ * another — the drain workflow's mover (entity-routing spec Phase 4).
25918
+ * Throttled copy → size-verify → delete source → index refresh; resumable
25919
+ * by construction (copy-if-absent). Single-flight: one job at a time.
25920
+ */
25921
+ /**
25922
+ * Render a short GIF from recorded footage around `aroundMs` (low profile,
25923
+ * palette-free ffmpeg gif). Synchronous — the window is a few seconds of
25924
+ * `low`, rendering in ~1-2s. Built for notification attachments: the
25925
+ * caller gets bytes, nothing persists. Fails when no footage covers the
25926
+ * window (camera not recording → caller skips the attachment).
25927
+ */
25928
+ renderGif: require_sleep.method(zod.z.object({
25929
+ deviceId: zod.z.number(),
25930
+ aroundMs: zod.z.number(),
25931
+ preRollSec: zod.z.number().min(0).max(30).default(2),
25932
+ postRollSec: zod.z.number().min(0).max(30).default(5),
25933
+ maxWidth: zod.z.number().int().min(120).max(1280).default(480),
25934
+ fps: zod.z.number().int().min(1).max(15).default(5)
25935
+ }), zod.z.object({
25936
+ gifBase64: zod.z.string(),
25937
+ fromMs: zod.z.number(),
25938
+ toMs: zod.z.number()
25939
+ }), {
25940
+ kind: "mutation",
25941
+ auth: "admin"
25942
+ }),
25943
+ /**
25944
+ * Render a short MP4 clip from recorded footage around `aroundMs` — the
25945
+ * "send a clip, not a gif" notification attachment. Same window, source
25946
+ * and fail-closed contract as {@link renderGif}: no footage covering the
25947
+ * window ⇒ it throws and the caller ships no attachment. Re-encoded (never
25948
+ * stream-copied) so a concat across segments with different encoder
25949
+ * parameters still plays. Silent by contract.
25950
+ *
25951
+ * The returned window is SEGMENT-GRANULAR: the source playlist is built
25952
+ * from whole segments, so the clip starts at or before `fromMs` and ends
25953
+ * at or after `toMs` — overshoot bounded by one segment per side (an 8 s
25954
+ * ask over 4 s segments measured 12 s). `fromMs`/`toMs` report the window
25955
+ * ASKED for, not the encoded duration.
25956
+ */
25957
+ renderClip: require_sleep.method(zod.z.object({
25958
+ deviceId: zod.z.number(),
25959
+ aroundMs: zod.z.number(),
25960
+ preRollSec: zod.z.number().min(0).max(30).default(3),
25961
+ postRollSec: zod.z.number().min(0).max(30).default(7),
25962
+ maxWidth: zod.z.number().int().min(160).max(1920).default(640)
25963
+ }), zod.z.object({
25964
+ clipBase64: zod.z.string(),
25965
+ mime: zod.z.string(),
25966
+ fromMs: zod.z.number(),
25967
+ toMs: zod.z.number(),
25968
+ bytes: zod.z.number().int()
25969
+ }), {
25970
+ kind: "mutation",
25971
+ auth: "admin"
25972
+ }),
25973
+ relocateFootage: require_sleep.method(RelocateFootageInputSchema, zod.z.object({ jobId: zod.z.string() }), {
25974
+ kind: "mutation",
25975
+ auth: "admin"
25976
+ }),
25977
+ /** Every known relocate job (in-RAM, newest-first). */
25978
+ getRelocateStatus: require_sleep.method(zod.z.object({}), zod.z.array(RelocateJobSchema).readonly(), {
25979
+ kind: "query",
25980
+ auth: "admin"
25981
+ }),
25982
+ cancelRelocate: require_sleep.method(zod.z.object({ jobId: zod.z.string() }), zod.z.object({ cancelled: zod.z.boolean() }), {
25983
+ kind: "mutation",
25984
+ auth: "admin"
25481
25985
  })
25482
25986
  }
25483
25987
  };
@@ -28416,6 +28920,12 @@ var METHOD_ACCESS_MAP = Object.freeze({
28416
28920
  addonId: null,
28417
28921
  access: "view"
28418
28922
  },
28923
+ "deviceManager.getDeviceStatusAggregateBatch": {
28924
+ capName: "device-manager",
28925
+ capScope: "system",
28926
+ addonId: null,
28927
+ access: "view"
28928
+ },
28419
28929
  "deviceManager.getLinkedDevices": {
28420
28930
  capName: "device-manager",
28421
28931
  capScope: "system",
@@ -29310,6 +29820,12 @@ var METHOD_ACCESS_MAP = Object.freeze({
29310
29820
  addonId: null,
29311
29821
  access: "view"
29312
29822
  },
29823
+ "localNetwork.getNotificationEndpoint": {
29824
+ capName: "local-network",
29825
+ capScope: "system",
29826
+ addonId: null,
29827
+ access: "view"
29828
+ },
29313
29829
  "localNetwork.getPreferred": {
29314
29830
  capName: "local-network",
29315
29831
  capScope: "system",
@@ -29334,6 +29850,12 @@ var METHOD_ACCESS_MAP = Object.freeze({
29334
29850
  addonId: null,
29335
29851
  access: "create"
29336
29852
  },
29853
+ "localNetwork.setNotificationEndpoint": {
29854
+ capName: "local-network",
29855
+ capScope: "system",
29856
+ addonId: null,
29857
+ access: "create"
29858
+ },
29337
29859
  "lockControl.lock": {
29338
29860
  capName: "lock-control",
29339
29861
  capScope: "device",
@@ -29976,6 +30498,12 @@ var METHOD_ACCESS_MAP = Object.freeze({
29976
30498
  addonId: null,
29977
30499
  access: "create"
29978
30500
  },
30501
+ "pipelineAnalytics.cancelMediaRelocate": {
30502
+ capName: "pipeline-analytics",
30503
+ capScope: "device",
30504
+ addonId: null,
30505
+ access: "create"
30506
+ },
29979
30507
  "pipelineAnalytics.clearTracks": {
29980
30508
  capName: "pipeline-analytics",
29981
30509
  capScope: "device",
@@ -30030,6 +30558,12 @@ var METHOD_ACCESS_MAP = Object.freeze({
30030
30558
  addonId: null,
30031
30559
  access: "view"
30032
30560
  },
30561
+ "pipelineAnalytics.getMediaRelocateStatus": {
30562
+ capName: "pipeline-analytics",
30563
+ capScope: "device",
30564
+ addonId: null,
30565
+ access: "view"
30566
+ },
30033
30567
  "pipelineAnalytics.getMotionEvents": {
30034
30568
  capName: "pipeline-analytics",
30035
30569
  capScope: "device",
@@ -30102,6 +30636,12 @@ var METHOD_ACCESS_MAP = Object.freeze({
30102
30636
  addonId: null,
30103
30637
  access: "create"
30104
30638
  },
30639
+ "pipelineAnalytics.relocateMedia": {
30640
+ capName: "pipeline-analytics",
30641
+ capScope: "device",
30642
+ addonId: null,
30643
+ access: "create"
30644
+ },
30105
30645
  "pipelineAnalytics.searchObjectEvents": {
30106
30646
  capName: "pipeline-analytics",
30107
30647
  capScope: "device",
@@ -30864,6 +31404,12 @@ var METHOD_ACCESS_MAP = Object.freeze({
30864
31404
  addonId: null,
30865
31405
  access: "create"
30866
31406
  },
31407
+ "recording.cancelRelocate": {
31408
+ capName: "recording",
31409
+ capScope: "system",
31410
+ addonId: null,
31411
+ access: "create"
31412
+ },
30867
31413
  "recording.deleteFootprint": {
30868
31414
  capName: "recording",
30869
31415
  capScope: "system",
@@ -30894,6 +31440,12 @@ var METHOD_ACCESS_MAP = Object.freeze({
30894
31440
  addonId: null,
30895
31441
  access: "view"
30896
31442
  },
31443
+ "recording.getRelocateStatus": {
31444
+ capName: "recording",
31445
+ capScope: "system",
31446
+ addonId: null,
31447
+ access: "view"
31448
+ },
30897
31449
  "recording.getStorageUsage": {
30898
31450
  capName: "recording",
30899
31451
  capScope: "system",
@@ -30924,6 +31476,24 @@ var METHOD_ACCESS_MAP = Object.freeze({
30924
31476
  addonId: null,
30925
31477
  access: "view"
30926
31478
  },
31479
+ "recording.relocateFootage": {
31480
+ capName: "recording",
31481
+ capScope: "system",
31482
+ addonId: null,
31483
+ access: "create"
31484
+ },
31485
+ "recording.renderClip": {
31486
+ capName: "recording",
31487
+ capScope: "system",
31488
+ addonId: null,
31489
+ access: "create"
31490
+ },
31491
+ "recording.renderGif": {
31492
+ capName: "recording",
31493
+ capScope: "system",
31494
+ addonId: null,
31495
+ access: "create"
31496
+ },
30927
31497
  "recording.rescanStorage": {
30928
31498
  capName: "recording",
30929
31499
  capScope: "system",
@@ -31518,6 +32088,12 @@ var METHOD_ACCESS_MAP = Object.freeze({
31518
32088
  addonId: null,
31519
32089
  access: "create"
31520
32090
  },
32091
+ "streamBroker.renderPreBufferClip": {
32092
+ capName: "stream-broker",
32093
+ capScope: "system",
32094
+ addonId: null,
32095
+ access: "create"
32096
+ },
31521
32097
  "streamBroker.restartProfile": {
31522
32098
  capName: "stream-broker",
31523
32099
  capScope: "system",
@@ -33325,6 +33901,7 @@ exports.MotionZonePatchSchema = MotionZonePatchSchema;
33325
33901
  exports.MotionZoneRegionSchema = MotionZoneRegionSchema;
33326
33902
  exports.MotionZoneStatusSchema = MotionZoneStatusSchema;
33327
33903
  exports.MqttBrokerStatusSchema = StatusSchema;
33904
+ exports.NC_BASE_CONDITION_KEYS = NC_BASE_CONDITION_KEYS;
33328
33905
  exports.NC_CONDITION_CATALOG = NC_CONDITION_CATALOG;
33329
33906
  exports.NC_HISTORY_LIMIT_DEFAULT = NC_HISTORY_LIMIT_DEFAULT;
33330
33907
  exports.NC_HISTORY_LIMIT_MAX = NC_HISTORY_LIMIT_MAX;
@@ -33339,12 +33916,14 @@ exports.NativeObjectDetectionRuntimeStateSchema = NativeObjectDetectionRuntimeSt
33339
33916
  exports.NativeObjectDetectionStatusSchema = NativeObjectDetectionStatusSchema;
33340
33917
  exports.NcConditionDescriptorSchema = NcConditionDescriptorSchema;
33341
33918
  exports.NcConditionsSchema = NcConditionsSchema;
33919
+ exports.NcCrossingSchema = NcCrossingSchema;
33342
33920
  exports.NcDeliverySchema = NcDeliverySchema;
33343
33921
  exports.NcHistoryEntrySchema = NcHistoryEntrySchema;
33344
33922
  exports.NcHistoryFilterSchema = NcHistoryFilterSchema;
33345
33923
  exports.NcHistoryRecordKindSchema = NcHistoryRecordKindSchema;
33346
33924
  exports.NcHistoryStatusSchema = NcHistoryStatusSchema;
33347
33925
  exports.NcHistorySubjectSchema = NcHistorySubjectSchema;
33926
+ exports.NcMediaFrameSchema = NcMediaFrameSchema;
33348
33927
  exports.NcMediaPolicySchema = NcMediaPolicySchema;
33349
33928
  exports.NcOccupancyConditionSchema = NcOccupancyConditionSchema;
33350
33929
  exports.NcPlateMatcherSchema = NcPlateMatcherSchema;
@@ -33357,6 +33936,7 @@ exports.NcScheduleWindowSchema = NcScheduleWindowSchema;
33357
33936
  exports.NcTaxonomyEntrySchema = NcTaxonomyEntrySchema;
33358
33937
  exports.NcTaxonomySchema = NcTaxonomySchema;
33359
33938
  exports.NcTestResultSchema = NcTestResultSchema;
33939
+ exports.NcThrottleGranularitySchema = NcThrottleGranularitySchema;
33360
33940
  exports.NcThrottleSchema = NcThrottleSchema;
33361
33941
  exports.NcZoneConditionSchema = NcZoneConditionSchema;
33362
33942
  exports.NetworkAccessStatusSchema = NetworkAccessStatusSchema;
@@ -33451,17 +34031,18 @@ exports.RecordingDaysSchema = RecordingDaysSchema;
33451
34031
  exports.RecordingDeviceUsageSchema = RecordingDeviceUsageSchema;
33452
34032
  exports.RecordingLocationUsageSchema = RecordingLocationUsageSchema;
33453
34033
  exports.RecordingManifestSchema = RecordingManifestSchema;
33454
- exports.RecordingModeSchema = RecordingModeSchema;
33455
34034
  exports.RecordingRangeSchema = RecordingRangeSchema;
33456
34035
  exports.RecordingRetentionSchema = RecordingRetentionSchema;
33457
- exports.RecordingRuleSchema = RecordingRuleSchema;
33458
- exports.RecordingScheduleSchema = RecordingScheduleSchema;
33459
34036
  exports.RecordingStatusSchema = RecordingStatusSchema;
33460
34037
  exports.RecordingStorageModeSchema = RecordingStorageModeSchema;
33461
34038
  exports.RecordingStorageUsageSchema = RecordingStorageUsageSchema;
33462
34039
  exports.RecordingTriggersSchema = RecordingTriggersSchema;
33463
34040
  exports.RecordingWeekdaySchema = RecordingWeekdaySchema;
33464
34041
  exports.RedirectLoginMethodSchema = RedirectLoginMethodSchema;
34042
+ exports.RelocateFootageInputSchema = RelocateFootageInputSchema;
34043
+ exports.RelocateJobSchema = RelocateJobSchema;
34044
+ exports.RelocateJobStateSchema = RelocateJobStateSchema;
34045
+ exports.RelocateMediaInputSchema = RelocateMediaInputSchema;
33465
34046
  exports.RenderedAsSchema = RenderedAsSchema;
33466
34047
  exports.ReportMotionInputSchema = ReportMotionInputSchema;
33467
34048
  exports.RingBuffer = RingBuffer;
@@ -33609,6 +34190,8 @@ exports.WidgetMetadataSchema = WidgetMetadataSchema;
33609
34190
  exports.WidgetRemoteSchema = WidgetRemoteSchema;
33610
34191
  exports.WidgetSizeEnum = WidgetSizeEnum;
33611
34192
  exports.YAMNET_TO_MACRO = YAMNET_TO_MACRO;
34193
+ exports.ZoneCrossingDirectionSchema = ZoneCrossingDirectionSchema;
34194
+ exports.ZoneCrossingSchema = ZoneCrossingSchema;
33612
34195
  exports.ZoneKindEnum = ZoneKindEnum;
33613
34196
  exports.ZoneRuleModeEnum = ZoneRuleModeEnum;
33614
34197
  exports.ZoneRuleSchema = ZoneRuleSchema;
@@ -33693,6 +34276,7 @@ exports.dayNightCapability = dayNightCapability;
33693
34276
  exports.decoderCapability = decoderCapability;
33694
34277
  exports.defaultDeviceFor = defaultDeviceFor;
33695
34278
  exports.defineCustomActions = defineCustomActions;
34279
+ exports.deriveRecordingMode = deriveRecordingMode;
33696
34280
  exports.describeModelVariant = describeModelVariant;
33697
34281
  exports.detectionPipelineCapability = detectionPipelineCapability;
33698
34282
  exports.deviceAdoptionCapability = deviceAdoptionCapability;
@@ -33750,6 +34334,7 @@ exports.integrationsCapability = integrationsCapability;
33750
34334
  exports.intercomCapability = intercomCapability;
33751
34335
  exports.isAgentOnlyPlacement = isAgentOnlyPlacement;
33752
34336
  exports.isArrayOutputSchema = isArrayOutputSchema;
34337
+ exports.isBaseConditionKey = isBaseConditionKey;
33753
34338
  exports.isCollectionArrayMethod = isCollectionArrayMethod;
33754
34339
  exports.isDeployableToAgent = isDeployableToAgent;
33755
34340
  exports.isDeviceConfigCap = require_sleep.isDeviceConfigCap;
@@ -33759,6 +34344,7 @@ exports.isObjectInput = isObjectInput;
33759
34344
  exports.isVoidInput = isVoidInput;
33760
34345
  exports.jobKindSchema = jobKindSchema;
33761
34346
  exports.kebabToCamel = kebabToCamel;
34347
+ exports.knownValues = knownValues;
33762
34348
  exports.lawnMowerControlCapability = lawnMowerControlCapability;
33763
34349
  exports.lifecycleJobSchema = lifecycleJobSchema;
33764
34350
  exports.lifecycleJobScopeSchema = lifecycleJobScopeSchema;
@@ -33784,7 +34370,6 @@ exports.mergeSourceInfo = mergeSourceInfo;
33784
34370
  exports.meshNetworkCapability = meshNetworkCapability;
33785
34371
  exports.method = require_sleep.method;
33786
34372
  exports.metricsProviderCapability = metricsProviderCapability;
33787
- exports.migrateConfigToBands = migrateConfigToBands;
33788
34373
  exports.modelConvertCapability = modelConvertCapability;
33789
34374
  exports.modelDistributorCapability = modelDistributorCapability;
33790
34375
  exports.modelFormatForRuntime = modelFormatForRuntime;
@@ -33817,6 +34402,7 @@ exports.parseStreamParamsFormPatch = parseStreamParamsFormPatch;
33817
34402
  exports.petFeederCapability = petFeederCapability;
33818
34403
  exports.pickAccessoryControl = pickAccessoryControl;
33819
34404
  exports.pickPreferredRtspEntry = pickPreferredRtspEntry;
34405
+ exports.pickerForCondition = pickerForCondition;
33820
34406
  exports.pipelineAnalyticsCapability = pipelineAnalyticsCapability;
33821
34407
  exports.pipelineExecutorCapability = pipelineExecutorCapability;
33822
34408
  exports.pipelineOrchestratorCapability = pipelineOrchestratorCapability;