@camstack/types 0.1.41 → 0.2.0

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 (608) hide show
  1. package/dist/addon/base-addon.d.ts +0 -1
  2. package/dist/addon/build-addon-route-provider.d.ts +0 -1
  3. package/dist/addon/durable-state.d.ts +0 -1
  4. package/dist/capabilities/accessories.cap.d.ts +0 -1
  5. package/dist/capabilities/addon-pages-source.cap.d.ts +0 -1
  6. package/dist/capabilities/addon-pages.cap.d.ts +0 -1
  7. package/dist/capabilities/addon-routes.cap.d.ts +0 -1
  8. package/dist/capabilities/addon-settings.cap.d.ts +0 -1
  9. package/dist/capabilities/addon-widgets-source.cap.d.ts +0 -1
  10. package/dist/capabilities/addon-widgets.cap.d.ts +0 -1
  11. package/dist/capabilities/addons.cap.d.ts +0 -1
  12. package/dist/capabilities/admin-ui.cap.d.ts +0 -1
  13. package/dist/capabilities/advanced-notifier.cap.d.ts +0 -1
  14. package/dist/capabilities/air-quality-sensor.cap.d.ts +0 -1
  15. package/dist/capabilities/alarm-panel.cap.d.ts +0 -1
  16. package/dist/capabilities/alerts.cap.d.ts +0 -1
  17. package/dist/capabilities/ambient-light-sensor.cap.d.ts +0 -1
  18. package/dist/capabilities/audio-analysis.cap.d.ts +0 -1
  19. package/dist/capabilities/audio-analyzer.cap.d.ts +1 -2
  20. package/dist/capabilities/audio-codec.cap.d.ts +0 -1
  21. package/dist/capabilities/audio-metrics.cap.d.ts +0 -1
  22. package/dist/capabilities/auth-provider.cap.d.ts +0 -1
  23. package/dist/capabilities/automation-control.cap.d.ts +0 -1
  24. package/dist/capabilities/backup.cap.d.ts +0 -1
  25. package/dist/capabilities/battery.cap.d.ts +0 -1
  26. package/dist/capabilities/binary.cap.d.ts +0 -1
  27. package/dist/capabilities/brightness.cap.d.ts +0 -1
  28. package/dist/capabilities/broker.cap.d.ts +0 -1
  29. package/dist/capabilities/button.cap.d.ts +0 -1
  30. package/dist/capabilities/camera-credentials.cap.d.ts +0 -1
  31. package/dist/capabilities/camera-pipeline-config.cap.d.ts +0 -1
  32. package/dist/capabilities/camera-streams.cap.d.ts +0 -1
  33. package/dist/capabilities/capability-definition.d.ts +0 -1
  34. package/dist/capabilities/carbon-monoxide.cap.d.ts +0 -1
  35. package/dist/capabilities/climate-control.cap.d.ts +0 -1
  36. package/dist/capabilities/color.cap.d.ts +0 -1
  37. package/dist/capabilities/connectivity.cap.d.ts +0 -1
  38. package/dist/capabilities/consumables.cap.d.ts +0 -1
  39. package/dist/capabilities/contact.cap.d.ts +0 -1
  40. package/dist/capabilities/control.cap.d.ts +0 -1
  41. package/dist/capabilities/cover.cap.d.ts +0 -1
  42. package/dist/capabilities/custom-actions.d.ts +0 -1
  43. package/dist/capabilities/decoder.cap.d.ts +0 -1
  44. package/dist/capabilities/detection-pipeline.cap.d.ts +0 -1
  45. package/dist/capabilities/device-adoption.cap.d.ts +0 -1
  46. package/dist/capabilities/device-discovery.cap.d.ts +0 -1
  47. package/dist/capabilities/device-export.cap.d.ts +0 -1
  48. package/dist/capabilities/device-manager.cap.d.ts +1 -2
  49. package/dist/capabilities/device-ops.cap.d.ts +0 -1
  50. package/dist/capabilities/device-provider.cap.d.ts +0 -1
  51. package/dist/capabilities/device-state.cap.d.ts +0 -1
  52. package/dist/capabilities/device-status.cap.d.ts +0 -1
  53. package/dist/capabilities/doorbell.cap.d.ts +0 -1
  54. package/dist/capabilities/embedding-encoder.cap.d.ts +0 -1
  55. package/dist/capabilities/enum-sensor.cap.d.ts +0 -1
  56. package/dist/capabilities/event-emitter.cap.d.ts +0 -1
  57. package/dist/capabilities/events.cap.d.ts +0 -1
  58. package/dist/capabilities/face-gallery.cap.d.ts +157 -0
  59. package/dist/capabilities/fan-control.cap.d.ts +0 -1
  60. package/dist/capabilities/feature-probe.cap.d.ts +0 -1
  61. package/dist/capabilities/filesystem-browse.cap.d.ts +38 -0
  62. package/dist/capabilities/flood.cap.d.ts +0 -1
  63. package/dist/capabilities/gas.cap.d.ts +0 -1
  64. package/dist/capabilities/humidifier.cap.d.ts +0 -1
  65. package/dist/capabilities/humidity-sensor.cap.d.ts +0 -1
  66. package/dist/capabilities/image.cap.d.ts +0 -1
  67. package/dist/capabilities/index.d.ts +56 -51
  68. package/dist/capabilities/integrations.cap.d.ts +0 -1
  69. package/dist/capabilities/intercom.cap.d.ts +0 -1
  70. package/dist/capabilities/lawn-mower-control.cap.d.ts +0 -1
  71. package/dist/capabilities/local-network.cap.d.ts +0 -1
  72. package/dist/capabilities/lock-control.cap.d.ts +0 -1
  73. package/dist/capabilities/log-destination.cap.d.ts +0 -1
  74. package/dist/capabilities/mask-shape.d.ts +0 -1
  75. package/dist/capabilities/media-player.cap.d.ts +0 -1
  76. package/dist/capabilities/mesh-network.cap.d.ts +0 -1
  77. package/dist/capabilities/metrics-provider.cap.d.ts +0 -1
  78. package/dist/capabilities/motion-detection.cap.d.ts +0 -1
  79. package/dist/capabilities/motion-trigger.cap.d.ts +0 -1
  80. package/dist/capabilities/motion-zones.cap.d.ts +0 -1
  81. package/dist/capabilities/motion.cap.d.ts +0 -1
  82. package/dist/capabilities/mqtt-broker.cap.d.ts +0 -1
  83. package/dist/capabilities/native-object-detection.cap.d.ts +0 -1
  84. package/dist/capabilities/network-access.cap.d.ts +0 -1
  85. package/dist/capabilities/network-quality.cap.d.ts +1 -2
  86. package/dist/capabilities/nodes.cap.d.ts +0 -1
  87. package/dist/capabilities/notification-output.cap.d.ts +0 -1
  88. package/dist/capabilities/notifier.cap.d.ts +0 -1
  89. package/dist/capabilities/numeric-sensor.cap.d.ts +0 -1
  90. package/dist/capabilities/oauth-integration.cap.d.ts +0 -1
  91. package/dist/capabilities/osd.cap.d.ts +0 -1
  92. package/dist/capabilities/pipeline-analytics.cap.d.ts +69 -2
  93. package/dist/capabilities/pipeline-executor.cap.d.ts +0 -1
  94. package/dist/capabilities/pipeline-orchestrator.cap.d.ts +0 -1
  95. package/dist/capabilities/pipeline-runner.cap.d.ts +4 -1
  96. package/dist/capabilities/plate-gallery.cap.d.ts +100 -0
  97. package/dist/capabilities/platform-probe.cap.d.ts +0 -1
  98. package/dist/capabilities/power-meter.cap.d.ts +0 -1
  99. package/dist/capabilities/presence.cap.d.ts +0 -1
  100. package/dist/capabilities/pressure-sensor.cap.d.ts +0 -1
  101. package/dist/capabilities/privacy-mask.cap.d.ts +0 -1
  102. package/dist/capabilities/ptz-autotrack.cap.d.ts +0 -1
  103. package/dist/capabilities/ptz.cap.d.ts +1 -2
  104. package/dist/capabilities/reboot.cap.d.ts +0 -1
  105. package/dist/capabilities/recording.cap.d.ts +191 -1
  106. package/dist/capabilities/restreamer.cap.d.ts +0 -1
  107. package/dist/capabilities/schemas/detection-shared.d.ts +0 -1
  108. package/dist/capabilities/schemas/orchestrator-metrics.d.ts +0 -1
  109. package/dist/capabilities/schemas/streaming-shared.d.ts +0 -1
  110. package/dist/capabilities/schemas/zone-rule.d.ts +0 -1
  111. package/dist/capabilities/script-runner.cap.d.ts +0 -1
  112. package/dist/capabilities/settings-store.cap.d.ts +0 -1
  113. package/dist/capabilities/smoke.cap.d.ts +0 -1
  114. package/dist/capabilities/smtp-provider.cap.d.ts +0 -1
  115. package/dist/capabilities/snapshot-provider.cap.d.ts +0 -1
  116. package/dist/capabilities/snapshot.cap.d.ts +0 -1
  117. package/dist/capabilities/sso-bridge.cap.d.ts +0 -1
  118. package/dist/capabilities/storage-evictable.cap.d.ts +0 -1
  119. package/dist/capabilities/storage-provider.cap.d.ts +15 -1
  120. package/dist/capabilities/storage.cap.d.ts +6 -1
  121. package/dist/capabilities/stream-broker.cap.d.ts +16 -1
  122. package/dist/capabilities/stream-catalog.cap.d.ts +0 -1
  123. package/dist/capabilities/stream-params-config-schema.d.ts +0 -1
  124. package/dist/capabilities/stream-params.cap.d.ts +0 -1
  125. package/dist/capabilities/streaming-engine.cap.d.ts +0 -1
  126. package/dist/capabilities/switch.cap.d.ts +0 -1
  127. package/dist/capabilities/system.cap.d.ts +1 -2
  128. package/dist/capabilities/tamper.cap.d.ts +0 -1
  129. package/dist/capabilities/temperature-sensor.cap.d.ts +0 -1
  130. package/dist/capabilities/toast.cap.d.ts +0 -1
  131. package/dist/capabilities/turn-provider.cap.d.ts +1 -2
  132. package/dist/capabilities/update.cap.d.ts +0 -1
  133. package/dist/capabilities/user-management.cap.d.ts +0 -1
  134. package/dist/capabilities/user-passkeys.cap.d.ts +1 -2
  135. package/dist/capabilities/vacuum-control.cap.d.ts +0 -1
  136. package/dist/capabilities/valve.cap.d.ts +0 -1
  137. package/dist/capabilities/vibration.cap.d.ts +0 -1
  138. package/dist/capabilities/videoclips.cap.d.ts +76 -0
  139. package/dist/capabilities/water-heater.cap.d.ts +0 -1
  140. package/dist/capabilities/weather.cap.d.ts +0 -1
  141. package/dist/capabilities/webrtc-session.cap.d.ts +0 -1
  142. package/dist/capabilities/webrtc.cap.d.ts +0 -1
  143. package/dist/capabilities/zone-analytics.cap.d.ts +0 -1
  144. package/dist/capabilities/zone-rules.cap.d.ts +0 -1
  145. package/dist/capabilities/zones.cap.d.ts +0 -1
  146. package/dist/catalogs/audio-classmap.d.ts +0 -1
  147. package/dist/catalogs/coco-classmap.d.ts +0 -1
  148. package/dist/catalogs/index.d.ts +0 -1
  149. package/dist/constants.d.ts +1 -2
  150. package/dist/deps/binary-downloader.d.ts +0 -1
  151. package/dist/deps/ffmpeg-downloader.d.ts +0 -1
  152. package/dist/deps/index.d.ts +1 -2
  153. package/dist/deps/python-downloader.d.ts +0 -1
  154. package/dist/device/accessory.d.ts +1 -2
  155. package/dist/device/base-device-provider.d.ts +0 -1
  156. package/dist/device/base-device.d.ts +0 -1
  157. package/dist/device/camera-device.d.ts +0 -1
  158. package/dist/device/device-binding.d.ts +0 -1
  159. package/dist/device/device-config.d.ts +0 -1
  160. package/dist/device/device-context.d.ts +1 -2
  161. package/dist/device/device-link-transform.d.ts +0 -1
  162. package/dist/device/device-management.d.ts +0 -1
  163. package/dist/device/device-profile.d.ts +0 -1
  164. package/dist/device/device-runtime-state.d.ts +0 -1
  165. package/dist/device/device-state-handle.d.ts +0 -1
  166. package/dist/device/device-type.d.ts +0 -1
  167. package/dist/device/device.d.ts +0 -1
  168. package/dist/device/features.d.ts +0 -1
  169. package/dist/device/index.d.ts +5 -6
  170. package/dist/device/path-util.d.ts +0 -1
  171. package/dist/device/runtime-state-helpers.d.ts +0 -1
  172. package/dist/device/schema-fields.d.ts +0 -1
  173. package/dist/device/source-info.d.ts +0 -1
  174. package/dist/device/system-mirror.d.ts +0 -1
  175. package/dist/device/zod-to-config-ui.d.ts +0 -1
  176. package/dist/disposer-chain.d.ts +0 -1
  177. package/dist/encode-profile.d.ts +0 -1
  178. package/dist/enums/event-category.d.ts +12 -2
  179. package/dist/enums/event-source-type.d.ts +0 -1
  180. package/dist/enums/index.d.ts +0 -1
  181. package/dist/generated/addon-api.d.ts +1128 -17
  182. package/dist/generated/cap-status-types.d.ts +0 -1
  183. package/dist/generated/capability-router-map.d.ts +14 -3
  184. package/dist/generated/device-local-state.d.ts +0 -1
  185. package/dist/generated/device-proxy.d.ts +7 -2
  186. package/dist/generated/method-access-map.d.ts +1 -2
  187. package/dist/generated/provider-kind-map.d.ts +0 -1
  188. package/dist/generated/scope-presets.d.ts +0 -1
  189. package/dist/generated/system-proxy.d.ts +5 -2
  190. package/dist/health/wiring-health.d.ts +0 -1
  191. package/dist/helpers/bind-addon-actions.d.ts +0 -1
  192. package/dist/index.d.ts +10 -10
  193. package/dist/index.js +28780 -7364
  194. package/dist/index.mjs +28207 -7478
  195. package/dist/interfaces/addon-data-plane.d.ts +0 -1
  196. package/dist/interfaces/addon-routes.d.ts +0 -1
  197. package/dist/interfaces/addon.d.ts +0 -1
  198. package/dist/interfaces/advanced-notifier.d.ts +0 -1
  199. package/dist/interfaces/agent-protocol.d.ts +0 -1
  200. package/dist/interfaces/agent.d.ts +0 -1
  201. package/dist/interfaces/alerts.d.ts +0 -1
  202. package/dist/interfaces/analysis-persistence.d.ts +0 -1
  203. package/dist/interfaces/analysis.d.ts +0 -1
  204. package/dist/interfaces/api-responses.d.ts +0 -1
  205. package/dist/interfaces/api-shared.d.ts +0 -1
  206. package/dist/interfaces/audio-analyzer.d.ts +0 -1
  207. package/dist/interfaces/audio-codec.d.ts +0 -1
  208. package/dist/interfaces/audio-inference-engine.d.ts +0 -1
  209. package/dist/interfaces/auth.d.ts +0 -1
  210. package/dist/interfaces/camera-pipeline.d.ts +0 -1
  211. package/dist/interfaces/capability.d.ts +47 -48
  212. package/dist/interfaces/config-ui.d.ts +3 -4
  213. package/dist/interfaces/context.d.ts +0 -1
  214. package/dist/interfaces/decoder.d.ts +0 -1
  215. package/dist/interfaces/detection-addon.d.ts +0 -1
  216. package/dist/interfaces/device-capabilities/camera.d.ts +0 -1
  217. package/dist/interfaces/device-capabilities/index.d.ts +0 -1
  218. package/dist/interfaces/device-provider.d.ts +0 -1
  219. package/dist/interfaces/device.d.ts +0 -1
  220. package/dist/interfaces/embedding-encoder.d.ts +0 -1
  221. package/dist/interfaces/engine-slots.d.ts +0 -1
  222. package/dist/interfaces/event-bus.d.ts +16 -6
  223. package/dist/interfaces/feature-flags.d.ts +0 -1
  224. package/dist/interfaces/ffmpeg.d.ts +0 -1
  225. package/dist/interfaces/frame-handle.d.ts +0 -1
  226. package/dist/interfaces/inference-capabilities.d.ts +0 -1
  227. package/dist/interfaces/inference-engine.d.ts +0 -1
  228. package/dist/interfaces/integration-registry.d.ts +0 -1
  229. package/dist/interfaces/kernel-abstractions.d.ts +0 -1
  230. package/dist/interfaces/lifecycle.d.ts +0 -1
  231. package/dist/interfaces/logging.d.ts +0 -1
  232. package/dist/interfaces/metrics-provider.d.ts +0 -1
  233. package/dist/interfaces/network-quality.d.ts +0 -1
  234. package/dist/interfaces/network.d.ts +0 -1
  235. package/dist/interfaces/notification.d.ts +0 -1
  236. package/dist/interfaces/pipeline-executor-capability.d.ts +0 -1
  237. package/dist/interfaces/pipeline-orchestrator-capability.d.ts +0 -1
  238. package/dist/interfaces/pipeline-runner-capability.d.ts +4 -1
  239. package/dist/interfaces/pipeline-runner.d.ts +0 -1
  240. package/dist/interfaces/pipeline-slot.d.ts +0 -1
  241. package/dist/interfaces/platform.d.ts +0 -1
  242. package/dist/interfaces/process.d.ts +0 -1
  243. package/dist/interfaces/python-env.d.ts +0 -1
  244. package/dist/interfaces/queryable.d.ts +0 -1
  245. package/dist/interfaces/raw-tensor-engine.d.ts +0 -1
  246. package/dist/interfaces/readiness.d.ts +0 -1
  247. package/dist/interfaces/recording-config-migrate.d.ts +12 -0
  248. package/dist/interfaces/recording-config.d.ts +119 -2
  249. package/dist/interfaces/repl.d.ts +0 -1
  250. package/dist/interfaces/restreamer.d.ts +0 -1
  251. package/dist/interfaces/router.d.ts +0 -1
  252. package/dist/interfaces/rtp-egress.d.ts +0 -1
  253. package/dist/interfaces/scoped-token.d.ts +0 -1
  254. package/dist/interfaces/server-analysis.d.ts +2 -3
  255. package/dist/interfaces/server-network.d.ts +0 -1
  256. package/dist/interfaces/storage-location-declaration.d.ts +0 -1
  257. package/dist/interfaces/storage-location.d.ts +1 -1
  258. package/dist/interfaces/storage.d.ts +0 -1
  259. package/dist/interfaces/stream-broker.d.ts +2 -1
  260. package/dist/interfaces/streaming.d.ts +0 -1
  261. package/dist/interfaces/task-handler.d.ts +0 -1
  262. package/dist/interfaces/timezones.d.ts +0 -1
  263. package/dist/interfaces/webrtc-provider.d.ts +0 -1
  264. package/dist/node.d.ts +0 -1
  265. package/dist/node.js +624 -462
  266. package/dist/node.mjs +604 -443
  267. package/dist/readiness/index.d.ts +0 -1
  268. package/dist/readiness/readiness-registry.d.ts +0 -1
  269. package/dist/schemas/auth-records.d.ts +0 -1
  270. package/dist/storage/filesystem-storage-provider.d.ts +0 -1
  271. package/dist/stream-selection.d.ts +0 -1
  272. package/dist/types/agent-pipeline-settings.d.ts +0 -1
  273. package/dist/types/analytics.d.ts +0 -1
  274. package/dist/types/camera-detection.d.ts +0 -1
  275. package/dist/types/camera-pipeline.d.ts +0 -1
  276. package/dist/types/config.d.ts +0 -1
  277. package/dist/types/detection.d.ts +12 -1
  278. package/dist/types/device-type.d.ts +0 -1
  279. package/dist/types/engine-output.d.ts +0 -1
  280. package/dist/types/entities.d.ts +0 -1
  281. package/dist/types/events.d.ts +0 -1
  282. package/dist/types/io.d.ts +0 -1
  283. package/dist/types/labels.d.ts +0 -1
  284. package/dist/types/live-state.d.ts +0 -1
  285. package/dist/types/models.d.ts +8 -1
  286. package/dist/types/pipeline-schema.d.ts +0 -1
  287. package/dist/types/pipeline-step.d.ts +0 -1
  288. package/dist/types/pipeline.d.ts +0 -1
  289. package/dist/types/tracked.d.ts +0 -1
  290. package/dist/util/location-match.d.ts +0 -1
  291. package/dist/utils/canonical-hash.d.ts +0 -1
  292. package/dist/utils/cosine-similarity.d.ts +0 -1
  293. package/dist/utils/element-config-store.d.ts +0 -1
  294. package/dist/utils/err-msg.d.ts +0 -1
  295. package/dist/utils/export-reconciler.d.ts +0 -1
  296. package/dist/utils/hf-url.d.ts +0 -1
  297. package/dist/utils/json-safe.d.ts +0 -1
  298. package/dist/utils/mask-url.d.ts +0 -1
  299. package/dist/utils/privacy-grid-raster.d.ts +0 -1
  300. package/dist/utils/ring-buffer.d.ts +0 -1
  301. package/dist/utils/run-inference-step.d.ts +0 -1
  302. package/dist/utils/runtime-mapping.d.ts +0 -1
  303. package/dist/utils/sleep.d.ts +0 -1
  304. package/dist/utils/zone-rule-eval.d.ts +0 -1
  305. package/package.json +3 -2
  306. package/dist/addon/base-addon.d.ts.map +0 -1
  307. package/dist/addon/build-addon-route-provider.d.ts.map +0 -1
  308. package/dist/addon/durable-state.d.ts.map +0 -1
  309. package/dist/capabilities/accessories.cap.d.ts.map +0 -1
  310. package/dist/capabilities/addon-pages-source.cap.d.ts.map +0 -1
  311. package/dist/capabilities/addon-pages.cap.d.ts.map +0 -1
  312. package/dist/capabilities/addon-routes.cap.d.ts.map +0 -1
  313. package/dist/capabilities/addon-settings.cap.d.ts.map +0 -1
  314. package/dist/capabilities/addon-widgets-source.cap.d.ts.map +0 -1
  315. package/dist/capabilities/addon-widgets.cap.d.ts.map +0 -1
  316. package/dist/capabilities/addons.cap.d.ts.map +0 -1
  317. package/dist/capabilities/admin-ui.cap.d.ts.map +0 -1
  318. package/dist/capabilities/advanced-notifier.cap.d.ts.map +0 -1
  319. package/dist/capabilities/air-quality-sensor.cap.d.ts.map +0 -1
  320. package/dist/capabilities/alarm-panel.cap.d.ts.map +0 -1
  321. package/dist/capabilities/alerts.cap.d.ts.map +0 -1
  322. package/dist/capabilities/ambient-light-sensor.cap.d.ts.map +0 -1
  323. package/dist/capabilities/audio-analysis.cap.d.ts.map +0 -1
  324. package/dist/capabilities/audio-analyzer.cap.d.ts.map +0 -1
  325. package/dist/capabilities/audio-codec.cap.d.ts.map +0 -1
  326. package/dist/capabilities/audio-metrics.cap.d.ts.map +0 -1
  327. package/dist/capabilities/auth-provider.cap.d.ts.map +0 -1
  328. package/dist/capabilities/automation-control.cap.d.ts.map +0 -1
  329. package/dist/capabilities/backup.cap.d.ts.map +0 -1
  330. package/dist/capabilities/battery.cap.d.ts.map +0 -1
  331. package/dist/capabilities/binary.cap.d.ts.map +0 -1
  332. package/dist/capabilities/brightness.cap.d.ts.map +0 -1
  333. package/dist/capabilities/broker.cap.d.ts.map +0 -1
  334. package/dist/capabilities/button.cap.d.ts.map +0 -1
  335. package/dist/capabilities/camera-credentials.cap.d.ts.map +0 -1
  336. package/dist/capabilities/camera-pipeline-config.cap.d.ts.map +0 -1
  337. package/dist/capabilities/camera-streams.cap.d.ts.map +0 -1
  338. package/dist/capabilities/capability-definition.d.ts.map +0 -1
  339. package/dist/capabilities/carbon-monoxide.cap.d.ts.map +0 -1
  340. package/dist/capabilities/climate-control.cap.d.ts.map +0 -1
  341. package/dist/capabilities/color.cap.d.ts.map +0 -1
  342. package/dist/capabilities/connectivity.cap.d.ts.map +0 -1
  343. package/dist/capabilities/consumables.cap.d.ts.map +0 -1
  344. package/dist/capabilities/contact.cap.d.ts.map +0 -1
  345. package/dist/capabilities/control.cap.d.ts.map +0 -1
  346. package/dist/capabilities/cover.cap.d.ts.map +0 -1
  347. package/dist/capabilities/custom-actions.d.ts.map +0 -1
  348. package/dist/capabilities/decoder.cap.d.ts.map +0 -1
  349. package/dist/capabilities/detection-pipeline.cap.d.ts.map +0 -1
  350. package/dist/capabilities/device-adoption.cap.d.ts.map +0 -1
  351. package/dist/capabilities/device-discovery.cap.d.ts.map +0 -1
  352. package/dist/capabilities/device-export.cap.d.ts.map +0 -1
  353. package/dist/capabilities/device-manager.cap.d.ts.map +0 -1
  354. package/dist/capabilities/device-ops.cap.d.ts.map +0 -1
  355. package/dist/capabilities/device-provider.cap.d.ts.map +0 -1
  356. package/dist/capabilities/device-state.cap.d.ts.map +0 -1
  357. package/dist/capabilities/device-status.cap.d.ts.map +0 -1
  358. package/dist/capabilities/doorbell.cap.d.ts.map +0 -1
  359. package/dist/capabilities/embedding-encoder.cap.d.ts.map +0 -1
  360. package/dist/capabilities/enum-sensor.cap.d.ts.map +0 -1
  361. package/dist/capabilities/event-emitter.cap.d.ts.map +0 -1
  362. package/dist/capabilities/events.cap.d.ts.map +0 -1
  363. package/dist/capabilities/fan-control.cap.d.ts.map +0 -1
  364. package/dist/capabilities/feature-probe.cap.d.ts.map +0 -1
  365. package/dist/capabilities/flood.cap.d.ts.map +0 -1
  366. package/dist/capabilities/gas.cap.d.ts.map +0 -1
  367. package/dist/capabilities/humidifier.cap.d.ts.map +0 -1
  368. package/dist/capabilities/humidity-sensor.cap.d.ts.map +0 -1
  369. package/dist/capabilities/image.cap.d.ts.map +0 -1
  370. package/dist/capabilities/index.d.ts.map +0 -1
  371. package/dist/capabilities/integrations.cap.d.ts.map +0 -1
  372. package/dist/capabilities/intercom.cap.d.ts.map +0 -1
  373. package/dist/capabilities/lawn-mower-control.cap.d.ts.map +0 -1
  374. package/dist/capabilities/local-network.cap.d.ts.map +0 -1
  375. package/dist/capabilities/lock-control.cap.d.ts.map +0 -1
  376. package/dist/capabilities/log-destination.cap.d.ts.map +0 -1
  377. package/dist/capabilities/mask-shape.d.ts.map +0 -1
  378. package/dist/capabilities/media-player.cap.d.ts.map +0 -1
  379. package/dist/capabilities/mesh-network.cap.d.ts.map +0 -1
  380. package/dist/capabilities/metrics-provider.cap.d.ts.map +0 -1
  381. package/dist/capabilities/motion-detection.cap.d.ts.map +0 -1
  382. package/dist/capabilities/motion-trigger.cap.d.ts.map +0 -1
  383. package/dist/capabilities/motion-zones.cap.d.ts.map +0 -1
  384. package/dist/capabilities/motion.cap.d.ts.map +0 -1
  385. package/dist/capabilities/mqtt-broker.cap.d.ts.map +0 -1
  386. package/dist/capabilities/native-object-detection.cap.d.ts.map +0 -1
  387. package/dist/capabilities/network-access.cap.d.ts.map +0 -1
  388. package/dist/capabilities/network-quality.cap.d.ts.map +0 -1
  389. package/dist/capabilities/nodes.cap.d.ts.map +0 -1
  390. package/dist/capabilities/notification-output.cap.d.ts.map +0 -1
  391. package/dist/capabilities/notifier.cap.d.ts.map +0 -1
  392. package/dist/capabilities/numeric-sensor.cap.d.ts.map +0 -1
  393. package/dist/capabilities/oauth-integration.cap.d.ts.map +0 -1
  394. package/dist/capabilities/osd.cap.d.ts.map +0 -1
  395. package/dist/capabilities/pipeline-analytics.cap.d.ts.map +0 -1
  396. package/dist/capabilities/pipeline-executor.cap.d.ts.map +0 -1
  397. package/dist/capabilities/pipeline-orchestrator.cap.d.ts.map +0 -1
  398. package/dist/capabilities/pipeline-runner.cap.d.ts.map +0 -1
  399. package/dist/capabilities/platform-probe.cap.d.ts.map +0 -1
  400. package/dist/capabilities/power-meter.cap.d.ts.map +0 -1
  401. package/dist/capabilities/presence.cap.d.ts.map +0 -1
  402. package/dist/capabilities/pressure-sensor.cap.d.ts.map +0 -1
  403. package/dist/capabilities/privacy-mask.cap.d.ts.map +0 -1
  404. package/dist/capabilities/ptz-autotrack.cap.d.ts.map +0 -1
  405. package/dist/capabilities/ptz.cap.d.ts.map +0 -1
  406. package/dist/capabilities/reboot.cap.d.ts.map +0 -1
  407. package/dist/capabilities/recording.cap.d.ts.map +0 -1
  408. package/dist/capabilities/restreamer.cap.d.ts.map +0 -1
  409. package/dist/capabilities/schemas/detection-shared.d.ts.map +0 -1
  410. package/dist/capabilities/schemas/orchestrator-metrics.d.ts.map +0 -1
  411. package/dist/capabilities/schemas/streaming-shared.d.ts.map +0 -1
  412. package/dist/capabilities/schemas/zone-rule.d.ts.map +0 -1
  413. package/dist/capabilities/script-runner.cap.d.ts.map +0 -1
  414. package/dist/capabilities/settings-store.cap.d.ts.map +0 -1
  415. package/dist/capabilities/smoke.cap.d.ts.map +0 -1
  416. package/dist/capabilities/smtp-provider.cap.d.ts.map +0 -1
  417. package/dist/capabilities/snapshot-provider.cap.d.ts.map +0 -1
  418. package/dist/capabilities/snapshot.cap.d.ts.map +0 -1
  419. package/dist/capabilities/sso-bridge.cap.d.ts.map +0 -1
  420. package/dist/capabilities/storage-evictable.cap.d.ts.map +0 -1
  421. package/dist/capabilities/storage-provider.cap.d.ts.map +0 -1
  422. package/dist/capabilities/storage.cap.d.ts.map +0 -1
  423. package/dist/capabilities/stream-broker.cap.d.ts.map +0 -1
  424. package/dist/capabilities/stream-catalog.cap.d.ts.map +0 -1
  425. package/dist/capabilities/stream-params-config-schema.d.ts.map +0 -1
  426. package/dist/capabilities/stream-params.cap.d.ts.map +0 -1
  427. package/dist/capabilities/streaming-engine.cap.d.ts.map +0 -1
  428. package/dist/capabilities/switch.cap.d.ts.map +0 -1
  429. package/dist/capabilities/system.cap.d.ts.map +0 -1
  430. package/dist/capabilities/tamper.cap.d.ts.map +0 -1
  431. package/dist/capabilities/temperature-sensor.cap.d.ts.map +0 -1
  432. package/dist/capabilities/toast.cap.d.ts.map +0 -1
  433. package/dist/capabilities/turn-provider.cap.d.ts.map +0 -1
  434. package/dist/capabilities/update.cap.d.ts.map +0 -1
  435. package/dist/capabilities/user-management.cap.d.ts.map +0 -1
  436. package/dist/capabilities/user-passkeys.cap.d.ts.map +0 -1
  437. package/dist/capabilities/vacuum-control.cap.d.ts.map +0 -1
  438. package/dist/capabilities/valve.cap.d.ts.map +0 -1
  439. package/dist/capabilities/vibration.cap.d.ts.map +0 -1
  440. package/dist/capabilities/water-heater.cap.d.ts.map +0 -1
  441. package/dist/capabilities/weather.cap.d.ts.map +0 -1
  442. package/dist/capabilities/webrtc-session.cap.d.ts.map +0 -1
  443. package/dist/capabilities/webrtc.cap.d.ts.map +0 -1
  444. package/dist/capabilities/zone-analytics.cap.d.ts.map +0 -1
  445. package/dist/capabilities/zone-rules.cap.d.ts.map +0 -1
  446. package/dist/capabilities/zones.cap.d.ts.map +0 -1
  447. package/dist/catalogs/audio-classmap.d.ts.map +0 -1
  448. package/dist/catalogs/coco-classmap.d.ts.map +0 -1
  449. package/dist/catalogs/index.d.ts.map +0 -1
  450. package/dist/constants.d.ts.map +0 -1
  451. package/dist/deps/binary-downloader.d.ts.map +0 -1
  452. package/dist/deps/ffmpeg-downloader.d.ts.map +0 -1
  453. package/dist/deps/index.d.ts.map +0 -1
  454. package/dist/deps/python-downloader.d.ts.map +0 -1
  455. package/dist/device/accessory.d.ts.map +0 -1
  456. package/dist/device/base-device-provider.d.ts.map +0 -1
  457. package/dist/device/base-device.d.ts.map +0 -1
  458. package/dist/device/camera-device.d.ts.map +0 -1
  459. package/dist/device/device-binding.d.ts.map +0 -1
  460. package/dist/device/device-config.d.ts.map +0 -1
  461. package/dist/device/device-context.d.ts.map +0 -1
  462. package/dist/device/device-link-transform.d.ts.map +0 -1
  463. package/dist/device/device-management.d.ts.map +0 -1
  464. package/dist/device/device-profile.d.ts.map +0 -1
  465. package/dist/device/device-runtime-state.d.ts.map +0 -1
  466. package/dist/device/device-state-handle.d.ts.map +0 -1
  467. package/dist/device/device-type.d.ts.map +0 -1
  468. package/dist/device/device.d.ts.map +0 -1
  469. package/dist/device/features.d.ts.map +0 -1
  470. package/dist/device/index.d.ts.map +0 -1
  471. package/dist/device/path-util.d.ts.map +0 -1
  472. package/dist/device/runtime-state-helpers.d.ts.map +0 -1
  473. package/dist/device/schema-fields.d.ts.map +0 -1
  474. package/dist/device/source-info.d.ts.map +0 -1
  475. package/dist/device/system-mirror.d.ts.map +0 -1
  476. package/dist/device/zod-to-config-ui.d.ts.map +0 -1
  477. package/dist/disposer-chain.d.ts.map +0 -1
  478. package/dist/encode-profile.d.ts.map +0 -1
  479. package/dist/enums/event-category.d.ts.map +0 -1
  480. package/dist/enums/event-source-type.d.ts.map +0 -1
  481. package/dist/enums/index.d.ts.map +0 -1
  482. package/dist/generated/addon-api.d.ts.map +0 -1
  483. package/dist/generated/cap-status-types.d.ts.map +0 -1
  484. package/dist/generated/capability-router-map.d.ts.map +0 -1
  485. package/dist/generated/device-local-state.d.ts.map +0 -1
  486. package/dist/generated/device-proxy.d.ts.map +0 -1
  487. package/dist/generated/method-access-map.d.ts.map +0 -1
  488. package/dist/generated/provider-kind-map.d.ts.map +0 -1
  489. package/dist/generated/scope-presets.d.ts.map +0 -1
  490. package/dist/generated/system-proxy.d.ts.map +0 -1
  491. package/dist/health/wiring-health.d.ts.map +0 -1
  492. package/dist/helpers/bind-addon-actions.d.ts.map +0 -1
  493. package/dist/index-BSA_TBea.js +0 -13311
  494. package/dist/index-BSA_TBea.js.map +0 -1
  495. package/dist/index-Bpj3ScIH.mjs +0 -13312
  496. package/dist/index-Bpj3ScIH.mjs.map +0 -1
  497. package/dist/index.d.ts.map +0 -1
  498. package/dist/index.js.map +0 -1
  499. package/dist/index.mjs.map +0 -1
  500. package/dist/interfaces/addon-data-plane.d.ts.map +0 -1
  501. package/dist/interfaces/addon-routes.d.ts.map +0 -1
  502. package/dist/interfaces/addon.d.ts.map +0 -1
  503. package/dist/interfaces/advanced-notifier.d.ts.map +0 -1
  504. package/dist/interfaces/agent-protocol.d.ts.map +0 -1
  505. package/dist/interfaces/agent.d.ts.map +0 -1
  506. package/dist/interfaces/alerts.d.ts.map +0 -1
  507. package/dist/interfaces/analysis-persistence.d.ts.map +0 -1
  508. package/dist/interfaces/analysis.d.ts.map +0 -1
  509. package/dist/interfaces/api-responses.d.ts.map +0 -1
  510. package/dist/interfaces/api-shared.d.ts.map +0 -1
  511. package/dist/interfaces/audio-analyzer.d.ts.map +0 -1
  512. package/dist/interfaces/audio-codec.d.ts.map +0 -1
  513. package/dist/interfaces/audio-inference-engine.d.ts.map +0 -1
  514. package/dist/interfaces/auth.d.ts.map +0 -1
  515. package/dist/interfaces/camera-pipeline.d.ts.map +0 -1
  516. package/dist/interfaces/capability.d.ts.map +0 -1
  517. package/dist/interfaces/config-ui.d.ts.map +0 -1
  518. package/dist/interfaces/context.d.ts.map +0 -1
  519. package/dist/interfaces/decoder.d.ts.map +0 -1
  520. package/dist/interfaces/detection-addon.d.ts.map +0 -1
  521. package/dist/interfaces/device-capabilities/camera.d.ts.map +0 -1
  522. package/dist/interfaces/device-capabilities/index.d.ts.map +0 -1
  523. package/dist/interfaces/device-provider.d.ts.map +0 -1
  524. package/dist/interfaces/device.d.ts.map +0 -1
  525. package/dist/interfaces/embedding-encoder.d.ts.map +0 -1
  526. package/dist/interfaces/engine-slots.d.ts.map +0 -1
  527. package/dist/interfaces/event-bus.d.ts.map +0 -1
  528. package/dist/interfaces/feature-flags.d.ts.map +0 -1
  529. package/dist/interfaces/ffmpeg.d.ts.map +0 -1
  530. package/dist/interfaces/frame-handle.d.ts.map +0 -1
  531. package/dist/interfaces/inference-capabilities.d.ts.map +0 -1
  532. package/dist/interfaces/inference-engine.d.ts.map +0 -1
  533. package/dist/interfaces/integration-registry.d.ts.map +0 -1
  534. package/dist/interfaces/kernel-abstractions.d.ts.map +0 -1
  535. package/dist/interfaces/lifecycle.d.ts.map +0 -1
  536. package/dist/interfaces/logging.d.ts.map +0 -1
  537. package/dist/interfaces/metrics-provider.d.ts.map +0 -1
  538. package/dist/interfaces/network-quality.d.ts.map +0 -1
  539. package/dist/interfaces/network.d.ts.map +0 -1
  540. package/dist/interfaces/notification.d.ts.map +0 -1
  541. package/dist/interfaces/pipeline-executor-capability.d.ts.map +0 -1
  542. package/dist/interfaces/pipeline-orchestrator-capability.d.ts.map +0 -1
  543. package/dist/interfaces/pipeline-runner-capability.d.ts.map +0 -1
  544. package/dist/interfaces/pipeline-runner.d.ts.map +0 -1
  545. package/dist/interfaces/pipeline-slot.d.ts.map +0 -1
  546. package/dist/interfaces/platform.d.ts.map +0 -1
  547. package/dist/interfaces/process.d.ts.map +0 -1
  548. package/dist/interfaces/python-env.d.ts.map +0 -1
  549. package/dist/interfaces/queryable.d.ts.map +0 -1
  550. package/dist/interfaces/raw-tensor-engine.d.ts.map +0 -1
  551. package/dist/interfaces/readiness.d.ts.map +0 -1
  552. package/dist/interfaces/recording-config.d.ts.map +0 -1
  553. package/dist/interfaces/repl.d.ts.map +0 -1
  554. package/dist/interfaces/restreamer.d.ts.map +0 -1
  555. package/dist/interfaces/router.d.ts.map +0 -1
  556. package/dist/interfaces/rtp-egress.d.ts.map +0 -1
  557. package/dist/interfaces/scoped-token.d.ts.map +0 -1
  558. package/dist/interfaces/server-analysis.d.ts.map +0 -1
  559. package/dist/interfaces/server-network.d.ts.map +0 -1
  560. package/dist/interfaces/storage-location-declaration.d.ts.map +0 -1
  561. package/dist/interfaces/storage-location.d.ts.map +0 -1
  562. package/dist/interfaces/storage.d.ts.map +0 -1
  563. package/dist/interfaces/stream-broker.d.ts.map +0 -1
  564. package/dist/interfaces/streaming.d.ts.map +0 -1
  565. package/dist/interfaces/task-handler.d.ts.map +0 -1
  566. package/dist/interfaces/timezones.d.ts.map +0 -1
  567. package/dist/interfaces/webrtc-provider.d.ts.map +0 -1
  568. package/dist/node.d.ts.map +0 -1
  569. package/dist/node.js.map +0 -1
  570. package/dist/node.mjs.map +0 -1
  571. package/dist/readiness/index.d.ts.map +0 -1
  572. package/dist/readiness/readiness-registry.d.ts.map +0 -1
  573. package/dist/schemas/auth-records.d.ts.map +0 -1
  574. package/dist/storage/filesystem-storage-provider.d.ts.map +0 -1
  575. package/dist/stream-selection.d.ts.map +0 -1
  576. package/dist/types/agent-pipeline-settings.d.ts.map +0 -1
  577. package/dist/types/analytics.d.ts.map +0 -1
  578. package/dist/types/camera-detection.d.ts.map +0 -1
  579. package/dist/types/camera-pipeline.d.ts.map +0 -1
  580. package/dist/types/config.d.ts.map +0 -1
  581. package/dist/types/detection.d.ts.map +0 -1
  582. package/dist/types/device-type.d.ts.map +0 -1
  583. package/dist/types/engine-output.d.ts.map +0 -1
  584. package/dist/types/entities.d.ts.map +0 -1
  585. package/dist/types/events.d.ts.map +0 -1
  586. package/dist/types/io.d.ts.map +0 -1
  587. package/dist/types/labels.d.ts.map +0 -1
  588. package/dist/types/live-state.d.ts.map +0 -1
  589. package/dist/types/models.d.ts.map +0 -1
  590. package/dist/types/pipeline-schema.d.ts.map +0 -1
  591. package/dist/types/pipeline-step.d.ts.map +0 -1
  592. package/dist/types/pipeline.d.ts.map +0 -1
  593. package/dist/types/tracked.d.ts.map +0 -1
  594. package/dist/util/location-match.d.ts.map +0 -1
  595. package/dist/utils/canonical-hash.d.ts.map +0 -1
  596. package/dist/utils/cosine-similarity.d.ts.map +0 -1
  597. package/dist/utils/element-config-store.d.ts.map +0 -1
  598. package/dist/utils/err-msg.d.ts.map +0 -1
  599. package/dist/utils/export-reconciler.d.ts.map +0 -1
  600. package/dist/utils/hf-url.d.ts.map +0 -1
  601. package/dist/utils/json-safe.d.ts.map +0 -1
  602. package/dist/utils/mask-url.d.ts.map +0 -1
  603. package/dist/utils/privacy-grid-raster.d.ts.map +0 -1
  604. package/dist/utils/ring-buffer.d.ts.map +0 -1
  605. package/dist/utils/run-inference-step.d.ts.map +0 -1
  606. package/dist/utils/runtime-mapping.d.ts.map +0 -1
  607. package/dist/utils/sleep.d.ts.map +0 -1
  608. package/dist/utils/zone-rule-eval.d.ts.map +0 -1
