@camera.ui/server 2.1.2 → 2.1.4

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 (552) hide show
  1. package/dist/interface/assets/{404-pb2fRn1r.js → 404-6v3-U7nj.js} +1 -1
  2. package/dist/interface/assets/{About-eljMnDub.js → About-IMZSnCy7.js} +1 -1
  3. package/dist/interface/assets/{Adminpanel-BtQdiyre.js → Adminpanel-jq9sK1Ey.js} +1 -1
  4. package/dist/interface/assets/{Automation-DOiLJcU_.js → Automation-xs_GEpGx.js} +3 -3
  5. package/dist/interface/assets/{AutomationImport-DflZNRBB.js → AutomationImport-CR4fWWkU.js} +2 -2
  6. package/dist/interface/assets/{AutomationStore-qF_NTNUf.js → AutomationStore-rB-eVXdY.js} +2 -2
  7. package/dist/interface/assets/{AutomationStoreDetail-CUw-jBBR.js → AutomationStoreDetail-DzMg8IOO.js} +2 -2
  8. package/dist/interface/assets/Automations-DWI8Q2TS.js +2 -0
  9. package/dist/interface/assets/Camera-BIppnvyN.js +2 -0
  10. package/dist/interface/assets/Camera-BfMZmurS.css +1 -0
  11. package/dist/interface/assets/{CameraConsole-CEARcJYc.js → CameraConsole-CQLrlDvb.js} +2 -2
  12. package/dist/interface/assets/{Cameras-C0oHuoTR.js → Cameras-kIN6bWi1.js} +2 -2
  13. package/dist/interface/assets/Camview-4jdGGny8.js +1 -0
  14. package/dist/interface/assets/Camview-UCj_OW0s.css +1 -0
  15. package/dist/interface/assets/Config-DxYeS7cY.js +2 -0
  16. package/dist/interface/assets/{ConfigActionCameraControl-De0qb88r.js → ConfigActionCameraControl-Biu5BwNu.js} +1 -1
  17. package/dist/interface/assets/{ConfigActionDelay-nDK4i-AL.js → ConfigActionDelay-CK5j4XLw.js} +1 -1
  18. package/dist/interface/assets/{ConfigActionHttp-DX-vapgv.js → ConfigActionHttp-Dtvi3jZB.js} +1 -1
  19. package/dist/interface/assets/{ConfigActionImageInput-CS7U7BsI.js → ConfigActionImageInput-Dh0A20j9.js} +1 -1
  20. package/dist/interface/assets/{ConfigActionMqtt-82swCx_F.js → ConfigActionMqtt-DwZdnDlb.js} +1 -1
  21. package/dist/interface/assets/{ConfigActionNotification-t-1zN_1y.js → ConfigActionNotification-BVqYxGu8.js} +1 -1
  22. package/dist/interface/assets/{ConfigActionNotificationControl-jz3ez2Uq.js → ConfigActionNotificationControl-BTdnQqox.js} +1 -1
  23. package/dist/interface/assets/{ConfigActionOutput-B6uJheX1.js → ConfigActionOutput-Dv745ppL.js} +1 -1
  24. package/dist/interface/assets/{ConfigActionPlugin-LyOIrZnv.js → ConfigActionPlugin-C9QdPDXC.js} +1 -1
  25. package/dist/interface/assets/{ConfigActionSensor-BTqc1inw.js → ConfigActionSensor-D17wASao.js} +1 -1
  26. package/dist/interface/assets/{ConfigActionSnapshot-DdPy_Ubu.js → ConfigActionSnapshot-CrbMLwuh.js} +1 -1
  27. package/dist/interface/assets/{ConfigActionVariable-Csf7jPOm.js → ConfigActionVariable-C0HobSMN.js} +1 -1
  28. package/dist/interface/assets/{ConfigConditionIfElse-BvzwZ70p.js → ConfigConditionIfElse-DsedkGhY.js} +1 -1
  29. package/dist/interface/assets/ConfigConditionSensorState-rRLbA2_b.js +1 -0
  30. package/dist/interface/assets/{ConfigConditionSwitch-DJU2JC-3.js → ConfigConditionSwitch-5nEVS-Oj.js} +1 -1
  31. package/dist/interface/assets/{ConfigConditionTime-BxE2CJMA.js → ConfigConditionTime-CieLn-sp.js} +1 -1
  32. package/dist/interface/assets/ConfigSensorValueInput-CRRM_aBz.js +1 -0
  33. package/dist/interface/assets/{ConfigTriggerDetection-DpC8V8K8.js → ConfigTriggerDetection-CMVgejZ3.js} +1 -1
  34. package/dist/interface/assets/{ConfigTriggerGeofence-DTzax7bc.js → ConfigTriggerGeofence-cMhyndiz.js} +1 -1
  35. package/dist/interface/assets/{ConfigTriggerManual-CtjnnQb1.js → ConfigTriggerManual-Bd9H0AfP.js} +1 -1
  36. package/dist/interface/assets/{ConfigTriggerMqtt-C7J22EMe.js → ConfigTriggerMqtt-BIv5Ca91.js} +1 -1
  37. package/dist/interface/assets/{ConfigTriggerSchedule-DnYDDz3F.js → ConfigTriggerSchedule-CzWWcnFW.js} +1 -1
  38. package/dist/interface/assets/ConfigTriggerSensor-C5lsyxsh.js +1 -0
  39. package/dist/interface/assets/{ConfigTriggerSystem-D1JulYVd.js → ConfigTriggerSystem-WipCRwTJ.js} +1 -1
  40. package/dist/interface/assets/{ConfigTriggerWebhook-BrKFtq7o.js → ConfigTriggerWebhook-Bl0O4RBX.js} +1 -1
  41. package/dist/interface/assets/Console-GtK0GVLX.js +1 -0
  42. package/dist/interface/assets/CuiAutomationRunsDialog-CUPBuq_J.js +1 -0
  43. package/dist/interface/assets/CuiBottomSheet-DQNpk0mh.js +1 -0
  44. package/dist/interface/assets/{CuiBottomSheet-C_1_moNo.js → CuiBottomSheet-K19nZQiG.js} +1 -1
  45. package/dist/interface/assets/CuiCameraPipCard-e3_uYELi.js +1 -0
  46. package/dist/interface/assets/CuiCameraRecordings-CPAMltfx.js +1 -0
  47. package/dist/interface/assets/CuiCameraRecordings-fB3X6kad.css +1 -0
  48. package/dist/interface/assets/{CuiCameraShares-XwN5kuC7.js → CuiCameraShares-BTn5ys6X.js} +1 -1
  49. package/dist/interface/assets/{CuiCameraTable-BeeHLaiQ.js → CuiCameraTable-DYvQ-GCz.js} +2 -2
  50. package/dist/interface/assets/{CuiConsole-B7R7U9UZ.js → CuiConsole-C4PawCou.js} +2 -2
  51. package/dist/interface/assets/{CuiDataTable-CQhCu0px.js → CuiDataTable-CORQOWsf.js} +1 -1
  52. package/dist/interface/assets/CuiLightControl-BYkQ8Ue3.js +1 -0
  53. package/dist/interface/assets/CuiList-BgZBIhXP.js +1 -0
  54. package/dist/interface/assets/CuiMarkdownContent-CCdOW_TM.js +1 -0
  55. package/dist/interface/assets/CuiMarkdownContent-ChezqgI1.js +1 -0
  56. package/dist/interface/assets/{CuiPluginCard-rkhmuumi.css → CuiPluginCard-C3ANAXSI.css} +1 -1
  57. package/dist/interface/assets/CuiPluginCard-C91rKOge.js +2 -0
  58. package/dist/interface/assets/{CuiPluginCategoryChip-JkdbQU4X.js → CuiPluginCategoryChip-B_Zy4B42.js} +1 -1
  59. package/dist/interface/assets/{CuiPluginOAuthButton-LYMFfb3v.js → CuiPluginOAuthButton-IXGedGWs.js} +2 -2
  60. package/dist/interface/assets/{CuiPluginTrustBadge-sZF0UKMD.js → CuiPluginTrustBadge-DTfM8Jjo.js} +1 -1
  61. package/dist/interface/assets/{CuiQRCode-B4ysluWR.js → CuiQRCode-D5vwhyuQ.js} +1 -1
  62. package/dist/interface/assets/CuiRecordingsGrid-Sv3uyj9a.css +1 -0
  63. package/dist/interface/assets/CuiRecordingsGrid-yXEzhnc4.js +1 -0
  64. package/dist/interface/assets/CuiSchema-hK_tgUP9.js +1 -0
  65. package/dist/interface/assets/{CuiTopNavbarItem-rMsWME9B.js → CuiTopNavbarItem-DWLnn7Kh.js} +1 -1
  66. package/dist/interface/assets/Faces-DzwTi8P1.js +1 -0
  67. package/dist/interface/assets/FirstSteps-0ojmFGSr.js +1 -0
  68. package/dist/interface/assets/Instances-DvoFBGMx.js +1 -0
  69. package/dist/interface/assets/{Logs-8onUmCYX.js → Logs-Cii4oP8R.js} +2 -2
  70. package/dist/interface/assets/Menu-pvtuFKFM.js +1 -0
  71. package/dist/interface/assets/OAuthDeviceFlow-BZgtsIjF.js +1 -0
  72. package/dist/interface/assets/Plugin-BDqNeTCT.css +1 -0
  73. package/dist/interface/assets/Plugin-BKqpBWJy.js +1 -0
  74. package/dist/interface/assets/{PluginConsole-JFcH_ZW0.js → PluginConsole-BFsCogtB.js} +1 -1
  75. package/dist/interface/assets/PluginDetail-Dl0OM6me.js +2 -0
  76. package/dist/interface/assets/{PluginSchema-Gfn_csMP.js → PluginSchema-D45zblVz.js} +1 -1
  77. package/dist/interface/assets/PluginSearch-DdIcv9xA.js +1 -0
  78. package/dist/interface/assets/{PluginSearch-CLjLT9JT.css → PluginSearch-Dlzc-aJ3.css} +1 -1
  79. package/dist/interface/assets/PluginSearch-DxoQUW8M.js +2 -0
  80. package/dist/interface/assets/{PluginUpdateProgress-DaI9bwSV.js → PluginUpdateProgress-CsRGGH8J.js} +1 -1
  81. package/dist/interface/assets/Plugins-CGj8DSLJ.js +1 -0
  82. package/dist/interface/assets/Recordings-PojBH8L3.js +1 -0
  83. package/dist/interface/assets/SensorEdit-D2ChsNDL.js +1 -0
  84. package/dist/interface/assets/{SensorHistory-2TmYLaL4.js → SensorHistory-B6ZKgot4.js} +1 -1
  85. package/dist/interface/assets/Sensors-B-Qhfr5i.css +1 -0
  86. package/dist/interface/assets/Sensors-DyqWcB-G.js +2 -0
  87. package/dist/interface/assets/{Settings-8yG5ny5r.js → Settings-BFJO08mq.js} +1 -1
  88. package/dist/interface/assets/SettingsAccount-DREZwvce.js +1 -0
  89. package/dist/interface/assets/SettingsAccount-QxmP0dzI.js +1 -0
  90. package/dist/interface/assets/SettingsAppearance-BejKI3_C.js +1 -0
  91. package/dist/interface/assets/{SettingsAppearance-WQtOksbk.js → SettingsAppearance-_zvMUQvn.js} +1 -1
  92. package/dist/interface/assets/SettingsBackup-8HCwVmDA.js +1 -0
  93. package/dist/interface/assets/SettingsList-B4H786Cc.js +1 -0
  94. package/dist/interface/assets/SettingsMqtt-D7ajm1JA.js +1 -0
  95. package/dist/interface/assets/{SettingsNotifications-BVGmt0eF.js → SettingsNotifications-fDDuqryh.js} +2 -2
  96. package/dist/interface/assets/{SettingsPermissions-BPqDIjVt.js → SettingsPermissions-DYirYf1Z.js} +1 -1
  97. package/dist/interface/assets/SettingsRecordings-4NxpAbu5.js +1 -0
  98. package/dist/interface/assets/SettingsRemote-DOQkaNzp.js +1 -0
  99. package/dist/interface/assets/SettingsSystem-CVWkw449.js +2 -0
  100. package/dist/interface/assets/{SettingsUsers-BtT17FNe.js → SettingsUsers-Dc6L7Lt2.js} +1 -1
  101. package/dist/interface/assets/Terminal-BgVnN-2g.js +4 -0
  102. package/dist/interface/assets/{VariableInput-CkXZ00Gc.js → VariableInput-ZYn-Phl4.js} +1 -1
  103. package/dist/interface/assets/{VariableSuggestions-BD1kOG5f.js → VariableSuggestions-BnzdQP6R.js} +1 -1
  104. package/dist/interface/assets/VersionsHandler-BvKvGOlF.js +7 -0
  105. package/dist/interface/assets/{VirtualSensorCreate-DcwJ_w-l.js → VirtualSensorCreate-Dk_YYzxR.js} +1 -1
  106. package/dist/interface/assets/Workers-CjEzGjy8.js +2 -0
  107. package/dist/interface/assets/{account-CY80SLLf.js → account-DuSFtIHf.js} +1 -1
  108. package/dist/interface/assets/{alert-circle-pDGfnZ4K.js → alert-circle-C2AU59aR.js} +1 -1
  109. package/dist/interface/assets/{alert-outline-CeoXcnQc.js → alert-outline-GrD7-zHq.js} +1 -1
  110. package/dist/interface/assets/{api-Mny5Elfn.js → api-36pS71R2.js} +1 -1
  111. package/dist/interface/assets/api-CDvtqu1L.css +2 -0
  112. package/dist/interface/assets/api-DTFsk1zB.js +2 -0
  113. package/dist/interface/assets/{arrow-left-D9jDhvK5.js → arrow-left-C1N6U6kZ.js} +1 -1
  114. package/dist/interface/assets/{arrow-right-outline-DF7tkKYk.js → arrow-right-outline-C24f5mwe.js} +1 -1
  115. package/dist/interface/assets/{auth-9_Jjlsh0.js → auth-DYoO8jpd.js} +1 -1
  116. package/dist/interface/assets/automations-BOvDlvvx.js +1 -0
  117. package/dist/interface/assets/{back-filled-DUUGErMw.js → back-filled-DcBDBvvP.js} +1 -1
  118. package/dist/interface/assets/{bell-ring-DV73JIre.js → bell-ring-DSX81yd4.js} +1 -1
  119. package/dist/interface/assets/cameras.schema-BvnUX82v.js +1 -0
  120. package/dist/interface/assets/{cctv-jy5ROx0o.js → cctv-BA5DvNlE.js} +1 -1
  121. package/dist/interface/assets/{check-circle-FwoylV5-.js → check-circle-Do_mBN_A.js} +1 -1
  122. package/dist/interface/assets/{chevron-down-umZ7i0mG.js → chevron-down-D111daTn.js} +1 -1
  123. package/dist/interface/assets/{clock-outline-CbvOAMhO.js → clock-outline-DF1wLNzs.js} +1 -1
  124. package/dist/interface/assets/{close-CtaDF28n.js → close-BNAWPz0y.js} +1 -1
  125. package/dist/interface/assets/{close-circle-FZ8IxGd4.js → close-circle-zhDWvz98.js} +1 -1
  126. package/dist/interface/assets/{cloud-check-CFSukfAF.js → cloud-check-pUK1Fpt9.js} +1 -1
  127. package/dist/interface/assets/cloudHandoff-DNKMEHOI.js +1 -0
  128. package/dist/interface/assets/{config-BZphegxi.js → config-DTGhJmsj.js} +1 -1
  129. package/dist/interface/assets/{copy-CFA_pDRv.js → copy-BPT84cDt.js} +1 -1
  130. package/dist/interface/assets/{cube-scan-DEuMi23T.js → cube-scan-DOe6W9mW.js} +1 -1
  131. package/dist/interface/assets/{delete-921w_nKy.js → delete-BF6keuqy.js} +1 -1
  132. package/dist/interface/assets/{deployed-code-update-CYS6eKfa.js → deployed-code-update-xHE-blDN.js} +1 -1
  133. package/dist/interface/assets/{dist-BwEXwXSw.js → dist-Yc5s0_JB.js} +1 -1
  134. package/dist/interface/assets/{download-C-LzNRmM.js → download-BCPfm6aN.js} +1 -1
  135. package/dist/interface/assets/esm-B3yVlCMw.js +1 -0
  136. package/dist/interface/assets/esm-BKQ7CQK7.js +1 -0
  137. package/dist/interface/assets/esm-BiSE05P9.js +1 -0
  138. package/dist/interface/assets/esm-BoPthGAl.js +1 -0
  139. package/dist/interface/assets/esm-C2ALrdyx.js +1 -0
  140. package/dist/interface/assets/esm-CKEGzys4.js +1 -0
  141. package/dist/interface/assets/esm-CctiCHtK.js +1 -0
  142. package/dist/interface/assets/esm-Cqq81lnk.js +1 -0
  143. package/dist/interface/assets/esm-CyrLQTu0.js +1 -0
  144. package/dist/interface/assets/esm-D6O-eZYo.js +1 -0
  145. package/dist/interface/assets/esm-DG1f0qwo.js +1 -0
  146. package/dist/interface/assets/esm-DGegIZMF.js +1 -0
  147. package/dist/interface/assets/esm-JGwpHVqo.js +1 -0
  148. package/dist/interface/assets/esm-TRigYTsA.js +1 -0
  149. package/dist/interface/assets/{eye-off-DESV3QdF.js → eye-off-CaRq7Ks2.js} +1 -1
  150. package/dist/interface/assets/{flowSchema-_RiPAgMv.js → flowSchema-zo1H4tnP.js} +1 -1
  151. package/dist/interface/assets/{history-60iCpGvQ.js → history-SuH8IHAj.js} +1 -1
  152. package/dist/interface/assets/{home-w5iY2RUg.js → home-CUykMSBW.js} +1 -1
  153. package/dist/interface/assets/{information-outline-CvBsGtDu.js → information-outline-BQDq8w2t.js} +1 -1
  154. package/dist/interface/assets/{lightbulb-outline-DLrnCPG5.js → lightbulb-outline-ClK17CO6.js} +1 -1
  155. package/dist/interface/assets/main-CcvCf5qj.js +3 -0
  156. package/dist/interface/assets/{main-DJb49Tjp.css → main-XQ5Vahbs.css} +1 -1
  157. package/dist/interface/assets/{microphone-DUVI-s2_.js → microphone-C0weJY9W.js} +1 -1
  158. package/dist/interface/assets/minus-RI3VlDe8.js +1 -0
  159. package/dist/interface/assets/mqtt-CYc8_9pb.js +1 -0
  160. package/dist/interface/assets/native-B01iGjCh.js +1 -0
  161. package/dist/interface/assets/native-D381pxlG.js +1 -0
  162. package/dist/interface/assets/{nodeDefinitions-BecZ8I2Q.js → nodeDefinitions-DQQlFmPN.js} +1 -1
  163. package/dist/interface/assets/{notifications-CK6XQBF-.js → notifications-cHS8-1HN.js} +1 -1
  164. package/dist/interface/assets/{pencil-outline-BrOrbuzc.js → pencil-outline-D7aD4cCo.js} +1 -1
  165. package/dist/interface/assets/plugin-W20ihuog.js +1 -0
  166. package/dist/interface/assets/plugins-CaKErv4E.js +1 -0
  167. package/dist/interface/assets/{plus-Dd-XLT76.js → plus-CA5o30dE.js} +1 -1
  168. package/dist/interface/assets/{plus-CL6KSxf8.js → plus-DHwFyXkb.js} +1 -1
  169. package/dist/interface/assets/{power-lCbm_7y7.js → power-C9UIp2oO.js} +1 -1
  170. package/dist/interface/assets/{ring-resize-CEqUkpxT.js → ring-resize-DkY5EgVl.js} +1 -1
  171. package/dist/interface/assets/{round-alt-arrow-left-bold-CwaLYdW5.js → round-alt-arrow-left-bold-BxX4ufd0.js} +1 -1
  172. package/dist/interface/assets/{round-restart-alt-BFgY3k77.js → round-restart-alt-DPYbDt-x.js} +1 -1
  173. package/dist/interface/assets/{search-CT2BLw7G.js → search-BZkSqZO5.js} +1 -1
  174. package/dist/interface/assets/sensorIcons-DepqfSoA.js +1 -0
  175. package/dist/interface/assets/sensors-CMpbwMO4.js +1 -0
  176. package/dist/interface/assets/{server-BSYs0zoo.js → server-C-WV93FX.js} +1 -1
  177. package/dist/interface/assets/{settings-CzS4dvIO.js → settings-BUEZ5iRE.js} +1 -1
  178. package/dist/interface/assets/{source-branch-C6p1G3a9.js → source-branch-ztDB0e13.js} +1 -1
  179. package/dist/interface/assets/{table-2-line-_VC4NuFA.js → table-2-line-B-z0xvbG.js} +1 -1
  180. package/dist/interface/assets/{theme-Dr_YO8-0.js → theme-BkwBz73p.js} +1 -1
  181. package/dist/interface/assets/{trash-2-DcOYT3oH.js → trash-2-DMMlSPXn.js} +1 -1
  182. package/dist/interface/assets/{trash-can-outline-cphfB8Jh.js → trash-can-outline-DLKniIWM.js} +1 -1
  183. package/dist/interface/assets/{trash-fill-CRBaUdPn.js → trash-fill-DevIK050.js} +1 -1
  184. package/dist/interface/assets/{trash2-CvhB8xOW.js → trash2-BLScx4HX.js} +1 -1
  185. package/dist/interface/assets/{types-3mdj4rRK.js → types-Cko7VOxd.js} +1 -1
  186. package/dist/interface/assets/types-ClTvDPjn.js +1 -0
  187. package/dist/interface/assets/{types-YwmhC3Ej.js → types-vaT6wuY0.js} +1 -1
  188. package/dist/interface/assets/{upload-DeN3O-ua.js → upload-ClkX9wUX.js} +1 -1
  189. package/dist/interface/assets/{useAppVersion-UIA6seZv.js → useAppVersion-V1S18l98.js} +1 -1
  190. package/dist/interface/assets/useBackupRestore-BZ73vHrV.js +1 -0
  191. package/dist/interface/assets/{useCameraOptions-Dx-zyqdH.js → useCameraOptions-o1hYGLbC.js} +1 -1
  192. package/dist/interface/assets/{useElectron-BXVcamD0.js → useElectron-3ZJLtRk3.js} +1 -1
  193. package/dist/interface/assets/{useLogsSocket-DSxzAvQF.js → useLogsSocket-DDgnQ_Dk.js} +1 -1
  194. package/dist/interface/assets/{usePermissions-B_C-zX5H.js → usePermissions-BWlj5SzG.js} +1 -1
  195. package/dist/interface/assets/{usePluginUpdates-QU3U82S_.js → usePluginUpdates-DI1p2NMc.js} +1 -1
  196. package/dist/interface/assets/{useServerRestart-BxDBO7k-.js → useServerRestart-D_ASBw_0.js} +1 -1
  197. package/dist/interface/assets/{useStreamStatus-DY4NM_Ua.js → useStreamStatus-BQJIFFLv.js} +1 -1
  198. package/dist/interface/assets/useUpdateChannel-CyLSUSAY.js +1 -0
  199. package/dist/interface/assets/useUserOptions-Ds1Ybn7N.js +1 -0
  200. package/dist/interface/assets/{variable-oLSsiEtj.js → variable-CCMnQpL2.js} +1 -1
  201. package/dist/interface/assets/{vendor-JQXDMBA-.js → vendor-BaiDFVEr.js} +17 -16
  202. package/dist/interface/assets/vendor-cameraui-CQTIVF_m.js +2326 -0
  203. package/dist/interface/assets/{vendor-capacitor-CDwgXF4b.js → vendor-capacitor-4nn-eF9U.js} +2 -2
  204. package/dist/interface/assets/{vendor-chart-KrNcA52y.js → vendor-chart-DtwjR6yw.js} +1 -1
  205. package/dist/interface/assets/vendor-core-DDtZhtY9.js +1 -0
  206. package/dist/interface/assets/{vendor-dnd-Jch9IvL6.js → vendor-dnd-ChrDrMuz.js} +1 -1
  207. package/dist/interface/assets/{vendor-draggabilly-Cn-knCpG.js → vendor-draggabilly-DSeIE_bQ.js} +1 -1
  208. package/dist/interface/assets/{vendor-markdown-BhFLJolW.js → vendor-markdown--U0EK8HV.js} +1 -1
  209. package/dist/interface/assets/{vendor-primevue-C0acGg0Y.js → vendor-primevue-DE-f4Z5f.js} +76 -76
  210. package/dist/interface/assets/{vendor-vueflow-DQrTmoNS.js → vendor-vueflow-CLJNLJXc.js} +1 -1
  211. package/dist/interface/assets/web-BNRwhIOt.js +1 -0
  212. package/dist/interface/assets/web-BPkOXv4d.js +1 -0
  213. package/dist/interface/assets/web-BZIx_2d3.js +1 -0
  214. package/dist/interface/assets/web-BjKL51lK-BwChM7zd.js +1 -0
  215. package/dist/interface/assets/web-BkmtZjSt.js +1 -0
  216. package/dist/interface/assets/web-C6RgriWz.js +1 -0
  217. package/dist/interface/assets/web-CQFMLa0a.js +1 -0
  218. package/dist/interface/assets/web-CZGnd6VE.js +1 -0
  219. package/dist/interface/assets/web-Cfzay11X.js +1 -0
  220. package/dist/interface/assets/web-DAgBwKL-.js +1 -0
  221. package/dist/interface/assets/web-DgVHh5ek.js +1 -0
  222. package/dist/interface/assets/web-DlSXwZBR.js +1 -0
  223. package/dist/interface/assets/web-eDYxVGH7.js +1 -0
  224. package/dist/interface/assets/web-h4k3EoRQ.js +1 -0
  225. package/dist/interface/assets/{webhook-CMAB4nTl.js → webhook-DQiZUPv8.js} +1 -1
  226. package/dist/interface/assets/workbox-window.prod.es5-CcJiPjAS.js +1 -0
  227. package/dist/interface/assets/{zoom-in-STm8SNt2.js → zoom-in-Du1IB9oA.js} +1 -1
  228. package/dist/interface/index.html +42 -41
  229. package/dist/interface/sw.js +1 -1
  230. package/dist/server/package.json +14 -14
  231. package/dist/server/requirements.txt +2 -2
  232. package/dist/server/src/_camera_ui_tools/camera_ui_sdk/__init__.py +6 -0
  233. package/dist/server/src/_camera_ui_tools/camera_ui_sdk/camera/__init__.py +0 -2
  234. package/dist/server/src/_camera_ui_tools/camera_ui_sdk/camera/events.py +11 -47
  235. package/dist/server/src/_camera_ui_tools/camera_ui_sdk/camera/frames.py +2 -4
  236. package/dist/server/src/_camera_ui_tools/camera_ui_sdk/internal/sensor_rpc.py +6 -0
  237. package/dist/server/src/_camera_ui_tools/camera_ui_sdk/plugin/contract.py +1 -1
  238. package/dist/server/src/_camera_ui_tools/camera_ui_sdk/plugin/notifier.py +7 -0
  239. package/dist/server/src/_camera_ui_tools/camera_ui_sdk/sensor/base.py +18 -1
  240. package/dist/server/src/_camera_ui_tools/camera_ui_sdk/sensor/classifier.py +14 -8
  241. package/dist/server/src/_camera_ui_tools/camera_ui_sdk/sensor/face.py +23 -7
  242. package/dist/server/src/_camera_ui_tools/camera_ui_sdk/sensor/license_plate.py +23 -7
  243. package/dist/server/src/_camera_ui_tools/camera_ui_sdk/storage/__init__.py +60 -2
  244. package/dist/server/src/api/controllers/automations.controller.d.ts +3 -1
  245. package/dist/server/src/api/controllers/automations.controller.js +27 -0
  246. package/dist/server/src/api/controllers/automations.controller.js.map +1 -1
  247. package/dist/server/src/api/controllers/cameras.controller.d.ts +3 -2
  248. package/dist/server/src/api/controllers/cameras.controller.js +26 -1
  249. package/dist/server/src/api/controllers/cameras.controller.js.map +1 -1
  250. package/dist/server/src/api/controllers/instances.controller.d.ts +2 -1
  251. package/dist/server/src/api/controllers/instances.controller.js +9 -0
  252. package/dist/server/src/api/controllers/instances.controller.js.map +1 -1
  253. package/dist/server/src/api/controllers/nvr.controller.d.ts +0 -3
  254. package/dist/server/src/api/controllers/nvr.controller.js +8 -38
  255. package/dist/server/src/api/controllers/nvr.controller.js.map +1 -1
  256. package/dist/server/src/api/controllers/plugins.controller.d.ts +9 -2
  257. package/dist/server/src/api/controllers/plugins.controller.js +156 -99
  258. package/dist/server/src/api/controllers/plugins.controller.js.map +1 -1
  259. package/dist/server/src/api/controllers/sensors.controller.d.ts +3 -1
  260. package/dist/server/src/api/controllers/sensors.controller.js +31 -0
  261. package/dist/server/src/api/controllers/sensors.controller.js.map +1 -1
  262. package/dist/server/src/api/database/index.d.ts +3 -2
  263. package/dist/server/src/api/database/index.js +12 -2
  264. package/dist/server/src/api/database/index.js.map +1 -1
  265. package/dist/server/src/api/database/migrations/v2-0-50.js +2 -1
  266. package/dist/server/src/api/database/migrations/v2-0-50.js.map +1 -1
  267. package/dist/server/src/api/database/migrations/v2-1-1.d.ts +3 -0
  268. package/dist/server/src/api/database/migrations/v2-1-1.js +35 -0
  269. package/dist/server/src/api/database/migrations/v2-1-1.js.map +1 -0
  270. package/dist/server/src/api/database/migrations/v2-1-4.d.ts +3 -0
  271. package/dist/server/src/api/database/migrations/v2-1-4.js +32 -0
  272. package/dist/server/src/api/database/migrations/v2-1-4.js.map +1 -0
  273. package/dist/server/src/api/database/record-schemas.d.ts +3 -0
  274. package/dist/server/src/api/database/record-schemas.js +1 -0
  275. package/dist/server/src/api/database/record-schemas.js.map +1 -1
  276. package/dist/server/src/api/database/types.d.ts +5 -0
  277. package/dist/server/src/api/routes/automations.routes.js +23 -1
  278. package/dist/server/src/api/routes/automations.routes.js.map +1 -1
  279. package/dist/server/src/api/routes/cameras.routes.js +15 -3
  280. package/dist/server/src/api/routes/cameras.routes.js.map +1 -1
  281. package/dist/server/src/api/routes/instances.routes.js +12 -1
  282. package/dist/server/src/api/routes/instances.routes.js.map +1 -1
  283. package/dist/server/src/api/routes/plugins.routes.js +36 -2
  284. package/dist/server/src/api/routes/plugins.routes.js.map +1 -1
  285. package/dist/server/src/api/routes/sensors.routes.js +23 -1
  286. package/dist/server/src/api/routes/sensors.routes.js.map +1 -1
  287. package/dist/server/src/api/schemas/automations.schema.d.ts +11 -0
  288. package/dist/server/src/api/schemas/automations.schema.js +7 -0
  289. package/dist/server/src/api/schemas/automations.schema.js.map +1 -1
  290. package/dist/server/src/api/schemas/cameras.schema.d.ts +33 -24
  291. package/dist/server/src/api/schemas/cameras.schema.js +18 -5
  292. package/dist/server/src/api/schemas/cameras.schema.js.map +1 -1
  293. package/dist/server/src/api/schemas/config.schema.d.ts +1 -0
  294. package/dist/server/src/api/schemas/config.schema.js +1 -0
  295. package/dist/server/src/api/schemas/config.schema.js.map +1 -1
  296. package/dist/server/src/api/schemas/instances.schema.d.ts +4 -0
  297. package/dist/server/src/api/schemas/instances.schema.js +3 -0
  298. package/dist/server/src/api/schemas/instances.schema.js.map +1 -1
  299. package/dist/server/src/api/schemas/plugins.schema.d.ts +11 -0
  300. package/dist/server/src/api/schemas/plugins.schema.js +6 -0
  301. package/dist/server/src/api/schemas/plugins.schema.js.map +1 -1
  302. package/dist/server/src/api/schemas/sensors.schema.d.ts +11 -0
  303. package/dist/server/src/api/schemas/sensors.schema.js +7 -0
  304. package/dist/server/src/api/schemas/sensors.schema.js.map +1 -1
  305. package/dist/server/src/api/schemas/users.schema.d.ts +12 -0
  306. package/dist/server/src/api/schemas/users.schema.js +4 -0
  307. package/dist/server/src/api/schemas/users.schema.js.map +1 -1
  308. package/dist/server/src/api/services/auth.service.js +28 -23
  309. package/dist/server/src/api/services/auth.service.js.map +1 -1
  310. package/dist/server/src/api/services/automations.service.js +36 -36
  311. package/dist/server/src/api/services/automations.service.js.map +1 -1
  312. package/dist/server/src/api/services/backup.service.js +29 -26
  313. package/dist/server/src/api/services/backup.service.js.map +1 -1
  314. package/dist/server/src/api/services/backupScheduler.service.js +1 -2
  315. package/dist/server/src/api/services/backupScheduler.service.js.map +1 -1
  316. package/dist/server/src/api/services/cameras.service.js +222 -173
  317. package/dist/server/src/api/services/cameras.service.js.map +1 -1
  318. package/dist/server/src/api/services/instances.service.d.ts +7 -0
  319. package/dist/server/src/api/services/instances.service.js +17 -0
  320. package/dist/server/src/api/services/instances.service.js.map +1 -1
  321. package/dist/server/src/api/services/mqtt.service.js +1 -2
  322. package/dist/server/src/api/services/mqtt.service.js.map +1 -1
  323. package/dist/server/src/api/services/notifications.service.d.ts +1 -0
  324. package/dist/server/src/api/services/notifications.service.js +3 -0
  325. package/dist/server/src/api/services/notifications.service.js.map +1 -1
  326. package/dist/server/src/api/services/plugins.service.js +1 -1
  327. package/dist/server/src/api/services/plugins.service.js.map +1 -1
  328. package/dist/server/src/api/services/remote.service.js +26 -25
  329. package/dist/server/src/api/services/remote.service.js.map +1 -1
  330. package/dist/server/src/api/services/sensors.service.d.ts +1 -0
  331. package/dist/server/src/api/services/sensors.service.js +1 -0
  332. package/dist/server/src/api/services/sensors.service.js.map +1 -1
  333. package/dist/server/src/api/services/server.service.js +9 -7
  334. package/dist/server/src/api/services/server.service.js.map +1 -1
  335. package/dist/server/src/api/services/shares.service.js +19 -14
  336. package/dist/server/src/api/services/shares.service.js.map +1 -1
  337. package/dist/server/src/api/services/users.service.js +159 -105
  338. package/dist/server/src/api/services/users.service.js.map +1 -1
  339. package/dist/server/src/api/services/workers.service.d.ts +1 -0
  340. package/dist/server/src/api/services/workers.service.js +55 -45
  341. package/dist/server/src/api/services/workers.service.js.map +1 -1
  342. package/dist/server/src/api/types/index.d.ts +38 -5
  343. package/dist/server/src/api/types/index.js.map +1 -1
  344. package/dist/server/src/api/utils/bulk.d.ts +9 -0
  345. package/dist/server/src/api/utils/bulk.js +27 -0
  346. package/dist/server/src/api/utils/bulk.js.map +1 -0
  347. package/dist/server/src/api/utils/cert.js +8 -0
  348. package/dist/server/src/api/utils/cert.js.map +1 -1
  349. package/dist/server/src/api/websocket/nsp/server.js +1 -1
  350. package/dist/server/src/api/websocket/nsp/server.js.map +1 -1
  351. package/dist/server/src/automations/conditions/sensorState.js +9 -0
  352. package/dist/server/src/automations/conditions/sensorState.js.map +1 -1
  353. package/dist/server/src/camera/controller.d.ts +1 -1
  354. package/dist/server/src/camera/controller.js +12 -11
  355. package/dist/server/src/camera/controller.js.map +1 -1
  356. package/dist/server/src/camera/decoder/child.d.ts +1 -0
  357. package/dist/server/src/camera/decoder/child.js +14 -1
  358. package/dist/server/src/camera/decoder/child.js.map +1 -1
  359. package/dist/server/src/camera/decoder/debug/detection-record.d.ts +42 -0
  360. package/dist/server/src/camera/decoder/debug/detection-record.js +103 -0
  361. package/dist/server/src/camera/decoder/debug/detection-record.js.map +1 -0
  362. package/dist/server/src/camera/decoder/debug/perf-tracker.d.ts +20 -0
  363. package/dist/server/src/camera/decoder/debug/perf-tracker.js +82 -0
  364. package/dist/server/src/camera/decoder/debug/perf-tracker.js.map +1 -0
  365. package/dist/server/src/camera/decoder/detection-coordinator.d.ts +28 -6
  366. package/dist/server/src/camera/decoder/detection-coordinator.js +452 -76
  367. package/dist/server/src/camera/decoder/detection-coordinator.js.map +1 -1
  368. package/dist/server/src/camera/decoder/detection-pipeline.d.ts +7 -20
  369. package/dist/server/src/camera/decoder/detection-pipeline.js +67 -127
  370. package/dist/server/src/camera/decoder/detection-pipeline.js.map +1 -1
  371. package/dist/server/src/camera/decoder/event-manager.d.ts +42 -14
  372. package/dist/server/src/camera/decoder/event-manager.js +304 -217
  373. package/dist/server/src/camera/decoder/event-manager.js.map +1 -1
  374. package/dist/server/src/camera/decoder/event-thumbnailer.d.ts +5 -8
  375. package/dist/server/src/camera/decoder/event-thumbnailer.js +11 -21
  376. package/dist/server/src/camera/decoder/event-thumbnailer.js.map +1 -1
  377. package/dist/server/src/camera/decoder/frame-scaler.d.ts +2 -1
  378. package/dist/server/src/camera/decoder/frame-scaler.js +9 -0
  379. package/dist/server/src/camera/decoder/frame-scaler.js.map +1 -1
  380. package/dist/server/src/camera/decoder/moment-crop.d.ts +30 -0
  381. package/dist/server/src/camera/decoder/moment-crop.js +86 -0
  382. package/dist/server/src/camera/decoder/moment-crop.js.map +1 -0
  383. package/dist/server/src/camera/decoder/nvr-sink.d.ts +38 -0
  384. package/dist/server/src/camera/decoder/nvr-sink.js +36 -0
  385. package/dist/server/src/camera/decoder/nvr-sink.js.map +1 -0
  386. package/dist/server/src/camera/decoder/secondary-stage.d.ts +4 -2
  387. package/dist/server/src/camera/decoder/secondary-stage.js +58 -96
  388. package/dist/server/src/camera/decoder/secondary-stage.js.map +1 -1
  389. package/dist/server/src/camera/decoder/sources/analysis-source.d.ts +10 -0
  390. package/dist/server/src/camera/decoder/sources/analysis-source.js +2 -0
  391. package/dist/server/src/camera/decoder/sources/analysis-source.js.map +1 -0
  392. package/dist/server/src/camera/decoder/sources/{snapshot-source.d.ts → buffered-source.d.ts} +17 -5
  393. package/dist/server/src/camera/decoder/sources/{snapshot-source.js → buffered-source.js} +81 -24
  394. package/dist/server/src/camera/decoder/sources/buffered-source.js.map +1 -0
  395. package/dist/server/src/camera/decoder/sources/frame-source.d.ts +4 -7
  396. package/dist/server/src/camera/decoder/sources/frame-source.js +4 -7
  397. package/dist/server/src/camera/decoder/sources/frame-source.js.map +1 -1
  398. package/dist/server/src/camera/decoder/types.d.ts +1 -0
  399. package/dist/server/src/camera/decoder/types.js.map +1 -1
  400. package/dist/server/src/camera/decoder/worker.js +15 -3
  401. package/dist/server/src/camera/decoder/worker.js.map +1 -1
  402. package/dist/server/src/internal-bus.d.ts +1 -1
  403. package/dist/server/src/internal-bus.js.map +1 -1
  404. package/dist/server/src/main.js +1 -1
  405. package/dist/server/src/main.js.map +1 -1
  406. package/dist/server/src/manager/discoveryManager.js +0 -11
  407. package/dist/server/src/manager/discoveryManager.js.map +1 -1
  408. package/dist/server/src/manager/notificationManager.d.ts +1 -1
  409. package/dist/server/src/manager/notificationManager.js +60 -41
  410. package/dist/server/src/manager/notificationManager.js.map +1 -1
  411. package/dist/server/src/mqtt/bridge.d.ts +2 -0
  412. package/dist/server/src/mqtt/bridge.js +39 -35
  413. package/dist/server/src/mqtt/bridge.js.map +1 -1
  414. package/dist/server/src/plugins/nvr.d.ts +2 -0
  415. package/dist/server/src/plugins/nvr.js +17 -0
  416. package/dist/server/src/plugins/nvr.js.map +1 -0
  417. package/dist/server/src/plugins/runtime/node/proxy/sensorManager.js +1 -1
  418. package/dist/server/src/plugins/runtime/node/proxy/sensorManager.js.map +1 -1
  419. package/dist/server/src/plugins/runtime/python/storage.py +18 -1
  420. package/dist/server/src/plugins/runtime/python/store.py +7 -1
  421. package/dist/server/src/plugins/schema.d.ts +2 -1
  422. package/dist/server/src/plugins/schema.js +66 -6
  423. package/dist/server/src/plugins/schema.js.map +1 -1
  424. package/dist/server/src/plugins/store/storeFile.js +10 -2
  425. package/dist/server/src/plugins/store/storeFile.js.map +1 -1
  426. package/dist/server/src/remote/services/index.js +1 -1
  427. package/dist/server/src/remote/services/index.js.map +1 -1
  428. package/dist/server/src/rpc/interfaces/frameworker.d.ts +1 -0
  429. package/dist/server/src/rpc/interfaces/sensor.d.ts +2 -0
  430. package/dist/server/src/rpc/server.js +2 -0
  431. package/dist/server/src/rpc/server.js.map +1 -1
  432. package/dist/server/src/sensors/registry.js +7 -2
  433. package/dist/server/src/sensors/registry.js.map +1 -1
  434. package/dist/server/src/sensors/sensor.js +13 -1
  435. package/dist/server/src/sensors/sensor.js.map +1 -1
  436. package/dist/server/src/services/config/constants.js +1 -0
  437. package/dist/server/src/services/config/constants.js.map +1 -1
  438. package/dist/server/src/services/config/index.d.ts +5 -2
  439. package/dist/server/src/services/config/index.js +38 -5
  440. package/dist/server/src/services/config/index.js.map +1 -1
  441. package/dist/server/src/services/config/types.d.ts +4 -0
  442. package/dist/server/src/utils/path.d.ts +1 -0
  443. package/dist/server/src/utils/path.js +33 -0
  444. package/dist/server/src/utils/path.js.map +1 -1
  445. package/dist/server/src/workers/capabilities/frame-decoding.js +1 -1
  446. package/dist/server/src/workers/capabilities/frame-decoding.js.map +1 -1
  447. package/package.json +14 -14
  448. package/dist/interface/assets/Automations-DBjwNb3F.js +0 -2
  449. package/dist/interface/assets/Camera-BfvpjkW3.js +0 -2
  450. package/dist/interface/assets/Camera-yUrhUGmO.css +0 -1
  451. package/dist/interface/assets/Camview-DArvg940.js +0 -1
  452. package/dist/interface/assets/Camview-mLCaY0ld.css +0 -1
  453. package/dist/interface/assets/Config-Ccp5Acpv.js +0 -2
  454. package/dist/interface/assets/ConfigConditionSensorState-lI9dzHiT.js +0 -1
  455. package/dist/interface/assets/ConfigSensorValueInput-DW4er753.js +0 -1
  456. package/dist/interface/assets/ConfigTriggerSensor-vhwPNmPj.js +0 -1
  457. package/dist/interface/assets/Console-C6yUdEaM.js +0 -1
  458. package/dist/interface/assets/CuiAutomationRunsDialog-C4i7y1Re.js +0 -1
  459. package/dist/interface/assets/CuiBottomSheet-C2zU_iyj.js +0 -1
  460. package/dist/interface/assets/CuiCameraPipCard-CZ-oDxzy.js +0 -1
  461. package/dist/interface/assets/CuiCameraRecordings-BHj7CUE7.css +0 -1
  462. package/dist/interface/assets/CuiCameraRecordings-mY_giLEi.js +0 -1
  463. package/dist/interface/assets/CuiLightControl-CEpcKss7.js +0 -1
  464. package/dist/interface/assets/CuiMarkdownContent-C2uBepC1.js +0 -1
  465. package/dist/interface/assets/CuiMarkdownContent-QxLR7_qs.js +0 -1
  466. package/dist/interface/assets/CuiPluginCard-1dSDwOCf.js +0 -2
  467. package/dist/interface/assets/CuiRecordingsGrid-COHg3ZCT.css +0 -1
  468. package/dist/interface/assets/CuiRecordingsGrid-CkwE3jcR.js +0 -1
  469. package/dist/interface/assets/CuiSchema-DKATswRc.js +0 -1
  470. package/dist/interface/assets/Faces-BeeZrFV-.js +0 -1
  471. package/dist/interface/assets/FirstSteps-DWT6Tt_T.js +0 -1
  472. package/dist/interface/assets/Instances-CJlFo8ni.js +0 -1
  473. package/dist/interface/assets/Menu-DP0aMICW.js +0 -1
  474. package/dist/interface/assets/OAuthDeviceFlow-CcSkntGk.js +0 -1
  475. package/dist/interface/assets/Plugin-8dbt_8iG.js +0 -1
  476. package/dist/interface/assets/Plugin-BLqyZrJP.css +0 -1
  477. package/dist/interface/assets/PluginDetail-C9dR9jrw.js +0 -2
  478. package/dist/interface/assets/PluginSearch-BVAtgBZs.js +0 -1
  479. package/dist/interface/assets/PluginSearch-HEf_6CrR.js +0 -2
  480. package/dist/interface/assets/Plugins-CQJhji6o.js +0 -1
  481. package/dist/interface/assets/Recordings-AD78njIA.js +0 -1
  482. package/dist/interface/assets/SensorEdit-rC02usEO.js +0 -1
  483. package/dist/interface/assets/Sensors-CFfII3-e.css +0 -1
  484. package/dist/interface/assets/Sensors-Vwr7MYz6.js +0 -2
  485. package/dist/interface/assets/SettingsAccount-BBsivYFf.js +0 -1
  486. package/dist/interface/assets/SettingsAccount-CN9Xcgt-.js +0 -1
  487. package/dist/interface/assets/SettingsAppearance-Qh1cw9iX.js +0 -1
  488. package/dist/interface/assets/SettingsBackup-DNDDU6a1.js +0 -1
  489. package/dist/interface/assets/SettingsList-tFKUMnsB.js +0 -1
  490. package/dist/interface/assets/SettingsMqtt-BYVV1Mew.js +0 -1
  491. package/dist/interface/assets/SettingsRecordings-B4DDJSKe.js +0 -1
  492. package/dist/interface/assets/SettingsRemote-Bib7kXto.js +0 -1
  493. package/dist/interface/assets/SettingsSystem-DIe7CSgH.js +0 -2
  494. package/dist/interface/assets/Terminal-DuJHIlLe.js +0 -4
  495. package/dist/interface/assets/VersionsHandler-D9sDkGXx.js +0 -7
  496. package/dist/interface/assets/Workers-fV_NEZ7U.js +0 -2
  497. package/dist/interface/assets/api-Draww2tC.js +0 -2
  498. package/dist/interface/assets/api-eELh8KCM.css +0 -2
  499. package/dist/interface/assets/automations-BfsdbSPC.js +0 -1
  500. package/dist/interface/assets/cameras.schema-DMY4SYte.js +0 -1
  501. package/dist/interface/assets/chevron-right-AhqYJOFy.js +0 -1
  502. package/dist/interface/assets/cloudHandoff-BQsDy9yp.js +0 -1
  503. package/dist/interface/assets/esm-B1LZs0VG.js +0 -1
  504. package/dist/interface/assets/esm-BB4SBaek.js +0 -1
  505. package/dist/interface/assets/esm-BGA8Ydne.js +0 -1
  506. package/dist/interface/assets/esm-BHI_KH7L.js +0 -1
  507. package/dist/interface/assets/esm-BQ0EuuZe.js +0 -1
  508. package/dist/interface/assets/esm-Bfb-tuKt.js +0 -1
  509. package/dist/interface/assets/esm-BzR_6ma5.js +0 -1
  510. package/dist/interface/assets/esm-CCIqNfsh.js +0 -1
  511. package/dist/interface/assets/esm-CSMN-8o1.js +0 -1
  512. package/dist/interface/assets/esm-CxWbrBxP.js +0 -1
  513. package/dist/interface/assets/esm-DBTrmJK6.js +0 -1
  514. package/dist/interface/assets/esm-DRswZUWf.js +0 -1
  515. package/dist/interface/assets/esm-Dk7gxPHs.js +0 -1
  516. package/dist/interface/assets/esm-P0RCkAtk.js +0 -1
  517. package/dist/interface/assets/main-CV7qCZ5i.js +0 -3
  518. package/dist/interface/assets/mqtt-BPfLOT7L.js +0 -1
  519. package/dist/interface/assets/native-Cr4dkfqy.js +0 -1
  520. package/dist/interface/assets/native-D1Vvlhds.js +0 -1
  521. package/dist/interface/assets/plugin-937qnq7E.js +0 -1
  522. package/dist/interface/assets/plugins-BU7TQh_f.js +0 -1
  523. package/dist/interface/assets/sensorIcons-DtJEfoU4.js +0 -1
  524. package/dist/interface/assets/sensors-DjgfMS8S.js +0 -1
  525. package/dist/interface/assets/types-BGMvANrz.js +0 -1
  526. package/dist/interface/assets/useBackupRestore-E3pVEOvA.js +0 -1
  527. package/dist/interface/assets/useCardSelection-DGPLn1ZH.js +0 -1
  528. package/dist/interface/assets/useUserOptions-BL53bECb.js +0 -1
  529. package/dist/interface/assets/vendor-cameraui-DojVuZ2L.js +0 -2326
  530. package/dist/interface/assets/vendor-core-ZDcIKAw9.js +0 -1
  531. package/dist/interface/assets/web-BQtDHNew.js +0 -1
  532. package/dist/interface/assets/web-BY9kjyTj.js +0 -1
  533. package/dist/interface/assets/web-BcQtDSat.js +0 -1
  534. package/dist/interface/assets/web-BgrRQzLO.js +0 -1
  535. package/dist/interface/assets/web-BjKL51lK-CJYmHsnY.js +0 -1
  536. package/dist/interface/assets/web-BxvsJylk.js +0 -1
  537. package/dist/interface/assets/web-C-3iwDhG.js +0 -1
  538. package/dist/interface/assets/web-C9XOwu07.js +0 -1
  539. package/dist/interface/assets/web-CPCxRDtw.js +0 -1
  540. package/dist/interface/assets/web-D0U5B2i2.js +0 -1
  541. package/dist/interface/assets/web-DtxjXJdS.js +0 -1
  542. package/dist/interface/assets/web-Duf-oV4e.js +0 -1
  543. package/dist/interface/assets/web-jy45nBi_.js +0 -1
  544. package/dist/interface/assets/web-vWx_-Iq5.js +0 -1
  545. package/dist/interface/assets/workbox-window.prod.es5-Dlqax_Po.js +0 -1
  546. package/dist/server/src/api/utils/moveFiles.d.ts +0 -4
  547. package/dist/server/src/api/utils/moveFiles.js +0 -37
  548. package/dist/server/src/api/utils/moveFiles.js.map +0 -1
  549. package/dist/server/src/camera/decoder/sources/snapshot-source.js.map +0 -1
  550. package/dist/server/src/camera/decoder/stationary-suppressor.d.ts +0 -38
  551. package/dist/server/src/camera/decoder/stationary-suppressor.js +0 -308
  552. package/dist/server/src/camera/decoder/stationary-suppressor.js.map +0 -1
