@camstack/addon-admin-ui 1.2.298 → 1.2.300

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 (96) hide show
  1. package/dist/assets/{AddonCollectionPage-Df7TFa8c.js → AddonCollectionPage-Cr-KfwvP.js} +1 -1
  2. package/dist/assets/{Addons-BL0l83HX.js → Addons-DoAs_KfP.js} +1 -1
  3. package/dist/assets/{AdminTabs-_3rYGvff.js → AdminTabs-nO86C-du.js} +1 -1
  4. package/dist/assets/{AiProfiles-Cb_Zmt2e.js → AiProfiles-DZuK8h7D.js} +1 -1
  5. package/dist/assets/{BrokerForm-O4qx5NOl.js → BrokerForm-MOPaJ62m.js} +1 -1
  6. package/dist/assets/Build-fVZjJtBq.js +32 -0
  7. package/dist/assets/{Capabilities-BhWA9I3U.js → Capabilities-5vhoPQFd.js} +1 -1
  8. package/dist/assets/{CapabilityBadges-E822NR6-.js → CapabilityBadges-CJnsp_LH.js} +1 -1
  9. package/dist/assets/{Cluster-CytT6oOR.js → Cluster-BsbJ3J5p.js} +2 -2
  10. package/dist/assets/CompositionEditor-DbDCjW1s.js +1 -0
  11. package/dist/assets/{CompositionEditorPage-D-Pr98e9.js → CompositionEditorPage-BfvnF5_n.js} +1 -1
  12. package/dist/assets/{Data-C_5nuknP.js → Data-DqV6ClEA.js} +1 -1
  13. package/dist/assets/{DetectionIntelligence-Ddu_ubPT.js → DetectionIntelligence-XPzIfD-8.js} +1 -1
  14. package/dist/assets/{DeviceAggregateSection-kHgMnzdV.js → DeviceAggregateSection-CG9OIoVb.js} +1 -1
  15. package/dist/assets/DeviceDetail-BfbO3V0b.js +2 -0
  16. package/dist/assets/{Devices-CkDDnlUY.js → Devices-Dq_iXMXN.js} +1 -1
  17. package/dist/assets/{EmbedPlayerPage-4bKTeu-8.js → EmbedPlayerPage-CY5PDgte.js} +1 -1
  18. package/dist/assets/Events-BeWVGaev.js +1 -0
  19. package/dist/assets/{FormBuilder-DFkvqrJD.js → FormBuilder-B8jus43Y.js} +1 -1
  20. package/dist/assets/{Identity-Bs0HMUZv.js → Identity-DaJyz-ig.js} +1 -1
  21. package/dist/assets/IntegrationDetail-mee6rfl4.js +1 -0
  22. package/dist/assets/Integrations-DTrUecHI.js +1 -0
  23. package/dist/assets/{Integrations-D5LYSgWQ.js → Integrations-e_CGcE53.js} +1 -1
  24. package/dist/assets/Locations-naeoUiMl.js +3 -0
  25. package/dist/assets/{Logs-CdSMPoxV.js → Logs-DHvS0ZG4.js} +1 -1
  26. package/dist/assets/{ModelLicenses-GuvIn1gk.js → ModelLicenses-CHF6ETO5.js} +1 -1
  27. package/dist/assets/{MotionZonesSettings-C5cymw6R.js → MotionZonesSettings-DveHRZ1M.js} +1 -1
  28. package/dist/assets/{MyAccess-DKvcVvYi.js → MyAccess-ZmbQ_xfb.js} +1 -1
  29. package/dist/assets/{Network-DO7j65It.js → Network-C4frL_HE.js} +1 -1
  30. package/dist/assets/{NodeAddonsSettingsPanel-Bj_BK8BK.js → NodeAddonsSettingsPanel-11F3P0IK.js} +1 -1
  31. package/dist/assets/{NodeInferenceDevices-DEF7iUIy.js → NodeInferenceDevices-B7lbdDTW.js} +1 -1
  32. package/dist/assets/Notifications-DRLYWjDS.js +1 -0
  33. package/dist/assets/{Pipeline-C3rd2o0z.js → Pipeline-qSnWQmZ4.js} +1 -1
  34. package/dist/assets/{Plates-KK9Jucpy.js → Plates-B0u-1Qcz.js} +1 -1
  35. package/dist/assets/{PrivacyMaskSettings-DLWoWKa1.js → PrivacyMaskSettings-CWYULq-y.js} +1 -1
  36. package/dist/assets/{ProviderIcon-B95H0OGs.js → ProviderIcon-DAp_lMDw.js} +1 -1
  37. package/dist/assets/{Recordings-BIMt47G_.js → Recordings-fNBcOSUc.js} +1 -1
  38. package/dist/assets/{ScanNetworkModal-C745HgYN.js → ScanNetworkModal-xnOiLGgg.js} +1 -1
  39. package/dist/assets/{SceneMonitorEditor-DEFeKrQi.js → SceneMonitorEditor-gDpt6iKo.js} +1 -1
  40. package/dist/assets/{Scenes-31t1OF8h.js → Scenes-DDAmEqU9.js} +1 -1
  41. package/dist/assets/{Settings-rfP-ZvI0.js → Settings-Dv_5fVj2.js} +1 -1
  42. package/dist/assets/{Showroom-Df8NV8QK.js → Showroom-B7D-nKLt.js} +1 -1
  43. package/dist/assets/{StorageLocationsPanel-DGsk0Ute.js → StorageLocationsPanel-BZ5j8c1h.js} +1 -1
  44. package/dist/assets/{Terminal-CDJOGeqz.js → Terminal-DR0RmRD6.js} +1 -1
  45. package/dist/assets/{Viewer-BjRST1rI.js → Viewer-Cg7A1w4F.js} +1 -1
  46. package/dist/assets/{_virtual_mf-localSharedImportMap___mfe_internal__admin_ui_host-C4tT4btJ.js → _virtual_mf-localSharedImportMap___mfe_internal__admin_ui_host-TK7cnRbq.js} +1 -1
  47. package/dist/assets/{archive-TrxiLNcl.js → archive-CCEAH2-E.js} +1 -1
  48. package/dist/assets/{authed-media-CH1U0Z7I.js → authed-media-ClZ80rNx.js} +1 -1
  49. package/dist/assets/{boxes-BAiYOams.js → boxes-BdtZgTjz.js} +1 -1
  50. package/dist/assets/circle-slash-CgvI8iSv.js +1 -0
  51. package/dist/assets/{debounced-invalidate-BDeU9yPQ.js → debounced-invalidate-C2eb-Tqo.js} +1 -1
  52. package/dist/assets/{device-integration-icon-CHkYoY0a.js → device-integration-icon-Ck2Y2lL5.js} +1 -1
  53. package/dist/assets/device-picker-model-qVKFWw6-.js +1 -0
  54. package/dist/assets/dist-BXj5mC45.js +349 -0
  55. package/dist/assets/{dist-a0ex8Xy3.js → dist-Cjkv3uUk.js} +1 -1
  56. package/dist/assets/{face-bbox-BO4f9HS4.js → face-bbox-Co5b1ky_.js} +1 -1
  57. package/dist/assets/{hard-drive-download-DMTgloj5.js → hard-drive-download-ep0y7LyP.js} +1 -1
  58. package/dist/assets/{hostInit-DImvGASf.js → hostInit-BoAo3PhF.js} +1 -1
  59. package/dist/assets/{index-CgXPc-AV.js → index-C_wdx2NZ.js} +3 -3
  60. package/dist/assets/index-egLHRpbu.css +2 -0
  61. package/dist/assets/{layers-eROspUmA.js → layers-BU-FWaJU.js} +1 -1
  62. package/dist/assets/{location-owned-usage-sOE3xLhc.js → location-owned-usage-C3ej6Pj6.js} +1 -1
  63. package/dist/assets/{mf-entry-bootstrap-0-84890b2e.js → mf-entry-bootstrap-0-50975fe6.js} +2 -2
  64. package/dist/assets/{player-overlays-o54P23P2.js → player-overlays-CjhGPGRH.js} +1 -1
  65. package/dist/assets/remoteEntry-C2_I-Of1.js +1 -0
  66. package/dist/assets/{send-D0d5eZ61.js → send-CEk5WYNt.js} +1 -1
  67. package/dist/assets/{settings-2-Dqj-Whfr.js → settings-2-MB6Thalh.js} +1 -1
  68. package/dist/assets/{square-check-big-CC2dU6RF.js → square-check-big-ZL-AwzeA.js} +1 -1
  69. package/dist/assets/src-BiDz1hgC.js +67 -0
  70. package/dist/assets/src-bXB9J58r.js +349 -0
  71. package/dist/assets/{use-scenes-feed-R-GEBDBU.js → use-scenes-feed-CwP86V7k.js} +1 -1
  72. package/dist/assets/{use-stationary-objects-CO4PdIFG.js → use-stationary-objects-eBMDdhXW.js} +1 -1
  73. package/dist/assets/{useDevice-BU0imY9B.js → useDevice-CGj-WKTC.js} +1 -1
  74. package/dist/assets/useEventInvalidation-BaNmc7Ke.js +1 -0
  75. package/dist/assets/{useNodeUrlSelection-Dlf0CWPU.js → useNodeUrlSelection-DMCMMjaf.js} +1 -1
  76. package/dist/assets/user-round-CqtnExEW.js +1 -0
  77. package/dist/assets/{virtual_mf-REMOTE_ENTRY_ID___mfe_internal__admin_ui_host__remoteEntry-_hash_-DAaE-Myc.js → virtual_mf-REMOTE_ENTRY_ID___mfe_internal__admin_ui_host__remoteEntry-_hash_-Dt6rtuC7.js} +2 -2
  78. package/dist/index.html +6 -6
  79. package/dist/server/addon.js +235 -102
  80. package/package.json +1 -1
  81. package/dist/assets/Build-CNQhG6ma.js +0 -32
  82. package/dist/assets/CompositionEditor-BhWVT7RV.js +0 -1
  83. package/dist/assets/DeviceDetail-BZJKkllF.js +0 -2
  84. package/dist/assets/Events-DoN_tLnP.js +0 -1
  85. package/dist/assets/IntegrationDetail-Cr5-tJiw.js +0 -1
  86. package/dist/assets/Integrations-D5hX1u4b.js +0 -1
  87. package/dist/assets/Locations-NysPu2nw.js +0 -3
  88. package/dist/assets/Notifications-R4TlE5EH.js +0 -1
  89. package/dist/assets/circle-slash-Di12V3ul.js +0 -1
  90. package/dist/assets/dist-3HV5hQQl.js +0 -349
  91. package/dist/assets/index-DOZUgTMC.css +0 -2
  92. package/dist/assets/remoteEntry-nDKnWQvr.js +0 -1
  93. package/dist/assets/src-C36-vO5A.js +0 -349
  94. package/dist/assets/src-f3OJiuN1.js +0 -67
  95. package/dist/assets/useEventInvalidation-BxCnrh5u.js +0 -1
  96. package/dist/assets/user-round-CXdkrmGZ.js +0 -1