package/dist/node.mjs CHANGED
@@ -1,485 +1,646 @@
1
+ import { errMsg } from "./index.mjs";
1
2
  import * as fs from "node:fs";
2
- import { existsSync, mkdirSync, createWriteStream, unlinkSync, chmodSync, readdirSync, rmSync, renameSync, writeFileSync, readFileSync } from "node:fs";
3
+ import { chmodSync, createWriteStream, existsSync, mkdirSync, readFileSync, readdirSync, renameSync, rmSync, unlinkSync, writeFileSync } from "node:fs";
3
4
  import * as path from "node:path";
4
- import { join, basename } from "node:path";
5
+ import { basename, join } from "node:path";
5
6
  import { pipeline } from "node:stream/promises";
6
7
  import { Readable } from "node:stream";
7
8
  import { execFileSync } from "node:child_process";
8
9
  import { createHash } from "node:crypto";
9
- import { e as errMsg } from "./index-Bpj3ScIH.mjs";
10
- import "zod";
10
+ //#region src/deps/binary-downloader.ts
11
11
  function getPlatformInfo() {
12
- return {
13
- platform: process.platform,
14
- arch: process.arch
15
- };
12
+ return {
13
+ platform: process.platform,
14
+ arch: process.arch
15
+ };
16
16
  }