@@ -15,24 +15,35 @@ import { DETECTION_SENSOR_TYPES } from '../../sensors/types.js';
15
15
  import { normalizeZone } from '../utils/filter.js';
16
16
  import { AudioDetectionLoop } from './audio-loop.js';
17
17
  import { CascadeManager } from './cascade-manager.js';
18
+ import { detectionRecord } from './debug/detection-record.js';
19
+ import { PerfTracker } from './debug/perf-tracker.js';
18
20
  import { DetectionPipeline } from './detection-pipeline.js';
19
21
  import { DwellManager } from './dwell-manager.js';
20
- import { DetectionEventManager } from './event-manager.js';
22
+ import { DetectionEventManager, MOMENT_RANK_ATTRIBUTE, MOMENT_RANK_OBJECT } from './event-manager.js';
21
23
  import { EventThumbnailer } from './event-thumbnailer.js';
22
24
  import { FrameScaler } from './frame-scaler.js';
25
+ import { directionBetween, directionOf, MOMENT_FORMATS, MOMENT_QUALITY, momentWindow, unionBox } from './moment-crop.js';
26
+ import { normalizePlateText } from './plate-vote.js';
23
27
  import { isVideoInputSpec, PluginRegistry } from './plugin-registry.js';
24
28
  import { PtzAutotracker } from './ptz/autotracker.js';
