@camstack/addon-terminal 0.1.122 → 0.1.123

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 (3) hide show
  1. package/dist/addon.js +887 -321
  2. package/dist/addon.mjs +887 -321
  3. package/package.json +1 -3
package/dist/addon.js CHANGED
@@ -31,7 +31,7 @@ let node_module = require("node:module");
31
31
  let sharp = require("sharp");
32
32
  sharp = __toESM(sharp);
33
33
  let node_http = require("node:http");
34
- //#region ../types/dist/event-category-C5xZWqz6.mjs
34
+ //#region ../types/dist/event-category-BGmz_oxW.mjs
35
35
  var EventCategory = /* @__PURE__ */ function(EventCategory) {
36
36
  EventCategory["SystemBoot"] = "system.boot";
37
37
  EventCategory["SystemAddonsReady"] = "system.addons-ready";
@@ -564,6 +564,15 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
564
564
  */
565
565
  EventCategory["PipelineAudioInferenceResult"] = "pipeline.audio-inference-result";
566
566
  EventCategory["DetectionPhaseTransition"] = "detection.phase-transition";
567
+ /**
568
+ * A camera provider's RAW onboard motion push (D673): the `MotionOnMotionChanged`
569
+ * data shape without `triggeredBy`, built by `providerMotionEvent`. Its one
570
+ * consumer is the orchestrator's camera-sensors bridge, which re-emits the
571
+ * camera's EFFECTIVE onboard motion as `MotionOnMotionChanged` (a pass-through
572
+ * for a camera with no attached sensor). Providers must not emit
573
+ * `MotionOnMotionChanged` themselves; `scripts/check-onboard-motion-emitters.ts`
574
+ * keeps it so (camera-grid is a named, deferred exception).
575
+ */
567
576
  EventCategory["ProviderMotion"] = "provider.motion";
568
577
  EventCategory["ProviderDetection"] = "provider.detection";
569
578
  EventCategory["EnrichmentEmbeddingStored"] = "enrichment.embedding.stored";
@@ -5402,7 +5411,7 @@ var ZodIssueCode = {
5402
5411
  var ZodFirstPartyTypeKind;
5403
5412
  ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
5404
5413
  //#endregion
5405
- //#region ../types/dist/sleep-gU6hqv4_.mjs
5414
+ //#region ../types/dist/sleep-CDCONfkt.mjs
5406
5415
  /**
5407
5416
  * The audio chunk plane's byte format, and the ONE expansion from a coded
5408
5417
  * window to float samples (D455).
@@ -7504,7 +7513,7 @@ function errMsg(err) {
7504
7513
  return String(err);
7505
7514
  }
7506
7515
  //#endregion
7507
- //#region ../types/dist/composition-Dq42XWp0.mjs
7516
+ //#region ../types/dist/composition-Bzr7GwgP.mjs
7508
7517
  /**
7509
7518
  * The ffmpeg build every CamStack node downloads, per platform and arch.
7510
7519
  *
@@ -7558,21 +7567,20 @@ function portable(target) {
7558
7567
  }
7559
7568
  portable("linux64"), portable("linuxarm64"), portable("macarm64"), portable("mac64");
7560
7569
  /**
7561
- * LA tabella "quale booleano di questo tipo di device conta come ALTO", e il
7562
- * valutatore puro del suo FRONTE.
7570
+ * THE table "which boolean of this device type counts as HIGH", and the
7571
+ * pure evaluator of its EDGE.
7563
7572
  *
7564
- * Viveva dentro il builtin virtual-doorbell
7565
- * (`@camstack/system` — `builtins/doorbell/trigger-engine.ts`) e i suoi
7566
- * predicati erano privati al modulo. Il recorder ne ha bisogno per il trigger
7567
- * `RecordingTriggers.sensorDeviceIds`: copiarla avrebbe creato la SECONDA
7568
- * tabella, che diverge alla prima cap aggiunta e il cui sintomo — "il sensore
7569
- * fa suonare il campanello ma non registra" — è esattamente D62. Quindi si
7570
- * SPOSTA qui e il doorbell la ri-esporta.
7573
+ * ONE table for everyone who asks "is this device HIGH?": the
7574
+ * recorder's `RecordingTriggers.sensorDeviceIds` trigger, the post-analysis
7575
+ * sensor markers, the orchestrator's camera-sensors bridge and
7576
+ * the sources of a composite doorbell (`doorbellFeatureSources`, D671).
7577
+ * A second copy would diverge at the first cap added, and the symptom — "the
7578
+ * sensor rings the doorbell but does not record" — is exactly D62.
7571
7579
  *
7572
- * ⚠ NON è `DEVICE_STATE_READERS` (`catalogs/device-state-vocabulary.ts`), e le
7573
- * due non vanno unificate: quella risponde a "qual è la PAROLA di stato per una
7574
- * regola" (e include `presence`, `cover`, `alarm-panel`), questa a "qual è il
7575
- * booleano il cui FRONTE conta". Vocabolari deliberatamente diversi.
7580
+ * ⚠ NOT `DEVICE_STATE_READERS` (`catalogs/device-state-vocabulary.ts`), and the
7581
+ * two must not be unified: that one answers "what is the state WORD for a
7582
+ * rule" (and includes `presence`, `cover`, `alarm-panel`), this one "which
7583
+ * boolean's EDGE counts". Deliberately different vocabularies.
7576
7584
  */
7577
7585
  /**
7578
7586
  * Known binary / switch source caps → the boolean slice field whose
@@ -9213,22 +9221,22 @@ var CLASS_MAP_MACRO_TARGETS = [
9213
9221
  "package"
9214
9222
  ];
9215
9223
  /**
9216
- * Le macro classi di PRIMO LIVELLO: quelle che un object detector emette e che
9217
- * un operatore può selezionare.
9224
+ * The FIRST-LEVEL macro classes: those an object detector emits and that
9225
+ * an operator can select.
9218
9226
  *
9219
- * Sono le tre offerte dallo step `object-detection`
9227
+ * They are the three offered by the `object-detection` step
9220
9228
  * (`addon-pipeline/src/detection-pipeline/registry/step-definitions.ts`,
9221
- * `enabledMacroClasses`). `package` sta in {@link CLASS_MAP_MACRO_TARGETS} e in
9222
- * `MACRO_LABELS` — è una macro vera — ma NON qui: appartiene allo step
9223
- * `package-detection`, la cui abilitazione è guidata dalle zone, e offrire la
9224
- * stessa parola due volte ha già fatto accendere a un operatore il proxy COCO
9229
+ * `enabledMacroClasses`). `package` is in {@link CLASS_MAP_MACRO_TARGETS} and in
9230
+ * `MACRO_LABELS` — it is a true macro — but NOT here: it belongs to the step
9231
+ * `package-detection`, whose enablement is driven by zones, and offering the
9232
+ * same word twice has already made an operator turn on the COCO proxy
9225
9233
  * (suitcase/backpack/handbag) lasciando spento il detector dedicato.
9226
9234
  *
9227
- * UNA lista. Prima di oggi le stesse tre erano scritte a mano nell'offerta
9228
- * dello step e una seconda volta come union `FirstLevelMacro`
9229
- * (`types/detection.ts`); una terza copia per il trigger di registrazione
9230
- * (`RecordingTriggers.objectClasses`) avrebbe reso invisibile la divergenza
9231
- * successiva.
9235
+ * ONE list. Before today the same three were hand-written in the step's offer
9236
+ * and a second time as the union `FirstLevelMacro`
9237
+ * (`types/detection.ts`); a third copy for the recording trigger
9238
+ * (`RecordingTriggers.objectClasses`) would have made the later divergence
9239
+ * invisible.
9232
9240
  */
9233
9241
  var FIRST_LEVEL_MACRO_CLASSES = [
9234
9242
  "person",
@@ -9293,17 +9301,17 @@ var RecordingStorageModeSchema = _enum([
9293
9301
  "on-device-decision"
9294
9302
  ]);
9295
9303
  /**
9296
- * Le macro classi che possono aprire una finestra di registrazione — le stesse
9297
- * tre offerte dallo step `object-detection`, da UNA lista
9304
+ * The macro classes that can open a recording window — the same
9305
+ * three offered by the `object-detection` step, from ONE list
9298
9306
  * ({@link FIRST_LEVEL_MACRO_CLASSES}).
9299
9307
  */
9300
9308
  var RecordingObjectTriggerClassSchema = _enum(FIRST_LEVEL_MACRO_CLASSES);
9301
9309
  /**
9302
- * True quando `values` non ripete un elemento.
9310
+ * True when `values` does not repeat an element.
9303
9311
  *
9304
- * Un duplicato non è innocuo: ogni voce di `objectClasses` / `sensorDeviceIds`
9305
- * diventa una SORGENTE in `bandTriggerSources`, e la stessa sorgente due volte
9306
- * conterebbe due volte le sue finestre in `segmentMissedByMs`.
9312
+ * A duplicate is not harmless: every entry of `objectClasses` / `sensorDeviceIds`
9313
+ * becomes a SOURCE in `bandTriggerSources`, and the same source twice
9314
+ * would count its windows twice in `segmentMissedByMs`.
9307
9315
  */
9308
9316
  var noDuplicates = (values) => new Set(values).size === values.length;
9309
9317
  /** Which detectors trigger an `events`-mode band. */
@@ -9311,34 +9319,34 @@ var RecordingTriggersSchema = object({
9311
9319
  motion: boolean().optional(),
9312
9320
  audioThresholdDbfs: number().optional(),
9313
9321
  /**
9314
- * Le macro classi la cui detection apre una finestra. ASSENTE = la sorgente
9315
- * non è ascoltata; un array VUOTO è rifiutato, perché "banda events, trigger
9316
- * object acceso, nessuna classe" è la stessa forma "abilitata e non registra
9317
- * nulla, per sempre" contro cui è scritto `eventsBandCanEverDemand`.
9322
+ * The macro classes whose detection opens a window. ABSENT = the source
9323
+ * is not listened to; an EMPTY array is rejected, because "events band, object
9324
+ * trigger on, no class" is the same shape "enabled and records
9325
+ * nothing, forever" that `eventsBandCanEverDemand` is written against.
9318
9326
  *
9319
- * Il segnale letto è GIÀ FILTRATO: solo detection `source: 'pipeline'`, cioè
9320
- * quelle che hanno attraversato `enabledMacroClasses`, i
9321
- * `minConfidence<Macro>` e il full-frame guard. L'AI a bordo camera
9322
- * (`source: 'onboard'`) non attraversa nessuno di quei gate e NON apre
9323
- * finestre — vedi `recorder/object-trigger.ts`.
9327
+ * The signal read is ALREADY FILTERED: only `source: 'pipeline'` detections, i.e.
9328
+ * those that went through `enabledMacroClasses`, the
9329
+ * `minConfidence<Macro>` and the full-frame guard. The camera's onboard AI
9330
+ * (`source: 'onboard'`) goes through none of those gates and does NOT open
9331
+ * windows — see `recorder/object-trigger.ts`.
9324
9332
  */
9325
9333
  objectClasses: array(RecordingObjectTriggerClassSchema).min(1).refine(noDuplicates, { message: "objectClasses must not repeat a class" }).optional(),
9326
9334
  /**
9327
- * I device LINKED il cui FRONTE ALTO apre una finestra. Assente = la sorgente
9328
- * non è ascoltata; un array vuoto è rifiutato per la stessa ragione di
9335
+ * The LINKED devices whose RISING EDGE opens a window. Absent = the source
9336
+ * is not listened to; an empty array is rejected for the same reason as
9329
9337
  * `objectClasses`.
9330
9338
  *
9331
- * Sono id di device SORGENTE, non camere: la banda li nomina, quindi il
9332
- * percorso caldo (`DeviceStateChanged`, a ritmo di bus su tutta la flotta)
9333
- * non fa RPC. L'OFFERTA da cui l'operatore li sceglie è un'altra domanda, e
9334
- * si risolve con `deviceManager.getLinkedDevices` + `getBindingsBatch` per
9335
- * device (D12) — mai un elenco globale di cap.
9339
+ * These are SOURCE device ids, not cameras: the band names them, so the
9340
+ * hot path (`DeviceStateChanged`, at bus rate across the whole fleet)
9341
+ * does no RPC. The OFFER from which the operator picks them is another question, and
9342
+ * is resolved with `deviceManager.getLinkedDevices` + `getBindingsBatch` per
9343
+ * device (D12) — never a global list of caps.
9336
9344
  *
9337
- * Cosa vuol dire "alto" dipende dal TIPO di device e non è deciso qui:
9338
- * `SOURCE_CAP_ACTIVE_FIELD` (`catalogs/sensor-active-state.ts`) è LA tabella,
9339
- * la stessa che il virtual-doorbell usa dal 2026-08-05. Ed è il FRONTE, non
9340
- * il livello: un contatto trovato già aperto al riavvio del runner non fa
9341
- * registrare.
9345
+ * What "high" means depends on the device TYPE and is not decided here:
9346
+ * `SOURCE_CAP_ACTIVE_FIELD` (`catalogs/sensor-active-state.ts`) is THE table,
9347
+ * the same one as the composite doorbell (D671). And it is the EDGE, not
9348
+ * the level: a contact found already open at runner restart does not
9349
+ * record.
9342
9350
  */
9343
9351
  sensorDeviceIds: array(number().int().positive()).min(1).max(16).refine(noDuplicates, { message: "sensorDeviceIds must not repeat a device" }).optional()
9344
9352
  });
@@ -10415,7 +10423,7 @@ var DecoderSessionConfigSchema = object({
10415
10423
  * - **VALUE** — at which level, for which scope, until when. That stays ONE
10416
10424
  * thing: the logging settings document on the `system` cap. Two authorities
10417
10425
  * over the values is the exact defect
10418
- * `docs/design/plans/2026-08-26-logging-per-componente.md` was written to
10426
+ * `docs/design/plans/2026-08-26-per-component-logging.md` was written to
10419
10427
  * remove; re-introducing it from the cure side would be grotesque.
10420
10428
  *
10421
10429
  * Nothing in this file reads a clock, an env var or a store. The registry is
@@ -12126,7 +12134,7 @@ var BrokerStatusEnum = _enum([
12126
12134
  "unreachable",
12127
12135
  "error"
12128
12136
  ]);
12129
- var BrokerInfoSchema$1 = object({
12137
+ var BrokerInfoSchema = object({
12130
12138
  /** Stable broker id. Persisted; survives addon restarts. */
12131
12139
  id: string(),
12132
12140
  /** Addon id of the provider that OWNS this broker.
@@ -12259,7 +12267,7 @@ var GetStateInputSchema = object({
12259
12267
  * HA: entity_id (returns the cached entity state). */
12260
12268
  key: string()
12261
12269
  });
12262
- method(ListInputSchema, array(BrokerInfoSchema$1)), method(GetInputSchema, BrokerInfoSchema$1.nullable()), method(_void(), array(BrokerProviderInfoSchema), { auth: "admin" }), method(AddInputSchema, AddResultSchema, {
12270
+ method(ListInputSchema, array(BrokerInfoSchema)), method(GetInputSchema, BrokerInfoSchema.nullable()), method(_void(), array(BrokerProviderInfoSchema), { auth: "admin" }), method(AddInputSchema, AddResultSchema, {
12263
12271
  kind: "mutation",
12264
12272
  auth: "admin"
12265
12273
  }), method(RemoveInputSchema, _void(), {
@@ -13970,7 +13978,7 @@ method(_void(), EngineInfoSchema, { auth: "admin" }), method(object({
13970
13978
  *
13971
13979
  * ⚠ An earlier version of this comment blamed Zod stripping, and that
13972
13980
  * was wrong — corrected 2026-08-26 after the hop map
13973
- * (`docs/design/2026-08-26-mappa-hop-argomenti.md`) traced the path.
13981
+ * (`docs/design/2026-08-26-topic-hop-map.md`) traced the path.
13974
13982
  * There is **no Zod parse at all** between the door and the engine: the
13975
13983
  * dispatcher forwards the payload verbatim and UDS carries it whole. A
13976
13984
  * field declared here reaches `SqliteSettingsBackend` either way.
@@ -14833,7 +14841,17 @@ var SiteZoneSchema = object({
14833
14841
  var ProviderStatusSchema = object({
14834
14842
  connected: boolean(),
14835
14843
  deviceCount: number(),
14836
- error: string().optional()
14844
+ error: string().optional(),
14845
+ /**
14846
+ * `'orchestrator'`: this provider writes NO camera's `motion` runtime slice
14847
+ * — the orchestrator is its only writer (D696). Set by `BaseDeviceProvider`,
14848
+ * which every provider bundles, so only a provider BUILT from D696-amended
14849
+ * code says it. ABSENT means an older provider that may still write it (raw
14850
+ * VMD writes, a boot seed), and the orchestrator's provider gate keeps that
14851
+ * provider's cameras unwritten (`camera-sensors/motion-slice-provider-gate.ts`)
14852
+ * — the provider twin of the runner's `getLocalLoad().motionSliceWriter`.
14853
+ */
14854
+ motionSliceWriter: literal("orchestrator").optional()
14837
14855
  });
14838
14856
  object({
14839
14857
  externalId: string(),
@@ -15631,109 +15649,10 @@ method(object({
15631
15649
  deviceIds: array(number()).readonly(),
15632
15650
  caps: array(string()).readonly().optional()
15633
15651
  }), record(string(), record(string(), unknown().nullable())));
15634
- /**
15635
- * Doorbell button cap. Two kinds of providers coexist behind this cap
15636
- * name (same pattern as `snapshot`):
15637
- *
15638
- * - **Native** providers: registered per-device by device-driver
15639
- * addons via `ctx.registerNativeCap` — either on a
15640
- * `DeviceType.Button` accessory with `role: DeviceRole.Doorbell`,
15641
- * or directly on the camera (Reolink registers at camera level).
15642
- * Emits an `onPressed` event every time the firmware pushes a
15643
- * ring; status tracks the last press and a pressCount since start
15644
- * (diagnostic).
15645
- *
15646
- * - **Wrapper** provider: the `virtual-doorbell` system builtin
15647
- * (`@camstack/system/builtins/doorbell`). Turns ANY binary-ish
15648
- * device (contact / switch / event-emitter …) into a doorbell for
15649
- * a camera. `defaultActive: false` — the operator explicitly binds
15650
- * it per camera in the device-bindings UI, then picks the source
15651
- * device + trigger in the per-device settings.
15652
- *
15653
- * The DeviceEventPropagator re-emits `onPressed` on the camera parent
15654
- * — subscribers listening at the camera level receive ring events
15655
- * with `via[]` populated. No code on the parent needed.
15656
- */
15657
- var DoorbellStatusSchema = object({
15658
- /** Ms epoch of the last press. null = never observed since this provider started. */
15659
- lastPressedAt: number().nullable(),
15660
- /** Counter since provider start. Resets on reboot. Useful for metrics/debug. */
15661
- pressCountSinceStart: number()
15662
- });
15663
- var DoorbellPressEventSchema = object({
15664
- deviceId: number(),
15665
- timestamp: number()
15666
- });
15667
- /**
15668
- * The `doorbell-source` extension slot's editable value (D648): the camera's
15669
- * virtual-doorbell trigger devices, exactly what the wrapper's
15670
- * `doorbellSources` persists (as `{ deviceId }` records).
15671
- */
15672
- var DoorbellSourceSlotValueSchema = object({ deviceIds: array(number().int().positive()) });
15673
- /**
15674
- * The `doorbell-source` slot — which devices ring this camera's VIRTUAL
15675
- * doorbell, owned by the `virtual-doorbell` wrapper over its
15676
- * `doorbellSources` store (D648). A source rings when one of its
15677
- * `SOURCE_CAPS` rises. Whether the wrapper is bound to the camera at all is a
15678
- * different authority (`deviceManager.setWrapperActive`, D62) — the slot
15679
- * reports it, it never writes it.
15680
- */
15681
- var DOORBELL_SOURCE_SLOT = {
15682
- id: "doorbell-source",
15683
- label: "Doorbell trigger devices",
15684
- description: "Any of these becoming active rings this camera's virtual doorbell: a binary sensor when it goes active, a switch when it turns on.",
15685
- shape: "association",
15686
- hostDeviceTypes: [DeviceType.Camera],
15687
- sourceCaps: SOURCE_CAPS,
15688
- cardinality: "many",
15689
- value: DoorbellSourceSlotValueSchema
15690
- };
15691
- var doorbellCapability = {
15692
- name: "doorbell",
15693
- scope: "device",
15694
- deviceNative: true,
15695
- mode: "singleton",
15696
- kind: "wrapper",
15697
- defaultActive: false,
15698
- deviceTypes: [DeviceType.Button, DeviceType.Camera],
15699
- extensionSlots: [DOORBELL_SOURCE_SLOT],
15700
- methods: {},
15701
- events: {
15702
- /**
15703
- * Fires once per physical press. Reolink delivers via Baichuan
15704
- * push (`ReolinkSimpleEvent.type === 'doorbell'`). There is no
15705
- * release/duration — it's a pulse.
15706
- */
15707
- onPressed: {
15708
- data: DoorbellPressEventSchema,
15709
- fromState: {
15710
- field: "lastPressedAt",
15711
- on: "advance"
15712
- }
15713
- } },
15714
- status: {
15715
- schema: DoorbellStatusSchema,
15716
- kind: "push"
15717
- },
15718
- /**
15719
- * Runtime-state slice — last press timestamp + lifetime press count.
15720
- * Mirrored by the kernel and readable via
15721
- * `device.state.doorbell.value`. UIs can show "last ring 5m ago"
15722
- * without subscribing.
15723
- */
15724
- runtimeState: DoorbellStatusSchema,
15725
- /**
15726
- * Runtime-state durability: **restored** — a monotonic accumulator: the slice IS the record. `lastPressedAt` is content here, not a clock, so it is deliberately NOT volatile.
15727
- *
15728
- * See `RuntimeStateDurability`. Enforced by
15729
- * `scripts/check-runtime-state-durability.ts`.
15730
- */
15731
- durability: "restored"
15732
- };
15733
- var ExtensionSlotIdSchema = _enum(["doorbell-source", "linked-devices"]);
15734
- DeviceType.Camera, DeviceType.Camera;
15652
+ var ExtensionSlotIdSchema = _enum(["linked-devices"]);
15653
+ DeviceType.Camera;
15735
15654
  /** A slot's editable value, discriminated on `slot`. */
15736
- var ExtensionSlotValueSchema = discriminatedUnion("slot", [DoorbellSourceSlotValueSchema.extend({ slot: literal("doorbell-source") }), LinkedDevicesSlotValueSchema.extend({ slot: literal("linked-devices") })]);
15655
+ var ExtensionSlotValueSchema = discriminatedUnion("slot", [LinkedDevicesSlotValueSchema.extend({ slot: literal("linked-devices") })]);
15737
15656
  DeviceType.Camera;
15738
15657
  var ExtensionSourceAvailabilitySchema = discriminatedUnion("state", [object({ state: literal("ok") }), object({
15739
15658
  state: literal("unreachable"),
@@ -15770,10 +15689,11 @@ var ExtensionSlotSourceSchema = object({
15770
15689
  });
15771
15690
  /**
15772
15691
  * A DIFFERENT authority that gates whether the slot's sources do anything —
15773
- * reported read-only, named, never written through this contract (D62). The
15774
- * virtual doorbell's sources ring only while the wrapper is bound to the
15775
- * camera, and that binding belongs to `deviceManager.setWrapperActive`.
15776
- * `unknown` means the gate could not be read; it is not "inactive" (D315).
15692
+ * reported read-only, named, never written through this contract (D62) — e.g.
15693
+ * a slot whose sources act only while a wrapper is bound to the host, a
15694
+ * binding that belongs to `deviceManager.setWrapperActive`. No slot reports
15695
+ * one today (`linked-devices` answers `null`). `unknown` means the gate could
15696
+ * not be read; it is not "inactive" (D315).
15777
15697
  */
15778
15698
  var ExtensionSlotActivationSchema = object({
15779
15699
  state: _enum([
@@ -15789,7 +15709,7 @@ var ExtensionSlotRowSchema = discriminatedUnion("state", [object({
15789
15709
  /** `<source>:<slotId>` — the routing key for `listCandidates` / `setSlot`. */
15790
15710
  slotRef: string(),
15791
15711
  slot: ExtensionSlotIdSchema,
15792
- /** Names the store written (D62), e.g. `virtual-doorbell:doorbellSources`. */
15712
+ /** Names the store written (D62), e.g. `device-manager:_linkedDeviceIds`. */
15793
15713
  authority: string(),
15794
15714
  activation: ExtensionSlotActivationSchema.nullable(),
15795
15715
  value: ExtensionSlotValueSchema,
@@ -16067,7 +15987,7 @@ method(object({
16067
15987
  * per-device window, `KeyFrameCaptureLog`, `bumpCropMetric`. Every one of them
16068
15988
  * ends in a log line, and a log line is the thing the operator asked to stop
16069
15989
  * needing: *"possiamo armare questi errori intanto? Così al prossimo giro
16070
- * ricontrolliamo tutti questi punti"*. Reading them meant grepping Loki and
15990
+ * ricontrolliamo tutti questi punti"* [can we instrument these errors in the meantime? That way next round we recheck all these points]. Reading them meant grepping Loki and
16071
15991
  * hand-correlating timestamps, which is how a 22% thumbnail gap and a 3-hour
16072
15992
  * media blackout were both diagnosed. The counters stay; this is where they can
16073
15993
  * be READ.
@@ -17443,7 +17363,7 @@ var BrokerStatusSchema$1 = _enum([
17443
17363
  "unreachable",
17444
17364
  "tls-error"
17445
17365
  ]);
17446
- var BrokerInfoSchema = object({
17366
+ var BrokerInfoSchema$1 = object({
17447
17367
  id: string(),
17448
17368
  name: string(),
17449
17369
  url: string(),
@@ -17506,7 +17426,7 @@ var StatusSchema = object({
17506
17426
  brokerCount: number(),
17507
17427
  embeddedRunning: boolean()
17508
17428
  });
17509
- method(_void(), array(BrokerInfoSchema)), method(IdInputSchema, BrokerConnectionDetailsSchema, { auth: "admin" }), method(AddBrokerInputSchema, AddBrokerResultSchema, {
17429
+ method(_void(), array(BrokerInfoSchema$1)), method(IdInputSchema, BrokerConnectionDetailsSchema, { auth: "admin" }), method(AddBrokerInputSchema, AddBrokerResultSchema, {
17510
17430
  kind: "mutation",
17511
17431
  auth: "admin"
17512
17432
  }), method(IdInputSchema, _void(), {
@@ -19720,78 +19640,16 @@ var NcRuleInputSchema = object({
19720
19640
  */
19721
19641
  confirm: NcConfirmSchema.optional(),
19722
19642
  /**
19723
- * WAIT for face/plate recognition before saying anything.
19724
- *
19725
- * A notification's TEXT is frozen at enqueue and its media is re-resolved at
19726
- * send; the identity is neither. A face is confirmed after `confirmFrames`
19727
- * agreeing observations — p50 **11.4 s** after the track was first seen,
19728
- * measured on this hub — and an `immediate` rule enqueues on the first object
19729
- * event, seconds before that. So "Gianluca è arrivato" is unsayable on the
19730
- * immediate path, and no amount of media re-resolution fixes a sentence.
19731
- *
19732
- * Only two honest answers exist, and this flag picks between them. It has
19733
- * effect ONLY on a rule that declares a recognition scope
19734
- * ({@link NcConditions.identities} or {@link NcConditions.plates}) — on any
19735
- * other rule there is nothing to wait for and the flag is inert.
19736
- *
19737
- * | value | what happens |
19738
- * | --- | --- |
19739
- * | `true` | the rule stops firing on the object event and fires at TRACK CLOSE instead, once, with the name — later, and complete |
19740
- * | absent / `false` | it fires at once WITHOUT the name, and if recognition lands before the track closes a SECOND, "…is Gianluca" notification follows (one per track, per rule, per target) |
19741
- *
19742
- * `.optional()` and deliberately NOT `.default()`: a Zod default does not run
19743
- * on the addon cap path, and absent has to keep meaning exactly what every
19744
- * rule authored before this field meant.
19745
- *
19746
- * The cost of `true` is stated here because the editor states it too: a rule
19747
- * that waits also inherits track-close SEMANTICS — its `zones` condition
19748
- * tests every zone the track visited and a `crossing` condition can no longer
19749
- * be satisfied, because a closed track carries no crossing.
19643
+ * IMMEDIATE GROUPED (D692): the first matching subject opens a window of this many
19644
+ * seconds; the rule sends ONE message when the window closes — early, once every
19645
+ * subject in it is final, never before {@link NC_GROUPING_MIN_SEC} — naming everybody
19646
+ * the rule matched, with one mosaic tile per subject.
19647
+ * Absent = plain immediate (one message per track, at the first match).
19648
+ * Only an `immediate` DETECTION rule may carry it (`ruleGroupingApplies`, enforced on
19649
+ * save by the hub's grouping guard). `.optional()`, never `.default()`: the addon cap
19650
+ * path does not run Zod defaults.
19750
19651
  */
19751
- waitForEnhancement: boolean().optional(),
19752
- /**
19753
- * GROUP a burst of subjects into ONE notification that grows.
19754
- *
19755
- * Seconds of quiet after the last matching subject before the burst is
19756
- * considered over. While it is open, the first subject enqueues immediately —
19757
- * **exactly as today, with no added latency** — and every real growth (a new
19758
- * subject, or a name confirmed on one already in it) REPLACES that
19759
- * notification with an updated one naming everybody. The push carries the
19760
- * group's own coalescing tag, so the phone replaces rather than stacks.
19761
- *
19762
- * `0` / absent = off, and off is today's behaviour byte for byte.
19763
- *
19764
- * ### Why an idle cutoff and not a window
19765
- *
19766
- * The measured seven-person arrival on device 590 spans 110 s with every
19767
- * internal gap under 30 s. A 12 s fixed window cuts it into three groups; an
19768
- * idle cutoff holds it as one and ends it when the arrival actually ends.
19769
- * 30 s is a widely shipped value for the same decision.
19770
- *
19771
- * ### What it replaces
19772
- *
19773
- * The blind cooldown, which collapses a burst by DISCARDING it. Measured on
19774
- * device 615 / *Persona su Uscio* over six days: 116 qualifying tracks → 74
19775
- * notifications, **44 (37.9%) suppressed outright**, 23 of them overlapping a
19776
- * track that did fire and 7 carrying a confirmed identity nobody heard about.
19777
- * A group collapses the same volume by MERGING, so the cooldown becomes a
19778
- * budget over GROUPS — which is what it always meant — and a growth is never
19779
- * throttled by the window its own first member spent.
19780
- *
19781
- * ### Interaction with {@link waitForEnhancement}
19782
- *
19783
- * They compose, and the order matters. `waitForEnhancement` defers the rule to
19784
- * TRACK CLOSE, so with both set the group is opened by the first member to
19785
- * CLOSE — already carrying its name — and grows as later members close. That
19786
- * is later, and complete. With grouping alone the group opens on the first
19787
- * object event and picks up names as they are confirmed, through the growth
19788
- * path. Neither combination fires twice for one subject.
19789
- *
19790
- * `.optional()` and deliberately NOT `.default()`: a Zod default does not run
19791
- * on the addon cap path, so absent must keep meaning what it meant before this
19792
- * field existed.
19793
- */
19794
- groupIdleSec: number().int().min(0).max(600).optional()
19652
+ groupingSec: number().int().min(5).max(60).optional()
19795
19653
  });
19796
19654
  /**
19797
19655
  * Partial patch for `updateRule` — any subset of the input fields, plus the
@@ -19839,9 +19697,10 @@ var NcRuleClearableKeySchema = _enum([
19839
19697
  "targetUsers",
19840
19698
  "snoozeOptions",
19841
19699
  "snoozeAllowGlobal",
19842
- "waitForEnhancement",
19843
19700
  "actions",
19844
19701
  "confirm",
19702
+ "groupingSec",
19703
+ "waitForEnhancement",
19845
19704
  "groupIdleSec"
19846
19705
  ]);
19847
19706
  var NcRuleUpdateInputSchema = object({
@@ -19863,9 +19722,25 @@ var NcRuleSchema = NcRuleInputSchema.extend({
19863
19722
  */
19864
19723
  disabledTargetIds: array(string()).default([])
19865
19724
  });
19725
+ /**
19726
+ * The state-summary SECTIONS (D647 / D698): the D637 kind groups that report a
19727
+ * still-true state. `backups-exports` and `alarm` are not sections — a completed
19728
+ * job is not an open state, and the alarm stays instant.
19729
+ */
19730
+ var NcStateSummarySectionIdSchema = _enum([
19731
+ "device-state",
19732
+ "streams",
19733
+ "battery",
19734
+ "consumables",
19735
+ "tanks",
19736
+ "detection-blind",
19737
+ "nodes",
19738
+ "addons",
19739
+ "updates"
19740
+ ]);
19866
19741
  /** One section of a previewed state summary. `unavailable` = its state could not be read. */
19867
19742
  var NcStateSummaryPreviewSectionSchema = object({
19868
- id: string(),
19743
+ id: NcStateSummarySectionIdSchema,
19869
19744
  status: _enum(["read", "unavailable"]),
19870
19745
  items: number().int().nonnegative(),
19871
19746
  reason: string().optional()
@@ -19875,7 +19750,7 @@ var NcStateSummaryPreviewSectionSchema = object({
19875
19750
  * a `rule` split (no `section`), one section's on a `section` split.
19876
19751
  */
19877
19752
  var NcStateSummaryPreviewRowSchema = object({
19878
- section: string().optional(),
19753
+ section: NcStateSummarySectionIdSchema.optional(),
19879
19754
  /** The section's name on a per-section row; every reported section's, joined, on a combined one. */
19880
19755
  title: string(),
19881
19756
  text: string(),
@@ -20312,6 +20187,29 @@ object({
20312
20187
  firstAt: number(),
20313
20188
  lastAt: number()
20314
20189
  });
20190
+ var NC_ALARM_TRIGGERED_MAX_SEC = 3600;
20191
+ var NcAlarmDelaySecSchema = number().int().min(0).max(600);
20192
+ var NcAlarmTriggeredSecSchema = number().int().min(0).max(NC_ALARM_TRIGGERED_MAX_SEC);
20193
+ var uniqueModes = (entries) => new Set(entries.map((e) => e.mode)).size === entries.length;
20194
+ var NcAlarmModeDelaysListSchema = array(object({
20195
+ mode: AlarmArmModeSchema,
20196
+ exitDelaySec: NcAlarmDelaySecSchema.optional(),
20197
+ entryDelaySec: NcAlarmDelaySecSchema.optional(),
20198
+ triggeredDurationSec: NcAlarmTriggeredSecSchema.optional()
20199
+ })).max(8).refine(uniqueModes, { message: "modeDelays: at most one entry per arm mode" });
20200
+ var NcAlarmModeDelaysEditListSchema = array(object({
20201
+ mode: AlarmArmModeSchema,
20202
+ exitDelaySec: NcAlarmDelaySecSchema.nullable().optional(),
20203
+ entryDelaySec: NcAlarmDelaySecSchema.nullable().optional(),
20204
+ triggeredDurationSec: NcAlarmTriggeredSecSchema.nullable().optional()
20205
+ })).max(8).refine(uniqueModes, { message: "modeDelays: at most one edit per arm mode" });
20206
+ /** One switch of the alarm table: put ONE device on, or take it off, ONE mode's list. */
20207
+ var NcAlarmNonBlockingEditSchema = object({
20208
+ mode: AlarmArmModeSchema,
20209
+ deviceId: number().int().positive(),
20210
+ /** true = on the list (may be open, does not block); false = off the list (blocks). */
20211
+ nonBlocking: boolean()
20212
+ });
20315
20213
  /**
20316
20214
  * The per-mode lists, at most one per mode. Two lists for one mode have no
20317
20215
  * meaning a reader could agree on (union? the last one?), so they are refused
@@ -20320,10 +20218,10 @@ object({
20320
20218
  var NcAlarmNonBlockingListSchema = array(object({
20321
20219
  mode: AlarmArmModeSchema,
20322
20220
  deviceIds: array(number().int()).max(200)
20323
- })).max(8).refine((lists) => new Set(lists.map((l) => l.mode)).size === lists.length, { message: "nonBlocking: at most one list per arm mode" });
20221
+ })).max(8).refine(uniqueModes, { message: "nonBlocking: at most one list per arm mode" });
20324
20222
  /**
20325
- * The three durations the panel's state machine runs on, who hears about its
20326
- * transitions, and which openings each mode tolerates.
20223
+ * The three durations — global, and per mode since D697 — the panel's state
20224
+ * machine runs on, who hears about its transitions, and which openings each mode tolerates.
20327
20225
  *
20328
20226
  * They live on the NOTIFICATION-RULES cap, not on `alarm-panel`, on purpose:
20329
20227
  * `alarm-panel` is `deviceNative` and its other provider mirrors somebody
@@ -20333,15 +20231,15 @@ var NcAlarmNonBlockingListSchema = array(object({
20333
20231
  */
20334
20232
  var NcAlarmSettingsSchema = object({
20335
20233
  /** Grace period between arming and the mode taking effect. 0 = immediate. */
20336
- exitDelaySec: number().int().min(0).max(600),
20234
+ exitDelaySec: NcAlarmDelaySecSchema,
20337
20235
  /** Grace period between a trigger and the alarm firing. 0 = immediate. */
20338
- entryDelaySec: number().int().min(0).max(600),
20236
+ entryDelaySec: NcAlarmDelaySecSchema,
20339
20237
  /**
20340
20238
  * How long `triggered` lasts before the panel re-arms itself.
20341
20239
  * **0 = until an operator disarms it** — the behaviour before this field
20342
20240
  * existed, and therefore what an untouched install keeps doing.
20343
20241
  */
20344
- triggeredDurationSec: number().int().min(0).max(3600),
20242
+ triggeredDurationSec: NcAlarmTriggeredSecSchema,
20345
20243
  /**
20346
20244
  * Deprecated by D630 — every transition is announced. Parsed, never read;
20347
20245
  * remove after one release. Optional so an older admin's patch (which still
@@ -20364,17 +20262,30 @@ var NcAlarmSettingsSchema = object({
20364
20262
  * per mode is meaningful. Defaulted to `[]` so a blob stored before D630
20365
20263
  * parses as "every opening blocks" — the behaviour it was written under.
20366
20264
  */
20367
- nonBlocking: NcAlarmNonBlockingListSchema.default([])
20265
+ nonBlocking: NcAlarmNonBlockingListSchema.default([]),
20266
+ /**
20267
+ * Per arm mode, the delays that mode OVERRIDES (D697). A mode with no entry, or an entry
20268
+ * without a field, uses the global value above — so `[]`, the default, is exactly the
20269
+ * behaviour of a blob stored before this field existed. Read through `resolveModeDelays`.
20270
+ */
20271
+ modeDelays: NcAlarmModeDelaysListSchema.default([])
20368
20272
  });
20369
20273
  /**
20370
20274
  * Every field optional — a tab edits one control at a time.
20371
20275
  *
20372
- * `nonBlocking` is re-declared WITHOUT its default: `.partial()` does not
20373
- * remove an inner `.default()`, so a patch that never named the field would
20374
- * parse to `nonBlocking: []` and wipe every mode's list on an unrelated edit
20375
- * (the same trap {@link NcRulePatchSchema} documents).
20276
+ * `nonBlocking` and `modeDelays` are re-declared WITHOUT their defaults:
20277
+ * `.partial()` does not remove an inner `.default()`, so a patch that never
20278
+ * named the field would parse to `[]` and wipe every mode's list on an
20279
+ * unrelated edit (the same trap {@link NcRulePatchSchema} documents). Here
20280
+ * `modeDelays` means EDITS, not the stored overrides.
20376
20281
  */
20377
- var NcAlarmSettingsPatchSchema = NcAlarmSettingsSchema.extend({ nonBlocking: NcAlarmNonBlockingListSchema }).partial();
20282
+ var NcAlarmSettingsPatchSchema = NcAlarmSettingsSchema.extend({
20283
+ nonBlocking: NcAlarmNonBlockingListSchema,
20284
+ /** Per-mode, per-field edits — NOT the whole list (see NcAlarmModeDelaysEditSchema). */
20285
+ modeDelays: NcAlarmModeDelaysEditListSchema,
20286
+ /** ONE membership change; the panel applies it to the list it holds at its turn. */
20287
+ nonBlockingEdit: NcAlarmNonBlockingEditSchema
20288
+ }).partial().refine((p) => p.nonBlocking === void 0 || p.nonBlockingEdit === void 0, { message: "nonBlocking and nonBlockingEdit are exclusive — send the whole lists or one edit" });
20378
20289
  /**
20379
20290
  * What one arm mode actually arms, DERIVED from the enabled rules gated on it.
20380
20291
  * Never authored, never stored — see `alarm-mode-coverage.ts` for why a stored
@@ -20474,6 +20385,28 @@ var NcAlarmConfigSchema = object({
20474
20385
  */
20475
20386
  live: NcAlarmLiveSchema.optional()
20476
20387
  });
20388
+ var NcAlarmSensorReadingSchema = _enum([
20389
+ "open",
20390
+ "closed",
20391
+ "unknown",
20392
+ "not-opening"
20393
+ ]);
20394
+ /** One device's state as the alarm reads it — the classifier the arm check uses. */
20395
+ var NcAlarmSensorStateSchema = object({
20396
+ deviceId: number().int().positive(),
20397
+ reading: NcAlarmSensorReadingSchema,
20398
+ /** The word as read (`open`, `closed`, `unlocked`, `stopped`, …); null when unknown / not an opening. */
20399
+ state: string().nullable(),
20400
+ /** Why `unknown`: the read failed, or the slice holds no word its cap defines (a placeholder included). */
20401
+ unknownWhy: _enum(["read-failed", "unknown-word"]).nullable(),
20402
+ /** The device manager's liveness as the centre mirrors it; null = not known. */
20403
+ online: boolean().nullable()
20404
+ });
20405
+ var NcAlarmSensorsInputSchema = object({ deviceIds: array(number().int().positive()).max(500) });
20406
+ var NcAlarmSensorsSchema = object({
20407
+ sensors: array(NcAlarmSensorStateSchema),
20408
+ readAt: number().int().nonnegative()
20409
+ });
20477
20410
  /**
20478
20411
  * ONE rule's demand on ONE camera's clip ring.
20479
20412
  *
@@ -20564,7 +20497,7 @@ method(object({}), object({ rules: array(NcRuleSchema) }), { auth: "admin" }), m
20564
20497
  }), method(object({}), NcAlarmConfigSchema, { auth: "admin" }), method(object({ patch: NcAlarmSettingsPatchSchema }), NcAlarmConfigSchema, {
20565
20498
  kind: "mutation",
20566
20499
  auth: "admin"
20567
- });
20500
+ }), method(NcAlarmSensorsInputSchema, NcAlarmSensorsSchema, { auth: "admin" });
20568
20501
  /**
20569
20502
  * Zod schemas for persisted record types.
20570
20503
  *
@@ -20911,12 +20844,26 @@ var CameraSensorRefSchema = object({
20911
20844
  function cameraSensorRefKey(ref) {
20912
20845
  return `${ref.addonId}/${ref.stableId}`;
20913
20846
  }
20914
- /** CS-1 accepts exactly one mode; CS-2 (D673) widens it to confirm / replace. */
20915
- var CameraSensorsModeSchema = _enum(["in-addition"]);
20916
- var CameraSensorsConfigSchema = object({
20917
- mode: CameraSensorsModeSchema,
20918
- sensors: array(CameraSensorRefSchema).min(1).max(8)
20919
- }).superRefine((value, ctx) => {
20847
+ /**
20848
+ * A sensor's mode (D673). `in-addition`: its motion is the camera's motion too.
20849
+ * `replace`: its motion is the camera's, and while one is READY the camera's
20850
+ * own motion no longer counts on its own. `confirm`: while one is READY the
20851
+ * camera's own motion counts only while a confirm sensor is active — with or
20852
+ * without a replace sensor (spec C2, the controller's ruling on Q1).
20853
+ */
20854
+ var CameraSensorModeSchema = _enum([
20855
+ "in-addition",
20856
+ "confirm",
20857
+ "replace"
20858
+ ]);
20859
+ /** A stored sensor with no mode — every CS-1 row — is in addition. */
20860
+ var DEFAULT_CAMERA_SENSOR_MODE = "in-addition";
20861
+ /**
20862
+ * A camera's attached sensors. A CS-1 row carried an envelope
20863
+ * `mode: 'in-addition'`: `z.object` drops it on parse, and the PARSED value is
20864
+ * what the write stores (D672 rule 3), so it is never written again.
20865
+ */
20866
+ var CameraSensorsConfigSchema = object({ sensors: array(CameraSensorRefSchema.extend({ mode: CameraSensorModeSchema.default(DEFAULT_CAMERA_SENSOR_MODE) })).min(1).max(8) }).superRefine((value, ctx) => {
20920
20867
  const seen = /* @__PURE__ */ new Set();
20921
20868
  value.sensors.forEach((ref, index) => {
20922
20869
  const key = cameraSensorRefKey(ref);
@@ -20928,39 +20875,41 @@ var CameraSensorsConfigSchema = object({
20928
20875
  seen.add(key);
20929
20876
  });
20930
20877
  });
20931
- var RefFields = {
20878
+ /** Every attachment names its mode; an older orchestrator that does not is in addition. */
20879
+ var AttachmentFields = {
20932
20880
  addonId: string(),
20933
- stableId: string()
20881
+ stableId: string(),
20882
+ mode: CameraSensorModeSchema.default(DEFAULT_CAMERA_SENSOR_MODE)
20934
20883
  };
20935
20884
  var CameraSensorAttachmentSchema = discriminatedUnion("state", [
20936
20885
  object({
20937
- ...RefFields,
20886
+ ...AttachmentFields,
20938
20887
  state: literal("ready"),
20939
20888
  deviceId: number(),
20940
20889
  name: string(),
20941
20890
  caps: array(string()).readonly()
20942
20891
  }),
20943
20892
  object({
20944
- ...RefFields,
20893
+ ...AttachmentFields,
20945
20894
  state: literal("offline"),
20946
20895
  deviceId: number(),
20947
20896
  name: string(),
20948
20897
  reason: _enum(["offline", "disabled"])
20949
20898
  }),
20950
20899
  object({
20951
- ...RefFields,
20900
+ ...AttachmentFields,
20952
20901
  state: literal("missing"),
20953
20902
  reason: string()
20954
20903
  }),
20955
20904
  object({
20956
- ...RefFields,
20905
+ ...AttachmentFields,
20957
20906
  state: literal("unsupported"),
20958
20907
  deviceId: number(),
20959
20908
  name: string(),
20960
20909
  reason: string()
20961
20910
  }),
20962
20911
  object({
20963
- ...RefFields,
20912
+ ...AttachmentFields,
20964
20913
  state: literal("unreadable"),
20965
20914
  reason: string()
20966
20915
  })
@@ -20973,17 +20922,49 @@ var CameraSensorAttachmentSchema = discriminatedUnion("state", [
20973
20922
  * say.
20974
20923
  */
20975
20924
  var CameraSensorsNotForwardedSchema = _enum(["onboard-not-listed", "no-active-detection"]);
20925
+ /** Whether the camera's OWN motion counts on its own (D673 C2), from its READY sensors (C3). */
20926
+ var CameraOwnMotionSchema = _enum([
20927
+ "always",
20928
+ "when-confirmed",
20929
+ "never"
20930
+ ]);
20931
+ /** Confirm / Replace cannot suppress this camera's motion: its provider still emits it directly (D673 C13). */
20932
+ var CameraSensorsNotEnforcedSchema = _enum(["provider-not-split"]);
20933
+ /**
20934
+ * The camera's OWN onboard motion (D696): the raw input the bridge combines,
20935
+ * never the effective value. The camera's `motion` slice is the effective one,
20936
+ * so a view of the camera's own row reads this.
20937
+ * - `atMs`: when the bridge received the camera's last own edge.
20938
+ * - `detected`: evaluated WHEN THE STATUS IS ASKED — the last edge said `true`
20939
+ * AND it is younger than the window the bridge counts the camera's own motion
20940
+ * for (`motionCooldownMs`, floored at two sustain ticks). A camera that never
20941
+ * sends a clear (heartbeats only) therefore reads `false` once no push came
20942
+ * within the window; a status read is a snapshot, so a live view re-asks.
20943
+ * Absent = this orchestrator has not received the camera's own motion since it
20944
+ * started (unknown, never "quiet"), or an orchestrator older than D696.
20945
+ */
20946
+ var CameraRawLevelSchema = object({
20947
+ detected: boolean(),
20948
+ atMs: number()
20949
+ });
20976
20950
  var CameraSensorsStatusSchema = discriminatedUnion("state", [
20977
- object({ state: literal("not-configured") }),
20951
+ object({
20952
+ state: literal("not-configured"),
20953
+ cameraLevel: CameraRawLevelSchema.optional()
20954
+ }),
20978
20955
  object({
20979
20956
  state: literal("unreadable"),
20980
- reason: string()
20957
+ reason: string(),
20958
+ cameraLevel: CameraRawLevelSchema.optional()
20981
20959
  }),
20982
20960
  object({
20983
20961
  state: literal("configured"),
20984
- mode: CameraSensorsModeSchema,
20962
+ cameraLevel: CameraRawLevelSchema.optional(),
20985
20963
  sensors: array(CameraSensorAttachmentSchema).readonly(),
20986
- notForwarded: CameraSensorsNotForwardedSchema.optional()
20964
+ /** Absent = an orchestrator older than CS-2: it does not say (D315). */
20965
+ cameraMotion: CameraOwnMotionSchema.optional(),
20966
+ notForwarded: CameraSensorsNotForwardedSchema.optional(),
20967
+ notEnforced: CameraSensorsNotEnforcedSchema.optional()
20987
20968
  })
20988
20969
  ]);
20989
20970
  Object.freeze({
@@ -21668,14 +21649,14 @@ var TrackSchema = object({
21668
21649
  * `derive-returned-null tile=standin`,
21669
21650
  * `native-tile tile=native no-key-frame-at-close`, …) written at close and
21670
21651
  * CLEARED by the late-keyFrame upgrade when a native tile lands after all.
21671
- * The operator-facing answer to "perché manca l'immagine?" on a track whose
21652
+ * The operator-facing answer to "perché manca l'immagine?" [why is the image missing?] on a track whose
21672
21653
  * tile is a face/plate stand-in, a raster crop, or an icon.
21673
21654
  *
21674
21655
  * **`no-key-frame-at-close` (D400).** The line used to be written ONLY when
21675
21656
  * the TILE ranked below native, so a track whose thumbnail landed natively
21676
21657
  * while its key frame missed carried no reason at all — three of the four
21677
21658
  * `MISSING_KEYFRAME` tracks in the 2026-09-07 operator audit were exactly
21678
- * that shape, and their "niente ultimo" had no cause anywhere on the row.
21659
+ * that shape, and their "niente ultimo" [no last frame] had no cause anywhere on the row.
21679
21660
  * The key frame is the head of a cascade (`keyFrame ⇒ keyFrameSmall ⇒ the
21680
21661
  * lastFrame copy source`), so its absence is now on this line whatever the
21681
21662
  * tile ended up being.
@@ -21762,7 +21743,7 @@ var MotionEventSchema = object({
21762
21743
  /**
21763
21744
  * Ms offsets from `timestamp` (the episode's own first rising edge, so the
21764
21745
  * first entry is always `0`) of every genuine off→on transition the
21765
- * episode saw — "ogni evento on si deve salvare" (D475). NOT one entry per
21746
+ * episode saw — "ogni evento on si deve salvare" [every ON event must be saved] (D475). NOT one entry per
21766
21747
  * push: a firmware source that keepalives at ~1 Hz for the whole burst
21767
21748
  * (Reolink, Hikvision) produces exactly one edge; a source that reports an
21768
21749
  * explicit `false` mid-episode and then resumes before the quiet window
@@ -22286,6 +22267,7 @@ var KeyEventSchema = object({
22286
22267
  bestEventId: string(),
22287
22268
  /** Track lifetime in ms (lastSeen - firstSeen). */
22288
22269
  windowMs: number().optional(),
22270
+ audioLabels: array(TrackAudioLabelSchema).readonly().optional(),
22289
22271
  ...TrackFlagFields,
22290
22272
  ...TrackRetrainFields
22291
22273
  });
@@ -24214,8 +24196,10 @@ var RunnerCameraConfigSchema = object({
24214
24196
  * - `analyzer`: ML/frame-diff motion detection (motion-wasm or other
24215
24197
  * analyzer providers) running on decoded frames in this runner.
24216
24198
  * - `onboard`: camera-native motion pushes (Reolink Baichuan, ONVIF
24217
- * analytics). The provider emits ProviderMotion
24218
- * events; the orchestrator forwards to `reportMotion`.
24199
+ * analytics). The provider emits its raw push as `ProviderMotion`
24200
+ * (D673); the orchestrator's camera-sensors bridge re-emits the camera's
24201
+ * effective motion as `MotionOnMotionChanged`, which is what reaches
24202
+ * `reportMotion`.
24219
24203
  */
24220
24204
  motionSources: MotionSourcesSchema.default(["analyzer"]),
24221
24205
  /**
@@ -24392,7 +24376,15 @@ var RunnerLocalLoadSchema = object({
24392
24376
  hasGpu: boolean(),
24393
24377
  inferenceBackend: string().optional(),
24394
24378
  cpuCores: number().optional()
24395
- })
24379
+ }),
24380
+ /**
24381
+ * Who writes a camera's `motion` runtime slice (D696). `'orchestrator'`: this
24382
+ * runner never writes it. ABSENT = a runner older than D696, which still
24383
+ * writes the slice from its phase machine; the orchestrator does not write
24384
+ * while any runner node is absent-or-unanswered, so one slice never has two
24385
+ * writers.
24386
+ */
24387
+ motionSliceWriter: literal("orchestrator").optional()
24396
24388
  });
24397
24389
  /**
24398
24390
  * Aggregate runtime metrics for the runner's whole local pool. Mirrors the
@@ -27205,7 +27197,7 @@ var ClipPlaybackSchema = object({
27205
27197
  * **One authorised yes is one wake.** `next-natural` — take the clip the next
27206
27198
  * time the camera is awake for its own reasons — is deliberately not a member:
27207
27199
  * it was proposed, it is free on the battery, and the operator declined it on
27208
- * 2026-09-20 (*"Quando un export viene richiesto si sveglia la camera."*,
27200
+ * 2026-09-20 (*"Quando un export viene richiesto si sveglia la camera."* [When an export is requested the camera wakes up],
27209
27201
  * D558 "Considered and not taken").
27210
27202
  */
27211
27203
  var ClipWakeSchema = _enum(["authorised"]);
@@ -27466,7 +27458,7 @@ DeviceType.Camera, method(object({
27466
27458
  * It replaced `sources?: string[]`, a VIEW filter over source ids that
27467
27459
  * assumed the answer was a fan-out over everything a camera has. The
27468
27460
  * operator settled otherwise on 2026-09-20 — *"l'utilizzatore è uno
27469
- * solo"* — so the list is asked of one provider at a time and there is
27461
+ * solo"* [there is only one user] — so the list is asked of one provider at a time and there is
27470
27462
  * nothing to filter out of it.
27471
27463
  */
27472
27464
  provider: string().min(1)
@@ -30061,6 +30053,70 @@ onStatusChanged: { data: object({
30061
30053
  * whether persisting is worth a SQLite commit. */
30062
30054
  volatileStateFields: ["lastChangedAt"]
30063
30055
  };
30056
+ var DoorbellStatusSchema = object({
30057
+ /** Ms epoch of the last press. null = never observed since this provider started. */
30058
+ lastPressedAt: number().nullable(),
30059
+ /** Counter since provider start. Resets on reboot. Useful for metrics/debug. */
30060
+ pressCountSinceStart: number()
30061
+ });
30062
+ var DoorbellPressEventSchema = object({
30063
+ deviceId: number(),
30064
+ timestamp: number()
30065
+ });
30066
+ /**
30067
+ * Doorbell button cap. Two kinds of provider serve it, and to every consumer
30068
+ * they are the same cap:
30069
+ *
30070
+ * - **Native** providers, registered per device by a driver addon through
30071
+ * `ctx.registerNativeCap` — a `DeviceType.Button` accessory with
30072
+ * `role: DeviceRole.Doorbell`, or the camera itself (Reolink registers at
30073
+ * camera level). They emit `onPressed` on every firmware ring.
30074
+ * - **A composed doorbell** (D670, D671): a camera's customization gives it
30075
+ * the cap, its `lastPressedAt` rising from the sources the operator
30076
+ * assigned in Customize → Doorbell, and the composer emits `onPressed`
30077
+ * from that field's advance (`fromState`).
30078
+ *
30079
+ * The DeviceEventPropagator re-emits `onPressed` on the camera parent.
30080
+ */
30081
+ var doorbellCapability = {
30082
+ name: "doorbell",
30083
+ scope: "device",
30084
+ deviceNative: true,
30085
+ mode: "singleton",
30086
+ deviceTypes: [DeviceType.Button, DeviceType.Camera],
30087
+ methods: {},
30088
+ events: {
30089
+ /**
30090
+ * Fires once per physical press. Reolink delivers via Baichuan
30091
+ * push (`ReolinkSimpleEvent.type === 'doorbell'`). There is no
30092
+ * release/duration — it's a pulse.
30093
+ */
30094
+ onPressed: {
30095
+ data: DoorbellPressEventSchema,
30096
+ fromState: {
30097
+ field: "lastPressedAt",
30098
+ on: "advance"
30099
+ }
30100
+ } },
30101
+ status: {
30102
+ schema: DoorbellStatusSchema,
30103
+ kind: "push"
30104
+ },
30105
+ /**
30106
+ * Runtime-state slice — last press timestamp + lifetime press count.
30107
+ * Mirrored by the kernel and readable via
30108
+ * `device.state.doorbell.value`. UIs can show "last ring 5m ago"
30109
+ * without subscribing.
30110
+ */
30111
+ runtimeState: DoorbellStatusSchema,
30112
+ /**
30113
+ * Runtime-state durability: **restored** — a monotonic accumulator: the slice IS the record. `lastPressedAt` is content here, not a clock, so it is deliberately NOT volatile.
30114
+ *
30115
+ * See `RuntimeStateDurability`. Enforced by
30116
+ * `scripts/check-runtime-state-durability.ts`.
30117
+ */
30118
+ durability: "restored"
30119
+ };
30064
30120
  /**
30065
30121
  * Enum-state sensor — a string value picked from a finite option set.
30066
30122
  * Drives HA `sensor` entries with `state_class: enum` (HVAC action
@@ -32205,9 +32261,9 @@ var MotionStatusSchema = object({
32205
32261
  /** Ms epoch of the last detected-true observation. Null if never detected. */
32206
32262
  lastDetectedAt: number().nullable(),
32207
32263
  /**
32208
- * `MOTION_CLOSE_AFTER_MS` while `detected: true` on a `Camera` device,
32209
- * `null` while false and on every `Sensor` device (D475) — see that
32210
- * constant's doc for the one-authority rule.
32264
+ * `MOTION_CLOSE_AFTER_MS` while `detected: true` on a `Camera` device (the
32265
+ * orchestrator writes it, D696), `null` while false and on every `Sensor`
32266
+ * device (D475) — see that constant's doc for the one-authority rule.
32211
32267
  *
32212
32268
  * ## Reading this field still arms nothing
32213
32269
  *
@@ -32225,34 +32281,31 @@ var MotionStatusSchema = object({
32225
32281
  * `addon-export-alexa/src/motion-clear-hold.ts` and
32226
32282
  * `addon-export-hap`'s `RESET_DEBOUNCE_MS` both do.
32227
32283
  *
32228
- * ## Who writes it
32229
- *
32230
- * - **Cameras** — the runner's phase machine, `active → watching` on
32231
- * `cooldown_expired`, which then writes this slice with
32232
- * `detected: false` (`handlePhaseChanged` in
32233
- * `pipeline-runner/index.ts`). It produces the FALLING edge, which
32234
- * matters most for the sources that only ever push a rising one:
32235
- * Reolink emits `MotionOnMotionChanged { detected: true }` and never
32236
- * a false.
32237
- * - **Sensors** (Home Assistant binary sensors, Homematic) — the
32238
- * provider pushes the false itself, from the upstream system's own
32239
- * state change. No phase machine is involved.
32240
- *
32241
- * ### The phase machine is CANONICAL, not sole — and that is a defect
32242
- *
32243
- * An earlier revision of this docblock (mine, 2026-09-12) claimed the
32244
- * phase machine is the sole writer for a camera. It is not.
32245
- * `hikvision-camera.ts:3464` and `amcrest-camera.ts:445` both call
32246
- * `setCapSlice(motionCapability, …)` on their own rising edge, and
32247
- * Hikvision's comment says why: it read THIS docblock, agreed the
32248
- * runner is canonical, and wrote anyway to avoid per-tick churn. So
32249
- * two authorities can disagree about one slice, which this repo
32250
- * forbids, and the doc said otherwise — which is worse than saying
32251
- * nothing, because it reads as verification.
32252
- *
32253
- * This predates D475 and is not fixed there: the fix touches every
32254
- * camera provider. Recorded in D475's Consequences. Do not restore the
32255
- * "sole writer" wording without also removing the other writers.
32284
+ * ## Who writes it (D696)
32285
+ *
32286
+ * - **Cameras** — the orchestrator, and nothing else. It writes the camera's
32287
+ * EFFECTIVE motion (`addon-pipeline-orchestrator`
32288
+ * `camera-sensors/motion-slice.ts`), alongside the effective
32289
+ * `MotionOnMotionChanged` it emits or receives: the camera-sensors bridge
32290
+ * for a split camera, an unsplit emitter's direct event, the analyzer and
32291
+ * device activity, as the camera's `motionSources` counts them. A source
32292
+ * that never sends a clear falls one window after its last `true`.
32293
+ * `lastDetectedAt` moves only on an effective rise. No camera provider
32294
+ * writes this slice (not even a boot seed), and neither does the runner's
32295
+ * phase machine: its phase is "a session is attached" for every on-motion
32296
+ * session, not motion, and it now has its own `DetectionPhaseTransition`.
32297
+ * A provider's `isDetected` answers from the hub's slice.
32298
+ * - **Sensors** (Home Assistant binary sensors, Homematic, Matter, Alexa
32299
+ * imports) — the provider pushes both edges itself, from the upstream
32300
+ * system's own state change. That is the sensor's own fact.
32301
+ *
32302
+ * `scripts/check-onboard-motion-emitters.ts` refuses any other writer of a
32303
+ * `motion` slice; each sensor writer is a named exemption.
32304
+ *
32305
+ * This replaces the D475 §4 rule ("the phase machine is the sole writer").
32306
+ * That rule was never true: Hikvision and Amcrest wrote the slice raw beside
32307
+ * it, every provider seeded it at boot, and every session left it
32308
+ * `detected: true` after its detach.
32256
32309
  */
32257
32310
  autoClearAfterMs: number().nullable()
32258
32311
  });
@@ -32324,11 +32377,12 @@ onMotionChanged: { data: MotionOnMotionChangedDataSchema } },
32324
32377
  */
32325
32378
  runtimeState: MotionStatusSchema,
32326
32379
  /**
32327
- * Runtime-state durability: **session** — every writer of this slice
32380
+ * Runtime-state durability: **session** — the writer of this slice
32328
32381
  * writes only on an EDGE, so a restored `detected: true` would stay
32329
32382
  * frozen until the next one instead of being corrected. The next edge
32330
- * re-publishes the real state. (On who the writers are, and why there
32331
- * is more than one, see `autoClearAfterMs` above.)
32383
+ * re-publishes the real state, and the orchestrator re-publishes every
32384
+ * camera when it starts writing (D696; on who writes it, see
32385
+ * `autoClearAfterMs` above).
32332
32386
  *
32333
32387
  * See `RuntimeStateDurability`. Enforced by
32334
32388
  * `scripts/check-runtime-state-durability.ts`.
@@ -34711,8 +34765,7 @@ var ptzAutotrackCapability = {
34711
34765
  deviceNative: true,
34712
34766
  mode: "singleton",
34713
34767
  /**
34714
- * Two kinds of provider behind one name, the same shape `snapshot` and
34715
- * `doorbell` use:
34768
+ * Two kinds of provider behind one name, the same shape `snapshot` uses:
34716
34769
  *
34717
34770
  * - **Native**: the camera's own firmware autotrack, registered per device by
34718
34771
  * the driver when the probe says it exists (Reolink: yes; Hikvision:
@@ -34720,7 +34773,7 @@ var ptzAutotrackCapability = {
34720
34773
  * - **Wrapper**: the emulated implementation (`@camstack/system`'s `autotrack` builtin),
34721
34774
  * which follows a subject with `ptz.move` pulses driven by the detection
34722
34775
  * pipeline. `defaultActive: false` — the operator binds it per camera in
34723
- * the bindings UI, exactly as `virtual-doorbell` is bound.
34776
+ * the bindings UI.
34724
34777
  *
34725
34778
  * The binding chooses WHICH implementation answers; `setEnabled` stays the
34726
34779
  * one switch for the function either way. A camera never has both driving its
@@ -35395,7 +35448,7 @@ var ReadGopBytesResultSchema = object({
35395
35448
  /**
35396
35449
  * A time WINDOW of one finalized segment, cut by byte range — the multi-GOP
35397
35450
  * twin of {@link ReadGopBytesResultSchema}'s single instant. Built for the
35398
- * replay clip's `recording` source (`docs/design/plans/2026-08-26-replay-clip-su-pipeline.md`):
35451
+ * replay clip's `recording` source (`docs/design/plans/2026-08-26-clip-replay-on-pipeline.md`):
35399
35452
  * a replay needs several seconds of native pixels, not one frame.
35400
35453
  *
35401
35454
  * `ok.data` is standalone-demuxable, same as a GOP read. `ok.reachesRequestedEnd`
@@ -38759,6 +38812,7 @@ var zoneRulesCapability = {
38759
38812
  */
38760
38813
  durability: "restored"
38761
38814
  };
38815
+ SOURCE_CAPS.filter((cap) => cap !== "switch" && cap !== "motion");
38762
38816
  /**
38763
38817
  * Accessory device helpers — shared across drivers.
38764
38818
  *
@@ -44784,6 +44838,12 @@ Object.freeze({
44784
44838
  addonId: null,
44785
44839
  access: "view"
44786
44840
  },
44841
+ "notificationRules.getAlarmSensors": {
44842
+ capName: "notification-rules",
44843
+ capScope: "system",
44844
+ addonId: null,
44845
+ access: "view"
44846
+ },
44787
44847
  "notificationRules.getClipRetentionAsks": {
44788
44848
  capName: "notification-rules",
44789
44849
  capScope: "system",
@@ -48362,6 +48422,11 @@ Object.freeze({
48362
48422
  }
48363
48423
  });
48364
48424
  Object.freeze({
48425
+ "accessories.getStatus": [{
48426
+ name: "deviceId",
48427
+ form: "single",
48428
+ optional: false
48429
+ }],
48365
48430
  "accessories.setChildHidden": [{
48366
48431
  name: "childDeviceId",
48367
48432
  form: "single",
@@ -48381,6 +48446,11 @@ Object.freeze({
48381
48446
  form: "single",
48382
48447
  optional: false
48383
48448
  }],
48449
+ "airQualitySensor.getStatus": [{
48450
+ name: "deviceId",
48451
+ form: "single",
48452
+ optional: false
48453
+ }],
48384
48454
  "alarmPanel.arm": [{
48385
48455
  name: "deviceId",
48386
48456
  form: "single",
@@ -48391,11 +48461,36 @@ Object.freeze({
48391
48461
  form: "single",
48392
48462
  optional: false
48393
48463
  }],
48464
+ "alarmPanel.getStatus": [{
48465
+ name: "deviceId",
48466
+ form: "single",
48467
+ optional: false
48468
+ }],
48394
48469
  "alarmPanel.trigger": [{
48395
48470
  name: "deviceId",
48396
48471
  form: "single",
48397
48472
  optional: false
48398
48473
  }],
48474
+ "ambientLightSensor.getStatus": [{
48475
+ name: "deviceId",
48476
+ form: "single",
48477
+ optional: false
48478
+ }],
48479
+ "audioAnalysis.applyDeviceSettingsPatch": [{
48480
+ name: "deviceId",
48481
+ form: "single",
48482
+ optional: false
48483
+ }],
48484
+ "audioAnalysis.getDeviceLiveContribution": [{
48485
+ name: "deviceId",
48486
+ form: "single",
48487
+ optional: false
48488
+ }],
48489
+ "audioAnalysis.getDeviceSettingsContribution": [{
48490
+ name: "deviceId",
48491
+ form: "single",
48492
+ optional: false
48493
+ }],
48399
48494
  "audioAnalysis.resolveDeviceSettings": [{
48400
48495
  name: "deviceId",
48401
48496
  form: "single",
@@ -48436,16 +48531,36 @@ Object.freeze({
48436
48531
  form: "single",
48437
48532
  optional: false
48438
48533
  }],
48534
+ "automationControl.getStatus": [{
48535
+ name: "deviceId",
48536
+ form: "single",
48537
+ optional: false
48538
+ }],
48439
48539
  "automationControl.trigger": [{
48440
48540
  name: "deviceId",
48441
48541
  form: "single",
48442
48542
  optional: false
48443
48543
  }],
48544
+ "battery.getStatus": [{
48545
+ name: "deviceId",
48546
+ form: "single",
48547
+ optional: false
48548
+ }],
48444
48549
  "battery.wakeForStream": [{
48445
48550
  name: "deviceId",
48446
48551
  form: "single",
48447
48552
  optional: false
48448
48553
  }],
48554
+ "binary.getStatus": [{
48555
+ name: "deviceId",
48556
+ form: "single",
48557
+ optional: false
48558
+ }],
48559
+ "brightness.getStatus": [{
48560
+ name: "deviceId",
48561
+ form: "single",
48562
+ optional: false
48563
+ }],
48449
48564
  "brightness.setBrightness": [{
48450
48565
  name: "deviceId",
48451
48566
  form: "single",
@@ -48461,6 +48576,26 @@ Object.freeze({
48461
48576
  form: "single",
48462
48577
  optional: false
48463
48578
  }],
48579
+ "cameraCredentials.getStatus": [{
48580
+ name: "deviceId",
48581
+ form: "single",
48582
+ optional: false
48583
+ }],
48584
+ "cameraGridLayout.applyDeviceSettingsPatch": [{
48585
+ name: "deviceId",
48586
+ form: "single",
48587
+ optional: false
48588
+ }],
48589
+ "cameraGridLayout.getDeviceLiveContribution": [{
48590
+ name: "deviceId",
48591
+ form: "single",
48592
+ optional: false
48593
+ }],
48594
+ "cameraGridLayout.getDeviceSettingsContribution": [{
48595
+ name: "deviceId",
48596
+ form: "single",
48597
+ optional: false
48598
+ }],
48464
48599
  "cameraGridLayout.getLayout": [{
48465
48600
  name: "deviceId",
48466
48601
  form: "single",
@@ -48476,6 +48611,21 @@ Object.freeze({
48476
48611
  form: "single",
48477
48612
  optional: false
48478
48613
  }],
48614
+ "cameraPipelineConfig.applyDeviceSettingsPatch": [{
48615
+ name: "deviceId",
48616
+ form: "single",
48617
+ optional: false
48618
+ }],
48619
+ "cameraPipelineConfig.getDeviceLiveContribution": [{
48620
+ name: "deviceId",
48621
+ form: "single",
48622
+ optional: false
48623
+ }],
48624
+ "cameraPipelineConfig.getDeviceSettingsContribution": [{
48625
+ name: "deviceId",
48626
+ form: "single",
48627
+ optional: false
48628
+ }],
48479
48629
  "cameraStreams.getBrokerStreams": [{
48480
48630
  name: "deviceId",
48481
48631
  form: "single",
@@ -48501,6 +48651,16 @@ Object.freeze({
48501
48651
  form: "single",
48502
48652
  optional: false
48503
48653
  }],
48654
+ "carbonMonoxide.getStatus": [{
48655
+ name: "deviceId",
48656
+ form: "single",
48657
+ optional: false
48658
+ }],
48659
+ "climateControl.getStatus": [{
48660
+ name: "deviceId",
48661
+ form: "single",
48662
+ optional: false
48663
+ }],
48504
48664
  "climateControl.setFanMode": [{
48505
48665
  name: "deviceId",
48506
48666
  form: "single",
@@ -48541,16 +48701,41 @@ Object.freeze({
48541
48701
  form: "single",
48542
48702
  optional: false
48543
48703
  }],
48704
+ "color.getStatus": [{
48705
+ name: "deviceId",
48706
+ form: "single",
48707
+ optional: false
48708
+ }],
48544
48709
  "color.setColor": [{
48545
48710
  name: "deviceId",
48546
48711
  form: "single",
48547
48712
  optional: false
48548
48713
  }],
48714
+ "connectivity.getStatus": [{
48715
+ name: "deviceId",
48716
+ form: "single",
48717
+ optional: false
48718
+ }],
48719
+ "consumables.getStatus": [{
48720
+ name: "deviceId",
48721
+ form: "single",
48722
+ optional: false
48723
+ }],
48549
48724
  "consumables.reset": [{
48550
48725
  name: "deviceId",
48551
48726
  form: "single",
48552
48727
  optional: false
48553
48728
  }],
48729
+ "contact.getStatus": [{
48730
+ name: "deviceId",
48731
+ form: "single",
48732
+ optional: false
48733
+ }],
48734
+ "control.getStatus": [{
48735
+ name: "deviceId",
48736
+ form: "single",
48737
+ optional: false
48738
+ }],
48554
48739
  "control.setValue": [{
48555
48740
  name: "deviceId",
48556
48741
  form: "single",
@@ -48561,6 +48746,11 @@ Object.freeze({
48561
48746
  form: "single",
48562
48747
  optional: false
48563
48748
  }],
48749
+ "cover.getStatus": [{
48750
+ name: "deviceId",
48751
+ form: "single",
48752
+ optional: false
48753
+ }],
48564
48754
  "cover.open": [{
48565
48755
  name: "deviceId",
48566
48756
  form: "single",
@@ -48586,6 +48776,11 @@ Object.freeze({
48586
48776
  form: "single",
48587
48777
  optional: false
48588
48778
  }],
48779
+ "dayNight.getStatus": [{
48780
+ name: "deviceId",
48781
+ form: "single",
48782
+ optional: false
48783
+ }],
48589
48784
  "dayNight.setSettings": [{
48590
48785
  name: "deviceId",
48591
48786
  form: "single",
@@ -48596,11 +48791,31 @@ Object.freeze({
48596
48791
  form: "single",
48597
48792
  optional: true
48598
48793
  }],
48794
+ "detectionPipeline.applyDeviceSettingsPatch": [{
48795
+ name: "deviceId",
48796
+ form: "single",
48797
+ optional: false
48798
+ }],
48799
+ "detectionPipeline.getDeviceLiveContribution": [{
48800
+ name: "deviceId",
48801
+ form: "single",
48802
+ optional: false
48803
+ }],
48804
+ "detectionPipeline.getDeviceSettingsContribution": [{
48805
+ name: "deviceId",
48806
+ form: "single",
48807
+ optional: false
48808
+ }],
48599
48809
  "deviceAdminLink.getAdminLink": [{
48600
48810
  name: "deviceId",
48601
48811
  form: "single",
48602
48812
  optional: false
48603
48813
  }],
48814
+ "deviceAdoption.getStatus": [{
48815
+ name: "deviceId",
48816
+ form: "single",
48817
+ optional: false
48818
+ }],
48604
48819
  "deviceAdoption.release": [{
48605
48820
  name: "camDeviceId",
48606
48821
  form: "single",
@@ -48616,6 +48831,11 @@ Object.freeze({
48616
48831
  form: "single",
48617
48832
  optional: false
48618
48833
  }],
48834
+ "deviceDiscovery.getStatus": [{
48835
+ name: "deviceId",
48836
+ form: "single",
48837
+ optional: false
48838
+ }],
48619
48839
  "deviceDiscovery.listDiscovered": [{
48620
48840
  name: "deviceId",
48621
48841
  form: "single",
@@ -48635,6 +48855,21 @@ Object.freeze({
48635
48855
  form: "single",
48636
48856
  optional: false
48637
48857
  }],
48858
+ "deviceExport.applyDeviceSettingsPatch": [{
48859
+ name: "deviceId",
48860
+ form: "single",
48861
+ optional: false
48862
+ }],
48863
+ "deviceExport.getDeviceLiveContribution": [{
48864
+ name: "deviceId",
48865
+ form: "single",
48866
+ optional: false
48867
+ }],
48868
+ "deviceExport.getDeviceSettingsContribution": [{
48869
+ name: "deviceId",
48870
+ form: "single",
48871
+ optional: false
48872
+ }],
48638
48873
  "deviceExtension.listCandidates": [{
48639
48874
  name: "deviceId",
48640
48875
  form: "single",
@@ -48983,6 +49218,26 @@ Object.freeze({
48983
49218
  form: "single",
48984
49219
  optional: false
48985
49220
  }],
49221
+ "deviceStatus.getStatus": [{
49222
+ name: "deviceId",
49223
+ form: "single",
49224
+ optional: false
49225
+ }],
49226
+ "doorbell.getStatus": [{
49227
+ name: "deviceId",
49228
+ form: "single",
49229
+ optional: false
49230
+ }],
49231
+ "enumSensor.getStatus": [{
49232
+ name: "deviceId",
49233
+ form: "single",
49234
+ optional: false
49235
+ }],
49236
+ "eventEmitter.getStatus": [{
49237
+ name: "deviceId",
49238
+ form: "single",
49239
+ optional: false
49240
+ }],
48986
49241
  "faceGallery.getFaceByTrack": [{
48987
49242
  name: "deviceId",
48988
49243
  form: "single",
@@ -48997,6 +49252,11 @@ Object.freeze({
48997
49252
  form: "array",
48998
49253
  optional: true
48999
49254
  }],
49255
+ "fanControl.getStatus": [{
49256
+ name: "deviceId",
49257
+ form: "single",
49258
+ optional: false
49259
+ }],
49000
49260
  "fanControl.setDirection": [{
49001
49261
  name: "deviceId",
49002
49262
  form: "single",
@@ -49017,6 +49277,26 @@ Object.freeze({
49017
49277
  form: "single",
49018
49278
  optional: false
49019
49279
  }],
49280
+ "featureProbe.getStatus": [{
49281
+ name: "deviceId",
49282
+ form: "single",
49283
+ optional: false
49284
+ }],
49285
+ "flood.getStatus": [{
49286
+ name: "deviceId",
49287
+ form: "single",
49288
+ optional: false
49289
+ }],
49290
+ "gas.getStatus": [{
49291
+ name: "deviceId",
49292
+ form: "single",
49293
+ optional: false
49294
+ }],
49295
+ "humidifier.getStatus": [{
49296
+ name: "deviceId",
49297
+ form: "single",
49298
+ optional: false
49299
+ }],
49020
49300
  "humidifier.setMode": [{
49021
49301
  name: "deviceId",
49022
49302
  form: "single",
@@ -49032,11 +49312,26 @@ Object.freeze({
49032
49312
  form: "single",
49033
49313
  optional: false
49034
49314
  }],
49315
+ "humiditySensor.getStatus": [{
49316
+ name: "deviceId",
49317
+ form: "single",
49318
+ optional: false
49319
+ }],
49320
+ "image.getStatus": [{
49321
+ name: "deviceId",
49322
+ form: "single",
49323
+ optional: false
49324
+ }],
49035
49325
  "imageSettings.getOptions": [{
49036
49326
  name: "deviceId",
49037
49327
  form: "single",
49038
49328
  optional: false
49039
49329
  }],
49330
+ "imageSettings.getStatus": [{
49331
+ name: "deviceId",
49332
+ form: "single",
49333
+ optional: false
49334
+ }],
49040
49335
  "imageSettings.setSettings": [{
49041
49336
  name: "deviceId",
49042
49337
  form: "single",
@@ -49047,6 +49342,11 @@ Object.freeze({
49047
49342
  form: "single",
49048
49343
  optional: false
49049
49344
  }],
49345
+ "intercom.getStatus": [{
49346
+ name: "deviceId",
49347
+ form: "single",
49348
+ optional: false
49349
+ }],
49050
49350
  "intercom.handleAnswer": [{
49051
49351
  name: "deviceId",
49052
49352
  form: "single",
@@ -49077,6 +49377,11 @@ Object.freeze({
49077
49377
  form: "single",
49078
49378
  optional: false
49079
49379
  }],
49380
+ "lawnMowerControl.getStatus": [{
49381
+ name: "deviceId",
49382
+ form: "single",
49383
+ optional: false
49384
+ }],
49080
49385
  "lawnMowerControl.pause": [{
49081
49386
  name: "deviceId",
49082
49387
  form: "single",
@@ -49087,6 +49392,11 @@ Object.freeze({
49087
49392
  form: "single",
49088
49393
  optional: false
49089
49394
  }],
49395
+ "lockControl.getStatus": [{
49396
+ name: "deviceId",
49397
+ form: "single",
49398
+ optional: false
49399
+ }],
49090
49400
  "lockControl.lock": [{
49091
49401
  name: "deviceId",
49092
49402
  form: "single",
@@ -49102,6 +49412,11 @@ Object.freeze({
49102
49412
  form: "single",
49103
49413
  optional: false
49104
49414
  }],
49415
+ "mediaPlayer.getStatus": [{
49416
+ name: "deviceId",
49417
+ form: "single",
49418
+ optional: false
49419
+ }],
49105
49420
  "mediaPlayer.next": [{
49106
49421
  name: "deviceId",
49107
49422
  form: "single",
@@ -49162,6 +49477,11 @@ Object.freeze({
49162
49477
  form: "single",
49163
49478
  optional: false
49164
49479
  }],
49480
+ "motion.getStatus": [{
49481
+ name: "deviceId",
49482
+ form: "single",
49483
+ optional: false
49484
+ }],
49165
49485
  "motion.isDetected": [{
49166
49486
  name: "deviceId",
49167
49487
  form: "single",
@@ -49172,11 +49492,31 @@ Object.freeze({
49172
49492
  form: "single",
49173
49493
  optional: false
49174
49494
  }],
49495
+ "motionDetection.applyDeviceSettingsPatch": [{
49496
+ name: "deviceId",
49497
+ form: "single",
49498
+ optional: false
49499
+ }],
49500
+ "motionDetection.getDeviceLiveContribution": [{
49501
+ name: "deviceId",
49502
+ form: "single",
49503
+ optional: false
49504
+ }],
49505
+ "motionDetection.getDeviceSettingsContribution": [{
49506
+ name: "deviceId",
49507
+ form: "single",
49508
+ optional: false
49509
+ }],
49175
49510
  "motionDetection.removeCamera": [{
49176
49511
  name: "deviceId",
49177
49512
  form: "single",
49178
49513
  optional: false
49179
49514
  }],
49515
+ "motionTrigger.getStatus": [{
49516
+ name: "deviceId",
49517
+ form: "single",
49518
+ optional: false
49519
+ }],
49180
49520
  "motionTrigger.setMotionTrigger": [{
49181
49521
  name: "deviceId",
49182
49522
  form: "single",
@@ -49187,6 +49527,11 @@ Object.freeze({
49187
49527
  form: "single",
49188
49528
  optional: false
49189
49529
  }],
49530
+ "motionZones.getStatus": [{
49531
+ name: "deviceId",
49532
+ form: "single",
49533
+ optional: false
49534
+ }],
49190
49535
  "motionZones.setZone": [{
49191
49536
  name: "deviceId",
49192
49537
  form: "single",
@@ -49197,6 +49542,11 @@ Object.freeze({
49197
49542
  form: "single",
49198
49543
  optional: false
49199
49544
  }],
49545
+ "nativeObjectDetection.getStatus": [{
49546
+ name: "deviceId",
49547
+ form: "single",
49548
+ optional: false
49549
+ }],
49200
49550
  "nativeObjectDetection.setEnabled": [{
49201
49551
  name: "deviceId",
49202
49552
  form: "single",
@@ -49212,6 +49562,11 @@ Object.freeze({
49212
49562
  form: "single",
49213
49563
  optional: false
49214
49564
  }],
49565
+ "navigation.getStatus": [{
49566
+ name: "deviceId",
49567
+ form: "single",
49568
+ optional: false
49569
+ }],
49215
49570
  "navigation.goToPoint": [{
49216
49571
  name: "deviceId",
49217
49572
  form: "single",
@@ -49257,6 +49612,11 @@ Object.freeze({
49257
49612
  form: "single",
49258
49613
  optional: false
49259
49614
  }],
49615
+ "networkLink.getStatus": [{
49616
+ name: "deviceId",
49617
+ form: "single",
49618
+ optional: false
49619
+ }],
49260
49620
  "networkQuality.getDeviceStats": [{
49261
49621
  name: "deviceId",
49262
49622
  form: "single",
@@ -49267,6 +49627,11 @@ Object.freeze({
49267
49627
  form: "single",
49268
49628
  optional: false
49269
49629
  }],
49630
+ "notificationRules.getAlarmSensors": [{
49631
+ name: "deviceIds",
49632
+ form: "array",
49633
+ optional: false
49634
+ }],
49270
49635
  "notificationRules.setDeviceMuted": [{
49271
49636
  name: "deviceId",
49272
49637
  form: "single",
@@ -49277,11 +49642,26 @@ Object.freeze({
49277
49642
  form: "single",
49278
49643
  optional: false
49279
49644
  }],
49645
+ "notifier.getStatus": [{
49646
+ name: "deviceId",
49647
+ form: "single",
49648
+ optional: false
49649
+ }],
49280
49650
  "notifier.send": [{
49281
49651
  name: "deviceId",
49282
49652
  form: "single",
49283
49653
  optional: false
49284
49654
  }],
49655
+ "numericSensor.getStatus": [{
49656
+ name: "deviceId",
49657
+ form: "single",
49658
+ optional: false
49659
+ }],
49660
+ "osd.getStatus": [{
49661
+ name: "deviceId",
49662
+ form: "single",
49663
+ optional: false
49664
+ }],
49285
49665
  "osd.setOverlay": [{
49286
49666
  name: "deviceId",
49287
49667
  form: "single",
@@ -49341,6 +49721,11 @@ Object.freeze({
49341
49721
  form: "single",
49342
49722
  optional: false
49343
49723
  }],
49724
+ "petFeeder.getStatus": [{
49725
+ name: "deviceId",
49726
+ form: "single",
49727
+ optional: false
49728
+ }],
49344
49729
  "petFeeder.markFoodReplenished": [{
49345
49730
  name: "deviceId",
49346
49731
  form: "single",
@@ -49376,6 +49761,11 @@ Object.freeze({
49376
49761
  form: "single",
49377
49762
  optional: false
49378
49763
  }],
49764
+ "pipelineAnalytics.applyDeviceSettingsPatch": [{
49765
+ name: "deviceId",
49766
+ form: "single",
49767
+ optional: false
49768
+ }],
49379
49769
  "pipelineAnalytics.clearTrackRelation": [{
49380
49770
  name: "deviceId",
49381
49771
  form: "single",
@@ -49416,6 +49806,16 @@ Object.freeze({
49416
49806
  form: "single",
49417
49807
  optional: false
49418
49808
  }],
49809
+ "pipelineAnalytics.getDeviceLiveContribution": [{
49810
+ name: "deviceId",
49811
+ form: "single",
49812
+ optional: false
49813
+ }],
49814
+ "pipelineAnalytics.getDeviceSettingsContribution": [{
49815
+ name: "deviceId",
49816
+ form: "single",
49817
+ optional: false
49818
+ }],
49419
49819
  "pipelineAnalytics.getEventDensity": [{
49420
49820
  name: "deviceId",
49421
49821
  form: "single",
@@ -49631,6 +50031,11 @@ Object.freeze({
49631
50031
  form: "single",
49632
50032
  optional: true
49633
50033
  }],
50034
+ "pipelineOrchestrator.applyDeviceSettingsPatch": [{
50035
+ name: "deviceId",
50036
+ form: "single",
50037
+ optional: false
50038
+ }],
49634
50039
  "pipelineOrchestrator.assignAudio": [{
49635
50040
  name: "deviceId",
49636
50041
  form: "single",
@@ -49676,6 +50081,16 @@ Object.freeze({
49676
50081
  form: "single",
49677
50082
  optional: false
49678
50083
  }],
50084
+ "pipelineOrchestrator.getDeviceLiveContribution": [{
50085
+ name: "deviceId",
50086
+ form: "single",
50087
+ optional: false
50088
+ }],
50089
+ "pipelineOrchestrator.getDeviceSettingsContribution": [{
50090
+ name: "deviceId",
50091
+ form: "single",
50092
+ optional: false
50093
+ }],
49679
50094
  "pipelineOrchestrator.getPipelineAssignment": [{
49680
50095
  name: "deviceId",
49681
50096
  form: "single",
@@ -49796,11 +50211,31 @@ Object.freeze({
49796
50211
  form: "single",
49797
50212
  optional: true
49798
50213
  }],
50214
+ "powerMeter.getStatus": [{
50215
+ name: "deviceId",
50216
+ form: "single",
50217
+ optional: false
50218
+ }],
50219
+ "presence.getStatus": [{
50220
+ name: "deviceId",
50221
+ form: "single",
50222
+ optional: false
50223
+ }],
50224
+ "pressureSensor.getStatus": [{
50225
+ name: "deviceId",
50226
+ form: "single",
50227
+ optional: false
50228
+ }],
49799
50229
  "privacyMask.getOptions": [{
49800
50230
  name: "deviceId",
49801
50231
  form: "single",
49802
50232
  optional: false
49803
50233
  }],
50234
+ "privacyMask.getStatus": [{
50235
+ name: "deviceId",
50236
+ form: "single",
50237
+ optional: false
50238
+ }],
49804
50239
  "privacyMask.setAudioEnabled": [{
49805
50240
  name: "deviceId",
49806
50241
  form: "single",
@@ -49851,6 +50286,11 @@ Object.freeze({
49851
50286
  form: "single",
49852
50287
  optional: false
49853
50288
  }],
50289
+ "ptz.getStatus": [{
50290
+ name: "deviceId",
50291
+ form: "single",
50292
+ optional: false
50293
+ }],
49854
50294
  "ptz.goHome": [{
49855
50295
  name: "deviceId",
49856
50296
  form: "single",
@@ -49941,6 +50381,11 @@ Object.freeze({
49941
50381
  form: "single",
49942
50382
  optional: false
49943
50383
  }],
50384
+ "recordingArchive.applyDeviceSettingsPatch": [{
50385
+ name: "deviceId",
50386
+ form: "single",
50387
+ optional: false
50388
+ }],
49944
50389
  "recordingArchive.deleteFootprint": [{
49945
50390
  name: "deviceId",
49946
50391
  form: "single",
@@ -49961,6 +50406,21 @@ Object.freeze({
49961
50406
  form: "single",
49962
50407
  optional: false
49963
50408
  }],
50409
+ "recordingArchive.getDeviceLiveContribution": [{
50410
+ name: "deviceId",
50411
+ form: "single",
50412
+ optional: false
50413
+ }],
50414
+ "recordingArchive.getDeviceSettingsContribution": [{
50415
+ name: "deviceId",
50416
+ form: "single",
50417
+ optional: false
50418
+ }],
50419
+ "recordingArchive.getStatus": [{
50420
+ name: "deviceId",
50421
+ form: "single",
50422
+ optional: false
50423
+ }],
49964
50424
  "recordingArchive.listOpsLog": [{
49965
50425
  name: "deviceId",
49966
50426
  form: "single",
@@ -50046,6 +50506,11 @@ Object.freeze({
50046
50506
  form: "single",
50047
50507
  optional: false
50048
50508
  }],
50509
+ "recordingOnboard.getStatus": [{
50510
+ name: "deviceId",
50511
+ form: "single",
50512
+ optional: false
50513
+ }],
50049
50514
  "recordingOnboard.setSettings": [{
50050
50515
  name: "deviceId",
50051
50516
  form: "single",
@@ -50076,6 +50541,11 @@ Object.freeze({
50076
50541
  form: "single",
50077
50542
  optional: false
50078
50543
  }],
50544
+ "sceneMonitor.getStatus": [{
50545
+ name: "deviceId",
50546
+ form: "single",
50547
+ optional: false
50548
+ }],
50079
50549
  "sceneMonitor.listScenes": [{
50080
50550
  name: "deviceId",
50081
50551
  form: "single",
@@ -50101,6 +50571,11 @@ Object.freeze({
50101
50571
  form: "single",
50102
50572
  optional: false
50103
50573
  }],
50574
+ "scriptRunner.getStatus": [{
50575
+ name: "deviceId",
50576
+ form: "single",
50577
+ optional: false
50578
+ }],
50104
50579
  "scriptRunner.run": [{
50105
50580
  name: "deviceId",
50106
50581
  form: "single",
@@ -50111,11 +50586,31 @@ Object.freeze({
50111
50586
  form: "single",
50112
50587
  optional: false
50113
50588
  }],
50589
+ "smoke.getStatus": [{
50590
+ name: "deviceId",
50591
+ form: "single",
50592
+ optional: false
50593
+ }],
50594
+ "snapshot.applyDeviceSettingsPatch": [{
50595
+ name: "deviceId",
50596
+ form: "single",
50597
+ optional: false
50598
+ }],
50114
50599
  "snapshot.getDebugState": [{
50115
50600
  name: "deviceId",
50116
50601
  form: "single",
50117
50602
  optional: false
50118
50603
  }],
50604
+ "snapshot.getDeviceLiveContribution": [{
50605
+ name: "deviceId",
50606
+ form: "single",
50607
+ optional: false
50608
+ }],
50609
+ "snapshot.getDeviceSettingsContribution": [{
50610
+ name: "deviceId",
50611
+ form: "single",
50612
+ optional: false
50613
+ }],
50119
50614
  "snapshot.getSnapshot": [{
50120
50615
  name: "deviceId",
50121
50616
  form: "single",
@@ -50132,6 +50627,11 @@ Object.freeze({
50132
50627
  form: "array",
50133
50628
  optional: false
50134
50629
  }],
50630
+ "snapshot.getStatus": [{
50631
+ name: "deviceId",
50632
+ form: "single",
50633
+ optional: false
50634
+ }],
50135
50635
  "snapshot.invalidateCache": [{
50136
50636
  name: "deviceId",
50137
50637
  form: "single",
@@ -50142,6 +50642,11 @@ Object.freeze({
50142
50642
  form: "single",
50143
50643
  optional: false
50144
50644
  }],
50645
+ "streamBroker.applyDeviceSettingsPatch": [{
50646
+ name: "deviceId",
50647
+ form: "single",
50648
+ optional: false
50649
+ }],
50145
50650
  "streamBroker.assignProfile": [{
50146
50651
  name: "deviceId",
50147
50652
  form: "single",
@@ -50157,6 +50662,16 @@ Object.freeze({
50157
50662
  form: "single",
50158
50663
  optional: false
50159
50664
  }],
50665
+ "streamBroker.getDeviceLiveContribution": [{
50666
+ name: "deviceId",
50667
+ form: "single",
50668
+ optional: false
50669
+ }],
50670
+ "streamBroker.getDeviceSettingsContribution": [{
50671
+ name: "deviceId",
50672
+ form: "single",
50673
+ optional: false
50674
+ }],
50160
50675
  "streamBroker.getStreamWithCodec": [{
50161
50676
  name: "deviceId",
50162
50677
  form: "single",
@@ -50217,16 +50732,46 @@ Object.freeze({
50217
50732
  form: "single",
50218
50733
  optional: false
50219
50734
  }],
50735
+ "streamParams.getStatus": [{
50736
+ name: "deviceId",
50737
+ form: "single",
50738
+ optional: false
50739
+ }],
50220
50740
  "streamParams.setProfile": [{
50221
50741
  name: "deviceId",
50222
50742
  form: "single",
50223
50743
  optional: false
50224
50744
  }],
50745
+ "switch.getStatus": [{
50746
+ name: "deviceId",
50747
+ form: "single",
50748
+ optional: false
50749
+ }],
50225
50750
  "switch.setState": [{
50226
50751
  name: "deviceId",
50227
50752
  form: "single",
50228
50753
  optional: false
50229
50754
  }],
50755
+ "tamper.getStatus": [{
50756
+ name: "deviceId",
50757
+ form: "single",
50758
+ optional: false
50759
+ }],
50760
+ "temperatureSensor.getStatus": [{
50761
+ name: "deviceId",
50762
+ form: "single",
50763
+ optional: false
50764
+ }],
50765
+ "update.getStatus": [{
50766
+ name: "deviceId",
50767
+ form: "single",
50768
+ optional: false
50769
+ }],
50770
+ "vacuumControl.getStatus": [{
50771
+ name: "deviceId",
50772
+ form: "single",
50773
+ optional: false
50774
+ }],
50230
50775
  "vacuumControl.locate": [{
50231
50776
  name: "deviceId",
50232
50777
  form: "single",
@@ -50262,6 +50807,11 @@ Object.freeze({
50262
50807
  form: "single",
50263
50808
  optional: false
50264
50809
  }],
50810
+ "valve.getStatus": [{
50811
+ name: "deviceId",
50812
+ form: "single",
50813
+ optional: false
50814
+ }],
50265
50815
  "valve.open": [{
50266
50816
  name: "deviceId",
50267
50817
  form: "single",
@@ -50277,6 +50827,11 @@ Object.freeze({
50277
50827
  form: "single",
50278
50828
  optional: false
50279
50829
  }],
50830
+ "vibration.getStatus": [{
50831
+ name: "deviceId",
50832
+ form: "single",
50833
+ optional: false
50834
+ }],
50280
50835
  "videoclips.dialClipStream": [{
50281
50836
  name: "deviceId",
50282
50837
  form: "single",
@@ -50312,6 +50867,11 @@ Object.freeze({
50312
50867
  form: "single",
50313
50868
  optional: false
50314
50869
  }],
50870
+ "waterHeater.getStatus": [{
50871
+ name: "deviceId",
50872
+ form: "single",
50873
+ optional: false
50874
+ }],
50315
50875
  "waterHeater.setAway": [{
50316
50876
  name: "deviceId",
50317
50877
  form: "single",
@@ -50327,6 +50887,11 @@ Object.freeze({
50327
50887
  form: "single",
50328
50888
  optional: false
50329
50889
  }],
50890
+ "weather.getStatus": [{
50891
+ name: "deviceId",
50892
+ form: "single",
50893
+ optional: false
50894
+ }],
50330
50895
  "webrtcSession.addIceCandidate": [{
50331
50896
  name: "deviceId",
50332
50897
  form: "single",
@@ -51064,7 +51629,7 @@ var PreviewTextField = string().max(200);
51064
51629
  * Whether the notification's preview is a STILL or a short animation.
51065
51630
  *
51066
51631
  * The operator's ask, verbatim: *"inviato come gif o video (come per le altre
51067
- * rule)"* — the other rules already offer an animated preview, and a ten-hour
51632
+ * rule)"* [sent as a gif or video (as for the other rules)] — the other rules already offer an animated preview, and a ten-hour
51068
51633
  * night reads better as three seconds of motion than as one frame of it. Both
51069
51634
  * modes get the SAME treatment (blurred frame, large centred title); `'gif'`
51070
51635
  * simply applies it to a dozen frames sampled across the render and assembles
@@ -51202,6 +51767,7 @@ TimelapseRuleInputSchema.extend({
51202
51767
  createdAt: number(),
51203
51768
  updatedAt: number()
51204
51769
  });
51770
+ MotionOnMotionChangedDataSchema.omit({ triggeredBy: true });
51205
51771
  object({
51206
51772
  /**
51207
51773
  * Fraction of the box's own size added on EACH side before cutting.