17
17
  function buildBinaryPath(dataDir, name, platform) {
18
- const ext = (platform ?? process.platform) === "win32" ? ".exe" : "";
19
- return join(dataDir, "deps", `${name}${ext}`);
18
+ return join(dataDir, "deps", `${name}${(platform ?? process.platform) === "win32" ? ".exe" : ""}`);
20
19
  }
20
+ /** Check if a binary exists in PATH */
21
21
  function findInPath(name) {
22
- try {
23
- execFileSync(name, ["--version"], { stdio: "pipe", timeout: 5e3 });
24
- return name;
25
- } catch {
26
- return null;
27
- }
22
+ try {
23
+ execFileSync(name, ["--version"], {
24
+ stdio: "pipe",
25
+ timeout: 5e3
26
+ });
27
+ return name;
28
+ } catch {
29
+ return null;
30
+ }
28
31
  }
32
+ /**
33
+ * Download a binary to the target directory.
34
+ * Handles archives (zip, tar.gz, tar.xz) and raw binaries.
35
+ */
29
36
  async function downloadBinary(opts) {
30
- const { name, url, targetDir, targetName, logger, isArchive, archiveFormat, archiveInnerPath } = opts;
31
- const targetPath = join(targetDir, targetName);
32
- if (existsSync(targetPath)) {
33
- logger.debug("Binary already exists", { meta: { name, targetPath } });
34
- return targetPath;
35
- }
36
- mkdirSync(targetDir, { recursive: true });
37
- logger.info("Downloading binary", { meta: { name, url } });
38
- const response = await fetch(url, { redirect: "follow" });
39
- if (!response.ok || !response.body) {
40
- throw new Error(`Failed to download ${name}: ${response.status} ${response.statusText}`);
41
- }
42
- if (isArchive) {
43
- const ext = archiveFormat ?? "tar.gz";
44
- const tmpArchive = join(targetDir, `${name}-download.${ext}`);
45
- const nodeStream = Readable.fromWeb(response.body);
46
- await pipeline(nodeStream, createWriteStream(tmpArchive));
47
- const tmpExtractDir = join(targetDir, `${name}-extract`);
48
- mkdirSync(tmpExtractDir, { recursive: true });
49
- if (ext === "zip") {
50
- try {
51
- execFileSync("unzip", ["-o", "-q", tmpArchive, "-d", tmpExtractDir], { stdio: "pipe" });
52
- } catch {
53
- execFileSync("tar", ["-xf", tmpArchive, "-C", tmpExtractDir], { stdio: "pipe" });
54
- }
55
- } else if (ext === "tar.xz") {
56
- execFileSync("tar", ["-xJf", tmpArchive, "-C", tmpExtractDir], { stdio: "pipe" });
57
- } else {
58
- execFileSync("tar", ["-xzf", tmpArchive, "-C", tmpExtractDir], { stdio: "pipe" });
59
- }
60
- if (archiveInnerPath) {
61
- const { copyFileSync } = await import("node:fs");
62
- const sourcePath = join(tmpExtractDir, archiveInnerPath);
63
- if (!existsSync(sourcePath)) {
64
- throw new Error(`Binary not found in archive at ${archiveInnerPath}`);
65
- }
66
- copyFileSync(sourcePath, targetPath);
67
- }
68
- unlinkSync(tmpArchive);
69
- const { rmSync: rmSync2 } = await import("node:fs");
70
- rmSync2(tmpExtractDir, { recursive: true, force: true });
71
- } else {
72
- const nodeStream = Readable.fromWeb(response.body);
73
- await pipeline(nodeStream, createWriteStream(targetPath));
74
- }
75
- chmodSync(targetPath, 493);
76
- logger.info("Binary downloaded", { meta: { name, targetPath } });
77
- return targetPath;
37
+ const { name, url, targetDir, targetName, logger, isArchive, archiveFormat, archiveInnerPath } = opts;
38
+ const targetPath = join(targetDir, targetName);
39
+ if (existsSync(targetPath)) {
40
+ logger.debug("Binary already exists", { meta: {
41
+ name,
42
+ targetPath
43
+ } });
44
+ return targetPath;
45
+ }
46
+ mkdirSync(targetDir, { recursive: true });
47
+ logger.info("Downloading binary", { meta: {
48
+ name,
49
+ url
50
+ } });
51
+ const response = await fetch(url, { redirect: "follow" });
52
+ if (!response.ok || !response.body) throw new Error(`Failed to download ${name}: ${response.status} ${response.statusText}`);
53
+ if (isArchive) {
54
+ const ext = archiveFormat ?? "tar.gz";
55
+ const tmpArchive = join(targetDir, `${name}-download.${ext}`);
56
+ await pipeline(Readable.fromWeb(response.body), createWriteStream(tmpArchive));
57
+ const tmpExtractDir = join(targetDir, `${name}-extract`);
58
+ mkdirSync(tmpExtractDir, { recursive: true });
59
+ if (ext === "zip") try {
60
+ execFileSync("unzip", [
61
+ "-o",
62
+ "-q",
63
+ tmpArchive,
64
+ "-d",
65
+ tmpExtractDir
66
+ ], { stdio: "pipe" });
67
+ } catch {
68
+ execFileSync("tar", [
69
+ "-xf",
70
+ tmpArchive,
71
+ "-C",
72
+ tmpExtractDir
73
+ ], { stdio: "pipe" });
74
+ }
75
+ else if (ext === "tar.xz") execFileSync("tar", [
76
+ "-xJf",
77
+ tmpArchive,
78
+ "-C",
79
+ tmpExtractDir
80
+ ], { stdio: "pipe" });
81
+ else execFileSync("tar", [
82
+ "-xzf",
83
+ tmpArchive,
84
+ "-C",
85
+ tmpExtractDir
86
+ ], { stdio: "pipe" });
87
+ if (archiveInnerPath) {
88
+ const { copyFileSync } = await import("node:fs");
89
+ const sourcePath = join(tmpExtractDir, archiveInnerPath);
90
+ if (!existsSync(sourcePath)) throw new Error(`Binary not found in archive at ${archiveInnerPath}`);
91
+ copyFileSync(sourcePath, targetPath);
92
+ }
93
+ unlinkSync(tmpArchive);
94
+ const { rmSync } = await import("node:fs");
95
+ rmSync(tmpExtractDir, {
96
+ recursive: true,
97
+ force: true
98
+ });
99
+ } else await pipeline(Readable.fromWeb(response.body), createWriteStream(targetPath));
100
+ chmodSync(targetPath, 493);
101
+ logger.info("Binary downloaded", { meta: {
102
+ name,
103
+ targetPath
104
+ } });
105
+ return targetPath;
78
106
  }