25
29
  import { ReconnectBackoff } from './reconnect-backoff.js';
26
30
  import { SecondaryStage } from './secondary-stage.js';
27
31
  import { FrameSource } from './sources/frame-source.js';
28
- import { StationarySuppressor } from './stationary-suppressor.js';
29
32
  import { DETECT_TIMEOUT_MS, ensureDetectionBoxes, MOTION_WIDTH_MAP } from './types.js';
33
+ const MOMENT_EVENTS = new Set(['objectEntered', 'objectWoke', 'objectRecovered', 'bestShotUpdated']);
34
+ const MOMENT_MOVING_SPEED = 0.05;
35
+ const MOMENT_ATTRIBUTE_MIN_AREA = 600;
30
36
  const DEFAULT_CASCADE_TIMEOUT = 10;
31
37
  const OBJECT_DWELL_SECONDS = 2;
32
38
  const SECONDARY_BBOX_TTL_MS = 2000;
33
39
  const CADENCE_MIN_SAMPLES = 5;
34
40
  const CADENCE_OUTLIER_BAND = 2.5;
35
41
  const CADENCE_OUTLIER_RESEED = 5;
42
+ const IDLE_TICK_MS = 200;
43
+ const ACTIVE_TICK_MS = 100;
44
+ const MOTION_INTERVAL_MS = 200;
45
+ const TICK_SLACK_MS = 20;
46
+ const MAIN_STREAM_HOLD_MS = 5000;
36
47
  let DetectionCoordinator = class DetectionCoordinator {
37
48
  config;
38
49
  proxy;
@@ -41,29 +52,38 @@ let DetectionCoordinator = class DetectionCoordinator {
41
52
  frameScaler;
42
53
  plugins = new PluginRegistry();
43
54
  pipeline;
44
- stationary;
45
55
  secondaries;
46
56
  thumbnailer;
47
57
  audioLoop;
48
58
  ptzAutotracker;
49
59
  eventManager;
50
60
  cascade = new CascadeManager();
61
+ worldSpans = new Set();
62
+ activeSensorTriggerTypes = new Map();
63
+ secondaryBboxSeen = new Map();
64
+ faceIdentities = new Set();
65
+ platesSeen = new Set();
66
+ classifierLabels = new Map();
67
+ feedingSensors = new Map();
51
68
  dwell = new DwellManager();
52
69
  videoBackoff = new ReconnectBackoff();
70
+ // debugging
71
+ perf = new PerfTracker();
72
+ hqUpgrade;
73
+ mainStreamActive = false;
74
+ idleSince = 0;
75
+ lastMotionAt = 0;
53
76
  loopRunning = false;
54
77
  loopPromise;
55
78
  videoStopPromise;
56
79
  adHocVideoLoop = false;
57
80
  processingExternalSecondary = false;
58
- cascadeUnsubscribe;
59
- dwellUnsubscribe;
60
- activeSensorTriggerTypes = new Map();
61
- secondaryBboxSeen = new Map();
62
- feedingSensors = new Set();
63
81
  lastObjectCallAt = 0;
64
82
  objectIntervalMs = 0;
65
83
  objectIntervalSamples = 0;
66
84
  objectIntervalOutliers = 0;
85
+ cascadeUnsubscribe;
86
+ dwellUnsubscribe;
67
87
  currentDetectionState = {};
68
88
  constructor(config, proxy, logger) {
69
89
  this.config = config;
@@ -72,7 +92,6 @@ let DetectionCoordinator = class DetectionCoordinator {
72
92
  const frameSourceConfig = {
73
93
  streamUrl: config.streamUrl,
74
94
  snapshotUrl: config.snapshotUrl,
75
- fps: this.config.frameWorkerSettings.fps,
76
95
  decoder: this.config.frameWorkerSettings.decoder,
77
96
  };
78
97
  if (config.controllerSnapshotSourceId) {
@@ -88,13 +107,18 @@ let DetectionCoordinator = class DetectionCoordinator {
88
107
  this.frameSource = new FrameSource(frameSourceConfig, logger);
89
108
  this.frameScaler = new FrameScaler(null, logger);
90
109
  this.pipeline = new DetectionPipeline(config.zones, config.detectionSettings);
91
- this.stationary = new StationarySuppressor(logger);
92
110
  this.secondaries = new SecondaryStage(this, this.plugins, this.pipeline, this.frameScaler, this.proxy, logger);
93
111
  if (config.lines.length > 0) {
94
112
  this.pipeline.updateLines(config.lines, this.videoAspectRatio);
95
113
  }
96
114
  this.eventManager = new DetectionEventManager(config.cameraId, this.proxy, this.logger);
115
+ this.eventManager.updateNvrRpc(config.nvrRpc);
97
116
  this.eventManager.onEventEnd(() => this.handleEventEnded());
117
+ this.eventManager.onSegmentClosed(() => {
118
+ if (!this.dwell.hasActive() && this.worldSpans.size === 0) {
119
+ this.eventManager.forceEndActiveEvent();
120
+ }
121
+ });
98
122
  this.thumbnailer = new EventThumbnailer({
99
123
  frameSource: this.frameSource,
100
124
  frameScaler: this.frameScaler,
@@ -102,7 +126,19 @@ let DetectionCoordinator = class DetectionCoordinator {
102
126
  logger,
103
127
  decoder: this.config.frameWorkerSettings.decoder,
104
128
  }, config.availableSources);
105
- this.thumbnailer.sync(this.config.frameWorkerSettings.hqSnapshots === true);
129
+ this.thumbnailer.sync(this.mainStreamAnalysisWanted);
130
+ // debugging
131
+ detectionRecord.sources({
132
+ roles: config.availableSources?.map((s) => s.role),
133
+ mainStreamAnalysis: this.config.frameWorkerSettings.mainStreamAnalysis === true,
134
+ hasMainStream: this.thumbnailer.hasMainStream,
135
+ cascade: this.cascadeEnabled,
136
+ cascadeTimeout: this.cascadeTimeoutSeconds,
137
+ motionTimeout: this.config.detectionSettings.motion.timeout,
138
+ audioTimeout: this.config.detectionSettings.audio.timeout,
139
+ suppressStatic: this.config.detectionSettings.object.suppressStatic ?? true,
140
+ motionResolution: this.motionResolution,
141
+ });
106
142
  this.audioLoop = new AudioDetectionLoop({
107
143
  cameraId: config.cameraId,
108
144
  getPlugin: () => this.plugins.get(SensorType.Audio),
@@ -120,11 +156,9 @@ let DetectionCoordinator = class DetectionCoordinator {
120
156
  });
121
157
  this.cascadeUnsubscribe = this.cascade.onChange((event) => {
122
158
  if (event.type === 'activated') {
123
- this.pipeline.setReidHitCounterMax(this.cascadeTimeoutSeconds * this.targetFps);
124
159
  this.startAdHocVideoLoopIfNeeded();
125
160
  }
126
161
  else {
127
- this.pipeline.setReidHitCounterMax(0);
128
162
  this.stopAdHocVideoLoopIfIdle();
129
163
  this.handleCascadeDeactivated();
130
164
  }
@@ -146,7 +180,8 @@ let DetectionCoordinator = class DetectionCoordinator {
146
180
  this.writeSensorProperties(event.sensorId, { detected: false, blocked: false });
147
181
  }
148
182
  this.activeSensorTriggerTypes.delete(event.sensorId);
149
- if (!this.dwell.hasActive()) {
183
+ this.eventManager.processResults(this.buildSnapshot());
184
+ if (!this.dwell.hasActive() && this.worldSpans.size === 0 && !this.eventManager.hasActiveSegment()) {
150
185
  this.eventManager.forceEndActiveEvent();
151
186
  }
152
187
  }
@@ -176,7 +211,11 @@ let DetectionCoordinator = class DetectionCoordinator {
176
211
  }
177
212
  updateFrameWorkerSettings(settings) {
178
213
  this.config.frameWorkerSettings = settings;
179
- this.thumbnailer.sync(settings.hqSnapshots === true);
214
+ this.thumbnailer.sync(this.mainStreamAnalysisWanted);
215
+ }
216
+ updateNvrRpc(namespace) {
217
+ this.config.nvrRpc = namespace;
218
+ this.eventManager.updateNvrRpc(namespace);
180
219
  }
181
220
  updateInterfaceSettings(settings) {
182
221
  this.config.interfaceSettings = settings;
@@ -196,12 +235,11 @@ let DetectionCoordinator = class DetectionCoordinator {
196
235
  this.eventManager.destroy();
197
236
  this.adHocVideoLoop = false;
198
237
  this.frameScaler.dispose();
199
- this.pipeline.cleanup();
200
238
  this.currentDetectionState = {};
201
239
  }
202
240
  async onSensorAdded(sensor) {
203
241
  if (DETECTION_SENSOR_TYPES.has(sensor.sensorType)) {
204
- this.feedingSensors.add(sensor.sensorId);
242
+ this.feedingSensors.set(sensor.sensorId, sensor.sensorType);
205
243
  }
206
244
  if (DETECTION_SENSOR_TYPES.has(sensor.sensorType) && sensor.requiresFrames) {
207
245
  await this.registerDetectionPluginInternal(sensor);
@@ -215,8 +253,22 @@ let DetectionCoordinator = class DetectionCoordinator {
215
253
  }
216
254
  }
217
255
  async onSensorRemoved(sensorId) {
218
- if (this.feedingSensors.delete(sensorId)) {
219
- this.writeSensorProperties(sensorId, { detected: false, detections: [] });
256
+ this.classifierLabels.delete(sensorId);
257
+ const sensorType = this.feedingSensors.get(sensorId);
258
+ if (sensorType === SensorType.Face)
259
+ this.faceIdentities.clear();
260
+ if (sensorType === SensorType.LicensePlate)
261
+ this.platesSeen.clear();
262
+ if (sensorType !== undefined && this.feedingSensors.delete(sensorId)) {
263
+ // a sensor removed mid-segment misses the cascade-end clear, so the
264
+ // recognized lists must reset here or they survive the re-register
265
+ this.writeSensorProperties(sensorId, {
266
+ detected: false,
267
+ detections: [],
268
+ ...(sensorType === SensorType.Face ? { identities: [] } : {}),
269
+ ...(sensorType === SensorType.LicensePlate ? { plates: [] } : {}),
270
+ ...(sensorType === SensorType.Classifier ? { labels: [] } : {}),
271
+ });
220
272
  }
221
273
  await this.removeDetectionPluginBySensor(sensorId);
222
274
  this.ptzAutotracker.unbind(sensorId);
@@ -264,7 +316,7 @@ let DetectionCoordinator = class DetectionCoordinator {
264
316
  this.ingestAssistedObjects(sensorId, objects);
265
317
  // processExternal only adapts the shape, external boxes get no real tracking
266
318
  const objectDetections = this.pipeline.processExternal(objects.detections);
267
- await this.runSecondariesAndThumbnails(peeked.frame, objectDetections, results);
319
+ await this.runSecondariesAndThumbnails({ frame: peeked.frame, scaler: this.frameScaler, isMainStream: false }, objectDetections, results);
268
320
  this.ingestResultsForAllSecondaries(results);
269
321
  const snapshot = this.buildSnapshot();
270
322
  if (results.thumbnails && results.thumbnails.length > 0) {
@@ -288,7 +340,7 @@ let DetectionCoordinator = class DetectionCoordinator {
288
340
  // real boxes: crop the object like the frame pipeline, so face and
289
341
  // plate secondaries run on the subject instead of the whole scene
290
342
  const objectDetections = this.pipeline.processExternal(objects.detections);
291
- await this.runSecondariesAndThumbnails(fetched.frame, objectDetections, results);
343
+ await this.runSecondariesAndThumbnails({ frame: fetched.frame, scaler: this.frameScaler, isMainStream: false }, objectDetections, results);
292
344
  this.ingestResultsForAllSecondaries(results);
293
345
  const snapshot = this.buildSnapshot();
294
346
  if (results.thumbnails && results.thumbnails.length > 0) {
@@ -297,11 +349,9 @@ let DetectionCoordinator = class DetectionCoordinator {
297
349
  this.eventManager.processResults(snapshot);
298
350
  }
299
351
  else {
300
- const objectDetections = this.pipeline.processExternal(objects.detections);
301
352
  const sceneJpeg = await this.secondaries.detectFullFrame(fetched.frame, results);
302
353
  try {
303
- // face/plate crops feed the segment attributes
304
- results.thumbnails = await this.secondaries.generateThumbnails(fetched.frame, this.frameScaler, false, objectDetections, results);
354
+ results.thumbnails = await this.secondaries.generateThumbnails(fetched.frame, this.frameScaler, results);
305
355
  }
306
356
  catch (error) {
307
357
  this.logger.error('Thumbnail generation error:', error);
@@ -356,7 +406,8 @@ let DetectionCoordinator = class DetectionCoordinator {
356
406
  }
357
407
  this.dwell.refresh(dwellKey, timeoutSeconds);
358
408
  if (action === 'activate' && this.cascadeEnabled) {
359
- this.cascade.triggerMomentary(this.cascadeTimeoutSeconds);
409
+ // trigger edges never repeat, the cascade covers the trigger's dwell
410
+ this.cascade.triggerMomentary(Math.max(timeoutSeconds, this.cascadeTimeoutSeconds));
360
411
  }
361
412
  this.eventManager.processResults(this.buildSnapshot());
362
413
  // no loop frame to encode from, fetch async (no-op if already captured)
@@ -377,6 +428,12 @@ let DetectionCoordinator = class DetectionCoordinator {
377
428
  hasPlugin(sensorType) {
378
429
  return this.plugins.has(sensorType);
379
430
  }
431
+ externalObjectSpanActive() {
432
+ const objectPlugin = this.plugins.get(SensorType.Object);
433
+ if (!objectPlugin || objectPlugin.requiresFrames)
434
+ return false;
435
+ return this.dwell.isActive(objectPlugin.sensorId);
436
+ }
380
437
  get cascadeEnabled() {
381
438
  return this.config.detectionSettings.cascadeDetection !== false;
382
439
  }
@@ -413,22 +470,26 @@ let DetectionCoordinator = class DetectionCoordinator {
413
470
  for (const plugin of this.plugins.getAll(SensorType.Classifier)) {
414
471
  clearTargets.push(plugin.sensorId);
415
472
  }
473
+ this.faceIdentities.clear();
474
+ this.platesSeen.clear();
475
+ this.classifierLabels.clear();
476
+ const faceSensorId = this.plugins.get(SensorType.Face)?.sensorId;
477
+ const plateSensorId = this.plugins.get(SensorType.LicensePlate)?.sensorId;
478
+ const classifierSensorIds = new Set(this.plugins.getAll(SensorType.Classifier).map((p) => p.sensorId));
416
479
  for (const sensorId of clearTargets) {
417
- this.writeSensorProperties(sensorId, { detected: false, detections: [] });
480
+ this.writeSensorProperties(sensorId, {
481
+ detected: false,
482
+ detections: [],
483
+ ...(sensorId === faceSensorId ? { identities: [] } : {}),
484
+ ...(sensorId === plateSensorId ? { plates: [] } : {}),
485
+ ...(classifierSensorIds.has(sensorId) ? { labels: [] } : {}),
486
+ });
418
487
  this.secondaryBboxSeen.delete(sensorId);
419
488
  }
420
489
  // segment ends here, the event itself continues while motion is active
421
490
  this.eventManager.processResults(this.buildSnapshot());
422
491
  }
423
492
  handleEventEnded() {
424
- if (this.config.detectionSettings.object.suppressStatic ?? true) {
425
- this.stationary.retainAcrossEvent((trackIds) => this.pipeline.retainTracks(trackIds));
426
- }
427
- else {
428
- this.pipeline.cleanup();
429
- this.stationary.clear();
430
- }
431
- this.stationary.resetEventState();
432
493
  this.activeSensorTriggerTypes.clear();
433
494
  this.currentDetectionState = {};
434
495
  }
@@ -451,15 +512,16 @@ let DetectionCoordinator = class DetectionCoordinator {
451
512
  };
452
513
  this.proxy.publish(NamespaceManager.sensorCameraViewNamespaces(this.config.cameraId).sensorWriteSubject, msg);
453
514
  }
454
- buildSnapshot() {
515
+ buildSnapshot(at = Date.now()) {
455
516
  const cs = this.currentDetectionState;
456
517
  return {
457
518
  hasCascadeTrigger: this.cascade.isActive,
519
+ hasOpenSpans: this.worldSpans.size > 0 || this.externalObjectSpanActive(),
458
520
  motion: cs.motion ? { detected: cs.motion.detected ?? false } : undefined,
459
521
  audio: cs.audio ? { detected: cs.audio.detected ?? false, detections: cs.audio.detections ?? [] } : undefined,
460
522
  cascadeTriggered: cs.cascadeTriggered,
461
523
  sensorTriggers: [...new Set(this.activeSensorTriggerTypes.values())],
462
- objects: cs.object?.detected ? this.stationary.excludeSealed(cs.object.detections) : [],
524
+ objects: cs.object?.detected ? cs.object.detections : [],
463
525
  faces: cs.face?.detections ?? [],
464
526
  faceEmbeddingModel: cs.faceEmbeddingModel,
465
527
  plates: cs.licensePlate?.detections ?? [],
@@ -472,7 +534,7 @@ let DetectionCoordinator = class DetectionCoordinator {
472
534
  clipEmbeddingModel: cs.clipEmbeddingModel,
473
535
  thumbnails: undefined,
474
536
  lineCrossings: cs.lineCrossings,
475
- timestamp: Date.now(),
537
+ timestamp: at,
476
538
  segmentTimeout: 10,
477
539
  expectedEndTime: this.dwell.maxExpiry(),
478
540
  detectionZones: this.getNormalizedDetectionZones(),
@@ -532,7 +594,6 @@ let DetectionCoordinator = class DetectionCoordinator {
532
594
  return properties;
533
595
  return { ...properties, detections: filtered, detected: filtered.length > 0 };
534
596
  }
535
- // PTZ-suppression gating happens upstream, callers decide what gets in here
536
597
  ingestDetectionResult(sensorType, sensorId, properties, pluginId) {
537
598
  if (sensorType === SensorType.Audio) {
538
599
  properties = this.applyAudioConfidence(properties);
@@ -543,7 +604,12 @@ let DetectionCoordinator = class DetectionCoordinator {
543
604
  const motionTimeout = this.config.detectionSettings.motion.timeout;
544
605
  this.dwell.refresh(sensorId, motionTimeout);
545
606
  if (this.cascadeEnabled) {
546
- this.cascade.triggerMomentary(this.cascadeTimeoutSeconds);
607
+ // a frame-based motion sensor re-arms on every motion frame, so its
608
+ // short tail is fine; an external sensor fires one edge and goes
609
+ // quiet, that edge must arm the cascade for the whole belief window
610
+ const framePlugin = this.plugins.get(SensorType.Motion);
611
+ const frameBased = framePlugin?.requiresFrames === true && framePlugin.sensorId === sensorId;
612
+ this.cascade.triggerMomentary(frameBased ? this.cascadeTimeoutSeconds : Math.max(motionTimeout, this.cascadeTimeoutSeconds));
547
613
  }
548
614
  }
549
615
  else if (sensorType === SensorType.Audio && detected) {
@@ -557,7 +623,7 @@ let DetectionCoordinator = class DetectionCoordinator {
557
623
  // the dwell bridges single missed frames; anchored stationary tracks
558
624
  // don't refresh it, so parked objects can't hold events open
559
625
  const detections = properties.detections ?? [];
560
- if (this.stationary.evaluate(detections)) {
626
+ if (detections.length > 0) {
561
627
  this.dwell.refresh(sensorId, OBJECT_DWELL_SECONDS);
562
628
  // a confirmed object re-arms the cascade like motion does: a time-based
563
629
  // motion sensor (ONVIF cool-down) must not blind detection and split
@@ -574,7 +640,6 @@ let DetectionCoordinator = class DetectionCoordinator {
574
640
  this.currentDetectionState.object.detected = false;
575
641
  this.currentDetectionState.object.detections = [];
576
642
  }
577
- this.stationary.logSuppressedOnce(detections);
578
643
  }
579
644
  }
580
645
  // dwell owns detected/blocked/lastTriggered for these types, a no-detection
@@ -711,8 +776,7 @@ let DetectionCoordinator = class DetectionCoordinator {
711
776
  for (const plugin of this.plugins.getAll(SensorType.Classifier)) {
712
777
  this.clearSecondaryBboxes(plugin.sensorId);
713
778
  }
714
- // image-space anchors don't survive a camera move, they re-form after
715
- this.stationary.dropForCameraMove();
779
+ this.pipeline.notifyCameraMove();
716
780
  }
717
781
  clearSecondaryBboxes(sensorId) {
718
782
  this.writeSensorProperties(sensorId, { detections: [] });
@@ -744,6 +808,9 @@ let DetectionCoordinator = class DetectionCoordinator {
744
808
  }
745
809
  this.logger.debug('Stopping video detection loop');
746
810
  this.loopRunning = false;
811
+ this.worldSpans.clear();
812
+ this.mainStreamActive = false;
813
+ this.idleSince = 0;
747
814
  const doStop = async () => {
748
815
  await this.frameSource.stop();
749
816
  await this.loopPromise;
@@ -776,27 +843,51 @@ let DetectionCoordinator = class DetectionCoordinator {
776
843
  try {
777
844
  await this.frameSource.start();
778
845
  this.frameScaler.updateHardwareContext(this.frameSource.hardwareContext);
846
+ // the hardware context exists only after start, re-evaluate the HQ session
847
+ this.thumbnailer.sync(this.mainStreamAnalysisWanted);
779
848
  this.logger.debug('Stream connected, processing frames...');
780
849
  this.videoBackoff.reset();
781
850
  let frameCount = 0;
782
851
  let lastFrameId = -1;
783
852
  while (this.loopRunning) {
853
+ const tickStart = Date.now();
784
854
  const snap = await this.frameSource.nextFrame(lastFrameId);
785
855
  if (!snap)
786
856
  break; // source ended (stop or EOF)
787
857
  lastFrameId = snap.id;
788
858
  frameCount++;
859
+ // motion always reads the low stream: switching its input resolution
860
+ // would reset the background model on every transition
861
+ const analysis = await this.acquireAnalysisFrame(snap.frame);
862
+ // debugging
863
+ detectionRecord.setFrame(analysis.isMainStream ? 'main' : 'low', analysis.frame.width, analysis.frame.height);
789
864
  try {
790
- await this.processRawFrame(snap.frame);
865
+ await this.processRawFrame(analysis, snap.frame);
791
866
  }
792
867
  finally {
793
868
  try {
869
+ if (this.hqUpgrade) {
870
+ this.hqUpgrade.frame[Symbol.dispose]?.();
871
+ this.hqUpgrade = undefined;
872
+ }
873
+ if (analysis.frame !== snap.frame)
874
+ analysis.frame[Symbol.dispose]?.();
794
875
  snap.frame[Symbol.dispose]?.();
795
876
  }
796
877
  catch {
797
878
  // best-effort
798
879
  }
799
880
  }
881
+ this.updateStreamState();
882
+ if (this.mainStreamActive)
883
+ this.perf.activeTicks++;
884
+ else
885
+ this.perf.idleTicks++;
886
+ this.perf.report(this.logger);
887
+ const remaining = (this.mainStreamActive ? ACTIVE_TICK_MS : IDLE_TICK_MS) - (Date.now() - tickStart);
888
+ if (remaining > 0)
889
+ await sleep(remaining);
890
+ this.perf.loopMs += Date.now() - tickStart;
800
891
  }
801
892
  const streamError = this.frameSource.lastError;
802
893
  await this.frameSource.stop();
@@ -825,25 +916,85 @@ let DetectionCoordinator = class DetectionCoordinator {
825
916
  this.frameScaler.clearCache();
826
917
  this.logger.debug('Detection loop ended');
827
918
  }
828
- async processRawFrame(rawFrame) {
919
+ get mainStreamAvailable() {
920
+ if (!this.thumbnailer.hasMainStream)
921
+ return false;
922
+ return this.mainStreamAnalysisWanted;
923
+ }
924
+ get mainStreamAnalysisWanted() {
925
+ return this.config.frameWorkerSettings.mainStreamAnalysis === true || this.frameSource.hardwareContext !== null;
926
+ }
927
+ async acquireAnalysisFrame(lowFrame) {
928
+ if (this.mainStreamActive) {
929
+ const t0 = Date.now();
930
+ try {
931
+ const main = await this.thumbnailer.acquireHqFrame(0);
932
+ if (main) {
933
+ this.perf.mainFrames++;
934
+ this.perf.decodeMs += Date.now() - t0;
935
+ return { frame: main.frame, scaler: main.scaler, isMainStream: true };
936
+ }
937
+ }
938
+ catch (error) {
939
+ this.logger.debug('Main stream frame unavailable:', error);
940
+ }
941
+ }
942
+ return { frame: lowFrame, scaler: this.frameScaler, isMainStream: false };
943
+ }
944
+ async acquireOpeningHqFrame() {
945
+ if (!this.mainStreamAvailable)
946
+ return undefined;
947
+ const t0 = Date.now();
948
+ try {
949
+ const main = await this.thumbnailer.acquireHqFrame(0);
950
+ if (main) {
951
+ this.perf.mainFrames++;
952
+ this.perf.decodeMs += Date.now() - t0;
953
+ return { frame: main.frame, scaler: main.scaler, isMainStream: true };
954
+ }
955
+ }
956
+ catch (error) {
957
+ this.logger.debug('HQ frame unavailable for the opening tick:', error);
958
+ }
959
+ return undefined;
960
+ }
961
+ updateStreamState() {
962
+ if (this.worldSpans.size > 0 || this.eventManager.hasActiveSegment()) {
963
+ this.idleSince = 0;
964
+ if (!this.mainStreamActive && this.mainStreamAvailable) {
965
+ this.mainStreamActive = true;
966
+ this.perf.switches++;
967
+ this.logger.debug('Analysis switched to the main stream');
968
+ }
969
+ return;
970
+ }
971
+ if (!this.mainStreamActive)
972
+ return;
973
+ if (this.idleSince === 0) {
974
+ this.idleSince = Date.now();
975
+ }
976
+ else if (Date.now() - this.idleSince >= MAIN_STREAM_HOLD_MS) {
977
+ this.mainStreamActive = false;
978
+ this.idleSince = 0;
979
+ this.perf.switches++;
980
+ this.logger.debug('Analysis back on the low-resolution stream');
981
+ }
982
+ }
983
+ async processRawFrame(analysis, motionRawFrame) {
829
984
  if (!this.loopRunning || !this.plugins.hasAny())
830
985
  return;
831
986
  try {
832
- await this.processDetection(rawFrame);
987
+ await this.processDetection(analysis, motionRawFrame);
833
988
  }
834
989
  catch (error) {
835
990
  this.logger.error('Detection processing error:', error);
836
991
  }
837
992
  }
838
- async processDetection(rawFrame) {
993
+ async processDetection(analysis, motionRawFrame) {
839
994
  const t0 = Date.now();
840
995
  let motionDetected = false;
841
996
  let objectDetections = [];
842
997
  const results = { timestamp: t0 };
843
- // keeps dead tracks from expiring during the cascade window
844
- if (this.cascade.isActive) {
845
- this.pipeline.refreshReid();
846
- }
847
998
  // while the PTZ repositions: motion and object keep running so the
848
999
  // background model and track ids survive the pan, but nothing below
849
1000
  // reaches dwell/events until the settle window ends
@@ -852,12 +1003,20 @@ let DetectionCoordinator = class DetectionCoordinator {
852
1003
  // object detection, not motion
853
1004
  const motionPlugin = this.plugins.get(SensorType.Motion);
854
1005
  if (motionPlugin?.requiresFrames) {
855
- const motionFrame = await this.scaleForMotion(rawFrame);
1006
+ // motion keeps its own rate, a background diff gains nothing from the active tick speed
1007
+ const motionDue = t0 - this.lastMotionAt >= MOTION_INTERVAL_MS - TICK_SLACK_MS;
1008
+ const motionScaleStart = Date.now();
1009
+ const motionFrame = motionDue ? await this.scaleForMotion(motionRawFrame) : undefined;
1010
+ if (motionDue)
1011
+ this.perf.scaleMs += Date.now() - motionScaleStart;
856
1012
  if (!this.loopRunning)
857
1013
  return;
858
1014
  if (motionFrame) {
1015
+ this.lastMotionAt = t0;
859
1016
  try {
1017
+ const motionInferStart = Date.now();
860
1018
  const result = await motionPlugin.proxy.detectMotion(motionFrame);
1019
+ this.perf.inferMs += Date.now() - motionInferStart;
861
1020
  if (!this.loopRunning)
862
1021
  return;
863
1022
  if (ptzSuppressed) {
@@ -899,12 +1058,16 @@ let DetectionCoordinator = class DetectionCoordinator {
899
1058
  const objectPlugin = this.plugins.get(SensorType.Object);
900
1059
  const shouldDetectObjects = objectPlugin?.requiresFrames === true && (ptzSuppressed || !this.cascadeEnabled || this.cascade.isActive);
901
1060
  if (shouldDetectObjects) {
902
- const objectFrame = await this.scaleForObject(rawFrame);
1061
+ const scaleStart = Date.now();
1062
+ const objectFrame = await this.scaleForObject(analysis.frame, analysis.scaler);
1063
+ this.perf.scaleMs += Date.now() - scaleStart;
903
1064
  if (!this.loopRunning)
904
1065
  return;
905
1066
  if (objectFrame) {
906
1067
  try {
1068
+ const inferStart = Date.now();
907
1069
  const result = await PromiseTimeout(objectPlugin.proxy.detectObjects(objectFrame.model), DETECT_TIMEOUT_MS, undefined, `Object detection timed out after ${DETECT_TIMEOUT_MS}ms`);
1070
+ this.perf.inferMs += Date.now() - inferStart;
908
1071
  if (!this.loopRunning)
909
1072
  return;
910
1073
  this.trackDetectionCadence();
@@ -912,14 +1075,26 @@ let DetectionCoordinator = class DetectionCoordinator {
912
1075
  // Kalman state; the pose delta keeps predictions stable across pans
913
1076
  const poseDelta = this.ptzAutotracker.consumePoseDelta();
914
1077
  const detected = FrameScaler.undoLetterbox(ensureDetectionBoxes(result.detections), objectFrame.geometry);
915
- const pipelineResult = this.pipeline.process(detected, objectFrame.tracking, poseDelta);
1078
+ const pipelineResult = this.pipeline.process(detected, poseDelta);
1079
+ // the tick that opens a span analysed the low stream (the switch lands
1080
+ // next tick), its picture work is worth a one-off HQ decode
1081
+ if (this.updateWorldSpans(pipelineResult) && !analysis.isMainStream) {
1082
+ this.hqUpgrade = await this.acquireOpeningHqFrame();
1083
+ }
1084
+ await this.captureMoments(pipelineResult, this.hqUpgrade ?? analysis, t0);
1085
+ // open spans and a lingering segment keep the cascade armed: the
1086
+ // world can only observe absence or a reappearance while it still
1087
+ // receives ticks
1088
+ if (this.cascadeEnabled && (this.worldSpans.size > 0 || this.eventManager.hasActiveSegment())) {
1089
+ this.cascade.triggerMomentary(this.cascadeTimeoutSeconds);
1090
+ }
916
1091
  // track id churn is invisible in the event log without this
917
1092
  if (pipelineResult.created.length > 0 || pipelineResult.removed.length > 0) {
918
1093
  const born = pipelineResult.created.map((id) => {
919
1094
  const t = pipelineResult.tracked.find((d) => d.trackId === id);
920
1095
  return `${t?.label ?? 'unknown'}#${id}`;
921
1096
  });
922
- const died = pipelineResult.removed.map((id) => `#${id}${this.stationary.isAnchored(id) ? ' (anchored!)' : ''}`);
1097
+ const died = pipelineResult.removed.map((id) => `#${id}`);
923
1098
  this.logger.trace(`[tracker] ${born.length ? `born: ${born.join(', ')}` : ''}${born.length && died.length ? ' — ' : ''}${died.length ? `died: ${died.join(', ')}` : ''}`);
924
1099
  }
925
1100
  // extrapolated (Kalman-only) tracks smooth single-frame misses in
@@ -974,7 +1149,11 @@ let DetectionCoordinator = class DetectionCoordinator {
974
1149
  if (!this.loopRunning)
975
1150
  return;
976
1151
  if (objectDetections.length > 0) {
977
- await this.runSecondariesAndThumbnails(rawFrame, objectDetections, results);
1152
+ const images = this.hqUpgrade ?? analysis;
1153
+ await this.runSecondariesAndThumbnails(images, objectDetections, results);
1154
+ if (!this.loopRunning)
1155
+ return;
1156
+ await this.captureAttributeMoment(results, images, t0);
978
1157
  }
979
1158
  if (!this.loopRunning)
980
1159
  return;
@@ -984,7 +1163,7 @@ let DetectionCoordinator = class DetectionCoordinator {
984
1163
  // messages already carry them
985
1164
  if (!this.loopRunning)
986
1165
  return;
987
- const snapshot = this.buildSnapshot();
1166
+ const snapshot = this.buildSnapshot(t0);
988
1167
  if (results.thumbnails && results.thumbnails.length > 0) {
989
1168
  snapshot.thumbnails = results.thumbnails;
990
1169
  }
@@ -994,7 +1173,9 @@ let DetectionCoordinator = class DetectionCoordinator {
994
1173
  let hqThumbAttached = false;
995
1174
  if (wantsEventThumb) {
996
1175
  try {
997
- const thumb = await this.thumbnailer.captureEventThumbnail(rawFrame);
1176
+ const thumbStart = Date.now();
1177
+ const thumb = await this.thumbnailer.captureEventThumbnail((this.hqUpgrade ?? analysis).frame);
1178
+ this.perf.jpegMs += Date.now() - thumbStart;
998
1179
  if (thumb.jpeg)
999
1180
  snapshot.eventThumbnail = thumb.jpeg;
1000
1181
  hqThumbAttached = thumb.fromHq;
@@ -1004,25 +1185,29 @@ let DetectionCoordinator = class DetectionCoordinator {
1004
1185
  }
1005
1186
  }
1006
1187
  this.eventManager.processResults(snapshot);
1188
+ // spans can outlive every trigger dwell (gate case); once spans, dwells
1189
+ // and the segment linger are all quiet the event ends here
1190
+ if (this.worldSpans.size === 0 && !this.dwell.hasActive() && !this.eventManager.hasActiveSegment()) {
1191
+ this.eventManager.forceEndActiveEvent();
1192
+ }
1007
1193
  // covers the window where the HQ source wasn't ready at event start
1008
1194
  if (wantsEventThumb && !hqThumbAttached) {
1009
1195
  this.thumbnailer.upgradeEventThumbnailAsync();
1010
1196
  }
1011
1197
  }
1012
- async runSecondariesAndThumbnails(rawFrame, objectDetections, results) {
1013
- objectDetections = this.stationary.excludeSealed(objectDetections);
1198
+ async runSecondariesAndThumbnails(analysis, objectDetections, results) {
1014
1199
  if (objectDetections.length === 0)
1015
1200
  return;
1016
- await this.secondaries.detect(rawFrame, objectDetections, results);
1201
+ this.perf.objects += objectDetections.length;
1202
+ const secondaryStart = Date.now();
1203
+ await this.secondaries.detect(analysis.frame, analysis.scaler, objectDetections, results);
1204
+ this.perf.secondaryMs += Date.now() - secondaryStart;
1017
1205
  try {
1018
- // detectors ran on the substream frame, thumbnails prefer the HQ frame
1019
- const hq = await this.thumbnailer.acquireHqFrame({ width: rawFrame.width, height: rawFrame.height });
1020
- try {
1021
- results.thumbnails = await this.secondaries.generateThumbnails(hq?.frame ?? rawFrame, hq?.scaler ?? this.frameScaler, hq !== null, objectDetections, results);
1022
- }
1023
- finally {
1024
- hq?.frame[Symbol.dispose]?.();
1025
- }
1206
+ const jpegStart = Date.now();
1207
+ results.thumbnails = await this.secondaries.generateThumbnails(analysis.frame, analysis.scaler, results);
1208
+ this.perf.jpegMs += Date.now() - jpegStart;
1209
+ this.perf.faces += results.face?.detections?.length ?? 0;
1210
+ this.perf.plates += results.licensePlate?.detections?.length ?? 0;
1026
1211
  }
1027
1212
  catch (error) {
1028
1213
  this.logger.error('Thumbnail generation error:', error);
@@ -1035,18 +1220,31 @@ let DetectionCoordinator = class DetectionCoordinator {
1035
1220
  }
1036
1221
  const facePlugin = this.plugins.get(SensorType.Face);
1037
1222
  if (facePlugin) {
1223
+ // no mid-segment clear: a turned-away head yields a no-face frame and
1224
+ // would flap the list, departure is reflected when the segment ends
1225
+ for (const detection of results.face.detections) {
1226
+ if (detection.identity)
1227
+ this.faceIdentities.add(detection.identity);
1228
+ }
1038
1229
  this.ingestDetectionResult(SensorType.Face, facePlugin.sensorId, {
1039
1230
  detected: results.face.detected,
1040
1231
  detections: results.face.detections,
1232
+ identities: [...this.faceIdentities].sort(),
1041
1233
  });
1042
1234
  }
1043
1235
  }
1044
1236
  if (results.licensePlate) {
1045
1237
  const lpdPlugin = this.plugins.get(SensorType.LicensePlate);
1046
1238
  if (lpdPlugin) {
1239
+ for (const detection of results.licensePlate.detections) {
1240
+ const plate = detection.plateText ? normalizePlateText(detection.plateText) || detection.plateText : '';
1241
+ if (plate)
1242
+ this.platesSeen.add(plate);
1243
+ }
1047
1244
  this.ingestDetectionResult(SensorType.LicensePlate, lpdPlugin.sensorId, {
1048
1245
  detected: results.licensePlate.detected,
1049
1246
  detections: results.licensePlate.detections,
1247
+ plates: [...this.platesSeen].sort(),
1050
1248
  });
1051
1249
  }
1052
1250
  }
@@ -1054,9 +1252,21 @@ let DetectionCoordinator = class DetectionCoordinator {
1054
1252
  for (const [pluginId, classifierResult] of Object.entries(results.classifiers)) {
1055
1253
  const plugin = this.plugins.getAll(SensorType.Classifier).find((p) => p.pluginId === pluginId);
1056
1254
  if (plugin) {
1255
+ let seen = this.classifierLabels.get(plugin.sensorId);
1256
+ if (!seen) {
1257
+ seen = new Set();
1258
+ this.classifierLabels.set(plugin.sensorId, seen);
1259
+ }
1260
+ for (const detection of classifierResult.detections) {
1261
+ // the specific answer wins (subAttribute, e.g. the bird species)
1262
+ const label = detection.subAttribute || detection.attribute || detection.label;
1263
+ if (label)
1264
+ seen.add(label);
1265
+ }
1057
1266
  this.ingestDetectionResult(SensorType.Classifier, plugin.sensorId, {
1058
1267
  detected: classifierResult.detected,
1059
1268
  detections: classifierResult.detections,
1269
+ labels: [...seen].sort(),
1060
1270
  }, pluginId);
1061
1271
  }
1062
1272
  }
@@ -1082,6 +1292,173 @@ let DetectionCoordinator = class DetectionCoordinator {
1082
1292
  return true;
1083
1293
  return false;
1084
1294
  }
1295
+ updateWorldSpans(result) {
1296
+ let opened = false;
1297
+ const suppressStatic = this.config.detectionSettings.object.suppressStatic ?? true;
1298
+ for (const event of result.events) {
1299
+ const obj = event.object;
1300
+ const recoveredRelevant = event.eventType === 'objectRecovered' && (obj.state !== 'stationary' || !suppressStatic);
1301
+ if (event.eventType === 'objectEntered' || event.eventType === 'objectWoke' || recoveredRelevant) {
1302
+ if (!this.worldSpans.has(obj.trackId))
1303
+ opened = true;
1304
+ this.worldSpans.add(obj.trackId);
1305
+ }
1306
+ else if (event.eventType === 'objectDeparted' || event.eventType === 'objectLost' || (event.eventType === 'objectSettled' && suppressStatic)) {
1307
+ this.worldSpans.delete(obj.trackId);
1308
+ }
1309
+ }
1310
+ return opened;
1311
+ }
1312
+ async captureMoments(result, analysis, at) {
1313
+ let subject;
1314
+ let bestScore = -1;
1315
+ let trigger = '';
1316
+ for (const event of result.events) {
1317
+ const obj = event.object;
1318
+ // a moment is worth a picture when a span opens or the view got better;
1319
+ // closing events report absence, there is nothing to show
1320
+ if (!MOMENT_EVENTS.has(event.eventType))
1321
+ continue;
1322
+ // and only for a track that holds a span: a tentative first sighting or a
1323
+ // stationary recovery opens nothing, so its picture is never handed over
1324
+ if (!this.worldSpans.has(obj.trackId))
1325
+ continue;
1326
+ const score = obj.confidence * Math.sqrt(obj.width * obj.height);
1327
+ if (score > bestScore) {
1328
+ bestScore = score;
1329
+ subject = obj;
1330
+ trigger = event.eventType;
1331
+ }
1332
+ }
1333
+ // one frame per tick, not one per object: they share the picture
1334
+ if (!subject)
1335
+ return;
1336
+ if (!this.eventManager.wantsMoment(MOMENT_RANK_OBJECT, bestScore, analysis.isMainStream ? 'main' : 'low', at))
1337
+ return;
1338
+ await this.captureMoment(subject, bestScore, trigger, result.tracked, analysis, at);
1339
+ }
1340
+ async captureMoment(subject, score, trigger, tracked, analysis, at) {
1341
+ const box = { x: subject.x, y: subject.y, width: subject.width, height: subject.height };
1342
+ const moving = tracked.filter((d) => (d.trackSpeed ?? 0) >= MOMENT_MOVING_SPEED).map((d) => d.box);
1343
+ const target = { subject: box, base: unionBox([box, ...moving]), hint: directionOf(subject.velocityX, subject.velocityY) };
1344
+ const rendered = await this.renderMoment(target, analysis);
1345
+ if (!rendered)
1346
+ return;
1347
+ const stream = analysis.isMainStream ? 'main' : 'low';
1348
+ this.eventManager.offerMoment({ strip: rendered.strip, card: rendered.card, capturedAt: at, score, rank: MOMENT_RANK_OBJECT, stream });
1349
+ // debugging
1350
+ await this.recordMoment(target, rendered, analysis, `${subject.label}-${subject.trackId}`, score, trigger, at);
1351
+ }
1352
+ async captureAttributeMoment(results, analysis, at) {
1353
+ const candidates = [];
1354
+ // same rule as the object rank: only a span-holding subject hands over a
1355
+ // picture. A face or plate riding on a settled bystander (the parked car
1356
+ // at the kerb) must not anchor the segment of an unrelated event
1357
+ const spanHolder = (parentTrackId) => parentTrackId !== undefined && this.worldSpans.has(parentTrackId);
1358
+ for (const face of results.face?.detections ?? []) {
1359
+ const f = face;
1360
+ if (!spanHolder(f.parentTrackId))
1361
+ continue;
1362
+ candidates.push({ label: `face:${f.identity ?? 'unknown'}`, box: f.box, parentBox: f.parentBox, confidence: f.confidence });
1363
+ }
1364
+ for (const plate of results.licensePlate?.detections ?? []) {
1365
+ const p = plate;
1366
+ if (!p.plateText || !spanHolder(p.parentTrackId))
1367
+ continue;
1368
+ candidates.push({ label: `plate:${normalizePlateText(p.plateText)}`, box: p.box, parentBox: p.parentBox, confidence: p.confidence });
1369
+ }
1370
+ // one picture per tick, never one per subject: with several faces the most
1371
+ // legible one frames the shot, the rest stay their own attribute tiles
1372
+ let best;
1373
+ let bestScore = -1;
1374
+ let bestCard;
1375
+ for (const candidate of candidates) {
1376
+ const cut = results.thumbnails?.find((t) => t.label === candidate.label);
1377
+ // a subject cut off by the frame edge makes a poor card
1378
+ if (cut?.onEdge)
1379
+ continue;
1380
+ // a few-pixel face or plate carries no information even at the crop's max
1381
+ // upscale: it stays an attribute tile, the anchor keeps the object shot
1382
+ const areaPx = candidate.box.width * analysis.frame.width * candidate.box.height * analysis.frame.height;
1383
+ if (areaPx < MOMENT_ATTRIBUTE_MIN_AREA)
1384
+ continue;
1385
+ const score = candidate.confidence * Math.sqrt(candidate.box.width * candidate.box.height);
1386
+ if (score > bestScore) {
1387
+ bestScore = score;
1388
+ best = candidate;
1389
+ bestCard = cut?.jpeg;
1390
+ }
1391
+ }
1392
+ // ask before cutting: the same face rides along on every tick of a segment
1393
+ // and re-encoding for a picture that loses anyway is pure cost
1394
+ if (!best || !this.eventManager.wantsMoment(MOMENT_RANK_ATTRIBUTE, bestScore, analysis.isMainStream ? 'main' : 'low', at))
1395
+ return;
1396
+ const target = {
1397
+ subject: best.box,
1398
+ hint: best.parentBox ? directionBetween(best.box, best.parentBox) : undefined,
1399
+ };
1400
+ // the attribute tile was cut from this frame with this very target, so the
1401
+ // card is already encoded; only the 16:9 companion is still missing
1402
+ const rendered = await this.renderMoment(target, analysis, bestCard);
1403
+ if (!rendered)
1404
+ return;
1405
+ const stream = analysis.isMainStream ? 'main' : 'low';
1406
+ this.eventManager.offerMoment({ strip: rendered.strip, card: rendered.card, capturedAt: at, score: bestScore, rank: MOMENT_RANK_ATTRIBUTE, stream });
1407
+ // debugging
1408
+ await this.recordMoment(target, rendered, analysis, best.label.replace(':', '-'), bestScore, 'attributeFound', at);
1409
+ }
1410
+ async renderMoment(target, analysis, card) {
1411
+ const start = Date.now();
1412
+ const rendered = new Map();
1413
+ const windows = {};
1414
+ if (card)
1415
+ rendered.set('card', card);
1416
+ try {
1417
+ for (const format of MOMENT_FORMATS) {
1418
+ const window = momentWindow(target, analysis.frame.width, analysis.frame.height, format);
1419
+ if (!window)
1420
+ continue;
1421
+ windows[format.name] = window;
1422
+ if (rendered.has(format.name))
1423
+ continue;
1424
+ const jpeg = await analysis.scaler.cropWindowToJPEG(analysis.frame, window, format.width, format.height, MOMENT_QUALITY);
1425
+ if (jpeg)
1426
+ rendered.set(format.name, jpeg);
1427
+ }
1428
+ }
1429
+ catch (error) {
1430
+ this.logger.debug('Moment crop failed:', error);
1431
+ }
1432
+ this.perf.jpegMs += Date.now() - start;
1433
+ const strip = rendered.get('strip');
1434
+ return strip ? { strip, card: rendered.get('card'), windows } : null;
1435
+ }
1436
+ // debugging
1437
+ async recordMoment(target, rendered, analysis, subjectName, score, trigger, at) {
1438
+ if (!detectionRecord.active)
1439
+ return;
1440
+ const stream = analysis.isMainStream ? 'main' : 'low';
1441
+ const detail = `${subjectName}_${stream}_s${score.toFixed(3)}`;
1442
+ try {
1443
+ const frameJpeg = await analysis.scaler.frameToJPEG(analysis.frame, analysis.frame.width, 85);
1444
+ detectionRecord.moment({
1445
+ at,
1446
+ trigger,
1447
+ score,
1448
+ subject: target.subject,
1449
+ base: target.base,
1450
+ windows: rendered.windows,
1451
+ pictures: {
1452
+ strip: detectionRecord.picture(at, 'moment', `strip_${detail}`, rendered.strip),
1453
+ card: rendered.card ? detectionRecord.picture(at, 'moment', `card_${detail}`, rendered.card) : undefined,
1454
+ },
1455
+ frame: frameJpeg ? detectionRecord.picture(at, 'frame', detail, frameJpeg) : undefined,
1456
+ });
1457
+ }
1458
+ catch (error) {
1459
+ this.logger.debug('Moment record failed:', error);
1460
+ }
1461
+ }
1085
1462
  async scaleForMotion(rawFrame) {
1086
1463
  const motionPlugin = this.plugins.get(SensorType.Motion);
1087
1464
  if (!motionPlugin?.requiresFrames)
@@ -1116,24 +1493,23 @@ let DetectionCoordinator = class DetectionCoordinator {
1116
1493
  this.objectIntervalSamples++;
1117
1494
  if (this.objectIntervalSamples < CADENCE_MIN_SAMPLES)
1118
1495
  return;
1119
- this.pipeline.syncDetectionCadence(this.objectIntervalMs);
1120
1496
  }
1121
- async scaleForObject(rawFrame) {
1497
+ async scaleForObject(rawFrame, scaler) {
1122
1498
  const objectPlugin = this.plugins.get(SensorType.Object);
1123
1499
  if (!objectPlugin?.requiresFrames)
1124
1500
  return undefined;
1125
- return this.scaleFrameForPlugin(rawFrame, objectPlugin);
1501
+ return this.scaleFrameForPlugin(rawFrame, objectPlugin, scaler);
1126
1502
  }
1127
- async scaleFrameForPlugin(rawFrame, plugin) {
1503
+ async scaleFrameForPlugin(rawFrame, plugin, scaler = this.frameScaler) {
1128
1504
  const inputSpec = plugin.modelSpec?.input;
1129
1505
  if (!isVideoInputSpec(inputSpec))
1130
1506
  return undefined;
1131
- const letterboxed = await this.frameScaler.letterboxToSpec(rawFrame, inputSpec);
1507
+ const letterboxed = await scaler.letterboxToSpec(rawFrame, inputSpec);
1132
1508
  if (!letterboxed)
1133
1509
  return undefined;
1134
1510
  return {
1135
- model: this.frameScaler.toVideoFrameData(letterboxed.padded, 'model'),
1136
- tracking: this.frameScaler.toVideoFrameData(letterboxed.inner, 'tracking'),
1511
+ model: scaler.toVideoFrameData(letterboxed.padded, 'model'),
1512
+ tracking: scaler.toVideoFrameData(letterboxed.inner, 'tracking'),
1137
1513
  geometry: letterboxed.geometry,
1138
1514
  };
1139
1515
  }