@camstack/addon-admin-ui 1.2.297 → 1.2.299

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 (95) hide show
  1. package/dist/assets/{AddonCollectionPage-B6o3CrJm.js → AddonCollectionPage-Bgk5av4b.js} +1 -1
  2. package/dist/assets/{Addons-CLx0TABX.js → Addons-BiAma6AN.js} +1 -1
  3. package/dist/assets/{AdminTabs-Dz-zU3Kb.js → AdminTabs-C7QmfUqk.js} +1 -1
  4. package/dist/assets/{AiProfiles-uhQJ9cM7.js → AiProfiles-B4z9wywC.js} +1 -1
  5. package/dist/assets/{BrokerForm-CrieL2V8.js → BrokerForm-lP42jKPi.js} +1 -1
  6. package/dist/assets/Build-6D08C629.js +32 -0
  7. package/dist/assets/{Capabilities-BbMlCUl3.js → Capabilities-BSbtmFZi.js} +1 -1
  8. package/dist/assets/{CapabilityBadges-DPRjowlM.js → CapabilityBadges-Ck0Zi6v3.js} +1 -1
  9. package/dist/assets/{Cluster-BgOyAnmN.js → Cluster-D8yFB0Np.js} +2 -2
  10. package/dist/assets/CompositionEditor-KckU34Rc.js +1 -0
  11. package/dist/assets/{CompositionEditorPage-DLqwil0X.js → CompositionEditorPage-CPRkhwhE.js} +1 -1
  12. package/dist/assets/{Data-l_C2rP1Y.js → Data-CPY-GSWR.js} +1 -1
  13. package/dist/assets/{DetectionIntelligence-DpUgfmZr.js → DetectionIntelligence-Bfo6e0Fm.js} +1 -1
  14. package/dist/assets/{DeviceAggregateSection-D6WHay_J.js → DeviceAggregateSection-XoINX6MC.js} +1 -1
  15. package/dist/assets/DeviceDetail-BkOvR0zE.js +2 -0
  16. package/dist/assets/{Devices-EK8lbkTh.js → Devices-CBo87XTe.js} +1 -1
  17. package/dist/assets/{EmbedPlayerPage-CpZnzmi4.js → EmbedPlayerPage-nlk8WGop.js} +1 -1
  18. package/dist/assets/Events-BTw7o3c3.js +1 -0
  19. package/dist/assets/{FormBuilder-CTSAVvR9.js → FormBuilder-DCWIHY3A.js} +1 -1
  20. package/dist/assets/{Identity-CbGj2sHC.js → Identity-Z0uQisms.js} +1 -1
  21. package/dist/assets/IntegrationDetail-CxpJItTw.js +1 -0
  22. package/dist/assets/{Integrations-Dkldg39k.js → Integrations-CWQ4Bmhh.js} +1 -1
  23. package/dist/assets/Integrations-CvQ2Qsiu.js +1 -0
  24. package/dist/assets/Locations-D-vr4FmX.js +3 -0
  25. package/dist/assets/{Logs-BGFt1EcI.js → Logs-MUeTxUBL.js} +1 -1
  26. package/dist/assets/{ModelLicenses-B1wgpejN.js → ModelLicenses-D4ZI-ieb.js} +1 -1
  27. package/dist/assets/{MotionZonesSettings-D8M8Q04w.js → MotionZonesSettings-eZjxA7t2.js} +1 -1
  28. package/dist/assets/{MyAccess-DsIKwI-L.js → MyAccess-BLNO_4Vb.js} +1 -1
  29. package/dist/assets/{Network-fI97plIN.js → Network-V-sOJFE3.js} +1 -1
  30. package/dist/assets/{NodeAddonsSettingsPanel-DdMyNtY6.js → NodeAddonsSettingsPanel-DeYrqSPH.js} +1 -1
  31. package/dist/assets/{NodeInferenceDevices-szoJKt03.js → NodeInferenceDevices-BAdCG-8q.js} +1 -1
  32. package/dist/assets/Notifications-CVMvqEcL.js +1 -0
  33. package/dist/assets/{Pipeline-C9WJxAiT.js → Pipeline-Dv9QxF4V.js} +1 -1
  34. package/dist/assets/{Plates-D0D3MpKS.js → Plates-BxIKSjrx.js} +1 -1
  35. package/dist/assets/{PrivacyMaskSettings-SZC4SEAg.js → PrivacyMaskSettings-1wQ0sX0H.js} +1 -1
  36. package/dist/assets/{ProviderIcon-BFGeK1fD.js → ProviderIcon-BbMyhwcl.js} +1 -1
  37. package/dist/assets/{Recordings-cFOGbe1I.js → Recordings-C7qug-1m.js} +1 -1
  38. package/dist/assets/{ScanNetworkModal-DjhT4ixb.js → ScanNetworkModal-DK_tyixc.js} +1 -1
  39. package/dist/assets/{SceneMonitorEditor-BbhkvRmw.js → SceneMonitorEditor-Ds9agOvV.js} +1 -1
  40. package/dist/assets/{Scenes-AfBceOIW.js → Scenes-Raq-0hCd.js} +1 -1
  41. package/dist/assets/{Settings-OryGXRp4.js → Settings-Ddx30tFk.js} +1 -1
  42. package/dist/assets/{Showroom-I0TllNwD.js → Showroom-B8b26pPh.js} +1 -1
  43. package/dist/assets/{StorageLocationsPanel-Cgdn2l-t.js → StorageLocationsPanel-DfOP9cjP.js} +1 -1
  44. package/dist/assets/{Terminal-BwxWb4zq.js → Terminal-BQlJcagf.js} +1 -1
  45. package/dist/assets/{Viewer-CEJR5MwN.js → Viewer-Dugm0Lyh.js} +1 -1
  46. package/dist/assets/{_virtual_mf-localSharedImportMap___mfe_internal__admin_ui_host-Cywkdc5t.js → _virtual_mf-localSharedImportMap___mfe_internal__admin_ui_host-BGlzIG7f.js} +1 -1
  47. package/dist/assets/{archive-1kBkJd-7.js → archive-M1NkdyX1.js} +1 -1
  48. package/dist/assets/{authed-media-BUAjWd16.js → authed-media-BbclCn8D.js} +1 -1
  49. package/dist/assets/{boxes-CaGF6_fi.js → boxes-3RvvFSDa.js} +1 -1
  50. package/dist/assets/circle-slash-CSI0dVHX.js +1 -0
  51. package/dist/assets/{debounced-invalidate-Xey73wOa.js → debounced-invalidate-Dg1eT_Y-.js} +1 -1
  52. package/dist/assets/{device-integration-icon-mWG8cJvN.js → device-integration-icon-CteXz-vc.js} +1 -1
  53. package/dist/assets/device-picker-model-B29vbIKa.js +1 -0
  54. package/dist/assets/{dist-CpvS1gR8.js → dist--LXFk-rO.js} +1 -1
  55. package/dist/assets/dist-B8s4O5ek.js +349 -0
  56. package/dist/assets/{face-bbox-DLUNf1TM.js → face-bbox-D0yJXCw6.js} +1 -1
  57. package/dist/assets/{hard-drive-download-BgHnBbNU.js → hard-drive-download-DWkfRg_9.js} +1 -1
  58. package/dist/assets/{hostInit-BVAuFCt8.js → hostInit-1ItCQHp9.js} +1 -1
  59. package/dist/assets/{index-4TogXFcf.js → index-BZ3TdH1g.js} +3 -3
  60. package/dist/assets/index-egLHRpbu.css +2 -0
  61. package/dist/assets/{layers-Di8kv7TA.js → layers-DkNaQ1QP.js} +1 -1
  62. package/dist/assets/{location-owned-usage-BRoWx0jW.js → location-owned-usage-BQ0INIT2.js} +1 -1
  63. package/dist/assets/{mf-entry-bootstrap-0-1a22509c.js → mf-entry-bootstrap-0-e02cda07.js} +2 -2
  64. package/dist/assets/{player-overlays-Bqzr3Tjh.js → player-overlays-B_uiidR6.js} +1 -1
  65. package/dist/assets/remoteEntry-CqjS7D1o.js +1 -0
  66. package/dist/assets/{send-_pOalXPP.js → send-B_CQqzXx.js} +1 -1
  67. package/dist/assets/{settings-2-CJt9SGbF.js → settings-2-BYvhRrnI.js} +1 -1
  68. package/dist/assets/{square-check-big-BzFBrtST.js → square-check-big-DvgdtLa5.js} +1 -1
  69. package/dist/assets/{src-BSGPnT6T.js → src-B3pgYpGR.js} +8 -8
  70. package/dist/assets/src-BH2M3zRW.js +349 -0
  71. package/dist/assets/{use-scenes-feed-DbObG-xM.js → use-scenes-feed-C3EryavW.js} +1 -1
  72. package/dist/assets/{use-stationary-objects-aMpbFTJa.js → use-stationary-objects-BM21l4YT.js} +1 -1
  73. package/dist/assets/{useDevice-De8PHIGN.js → useDevice-DPvLTx63.js} +1 -1
  74. package/dist/assets/useEventInvalidation-B0D6f62J.js +1 -0
  75. package/dist/assets/{useNodeUrlSelection-B1sfqqks.js → useNodeUrlSelection-DPB3ldG4.js} +1 -1
  76. package/dist/assets/user-round-BijBSyFY.js +1 -0
  77. package/dist/assets/{virtual_mf-REMOTE_ENTRY_ID___mfe_internal__admin_ui_host__remoteEntry-_hash_-D_NQ5pkv.js → virtual_mf-REMOTE_ENTRY_ID___mfe_internal__admin_ui_host__remoteEntry-_hash_-Bu6krwIe.js} +2 -2
  78. package/dist/index.html +6 -6
  79. package/dist/server/addon.js +191 -93
  80. package/package.json +2 -2
  81. package/dist/assets/Build-ryMzY-F2.js +0 -32
  82. package/dist/assets/CompositionEditor-C4k-XC1u.js +0 -1
  83. package/dist/assets/DeviceDetail-Cp1ILpRI.js +0 -2
  84. package/dist/assets/Events-Yf2kZxNW.js +0 -1
  85. package/dist/assets/IntegrationDetail-DndCrz-c.js +0 -1
  86. package/dist/assets/Integrations-DU5E0ptf.js +0 -1
  87. package/dist/assets/Locations-D38UyYkP.js +0 -3
  88. package/dist/assets/Notifications-BYj6aZpM.js +0 -1
  89. package/dist/assets/circle-slash-Ct0GeVaM.js +0 -1
  90. package/dist/assets/dist-CG8QNdf7.js +0 -349
  91. package/dist/assets/index-DOZUgTMC.css +0 -2
  92. package/dist/assets/remoteEntry-zj4B5tmA.js +0 -1
  93. package/dist/assets/src-BnA_ovuP.js +0 -349
  94. package/dist/assets/useEventInvalidation-Xr6xsOOg.js +0 -1
  95. package/dist/assets/user-round-_b9E4_sG.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,