107
+ /**
108
+ * Ensure a binary is available. Checks:
109
+ * 1. Target path (already downloaded)
110
+ * 2. System PATH
111
+ * 3. Download from URL
112
+ */
79
113
  async function ensureBinary(opts) {
80
- const ext = process.platform === "win32" ? ".exe" : "";
81
- const targetName = `${opts.name}${ext}`;
82
- const targetPath = join(opts.targetDir, targetName);
83
- if (existsSync(targetPath)) {
84
- opts.logger.debug("Binary found at target path", { meta: { name: opts.name, targetPath } });
85
- return targetPath;
86
- }
87
- const inPath = findInPath(opts.name);
88
- if (inPath) {
89
- opts.logger.info("Binary found in system PATH", { meta: { name: opts.name } });
90
- return inPath;
91
- }
92
- return downloadBinary({
93
- name: opts.name,
94
- url: opts.downloadUrl,
95
- targetDir: opts.targetDir,
96
- targetName,
97
- logger: opts.logger,
98
- isArchive: opts.isArchive,
99
- archiveFormat: opts.archiveFormat,
100
- archiveInnerPath: opts.archiveInnerPath
101
- });
114
+ const ext = process.platform === "win32" ? ".exe" : "";
115
+ const targetName = `${opts.name}${ext}`;
116
+ const targetPath = join(opts.targetDir, targetName);
117
+ if (existsSync(targetPath)) {
118
+ opts.logger.debug("Binary found at target path", { meta: {
119
+ name: opts.name,
120
+ targetPath
121
+ } });
122
+ return targetPath;
123
+ }
124
+ const inPath = findInPath(opts.name);
125
+ if (inPath) {
126
+ opts.logger.info("Binary found in system PATH", { meta: { name: opts.name } });
127
+ return inPath;
128
+ }
129
+ return downloadBinary({
130
+ name: opts.name,
131
+ url: opts.downloadUrl,
132
+ targetDir: opts.targetDir,
133
+ targetName,
134
+ logger: opts.logger,
135
+ isArchive: opts.isArchive,
136
+ archiveFormat: opts.archiveFormat,
137
+ archiveInnerPath: opts.archiveInnerPath
138
+ });
102
139
  }