@@ -1,6 +1,6 @@
1
1
  import path from "node:path";
2
2
  import { fileURLToPath } from "node:url";
3
- //#region ../types/dist/event-category-C5xZWqz6.mjs
3
+ //#region ../types/dist/event-category-BGmz_oxW.mjs
4
4
  var EventCategory = /* @__PURE__ */ function(EventCategory) {
5
5
  EventCategory["SystemBoot"] = "system.boot";
6
6
  EventCategory["SystemAddonsReady"] = "system.addons-ready";
@@ -533,6 +533,15 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
533
533
  */
534
534
  EventCategory["PipelineAudioInferenceResult"] = "pipeline.audio-inference-result";
535
535
  EventCategory["DetectionPhaseTransition"] = "detection.phase-transition";
536
+ /**
537
+ * A camera provider's RAW onboard motion push (D673): the `MotionOnMotionChanged`
538
+ * data shape without `triggeredBy`, built by `providerMotionEvent`. Its one
539
+ * consumer is the orchestrator's camera-sensors bridge, which re-emits the
540
+ * camera's EFFECTIVE onboard motion as `MotionOnMotionChanged` (a pass-through
541
+ * for a camera with no attached sensor). Providers must not emit
542
+ * `MotionOnMotionChanged` themselves; `scripts/check-onboard-motion-emitters.ts`
543
+ * keeps it so (camera-grid is a named, deferred exception).
544
+ */
536
545
  EventCategory["ProviderMotion"] = "provider.motion";
537
546
  EventCategory["ProviderDetection"] = "provider.detection";
538
547
  EventCategory["EnrichmentEmbeddingStored"] = "enrichment.embedding.stored";
@@ -5371,7 +5380,7 @@ var ZodIssueCode = {
5371
5380
  var ZodFirstPartyTypeKind;
5372
5381
  ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
5373
5382
  //#endregion
5374
- //#region ../types/dist/sleep-gU6hqv4_.mjs
5383
+ //#region ../types/dist/sleep-CDCONfkt.mjs
5375
5384
  /**
5376
5385
  * The audio chunk plane's byte format, and the ONE expansion from a coded
5377
5386
  * window to float samples (D455).
@@ -7418,7 +7427,7 @@ var DeviceRole = /* @__PURE__ */ function(DeviceRole) {
7418
7427
  return DeviceRole;
7419
7428
  }({});
7420
7429
  //#endregion
7421
- //#region ../types/dist/composition-Dq42XWp0.mjs
7430
+ //#region ../types/dist/composition-43aqsZQj.mjs
7422
7431
  /**
7423
7432
  * The ffmpeg build every CamStack node downloads, per platform and arch.
7424
7433
  *
@@ -7475,13 +7484,12 @@ portable("linux64"), portable("linuxarm64"), portable("macarm64"), portable("mac
7475
7484
  * LA tabella "quale booleano di questo tipo di device conta come ALTO", e il
7476
7485
  * valutatore puro del suo FRONTE.
7477
7486
  *
7478
- * Viveva dentro il builtin virtual-doorbell
7479
- * (`@camstack/system` — `builtins/doorbell/trigger-engine.ts`) e i suoi
7480
- * predicati erano privati al modulo. Il recorder ne ha bisogno per il trigger
7481
- * `RecordingTriggers.sensorDeviceIds`: copiarla avrebbe creato la SECONDA
7482
- * tabella, che diverge alla prima cap aggiunta e il cui sintomo — "il sensore
7483
- * fa suonare il campanello ma non registra" — è esattamente D62. Quindi si
7484
- * SPOSTA qui e il doorbell la ri-esporta.
7487
+ * UNA tabella per tutti quelli che chiedono "questo device è ALTO?": il
7488
+ * trigger `RecordingTriggers.sensorDeviceIds` del recorder, i marker dei
7489
+ * sensori della post-analysis, il bridge camera-sensors dell'orchestratore e
7490
+ * le sorgenti di un campanello composto (`doorbellFeatureSources`, D671).
7491
+ * Una seconda copia divergerebbe alla prima cap aggiunta, e il sintomo — "il
7492
+ * sensore fa suonare il campanello ma non registra" — è esattamente D62.
7485
7493
  *
7486
7494
  * ⚠ NON è `DEVICE_STATE_READERS` (`catalogs/device-state-vocabulary.ts`), e le
7487
7495
  * due non vanno unificate: quella risponde a "qual è la PAROLA di stato per una
@@ -9216,7 +9224,7 @@ var RecordingTriggersSchema = object({
9216
9224
  *
9217
9225
  * Cosa vuol dire "alto" dipende dal TIPO di device e non è deciso qui:
9218
9226
  * `SOURCE_CAP_ACTIVE_FIELD` (`catalogs/sensor-active-state.ts`) è LA tabella,
9219
- * la stessa che il virtual-doorbell usa dal 2026-08-05. Ed è il FRONTE, non
9227
+ * la stessa del campanello composto (D671). Ed è il FRONTE, non
9220
9228
  * il livello: un contatto trovato già aperto al riavvio del runner non fa
9221
9229
  * registrare.
9222
9230
  */
@@ -15302,28 +15310,10 @@ method(object({
15302
15310
  deviceIds: array(number()).readonly(),
15303
15311
  caps: array(string()).readonly().optional()
15304
15312
  }), record(string(), record(string(), unknown().nullable())));
15305
- object({
15306
- /** Ms epoch of the last press. null = never observed since this provider started. */
15307
- lastPressedAt: number().nullable(),
15308
- /** Counter since provider start. Resets on reboot. Useful for metrics/debug. */
15309
- pressCountSinceStart: number()
15310
- });
15311
- object({
15312
- deviceId: number(),
15313
- timestamp: number()
15314
- });
15315
- /**
15316
- * The `doorbell-source` extension slot's editable value (D648): the camera's
15317
- * virtual-doorbell trigger devices, exactly what the wrapper's
15318
- * `doorbellSources` persists (as `{ deviceId }` records).
15319
- */
15320
- var DoorbellSourceSlotValueSchema = object({ deviceIds: array(number().int().positive()) });
15313
+ var ExtensionSlotIdSchema = _enum(["linked-devices"]);
15321
15314
  DeviceType.Camera;
15322
- DeviceType.Button, DeviceType.Camera;
15323
- var ExtensionSlotIdSchema = _enum(["doorbell-source", "linked-devices"]);
15324
- DeviceType.Camera, DeviceType.Camera;
15325
15315
  /** A slot's editable value, discriminated on `slot`. */
15326
- var ExtensionSlotValueSchema = discriminatedUnion("slot", [DoorbellSourceSlotValueSchema.extend({ slot: literal("doorbell-source") }), LinkedDevicesSlotValueSchema.extend({ slot: literal("linked-devices") })]);
15316
+ var ExtensionSlotValueSchema = discriminatedUnion("slot", [LinkedDevicesSlotValueSchema.extend({ slot: literal("linked-devices") })]);
15327
15317
  DeviceType.Camera;
15328
15318
  var ExtensionSourceAvailabilitySchema = discriminatedUnion("state", [object({ state: literal("ok") }), object({
15329
15319
  state: literal("unreachable"),
@@ -15360,10 +15350,11 @@ var ExtensionSlotSourceSchema = object({
15360
15350
  });
15361
15351
  /**
15362
15352
  * A DIFFERENT authority that gates whether the slot's sources do anything —
15363
- * reported read-only, named, never written through this contract (D62). The
15364
- * virtual doorbell's sources ring only while the wrapper is bound to the
15365
- * camera, and that binding belongs to `deviceManager.setWrapperActive`.
15366
- * `unknown` means the gate could not be read; it is not "inactive" (D315).
15353
+ * reported read-only, named, never written through this contract (D62) — e.g.
15354
+ * a slot whose sources act only while a wrapper is bound to the host, a
15355
+ * binding that belongs to `deviceManager.setWrapperActive`. No slot reports
15356
+ * one today (`linked-devices` answers `null`). `unknown` means the gate could
15357
+ * not be read; it is not "inactive" (D315).
15367
15358
  */
15368
15359
  var ExtensionSlotActivationSchema = object({
15369
15360
  state: _enum([
@@ -15379,7 +15370,7 @@ var ExtensionSlotRowSchema = discriminatedUnion("state", [object({
15379
15370
  /** `<source>:<slotId>` — the routing key for `listCandidates` / `setSlot`. */
15380
15371
  slotRef: string(),
15381
15372
  slot: ExtensionSlotIdSchema,
15382
- /** Names the store written (D62), e.g. `virtual-doorbell:doorbellSources`. */
15373
+ /** Names the store written (D62), e.g. `device-manager:_linkedDeviceIds`. */
15383
15374
  authority: string(),
15384
15375
  activation: ExtensionSlotActivationSchema.nullable(),
15385
15376
  value: ExtensionSlotValueSchema,
@@ -19864,6 +19855,29 @@ object({
19864
19855
  firstAt: number(),
19865
19856
  lastAt: number()
19866
19857
  });
19858
+ var NC_ALARM_TRIGGERED_MAX_SEC = 3600;
19859
+ var NcAlarmDelaySecSchema = number().int().min(0).max(600);
19860
+ var NcAlarmTriggeredSecSchema = number().int().min(0).max(NC_ALARM_TRIGGERED_MAX_SEC);
19861
+ var uniqueModes = (entries) => new Set(entries.map((e) => e.mode)).size === entries.length;
19862
+ var NcAlarmModeDelaysListSchema = array(object({
19863
+ mode: AlarmArmModeSchema,
19864
+ exitDelaySec: NcAlarmDelaySecSchema.optional(),
19865
+ entryDelaySec: NcAlarmDelaySecSchema.optional(),
19866
+ triggeredDurationSec: NcAlarmTriggeredSecSchema.optional()
19867
+ })).max(8).refine(uniqueModes, { message: "modeDelays: at most one entry per arm mode" });
19868
+ var NcAlarmModeDelaysEditListSchema = array(object({
19869
+ mode: AlarmArmModeSchema,
19870
+ exitDelaySec: NcAlarmDelaySecSchema.nullable().optional(),
19871
+ entryDelaySec: NcAlarmDelaySecSchema.nullable().optional(),
19872
+ triggeredDurationSec: NcAlarmTriggeredSecSchema.nullable().optional()
19873
+ })).max(8).refine(uniqueModes, { message: "modeDelays: at most one edit per arm mode" });
19874
+ /** One switch of the alarm table: put ONE device on, or take it off, ONE mode's list. */
19875
+ var NcAlarmNonBlockingEditSchema = object({
19876
+ mode: AlarmArmModeSchema,
19877
+ deviceId: number().int().positive(),
19878
+ /** true = on the list (may be open, does not block); false = off the list (blocks). */
19879
+ nonBlocking: boolean()
19880
+ });
19867
19881
  /**
19868
19882
  * The per-mode lists, at most one per mode. Two lists for one mode have no
19869
19883
  * meaning a reader could agree on (union? the last one?), so they are refused
@@ -19872,10 +19886,10 @@ object({
19872
19886
  var NcAlarmNonBlockingListSchema = array(object({
19873
19887
  mode: AlarmArmModeSchema,
19874
19888
  deviceIds: array(number().int()).max(200)
19875
- })).max(8).refine((lists) => new Set(lists.map((l) => l.mode)).size === lists.length, { message: "nonBlocking: at most one list per arm mode" });
19889
+ })).max(8).refine(uniqueModes, { message: "nonBlocking: at most one list per arm mode" });
19876
19890
  /**
19877
- * The three durations the panel's state machine runs on, who hears about its
19878
- * transitions, and which openings each mode tolerates.
19891
+ * The three durations — global, and per mode since D697 — the panel's state
19892
+ * machine runs on, who hears about its transitions, and which openings each mode tolerates.
19879
19893
  *
19880
19894
  * They live on the NOTIFICATION-RULES cap, not on `alarm-panel`, on purpose:
19881
19895
  * `alarm-panel` is `deviceNative` and its other provider mirrors somebody
@@ -19885,15 +19899,15 @@ var NcAlarmNonBlockingListSchema = array(object({
19885
19899
  */
19886
19900
  var NcAlarmSettingsSchema = object({
19887
19901
  /** Grace period between arming and the mode taking effect. 0 = immediate. */
19888
- exitDelaySec: number().int().min(0).max(600),
19902
+ exitDelaySec: NcAlarmDelaySecSchema,
19889
19903
  /** Grace period between a trigger and the alarm firing. 0 = immediate. */
19890
- entryDelaySec: number().int().min(0).max(600),
19904
+ entryDelaySec: NcAlarmDelaySecSchema,
19891
19905
  /**
19892
19906
  * How long `triggered` lasts before the panel re-arms itself.
19893
19907
  * **0 = until an operator disarms it** — the behaviour before this field
19894
19908
  * existed, and therefore what an untouched install keeps doing.
19895
19909
  */
19896
- triggeredDurationSec: number().int().min(0).max(3600),
19910
+ triggeredDurationSec: NcAlarmTriggeredSecSchema,
19897
19911
  /**
19898
19912
  * Deprecated by D630 — every transition is announced. Parsed, never read;
19899
19913
  * remove after one release. Optional so an older admin's patch (which still
@@ -19916,17 +19930,30 @@ var NcAlarmSettingsSchema = object({
19916
19930
  * per mode is meaningful. Defaulted to `[]` so a blob stored before D630
19917
19931
  * parses as "every opening blocks" — the behaviour it was written under.
19918
19932
  */
19919
- nonBlocking: NcAlarmNonBlockingListSchema.default([])
19933
+ nonBlocking: NcAlarmNonBlockingListSchema.default([]),
19934
+ /**
19935
+ * Per arm mode, the delays that mode OVERRIDES (D697). A mode with no entry, or an entry
19936
+ * without a field, uses the global value above — so `[]`, the default, is exactly the
19937
+ * behaviour of a blob stored before this field existed. Read through `resolveModeDelays`.
19938
+ */
19939
+ modeDelays: NcAlarmModeDelaysListSchema.default([])
19920
19940
  });
19921
19941
  /**
19922
19942
  * Every field optional — a tab edits one control at a time.
19923
19943
  *
19924
- * `nonBlocking` is re-declared WITHOUT its default: `.partial()` does not
19925
- * remove an inner `.default()`, so a patch that never named the field would
19926
- * parse to `nonBlocking: []` and wipe every mode's list on an unrelated edit
19927
- * (the same trap {@link NcRulePatchSchema} documents).
19944
+ * `nonBlocking` and `modeDelays` are re-declared WITHOUT their defaults:
19945
+ * `.partial()` does not remove an inner `.default()`, so a patch that never
19946
+ * named the field would parse to `[]` and wipe every mode's list on an
19947
+ * unrelated edit (the same trap {@link NcRulePatchSchema} documents). Here
19948
+ * `modeDelays` means EDITS, not the stored overrides.
19928
19949
  */
19929
- var NcAlarmSettingsPatchSchema = NcAlarmSettingsSchema.extend({ nonBlocking: NcAlarmNonBlockingListSchema }).partial();
19950
+ var NcAlarmSettingsPatchSchema = NcAlarmSettingsSchema.extend({
19951
+ nonBlocking: NcAlarmNonBlockingListSchema,
19952
+ /** Per-mode, per-field edits — NOT the whole list (see NcAlarmModeDelaysEditSchema). */
19953
+ modeDelays: NcAlarmModeDelaysEditListSchema,
19954
+ /** ONE membership change; the panel applies it to the list it holds at its turn. */
19955
+ nonBlockingEdit: NcAlarmNonBlockingEditSchema
19956
+ }).partial().refine((p) => p.nonBlocking === void 0 || p.nonBlockingEdit === void 0, { message: "nonBlocking and nonBlockingEdit are exclusive — send the whole lists or one edit" });
19930
19957
  /**
19931
19958
  * What one arm mode actually arms, DERIVED from the enabled rules gated on it.
19932
19959
  * Never authored, never stored — see `alarm-mode-coverage.ts` for why a stored
@@ -20026,6 +20053,28 @@ var NcAlarmConfigSchema = object({
20026
20053
  */
20027
20054
  live: NcAlarmLiveSchema.optional()
20028
20055
  });
20056
+ var NcAlarmSensorReadingSchema = _enum([
20057
+ "open",
20058
+ "closed",
20059
+ "unknown",
20060
+ "not-opening"
20061
+ ]);
20062
+ /** One device's state as the alarm reads it — the classifier the arm check uses. */
20063
+ var NcAlarmSensorStateSchema = object({
20064
+ deviceId: number().int().positive(),
20065
+ reading: NcAlarmSensorReadingSchema,
20066
+ /** The word as read (`open`, `closed`, `unlocked`, `stopped`, …); null when unknown / not an opening. */
20067
+ state: string().nullable(),
20068
+ /** Why `unknown`: the read failed, or the slice holds no word its cap defines (a placeholder included). */
20069
+ unknownWhy: _enum(["read-failed", "unknown-word"]).nullable(),
20070
+ /** The device manager's liveness as the centre mirrors it; null = not known. */
20071
+ online: boolean().nullable()
20072
+ });
20073
+ var NcAlarmSensorsInputSchema = object({ deviceIds: array(number().int().positive()).max(500) });
20074
+ var NcAlarmSensorsSchema = object({
20075
+ sensors: array(NcAlarmSensorStateSchema),
20076
+ readAt: number().int().nonnegative()
20077
+ });
20029
20078
  /**
20030
20079
  * ONE rule's demand on ONE camera's clip ring.
20031
20080
  *
@@ -20116,7 +20165,7 @@ method(object({}), object({ rules: array(NcRuleSchema) }), { auth: "admin" }), m
20116
20165
  }), method(object({}), NcAlarmConfigSchema, { auth: "admin" }), method(object({ patch: NcAlarmSettingsPatchSchema }), NcAlarmConfigSchema, {
20117
20166
  kind: "mutation",
20118
20167
  auth: "admin"
20119
- });
20168
+ }), method(NcAlarmSensorsInputSchema, NcAlarmSensorsSchema, { auth: "admin" });
20120
20169
  /**
20121
20170
  * Zod schemas for persisted record types.
20122
20171
  *
@@ -20463,12 +20512,26 @@ var CameraSensorRefSchema = object({
20463
20512
  function cameraSensorRefKey(ref) {
20464
20513
  return `${ref.addonId}/${ref.stableId}`;
20465
20514
  }
20466
- /** CS-1 accepts exactly one mode; CS-2 (D673) widens it to confirm / replace. */
20467
- var CameraSensorsModeSchema = _enum(["in-addition"]);
20468
- var CameraSensorsConfigSchema = object({
20469
- mode: CameraSensorsModeSchema,
20470
- sensors: array(CameraSensorRefSchema).min(1).max(8)
20471
- }).superRefine((value, ctx) => {
20515
+ /**
20516
+ * A sensor's mode (D673). `in-addition`: its motion is the camera's motion too.
20517
+ * `replace`: its motion is the camera's, and while one is READY the camera's
20518
+ * own motion no longer counts on its own. `confirm`: while one is READY the
20519
+ * camera's own motion counts only while a confirm sensor is active — with or
20520
+ * without a replace sensor (spec C2, the controller's ruling on Q1).
20521
+ */
20522
+ var CameraSensorModeSchema = _enum([
20523
+ "in-addition",
20524
+ "confirm",
20525
+ "replace"
20526
+ ]);
20527
+ /** A stored sensor with no mode — every CS-1 row — is in addition. */
20528
+ var DEFAULT_CAMERA_SENSOR_MODE = "in-addition";
20529
+ /**
20530
+ * A camera's attached sensors. A CS-1 row carried an envelope
20531
+ * `mode: 'in-addition'`: `z.object` drops it on parse, and the PARSED value is
20532
+ * what the write stores (D672 rule 3), so it is never written again.
20533
+ */
20534
+ var CameraSensorsConfigSchema = object({ sensors: array(CameraSensorRefSchema.extend({ mode: CameraSensorModeSchema.default(DEFAULT_CAMERA_SENSOR_MODE) })).min(1).max(8) }).superRefine((value, ctx) => {
20472
20535
  const seen = /* @__PURE__ */ new Set();
20473
20536
  value.sensors.forEach((ref, index) => {
20474
20537
  const key = cameraSensorRefKey(ref);
@@ -20480,39 +20543,41 @@ var CameraSensorsConfigSchema = object({
20480
20543
  seen.add(key);
20481
20544
  });
20482
20545
  });
20483
- var RefFields = {
20546
+ /** Every attachment names its mode; an older orchestrator that does not is in addition. */
20547
+ var AttachmentFields = {
20484
20548
  addonId: string(),
20485
- stableId: string()
20549
+ stableId: string(),
20550
+ mode: CameraSensorModeSchema.default(DEFAULT_CAMERA_SENSOR_MODE)
20486
20551
  };
20487
20552
  var CameraSensorAttachmentSchema = discriminatedUnion("state", [
20488
20553
  object({
20489
- ...RefFields,
20554
+ ...AttachmentFields,
20490
20555
  state: literal("ready"),
20491
20556
  deviceId: number(),
20492
20557
  name: string(),
20493
20558
  caps: array(string()).readonly()
20494
20559
  }),
20495
20560
  object({
20496
- ...RefFields,
20561
+ ...AttachmentFields,
20497
20562
  state: literal("offline"),
20498
20563
  deviceId: number(),
20499
20564
  name: string(),
20500
20565
  reason: _enum(["offline", "disabled"])
20501
20566
  }),
20502
20567
  object({
20503
- ...RefFields,
20568
+ ...AttachmentFields,
20504
20569
  state: literal("missing"),
20505
20570
  reason: string()
20506
20571
  }),
20507
20572
  object({
20508
- ...RefFields,
20573
+ ...AttachmentFields,
20509
20574
  state: literal("unsupported"),
20510
20575
  deviceId: number(),
20511
20576
  name: string(),
20512
20577
  reason: string()
20513
20578
  }),
20514
20579
  object({
20515
- ...RefFields,
20580
+ ...AttachmentFields,
20516
20581
  state: literal("unreadable"),
20517
20582
  reason: string()
20518
20583
  })
@@ -20525,17 +20590,49 @@ var CameraSensorAttachmentSchema = discriminatedUnion("state", [
20525
20590
  * say.
20526
20591
  */
20527
20592
  var CameraSensorsNotForwardedSchema = _enum(["onboard-not-listed", "no-active-detection"]);
20593
+ /** Whether the camera's OWN motion counts on its own (D673 C2), from its READY sensors (C3). */
20594
+ var CameraOwnMotionSchema = _enum([
20595
+ "always",
20596
+ "when-confirmed",
20597
+ "never"
20598
+ ]);
20599
+ /** Confirm / Replace cannot suppress this camera's motion: its provider still emits it directly (D673 C13). */
20600
+ var CameraSensorsNotEnforcedSchema = _enum(["provider-not-split"]);
20601
+ /**
20602
+ * The camera's OWN onboard motion (D696): the raw input the bridge combines,
20603
+ * never the effective value. The camera's `motion` slice is the effective one,
20604
+ * so a view of the camera's own row reads this.
20605
+ * - `atMs`: when the bridge received the camera's last own edge.
20606
+ * - `detected`: evaluated WHEN THE STATUS IS ASKED — the last edge said `true`
20607
+ * AND it is younger than the window the bridge counts the camera's own motion
20608
+ * for (`motionCooldownMs`, floored at two sustain ticks). A camera that never
20609
+ * sends a clear (heartbeats only) therefore reads `false` once no push came
20610
+ * within the window; a status read is a snapshot, so a live view re-asks.
20611
+ * Absent = this orchestrator has not received the camera's own motion since it
20612
+ * started (unknown, never "quiet"), or an orchestrator older than D696.
20613
+ */
20614
+ var CameraRawLevelSchema = object({
20615
+ detected: boolean(),
20616
+ atMs: number()
20617
+ });
20528
20618
  var CameraSensorsStatusSchema = discriminatedUnion("state", [
20529
- object({ state: literal("not-configured") }),
20619
+ object({
20620
+ state: literal("not-configured"),
20621
+ cameraLevel: CameraRawLevelSchema.optional()
20622
+ }),
20530
20623
  object({
20531
20624
  state: literal("unreadable"),
20532
- reason: string()
20625
+ reason: string(),
20626
+ cameraLevel: CameraRawLevelSchema.optional()
20533
20627
  }),
20534
20628
  object({
20535
20629
  state: literal("configured"),
20536
- mode: CameraSensorsModeSchema,
20630
+ cameraLevel: CameraRawLevelSchema.optional(),
20537
20631
  sensors: array(CameraSensorAttachmentSchema).readonly(),
20538
- notForwarded: CameraSensorsNotForwardedSchema.optional()
20632
+ /** Absent = an orchestrator older than CS-2: it does not say (D315). */
20633
+ cameraMotion: CameraOwnMotionSchema.optional(),
20634
+ notForwarded: CameraSensorsNotForwardedSchema.optional(),
20635
+ notEnforced: CameraSensorsNotEnforcedSchema.optional()
20539
20636
  })
20540
20637
  ]);
20541
20638
  Object.freeze({
@@ -23726,8 +23823,10 @@ var RunnerCameraConfigSchema = object({
23726
23823
  * - `analyzer`: ML/frame-diff motion detection (motion-wasm or other
23727
23824
  * analyzer providers) running on decoded frames in this runner.
23728
23825
  * - `onboard`: camera-native motion pushes (Reolink Baichuan, ONVIF
23729
- * analytics). The provider emits ProviderMotion
23730
- * events; the orchestrator forwards to `reportMotion`.
23826
+ * analytics). The provider emits its raw push as `ProviderMotion`
23827
+ * (D673); the orchestrator's camera-sensors bridge re-emits the camera's
23828
+ * effective motion as `MotionOnMotionChanged`, which is what reaches
23829
+ * `reportMotion`.
23731
23830
  */
23732
23831
  motionSources: MotionSourcesSchema.default(["analyzer"]),
23733
23832
  /**
@@ -23904,7 +24003,15 @@ var RunnerLocalLoadSchema = object({
23904
24003
  hasGpu: boolean(),
23905
24004
  inferenceBackend: string().optional(),
23906
24005
  cpuCores: number().optional()
23907
- })
24006
+ }),
24007
+ /**
24008
+ * Who writes a camera's `motion` runtime slice (D696). `'orchestrator'`: this
24009
+ * runner never writes it. ABSENT = a runner older than D696, which still
24010
+ * writes the slice from its phase machine; the orchestrator does not write
24011
+ * while any runner node is absent-or-unanswered, so one slice never has two
24012
+ * writers.
24013
+ */
24014
+ motionSliceWriter: literal("orchestrator").optional()
23908
24015
  });
23909
24016
  /**
23910
24017
  * Aggregate runtime metrics for the runner's whole local pool. Mirrors the
@@ -28745,6 +28852,17 @@ object({
28745
28852
  deviceId: number(),
28746
28853
  status: DeviceStatusSchema
28747
28854
  });
28855
+ object({
28856
+ /** Ms epoch of the last press. null = never observed since this provider started. */
28857
+ lastPressedAt: number().nullable(),
28858
+ /** Counter since provider start. Resets on reboot. Useful for metrics/debug. */
28859
+ pressCountSinceStart: number()
28860
+ });
28861
+ object({
28862
+ deviceId: number(),
28863
+ timestamp: number()
28864
+ });
28865
+ DeviceType.Button, DeviceType.Camera;
28748
28866
  /**
28749
28867
  * Enum-state sensor — a string value picked from a finite option set.
28750
28868
  * Drives HA `sensor` entries with `state_class: enum` (HVAC action
@@ -30389,9 +30507,9 @@ object({
30389
30507
  /** Ms epoch of the last detected-true observation. Null if never detected. */
30390
30508
  lastDetectedAt: number().nullable(),
30391
30509
  /**
30392
- * `MOTION_CLOSE_AFTER_MS` while `detected: true` on a `Camera` device,
30393
- * `null` while false and on every `Sensor` device (D475) — see that
30394
- * constant's doc for the one-authority rule.
30510
+ * `MOTION_CLOSE_AFTER_MS` while `detected: true` on a `Camera` device (the
30511
+ * orchestrator writes it, D696), `null` while false and on every `Sensor`
30512
+ * device (D475) — see that constant's doc for the one-authority rule.
30395
30513
  *
30396
30514
  * ## Reading this field still arms nothing
30397
30515
  *
@@ -30409,38 +30527,41 @@ object({
30409
30527
  * `addon-export-alexa/src/motion-clear-hold.ts` and
30410
30528
  * `addon-export-hap`'s `RESET_DEBOUNCE_MS` both do.
30411
30529
  *
30412
- * ## Who writes it
30413
- *
30414
- * - **Cameras** — the runner's phase machine, `active → watching` on
30415
- * `cooldown_expired`, which then writes this slice with
30416
- * `detected: false` (`handlePhaseChanged` in
30417
- * `pipeline-runner/index.ts`). It produces the FALLING edge, which
30418
- * matters most for the sources that only ever push a rising one:
30419
- * Reolink emits `MotionOnMotionChanged { detected: true }` and never
30420
- * a false.
30421
- * - **Sensors** (Home Assistant binary sensors, Homematic) — the
30422
- * provider pushes the false itself, from the upstream system's own
30423
- * state change. No phase machine is involved.
30424
- *
30425
- * ### The phase machine is CANONICAL, not sole — and that is a defect
30426
- *
30427
- * An earlier revision of this docblock (mine, 2026-09-12) claimed the
30428
- * phase machine is the sole writer for a camera. It is not.
30429
- * `hikvision-camera.ts:3464` and `amcrest-camera.ts:445` both call
30430
- * `setCapSlice(motionCapability, …)` on their own rising edge, and
30431
- * Hikvision's comment says why: it read THIS docblock, agreed the
30432
- * runner is canonical, and wrote anyway to avoid per-tick churn. So
30433
- * two authorities can disagree about one slice, which this repo
30434
- * forbids, and the doc said otherwise — which is worse than saying
30435
- * nothing, because it reads as verification.
30436
- *
30437
- * This predates D475 and is not fixed there: the fix touches every
30438
- * camera provider. Recorded in D475's Consequences. Do not restore the
30439
- * "sole writer" wording without also removing the other writers.
30530
+ * ## Who writes it (D696)
30531
+ *
30532
+ * - **Cameras** — the orchestrator, and nothing else. It writes the camera's
30533
+ * EFFECTIVE motion (`addon-pipeline-orchestrator`
30534
+ * `camera-sensors/motion-slice.ts`), alongside the effective
30535
+ * `MotionOnMotionChanged` it emits or receives: the camera-sensors bridge
30536
+ * for a split camera, an unsplit emitter's direct event, the analyzer and
30537
+ * device activity, as the camera's `motionSources` counts them. A source
30538
+ * that never sends a clear falls one window after its last `true`.
30539
+ * `lastDetectedAt` moves only on an effective rise. No camera provider
30540
+ * writes this slice (not even a boot seed), and neither does the runner's
30541
+ * phase machine: its phase is "a session is attached" for every on-motion
30542
+ * session, not motion, and it now has its own `DetectionPhaseTransition`.
30543
+ * A provider's `isDetected` answers from the hub's slice.
30544
+ * - **Sensors** (Home Assistant binary sensors, Homematic, Matter, Alexa
30545
+ * imports) — the provider pushes both edges itself, from the upstream
30546
+ * system's own state change. That is the sensor's own fact.
30547
+ *
30548
+ * `scripts/check-onboard-motion-emitters.ts` refuses any other writer of a
30549
+ * `motion` slice; each sensor writer is a named exemption.
30550
+ *
30551
+ * This replaces the D475 §4 rule ("the phase machine is the sole writer").
30552
+ * That rule was never true: Hikvision and Amcrest wrote the slice raw beside
30553
+ * it, every provider seeded it at boot, and every session left it
30554
+ * `detected: true` after its detach.
30440
30555
  */
30441
30556
  autoClearAfterMs: number().nullable()
30442
30557
  });
30443
- object({
30558
+ /**
30559
+ * Payload of `motion.onMotionChanged` event + the corresponding bus
30560
+ * event `EventCategory.MotionOnMotionChanged`. Single source of truth
30561
+ * — both the cap event surface and the bus payload type alias to this
30562
+ * schema.
30563
+ */
30564
+ var MotionOnMotionChangedDataSchema = object({
30444
30565
  deviceId: number(),
30445
30566
  detected: boolean(),
30446
30567
  timestamp: number(),
@@ -40499,6 +40620,12 @@ Object.freeze({
40499
40620
  addonId: null,
40500
40621
  access: "view"
40501
40622
  },
40623
+ "notificationRules.getAlarmSensors": {
40624
+ capName: "notification-rules",
40625
+ capScope: "system",
40626
+ addonId: null,
40627
+ access: "view"
40628
+ },
40502
40629
  "notificationRules.getClipRetentionAsks": {
40503
40630
  capName: "notification-rules",
40504
40631
  capScope: "system",
@@ -44982,6 +45109,11 @@ Object.freeze({
44982
45109
  form: "single",
44983
45110
  optional: false
44984
45111
  }],
45112
+ "notificationRules.getAlarmSensors": [{
45113
+ name: "deviceIds",
45114
+ form: "array",
45115
+ optional: false
45116
+ }],
44985
45117
  "notificationRules.setDeviceMuted": [{
44986
45118
  name: "deviceId",
44987
45119
  form: "single",
@@ -46917,6 +47049,7 @@ TimelapseRuleInputSchema.extend({
46917
47049
  createdAt: number(),
46918
47050
  updatedAt: number()
46919
47051
  });
47052
+ MotionOnMotionChangedDataSchema.omit({ triggeredBy: true });
46920
47053
  object({
46921
47054
  /**
46922
47055
  * Fraction of the box's own size added on EACH side before cutting.
@@ -47118,7 +47251,7 @@ var AdminUIAddon = class extends BaseAddon {
47118
47251
  capability: adminUiCapability,
47119
47252
  provider: {
47120
47253
  getStaticDir: async () => ({ staticDir: resolveAdminUiDistDir() }),
47121
- getVersion: async () => ({ version: "1.2.298" })
47254
+ getVersion: async () => ({ version: "1.2.300" })
47122
47255
  }
47123
47256
  }];
47124
47257
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/addon-admin-ui",
3
- "version": "1.2.298",
3
+ "version": "1.2.300",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "description": "Admin UI — Vite frontend build and server-side addon",