@@ -18406,17 +18397,25 @@ var NcScheduleSchema = object({
18406
18397
  */
18407
18398
  var NcSystemEventDeliveryModeSchema = _enum(["instant", "summary"]);
18408
18399
  /**
18400
+ * How a summary window is SENT (D698): `rule` (absent) = ONE notification with
18401
+ * every section; `section` = one notification per section with something to
18402
+ * say (an unavailable section included), each titled by its section.
18403
+ */
18404
+ var NcStateSummarySplitSchema = _enum(["rule", "section"]);
18405
+ /**
18409
18406
  * `summary`: the rule sends NOTHING per event. When a window of `schedule`
18410
18407
  * CLOSES, it sends one notification with the current state of its kinds
18411
18408
  * (low batteries, consumables to replace, devices offline, updates
18412
- * available, ...), after its own filters. Nothing to report sends nothing.
18409
+ * available, ...), after its own filters — or, with `split: 'section'`
18410
+ * (D698), one notification per section. Nothing to report sends nothing.
18413
18411
  * The schedule is the ordinary `NcSchedule` (weekly windows, IANA timezone,
18414
18412
  * midnight crossing); the send time is each window's END. Refused on the
18415
18413
  * `alarm` family, which stays instant (`systemEventDeliveryProblems`).
18416
18414
  */
18417
18415
  var NcSystemEventDeliverySchema = discriminatedUnion("mode", [object({ mode: literal("instant") }), object({
18418
18416
  mode: literal("summary"),
18419
- schedule: NcScheduleSchema
18417
+ schedule: NcScheduleSchema,
18418
+ split: NcStateSummarySplitSchema.optional()
18420
18419
  })]);
18421
18420
  /** Fuzzy plate matcher — OCR noise makes exact match useless (spec row 12/13). */
18422
18421
  var NcPlateMatcherSchema = object({
@@ -19415,11 +19414,23 @@ var NcStateSummaryPreviewSectionSchema = object({
19415
19414
  reason: string().optional()
19416
19415
  });
19417
19416
  /**
19417
+ * One notification a previewed summary would send (D698): the whole summary on
19418
+ * a `rule` split (no `section`), one section's on a `section` split.
19419
+ */
19420
+ var NcStateSummaryPreviewRowSchema = object({
19421
+ section: string().optional(),
19422
+ /** The section's name on a per-section row; every reported section's, joined, on a combined one. */
19423
+ title: string(),
19424
+ text: string(),
19425
+ count: number().int().nonnegative()
19426
+ });
19427
+ /**
19418
19428
  * The summary a rule would send now. `empty` = nothing to report and every
19419
19429
  * section read: such a summary is NOT sent. `dropped` counts the open states
19420
19430
  * the rule's own filters (or a camera mute) left out, by reason.
19421
19431
  * `excludedGroups` names the kind groups selected that have no state to report
19422
- * (backups & exports).
19432
+ * (backups & exports). `split` and `rows` (D698) say how it would be sent —
19433
+ * optional, so an older hub's answer still parses.
19423
19434
  */
19424
19435
  var NcStateSummaryPreviewSchema = object({
19425
19436
  empty: boolean(),
@@ -19427,7 +19438,9 @@ var NcStateSummaryPreviewSchema = object({
19427
19438
  text: string(),
19428
19439
  sections: array(NcStateSummaryPreviewSectionSchema),
19429
19440
  dropped: record(string(), number().int().nonnegative()),
19430
- excludedGroups: array(string())
19441
+ excludedGroups: array(string()),
19442
+ split: NcStateSummarySplitSchema.optional(),
19443
+ rows: array(NcStateSummaryPreviewRowSchema).optional()
19431
19444
  });
19432
19445
  var NcTestResultSchema = object({
19433
19446
  recordId: string(),
@@ -20441,12 +20454,26 @@ var CameraSensorRefSchema = object({
20441
20454
  function cameraSensorRefKey(ref) {
20442
20455
  return `${ref.addonId}/${ref.stableId}`;
20443
20456
  }
20444
- /** CS-1 accepts exactly one mode; CS-2 (D673) widens it to confirm / replace. */
20445
- var CameraSensorsModeSchema = _enum(["in-addition"]);
20446
- var CameraSensorsConfigSchema = object({
20447
- mode: CameraSensorsModeSchema,
20448
- sensors: array(CameraSensorRefSchema).min(1).max(8)
20449
- }).superRefine((value, ctx) => {
20457
+ /**
20458
+ * A sensor's mode (D673). `in-addition`: its motion is the camera's motion too.
20459
+ * `replace`: its motion is the camera's, and while one is READY the camera's
20460
+ * own motion no longer counts on its own. `confirm`: while one is READY the
20461
+ * camera's own motion counts only while a confirm sensor is active — with or
20462
+ * without a replace sensor (spec C2, the controller's ruling on Q1).
20463
+ */
20464
+ var CameraSensorModeSchema = _enum([
20465
+ "in-addition",
20466
+ "confirm",
20467
+ "replace"
20468
+ ]);
20469
+ /** A stored sensor with no mode — every CS-1 row — is in addition. */
20470
+ var DEFAULT_CAMERA_SENSOR_MODE = "in-addition";
20471
+ /**
20472
+ * A camera's attached sensors. A CS-1 row carried an envelope
20473
+ * `mode: 'in-addition'`: `z.object` drops it on parse, and the PARSED value is
20474
+ * what the write stores (D672 rule 3), so it is never written again.
20475
+ */
20476
+ var CameraSensorsConfigSchema = object({ sensors: array(CameraSensorRefSchema.extend({ mode: CameraSensorModeSchema.default(DEFAULT_CAMERA_SENSOR_MODE) })).min(1).max(8) }).superRefine((value, ctx) => {
20450
20477
  const seen = /* @__PURE__ */ new Set();
20451
20478
  value.sensors.forEach((ref, index) => {
20452
20479
  const key = cameraSensorRefKey(ref);
@@ -20458,39 +20485,41 @@ var CameraSensorsConfigSchema = object({
20458
20485
  seen.add(key);
20459
20486
  });
20460
20487
  });
20461
- var RefFields = {
20488
+ /** Every attachment names its mode; an older orchestrator that does not is in addition. */
20489
+ var AttachmentFields = {
20462
20490
  addonId: string(),
20463
- stableId: string()
20491
+ stableId: string(),
20492
+ mode: CameraSensorModeSchema.default(DEFAULT_CAMERA_SENSOR_MODE)
20464
20493
  };
20465
20494
  var CameraSensorAttachmentSchema = discriminatedUnion("state", [
20466
20495
  object({
20467
- ...RefFields,
20496
+ ...AttachmentFields,
20468
20497
  state: literal("ready"),
20469
20498
  deviceId: number(),
20470
20499
  name: string(),
20471
20500
  caps: array(string()).readonly()
20472
20501
  }),
20473
20502
  object({
20474
- ...RefFields,
20503
+ ...AttachmentFields,
20475
20504
  state: literal("offline"),
20476
20505
  deviceId: number(),
20477
20506
  name: string(),
20478
20507
  reason: _enum(["offline", "disabled"])
20479
20508
  }),
20480
20509
  object({
20481
- ...RefFields,
20510
+ ...AttachmentFields,
20482
20511
  state: literal("missing"),
20483
20512
  reason: string()
20484
20513
  }),
20485
20514
  object({
20486
- ...RefFields,
20515
+ ...AttachmentFields,
20487
20516
  state: literal("unsupported"),
20488
20517
  deviceId: number(),
20489
20518
  name: string(),
20490
20519
  reason: string()
20491
20520
  }),
20492
20521
  object({
20493
- ...RefFields,
20522
+ ...AttachmentFields,
20494
20523
  state: literal("unreadable"),
20495
20524
  reason: string()
20496
20525
  })
@@ -20503,17 +20532,49 @@ var CameraSensorAttachmentSchema = discriminatedUnion("state", [
20503
20532
  * say.
20504
20533
  */
20505
20534
  var CameraSensorsNotForwardedSchema = _enum(["onboard-not-listed", "no-active-detection"]);
20535
+ /** Whether the camera's OWN motion counts on its own (D673 C2), from its READY sensors (C3). */
20536
+ var CameraOwnMotionSchema = _enum([
20537
+ "always",
20538
+ "when-confirmed",
20539
+ "never"
20540
+ ]);
20541
+ /** Confirm / Replace cannot suppress this camera's motion: its provider still emits it directly (D673 C13). */
20542
+ var CameraSensorsNotEnforcedSchema = _enum(["provider-not-split"]);
20543
+ /**
20544
+ * The camera's OWN onboard motion (D696): the raw input the bridge combines,
20545
+ * never the effective value. The camera's `motion` slice is the effective one,
20546
+ * so a view of the camera's own row reads this.
20547
+ * - `atMs`: when the bridge received the camera's last own edge.
20548
+ * - `detected`: evaluated WHEN THE STATUS IS ASKED — the last edge said `true`
20549
+ * AND it is younger than the window the bridge counts the camera's own motion
20550
+ * for (`motionCooldownMs`, floored at two sustain ticks). A camera that never
20551
+ * sends a clear (heartbeats only) therefore reads `false` once no push came
20552
+ * within the window; a status read is a snapshot, so a live view re-asks.
20553
+ * Absent = this orchestrator has not received the camera's own motion since it
20554
+ * started (unknown, never "quiet"), or an orchestrator older than D696.
20555
+ */
20556
+ var CameraRawLevelSchema = object({
20557
+ detected: boolean(),
20558
+ atMs: number()
20559
+ });
20506
20560
  var CameraSensorsStatusSchema = discriminatedUnion("state", [
20507
- object({ state: literal("not-configured") }),
20561
+ object({
20562
+ state: literal("not-configured"),
20563
+ cameraLevel: CameraRawLevelSchema.optional()
20564
+ }),
20508
20565
  object({
20509
20566
  state: literal("unreadable"),
20510
- reason: string()
20567
+ reason: string(),
20568
+ cameraLevel: CameraRawLevelSchema.optional()
20511
20569
  }),
20512
20570
  object({
20513
20571
  state: literal("configured"),
20514
- mode: CameraSensorsModeSchema,
20572
+ cameraLevel: CameraRawLevelSchema.optional(),
20515
20573
  sensors: array(CameraSensorAttachmentSchema).readonly(),
20516
- notForwarded: CameraSensorsNotForwardedSchema.optional()
20574
+ /** Absent = an orchestrator older than CS-2: it does not say (D315). */
20575
+ cameraMotion: CameraOwnMotionSchema.optional(),
20576
+ notForwarded: CameraSensorsNotForwardedSchema.optional(),
20577
+ notEnforced: CameraSensorsNotEnforcedSchema.optional()
20517
20578
  })
20518
20579
  ]);
20519
20580
  Object.freeze({
@@ -23704,8 +23765,10 @@ var RunnerCameraConfigSchema = object({
23704
23765
  * - `analyzer`: ML/frame-diff motion detection (motion-wasm or other
23705
23766
  * analyzer providers) running on decoded frames in this runner.
23706
23767
  * - `onboard`: camera-native motion pushes (Reolink Baichuan, ONVIF
23707
- * analytics). The provider emits ProviderMotion
23708
- * events; the orchestrator forwards to `reportMotion`.
23768
+ * analytics). The provider emits its raw push as `ProviderMotion`
23769
+ * (D673); the orchestrator's camera-sensors bridge re-emits the camera's
23770
+ * effective motion as `MotionOnMotionChanged`, which is what reaches
23771
+ * `reportMotion`.
23709
23772
  */
23710
23773
  motionSources: MotionSourcesSchema.default(["analyzer"]),
23711
23774
  /**
@@ -23882,7 +23945,15 @@ var RunnerLocalLoadSchema = object({
23882
23945
  hasGpu: boolean(),
23883
23946
  inferenceBackend: string().optional(),
23884
23947
  cpuCores: number().optional()
23885
- })
23948
+ }),
23949
+ /**
23950
+ * Who writes a camera's `motion` runtime slice (D696). `'orchestrator'`: this
23951
+ * runner never writes it. ABSENT = a runner older than D696, which still
23952
+ * writes the slice from its phase machine; the orchestrator does not write
23953
+ * while any runner node is absent-or-unanswered, so one slice never has two
23954
+ * writers.
23955
+ */
23956
+ motionSliceWriter: literal("orchestrator").optional()
23886
23957
  });
23887
23958
  /**
23888
23959
  * Aggregate runtime metrics for the runner's whole local pool. Mirrors the
@@ -28723,6 +28794,17 @@ object({
28723
28794
  deviceId: number(),
28724
28795
  status: DeviceStatusSchema
28725
28796
  });
28797
+ object({
28798
+ /** Ms epoch of the last press. null = never observed since this provider started. */
28799
+ lastPressedAt: number().nullable(),
28800
+ /** Counter since provider start. Resets on reboot. Useful for metrics/debug. */
28801
+ pressCountSinceStart: number()
28802
+ });
28803
+ object({
28804
+ deviceId: number(),
28805
+ timestamp: number()
28806
+ });
28807
+ DeviceType.Button, DeviceType.Camera;
28726
28808
  /**
28727
28809
  * Enum-state sensor — a string value picked from a finite option set.
28728
28810
  * Drives HA `sensor` entries with `state_class: enum` (HVAC action
@@ -30367,9 +30449,9 @@ object({
30367
30449
  /** Ms epoch of the last detected-true observation. Null if never detected. */
30368
30450
  lastDetectedAt: number().nullable(),
30369
30451
  /**
30370
- * `MOTION_CLOSE_AFTER_MS` while `detected: true` on a `Camera` device,
30371
- * `null` while false and on every `Sensor` device (D475) — see that
30372
- * constant's doc for the one-authority rule.
30452
+ * `MOTION_CLOSE_AFTER_MS` while `detected: true` on a `Camera` device (the
30453
+ * orchestrator writes it, D696), `null` while false and on every `Sensor`
30454
+ * device (D475) — see that constant's doc for the one-authority rule.
30373
30455
  *
30374
30456
  * ## Reading this field still arms nothing
30375
30457
  *
@@ -30387,38 +30469,41 @@ object({
30387
30469
  * `addon-export-alexa/src/motion-clear-hold.ts` and
30388
30470
  * `addon-export-hap`'s `RESET_DEBOUNCE_MS` both do.
30389
30471
  *
30390
- * ## Who writes it
30391
- *
30392
- * - **Cameras** — the runner's phase machine, `active → watching` on
30393
- * `cooldown_expired`, which then writes this slice with
30394
- * `detected: false` (`handlePhaseChanged` in
30395
- * `pipeline-runner/index.ts`). It produces the FALLING edge, which
30396
- * matters most for the sources that only ever push a rising one:
30397
- * Reolink emits `MotionOnMotionChanged { detected: true }` and never
30398
- * a false.
30399
- * - **Sensors** (Home Assistant binary sensors, Homematic) — the
30400
- * provider pushes the false itself, from the upstream system's own
30401
- * state change. No phase machine is involved.
30402
- *
30403
- * ### The phase machine is CANONICAL, not sole — and that is a defect
30404
- *
30405
- * An earlier revision of this docblock (mine, 2026-09-12) claimed the
30406
- * phase machine is the sole writer for a camera. It is not.
30407
- * `hikvision-camera.ts:3464` and `amcrest-camera.ts:445` both call
30408
- * `setCapSlice(motionCapability, …)` on their own rising edge, and
30409
- * Hikvision's comment says why: it read THIS docblock, agreed the
30410
- * runner is canonical, and wrote anyway to avoid per-tick churn. So
30411
- * two authorities can disagree about one slice, which this repo
30412
- * forbids, and the doc said otherwise — which is worse than saying
30413
- * nothing, because it reads as verification.
30414
- *
30415
- * This predates D475 and is not fixed there: the fix touches every
30416
- * camera provider. Recorded in D475's Consequences. Do not restore the
30417
- * "sole writer" wording without also removing the other writers.
30472
+ * ## Who writes it (D696)
30473
+ *
30474
+ * - **Cameras** — the orchestrator, and nothing else. It writes the camera's
30475
+ * EFFECTIVE motion (`addon-pipeline-orchestrator`
30476
+ * `camera-sensors/motion-slice.ts`), alongside the effective
30477
+ * `MotionOnMotionChanged` it emits or receives: the camera-sensors bridge
30478
+ * for a split camera, an unsplit emitter's direct event, the analyzer and
30479
+ * device activity, as the camera's `motionSources` counts them. A source
30480
+ * that never sends a clear falls one window after its last `true`.
30481
+ * `lastDetectedAt` moves only on an effective rise. No camera provider
30482
+ * writes this slice (not even a boot seed), and neither does the runner's
30483
+ * phase machine: its phase is "a session is attached" for every on-motion
30484
+ * session, not motion, and it now has its own `DetectionPhaseTransition`.
30485
+ * A provider's `isDetected` answers from the hub's slice.
30486
+ * - **Sensors** (Home Assistant binary sensors, Homematic, Matter, Alexa
30487
+ * imports) — the provider pushes both edges itself, from the upstream
30488
+ * system's own state change. That is the sensor's own fact.
30489
+ *
30490
+ * `scripts/check-onboard-motion-emitters.ts` refuses any other writer of a
30491
+ * `motion` slice; each sensor writer is a named exemption.
30492
+ *
30493
+ * This replaces the D475 §4 rule ("the phase machine is the sole writer").
30494
+ * That rule was never true: Hikvision and Amcrest wrote the slice raw beside
30495
+ * it, every provider seeded it at boot, and every session left it
30496
+ * `detected: true` after its detach.
30418
30497
  */
30419
30498
  autoClearAfterMs: number().nullable()
30420
30499
  });
30421
- object({
30500
+ /**
30501
+ * Payload of `motion.onMotionChanged` event + the corresponding bus
30502
+ * event `EventCategory.MotionOnMotionChanged`. Single source of truth
30503
+ * — both the cap event surface and the bus payload type alias to this
30504
+ * schema.
30505
+ */
30506
+ var MotionOnMotionChangedDataSchema = object({
30422
30507
  deviceId: number(),
30423
30508
  detected: boolean(),
30424
30509
  timestamp: number(),
@@ -46545,6 +46630,18 @@ var STATE_SUMMARY_VARS = [
46545
46630
  systemEventKinds: [...SUMMARISABLE],
46546
46631
  systemEventDeliveries: ["summary"]
46547
46632
  },
46633
+ {
46634
+ name: "summarySection",
46635
+ label: "Summary: this section",
46636
+ description: "The section a per-section summary row is about (D698); on a summary sent as one message, every section it reports, comma-separated.",
46637
+ example: "Batterie scariche",
46638
+ group: "system",
46639
+ families: ["rule"],
46640
+ fields: [...RULE_TEXT],
46641
+ kinds: ["system"],
46642
+ systemEventKinds: [...SUMMARISABLE],
46643
+ systemEventDeliveries: ["summary"]
46644
+ },
46548
46645
  ...STATE_SUMMARY_SECTION_VARS.map((v) => ({
46549
46646
  name: v.name,
46550
46647
  label: v.label,
@@ -46883,6 +46980,7 @@ TimelapseRuleInputSchema.extend({
46883
46980
  createdAt: number(),
46884
46981
  updatedAt: number()
46885
46982
  });
46983
+ MotionOnMotionChangedDataSchema.omit({ triggeredBy: true });
46886
46984
  object({
46887
46985
  /**
46888
46986
  * Fraction of the box's own size added on EACH side before cutting.
@@ -47084,7 +47182,7 @@ var AdminUIAddon = class extends BaseAddon {
47084
47182
  capability: adminUiCapability,
47085
47183
  provider: {
47086
47184
  getStaticDir: async () => ({ staticDir: resolveAdminUiDistDir() }),
47087
- getVersion: async () => ({ version: "1.2.297" })
47185
+ getVersion: async () => ({ version: "1.2.299" })
47088
47186
  }
47089
47187
  }];
47090
47188
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/addon-admin-ui",
3
- "version": "1.2.297",
3
+ "version": "1.2.299",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "description": "Admin UI — Vite frontend build and server-side addon",
@@ -41,7 +41,7 @@
41
41
  "preview": "vite preview",
42
42
  "test": "vitest run",
43
43
  "test:watch": "vitest",
44
- "typecheck": "tsc --noEmit && tsc --noEmit -p tsconfig.server.json",
44
+ "typecheck": "tsc --noEmit -p tsconfig.spec.json && tsc --noEmit -p tsconfig.server.json",
45
45
  "publish:npm": "npm publish --access public"
46
46
  },
47
47
  "dependencies": {},