103
- const FFMPEG_VERSION = "7.1";
140
+ //#endregion
141
+ //#region src/deps/ffmpeg-downloader.ts
142
+ /**
143
+ * Download ffmpeg static build for the current platform.
144
+ *
145
+ * Sources:
146
+ * - Linux: https://johnvansickle.com/ffmpeg/ (static builds)
147
+ * - macOS: https://evermeet.cx/ffmpeg/ or homebrew
148
+ *
149
+ * Using BtbN's GitHub releases as they cover both platforms:
150
+ * https://github.com/BtbN/FFmpeg-Builds/releases
151
+ */
152
+ var FFMPEG_VERSION = "7.1";
104
153
  function getFfmpegDownloadUrl(platform, arch) {
105
- switch (platform) {
106
- case "linux": {
107
- const archMap = { x64: "amd64", arm64: "arm64" };
108
- const a = archMap[arch];
109
- if (!a) throw new Error(`Unsupported Linux architecture: ${arch}`);
110
- return `https://johnvansickle.com/ffmpeg/releases/ffmpeg-release-${a}-static.tar.xz`;
111
- }
112
- case "darwin": {
113
- const archMap = { arm64: "arm64", x64: "amd64" };
114
- const a = archMap[arch];
115
- if (!a) throw new Error(`Unsupported macOS architecture: ${arch}`);
116
- return `https://www.osxexperts.net/ffmpeg${FFMPEG_VERSION.replace(".", "")}arm.zip`;
117
- }
118
- default:
119
- throw new Error(`Unsupported platform: ${platform}`);
120
- }
154
+ switch (platform) {
155
+ case "linux": {
156
+ const a = {
157
+ x64: "amd64",
158
+ arm64: "arm64"
159
+ }[arch];
160
+ if (!a) throw new Error(`Unsupported Linux architecture: ${arch}`);
161
+ return `https://johnvansickle.com/ffmpeg/releases/ffmpeg-release-${a}-static.tar.xz`;
162
+ }
163
+ case "darwin":
164
+ if (!{
165
+ arm64: "arm64",
166
+ x64: "amd64"
167
+ }[arch]) throw new Error(`Unsupported macOS architecture: ${arch}`);
168
+ return `https://www.osxexperts.net/ffmpeg${FFMPEG_VERSION.replace(".", "")}arm.zip`;
169
+ default: throw new Error(`Unsupported platform: ${platform}`);
170
+ }
121
171
  }
122
172
  function getFfmpegArchiveInfo(platform) {
123
- switch (platform) {
124
- case "linux":
125
- return {
126
- isArchive: true,
127
- archiveFormat: "tar.xz",
128
- archiveInnerPath: `ffmpeg-${FFMPEG_VERSION}-amd64-static/ffmpeg`
129
- };
130
- case "darwin":
131
- return {
132
- isArchive: true,
133
- archiveFormat: "zip",
134
- archiveInnerPath: "ffmpeg"
135
- };
136
- default:
137
- throw new Error(`Unsupported platform: ${platform}`);
138
- }
173
+ switch (platform) {
174
+ case "linux": return {
175
+ isArchive: true,
176
+ archiveFormat: "tar.xz",
177
+ archiveInnerPath: `ffmpeg-${FFMPEG_VERSION}-amd64-static/ffmpeg`
178
+ };
179
+ case "darwin": return {
180
+ isArchive: true,
181
+ archiveFormat: "zip",
182
+ archiveInnerPath: "ffmpeg"
183
+ };
184
+ default: throw new Error(`Unsupported platform: ${platform}`);
185
+ }
139
186
  }
187
+ /**
188
+ * Ensure ffmpeg binary is available.
189
+ * Checks: deps dir → system PATH → download.
190
+ */
140
191
  async function ensureFfmpeg(dataDir, logger) {
141
- const depsDir = join(dataDir, "deps");
142
- const platform = process.platform;
143
- const arch = process.arch;
144
- const archiveInfo = getFfmpegArchiveInfo(platform);
145
- return ensureBinary({
146
- name: "ffmpeg",
147
- targetDir: depsDir,
148
- downloadUrl: getFfmpegDownloadUrl(platform, arch),
149
- logger,
150
- ...archiveInfo
151
- });
192
+ const depsDir = join(dataDir, "deps");
193
+ const platform = process.platform;
194
+ const arch = process.arch;
195
+ const archiveInfo = getFfmpegArchiveInfo(platform);
196
+ return ensureBinary({
197
+ name: "ffmpeg",
198
+ targetDir: depsDir,
199
+ downloadUrl: getFfmpegDownloadUrl(platform, arch),
200
+ logger,
201
+ ...archiveInfo
202
+ });
152
203
  }
153
- const PYTHON_VERSION = "3.12.12";
154
- const PP_BASE = `https://github.com/bjia56/portable-python/releases/download/cpython-v${PYTHON_VERSION}-build.0`;
204
+ //#endregion
205
+ //#region src/deps/python-downloader.ts
206
+ /**
207
+ * Download portable Python (headless) from bjia56/portable-python.
208
+ *
209
+ * Source: https://github.com/bjia56/portable-python
210
+ *
211
+ * Advantages over python-build-standalone:
212
+ * - macOS universal2 binary (arm64+x86_64 in one)
213
+ * - Lighter (~24-28MB headless zip)
214
+ * - glibc 2.17 minimum (better compat)
215
+ * - Headless variant excludes tkinter/UI (ideal for ML inference)
216
+ *
217
+ * The zip's top-level dir is platform-specific (e.g.
218
+ * `python-headless-3.12.12-darwin-universal2/`); after extraction
219
+ * we rename it to a stable `python/` so consumers can rely on
220
+ * `<dataDir>/deps/python/bin/python3`.
221
+ */
222
+ var PYTHON_VERSION = "3.12.12";
223
+ var PP_BASE = `https://github.com/bjia56/portable-python/releases/download/cpython-v${PYTHON_VERSION}-build.0`;
155
224
  function getPythonDownloadUrl(platform, arch) {
156
- switch (platform) {
157
- case "linux": {
158
- const archMap = { x64: "x86_64", arm64: "aarch64" };
159
- const a = archMap[arch];
160
- if (!a) throw new Error(`Unsupported Linux architecture for Python: ${arch}`);
161
- return `${PP_BASE}/python-headless-${PYTHON_VERSION}-linux-${a}.zip`;
162
- }
163
- case "darwin": {
164
- return `${PP_BASE}/python-headless-${PYTHON_VERSION}-darwin-universal2.zip`;
165
- }
166
- default:
167
- throw new Error(`Unsupported platform for portable Python: ${platform}`);
168
- }
225
+ switch (platform) {
226
+ case "linux": {
227
+ const a = {
228
+ x64: "x86_64",
229
+ arm64: "aarch64"
230
+ }[arch];
231
+ if (!a) throw new Error(`Unsupported Linux architecture for Python: ${arch}`);
232
+ return `${PP_BASE}/python-headless-${PYTHON_VERSION}-linux-${a}.zip`;
233
+ }
234
+ case "darwin": return `${PP_BASE}/python-headless-${PYTHON_VERSION}-darwin-universal2.zip`;
235
+ default: throw new Error(`Unsupported platform for portable Python: ${platform}`);
236
+ }
169
237
  }
238
+ /**
239
+ * Ensure the embedded portable Python is available.
240
+ *
241
+ * ALWAYS returns the path to the embedded interpreter under
242
+ * `<dataDir>/deps/python/bin/python3` — downloads it on first call
243
+ * and reuses it thereafter. The system PATH is intentionally NOT
244
+ * consulted: addons rely on `installPythonRequirements()` to manage
245
+ * deps inside the embedded site-packages, and a system interpreter
246
+ * (different version, missing modules) silently breaks that contract.
247
+ *
248
+ * Returns null only if the download/extract step fails.
249
+ */
170
250
  async function ensurePython(dataDir, logger) {
171
- const pythonDir = join(dataDir, "deps", "python");
172
- const pythonBin = join(pythonDir, "bin", "python3");
173
- if (existsSync(pythonBin)) {
174
- logger.debug("Portable Python found", { meta: { pythonBin } });
175
- return pythonBin;
176
- }
177
- logger.info("Downloading portable Python (headless)", { meta: { version: PYTHON_VERSION } });
178
- const depsDir = join(dataDir, "deps");
179
- mkdirSync(depsDir, { recursive: true });
180
- const url = getPythonDownloadUrl(process.platform, process.arch);
181
- const tmpArchive = join(depsDir, "python-download.zip");
182
- logger.info("Python download source", { meta: { url } });
183
- const response = await fetch(url, { redirect: "follow" });
184
- if (!response.ok || !response.body) {
185
- logger.warn("Failed to download Python — ML detection will not be available", { meta: { status: response.status } });
186
- return null;
187
- }
188
- const nodeStream = Readable.fromWeb(response.body);
189
- await pipeline(nodeStream, createWriteStream(tmpArchive));
190
- try {
191
- execFileSync("unzip", ["-o", "-q", tmpArchive, "-d", depsDir], { stdio: "pipe" });
192
- } catch {
193
- execFileSync("python3", ["-m", "zipfile", "-e", tmpArchive, depsDir], { stdio: "pipe" });
194
- }
195
- const { unlinkSync: unlinkSync2 } = await import("node:fs");
196
- unlinkSync2(tmpArchive);
197
- if (!existsSync(pythonBin)) {
198
- const candidates = readdirSync(depsDir).filter(
199
- (name) => name.startsWith("python-") && existsSync(join(depsDir, name, "bin", "python3"))
200
- );
201
- if (candidates.length === 0) {
202
- logger.warn("Python extraction succeeded but no python3 binary found in any subdir", {
203
- meta: { depsDir }
204
- });
205
- return null;
206
- }
207
- const extractedRoot = join(depsDir, candidates[0]);
208
- if (existsSync(pythonDir)) {
209
- rmSync(pythonDir, { recursive: true, force: true });
210
- }
211
- renameSync(extractedRoot, pythonDir);
212
- }
213
- if (!existsSync(pythonBin)) {
214
- logger.warn("Python extraction succeeded but binary not found at expected path", {
215
- meta: { pythonBin }
216
- });
217
- return null;
218
- }
219
- chmodSync(pythonBin, 493);
220
- if (process.platform === "darwin") {
221
- const realBin = join(pythonDir, "bin", "python3.real");
222
- if (!existsSync(realBin)) {
223
- renameSync(pythonBin, realBin);
224
- const archFlag = process.arch === "arm64" ? "-arm64" : "-x86_64";
225
- writeFileSync(
226
- pythonBin,
227
- `#!/bin/sh
228
- exec /usr/bin/arch ${archFlag} "${realBin}" "$@"
229
- `
230
- );
231
- chmodSync(pythonBin, 493);
232
- const pyAlt = join(pythonDir, "bin", "python");
233
- if (existsSync(pyAlt)) {
234
- try {
235
- rmSync(pyAlt, { force: true });
236
- } catch {
237
- }
238
- writeFileSync(
239
- pyAlt,
240
- `#!/bin/sh
241
- exec /usr/bin/arch ${archFlag} "${realBin}" "$@"
242
- `
243
- );
244
- chmodSync(pyAlt, 493);
245
- }
246
- logger.info("Locked python3 to host arch via shell stub", {
247
- meta: { archFlag, realBin }
248
- });
249
- }
250
- }
251
- logger.info("Portable Python installed", { meta: { version: PYTHON_VERSION, pythonBin } });
252
- return pythonBin;
251
+ const pythonDir = join(dataDir, "deps", "python");
252
+ const pythonBin = join(pythonDir, "bin", "python3");
253
+ if (existsSync(pythonBin)) {
254
+ logger.debug("Portable Python found", { meta: { pythonBin } });
255
+ return pythonBin;
256
+ }
257
+ logger.info("Downloading portable Python (headless)", { meta: { version: PYTHON_VERSION } });
258
+ const depsDir = join(dataDir, "deps");
259
+ mkdirSync(depsDir, { recursive: true });
260
+ const url = getPythonDownloadUrl(process.platform, process.arch);
261
+ const tmpArchive = join(depsDir, "python-download.zip");
262
+ logger.info("Python download source", { meta: { url } });
263
+ const response = await fetch(url, { redirect: "follow" });
264
+ if (!response.ok || !response.body) {
265
+ logger.warn("Failed to download Python — ML detection will not be available", { meta: { status: response.status } });
266
+ return null;
267
+ }
268
+ await pipeline(Readable.fromWeb(response.body), createWriteStream(tmpArchive));
269
+ try {
270
+ execFileSync("unzip", [
271
+ "-o",
272
+ "-q",
273
+ tmpArchive,
274
+ "-d",
275
+ depsDir
276
+ ], { stdio: "pipe" });
277
+ } catch {
278
+ execFileSync("python3", [
279
+ "-m",
280
+ "zipfile",
281
+ "-e",
282
+ tmpArchive,
283
+ depsDir
284
+ ], { stdio: "pipe" });
285
+ }
286
+ const { unlinkSync } = await import("node:fs");
287
+ unlinkSync(tmpArchive);
288
+ if (!existsSync(pythonBin)) {
289
+ const candidates = readdirSync(depsDir).filter((name) => name.startsWith("python-") && existsSync(join(depsDir, name, "bin", "python3")));
290
+ if (candidates.length === 0) {
291
+ logger.warn("Python extraction succeeded but no python3 binary found in any subdir", { meta: { depsDir } });
292
+ return null;
293
+ }
294
+ const extractedRoot = join(depsDir, candidates[0]);
295
+ if (existsSync(pythonDir)) rmSync(pythonDir, {
296
+ recursive: true,
297
+ force: true
298
+ });
299
+ renameSync(extractedRoot, pythonDir);
300
+ }
301
+ if (!existsSync(pythonBin)) {
302
+ logger.warn("Python extraction succeeded but binary not found at expected path", { meta: { pythonBin } });
303
+ return null;
304
+ }
305
+ chmodSync(pythonBin, 493);
306
+ if (process.platform === "darwin") {
307
+ const realBin = join(pythonDir, "bin", "python3.real");
308
+ if (!existsSync(realBin)) {
309
+ renameSync(pythonBin, realBin);
310
+ const archFlag = process.arch === "arm64" ? "-arm64" : "-x86_64";
311
+ writeFileSync(pythonBin, `#!/bin/sh\nexec /usr/bin/arch ${archFlag} "${realBin}" "$@"\n`);
312
+ chmodSync(pythonBin, 493);
313
+ const pyAlt = join(pythonDir, "bin", "python");
314
+ if (existsSync(pyAlt)) {
315
+ try {
316
+ rmSync(pyAlt, { force: true });
317
+ } catch {}
318
+ writeFileSync(pyAlt, `#!/bin/sh\nexec /usr/bin/arch ${archFlag} "${realBin}" "$@"\n`);
319
+ chmodSync(pyAlt, 493);
320
+ }
321
+ logger.info("Locked python3 to host arch via shell stub", { meta: {
322
+ archFlag,
323
+ realBin
324
+ } });
325
+ }
326
+ }
327
+ logger.info("Portable Python installed", { meta: {
328
+ version: PYTHON_VERSION,
329
+ pythonBin
330
+ } });
331
+ return pythonBin;
253
332
  }
333
+ /**
334
+ * Install Python packages into the portable Python environment.
335
+ */
254
336
  async function installPythonPackages(pythonPath, packages, logger) {
255
- if (packages.length === 0) return;
256
- logger.info("Installing Python packages", { meta: { packages } });
257
- try {
258
- execFileSync(pythonPath, ["-m", "pip", "install", "--quiet", ...packages], {
259
- stdio: "pipe",
260
- timeout: 3e5
261
- // 5 minutes for large packages like torch
262
- });
263
- logger.info("Python packages installed successfully");
264
- } catch (err) {
265
- logger.error("Failed to install Python packages", { meta: { error: errMsg(err) } });
266
- throw err;
267
- }
337
+ if (packages.length === 0) return;
338
+ logger.info("Installing Python packages", { meta: { packages } });
339
+ try {
340
+ execFileSync(pythonPath, [
341
+ "-m",
342
+ "pip",
343
+ "install",
344
+ "--quiet",
345
+ ...packages
346
+ ], {
347
+ stdio: "pipe",
348
+ timeout: 3e5
349
+ });
350
+ logger.info("Python packages installed successfully");
351
+ } catch (err) {
352
+ logger.error("Failed to install Python packages", { meta: { error: errMsg(err) } });
353
+ throw err;
354
+ }
268
355
  }
356
+ /**
357
+ * Install a pip requirements file into the embedded Python.
358
+ *
359
+ * Idempotent: keyed on (requirements file basename + sha256 of its
360
+ * contents). The marker is written under
361
+ * `<python-install-dir>/.requirements-installed/` so it lives and
362
+ * dies with the python install — re-downloading python wipes both
363
+ * the site-packages and the markers, forcing a fresh re-install.
364
+ *
365
+ * The marker is updated only after `pip install` succeeds. A failed
366
+ * install never writes a marker, so the next call retries.
367
+ */
269
368
  async function installPythonRequirements(pythonPath, requirementsFile, logger) {
270
- if (!existsSync(requirementsFile)) {
271
- throw new Error(`Requirements file not found: ${requirementsFile}`);
272
- }
273
- const contents = readFileSync(requirementsFile);
274
- const hash = createHash("sha256").update(contents).digest("hex").slice(0, 16);
275
- const fileBase = basename(requirementsFile).replace(/\.txt$/i, "");
276
- const pythonRoot = join(pythonPath, "..", "..");
277
- const markerDir = join(pythonRoot, ".requirements-installed");
278
- const markerPath = join(markerDir, `${fileBase}-${hash}.marker`);
279
- if (existsSync(markerPath)) {
280
- logger.debug("Python requirements already installed", { meta: { requirementsFile, hash } });
281
- return;
282
- }
283
- logger.info("Installing Python requirements", { meta: { requirementsFile, hash } });
284
- try {
285
- execFileSync(
286
- pythonPath,
287
- ["-m", "pip", "install", "--quiet", "--disable-pip-version-check", "-r", requirementsFile],
288
- {
289
- stdio: "pipe",
290
- timeout: 6e5
291
- // 10 minutes — coremltools + tensorflow can be slow
292
- }
293
- );
294
- } catch (err) {
295
- logger.error("Failed to install Python requirements", {
296
- meta: { requirementsFile, error: errMsg(err) }
297
- });
298
- throw err;
299
- }
300
- mkdirSync(markerDir, { recursive: true });
301
- writeFileSync(markerPath, `${requirementsFile}
302
- ${(/* @__PURE__ */ new Date()).toISOString()}
303
- `);
304
- logger.info("Python requirements installed", { meta: { requirementsFile, hash } });
369
+ if (!existsSync(requirementsFile)) throw new Error(`Requirements file not found: ${requirementsFile}`);
370
+ const contents = readFileSync(requirementsFile);
371
+ const hash = createHash("sha256").update(contents).digest("hex").slice(0, 16);
372
+ const fileBase = basename(requirementsFile).replace(/\.txt$/i, "");
373
+ const markerDir = join(join(pythonPath, "..", ".."), ".requirements-installed");
374
+ const markerPath = join(markerDir, `${fileBase}-${hash}.marker`);
375
+ if (existsSync(markerPath)) {
376
+ logger.debug("Python requirements already installed", { meta: {
377
+ requirementsFile,
378
+ hash
379
+ } });
380
+ return;
381
+ }
382
+ logger.info("Installing Python requirements", { meta: {
383
+ requirementsFile,
384
+ hash
385
+ } });
386
+ try {
387
+ execFileSync(pythonPath, [
388
+ "-m",
389
+ "pip",
390
+ "install",
391
+ "--quiet",
392
+ "--disable-pip-version-check",
393
+ "-r",
394
+ requirementsFile
395
+ ], {
396
+ stdio: "pipe",
397
+ timeout: 6e5
398
+ });
399
+ } catch (err) {
400
+ logger.error("Failed to install Python requirements", { meta: {
401
+ requirementsFile,
402
+ error: errMsg(err)
403
+ } });
404
+ throw err;
405
+ }
406
+ mkdirSync(markerDir, { recursive: true });
407
+ writeFileSync(markerPath, `${requirementsFile}\n${(/* @__PURE__ */ new Date()).toISOString()}\n`);
408
+ logger.info("Python requirements installed", { meta: {
409
+ requirementsFile,
410
+ hash
411
+ } });
305
412
  }
306
- const STORAGE_LOCATION_TYPES = [
307
- "data",
308
- "media",
309
- "recordings",
310
- "recordings-high",
311
- "recordings-low",
312
- "recordings-clips",
313
- "event-images",
314
- "models",
315
- "addons-data",
316
- "cache",
317
- "logs",
318
- "backups"
413
+ //#endregion
414
+ //#region src/storage/filesystem-storage-provider.ts
415
+ var STORAGE_LOCATION_TYPES = [
416
+ "data",
417
+ "media",
418
+ "recordings",
419
+ "recordings-high",
420
+ "recordings-low",
421
+ "recordings-clips",
422
+ "event-images",
423
+ "models",
424
+ "addons-data",
425
+ "cache",
426
+ "logs",
427
+ "backups"
319
428
  ];
320
- const DEFAULT_LOCATION_SUBDIRS = {
321
- "data": "db",
322
- "media": "media",
323
- "recordings": "recordings",
324
- "recordings-high": "recordings-high",
325
- "recordings-low": "recordings-low",
326
- "recordings-clips": "recordings-clips",
327
- "event-images": "event-images",
328
- "models": "models",
329
- "addons-data": "addons-data",
330
- "cache": "/tmp/camstack-cache",
331
- "logs": "logs",
332
- "backups": "backups"
429
+ var DEFAULT_LOCATION_SUBDIRS = {
430
+ data: "db",
431
+ media: "media",
432
+ recordings: "recordings",
433
+ "recordings-high": "recordings-high",
434
+ "recordings-low": "recordings-low",
435
+ "recordings-clips": "recordings-clips",
436
+ "event-images": "event-images",
437
+ models: "models",
438
+ "addons-data": "addons-data",
439
+ cache: "/tmp/camstack-cache",
440
+ logs: "logs",
441
+ backups: "backups"
333
442
  };
334
- class FilesystemStorageProvider {
335
- id = "local";
336
- name = "Local Filesystem";
337
- supportedLocations = [...STORAGE_LOCATION_TYPES];
338
- rootPath;
339
- locationPaths;
340
- constructor(rootPath, overrides) {
341
- this.rootPath = path.resolve(rootPath);
342
- this.locationPaths = /* @__PURE__ */ new Map();
343
- for (const loc of STORAGE_LOCATION_TYPES) {
344
- const override = overrides?.[loc];
345
- if (override) {
346
- this.locationPaths.set(loc, path.resolve(override));
347
- } else {
348
- const subdir = DEFAULT_LOCATION_SUBDIRS[loc] ?? loc;
349
- this.locationPaths.set(
350
- loc,
351
- path.isAbsolute(subdir) ? subdir : path.join(this.rootPath, subdir)
352
- );
353
- }
354
- }
355
- }
356
- async resolve({ location, relativePath }) {
357
- const base = this.locationPaths.get(location) ?? path.join(this.rootPath, location);
358
- return path.join(base, relativePath);
359
- }
360
- async write({ location, relativePath, data }) {
361
- const filePath = await this.resolve({ location, relativePath });
362
- await fs.promises.mkdir(path.dirname(filePath), { recursive: true });
363
- if (Buffer.isBuffer(data)) {
364
- await fs.promises.writeFile(filePath, data);
365
- } else {
366
- const writeStream = fs.createWriteStream(filePath);
367
- await new Promise((resolve, reject) => {
368
- data.pipe(writeStream);
369
- writeStream.on("finish", resolve);
370
- writeStream.on("error", reject);
371
- });
372
- }
373
- }
374
- async read({ location, relativePath }) {
375
- return fs.promises.readFile(await this.resolve({ location, relativePath }));
376
- }
377
- async exists({ location, relativePath }) {
378
- try {
379
- await fs.promises.access(await this.resolve({ location, relativePath }));
380
- return true;
381
- } catch {
382
- return false;
383
- }
384
- }
385
- async list({ location, prefix }) {
386
- const base = this.locationPaths.get(location);
387
- if (!base) return [];
388
- const dir = prefix ? path.join(base, prefix) : base;
389
- try {
390
- const entries = await fs.promises.readdir(dir, { withFileTypes: true });
391
- return entries.map((e) => prefix ? `${prefix}/${e.name}` : e.name);
392
- } catch {
393
- return [];
394
- }
395
- }
396
- async delete({ location, relativePath }) {
397
- const filePath = await this.resolve({ location, relativePath });
398
- await fs.promises.rm(filePath, { force: true });
399
- }
400
- async getAvailableSpace({ location }) {
401
- const base = this.locationPaths.get(location);
402
- if (!base) return null;
403
- try {
404
- let target = base;
405
- while (!fs.existsSync(target)) {
406
- const parent = path.dirname(target);
407
- if (!parent || parent === target) return null;
408
- target = parent;
409
- }
410
- const stats = await fs.promises.statfs(target);
411
- return stats.bavail * stats.bsize;
412
- } catch {
413
- return null;
414
- }
415
- }
416
- /** Get the resolved path for a location type (addon-declared ids fall back
417
- * to `<rootPath>/<id>`). */
418
- getLocationPath(location) {
419
- return this.locationPaths.get(location) ?? path.join(this.rootPath, location);
420
- }
421
- /** Get the root path */
422
- getRootPath() {
423
- return this.rootPath;
424
- }
425
- }
443
+ /**
444
+ * Filesystem storage provider — serves all location types from a local directory tree.
445
+ *
446
+ * Default layout:
447
+ * {rootPath}/recordings-high/
448
+ * {rootPath}/recordings-low/
449
+ * {rootPath}/recordings-clips/
450
+ * {rootPath}/event-images/
451
+ * {rootPath}/models/
452
+ * {rootPath}/addons-data/
453
+ * {rootPath}/logs/
454
+ * /tmp/camstack-cache/ (cache is always local)
455
+ *
456
+ * Individual location paths can be overridden.
457
+ */
458
+ var FilesystemStorageProvider = class {
459
+ id = "local";
460
+ name = "Local Filesystem";
461
+ supportedLocations = [...STORAGE_LOCATION_TYPES];
462
+ rootPath;
463
+ locationPaths;
464
+ constructor(rootPath, overrides) {
465
+ this.rootPath = path.resolve(rootPath);
466
+ this.locationPaths = /* @__PURE__ */ new Map();
467
+ for (const loc of STORAGE_LOCATION_TYPES) {
468
+ const override = overrides?.[loc];
469
+ if (override) this.locationPaths.set(loc, path.resolve(override));
470
+ else {
471
+ const subdir = DEFAULT_LOCATION_SUBDIRS[loc] ?? loc;
472
+ this.locationPaths.set(loc, path.isAbsolute(subdir) ? subdir : path.join(this.rootPath, subdir));
473
+ }
474
+ }
475
+ }
476
+ async resolve({ location, relativePath }) {
477
+ const base = this.locationPaths.get(location) ?? path.join(this.rootPath, location);
478
+ return path.join(base, relativePath);
479
+ }
480
+ async write({ location, relativePath, data }) {
481
+ const filePath = await this.resolve({
482
+ location,
483
+ relativePath
484
+ });
485
+ await fs.promises.mkdir(path.dirname(filePath), { recursive: true });
486
+ if (Buffer.isBuffer(data)) await fs.promises.writeFile(filePath, data);
487
+ else {
488
+ const writeStream = fs.createWriteStream(filePath);
489
+ await new Promise((resolve, reject) => {
490
+ data.pipe(writeStream);
491
+ writeStream.on("finish", resolve);
492
+ writeStream.on("error", reject);
493
+ });
494
+ }
495
+ }
496
+ async read({ location, relativePath }) {
497
+ return fs.promises.readFile(await this.resolve({
498
+ location,
499
+ relativePath
500
+ }));
501
+ }
502
+ async exists({ location, relativePath }) {
503
+ try {
504
+ await fs.promises.access(await this.resolve({
505
+ location,
506
+ relativePath
507
+ }));
508
+ return true;
509
+ } catch {
510
+ return false;
511
+ }
512
+ }
513
+ async list({ location, prefix }) {
514
+ const base = this.locationPaths.get(location);
515
+ if (!base) return [];
516
+ const dir = prefix ? path.join(base, prefix) : base;
517
+ try {
518
+ return (await fs.promises.readdir(dir, { withFileTypes: true })).map((e) => prefix ? `${prefix}/${e.name}` : e.name);
519
+ } catch {
520
+ return [];
521
+ }
522
+ }
523
+ async delete({ location, relativePath }) {
524
+ const filePath = await this.resolve({
525
+ location,
526
+ relativePath
527
+ });
528
+ await fs.promises.rm(filePath, { force: true });
529
+ }
530
+ async getAvailableSpace({ location }) {
531
+ const base = this.locationPaths.get(location);
532
+ if (!base) return null;
533
+ try {
534
+ let target = base;
535
+ while (!fs.existsSync(target)) {
536
+ const parent = path.dirname(target);
537
+ if (!parent || parent === target) return null;
538
+ target = parent;
539
+ }
540
+ const stats = await fs.promises.statfs(target);
541
+ return stats.bavail * stats.bsize;
542
+ } catch {
543
+ return null;
544
+ }
545
+ }
546
+ /** Get the resolved path for a location type (addon-declared ids fall back
547
+ * to `<rootPath>/<id>`). */
548
+ getLocationPath(location) {
549
+ return this.locationPaths.get(location) ?? path.join(this.rootPath, location);
550
+ }
551
+ /** Get the root path */
552
+ getRootPath() {
553
+ return this.rootPath;
554
+ }
555
+ };
556
+ //#endregion
557
+ //#region src/utils/canonical-hash.ts
558
+ /**
559
+ * Deterministic SHA-256 hash of an arbitrary serialisable value. The
560
+ * canonical form sorts object keys alphabetically at every depth so two
561
+ * structurally-equal inputs with different key insertion orders produce
562
+ * the same hash. Returns a 64-char lowercase hex digest.
563
+ *
564
+ * Used by export adapters (Alexa, HAP) to short-circuit re-discovery /
565
+ * accessory-rebuild work when the upstream shape is byte-identical to
566
+ * the last applied state — preventing user-visible "re-discovery"
567
+ * notifications on every addon-runner respawn. Each respawn re-fires
568
+ * `DeviceBindingsChanged` for every cap registration, which without
569
+ * this guard would propagate redundant pushes.
570
+ *
571
+ * Note: this is a SYMPTOMATIC fix layered on top of the binding-change
572
+ * subscription. The proper fix is a single "device ready" lifecycle
573
+ * barrier so exports react only when the full cap set has landed —
574
+ * tracked separately for post-HA-integration work.
575
+ */
426
576
  function canonicalHash(value) {
427
- const canonical = JSON.stringify(value, replaceWithSortedKeys);
428
- return createHash("sha256").update(canonical ?? "").digest("hex");
577
+ const canonical = JSON.stringify(value, replaceWithSortedKeys);
578
+ return createHash("sha256").update(canonical ?? "").digest("hex");
429
579
  }
430
580
  function replaceWithSortedKeys(_key, value) {
431
- if (value && typeof value === "object" && !Array.isArray(value)) {
432
- const obj = value;
433
- const out = {};
434
- for (const k of Object.keys(obj).sort()) out[k] = obj[k];
435
- return out;
436
- }
437
- return value;
581
+ if (value && typeof value === "object" && !Array.isArray(value)) {
582
+ const obj = value;
583
+ const out = {};
584
+ for (const k of Object.keys(obj).toSorted()) out[k] = obj[k];
585
+ return out;
586
+ }
587
+ return value;
438
588
  }
589
+ //#endregion
590
+ //#region src/utils/export-reconciler.ts
591
+ /**
592
+ * Compute the stable 64-char lowercase-hex fingerprint of a device's
593
+ * export-relevant shape. Two structurally-equal shapes (any feature order,
594
+ * any duplicates, any deviceId) hash identically.
595
+ */
439
596
  function canonicalDeviceFingerprint(shape) {
440
- const features = [...new Set(shape.features)].sort();
441
- return canonicalHash({ deviceType: shape.deviceType, features });
597
+ const features = [...new Set(shape.features)].toSorted();
598
+ return canonicalHash({
599
+ deviceType: shape.deviceType,
600
+ features
601
+ });
442
602
  }
603
+ /**
604
+ * Pure 3-way diff of desired export state against the persisted
605
+ * last-advertised state, keyed by `deviceId`.
606
+ *
607
+ * - `desired` — one entry per device to advertise this cycle, each carrying
608
+ * the freshly-computed `fingerprint`.
609
+ * - `lastAdvertised` — the exporter's persisted per-target sync state.
610
+ *
611
+ * Neither input is mutated.
612
+ */
443
613
  function diffExportTargets(desired, lastAdvertised) {
444
- const toAdd = [];
445
- const toUpdate = [];
446
- const desiredIds = /* @__PURE__ */ new Set();
447
- for (const entry of desired) {
448
- desiredIds.add(entry.deviceId);
449
- const previous = lastAdvertised.get(entry.deviceId);
450
- if (previous === void 0) {
451
- toAdd.push(entry);
452
- } else if (previous.fingerprint !== entry.fingerprint) {
453
- toUpdate.push(entry);
454
- }
455
- }
456
- const toRemove = [];
457
- for (const deviceId of lastAdvertised.keys()) {
458
- if (!desiredIds.has(deviceId)) toRemove.push(deviceId);
459
- }
460
- return { toAdd, toUpdate, toRemove };
614
+ const toAdd = [];
615
+ const toUpdate = [];
616
+ const desiredIds = /* @__PURE__ */ new Set();
617
+ for (const entry of desired) {
618
+ desiredIds.add(entry.deviceId);
619
+ const previous = lastAdvertised.get(entry.deviceId);
620
+ if (previous === void 0) toAdd.push(entry);
621
+ else if (previous.fingerprint !== entry.fingerprint) toUpdate.push(entry);
622
+ }
623
+ const toRemove = [];
624
+ for (const deviceId of lastAdvertised.keys()) if (!desiredIds.has(deviceId)) toRemove.push(deviceId);
625
+ return {
626
+ toAdd,
627
+ toUpdate,
628
+ toRemove
629
+ };
461
630
  }
631
+ /**
632
+ * Resolve the fingerprint an exporter should feed into `diffExportTargets`
633
+ * for one device this cycle.
634
+ *
635
+ * When a device is NOT yet probe-ready, carry forward its last-advertised
636
+ * (persisted) fingerprint so it nets to NO CHANGE in `diffExportTargets`
637
+ * (neither update nor remove) — never advertise a partial mid-probe shape. A
638
+ * brand-new un-probed device with no persisted entry falls back to `fresh` so
639
+ * it can advertise once.
640
+ */
462
641
  function resolveExportFingerprint(input) {
463
- if (input.ready) return input.fresh;
464
- return input.persisted ?? input.fresh;
642
+ if (input.ready) return input.fresh;
643
+ return input.persisted ?? input.fresh;
465
644
  }
466
- export {
467
- FilesystemStorageProvider,
468
- PYTHON_VERSION,
469
- buildBinaryPath,
470
- canonicalDeviceFingerprint,
471
- canonicalHash,
472
- diffExportTargets,
473
- downloadBinary,
474
- ensureBinary,
475
- ensureFfmpeg,
476
- ensurePython,
477
- findInPath,
478
- getFfmpegDownloadUrl,
479
- getPlatformInfo,
480
- getPythonDownloadUrl,
481
- installPythonPackages,
482
- installPythonRequirements,
483
- resolveExportFingerprint
484
- };
485
- //# sourceMappingURL=node.mjs.map
645
+ //#endregion
646
+ export { FilesystemStorageProvider, PYTHON_VERSION, buildBinaryPath, canonicalDeviceFingerprint, canonicalHash, diffExportTargets, downloadBinary, ensureBinary, ensureFfmpeg, ensurePython, findInPath, getFfmpegDownloadUrl, getPlatformInfo, getPythonDownloadUrl, installPythonPackages, installPythonRequirements, resolveExportFingerprint };